docs(04-05): complete frontend USB status bar and print label plan

This commit is contained in:
Mikkel Georgsen 2026-04-10 06:58:21 +00:00
parent 4d2d35e277
commit de807ba931

View file

@ -0,0 +1,117 @@
---
phase: 04-usb-manager-label-printing
plan: "05"
subsystem: frontend
tags: [usb, sse, react, label-printing, real-time]
dependency_graph:
requires: [04-03]
provides: [USB-04-frontend]
affects: [DashboardPage, ItemCard, ItemRow]
tech_stack:
added: []
patterns: [EventSource SSE, react-hot-toast, lucide-react icons]
key_files:
created:
- web/src/hooks/useUSBEvents.ts
- web/src/components/USBStatusBar.tsx
modified:
- web/src/lib/api.ts
- web/src/components/inventory/ItemCard.tsx
- web/src/components/inventory/ItemRow.tsx
- web/src/pages/DashboardPage.tsx
decisions:
- Print button added to ItemCard and ItemRow directly (not DashboardPage map) — cleaner separation of concerns
- handlePrintLabel defined at module level outside component to avoid per-render allocation
- USBStatusBar placed in DashboardPage header (flex justify-between alongside title)
- No ESLint config exists in project — skipped ESLint step, TypeScript + build used as verification
metrics:
duration: 8m
completed: 2026-04-10
tasks_completed: 2
files_changed: 6
---
# Phase 04 Plan 05: Frontend USB Status Bar and Print Label Summary
One-liner: SSE-backed useUSBEvents hook with USBStatusBar component and per-item print label button wired to POST /api/labels/:id/print with react-hot-toast feedback.
## Tasks Completed
| Task | Description | Commit |
|------|-------------|--------|
| 1 | useUSBEvents hook + USBStatusBar component | 8b88970 |
| 2 | Wire USBStatusBar + Print Label into dashboard | 3de1e4f |
## What Was Built
### useUSBEvents hook (`web/src/hooks/useUSBEvents.ts`)
- Subscribes to `GET /api/usb/events` SSE stream via `new EventSource('/api/usb/events')`
- Maintains `connectedDevices: Map<string, DeviceSpec>` in React state
- Connect events add to map; disconnect events remove from map
- Malformed JSON silently ignored (T-04-14 mitigated)
- EventSource auto-reconnects on error (T-04-15 accepted)
- Exports: `useUSBEvents`, `DeviceEvent`, `DeviceSpec`, `StateConnected`, `StateDisconnected`
### USBStatusBar component (`web/src/components/USBStatusBar.tsx`)
- Consumes `useUSBEvents()`, renders connected device list
- Role icons: Printer (role=0), Cable (role=1), Usb (role=2/unknown)
- Green dot per connected device with device name
- Empty state: "No USB devices" with USB icon in muted text
- ClickHouse design: black bg, `border-white/10`, `text-white/80`, `bg-green-500` status dots
### api.ts additions (`web/src/lib/api.ts`)
- `printLabel(deviceId: number): Promise<PrintLabelResponse>` — POST /api/labels/:id/print
- `PrintLabelResponse` interface: `{ status: string; print_skipped?: boolean }`
- Throws typed Error on non-OK response
### ItemCard (`web/src/components/inventory/ItemCard.tsx`)
- Module-level `handlePrintLabel(e, itemId)` using `printLabel()` from api.ts
- Printer icon button in CardFooter alongside NetBox link
- Toast: loading → success / "queued — printer not connected" / error
### ItemRow (`web/src/components/inventory/ItemRow.tsx`)
- Same `handlePrintLabel` pattern
- Print button added to quick-actions group (appears on hover with ExternalLink)
- Opacity transition matches existing group-hover pattern
### DashboardPage (`web/src/pages/DashboardPage.tsx`)
- Imports and renders `<USBStatusBar />` in page header (flex row, right-aligned)
- No layout restructuring — additive change only
## Deviations from Plan
### Auto-fixed Issues
None — plan executed exactly as written with one minor deviation:
**1. [Rule 2 - Deviation] Print button added to ItemCard/ItemRow rather than DashboardPage map**
- **Found during:** Task 2
- **Reason:** DashboardPage passes items to `<ItemCard>` and `<ItemRow>` as components — adding print logic inline in the map would duplicate code and break component encapsulation. Plan said "find where item quick actions are rendered" which is the card/row components.
- **Impact:** Cleaner architecture; identical user-visible result
- **Files modified:** ItemCard.tsx, ItemRow.tsx (instead of DashboardPage.tsx map)
## Known Stubs
None — all data flows wired. USBStatusBar connects to live SSE. Print button calls real endpoint.
## Threat Flags
None — no new trust boundaries beyond those in the plan's threat model.
## Self-Check
Files exist:
- web/src/hooks/useUSBEvents.ts — FOUND
- web/src/components/USBStatusBar.tsx — FOUND
- web/src/lib/api.ts (modified) — FOUND
- web/src/components/inventory/ItemCard.tsx (modified) — FOUND
- web/src/components/inventory/ItemRow.tsx (modified) — FOUND
- web/src/pages/DashboardPage.tsx (modified) — FOUND
Commits:
- 8b88970 — feat(04-05): add useUSBEvents hook and USBStatusBar component
- 3de1e4f — feat(04-05): wire USBStatusBar and Print Label button into dashboard
Build: `npm run build` — PASSED (tsc -b + vite build, 0 errors, 1965 modules)
## Self-Check: PASSED