Browse Source

Fix Print Queue showing UUID hash instead of filename (#438)

Library files are stored on disk with UUID-hex filenames for uniqueness,
but archive_print() used the disk path as the display name. Pass the
original LibraryFile.filename through from both the print scheduler and
direct-print-from-library flow so the archive's filename, print_name,
and directory name all use the human-readable name.
maziggy 3 months ago
parent
commit
9c81657df7

+ 1 - 0
CHANGELOG.md

@@ -16,6 +16,7 @@ All notable changes to Bambuddy will be documented in this file.
 - **H2D Tray Disambiguation Triggers on Single-Nozzle Printers** — The `tray_now <= 3` check for H2D dual-nozzle disambiguation matched any printer loading from AMS 0 (trays 0-3). On P2S, X1C, and X1E with multiple AMS units, this caused warning log spam every second. Now uses a persistent `_is_dual_nozzle` flag detected from `device.extruder.info` (>= 2 entries), which only dual-nozzle printers (H2D, H2D Pro) report.
 - **H2D Tray Disambiguation Triggers on Single-Nozzle Printers** — The `tray_now <= 3` check for H2D dual-nozzle disambiguation matched any printer loading from AMS 0 (trays 0-3). On P2S, X1C, and X1E with multiple AMS units, this caused warning log spam every second. Now uses a persistent `_is_dual_nozzle` flag detected from `device.extruder.info` (>= 2 entries), which only dual-nozzle printers (H2D, H2D Pro) report.
 - **AMS-HT Snow Slot Mismatch Log Spam on H2D** — The snow-based tray_now disambiguation computed `snow_slot = -1` for AMS-HT trays (IDs 128-135), causing a "slot mismatch" debug log on every MQTT update even though the result was correct. Now correctly computes `snow_slot = 0` for AMS-HT single-slot units.
 - **AMS-HT Snow Slot Mismatch Log Spam on H2D** — The snow-based tray_now disambiguation computed `snow_slot = -1` for AMS-HT trays (IDs 128-135), causing a "slot mismatch" debug log on every MQTT update even though the result was correct. Now correctly computes `snow_slot = 0` for AMS-HT single-slot units.
 - **Color Tooltip Clipped Behind Adjacent Swatches** — Color swatch hover tooltips in the spool form were rendered behind neighboring swatches due to missing z-index on the hover state. Added `hover:z-20` and tooltip `z-20` classes.
 - **Color Tooltip Clipped Behind Adjacent Swatches** — Color swatch hover tooltips in the spool form were rendered behind neighboring swatches due to missing z-index on the hover state. Added `hover:z-20` and tooltip `z-20` classes.
+- **Print Queue Shows UUID Hash Instead of Filename** ([#438](https://github.com/maziggy/bambuddy/issues/438)) — When printing a library file, the Print Queue and archive displayed the UUID-hex disk filename (e.g., `c65887535303404eba1525176a0f78dc`) instead of the original human-readable name. Library files are stored on disk with UUID filenames for uniqueness, but `archive_print()` used the disk path as the display name. Now passes the original `LibraryFile.filename` through to `archive_print()` from both the print scheduler and the direct-print-from-library flow, so the archive's `filename`, `print_name`, and directory name all use the human-readable name.
 
 
 - **Usage Tracking Wrong Spool on Dual-Nozzle / Multi-AMS Printers** ([#364](https://github.com/maziggy/bambuddy/issues/364)) — On H2C, H2D Pro, and other dual-nozzle printers with multiple AMS units, the usage tracker attributed filament consumption to the wrong spools. The MQTT `mapping` field — a per-print array that maps slicer filament slots to physical AMS trays — was preserved in state but never parsed or used. The tracker fell back to `slot_id - 1` as the global tray ID, which is incorrect when AMS hardware IDs differ from sequential indices (e.g., AMS-HT units with ID 128). Now decodes the MQTT mapping field from its snow encoding (`ams_hw_id * 256 + local_slot`) into bambuddy global tray IDs and uses it as a universal mapping source — working for all printer models and all print sources (slicer, queue, reprint) without relying on `tray_now` disambiguation. For printers that don't provide the MQTT mapping field (A1, A1 Mini, P1S, P2S), a color-matching fallback compares 3MF filament slot colors against AMS tray colors to resolve the correct slot-to-tray mapping. Gracefully returns no match when colors are ambiguous (duplicate tray colors) or unavailable.
 - **Usage Tracking Wrong Spool on Dual-Nozzle / Multi-AMS Printers** ([#364](https://github.com/maziggy/bambuddy/issues/364)) — On H2C, H2D Pro, and other dual-nozzle printers with multiple AMS units, the usage tracker attributed filament consumption to the wrong spools. The MQTT `mapping` field — a per-print array that maps slicer filament slots to physical AMS trays — was preserved in state but never parsed or used. The tracker fell back to `slot_id - 1` as the global tray ID, which is incorrect when AMS hardware IDs differ from sequential indices (e.g., AMS-HT units with ID 128). Now decodes the MQTT mapping field from its snow encoding (`ams_hw_id * 256 + local_slot`) into bambuddy global tray IDs and uses it as a universal mapping source — working for all printer models and all print sources (slicer, queue, reprint) without relying on `tray_now` disambiguation. For printers that don't provide the MQTT mapping field (A1, A1 Mini, P1S, P2S), a color-matching fallback compares 3MF filament slot colors against AMS tray colors to resolve the correct slot-to-tray mapping. Gracefully returns no match when colors are ambiguous (duplicate tray colors) or unavailable.
 - **npm audit: suppress moderate ajv ReDoS finding** — Added `audit-level=high` to `frontend/.npmrc` so `npm audit` exits cleanly. The ajv@6 ReDoS (GHSA-2g4f-4pwh-qvx6) is a transitive dependency of eslint@9 with no patched v6 release; ajv@8 override breaks eslint. The vulnerability requires crafted `$data` schema input — not an attack vector in a linting config.
 - **npm audit: suppress moderate ajv ReDoS finding** — Added `audit-level=high` to `frontend/.npmrc` so `npm audit` exits cleanly. The ajv@6 ReDoS (GHSA-2g4f-4pwh-qvx6) is a transitive dependency of eslint@9 with no patched v6 release; ajv@8 override breaks eslint. The vulnerability requires crafted `$data` schema input — not an attack vector in a linting config.

+ 1 - 0
backend/app/api/routes/library.py

@@ -1795,6 +1795,7 @@ async def print_library_file(
     archive = await archive_service.archive_print(
     archive = await archive_service.archive_print(
         printer_id=printer_id,
         printer_id=printer_id,
         source_file=file_path,
         source_file=file_path,
+        original_filename=lib_file.filename,
     )
     )
 
 
     if not archive:
     if not archive:

+ 7 - 3
backend/app/services/archive.py

@@ -831,6 +831,7 @@ class ArchiveService:
         source_file: Path,
         source_file: Path,
         print_data: dict | None = None,
         print_data: dict | None = None,
         created_by_id: int | None = None,
         created_by_id: int | None = None,
+        original_filename: str | None = None,
     ) -> PrintArchive | None:
     ) -> PrintArchive | None:
         """Archive a 3MF file with metadata.
         """Archive a 3MF file with metadata.
 
 
@@ -839,6 +840,8 @@ class ArchiveService:
             source_file: Path to the 3MF file
             source_file: Path to the 3MF file
             print_data: Print data from MQTT (optional)
             print_data: Print data from MQTT (optional)
             created_by_id: User ID who created this archive (optional, for user tracking)
             created_by_id: User ID who created this archive (optional, for user tracking)
+            original_filename: Original human-readable filename (optional, for library files
+                stored with UUID names)
         """
         """
         # Verify printer exists if specified
         # Verify printer exists if specified
         if printer_id is not None:
         if printer_id is not None:
@@ -849,7 +852,8 @@ class ArchiveService:
 
 
         # Create archive directory structure
         # Create archive directory structure
         timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
         timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-        archive_name = f"{timestamp}_{source_file.stem}"
+        display_stem = Path(original_filename).stem if original_filename else source_file.stem
+        archive_name = f"{timestamp}_{display_stem}"
         # Use "unassigned" folder for archives without a printer
         # Use "unassigned" folder for archives without a printer
         printer_folder = str(printer_id) if printer_id is not None else "unassigned"
         printer_folder = str(printer_id) if printer_id is not None else "unassigned"
         archive_dir = settings.archive_dir / printer_folder / archive_name
         archive_dir = settings.archive_dir / printer_folder / archive_name
@@ -923,12 +927,12 @@ class ArchiveService:
         # Create archive record
         # Create archive record
         archive = PrintArchive(
         archive = PrintArchive(
             printer_id=printer_id,
             printer_id=printer_id,
-            filename=source_file.name,
+            filename=original_filename or source_file.name,
             file_path=str(dest_file.relative_to(settings.base_dir)),
             file_path=str(dest_file.relative_to(settings.base_dir)),
             file_size=dest_file.stat().st_size,
             file_size=dest_file.stat().st_size,
             content_hash=content_hash,
             content_hash=content_hash,
             thumbnail_path=thumbnail_path,
             thumbnail_path=thumbnail_path,
-            print_name=metadata.get("print_name") or source_file.stem,
+            print_name=metadata.get("print_name") or display_stem,
             print_time_seconds=metadata.get("print_time_seconds"),
             print_time_seconds=metadata.get("print_time_seconds"),
             filament_used_grams=metadata.get("filament_used_grams"),
             filament_used_grams=metadata.get("filament_used_grams"),
             filament_type=metadata.get("filament_type"),
             filament_type=metadata.get("filament_type"),

+ 1 - 0
backend/app/services/print_scheduler.py

@@ -915,6 +915,7 @@ class PrintScheduler:
                 archive = await archive_service.archive_print(
                 archive = await archive_service.archive_print(
                     printer_id=item.printer_id,
                     printer_id=item.printer_id,
                     source_file=file_path,
                     source_file=file_path,
+                    original_filename=filename,
                 )
                 )
                 if archive:
                 if archive:
                     item.archive_id = archive.id
                     item.archive_id = archive.id