Commit Graph
498 Commits
Author SHA1 Message Date
maziggy 150eaffe1c Fix bug report bubble overlapping toast notifications
Move the toast container from bottom-4 to bottom-20 so toast
  notifications and upload progress stack above the bug report bubble
  instead of rendering on top of each other.
2026-03-05 09:44:54 +01:00
maziggy ed462c5cca Add tests, docs, and lint fix for AMS Info Card feature (#570)
- Add 12 backend integration tests for AMS labels API (GET/PUT/DELETE,
    serial resolution, synthetic key fallback, whitespace handling, validation)
  - Add 10 frontend tests for FilamentSlotCircle component (rendering,
    border styles, background colors, text contrast inversion)
  - Fix ruff W293 trailing whitespace in inventory.py from contributor fix
  - Add ams_label model import to test conftest.py
  - Update CHANGELOG, README, website features page, and wiki AMS docs
2026-03-05 08:46:39 +01:00
maziggy 39a231514c Housekeeping 2026-03-04 14:08:27 +01:00
maziggy 058f74a7da Add in-app bug reporting with relay, debug log collection, and privacy controls
Floating bug report button submits issues via bambuddy.cool relay (no GitHub
  token needed locally). Collects 30s debug logs with printer push_all, sanitizes
  all sensitive data, uploads logs as files to GitHub. Screenshot upload/paste/drag
  with JPEG compression. Translated into all 7 languages. Includes 21 tests.
2026-03-04 13:33:19 +01:00
maziggy 4c81a92175 Post work PR #581 2026-03-04 10:29:55 +01:00
MartinNYHC ba2abe100d Merge branch '0.2.2b1' into refactor-utils 2026-03-04 10:21:34 +01:00
maziggy 6388b0df9b Show ethernet indicator instead of WiFi signal for wired printers (#585)
Parse home_flag bit 18 (0x00040000) from MQTT to detect ethernet
  connections. When set, the printer card shows a green "Ethernet"
  badge with a cable icon instead of WiFi signal strength in dBm.
  The printer info modal also displays "Ethernet" instead of WiFi
  signal details.
2026-03-04 09:44:08 +01:00
AneoPsy abe40f1ed0 Consolidate duplicate utility functions into shared modules
Extract repeated helper functions from components into shared utils
(colors.ts, date.ts, file.ts) to reduce duplication:
- isLightColor, parseFilamentColor, hexToColorName → utils/colors.ts
- formatMediaTime, formatDurationFromHours → utils/date.ts
- formatFileSize guard hardened for NaN/negative → utils/file.ts
- formatBytes (ToastContext), formatTime (Timelapse*) deduplicated

Functions with subtly different behavior are intentionally kept local
(formatFilament, formatStorageSize, formatBytes, formatUptime,
formatDateTime, formatDate, formatTimeAgo) to preserve exact UI output.
2026-03-03 04:20:21 -10:00
AneoPsy 15521deb0a Refactor date and currency utility functions
- Extract shared detectSystemDateFormat() helper to eliminate
  duplicated system locale detection in date.ts
- Derive SUPPORTED_CURRENCIES from CURRENCY_SYMBOLS map instead
  of maintaining a duplicate hardcoded list
- Consolidate redundant time-parsing regex paths into one
- Use applyTimeFormat() consistently in formatETA()
- Add exhaustive switch default for type safety
2026-03-03 03:45:12 -10:00
maziggy 19a1a7584b Fix archive card showing "Source" badge for sliced .3mf files
The isSlicedFile() check only matched .gcode or .gcode.3mf extensions,
  so archives from .3mf prints (the standard Bambu slicer output) showed
  a "SOURCE" badge instead of "GCODE". Since .3mf can be either sliced or
  a raw CAD export, now checks the archive's total_layers and
  print_time_seconds metadata to distinguish them. Also passes the
  original filename when creating archives from file manager prints.
2026-03-03 14:26:03 +01:00
maziggy 6b92a99dd8 Improve FTP upload progress and widen print modal
FTP upload: reduce chunk size from 1MB to 64KB for smooth progress bar
  updates (~1s intervals instead of 20+ second gaps). Skip voidresp() for
  all printer models — H2D delays the 226 response by 30+ seconds after
  data transfer, causing a hang at 100%. Add transfer speed and TLS
  handshake timing to logs for diagnosing slow connections.

  Print/Schedule modal: widen from max-w-lg (512px) to max-w-2xl (672px)
  to accommodate long filament profile names like "PLA Support for PETG
  PETG Basic @Bambu Lab H2D 0.4 nozzle".
2026-03-03 14:14:26 +01:00
maziggy 330d77198a Fix AMS slot showing wrong material for "Support for" profiles
Profiles like "PLA Support for PETG PETG Basic @Bambu Lab H2D" have
  filament_type PETG, but both the frontend and backend name parsers
  found "PLA" first (iterating material types in order). The MQTT command
  sent tray_type=PLA and tray_info_idx=GFL99 (PLA generic), so the
  slicer displayed PLA instead of PETG.

  - Frontend parsePresetName(): detect "X Support for Y" pattern, extract
    material after "Support for"
  - Frontend ConfigureAmsSlotModal: prefer corrected parsed material over
    stored localPreset.filament_type for tray_type, tray_info_idx, and
    temperature fallback
  - Backend _parse_material_from_name(): same "Support for" handling for
    future profile imports
  - Backend assign_spool: prioritize spool.material over lp.filament_type
    for generic filament ID lookup
2026-03-03 13:34:03 +01:00
maziggy 23b2d97170 Add Hungarian Forint (HUF) currency for filament cost tracking
Closes #579 — adds HUF with symbol "Ft" to the supported currencies
  list so Hungarian users can track filament costs in their local currency.
2026-03-03 12:10:29 +01:00
maziggy 2a740c52eb Reverted commit d4aa77f502 2026-03-03 11:26:39 +01:00
maziggy f45f3b0500 Post work PR #569 2026-03-03 10:49:18 +01:00
AneoPsyandMartinNYHC fa9d3779cc [Feature]: Printer Page - Add a print button & Drop zone on the printer card (#569)
* Add printer card print flow with drag-drop and reusable LibraryUploadModal

Extract inline upload modal from FileManagerPage into a reusable
LibraryUploadModal component. Add a Print button and drag-drop zone
to printer cards that upload files to the library and open PrintModal
with the printer pre-selected. Only .gcode/.gcode.3mf files are
accepted for printing. PrintModal hides printer selector when a
printer is provided via initialSelectedPrinterIds prop.

* Add printer compatibility check for drag-drop and upload-to-print flows

Validates sliced_for_model from file metadata against the target printer model
before opening the print modal, preventing users from printing with incompatible files.

* Improve FileUploadModal: auto-close on success, inline errors, file validation, and i18n

- Close modal automatically after successful upload instead of showing summary
- Show printer compatibility errors inline in the modal instead of closing
- Add validateFile and accept props to restrict file types for print flow
- Add onFileUploaded error return to prevent modal close on incompatible files
- Internationalize all hardcoded error/warning strings across 6 locales

* Clean up incompatible files from library and fix print button i18n

- Delete uploaded file from library when printer compatibility check fails
  in both drag-drop and modal upload flows
- Fix print button tooltip to use existing common.print i18n key
- Fix accept attribute to use .gcode,.3mf for proper browser support

* Add printer information modal accessible from card 3-dot menu

Replace inline IP/serial display at bottom of printer card with a
dedicated "Printer Information" modal opened via the card menu. The
modal shows model, status, state, IP address (copyable), serial number
(copyable), WiFi signal, firmware, developer mode, nozzle count, SD
card, auto-archive, total print hours, location, and added date, along
with the printer image. Includes full i18n support across all 6 locales
and accessibility attributes (role="dialog", aria-modal).

* Extract getPrinterImage and getWifiStrength into shared printer utils

---------

Co-authored-by: MartinNYHC <mz@v8w.de>
2026-03-03 10:26:30 +01:00
maziggy 0918c57928 Add i18n keys for printer card drag-drop print overlay
PR #569 introduces drag-drop printing on printer cards with
  inline fallback strings for common.uploading, common.uploadFailed,
  printers.dropToPrint, and printers.cannotPrint. Add these keys
  to all 7 locale files so they render in the correct language.
2026-03-03 10:22:15 +01:00
maziggy 9cdda80849 Added Simplified Chinese translation zh-CN (Issue #571) 2026-03-03 09:51:07 +01:00
maziggy f943420ea2 Add SpoolBuddy NFC tag writing with OpenTag3D format
Write NTAG213/215/216 tags for third-party spools via the SpoolBuddy
  kiosk UI. New "Write" page with three workflows: existing spool, new
  spool creation, and tag replacement. Backend encodes 133-byte OpenTag3D
  NDEF payloads (material, color, brand, weight, temp). Daemon writes
  page-by-page via PN5180 NTAG WRITE command with read-back verification.
  Write commands flow through heartbeat polling with WebSocket status
  updates. Includes 39 new tests and translations for all 6 languages.
2026-03-02 13:56:15 +01:00
maziggy e1795ff3b7 Add printer status badges, remove SpoolBuddy inventory page
- Add printer status badges to dashboard left column (green/gray
    online/offline dots, compact wrapping pills, overflow-hidden)
  - Remove SpoolBuddy inventory page — inventory management belongs
    in the main Bambuddy frontend, not the kiosk
  - Remove inventory nav item from bottom nav (now 3 tabs)
  - Replace "Add to Inventory" navigate with quick-add modal that
    creates a basic PLA spool entry via API, with a hint to use
    the main Bambuddy UI for full spool details instead
2026-03-02 13:04:36 +01:00
maziggy 628a814271 Redesign SpoolBuddy settings page, add language/time format support
- Redesign settings page with tabbed layout (Device, Display, Scale, Updates)
  - Add screen blank timeout: blanks after touch inactivity, tap to wake
  - Add CSS brightness filter for HDMI displays (no sysfs on HDMI)
  - Add backend `language` field to app settings for server-side persistence
  - Sync UI language from backend on kiosk load (separate Chromium instance)
  - Top bar clock respects user's time format setting (system/12h/24h)
  - Add SpoolBuddy settings translations for all 6 languages (en/de/fr/ja/it/pt-BR)
  - Disable Chromium swipe-to-navigate in kiosk install script
  - Add `video` group for DSI backlight access
2026-03-02 12:44:45 +01:00
maziggy 48b492f619 Spoolbuddy
1. Device tab — repo URL unlinked

  Replaced the <a> tag with a <span> so the GitHub URL is displayed as plain text (no clickable link in kiosk mode).

  2. Display controls — moved to frontend

  Root cause: The daemon runs as a system user without Wayland access, and the kiosk uses an HDMI display (no sysfs backlight). Neither wlopm, vcgencmd, nor sysfs writes
  can work in this setup.

  Fix — frontend-controlled display in SpoolBuddyLayout.tsx:
  - Brightness: CSS filter: brightness(X) applied to the layout root. Immediate visual dimming that works on any display type.
  - Screen blanking: Full-screen black overlay (z-[9999]) shown after the configured inactivity timeout. Touch anywhere to wake.
  - Activity tracking: Resets on pointerdown/keydown events AND on WebSocket-driven NFC/scale changes (weight update, tag scan).
  - Queries device data every 15s to read the current brightness and blank timeout values.

  Daemon display_control.py — Simplified:
  - Removed vcgencmd/wlopm/subprocess usage entirely
  - _blank/_unblank are now state-tracking no-ops (log only)
  - DSI backlight brightness via sysfs is preserved as a bonus for DSI displays
  - Updated docstring to explain the architecture

  3. Scale tab — redesigned with step indicator

  Idle state: Same as before — weight card with tare/calibrate buttons.

  Calibration wizard: Two-column layout:
  - Left column (~64px): Vertical step indicator with numbered circles, checkmark for completed steps, and a connecting line
  - Right column: Live weight bar (with stable/settling indicator), step-specific content (instructions or numpad), and action buttons pinned to bottom via mt-auto

  The numpad buttons are min-h-[52px] with text-lg — large enough for touch on 1024x600. The weight info card is hidden during the weight entry step to maximize vertical
  space.
2026-03-02 11:58:10 +01:00
maziggy 28fda7b1a0 Display Controls (brightness + blanking)
Root cause: The daemon used wlopm for screen blanking, but wlopm was never installed. Additionally, the daemon runs as the spoolbuddy system user which has no access to
   the Wayland socket, so Wayland-based tools can't work.

  Fix in display_control.py:
  - Replaced wlopm --off/--on with vcgencmd display_power 0/1 — this is a Raspberry Pi firmware-level command that's pre-installed and works without Wayland socket access
  - Added shutil.which("vcgencmd") check at init to avoid repeated failures on non-RPi hardware
  - Added explicit PermissionError handling for brightness writes with a helpful message about the video group

  Fix in install.sh:
  - Added video group to the spoolbuddy service user's groups (was: gpio, spi, i2c → now: gpio, spi, i2c, video), which grants access to both vcgencmd and sysfs backlight
   files

  Scale Tab Numpad

  Root cause: On the 1024x600 kiosk screen (~376px available content height), the weight info card + numpad + action buttons exceeded the space, causing tiny buttons and
  overlapping.

  Fix in SpoolBuddySettingsPage.tsx:
  - Hide the weight info card during weight entry step (calStep !== 'weight'), reclaiming ~70px
  - Compact inline weight reading in the step header (small dot + monospace text) so users can still see the live scale value
  - Larger numpad buttons: min-h-[56px] with text-lg font size (was no min-height, text-sm)
  - Added active:scale-95 for tactile touch feedback
  - mt-auto on action buttons to push them to the bottom, preventing overlap
  - Removed the wrapping card around the calibration flow to save vertical padding
2026-03-02 11:40:45 +01:00
maziggy f2d28a0ef8 Spoolbuddy frontend fixes 2026-03-02 11:22:52 +01:00
maziggy bffbac54e4 Add on-screen virtual keyboard for SpoolBuddy kiosk UI
The Raspberry Pi kiosk has no physical keyboard and system-level virtual
  keyboards (squeekboard, wvkbd) don't auto-show/hide with labwc/Chromium.
  Add a react-simple-keyboard QWERTY keyboard that auto-shows on input
  focus, with dark theme, shift/caps/backspace, email keys (@, .), and a
  two-phase close that prevents ghost-click passthrough to elements below.
  Inputs with data-vkb="false" opt out (e.g. SpoolBuddySettingsPage numpad).
2026-03-02 10:20:22 +01:00
maziggy 8b36a129b7 Fix SpoolBuddy AMS page fill levels, ext-R active bug, and layout
- Show inventory-based fill levels for non-BL spools in AMS slots by
    fetching spool assignments and computing fill from weight_used/label_weight,
    falling back to AMS remain when no assignment exists
  - Fix ext-R slot falsely highlighted as active when idle: tray_now=255
    (no tray loaded) matched ext-R's id=255 without a guard
  - Improve single-slot card layout: use responsive grid aligned with AMS
    card columns, fix vertical stretching with few AMS units
  - Remove redundant L/R nozzle badges from ext slots (label already shows
    Ext-L/Ext-R)
  - Add 16 tests for ext active state logic and fill override fallback
2026-03-02 09:31:56 +01:00
maziggy a5016432df Fix SpoolBuddy tag_type for linked spools + add inventory weight check column
SpoolBuddy's "Link to Spool" used the generic updateSpool API which only
  set tag_uid, leaving tag_type and data_origin empty. Now uses linkTagToSpool
  with tag_type='generic' and data_origin='nfc_link'.

  Added a "Weight Check" inventory column (hidden by default) that compares
  each spool's last scale measurement against calculated gross weight with
  ±50g tolerance. Shows green check for match, yellow warning + sync button
  for mismatch. Backend stores last_scale_weight and last_weighed_at on each
  spool when weight is synced via SpoolBuddy. Includes edge case handling
  when scale weight < core weight. i18n keys added for all 6 locales.
2026-03-02 08:29:22 +01:00
maziggy 8f103f38ea Add daily beta build publish script
Automates the full beta release workflow: version bump in config.py,
  CHANGELOG date update, git commit + tag, multi-arch Docker build+push
  to GHCR and Docker Hub, and GitHub prerelease creation with changelog
  notes. Supports --parallel, --ghcr-only, --dockerhub-only, and
  --skip-release flags. Documents daily beta builds in README and
  DOCKERHUB.md.
2026-03-01 18:11:02 +01:00
maziggy 7fab96ee6d Fix printer card losing print info when paused (#562)
The printer card only showed progress bar, print name, ETA, layers,
  and cover image when gcode_state was RUNNING. A paused print (state
  PAUSE) fell through to the idle display, hiding all print context.
  Added PAUSE to the display conditions in both compact and expanded
  view modes, and replaced the hardcoded "Printing" status label with
  getStatusDisplay() so it correctly shows "Paused".
2026-03-01 15:13:40 +01:00
maziggy 42eb19afce Fix SpoolBuddy "Assign to AMS" slot showing empty fields in slicer
The assign_spool endpoint sent wrong MQTT field values for user presets,
  causing the slicer's AMS slot detail card to show all fields empty.

  Two bugs: (1) cloud API was called with the raw slicer_filament value
  including its version suffix (e.g. PFUS9ac902733670a9_07), returning 404;
  the silent fallback sent setting_id as tray_info_idx instead of the real
  filament_id; (2) no SlotPresetMapping was saved after assignment.

  Now strips version suffixes before cloud lookup, resolves the real
  filament_id via cloud API (with local preset and generic fallbacks),
  includes brand in tray_sub_brands, and saves slot preset mapping.
2026-03-01 14:51:29 +01:00
maziggy bf66f7a536 Added delete tag button to inventory's edit spool modal 2026-03-01 12:04:19 +01:00
maziggy 1cf40a5c35 Redesign SpoolBuddy dashboard: inline spool cards, full-screen AMS assign modal, filament ID normalization
- Replace TagDetectedModal with inline SpoolInfoCard/UnknownTagCard
    in dashboard right panel (known spools show assign/sync/close,
    unknown tags show add-to-inventory/link/close)
  - Rewrite AssignToAmsModal as full-screen overlay reusing AmsUnitCard,
    with AMS-HT and external slot support, single assignSpool API call
  - Remove printer selector from assign modal (uses top bar selection)
  - Extract filament_id <-> setting_id conversion to shared utility
    (backend/app/utils/filament_ids.py), used by inventory + cloud routes
  - Normalize slicer_filament in assign_spool to derive proper
    tray_info_idx and setting_id for MQTT (was sending setting_id="")
  - Rename SpoolBuddy top bar status label "Online" -> "Backend"
  - Remove weightStable guard from sync weight button
2026-03-01 11:56:52 +01:00
maziggy aa59e0028e Separate firmware and software sections in Updates settings card
The Updates card on the Settings page mixed printer firmware and
  Bambuddy software update toggles with no visual distinction. Now
  groups them into labeled sections ("Printer Firmware" at top,
  "Bambuddy Software" below) with a divider between them.
2026-03-01 08:21:52 +01:00
maziggy 65c904b231 Fix sidebar navigation not respecting user permissions
Sidebar nav items (Archives, Queue, Stats, Profiles, Maintenance,
  Projects, Inventory, Files) were visible to all users regardless of
  role permissions — only Settings was gated. Now each item is hidden
  when the user lacks the corresponding read permission. Printers
  remains always visible as the home page.

  Also adds missing inventory:read|create|update|delete to the frontend
  Permission type (existed in backend but was absent from the frontend
  type definition).
2026-02-28 13:07:54 +01:00
maziggy 1eeeb37b42 Updated commit message (now includes the test fix):
Fix camera button permissions & ffmpeg process leak (#550)

  Camera button on printer card was clickable without camera:view
  permission. ffmpeg processes (~240MB each) accumulated after closing
  camera streams because: (1) stop endpoint called terminate() without
  wait()/kill(), (2) HTTP disconnect detection only ran between frames
  so was blocked when the generator was stuck on stdout read, and
  (3) no mechanism caught processes orphaned by generator abandonment
  or app restarts.

  - Add camera:view permission check + tooltip to camera button
  - Fix stop endpoint: terminate() → wait(2s) → kill() → wait()
  - Add background disconnect monitor (polls every 2s, kills ffmpeg
    directly on disconnect)
  - Add periodic /proc scan (every 60s) that SIGKILLs any ffmpeg
    with rtsps://bblp: not in an active stream
  - Add noCamera i18n key to all 6 locales
  - Fix camera API test mocks for async wait() and pid attribute
2026-02-28 12:58:31 +01:00
maziggy ce97a47627 Add H2C dual nozzle variant O1C2 model support (#489)
The H2C dual nozzle variant reports model code O1C2 via MQTT, but only
  O1C was recognized. This caused the camera to use the wrong protocol
  (chamber image on port 6000 instead of RTSP on port 322), producing a
  reconnect loop. Added O1C2 to all model ID maps across 8 files.
2026-02-28 11:53:38 +01:00
maziggy 04e64ffde1 Fix SpoolBuddy scale tare & calibration not being applied
The tare and calibrate buttons on the Settings page queued commands
  but never executed them due to five broken links:

  1. Daemon received tare command but never called scale.tare()
  2. No endpoint to persist tare offset back to backend DB
  3. Heartbeat never called scale.update_calibration()
  4. Heartbeat response with stale values overwrote new tare to zero
  5. set-factor used DB tare_offset (stale/zero), producing wrong
     calibration factor — empty scale showed ~5000g

  Fixed daemon to execute tare, persist result, and propagate
  calibration. Calibration step now captures raw ADC at tare time
  and sends it with step 2, making factor computation self-contained.

  Replaced calibration weight input with compact touch numpad for
  the RPi kiosk's 1024x600 touchscreen (no physical keyboard).
2026-02-28 09:51:51 +01:00
maziggy 49ddb570cc Fix SpoolBuddy scale tare & calibration not being applied
The tare and calibrate buttons on the Settings page queued commands
  but never executed them due to four broken links:

  1. Daemon received tare command via heartbeat but never called
     scale.tare() — the ScaleReader was available in shared dict
     but unused
  2. No API endpoint for the daemon to report the new tare offset
     back to the backend DB, so tare results were lost
  3. Heartbeat updated config but never called
     scale.update_calibration(), so ScaleReader kept initial values
  4. The heartbeat response delivering the tare command still had
     pre-tare values, immediately overwriting the new offset to zero

  Added set-tare endpoint + API client method, and fixed heartbeat
  loop to execute tare, persist the result, propagate calibration
  changes to the ScaleReader, and skip calibration sync on the
  heartbeat cycle that delivers a tare command.

  Also replaced the calibration weight input with a touch-friendly
  numpad since the RPi kiosk has no physical keyboard.
2026-02-28 09:39:11 +01:00
maziggy 7767851975 Add SpoolBuddy tag detection modal and fix NFC reader silent failure
Frontend: Replace inline SpoolInfoCard/UnknownTagCard with full-screen
  TagDetectedModal that auto-opens on NFC tag detection. Known spools show
  remaining weight, fill bar, and offer "Assign to AMS" (new sub-modal with
  printer selector + AMS slot grid) and "Sync Weight". Unknown tags offer
  "Add to Inventory" and "Link to Spool". Modal stays open on tag removal,
  won't re-open for dismissed tags, reopens on re-place after removal.

  Daemon: Fix PN5180 NFC reader silently stopping tag detection when the
  reader drifts into a stuck state. Add auto-recovery (full hardware reset
  after 10 consecutive errors), preventive RF cycling every 60s when idle,
  and periodic status logging. Heartbeat now reports actual nfc_ok/scale_ok
  from reader instances instead of hardcoded True.
2026-02-28 08:54:39 +01:00
maziggy 7eb7bf7b93 Fix queue badge showing on printers without matching filament (#486)
The purple queue counter badge in the printer card header used the raw
unfiltered queue item count, so it appeared on ALL printers of the same
model when a job was scheduled for "any [model]" — even printers without
the matching filament color. The PrinterQueueWidget below it (which
shows "Clear Plate & Start") already filtered by filament type + color.

Apply the same filament compatibility filter (type check + color override
check) to the badge count so it only shows on printers that can actually
run the queued jobs.
2026-02-28 07:28:14 +01:00
maziggy 0200c5d92f SpoolBuddy touch-friendly UI overhaul for 1024x600 kiosk display
Enlarge all interactive elements across 9 SpoolBuddy components to meet
44px minimum tap targets on the RPi touchscreen. Increase nav icons
(20→24px), labels (10→12px), bar heights, section headers, printer
buttons, spool visualizations, fill bars, and status indicators.
Compact the dashboard stats bar and remove the printers card. Add
fullScreen prop to ConfigureAmsSlotModal with two-column layout
(filament list left, K-profile + color right) to eliminate scrolling.
2026-02-27 13:34:20 +01:00
maziggy 42b07d8bfd Add API key auth support to /auth/me for SpoolBuddy kiosk
When Bambuddy auth is enabled, the SpoolBuddy kiosk gets redirected to
the login page because ProtectedRoute requires a user from GET /auth/me,
which only handled JWT tokens. The kiosk daemon already has an API key
but couldn't use it to satisfy the frontend auth check.

- Backend: /auth/me now accepts API keys (Bearer bb_xxx or X-API-Key)
  and returns a synthetic admin UserResponse with all permissions
- Frontend: AuthContext reads ?token= from URL on first load, stores in
  localStorage, and strips from URL (prevents history/referrer leakage)
- Install script: kiosk URL now includes ?token=${API_KEY}
- Tests: 3 new integration tests (Bearer API key, X-API-Key header,
  invalid key rejection)
2026-02-27 13:34:19 +01:00
maziggy 8c9c0a7994 Minor Spoolbuddy frontend improvements 2026-02-27 13:33:47 +01:00
maziggy 46f209e2ac Add SpoolBuddy AMS slot config, external slots, and dashboard redesign
- AMS page: external spool slots (Ext/Ext-L/Ext-R), click-to-configure
  modal on all slots, temperature/humidity threshold-colored indicators,
  nozzle L/R badges for dual-nozzle printers, compact AMS-HT layout
- Dashboard: two-column layout with device status + printers list (left)
  and current spool card (right), state-colored scale/NFC icons, dashed
  border card styling
- Daemon: suppress redundant scale reports (±2g threshold + stability
  state change detection) to prevent weight display bouncing
- TopBar: auto-select online printers only, SpoolBuddy logo
2026-02-27 13:31:48 +01:00
maziggy 94d0f55e1c Fix AMS history chart showing wrong time range (#535)
The chart X axis used dataMin/dataMax domain, compressing the view to
only the data present. A 6h view with 1.5h of data looked like 1.5h.
Pin the X axis to the full selected time range, pad data edges so the
line extends to both ends, and connect through nulls for a continuous
line.
2026-02-27 08:44:24 +01:00
maziggy ad6108c8a7 Fix "Clear Plate" button shown on printers without matching filament color (#486)
When a print was queued to "any printer" with a filament color override
(e.g., white PETG), the "Clear Plate & Start Next" button appeared on
printers that had the right type but wrong color. The backend scheduler
already rejected color mismatches, but the frontend only checked filament
types. Now passes loaded type+color pairs from AMS status to the widget
and filters against filament_overrides, mirroring the backend's
_count_override_color_matches() logic.
2026-02-27 08:03:21 +01:00
maziggy 4f5a9f4b95 Fix spool form profile dropdown truncating long preset names (#534)
Long filament profile names were cut off because inline filament ID
codes consumed horizontal space in the dropdown. Remove the codes from
dropdown items (selected code still shown below the input) and widen
the modal from max-w-lg to max-w-xl.
2026-02-27 07:30:03 +01:00
maziggy f4f09ccc2d Hide unnecessary target model selector on "Any" tab (#528)
When scheduling a print to "Any {model}", a redundant "Target Model"
dropdown appeared even though the G-code is already sliced for a
specific printer model. Changing it would lead to print failures.

Hide the dropdown when slicedForModel is known — the tab label already
communicates the target. The dropdown still appears as a fallback for
legacy files without model metadata.
2026-02-26 09:13:06 +01:00
maziggy 20c291d678 Fix "Clear Plate & Next" shown on printers without correct filament (#527)
The "Clear Plate & Start Next" button appeared on ALL printers of a
model when a job was queued via "Queue to Any X", even printers without
the required filament loaded. Clicking it started a print that fails.

PrinterQueueWidget now filters queue items by filament compatibility —
each item's required_filament_types must all be present in the printer's
loaded filaments (AMS + external spools). If no compatible items exist,
the widget is hidden entirely. Matching is type-only (not color) and
case-insensitive, consistent with the backend scheduler. When filament
data is unavailable, no filtering is applied (graceful degradation).
2026-02-26 08:57:39 +01:00
maziggy 1973a5bead Fix virtual printer queue mode not assigning printer (#518), settings text fields resetting mid-typing
Virtual printer "print_queue" mode created queue items with no printer
assignment. Now sets target_model from the VP's SSDP model code (e.g.
P1S, X1C) for "Any Printer" scheduling, or uses target_printer_id if
configured.

Settings page auto-save onSuccess overwrote localSettings with the
server response, discarding characters typed during the save request.
Removed the stale state overwrite so in-progress input is preserved.
2026-02-26 08:06:56 +01:00