feat: bulk action progress — header pill + per-thumbnail states

- New bulkAction store: tracks active/label/detail state for the pill
  and a Map<uid, pending|done|error> for per-tile overlays
- Extract StatusPill.svelte from IndexerStatusPill (generic active/label/detail
  props); IndexerStatusPill becomes a one-line wrapper
- +layout.svelte: render a second StatusPill driven by bulkAction store,
  alongside the indexer pill in the AnimatedMule header
- BulkActionBar: extend withBusy with optional BulkConfig (ids/label/doneLabel);
  pending tiles dim + spinner on start, green checkmark flashes for 400ms before
  cache invalidation removes them; red overlay on error, auto-clears after 2s
- onApprove/batchEdit: wire onProgress callback to setDetail so the pill shows
  the filename currently being processed during fan-out keep operations
- batch.ts: add completedId as third arg to onProgress (backwards-compatible)
- PhotoTile: derive bulkState from store; pending/done/error overlays sit above
  the selection tint; hover-video guarded against pending tiles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dtoro
2026-06-07 09:43:12 +02:00
parent 86e38e152d
commit da63ad769a
7 changed files with 177 additions and 56 deletions

View File

@@ -13,7 +13,7 @@ export interface BatchResult<T> {
export interface BatchOptions {
concurrency?: number;
onProgress?: (done: number, total: number) => void;
onProgress?: (done: number, total: number, completedId: string) => void;
}
export async function batchEdit<T>(
@@ -38,7 +38,7 @@ export async function batchEdit<T>(
errors.push({ id, message: err instanceof Error ? err.message : String(err) });
} finally {
done++;
opts.onProgress?.(done, ids.length);
opts.onProgress?.(done, ids.length, id);
}
}
}