mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-08 15:11:21 +02:00
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).
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:
- @vitejs/plugin-react uses Babel (or oxc when used in rolldown-vite) for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
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...
},
},
])