- Fix defusedxml import style in print_queue.py to be recognized by Bandit
(use `import defusedxml.ElementTree as ET` not `from defusedxml import`)
- Update Trivy scanner version from 0.65.0 to 0.69.1
Date input for scheduled prints was swapping month and day for European
users because:
1. EU format only accepted "/" separator, not "." which is common in
European locales (e.g., "5.2.2026" for Feb 5th)
2. System format fell back to new Date() which interprets ambiguous
dates in US format
Changes:
- Added splitDateParts() helper to accept /, ., and - separators
- Updated parseDateInput() to use proper locale detection for system
format instead of relying on Date constructor
- All explicit formats (us, eu, iso) now accept any of the three
separators
Closes#233
The FilamentHoverCard positioning logic now accounts for the fixed 56px
header when calculating available space above the trigger element.
Previously, when hovering over AMS slots near the top of the page, the
hover card would appear above the slot but go behind the navigation bar.
Now it correctly detects there isn't enough usable space and flips to
show below the slot instead.
Closes#259
- Changed the 401 handling in request() to only clear the auth token when the error message indicates the token is actually invalid
- Previously: ANY 401 response cleared the token (could cause cascading failures)
- Now: Only clears on specific messages like "Token has expired", "Could not validate credentials", etc.
- "Authentication required" (which might be a timing issue) no longer clears the token
Closes#257
The tray_info_idx field is a filament TYPE identifier (e.g., "GFA00" for
generic PLA), not unique per spool. When multiple AMS trays are loaded
with the same filament type, the previous code used find() which always
returned the first match regardless of color.
Now checks if tray_info_idx is unique among available trays:
- If unique: use that tray as definitive match (existing behavior)
- If not unique: fall back to color matching among matching trays
Fixed in both backend (print_scheduler.py) and frontend (useFilamentMapping.ts).
Closes#245
- SSDP proxy for cross-network setups: select slicer network interface for automatic printer discovery via SSDP relay
- FTP proxy now listens on privileged port 990 (matching Bambu Studio expectations) instead of 9990
- For systemd: requires `AmbientCapabilities=CAP_NET_BIND_SERVICE` capability
- Automatic directory permission checking at startup with clear error messages for Docker/bare metal
When multiple AMS trays have the same filament type and color, Bambuddy
now uses the tray_info_idx attribute from the 3MF file to identify the
exact spool selected during slicing. This ensures the correct tray is
used rather than just picking the first match.
Matching priority: tray_info_idx > exact color > similar color > type-only
Closes#245
Header action buttons were overflowing outside the screen on iPhone/mobile
devices because the header containers used fixed horizontal layouts.
Changed both pages to use the responsive pattern from PrintersPage:
- Headers stack vertically on mobile (flex-col), horizontal on sm+ (sm:flex-row)
- Button containers use flex-wrap to allow wrapping on narrow screens
- Added gap-4 between title and buttons when stacked
Closes#255
When editing a queue item, the scheduled time was being displayed in UTC
instead of the user's local timezone. This caused confusion where:
- User selects April 2, 2:00 PM local time
- After saving, it appears shifted by their timezone offset
- Month/day could appear swapped due to the timezone difference
The fix converts the UTC time from the server to local time when
populating the datetime-local input, using toDateTimeLocalValue()
instead of toISOString().slice(0, 16).
Closes#233
The queue was showing "Printing" even when the printer was paused.
Now fetches real-time printer state for active print jobs and displays
"Paused" with a yellow badge when the printer state is PAUSE/PAUSED.
Changes:
- Add printerState prop to StatusBadge and SortableQueueItem components
- Fetch printer statuses for printers with active jobs using useQueries
- Show pause icon and yellow badge when printing but printer is paused
- Add "paused" translation key for queue status (en, de, ja)
Closes#249
The filament_used_grams field already contains the total filament for
the entire print job (all items combined). The code was incorrectly
multiplying this value by quantity, causing inflated filament totals.
Example: A print with 26 objects using 126g total was being calculated
as 126g * 26 = 3,276g instead of the correct 126g.
Fixes:
- backend/app/api/routes/archives.py: Archive stats endpoint
- backend/app/api/routes/metrics.py: Prometheus metrics endpoint
- frontend/src/components/FilamentTrends.tsx: Trends chart calculations
Closes#229
Several frontend components were using raw fetch() instead of the API
client, causing 401 Unauthorized errors when authentication is enabled.
Changes:
- SpoolmanSettings: Use api.getSpoolmanSettings/updateSpoolmanSettings
- ProjectsPage: Use api.importProjectFile for ZIP imports
- ProjectDetailPage: Use api.exportProjectZip for exports
- CameraPage/EmbeddedCameraViewer: Use api.getCameraStatus
Added to API client:
- getSpoolmanSettings()
- updateSpoolmanSettings()
- importProjectFile()
- exportProjectZip()
- getCameraStatus()
Added tests for auth token handling in client.test.ts
Fixed VirtualPrinterSettings test expectations to match i18n strings
Closes#231
Proxy mode changes:
- Replace transparent TCP proxy with TLS-terminating proxy
- Slicer connects to Bambuddy cert, Bambuddy connects to printer
- Use real printer's serial number for SSDP and certificate
- This ensures MQTT topic subscriptions match the real printer
The proxy now:
1. Accepts TLS from slicer using Bambuddy's certificate
2. Opens TLS connection to real printer
3. Forwards decrypted data bidirectionally
Also: Complete i18n localization for VirtualPrinterSettings component
When a spool is already linked in Spoolman, the FilamentHoverCard now shows
"Open in Spoolman" button instead of "Link to Spoolman". This allows users
to quickly navigate to the spool's page in Spoolman for editing.
Changes:
- Add GET /api/v1/spoolman/spools/linked endpoint returning tag->spool_id map
- FilamentHoverCard shows "Open in Spoolman" when linkedSpoolId is set
- "Link to Spoolman" only shows when spool is not linked
- Fix unlinked spools detection to strip JSON quotes from empty tags
- Add toast notifications for link success/failure
- Invalidate linked-spools query after linking
- Add backend tests for linked spools endpoint
- Add frontend tests for LinkSpoolModal
Closes#210
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
- Add new `printers:ams_rfid` permission for re-reading AMS RFID tags
- Allows granting RFID re-read access without full printer control
- Operators group includes this permission by default
- Previously used `printers:control` which grants broader access
- Permission available in Settings > Users > Group Editor
Closes#204
Backend:
- Split update/delete permissions into *_own and *_all variants:
- queue:update_own/all, queue:delete_own/all
- archives:update_own/all, archives:delete_own/all, archives:reprint_own/all
- library:update_own/all, library:delete_own/all
- Add require_ownership_permission dependency factory in auth.py
- Enforce ownership checks on all relevant API endpoints:
- archives.py: PATCH, DELETE, POST /reprint
- print_queue.py: PATCH, DELETE, POST /cancel, PATCH /bulk
- library.py: PUT /files, DELETE /files, POST /bulk-delete, DELETE /folders
- Add user items count endpoint: GET /users/{id}/items-count
- Add delete_items parameter to DELETE /users/{id}
- Explicitly set created_by_id to NULL on user deletion for DB portability
- Add permission migration for existing groups in database.py
- Add require_permission_if_auth_enabled for folder delete
Frontend:
- Add canModify helper to AuthContext for ownership-based checks
- Update ArchivesPage: use canModify for edit/delete/reprint buttons
- Update QueuePage: use canModify for edit/delete/cancel buttons
- Update FileManagerPage: use canModify for edit/delete buttons
- Update SettingsPage: add user deletion modal with item handling options
- Update StatsPage: use archives:update_all for recalculate costs
- Update Permission type with new ownership permissions
- Add getUserItemsCount and update deleteUser API methods
Tests:
- Add test_ownership_permissions.py with 28 comprehensive tests
- Test admin *_all permissions, operator *_own permissions
- Test bulk operations skip non-owned items
- Test auth disabled allows all operations
- Test user deletion with/without items
Closes#205
Track and display who performs key actions in Bambuddy:
- Archives: who uploaded each archive file
- Library: who uploaded each file in File Manager
- Queue: who added each print job to the queue
- Printers: who started the current print (reprint tracking)
Backend changes:
- Add created_by_id column to print_archives, library_files, print_queue tables
- Add database migrations for new columns (auto-run on startup)
- Update archive, library, and queue routes to capture current user
- Add current-print-user endpoint for printer reprint tracking
- Track reprint user in PrinterManager in-memory state
- Fix file uploads not sending auth headers (FormData requires explicit headers)
Frontend changes:
- Display username on archive cards, library files, queue items
- Show "Started by" on printer cards during active prints
- Add auth headers to all 12 FormData upload functions
- Update TypeScript types for user tracking fields
Tests:
- Add unit tests for PrinterManager user tracking methods (7 tests)
- Add integration tests for current-print-user endpoint (3 tests)
- Add integration tests for library file user tracking (3 tests)
Works when authentication is enabled; gracefully hidden when disabled.
Closes#206
- Add "Schedule" button next to "Reprint" on archive cards for quick
access to print queue functionality
- Button respects queue:create permission for restricted users
- Previously only accessible via context menu (right-click)
Closes#208
Library files now store paths relative to base_dir instead of absolute
paths. This ensures thumbnails and files work correctly after restoring
a backup on a different system or with a different data directory.
Changes:
- Add to_relative_path() and to_absolute_path() helper functions
- Update file upload, ZIP extraction, and STL thumbnail generation
to store relative paths
- Update download, thumbnail, gcode, and delete endpoints to resolve
relative paths when accessing files
- Add database migration to convert existing absolute paths to relative
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The code is ready for testing. After pushing to the remote host:
1. The migration will run automatically on startup, converting any existing absolute paths
2. New files will be stored with relative paths
3. Thumbnails should display correctly after backup/restore
- Add ?fps=N parameter to control camera frame rate (1-30, default 15)
- Add ?camera=false parameter for status-only overlay without camera feed
- Increase default camera FPS from 10 to 15 across all camera views
- Add comprehensive tests for new overlay parameters
Resolves user request on Issue #164 for higher FPS and status-only option.
When using "Any [Model]" queue assignment, the scheduler now computes
AMS mapping after a printer is assigned, instead of requiring it upfront.
This fixes H2D Pro (and other printers) failing at filament loading when
queued via model-based assignment. The issue was that no AMS mapping was
sent to the printer because the specific printer wasn't known at queue time.
Closes#192
Add new setting "Check printer firmware" in Settings → General → Updates
that allows users to disable automatic firmware update checks from
Bambu Lab servers.
Closes#169
- Queue now shows correct plate thumbnail based on selected plate_id
(previously always showed plate 1 regardless of selection)
- Archive cards now support plate browsing for multi-plate 3MF files:
- Left/right arrows to cycle through plates on hover
- Dot indicators at bottom show current plate (clickable)
- Lazy-loads plate data only when user hovers
- Added getArchivePlateThumbnail and getLibraryFilePlateThumbnail API methods
Closes#166
The GitHub backup settings page was showing "1/2 connected" even when
both printers were connected. This happened because the code read
printer status from the React Query cache, which is only populated by
WebSocket messages received on other pages.
Changed to use useQueries to fetch printer status directly from the API
(/api/v1/printers/{id}/status) instead of relying on cached WebSocket
data. Results are cached for 10s and refreshed every 30s.
Expose printer telemetry at /api/v1/metrics in Prometheus text format for
integration with Grafana, Prometheus, and other monitoring systems.
Backend:
- Add metrics.py route with GET /api/v1/metrics endpoint
- Support optional bearer token authentication
- Export printer metrics: connection, state, temperatures, fans, WiFi
- Export print metrics: progress, remaining time, layer count
- Export statistics: prints by status, filament used, print time
- Export queue metrics: pending and active jobs
- Add prometheus_enabled and prometheus_token settings
Frontend:
- Add Prometheus Metrics card in Settings → Network tab
- Toggle to enable/disable metrics endpoint
- Optional bearer token field for authentication
- Display list of available metrics
Tests:
- Add test_metrics_api.py with 7 integration tests
- Test access control (disabled, enabled, token auth)
- Test metrics format and content validation
- Add draggable resize handle to folder sidebar (200-500px range)
- Persist sidebar width in localStorage
- Double-click resize handle to reset to default width
- Add "Wrap" toggle button in Folders header for text wrapping
- When wrap enabled: folder names break across lines, menu always visible
- When wrap disabled: folder names truncate with tooltip on hover
- Persist wrap preference in localStorage
Closes#160
- Automatically turn on chamber light before plate check if it's off
- Restore light to original state after modal closes or check completes
- Add 2.5s delay for light to turn on and camera to adjust exposure
- Remove manual light warning from plate check modal
- Apply to both manual plate checks (modal) and automatic checks on print start
New feature to automatically backup K-profiles, cloud profiles, and app
settings to a GitHub repository with scheduled or on-demand execution.
Features:
- Configure GitHub repo URL and Personal Access Token
- Schedule backups hourly, daily, or weekly (background scheduler)
- Manual backup trigger with real-time progress tracking
- Skip unchanged commits (only creates commit when data changes)
- Backup history log with status and commit links
- Requires Bambu Cloud login for full profile access
- New Settings → Backup & Restore tab consolidating all backup options
- GitHub backup config included in local backup/restore (except PAT)
Backend:
- New models: GitHubBackupConfig, GitHubBackupLog
- New service: GitHubBackupService with scheduler and GitHub API client
- New routes: /github-backup/* for config, status, logs, and triggers
- Updated settings.py to include github_backup in backup/restore
Frontend:
- New GitHubBackupSettings.tsx component with auto-save
- Updated SettingsPage with Backup tab and status indicator
- Added API types and methods to client.ts
Tests:
- Backend integration tests for all GitHub backup API endpoints
- Frontend API type and endpoint tests
- Add "Plate Detection" option to backup modal
- Store printer_id_to_serial mapping in backup for calibration files
- Remap printer IDs during restore based on serial numbers so files
like printer_3_ref_0.jpg get correctly renamed if printer 3 becomes
printer 2 on the new system
- Add parents=True to mkdir calls in config.py to fix startup crash
- Labels/metadata are now correctly restored via the metadata.json files
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