Commit Graph
669 Commits
Author SHA1 Message Date
maziggy a0705fed5a Hosekeeping 2026-04-11 09:57:19 +02:00
maziggy 6735f6d945 Housekeeping 2026-04-10 16:32:40 +02:00
maziggy b01b5e05fd Add tests, docs, and changelog for #920 + #932
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)
2026-04-10 13:09:21 +02:00
maziggy b453385d22 Add location filter tests and changelog entry for printer search (#920)
PR #920 was merged without a CHANGELOG entry and without test coverage
  for the location filter dropdown (every other new control — name
  search, model search, serial search, whitespace trim, clear button,
  status filter, empty states, combined filters — already had tests).

  Adds:
  - `filters by location via dropdown` — overrides the printers mock so
    printer 1 has location 'Workshop' and printer 2 has location
    'Office', then verifies that selecting each location shows only the
    matching printer and that switching between the two works.
  - `hides location filter when no printers have a location` — both
    printers get a null location, and the test asserts the status filter
    dropdown is still rendered but the location filter dropdown is not.
  - CHANGELOG entry under [0.2.3b3] > New Features crediting the
    contributor and documenting the search/filter feature, including the
    WebSocket-reactive status filter behavior.
2026-04-10 12:32:23 +02:00
maziggy d65d440cfb Fix external sidebar link icon missing when auth enabled (#878)
The sidebar <img> tag in Layout.tsx fetched custom external-link icons
  via a raw /api/v1/external-links/{id}/icon URL. That endpoint is
  protected by the shared camera-stream token (passed as ?token=xxx
  because <img> tags cannot send Authorization headers), so the request
  came back 401 with the "Valid camera stream token required" message.

  The edit dialog already routed through api.getExternalLinkIconUrl(),
  which wraps the URL via withStreamToken(); the sidebar now does the
  same in both the open-in-new-tab and NavLink branches.
2026-04-10 09:56:56 +02:00
maziggy 4d57c9cac4 Fix SJF toggle disappearing from queue page (#879)
The Shortest Job First toggle badge was rendered inside the Pending
  Queue section header, which only mounts when pendingItems.length > 0
  and the list view is selected. Clicking the toggle often lined up
  with the scheduler picking up the last pending item, which unmounted
  the whole section and took the toggle with it.

  Moved the toggle into the queue page header next to the list/timeline
  view switcher so it stays visible regardless of pending-item count,
  filters, or view mode. On mobile the view-mode switcher remains
  hidden (as before) but the SJF button is visible icon-only.
2026-04-10 09:48:40 +02:00
maziggy 39a5840f67 Fix camera reconnect counter off-by-one and ffmpeg log flood (#925)
Two bugs surfaced while investigating camera reconnect behaviour in #925.

  The camera page briefly displayed "Reconnecting attempt 6 of 5" before
  giving up, because the attempt counter could be incremented to the
  maximum while the reconnect banner was still rendering. The displayed
  value is now clamped to the configured maximum.

  Every failed ffmpeg spawn logged the full ~20-line ffmpeg version,
  configuration, and lib* banner, producing hundreds of lines of noise
  per failed camera click (one reported click produced 555 log lines
  across 30 retries). A new _summarize_ffmpeg_stderr helper strips the
  banner and caps output at the last 10 meaningful lines, applied at
  all three stderr log sites (immediate-failure, stream-ended,
  read-timeout). Covered by unit tests for empty input, banner
  stripping, line cap, blank-line filtering, and banner-only input.

  The underlying "camera service stops accepting connections after
  prolonged uptime" behaviour in the X1C firmware is still under
  investigation — these two fixes are independent of that root cause.
2026-04-09 11:29:57 +02:00
maziggy 848f558105 LDAP: POSIX primary group support and default fallback group
Two related LDAP authentication changes.

  Fix: POSIX primary group membership was ignored. authenticate_ldap_user
  only searched for posixGroup entries via memberUid (supplementary
  groups). A user's primary group — referenced by the gidNumber attribute
  on the user object matching gidNumber on a posixGroup — was never
  resolved, so users whose role came from their primary group landed
  without the expected permissions. The authenticator now runs a second
  search for posixGroup entries whose gidNumber matches the user's
  primary gidNumber, then dedupes DNs case-insensitively before passing
  the list to resolve_group_mapping (LDAP DNs are case-insensitive by
  spec).

  New feature: ldap_default_group setting. Settings → Authentication →
  LDAP → Advanced has a new "Default group" selector. When an LDAP user
  authenticates but is not listed in any mapped LDAP group, they are
  assigned to this fallback group instead of being left with no groups
  (and therefore no permissions). A warning is logged each time the
  fallback is applied so admins can spot missing group assignments.
  Empty setting preserves the old behavior.

  Tests: added 4 mocked authenticate_ldap_user tests covering primary
  gidNumber lookup, dedupe of overlapping memberUid+primary gid matches,
  case-insensitive DN dedupe, and the guard when a user entry has no
  gidNumber attribute. Also extended the existing parse_ldap_config tests
  to cover the new default_group field.

  Backend: ldap_service.py (primary group + dedupe + default_group
  field), schemas/settings.py (schema field), api/routes/auth.py
  (fallback wiring in _provision_ldap_user / _sync_ldap_user).

  Frontend: LDAPSettings.tsx default-group dropdown in the Advanced
  collapsible, api/client.ts type field, new i18n keys in all 7 locales
  (defaultGroup, defaultGroupNone, defaultGroupHint).
2026-04-09 10:48:42 +02:00
maziggy da080c22d3 Improve settings menu layout - 2 2026-04-09 09:52:56 +02:00
maziggy 8813de6f80 Improve settings menu layout - 1 2026-04-09 09:32:09 +02:00
maziggy 813d9dde38 Fix Spoolman location not cleared on auto-sync when spool removed from AMS (#921)
The on_ams_change auto-sync callback set locations for new spools but
  never called clear_location_for_removed_spools(), leaving stale locations
  that caused double-booked slots. Also pass synced_spool_ids in the
  single-printer sync route to match the sync-all endpoint behavior.
2026-04-09 08:16:54 +02:00
maziggy 502959a0df Fix plate-clear button unclickable after second print (#912)
The clearPlateMutation.isSuccess state from React Query persisted after
  the first successful plate clear. When the next print finished, the
  stale isSuccess rendered the static confirmation instead of the clickable
  button. Reset mutation state when printer leaves FINISH/FAILED.
2026-04-09 08:00:58 +02:00
maziggy 8f327c541a Fix filament hover card rendering behind sidebar
Bump FilamentHoverCard z-index from z-50 to z-[60] so it always
  renders above the sidebar (z-30 desktop, z-50 mobile). (#900)
2026-04-08 13:07:25 +02:00
maziggy 329223502a Spoolbuddy - fixed horizontal swiping 2026-04-08 11:59:59 +02:00
maziggy 49f3fc2964 Spoolbuddy - fixed horizontal swiping 2026-04-08 11:47:15 +02:00
maziggy 4c55eadeb6 Add SpoolBuddy quick menu with power control and system commands (#893)
Swipe down from the top of the SpoolBuddy display to open a quick-access
  menu for toggling printer smart plugs and managing the device (restart
  daemon, restart browser, reboot, shutdown). All destructive actions
  require confirmation.

  Backend: new POST /spoolbuddy/devices/{id}/system/command endpoint
  queuing reboot/shutdown/restart_daemon/restart_browser commands.
  Daemon: handles commands via subprocess (sudo reboot, systemctl restart).
  Frontend: SpoolBuddyQuickMenu component, swipe-down gesture detection,
  i18n keys for all 7 locales.
2026-04-08 11:38:50 +02:00
maziggy b76d6210cf Add SpoolBuddy quick menu with power control and system commands (#893)
Swipe down from the top of the SpoolBuddy display to open a quick-access
  menu for toggling printer smart plugs and managing the device (restart
  daemon, restart browser, reboot, shutdown). All destructive actions
  require confirmation.

  Backend: new POST /spoolbuddy/devices/{id}/system/command endpoint
  queuing reboot/shutdown/restart_daemon/restart_browser commands.
  Daemon: handles commands via subprocess (sudo reboot, systemctl restart).
  Frontend: SpoolBuddyQuickMenu component, swipe-down gesture detection,
  i18n keys for all 7 locales.
2026-04-08 11:29:44 +02:00
maziggy b6599dd419 Add LDAP/Active Directory authentication (#794)
Users can authenticate against an LDAP/AD server with configurable
  server URL, bind DN, search base, and user filter. Supports StartTLS
  and LDAPS — plaintext is not allowed. Both Active Directory (memberOf)
  and POSIX groups (memberUid) are mapped to BamBuddy groups on each
  login. Auto-provisioning creates local accounts on first LDAP login.
  Local admin accounts remain as fallback when LDAP is unreachable.
  Password management is disabled for LDAP users.
2026-04-08 10:41:27 +02:00
maziggy f3a8d5db20 Post work PR #889 2026-04-08 08:30:13 +02:00
maziggy 4c052e04e1 Fix SpoolBuddy inventory not updating on spool changes (#905)
Spool CRUD endpoints (create, bulk create, update, delete, archive,
  restore) did not emit websocket events, so SpoolBuddy Dashboard and
  other tabs relying on event-driven cache invalidation never refreshed.

  All inventory mutation endpoints now broadcast an `inventory_changed`
  websocket event. Frontend handles it by invalidating `inventory-spools`.
2026-04-07 12:32:44 +02:00
maziggy f006472f79 Add auto-print G-code injection for queue items (#422)
Per-model start/end G-code snippets configurable in Settings (Workflow
  tab). Queue items get "Inject G-code" toggle — scheduler injects
  snippets into a temp 3MF copy before FTP upload. Supports Farmloop,
  SwapMod, AutoClear, Printflow 3D and similar bed-clearing systems.
  Original files are never modified.
2026-04-05 11:14:26 +02:00
maziggy f20beae6cc Hosekeeping 2026-04-04 15:46:23 +02:00
maziggy 0ece6725bd Fix thumbnails returning 401 after backend restart
Stream tokens are stored in-memory and lost on restart. The frontend
  cached the old token for up to 50 minutes (staleTime) and never
  refetched, so all thumbnail/stream requests failed with 401 until
  a manual page reload.

  Added a global error listener in useStreamTokenSync that detects
  when img/video elements fail to load with the current stream token
  and automatically invalidates the camera-stream-token query to
  fetch a fresh one. Debounced with a 5s cooldown to avoid spamming
  when many images fail at once.
2026-04-04 12:31:39 +02:00
maziggy 039db1217d Add shortest-job-first queue scheduling with starvation guard (#879)
New SJF toggle badge on the queue page. When enabled, the scheduler
  picks shorter print jobs before longer ones instead of FIFO. A
  starvation guard flags jobs that get skipped once, moving them to
  the front on the next cycle so long jobs can't be postponed indefinitely.

  - Add print_time_seconds and been_jumped columns to PrintQueueItem
  - Cache print duration from 3MF metadata at queue item creation
  - SJF query: printer_id, target_model, been_jumped DESC, print_time_seconds ASC, position
  - Mark jumped items in-memory after each print start
  - Toggle badge on queue page header with live state indicator
  - Frontend auto-sorts to match scheduler order when SJF enabled
  - Settings schema, boolean parsing, and migration (SQLite + PostgreSQL)
  - i18n badge keys for all 7 locales
  - 10 integration tests for SJF ordering and starvation logic
  - Wiki, website, README, and changelog updated
2026-04-04 10:25:17 +02:00
maziggy 6d40ee561c Show plate number on printer cards and actual printer in queue (#881)
Printer cards and stream overlay now display the plate number when
  printing plate 2+ of a multi-plate 3MF (e.g. "MyModel — Plate 3").
  Queue items using model-based assignment ("Any P1S") now show the
  actual assigned printer name once the scheduler picks a printer,
  instead of continuing to show the generic target.
2026-04-04 09:19:31 +02:00
maziggy 0f0fac9b32 Show database engine and version on System Information page
Display the active database backend (SQLite or PostgreSQL) and its
  version in the Database section of the System Info page. SQLite queries
  sqlite_version(), PostgreSQL queries SELECT version() and
  pg_database_size(). Helps users verify which database is in use.
2026-04-04 09:05:35 +02:00
maziggy 15cd4cbb0a Fix queue widget ignoring plate-clear confirmation setting (#752)
The "Clear Plate & Start Next" button on printer cards appeared
  even when "Require plate-clear confirmation" was disabled in
  Settings. The backend correctly auto-dispatched without waiting,
  but the frontend widget always showed the prompt. Thread the
  require_plate_clear setting through PrinterCard → PrinterQueueWidget
  so the widget shows a passive queue link when the setting is off.
2026-04-03 11:47:18 +02:00
maziggy 76adf70fd4 Add separate power/energy URLs and multipliers for REST smart plugs (#472)
REST/Webhook smart plugs can now fetch power and energy data from
  individual URLs instead of requiring all values in a single status
  response. Each value falls back to the shared Status URL when no
  separate URL is set, preserving backward compatibility. Added power
  and energy multipliers for unit conversion (e.g. 0.001 for Wh→kWh).
2026-04-03 08:31:08 +02:00
maziggy 02262472f8 Fix SpoolBuddy status bar not updating on printer switch
The bottom message bar showed stale warnings from the previous printer
  after switching via dropdown or swipe. Cached AMS data was shared across
  all printers in a single ref, so switching to a printer whose status
  hadn't loaded fell back to the wrong printer's data. The Layout also
  unconditionally cleared alerts set by child pages. Fixed by keying the
  AMS cache per printer ID and only clearing Layout-owned alerts.
2026-04-02 11:34:42 +02:00
maziggy f4df4393be Add spool inventory and print archive backup to GitHub backup (#870)
GitHub backup can now optionally include spool inventory (with usage
  history) and print archive metadata as JSON. Both toggles are off by
  default. No binary files (gcode/3MF) are included.
2026-04-02 09:59:00 +02:00
maziggy 75fa935851 Fix filament color name and subtype inconsistencies (#857) 2026-04-01 12:20:12 +02:00
maziggy 3270179090 Add batch print quantity to print/schedule dialog (#342) 2026-04-01 11:55:30 +02:00
maziggy 9aa9fdc586 Add configurable default print options (#858) 2026-04-01 10:30:05 +02:00
maziggy 914adde5aa Add REST/Webhook smart plug type (#472) 2026-04-01 10:06:01 +02:00
maziggy f228a8b549 Fix sidebar bottom icons cut off when smart plugs enabled (#862) 2026-04-01 09:17:03 +02:00
maziggy 5a696f9fa3 ● Add prefer lowest remaining filament in auto-matching (#805)
When multiple AMS spools match the same type/color criteria, an optional
  setting now prefers the spool with the lowest remaining filament. This
  helps consume partial spools before starting new ones. Sorting applies
  to all matching paths: queue scheduler, print modal, and multi-printer
  mapping. Unknown remain values (-1) sort to end.
2026-03-31 14:14:15 +02:00
maziggy 3c887f5166 Add bulk printer actions toolbar (#825)
Select multiple printer cards and apply bulk actions (stop, pause,
  resume, clear notifications, clear bed) from a floating toolbar.
  Selection shortcuts: Select All, Select by State (printing/paused/
  finished/idle/error/offline), Select by Location. Action buttons are
  smart-enabled based on selected printers' current states. Confirmation
  modals for destructive actions. The status summary bar now shows all
  printer states.
2026-03-31 13:24:43 +02:00
maziggy ec0ae162e8 Add per-user statistics filtering (#730)
Admins can now filter the Statistics page by user via a new
  stats:filter_by_user permission. A user dropdown appears in the stats
  header showing all users plus "No User (System)" for prints without
  attribution. The filter applies to all stats widgets, failure analysis,
  and CSV/Excel exports. Backend validates the permission on all 4 stats
  endpoints, returning 403 if the filter is used without authorization.
2026-03-31 12:13:58 +02:00
maziggy 51b5781c0b Re-arranged settings 2026-03-31 11:27:06 +02:00
maziggy 046dbf3608 Add stagger to Print dialog, add plate-clear setting (#752)
Stagger option now available when printing directly to multiple printers,
  not just in queue mode. Prints are automatically queued with staggered
  start times using group size/interval from Settings. New "Require
  plate-clear confirmation" setting lets farm users disable per-printer
  plate confirmations so queued prints start automatically on finished
  printers.

  Also fixes settings API type parsing for require_plate_clear (boolean),
  stagger_group_size and stagger_interval_minutes (integer) — without this,
  saved values returned as strings would cause the settings toggle to
  always show enabled and trigger a permanent save loop.
2026-03-31 11:12:42 +02:00
maziggy 86693b4f75 Fix archives capped at 50 items, add pagination (#843)
The archives page only fetched the 50 most recent prints due to a
  hardcoded API limit default. Added client-side pagination with
  configurable page sizes (25/50/100/200/All) and bumped the fetch
  limit to return all archives. Page size is persisted to localStorage.
2026-03-30 08:27:34 +02:00
maziggy eaf0a1c281 Add queue timeline view, visual refresh, and fix plate thumbnail auth
Queue page redesign: compact stats bar replaces summary cards, color-
  coded left borders for status scanning, collapsible history with
  condensed rows, and a new production schedule timeline view (#823)
  showing estimated completion times grouped by hour with filter tabs
  and day navigation. i18n keys added for all 7 languages.

  Fix plate thumbnails returning 401 in print modal when auth is enabled
  (missing stream token). Fix schedule calendar picker opening off-screen
  (hidden input positioned with sr-only instead of near the date field).
2026-03-28 13:45:37 +01:00
maziggy 68dce24cc9 Add staggered batch start for multi-printer queue jobs (#752)
When adding a print to the queue for multiple printers, users can now
  enable "Stagger printer starts" to avoid power spikes from simultaneous
  bed heating. Configurable group size and interval — first group starts
  immediately (ASAP) or at scheduled time, subsequent groups get offset
  scheduled_time values. No backend queue/scheduler changes — leverages
  existing scheduled_time field.

  Also adds a dedicated Queue tab in Settings (stagger defaults + auto-
  drying moved from Filament tab), i18n keys for all 7 locales, frontend
  and backend tests.
2026-03-28 12:11:22 +01:00
maziggy a4b927f2d2 Fix SpoolBuddy add-to-inventory, dashboard crash, and kiosk display issues
- Round scale weight to integer before sending to backend (Pydantic
    rejects non-whole floats for int fields), move modal close to finally
    block, add error toast with actual API message
  - Fix null-field crash in SpoolInfoCard prop construction: pick one
    source object instead of per-field ?? fallbacks that crash when
    displayedSpool has null subtype/brand/rgba and matchedSpool is null
  - Add React ErrorBoundary to App so crashes show error instead of
    black screen
  - Remove --max-old-space-size=128 and --enable-low-end-device-mode
    from kiosk Chromium flags (crashed renderer/display)
  - Append kiosk flags to Pi GPU defaults instead of resetting them
  - Add wlr-randr keep-alive and screenBlankTimeout=0 to prevent
    display blanking on labwc 0.9.x
  - Fix tests: add ToastProvider to Dashboard test wrapper, update
    StatusBar tests for removed animate-pulse class
2026-03-28 10:51:51 +01:00
maziggy 09ebac1c09 Reduce SpoolBuddy kiosk idle CPU load from ~3.3 to ~0.9
Frontend: replace expensive idle dashboard animations (3x animate-ping
  with scale transforms, blur-2xl glow, continuous animate-pulse on
  status dots) with static NFC rings and slow 5s color-cycling spool.
  Chromium: add --disable-extensions, --disable-background-timer-throttling,
  --memory-pressure-off, --disable-renderer-backgrounding, --disable-breakpad,
  and --js-flags=--max-old-space-size=128. Install script: mask stripped
  services (not just disable) to prevent socket/dbus reactivation; use
  /etc/systemd/user/ global overrides for user services instead of
  unreliable su-based systemctl --user. Remove chromium/upower from
  strip_packages since kiosk reinstalls them immediately.
2026-03-27 14:04:11 +01:00
maziggy 3887938e8f Security: add token-based auth for all media endpoints
Camera streams, snapshots, thumbnails, timelapse videos, photos, QR
  codes, and cover images served via <img>/<video> tags were previously
  unauthenticated because browser media elements cannot send Authorization
  headers. When auth is enabled, these endpoints are now protected by a
  reusable stream token (?token=xxx) obtained from POST
  /printers/camera/stream-token (requires CAMERA_VIEW permission).
2026-03-27 12:58:08 +01:00
maziggy f9ae9f83cc Optimize SpoolBuddy kiosk performance on Raspberry Pi
Chromium: override Debian defaults via /etc/chromium.d/spoolbuddy-kiosk
  to disable GPU rasterization, enable low-end device mode, and disable
  smooth scrolling/background networking. The system default
  --enable-gpu-rasterization conflicted with per-launch flags.

  WebSocket: add React Query `select` to SpoolBuddyLayout and
  SpoolBuddyDashboard printer status queries so only `connected` is
  extracted. Temperature/fan/progress changes no longer trigger
  re-renders on every MQTT tick (~10/sec idle).

  Services: expand install script to strip pipewire, CUPS, rpcbind,
  upower, polkit, accounts-daemon, xdg-desktop-portal, mpris-proxy.
  Add user-level service masking for pipewire/portals.
2026-03-27 11:37:15 +01:00
maziggy 6b93cf806e Fix SpoolBuddy virtual keyboard layout and number input support
Virtual keyboard now participates in flex layout instead of fixed
  overlay, eliminating dead space between content and keyboard. Bottom
  nav and status bar hide when keyboard is open. Number inputs (e.g.
  Weight field on Write Tag) now accept virtual keyboard input.
2026-03-27 08:29:48 +01:00
maziggy c6f62f9cd9 Add persistent auto-off option for smart plugs (#826)
Auto-off now has a "Keep Enabled" toggle that keeps it active between
  prints instead of disabling after each use (one-shot). Useful for HA
  accessories like BentoBox filters that should always power off after
  prints. Default behavior (one-shot) is unchanged.
2026-03-27 07:50:47 +01:00
maziggy 94c6696469 Add Ukrainian Hryvnia to known currencies (#815) 2026-03-26 17:25:35 +01:00