docs(04-05): complete frontend USB status bar and print label plan
This commit is contained in:
parent
4d2d35e277
commit
de807ba931
1 changed files with 117 additions and 0 deletions
117
.planning/phases/04-usb-manager-label-printing/04-05-SUMMARY.md
Normal file
117
.planning/phases/04-usb-manager-label-printing/04-05-SUMMARY.md
Normal 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
|
||||
Loading…
Add table
Reference in a new issue