|
|
@@ -90,9 +90,20 @@ import { getColorName, parseFilamentColor, isLightColor } from '../utils/colors'
|
|
|
// Color names resolve via getColorName() which reads the backend color_catalog
|
|
|
// (loaded once by ColorCatalogProvider). No hardcoded tables here — see #857.
|
|
|
|
|
|
-// Extract plate number from gcode_file path and append to print name
|
|
|
-function formatPrintName(name: string | null, gcodeFile: string | null | undefined, t: (key: string, fallback: string, opts?: Record<string, unknown>) => string): string {
|
|
|
+// Append a plate label to the print name. When `plateLabel` is provided (resolved
|
|
|
+// by the caller from the linked archive's plate list — see #881 follow-up), it
|
|
|
+// is used verbatim, including the explicit "Plate 1" case on multi-plate 3MFs.
|
|
|
+// Falls back to parsing `plate_N.gcode` from the MQTT gcode_file path, and in
|
|
|
+// that fallback we only show N > 1 because we can't tell from the path alone
|
|
|
+// whether the 3MF is multi-plate.
|
|
|
+export function formatPrintName(
|
|
|
+ name: string | null,
|
|
|
+ gcodeFile: string | null | undefined,
|
|
|
+ t: (key: string, fallback: string, opts?: Record<string, unknown>) => string,
|
|
|
+ plateLabel?: string | null,
|
|
|
+): string {
|
|
|
if (!name) return '';
|
|
|
+ if (plateLabel) return `${name} — ${plateLabel}`;
|
|
|
if (!gcodeFile) return name;
|
|
|
const match = gcodeFile.match(/plate_(\d+)\.gcode/);
|
|
|
if (match && parseInt(match[1], 10) > 1) {
|
|
|
@@ -1528,6 +1539,23 @@ function PrinterCard({
|
|
|
staleTime: 2 * 60 * 1000, // 2 minutes
|
|
|
});
|
|
|
|
|
|
+ // Fetch plate list for the archive linked to the active print (#881 follow-up).
|
|
|
+ // Only queried when there's a running print backed by an archive; shared
|
|
|
+ // React Query cache with the Queue / Archives pages keeps it cheap.
|
|
|
+ const activeArchiveId =
|
|
|
+ (status?.state === 'RUNNING' || status?.state === 'PAUSE') ? status?.current_archive_id ?? null : null;
|
|
|
+ const { data: activeArchivePlates } = useQuery({
|
|
|
+ queryKey: ['archive-plates', activeArchiveId],
|
|
|
+ queryFn: () => api.getArchivePlates(activeArchiveId!),
|
|
|
+ enabled: activeArchiveId != null,
|
|
|
+ staleTime: 5 * 60 * 1000,
|
|
|
+ });
|
|
|
+ const activePlateLabel = (() => {
|
|
|
+ if (!activeArchivePlates?.is_multi_plate || status?.current_plate_id == null) return null;
|
|
|
+ const plate = activeArchivePlates.plates.find(p => p.index === status.current_plate_id);
|
|
|
+ return plate?.name || t('printers.plateNumber', 'Plate {{number}}', { number: status.current_plate_id });
|
|
|
+ })();
|
|
|
+
|
|
|
// Fetch user-defined AMS friendly names from the database
|
|
|
const { data: amsLabels, refetch: refetchAmsLabels } = useQuery({
|
|
|
queryKey: ['amsLabels', printer.id],
|
|
|
@@ -2718,7 +2746,7 @@ function PrinterCard({
|
|
|
{/* Cover Image */}
|
|
|
<CoverImage
|
|
|
url={(status.state === 'RUNNING' || status.state === 'PAUSE') ? status.cover_url : null}
|
|
|
- printName={(status.state === 'RUNNING' || status.state === 'PAUSE') ? (formatPrintName(status.subtask_name || status.current_print || null, status.gcode_file, t) || undefined) : undefined}
|
|
|
+ printName={(status.state === 'RUNNING' || status.state === 'PAUSE') ? (formatPrintName(status.subtask_name || status.current_print || null, status.gcode_file, t, activePlateLabel) || undefined) : undefined}
|
|
|
/>
|
|
|
{/* Print Info */}
|
|
|
<div className="flex-1 min-w-0">
|
|
|
@@ -2729,7 +2757,7 @@ function PrinterCard({
|
|
|
{plateStatusPill}
|
|
|
</div>
|
|
|
<p className="text-white text-sm mb-2 truncate">
|
|
|
- {formatPrintName(status.subtask_name || status.current_print || null, status.gcode_file, t)}
|
|
|
+ {formatPrintName(status.subtask_name || status.current_print || null, status.gcode_file, t, activePlateLabel)}
|
|
|
</p>
|
|
|
<div className="flex items-center justify-between text-sm">
|
|
|
<div className="flex-1 bg-bambu-dark-tertiary rounded-full h-2 mr-3">
|