--- phase: 11-per-library-scan-pipeline plan: 02 type: execute wave: 2 depends_on: ["11-01"] files_modified: - frontend/src/components/config-page/config-page.ts - frontend/src/components/library-manager/library-manager.ts - frontend/wailsjs/go/library/Library.d.ts - frontend/wailsjs/go/library/Library.js autonomous: true requirements: [LSCAN-03, LSCAN-04] must_haves: truths: - "Progress UI shows which library is currently being scanned by name" - "Progress UI shows queue count when libraries are queued" - "Cancel during queued multi-scan shows modal with 'Cancel This Library' and 'Cancel All Scanning' choices" - "Cancelling one library automatically starts scanning the next queued library" - "Scan All Libraries button exists and triggers ScanAllLibraries binding" artifacts: - path: "frontend/src/components/config-page/config-page.ts" provides: "Updated cancel dialog with scope choice, progress with library name" - path: "frontend/src/components/library-manager/library-manager.ts" provides: "Scan All Libraries button, per-library progress display" - path: "frontend/wailsjs/go/library/Library.d.ts" provides: "TypeScript declarations for ScanLibrary, ScanAllLibraries, CancelCurrentScan, CancelAllScans" key_links: - from: "frontend/src/components/config-page/config-page.ts" to: "@go/library/Library" via: "Wails binding calls for CancelCurrentScan, CancelAllScans" pattern: "CancelCurrentScan|CancelAllScans" - from: "frontend/src/components/library-manager/library-manager.ts" to: "@go/library/Library" via: "Wails binding calls for ScanAllLibraries" pattern: "ScanAllLibraries" --- Update the frontend scan UI to display per-library progress (library name + queue count), add a "Scan All Libraries" button, and implement the cancel scope modal dialog for queued scans. Purpose: Fulfill LSCAN-03 (progress identifies which library) and LSCAN-04 frontend (cancel/pause work per-library with clear scope). Output: Updated config-page with library-aware cancel dialog, library-manager with Scan All button, Wails binding stubs. @/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/opencode/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/11-per-library-scan-pipeline/11-CONTEXT.md @.planning/phases/11-per-library-scan-pipeline/11-01-SUMMARY.md @.planning/phases/09-scan-cancellation-keyboard-shortcuts/09-03-SUMMARY.md Updated ScanProgress payload (from backend/library/metrics.go after Plan 01): ```typescript interface ScanProgress { phase: 'counting' | 'scanning' | 'orphans' | 'thumbnails'; total: number; processed: number; added: number; skipped: number; updated: number; libraryId: number; // NEW — which library is scanning libraryName: string; // NEW — display name queuedCount: number; // NEW — libraries still queued } ``` New Wails-bound methods (from Plan 01): ```typescript // These will need stubs in Library.d.ts and Library.js export function ScanLibrary(id: number): Promise; export function ScanAllLibraries(): Promise; export function CancelCurrentScan(): Promise; export function CancelAllScans(): Promise; export function GetScanQueueLength(): Promise; ``` New events (from Plan 01): ```typescript LibraryScanQueued: "LibraryScanQueued", LibraryScanQueueDrained: "LibraryScanQueueDrained", ``` Existing cancel dialog pattern from config-page.ts: - Modal overlay with stopPropagation - Three button choices - handleCancelKeep / handleCancelDiscard / handleCancelDialogDismiss Task 1: Add Wails binding stubs and update progress/cancel UI in config-page frontend/wailsjs/go/library/Library.d.ts frontend/wailsjs/go/library/Library.js frontend/src/components/config-page/config-page.ts 1. **Add Wails binding stubs** to `frontend/wailsjs/go/library/Library.d.ts`: ```typescript export function ScanLibrary(id: number): Promise; export function ScanAllLibraries(): Promise; export function CancelCurrentScan(): Promise; export function CancelAllScans(): Promise; export function GetScanQueueLength(): Promise; export function QueuedLibraryNames(): Promise; ``` And corresponding runtime implementations in `Library.js`: ```javascript export function ScanLibrary(id) { return window['go']['library']['Library']['ScanLibrary'](id); } export function ScanAllLibraries() { return window['go']['library']['Library']['ScanAllLibraries'](); } export function CancelCurrentScan() { return window['go']['library']['Library']['CancelCurrentScan'](); } export function CancelAllScans() { return window['go']['library']['Library']['CancelAllScans'](); } export function GetScanQueueLength() { return window['go']['library']['Library']['GetScanQueueLength'](); } export function QueuedLibraryNames() { return window['go']['library']['Library']['QueuedLibraryNames'](); } ``` 2. **Update config-page.ts ScanProgress interface** to include the new fields: - Add `libraryId: number`, `libraryName: string`, `queuedCount: number` to the `ScanProgress` interface 3. **Update imports** — replace `CancelScan` import with `CancelCurrentScan, CancelAllScans` from `@go/library/Library` 4. **Update progress display** (`renderScanProgress` method or equivalent): - When `scanProgress.libraryName` is non-empty, show "Scanning: [Library Name]" as the progress label instead of just "Scanning" - When `scanProgress.queuedCount > 0`, add a line below: "[N] libraries queued" in tertiary text color - Format: `Scanning: My Music (245/1200 files)` with `2 libraries queued` below 5. **Update cancel dialog** — replace the current three-option dialog with the per-library-aware version per CONTEXT.md: - Add `@state() private scanQueuedCount = 0;` to track queue state - Update `handleScanProgress` to also save `queuedCount` - **When `queuedCount > 0`** (multi-scan in progress): show modal dialog with TWO buttons: - "Cancel This Library" — calls `CancelCurrentScan()` (stops current, next starts) - "Cancel All Scanning" — calls `CancelAllScans()` (stops everything) - No default — user must pick (per CONTEXT.md: "no default, user must pick") - **When `queuedCount === 0`** (single scan): keep existing cancel behavior but call `CancelCurrentScan()` instead of `CancelScan()`. Can use the existing Keep/Discard/Continue dialog pattern. - Update `handleCancelKeep` → call `CancelCurrentScan()` instead of `CancelScan()` - Update `handleCancelDiscard` → call `CancelCurrentScan()` instead of `CancelScan()` 6. **Handle new events** in `connectedCallback`: - Listen for `LibraryScanQueued` — update `scanQueuedCount` from event payload - Listen for `LibraryScanQueueDrained` — set `scanQueuedCount = 0`, reset scan state 7. **Update scan buttons section** — when not scanning, show "Scan All Libraries" as an additional button alongside Soft Scan and Full Rescan. It calls `ScanAllLibraries()`. **Styling notes:** - Use existing design tokens (`--yj-text-primary`, `--yj-text-tertiary`, `--yj-accent`) - Queue count text: `.progress-detail` style (smaller, tertiary color) - Library name in progress: bold, primary text color - Cancel modal buttons: "Cancel This Library" gets `btn-warning`, "Cancel All Scanning" gets `btn-danger` - Keep `.cancel-dialog` CSS class pattern from Phase 9 **TypeScript strictness:** - `override` keyword on lifecycle methods - `import type` for type-only imports - Private event handlers as arrow functions cd /mnt/vault/dev/golang/yellowjacket/frontend && npx tsc --noEmit - ScanProgress interface includes libraryId, libraryName, queuedCount - Progress UI shows "Scanning: [Library Name]" and queue count - Cancel dialog shows scope choice when multiple scans queued - CancelCurrentScan/CancelAllScans called instead of CancelScan - Scan All Libraries button exists in scan actions - TypeScript compiles cleanly Task 2: Update library-manager component for per-library scan display frontend/src/components/library-manager/library-manager.ts 1. **Update ScanProgress interface** in library-manager.ts to match the new fields: add `libraryId: number`, `libraryName: string`, `queuedCount: number`. 2. **Update progress rendering** in `renderScanProgress()`: - Show library name: "Scanning: [Library Name]" as the progress label - Show queued count when > 0: "[N] libraries queued" in tertiary text 3. **Update imports** — add `ScanAllLibraries` import from `@go/library/Library` 4. **Add "Scan All Libraries" button** to the scan actions section: - Place it alongside existing "Soft Scan" and "Full Rescan" buttons - Style: `btn-primary` class, disabled when scanning - Handler: `private handleScanAll = async (): Promise => { await ScanAllLibraries(); }` - Label: "Scan All Libraries" (or "Scanning..." when active) 5. **Listen for LibraryScanQueued and LibraryScanQueueDrained events**: - In `connectedCallback`, add event subscriptions - In `disconnectedCallback`, clean up subscriptions - These events update scanning state for the UI 6. **Update handleScanComplete** to handle per-library scan completion: - The `LibraryScanComplete` event now includes `libraryName` in the metrics - If queue is still draining, don't reset scanning state (wait for `LibraryScanQueueDrained`) - Only fully reset `scanning = false` on `LibraryScanQueueDrained` or when `queuedCount === 0` in the complete event cd /mnt/vault/dev/golang/yellowjacket/frontend && npx tsc --noEmit - Library-manager shows library name in scan progress - "Scan All Libraries" button exists and calls ScanAllLibraries - Scan state properly tracks queue draining (doesn't reset early) - TypeScript compiles cleanly ```bash # TypeScript compiles cd frontend && npx tsc --noEmit # Full project builds (backend + frontend) cd .. && go build ./... ``` - Progress bar shows "Scanning: [Library Name] (N/M files)" during scan - Queue count visible when libraries are queued - Cancel modal offers "Cancel This Library" / "Cancel All Scanning" during queued scans - "Scan All Libraries" button exists in both config-page and library-manager - TypeScript compiles cleanly After completion, create `.planning/phases/11-per-library-scan-pipeline/11-02-SUMMARY.md`