Opening the Print Queue page fired 404s on /archives/{id}/thumbnail,
/archives/{id}/plates, and /archives/{id}/plate-thumbnail/{n} for any
row pointing at a soft-deleted archive. Two underlying problems wearing
one mask:
1. Cosmetic: the queue API was copying item.archive.thumbnail_path into
archive_thumbnail without checking deleted_at. Soft-delete leaves the
row (so the relationship resolves) but removes the file from disk, so
the cached path was always stale.
2. Functional: a queue item whose 3MF was removed can never dispatch.
Without an explicit cancel, the item sits in 'pending' forever with
no indication to the user about why nothing is printing.
Fix in three parts:
- New _cancel_pending_queue_items() helper, called from soft_delete_archive
alongside the existing print-log thumbnail cleanup. Sets status='cancelled'
+ waiting_reason='Source archive deleted' on every pending queue item
linked to the archive. Only 'pending' is touched - completed/failed/
cancelled rows are historical and untouched. Hard-delete is already
covered by ON DELETE CASCADE on print_queue.archive_id.
- Queue API serializer now checks item.archive.deleted_at before
populating any archive-derived field. New archive_deleted: bool field
on PrintQueueItemResponse signals the soft-deleted state.
- Frontend's getArchivePlates query in QueuePage was gated on archive_id
only - archive_id is the real FK and stays exposed for dispatch/audit,
so added an explicit && !item.archive_deleted clause to respect the
new flag. Thumbnail render and CompactHistoryRow/QueueTimelineView
already gate on archive_thumbnail so the backend suppression alone
covers them.
Regression tests pin cancel-only-pending behavior, soft-deleted
suppression + archive_deleted=True flag, and the sanity guard that
live-archive fields keep flowing through unchanged.
Both fields have existed on the model and been shown in the File
Manager for some time, but nothing ever wrote to them — every file in
every library appeared to have never been printed.
Now on_print_complete's queue-status update path calls a small
_bump_library_file_usage_if_completed() helper that increments
print_count and stamps last_printed_at on the source library file
whenever a queued print completes successfully. Failed, cancelled and
user-aborted prints are intentionally skipped so the fields represent
successful usage rather than attempt count.
Unblocks sorting the File Manager by last-printed date and is a
prerequisite for the scheduled-purge feature requested in #1008,
which is held until we see whether manual sort+bulk-delete covers the
use case.
Audit PRs #920 (printers search/filter) and #932 (print from project
view) for regressions, i18n coverage, test gaps, and docs.
No regressions found: existing callers of the changed signatures
(archive_print, getLibraryFiles, filteredPrinters chain) are unaffected;
i18n is complete in all 7 locales for both features.
Backend tests (4 new, all passing):
- test_list_files_by_project_id — bulk JOIN returns files across all
linked folders, excludes unlinked ones
- test_list_files_folder_id_takes_precedence_over_project_id — guards
the documented precedence folder_id > project_id > include_root
- test_add_to_queue_with_project_id — project_id is persisted on the
queue row for later archive linkage
- test_add_to_queue_invalid_project_id_returns_404 — regression guard
for the validation pre-check on the queue path (mirrors the one on
the direct-print path in library.py)
Queue status update (printing → completed) failed silently when SQLite
was locked by another writer, leaving ghost jobs permanently stuck in
printing status. Add run_with_retry() for SQLite lock retries and split
runtime tracker into per-printer commits to reduce lock hold time.
The MQTT completion handler stored "aborted" as the queue item status
when a print was cancelled mid-print, but the response schema only
allows "cancelled". Pydantic validation failed on the invalid status
when listing all queue items, returning 500. Filtering by specific
status excluded the bad row so those still worked.
Normalise "aborted" → "cancelled" before storing. A startup fixup
also converts any existing "aborted" rows in the database.
Features:
- Add location filter for "Any {Model}" queue assignments
- Queue items can target a specific location (e.g., "Any X1C in Workshop")
- Location dropdown filter on Queue page to view jobs by location
- Scheduler considers location when assigning model-based jobs
Closes#220
New Features:
- Queue bulk edit: Select multiple pending items and edit printer
assignment, print options, or cancel them at once (Issue #159)
- Tri-state toggles (unchanged/on/off) for selective field updates
Fixes:
- Progress milestone notifications showed wrong time (e.g., "17m" instead
of "17h 47m") - fixed by converting remaining_time from minutes to
seconds (Issue #157)
- File Manager folder names now show full name on hover tooltip (Issue #160)
Backend:
- Added PATCH /queue/bulk endpoint for bulk updates
- Route ordering fixed to prevent /bulk matching as /{item_id}
Frontend:
- Added checkbox selection to pending queue items
- Added bulk action toolbar with Select All, Edit Selected, Cancel Selected
- Created BulkEditModal with tri-state toggles for each setting
Tests:
- Added 7 integration tests for bulk update endpoint
Closes#159
- Print from File Manager with plate selection, AMS mapping, and print options. Closes#94
- Add to queue without creating archive (reduces clutter)
- Queue displays library file name, thumbnail, and print time
Fixes:
Queue items from File Manager now reference library files directly instead of
creating archives upfront. Archives are created automatically when prints start.
- Comprehensive hex-based color mapping (~200 Bambu colors from CSV)
- Fixed tooltips to use Bambu color lookup
- Widened modals (max-w-md → max-w-lg)
- Adjusted grid layout to fit long color names
- Service worker bumped to v21
Pending changes in bambuddy repo:
- CHANGELOG.md, README.md
- backend/app/api/routes/print_queue.py
- backend/tests/integration/test_print_queue_api.py
- frontend components (ReprintModal, AddToQueueModal, EditQueueItemModal)
- sw.js (v21)
Features:
- Resizable printer cards (S/M/L/XL) with toolbar controls on Printers page
- Queue Only mode for staging prints without automatic scheduling
- "Queue Only" option in add/edit queue modals
- Purple "Staged" badge and Play button to release to queue
- manual_start field in database with migration
Fixes:
- Improved camera stream stuck detection with automatic reconnection
Tests:
- Added 16 integration tests for print queue API endpoints