Commit Graph
520 Commits
Author SHA1 Message Date
maziggy e4bdddcde1 Housekeeping 2026-03-09 12:35:05 +01:00
maziggy ec8b1f935d Fixed frontend/src/__tests__/utils/currency.test.ts 2026-03-09 12:35:05 +01:00
maziggy 1a4f56d853 Show filament subtypes in all mapping dropdowns (#624)
All filament mapping dropdowns (single-printer, multi-printer, and
  "Print to Any" model-based) showed only the base material type (e.g.
  "PLA") without distinguishing subtypes like "PLA Basic" vs "PLA Matte",
  making entries with different subtypes but same color look identical.

  Backend: Add tray_sub_brands to available-filaments response and include
  it in the dedup key so different subtypes of the same color appear as
  separate entries.

  Frontend: Show tray_sub_brands in FilamentMapping, FilamentOverride, and
  PrinterSelector dropdowns, falling back to base type when unset. Add
  traySubBrands field to LoadedFilament interface.
2026-03-09 12:35:05 +01:00
maziggy 5632368490 fix: remove incorrect ethernet badge on printer cards
home_flag bit 18 was incorrectly interpreted as "wired/ethernet
  connection", causing the ethernet badge to always show — even on
  printers without an ethernet port (e.g. A1, P1S). This hid the
  WiFi signal indicator entirely.

  Removed the wired_network field and ethernet badge UI. The WiFi
  signal badge now shows correctly whenever the printer reports
  signal strength.
2026-03-09 12:33:23 +01:00
maziggy 121b3d53df fix: remove incorrect ethernet badge on printer cards
home_flag bit 18 was incorrectly interpreted as "wired/ethernet
  connection", causing the ethernet badge to always show — even on
  printers without an ethernet port (e.g. A1, P1S). This hid the
  WiFi signal indicator entirely.

  Removed the wired_network field and ethernet badge UI. The WiFi
  signal badge now shows correctly whenever the printer reports
  signal strength.
2026-03-09 12:16:22 +01:00
d7401a80df Feature: Force Color Match (#625)
* Added "Force Color Match" feature to filament override

* Update settings.py

* Update settings.py

* Label updates for warnings and checkbox case

* Initial plan

* Add noMatchingMaterial i18n translations to all 7 locale files

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Updates for PR#625 comments

* Added "Force Color Match" feature to filament override

* Update settings.py

* Update settings.py

* Label updates for warnings and checkbox case

* Initial plan

* Add noMatchingMaterial i18n translations to all 7 locale files

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Use {{material}} interpolation in noMatchingMaterial; populate from filament_overrides with getColorName

Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>

* Updates to PrintersPage and QueuePage

* Update QueuePage.tsx

* Rebase to 0.2.2b3

* Fix compile errors with FilamentOverride

* Updates for PR#625 comments

https://github.com/maziggy/bambuddy/pull/625#pullrequestreview-3908738261

* Fix force color match default, loadedFilamentTypes bug, remove dead translations

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: cadtoolbox <12723486+cadtoolbox@users.noreply.github.com>
Co-authored-by: MartinNYHC <mz@v8w.de>
2026-03-09 11:54:02 +01:00
maziggy d225421c6d Fixed frontend/src/__tests__/utils/currency.test.ts 2026-03-07 14:13:12 +01:00
maziggy 9f4d8e126a Show filament subtypes in all mapping dropdowns (#624)
All filament mapping dropdowns (single-printer, multi-printer, and
  "Print to Any" model-based) showed only the base material type (e.g.
  "PLA") without distinguishing subtypes like "PLA Basic" vs "PLA Matte",
  making entries with different subtypes but same color look identical.

  Backend: Add tray_sub_brands to available-filaments response and include
  it in the dedup key so different subtypes of the same color appear as
  separate entries.

  Frontend: Show tray_sub_brands in FilamentMapping, FilamentOverride, and
  PrinterSelector dropdowns, falling back to base type when unset. Add
  traySubBrands field to LoadedFilament interface.
2026-03-07 14:08:38 +01:00
maziggy 6b12c685aa Add queue-all-plates and fix clear plate prompt for staged items (#530)
Multi-plate 3MF files can now be queued in one action via a "Queue All
  Plates" toggle in the plate selector (add-to-queue mode only). Each
  plate becomes a separate queue entry, individually editable.

  Fix: "Clear Plate & Start Next" no longer appears when all pending
  queue items are staged (manual_start). The prompt only shows when
  there are auto-dispatchable items the scheduler will actually start.
2026-03-07 12:51:07 +01:00
maziggy b3c37072b2 Add auto-dispatch toggle for virtual printer queue mode (#587)
Virtual printers in Queue mode now have an "Auto-dispatch" setting.
  When enabled (default), prints start automatically — preserving current
  behavior. When disabled, prints are added with manual_start so they
  wait for manual dispatch from the queue UI.
2026-03-07 11:41:01 +01:00
maziggy a7ddc483b3 Add bulk delete for spool and color catalog entries (#646)
Checkbox selection + "Delete Selected" button in Settings > Filament
  for both Spool Catalog and Color Catalog. Adds POST bulk-delete
  endpoints and translations for all 7 locales.
2026-03-07 10:13:40 +01:00
maziggy d55585a73f Fix P2S showing carbon rod maintenance tasks (#640)
P2S uses hardened steel rods, not carbon fiber. Move P2S from
  carbon rod classification to new steel_rod category with its own
  "Lubricate Steel Rods" / "Clean Steel Rods" maintenance tasks.
2026-03-07 09:45:14 +01:00
maziggy f66bd26f6e Add inventory:view_assignments permission so admins can grant users
visibility into AMS spool assignments on printer cards without exposing
  the full Inventory page (#635). The list_assignments endpoint now
  requires this new permission instead of inventory:read. All default
  groups (Administrators, Operators, Viewers) include it for backward
  compatibility.

  Closes #634
2026-03-07 09:17:26 +01:00
maziggy 60b17ea5d8 Added MYR (Malaysian Ringgit) with the symbol RM to the currency list 2026-03-07 08:59:51 +01:00
maziggy e1e4ec224c Fix dispatch toast stuck after second print dispatch
The print dispatch progress toast stayed visible forever after the
  second print in a session. lastDispatchSummaryRef was never reset
  between batches — every single-printer dispatch produced the same
  summary key ("first-complete:1:0"), so subsequent completions matched
  the stale ref and skipped creating the done toast.

  Reset the dedup guard when the dispatch toast is dismissed and when
  a new batch starts.
2026-03-06 16:50:04 +01:00
maziggy c0625422a4 Moved toast messages 2026-03-06 14:50:53 +01:00
maziggy b631713fff Keep dispatch toast visible for 3s after print upload completes (#615)
The print dispatch notification disappeared instantly for small files or
  closed immediately when the progress bar reached 100%, giving no
  confirmation that the job was submitted. The dispatch toast now stays
  visible for 3 seconds showing the completion message before auto-
  dismissing. For very fast uploads where no progress toast was shown,
  a fresh confirmation toast is created instead.
2026-03-06 14:39:36 +01:00
maziggy a010134c09 Disable busy printers in print modal's reprint mode (#622)
When printing from the file manager, the print modal showed all printers
  including busy ones. Selecting a busy printer resulted in a failed send.
  The printer selector now fetches live status for each printer and shows
  state badges (Idle, Printing, Paused, etc.). In reprint mode, non-available
  printers (anything other than IDLE, FINISH, FAILED) are grayed out and
  not selectable. "Select all" skips them. Queue/edit modes still allow
  selecting busy printers since the job will wait.
2026-03-06 14:31:43 +01:00
maziggy 0eada5edcd Fix PWA install not available in Chrome (#629)
Resize PWA icons to match their declared dimensions (192x192, 512x512,
  180x180), split discouraged "any maskable" icon purpose, and add mobile
  and desktop screenshots to manifest.json for Chrome's richer install UI.
2026-03-06 13:35:34 +01:00
maziggy 8c308487c7 Add i18n support for Settings, Smart Plugs, Notifications, and Backup/Restore
Replace all hardcoded English strings with t() translation calls across
  9 components: SettingsPage, SmartPlugCard, AddSmartPlugModal,
  SwitchbarPopover, NotificationProviderCard, AddNotificationModal,
  NotificationTemplateEditor, NotificationLogViewer, GitHubBackupSettings,
  and RestoreModal. Add ~600 new translation keys to all 7 locales
  (en, de, ja, fr, it, pt-BR, zh-CN).
2026-03-06 13:23:55 +01:00
maziggy 940810cba3 Show filament subtypes in all mapping dropdowns (#624)
All filament mapping dropdowns (single-printer, multi-printer, and
  "Print to Any" model-based) showed only the base material type (e.g.
  "PLA") without distinguishing subtypes like "PLA Basic" vs "PLA Matte",
  making entries with different subtypes but same color look identical.

  Backend: Add tray_sub_brands to available-filaments response and include
  it in the dedup key so different subtypes of the same color appear as
  separate entries.

  Frontend: Show tray_sub_brands in FilamentMapping, FilamentOverride, and
  PrinterSelector dropdowns, falling back to base type when unset. Add
  traySubBrands field to LoadedFilament interface.
2026-03-06 08:35:06 +01:00
maziggy 1bc3da3fad Fix multi-printer filament mapping ignoring nozzle on dual-nozzle printers (#624)
The per-printer InlineMappingEditor showed filaments from both nozzles
  on H2D printers. The single-printer FilamentMapping dropdown was fixed
  in 29e9593 but the multi-printer code path was missed. Added nozzle_id
  filtering to both auto-match logic and dropdown options via shared
  autoMatchFilament() and filterFilamentsByNozzle() functions in
  amsHelpers.ts, with 10 regression tests.
2026-03-05 15:38:37 +01:00
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