Files
yellowjacket/.planning/phases/11-per-library-scan-pipeline/11-02-PLAN.md
T

11 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
11-per-library-scan-pipeline 02 execute 2
11-01
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
true
LSCAN-03
LSCAN-04
truths artifacts key_links
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
path provides
frontend/src/components/config-page/config-page.ts Updated cancel dialog with scope choice, progress with library name
path provides
frontend/src/components/library-manager/library-manager.ts Scan All Libraries button, per-library progress display
path provides
frontend/wailsjs/go/library/Library.d.ts TypeScript declarations for ScanLibrary, ScanAllLibraries, CancelCurrentScan, CancelAllScans
from to via pattern
frontend/src/components/config-page/config-page.ts @go/library/Library Wails binding calls for CancelCurrentScan, CancelAllScans CancelCurrentScan|CancelAllScans
from to via pattern
frontend/src/components/library-manager/library-manager.ts @go/library/Library Wails binding calls for ScanAllLibraries 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.

<execution_context> @/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md @/home/caleb/.config/opencode/get-shit-done/templates/summary.md </execution_context>

@.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):

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):

// These will need stubs in Library.d.ts and Library.js
export function ScanLibrary(id: number): Promise<void>;
export function ScanAllLibraries(): Promise<void>;
export function CancelCurrentScan(): Promise<void>;
export function CancelAllScans(): Promise<void>;
export function GetScanQueueLength(): Promise<number>;

New events (from Plan 01):

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:

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'](); }
  1. Update config-page.ts ScanProgress interface to include the new fields:

    • Add libraryId: number, libraryName: string, queuedCount: number to the ScanProgress interface
  2. Update imports — replace CancelScan import with CancelCurrentScan, CancelAllScans from @go/library/Library

  3. 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
  4. 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()
  5. Handle new events in connectedCallback:

    • Listen for LibraryScanQueued — update scanQueuedCount from event payload
    • Listen for LibraryScanQueueDrained — set scanQueuedCount = 0, reset scan state
  6. 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`.
  1. 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
  2. Update imports — add ScanAllLibraries import from @go/library/Library

  3. 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<void> => { await ScanAllLibraries(); }
    • Label: "Scan All Libraries" (or "Scanning..." when active)
  4. Listen for LibraryScanQueued and LibraryScanQueueDrained events:

    • In connectedCallback, add event subscriptions
    • In disconnectedCallback, clean up subscriptions
    • These events update scanning state for the UI
  5. 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 ./...

</verification>

<success_criteria>
- 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
</success_criteria>

<output>
After completion, create `.planning/phases/11-per-library-scan-pipeline/11-02-SUMMARY.md`
</output>