Files
bambuddy/frontend
maziggy 11fe68578e fix(#1133): list every spool in the AMS-slot inventory picker
The picker that opens from <FilamentHoverCard> / SpoolBuddy's slot-action
  sheet had two stacked filters that together blocked a real workflow:

  1. AssignSpoolModal only listed spools whose tag_uid AND tray_uuid were
     both null, hiding any Bambu Lab spool that had been auto-created from
     RFID or scanned via SpoolBuddy NFC.
  2. FilamentHoverCard rendered its inventory section only when the slot's
     vendor was not 'Bambu Lab', so even with #1 fixed the assign button
     wasn't visible on a BL slot.

  Both filters blocked the same use case: a user has a Bambu Lab spool in
  inventory but doesn't want to scan via SpoolBuddy NFC every time and
  just wants to pick it from the list.

  Both gates removed. Modal lists every spool that isn't already taken by
  another (printer/ams_id/tray_id) tuple. Hover-card inventory section
  renders for every vendor including Bambu Lab. The AMS-vs-external
  special-case in the modal collapsed too — external slots used to be the
  only path that allowed picking a tagged spool, that distinction is gone.

  Empty slots lost their assign affordance entirely. A physically empty
  slot has no spool to attach an inventory record to, and offering the
  action there only led to users assigning the wrong spool to a slot the
  printer hadn't actually loaded yet. Bambuddy: EmptySlotHoverCard's
  inventory prop removed; PrintersPage drops the matching inventory
  props on three sites. SpoolBuddy: slot-action picker gates the
  assign/unassign block on slotActionPicker.tray !== null.

  Modal also gets defensive hardening from the rollout investigation:
  its own dedicated cache key (['inventory-spools', 'assign-modal']) so
  it can't be poisoned by other components calling getSpools() with
  different includeArchived args; getSpools(true) + client-side
  !archived_at filter so the picker sees the full inventory regardless
  of cache priming order; "Show all spools" toggle now bypasses BOTH
  filters (was only bypassing material/profile, label was a lie); a
  small "X fetched · Y archived · Z assigned" counter in the empty state
  so future "missing spool" reports are debuggable from screenshots.

  i18n.inventory.noManualSpools renamed to inventory.noAvailableSpools
  with new copy ("No spools available. Add a spool to your inventory or
  unassign one from another slot first.") since the empty-state premise
  changed. Localised across all 8 languages.

  15 frontend tests: assign/unassign render for vendor: 'Bambu Lab',
  non-BL vendors unchanged, EmptySlotHoverCard renders no assign
  affordance, configure button still works on empty slots, picker lists
  BL spools alongside manual ones, picker drops spools assigned
  elsewhere unless toggle is on, picker drops archived spools always,
  toggle escape-hatch shows everything, empty-state copy update.
  SpoolBuddy unassign now invalidates both ['spool-assignments'] and
  ['spool-assignments', printerId] so the modal's cache stays fresh
  (dual cache-key consolidation deferred to its own PR).
2026-04-26 11:45:18 +02:00
..
…

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see this documentation.

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...

      // Remove tseslint.configs.recommended and replace with this
      tseslint.configs.recommendedTypeChecked,
      // Alternatively, use this for stricter rules
      tseslint.configs.strictTypeChecked,
      // Optionally, add this for stylistic rules
      tseslint.configs.stylisticTypeChecked,

      // Other configs...
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])

You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:

// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{ts,tsx}'],
    extends: [
      // Other configs...
      // Enable lint rules for React
      reactX.configs['recommended-typescript'],
      // Enable lint rules for React DOM
      reactDom.configs.recommended,
    ],
    languageOptions: {
      parserOptions: {
        project: ['./tsconfig.node.json', './tsconfig.app.json'],
        tsconfigRootDir: import.meta.dirname,
      },
      // other options...
    },
  },
])