Commit Graph
797 Commits
Author SHA1 Message Date
maziggy 504a0f9970 Compact SpoolBuddy settings Device tab to fit without scrolling
Remove branding/about card, fold Device ID into Device Info card,
  place Backend/Auth config and diagnostic buttons side by side in a
  2-column grid, remove redundant online/offline status from Device
  Info, and tighten spacing throughout.
2026-03-25 12:57:24 +01:00
maziggy 73aeee7bdf Compact SpoolBuddy settings Device tab to avoid scrolling
Remove the branding/about card, fold Device ID into the Device Info
  card, make diagnostic buttons a horizontal 3-column row, and put the
  API token input and Save button on the same line. Tighten spacing
  throughout so the tab fits on the small touchscreen without scrolling.
2026-03-25 12:52:43 +01:00
maziggy 88c0503009 Show spool notes as hover tooltip in Assign Spool modal (#793) 2026-03-25 08:55:06 +01:00
maziggy c9efa4b8bb Fix stale AMS slot data and empty slot button visibility (#784)
Some printers (e.g. H2D) only send {id, state} in incremental MQTT
  tray updates — no tray_type, tray_color, or other fields. When
  filament is unloaded (state changes from 11 to 10), the old tray
  data persisted indefinitely because the merge logic only updates
  fields present in the incoming message.

  Backend:
  - Detect tray state != 11 without tray_type in incremental updates
    and clear stale tray data (bambu_mqtt.py)
  - Expose tray `state` field via REST API and WebSocket broadcasts
    (printer.py schema, printers.py route, printer_manager.py)
  - Include AMS tray content in WebSocket dedup key so load/unload
    transitions trigger broadcasts (main.py)

  Frontend:
  - Add `state` to AMSTray interface (client.ts)
  - Show configure/assign buttons for state=10 (spool present, not
    loaded) but hide for state=9 (truly empty) on AMS/HT slots
  - Hide fill level bar on empty slots

  Tests:
  - 5 new tests covering state-based clearing, preservation, reload,
    and idempotency
2026-03-24 16:03:34 +01:00
Keybored 6e648804fc [Feature] Spoolbuddy Fixes and Improvements (#787)
[Feature] Spoolbuddy Fixes and Improvements (#787)
2026-03-24 11:56:33 +01:00
Keybored 3f7d0e2d55 Add notification for no spool assigned for active trays, improve usage tracker logic in edge cases (#789)
Add notification for no spool assigned for active trays, improve usage tracker logic in edge cases (#789)
2026-03-24 11:31:32 +01:00
maziggy 82278e8d93 Add external folder mounting for File Manager (#124)
Host directories (NAS, USB, network shares) can now be mounted
  into the File Manager without copying files. Files are indexed
  into the database on scan but read directly from their original
  location. Supports read-only mode, hidden file filtering, and
  automatic thumbnail extraction for 3MF/STL/gcode.

  - POST /library/folders/external — create with path validation
  - POST /library/folders/{id}/scan — discover/sync files
  - Block uploads, moves, and deletes for read-only external folders
  - Never delete actual files from external paths (DB-only removal)
  - Purple folder icon + info bar with rescan button in UI
  - i18n for all 7 languages
  - 19 backend + 11 frontend tests
2026-03-24 08:43:23 +01:00
maziggy b8a3aa842b Add tests for SpoolBuddy SSH update service and settings UI
15 backend unit tests covering keypair management, branch detection,
  SSH command execution (success/failure/timeout), and full update flow
  with error handling. 4 new frontend tests for the Updates tab (version
  display, buttons, SSH setup, update available state).
2026-03-23 15:55:44 +01:00
maziggy 8d60c31aa7 Force-clear service worker and caches on SpoolBuddy kiosk load
Just unregistering the SW wasn't enough — the old SW still controlled
  the page for that load. Now detects if any SW exists, nukes all SWs
  and caches, then reloads once to get a clean fetch from the server.
  Subsequent loads skip this since no SW is registered.
2026-03-23 15:32:06 +01:00
maziggy bc37c12f90 Disable service worker on SpoolBuddy kiosk to prevent stale frontend
The kiosk touchscreen has no way to hard-refresh, and the service worker
  served stale cached JS after updates. SpoolBuddy pages now unregister
  any existing SW and skip registration entirely. Regular desktop/mobile
  users still get the SW. Restored kiosk restart in SSH update flow since
  SW is no longer an obstacle.
2026-03-23 15:28:24 +01:00
maziggy 7f1ced60fd Fix stale frontend after deploy due to service worker caching
The SW used stale-while-revalidate for JS/CSS, serving old cached
  bundles even after a new build. Changed to network-first (Vite already
  content-hashes filenames), bumped cache version v24→v25, and added
  Cache-Control: no-cache to the sw.js endpoint so browsers always fetch
  the latest service worker.
2026-03-23 15:12:18 +01:00
maziggy 8be4bed384 Fix SpoolBuddy update UI responsiveness and stale data
Rewrote update button states: single `busy` flag stays set from click
  through to device pickup — no more gap with no feedback. Buttons hide
  while any operation is in progress. Listens for spoolbuddy-online
  WebSocket event to reload the page after daemon re-registers, ensuring
  fresh version and status. Set staleTime to 0 on update check queries.
2026-03-23 15:04:56 +01:00
maziggy 559d41cc5e Fix SpoolBuddy update UI: loading states, page reload, stale data
Check button had no visual feedback because isFetching doesn't trigger
  reliably with cached data — replaced with manual loading state. Removed
  kiosk restart via getty; the frontend now detects daemon re-registration
  via WebSocket and calls window.location.reload(), keeping the user on
  the same page and fetching all fresh data.
2026-03-23 14:59:12 +01:00
maziggy 1f24bd264a Fix SpoolBuddy update UI feedback and stale query cache
- Check button now shows spinner on refetch (isFetching vs isLoading)
  - Force Update button shows spinner while triggering
  - Reduced staleTime from 4 minutes to 30 seconds so the UI picks up
    version changes after an update without a long delay
2026-03-23 14:48:10 +01:00
maziggy 0e44e149bd ● Compact SpoolBuddy updates tab layout to fit without scrolling
Merged version, status, and update check into a single card. Buttons
  are side by side when up to date. Reduced padding and font sizes.
  Removed separate "complete" banner since status is now cleared on
  re-registration. SSH Setup section is smaller and more compact.
2026-03-23 14:36:58 +01:00
maziggy 811813165b Fix stale SpoolBuddy update status after daemon restart
After an SSH update completed, the UI kept showing "Update complete,
  daemon restarting..." and the old "update available" banner because
  nothing cleared the stale state. Registration now resets update_status
  when the daemon comes back, and WebSocket handlers for spoolbuddy_update
  and spoolbuddy_online invalidate the frontend queries immediately.
2026-03-23 13:55:12 +01:00
maziggy bc1bba078b Replace SpoolBuddy self-update with SSH-based updates from Bambuddy
The daemon's self-update mechanism (git fetch/reset on its own code) was
  fragile: .git permission errors, self-modifying code mid-run, hardcoded
  main branch. Bambuddy now SSHes into the SpoolBuddy Pi and drives the
  update remotely — matching its own branch, with step-by-step progress
  via WebSocket. Install script updated with SSH access, sudoers entry,
  and --ssh-pubkey flag for pairing.
2026-03-23 12:51:21 +01:00
maziggy 511ece791a Fix SpoolBuddy update check comparing against GitHub releases instead of backend version
The SpoolBuddy daemon update endpoint fetched GitHub releases and compared
  them against device.firmware_version, which always showed "up to date"
  because the comparison source was wrong. Now compares directly against
  APP_VERSION from the running backend, so a daemon at 0.2.3b1 correctly
  sees 0.2.3 as an available update.
2026-03-23 12:05:20 +01:00
maziggy 40f0405ea0 Revert "Feature/multiple switches per prtinter (#786)"
This reverts commit 9e81f246d8.
2026-03-23 10:11:56 +01:00
ManuelW 9e81f246d8 Feature/multiple switches per prtinter (#786)
Feature/multiple switches per prtinter (#786)
2026-03-23 10:09:14 +01:00
maziggy 27e96c9827 Fix spool assignment on empty AMS slots (#784)
Remove "Assign Spool" and "Configure" buttons from empty AMS slot
  hover popups (standard AMS and HT AMS). Assigning a spool to a
  physically empty slot created a stuck state — no unassign button
  exists for empty slots, so the assignment couldn't be removed.
  External spool holders are unaffected.
2026-03-23 09:49:26 +01:00
maziggy 89bf138473 Bump flatted 3.4.1 → 3.4.2 to fix prototype pollution
Fixes GHSA-rf6f-7fwh-wjgh (CWE-1321). Dev-only dependency via
  eslint → file-entry-cache → flat-cache → flatted.
2026-03-22 13:26:24 +01:00
maziggy 311a14e7ec Improve SpoolBuddy update UX: auto-check and remove beta toggle
The SpoolBuddy layout now auto-checks for daemon updates every 5
  minutes and shows "Update available: v{version}" in the status bar.
  Removed the beta toggle since SpoolBuddy follows Bambuddy's release
  channel. The daemon version is now read from backend APP_VERSION
  instead of a stale hardcoded string.
2026-03-22 13:15:44 +01:00
maziggy d750e8f0e0 Added Spoolbuddy frontend/backend tests 2026-03-22 12:55:35 +01:00
maziggy cf2203914d [Feature] SpoolBuddy OTA updates via Bambuddy UI
SpoolBuddy devices can now be updated from Settings → Updates without
  SSH access. The daemon picks up an "update" command via its existing
  heartbeat, runs git fetch/reset + pip install, reports progress back
  to the backend, then exits for systemd to restart with the new code.

  Backend: update_status/update_message fields, trigger + status endpoints
  Daemon: _perform_update() handler, report_update_status() API method
  Frontend: "Apply Update" button with live progress in UpdatesTab
2026-03-22 12:40:25 +01:00
maziggy d6e883652d Misc Spoolbuddy frontend fixes 2026-03-22 11:34:21 +01:00
maziggy 1b3faca4c7 Add checkboxes to select plates to queue (#777)
Multi-plate 3MF files now support selecting a subset of plates to queue
  via checkboxes, instead of the binary "one plate" or "all plates" toggle.
  In add-to-queue mode, each plate gets a checkbox for multi-select with a
  Select All / Deselect All toggle. Reprint and edit modes remain single-select.
2026-03-22 07:51:47 +01:00
maziggy 7b88b50d27 Fix AMS slot search still showing wrong preset for PLA Silk (#681)
The saved preset bypassed the search filter entirely, so when a slot's
  DB mapping was stale (e.g. previously Matte, now physically Silk), the
  old preset always appeared regardless of search query. Remove the search
  bypass — saved/current presets still bypass the printer model filter but
  must match the search text like all other presets.
2026-03-21 14:08:30 +01:00
maziggy 0db6541664 [Feature] Improve HMS error visibility on Printers page (#772)
Add visual indicators so printers with HMS errors stand out in large
  print farms:

  - Red "Problem" counter in the status summary bar
  - Status pip turns red (fatal/serious) or amber (warning) for HMS errors
  - Progress bar turns amber when a print is paused
  - Status sort prioritizes printers with HMS errors at the top
2026-03-21 09:47:50 +01:00
Thomas Rambach 2cac7d0172 Feature: Admin Set Default Nav-Menu Order (#761)
Feature: Admin Set Default Nav-Menu Order (#761)
2026-03-21 09:30:18 +01:00
maziggy dc4d77b93a [Feature] Redesign bug report debug log capture flow
Replace fixed 30-second debug log collection with an interactive
  3-step flow: start logging, reproduce the issue, stop & submit.
  Users now control timing instead of racing a countdown.

  Backend: split _collect_debug_logs() into POST /start-logging and
  POST /stop-logging endpoints; add debug_logs field to submit request.
  Frontend: 3-step progress indicator with elapsed timer, pulsing
  active state, and 5-minute auto-stop. Updated all 7 locale files.
2026-03-20 14:18:24 +01:00
maziggy e82362ac65 [Feature] Add spool rotation option for AMS drying
Add a "Rotate spool during drying" checkbox to the manual drying popover
  for AMS 2 Pro and AMS-HT units. The firmware-level rotate_tray field was
  already sent (hardcoded to false) — this makes it user-configurable.
  The checkbox defaults to unchecked and resets each time the popover opens.
  Firmware silently disables rotation if filament is currently loaded.
2026-03-20 12:14:44 +01:00
maziggy 35ce075486 [Fix] Suppress spurious "waiting for filament" notification when printers are busy (#753)
When all matching printers were busy and a job was queued with ASAP
  timing, the scheduler immediately fired a "Job Waiting for Filament"
  notification even though the job was just waiting for a printer to
  finish — no user action required.

  Added _is_busy_only() check to skip the waiting notification when the
  only reason is "Busy". Notifications still fire for actionable reasons
  (missing filament, offline, wrong color). Also renamed the default
  notification template title to "Queue Job Waiting" and updated
  descriptions across all 7 locales.
2026-03-20 11:34:23 +01:00
maziggy 664fc86e3f [Fix] File rename preserves extension in File Manager (#751)
Renaming a file in the File Manager included the extension in the
  editable text, letting users accidentally strip it and break the file.
  The rename modal now separates the base name from the extension
  (.3mf, .gcode, .gcode.3mf), showing the extension as a non-editable
  gray suffix and re-appending it on save.
2026-03-20 11:18:28 +01:00
mrtncode 7e0f52ebb0 Improve Home Assistant notifications (#750)
Improve Home Assistant notifications (#750)
2026-03-20 11:10:43 +01:00
maziggy dfb995bfe9 [Fix] Remove incorrect "Lubricate Carbon Rods" maintenance task (#755)
Carbon rods use plain bearings — lubricating them degrades print quality.
  Removed the lubrication task from defaults; only "Clean Carbon Rods"
  remains. Existing entries are auto-removed on next startup via
  ensure_default_types(). Updated wiki link mapping and tests.
2026-03-19 08:40:24 +01:00
maziggy c5a0651172 Fix AMS slot search showing unrelated filament profiles (#681)
When searching for a non-existent profile in the AMS slot config modal,
  presets matching the current slot's tray_info_idx bypassed the search
  filter, showing e.g. all "Generic PLA" variants instead of no results.
  Narrow the search bypass to only the exact saved preset — the broader
  trayIdx match still bypasses the model filter as intended.
2026-03-19 08:29:03 +01:00
maziggy 0e712c72a1 [Feature] Add quick print speed control to printer card (#256)
Add a speed control badge to the printer monitoring card controls row
  that lets users switch between Silent (50%), Standard (100%), Sport
  (124%), and Ludicrous (166%) presets during active prints. The badge
  displays a gauge icon with the current speed percentage, always visible
  but disabled when idle. Includes backend endpoint, optimistic UI
  updates, i18n for all 7 locales, and full test coverage.
2026-03-18 11:13:27 +01:00
maziggy 96966cd3d2 [Feature] Add spool name column and filter to filament inventory (#740)
Add a "Spool" column to the filament inventory table that displays
  the spool catalog entry name associated with each spool. The column
  is hidden by default and can be enabled via the column visibility
  menu. Also add a spool name filter dropdown next to the brand filter,
  shown when any spools have catalog entries assigned. No backend
  changes needed — catalog data is fetched and joined on the frontend.
2026-03-18 10:34:15 +01:00
maziggy 82d329d85c [Fix] Virtual Printer FTP routed to wrong VP with different access codes (#735)
When running multiple virtual printers with different access codes on
  separate bind IPs, FTP connections were always routed to the wrong VP.

  Root cause: the iptables REDIRECT rule (990→9990) rewrites the
  destination IP to the incoming interface's primary address. With Linux's
  weak host model (arp_filter=0), packets for secondary IPs arrive on the
  primary interface, and REDIRECT sends them all to the first VP's FTP
  server. MQTT was unaffected because port 8883 had no redirect.

  Fix: FTP server now binds directly to port 990 (standard implicit FTPS),
  eliminating the iptables redirect entirely. Requires CAP_NET_BIND_SERVICE
  (already set in the systemd service file and Docker image).

  Also removed a global asyncio set_exception_handler() in the MQTT server
  that was overwritten by each VP instance, causing spurious "Unhandled
  exception in client_connected_cb" errors on startup.

  Changes:
  - FTP_PORT: 9990 → 990 (ftp_server.py)
  - Removed set_exception_handler() from MQTT server
  - Updated Dockerfile, docker-compose.yml port mappings
  - Deprecated --redirect-990 in install script
  - Updated wiki: removed iptables instructions for all platforms
  - Added migration guide (docs/migration-vp-ftp-port.md)
  - Added unit tests for port constant and no-global-state invariant
2026-03-18 09:04:31 +01:00
maziggy dcdebef9a8 [Fix] Spool assignment UI shows wrong filament preset name (#681)
After assigning a spool to an AMS slot, the Bambuddy UI could show the
  wrong filament preset (e.g. "Bambu PLA Matte" instead of "Bambu PLA
  Silk") even though the printer was configured correctly.

  Two bugs:
  1. AssignSpoolModal (PrintersPage hover card path) never saved the slot
     preset mapping to the DB, so the display fell back to the old/stale
     mapping from a previous manual configuration.
  2. AssignToAmsModal (SpoolBuddy path) constructed the preset name from
     spool.material + spool.subtype ("PLA Silk") instead of using the
     authoritative spool.slicer_filament_name ("Bambu PLA Silk").

  Fix: the backend now saves the slot preset mapping in assign_spool()
  after successful MQTT configuration, using slicer_filament_name as the
  display name. This covers both frontend paths and ensures the correct
  name is always stored.
2026-03-18 08:12:08 +01:00
Keybored b12c51189d [Feature] Add Total cost to Projects (#733)
[Feature] Add Total cost to Projects (#733)
2026-03-18 07:52:59 +01:00
maziggy 6be5fa6632 [Fix] Camera window overlapping modals (#738)
Floating camera viewer used z-50, same as all modals, causing it to
  render on top of dialogs like Assign Spool. Lowered to z-40 so modals
  always stack above the camera window.
2026-03-17 16:40:16 +01:00
maziggy 4f617c21e1 [Fix] X1C Virtual Printer not accepting sends (#735)
X1C and X1 virtual printers used legacy SSDP model codes
  (3DPrinter-X1-Carbon, 3DPrinter-X1) that BambuStudio doesn't
  recognize, causing "incompatible printer preset" errors when
  sending prints. Changed to the correct codes (BL-P001, BL-P002)
  that real printers report via SSDP.

  Also fixed proxy mode auto-inherit storing printer display names
  (e.g. "X1C") instead of SSDP codes, by adding a resolution layer
  that maps display names to model codes.

  DB migration auto-converts existing VPs on startup.
2026-03-17 16:25:31 +01:00
maziggy fe3c1983af Add camera image rotation option (#672)
Per-printer camera rotation (0°/90°/180°/270°) for cameras mounted
  in portrait or upside-down. CSS rotation for live views, Pillow
  rotation for notification snapshots. Setting visible in external
  camera config when enabled.
2026-03-17 13:59:01 +01:00
maziggy aeae5cfa23 Reformat AMS drying presets table (#732)
Group columns by AMS type (AMS 2 Pro, AMS-HT) with inline °C and h
  unit labels next to each input instead of separate column headers.
2026-03-17 13:36:39 +01:00
maziggy a4006408a2 Fix white filament color swatches invisible in light theme (#726)
Changed filament color circle borders from border-white/20 to
  border-black/20 across all views so white spools are distinguishable
  against light backgrounds.
2026-03-17 13:08:04 +01:00
maziggy 11610a5b48 Compact assign spool modal grid layout (#725)
- Change spool list from vertical to 3-column grid (2-col on small screens)
  - Widen modal from max-w-md to max-w-2xl
  - Increase scroll area from max-h-64 to max-h-96
  - Show compact cards with name, color dot, and remaining/total weight
2026-03-17 12:40:38 +01:00
maziggy 7ab9b3e39f Fix mobile sidebar scroll, lint errors, and add tests for (#724)
- Fix mobile sidebar not scrollable when nav items exceed viewport
2026-03-17 12:31:11 +01:00
maziggy a6d307d739 Post work PR #693
Add tests, docs, and ruff fixes for per-user email notifications

  - Fix missing timezone import in email_service.py (F821)
  - Fix unused lambda arg in main.py asyncio done_callback (ARG005)
  - Fix E302 blank line spacing for mark_printer_stopped_by_user
  - Fix F821/UP037 forward reference in user_email_pref model
  - Fix SettingsPage test for duplicate "Notifications" text
  - Add backend unit tests for permissions, schemas, and templates
  - Add backend integration tests for user-notifications API
  - Add frontend tests for NotificationsPage
  - Add user_email_pref model import to test conftest
  - Update CHANGELOG and README
2026-03-17 12:24:36 +01:00