|
@@ -755,6 +755,10 @@ interface FileCardProps {
|
|
|
onOpenInSlicer?: (file: LibraryFileListItem) => void;
|
|
onOpenInSlicer?: (file: LibraryFileListItem) => void;
|
|
|
onRunPipeline?: (file: LibraryFileListItem) => void;
|
|
onRunPipeline?: (file: LibraryFileListItem) => void;
|
|
|
useSlicerApi?: boolean;
|
|
useSlicerApi?: boolean;
|
|
|
|
|
+ // Which slicer the desktop handoff targets. Decides whether an STL or STEP
|
|
|
|
|
+ // gets a Slice action at all: Bambu Studio's protocol handler takes 3MF only
|
|
|
|
|
+ // (#3029), so offering one there would only ever fail.
|
|
|
|
|
+ desktopSlicer: SlicerType;
|
|
|
canSlice?: boolean;
|
|
canSlice?: boolean;
|
|
|
onPreview3d?: (file: LibraryFileListItem) => void;
|
|
onPreview3d?: (file: LibraryFileListItem) => void;
|
|
|
onRename?: (file: LibraryFileListItem) => void;
|
|
onRename?: (file: LibraryFileListItem) => void;
|
|
@@ -768,7 +772,7 @@ interface FileCardProps {
|
|
|
t: TFunction;
|
|
t: TFunction;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function FileCard({ file, isSelected, onSelect, onDelete, onDownload, onPrint, onSlice, onOpenInSlicer, onRunPipeline, useSlicerApi, canSlice, onPreview3d, onRename, onGenerateThumbnail, onTagClick, thumbnailVersion, hasPermission, canModify, authEnabled, showModified, t }: FileCardProps) {
|
|
|
|
|
|
|
+function FileCard({ file, isSelected, onSelect, onDelete, onDownload, onPrint, onSlice, onOpenInSlicer, onRunPipeline, useSlicerApi, desktopSlicer, canSlice, onPreview3d, onRename, onGenerateThumbnail, onTagClick, thumbnailVersion, hasPermission, canModify, authEnabled, showModified, t }: FileCardProps) {
|
|
|
// Viewport coordinates rather than a flag, because the menu is rendered by
|
|
// Viewport coordinates rather than a flag, because the menu is rendered by
|
|
|
// `ContextMenu` at `position: fixed` and anchored to the button (#2846). The
|
|
// `ContextMenu` at `position: fixed` and anchored to the button (#2846). The
|
|
|
// card it belongs to is only ~270px tall for a bare STL, which is shorter
|
|
// card it belongs to is only ~270px tall for a bare STL, which is shorter
|
|
@@ -792,7 +796,7 @@ function FileCard({ file, isSelected, onSelect, onDelete, onDownload, onPrint, o
|
|
|
title: !hasPermission('queue:create') ? t('fileManager.noPermissionAddToQueue') : undefined,
|
|
title: !hasPermission('queue:create') ? t('fileManager.noPermissionAddToQueue') : undefined,
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
- if (isSliceableLibraryFile(file, !!useSlicerApi) && (useSlicerApi ? onSlice : onOpenInSlicer)) {
|
|
|
|
|
|
|
+ if (isSliceableLibraryFile(file, !!useSlicerApi, desktopSlicer) && (useSlicerApi ? onSlice : onOpenInSlicer)) {
|
|
|
menuItems.push({
|
|
menuItems.push({
|
|
|
label: t('slice.action'),
|
|
label: t('slice.action'),
|
|
|
icon: useSlicerApi ? <Cog className="w-4 h-4" /> : <ExternalLink className="w-4 h-4" />,
|
|
icon: useSlicerApi ? <Cog className="w-4 h-4" /> : <ExternalLink className="w-4 h-4" />,
|
|
@@ -801,7 +805,7 @@ function FileCard({ file, isSelected, onSelect, onDelete, onDownload, onPrint, o
|
|
|
title: !canSlice ? (useSlicerApi ? t('fileManager.noPermissionSlice') : t('fileManager.noPermissionDownload')) : undefined,
|
|
title: !canSlice ? (useSlicerApi ? t('fileManager.noPermissionSlice') : t('fileManager.noPermissionDownload')) : undefined,
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
- if (onRunPipeline && useSlicerApi && isSliceableLibraryFile(file, true)) {
|
|
|
|
|
|
|
+ if (onRunPipeline && useSlicerApi && isSliceableLibraryFile(file, true, desktopSlicer)) {
|
|
|
menuItems.push({
|
|
menuItems.push({
|
|
|
label: t('library.runWithPipeline.actionLabel'),
|
|
label: t('library.runWithPipeline.actionLabel'),
|
|
|
icon: <Play className="w-4 h-4" />,
|
|
icon: <Play className="w-4 h-4" />,
|
|
@@ -2428,6 +2432,7 @@ export function FileManagerPage() {
|
|
|
onPrint={setPrintFile}
|
|
onPrint={setPrintFile}
|
|
|
onSlice={setSliceFile}
|
|
onSlice={setSliceFile}
|
|
|
onOpenInSlicer={handleOpenInSlicer}
|
|
onOpenInSlicer={handleOpenInSlicer}
|
|
|
|
|
+ desktopSlicer={preferredSlicer}
|
|
|
onRunPipeline={setRunPipelineFile}
|
|
onRunPipeline={setRunPipelineFile}
|
|
|
useSlicerApi={settings?.use_slicer_api ?? false}
|
|
useSlicerApi={settings?.use_slicer_api ?? false}
|
|
|
canSlice={canSlice()}
|
|
canSlice={canSlice()}
|
|
@@ -2606,7 +2611,7 @@ export function FileManagerPage() {
|
|
|
</button>
|
|
</button>
|
|
|
</>
|
|
</>
|
|
|
)}
|
|
)}
|
|
|
- {isSliceableLibraryFile(file, !!settings?.use_slicer_api) && (
|
|
|
|
|
|
|
+ {isSliceableLibraryFile(file, !!settings?.use_slicer_api, preferredSlicer) && (
|
|
|
<button
|
|
<button
|
|
|
onClick={() => {
|
|
onClick={() => {
|
|
|
if (!canSlice()) return;
|
|
if (!canSlice()) return;
|
|
@@ -2623,7 +2628,7 @@ export function FileManagerPage() {
|
|
|
{settings?.use_slicer_api ? <Cog className="w-4 h-4" /> : <ExternalLink className="w-4 h-4" />}
|
|
{settings?.use_slicer_api ? <Cog className="w-4 h-4" /> : <ExternalLink className="w-4 h-4" />}
|
|
|
</button>
|
|
</button>
|
|
|
)}
|
|
)}
|
|
|
- {(settings?.use_slicer_api ?? false) && isSliceableLibraryFile(file, true) && (
|
|
|
|
|
|
|
+ {(settings?.use_slicer_api ?? false) && isSliceableLibraryFile(file, true, preferredSlicer) && (
|
|
|
<button
|
|
<button
|
|
|
onClick={() => hasPermission('pipelines:run') && setRunPipelineFile(file)}
|
|
onClick={() => hasPermission('pipelines:run') && setRunPipelineFile(file)}
|
|
|
className={`p-1.5 rounded transition-colors ${
|
|
className={`p-1.5 rounded transition-colors ${
|
|
@@ -2869,7 +2874,7 @@ export function FileManagerPage() {
|
|
|
onSliceWithBambuddy={
|
|
onSliceWithBambuddy={
|
|
|
// Only offer in-app slicing on files the SliceModal can actually
|
|
// Only offer in-app slicing on files the SliceModal can actually
|
|
|
// handle (matches the file-row Cog visibility check at :2127).
|
|
// handle (matches the file-row Cog visibility check at :2127).
|
|
|
- isSliceableLibraryFile(viewerFile, true) && hasPermission('library:upload')
|
|
|
|
|
|
|
+ isSliceableLibraryFile(viewerFile, true, preferredSlicer) && hasPermission('library:upload')
|
|
|
? () => {
|
|
? () => {
|
|
|
const f = viewerFile;
|
|
const f = viewerFile;
|
|
|
setViewerFile(null);
|
|
setViewerFile(null);
|