feat(11-02): update library-manager with per-library progress and Scan All button
- Add libraryId, libraryName, queuedCount to ScanProgress interface - Show library name in progress label (Scanning: [Library Name]) - Show queue count below progress bar when libraries queued - Add Scan All Libraries button (calls ScanAllLibraries binding) - Subscribe to LibraryScanQueued/LibraryScanQueueDrained events - Scan state properly tracks queue draining (doesn't reset early)
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
import { LitElement, html, css, nothing } from 'lit';
|
import { LitElement, html, css, nothing } from 'lit';
|
||||||
import { customElement, state } from 'lit/decorators.js';
|
import { customElement, state } from 'lit/decorators.js';
|
||||||
import { EventsOn } from '@runtime/runtime';
|
import { EventsOn } from '@runtime/runtime';
|
||||||
import { Scan, FullRescan } from '@go/library/Library';
|
import {
|
||||||
|
Scan,
|
||||||
|
FullRescan,
|
||||||
|
ScanAllLibraries,
|
||||||
|
} from '@go/library/Library';
|
||||||
import {
|
import {
|
||||||
GetLibraryDirectory,
|
GetLibraryDirectory,
|
||||||
SetLibraryDirectory,
|
SetLibraryDirectory,
|
||||||
@@ -26,6 +30,9 @@ interface ScanProgress {
|
|||||||
added: number;
|
added: number;
|
||||||
skipped: number;
|
skipped: number;
|
||||||
updated: number;
|
updated: number;
|
||||||
|
libraryId: number;
|
||||||
|
libraryName: string;
|
||||||
|
queuedCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ScanMetrics {
|
interface ScanMetrics {
|
||||||
@@ -247,9 +254,12 @@ export class LibraryManager extends LitElement {
|
|||||||
@state() private errorsCopied = false;
|
@state() private errorsCopied = false;
|
||||||
@state() private scanErrors = '';
|
@state() private scanErrors = '';
|
||||||
@state() private concurrencyMode = 'auto';
|
@state() private concurrencyMode = 'auto';
|
||||||
|
@state() private scanQueuedCount = 0;
|
||||||
private cancelScanStarted?: () => void;
|
private cancelScanStarted?: () => void;
|
||||||
private cancelScanProgress?: () => void;
|
private cancelScanProgress?: () => void;
|
||||||
private cancelScanComplete?: () => void;
|
private cancelScanComplete?: () => void;
|
||||||
|
private cancelScanQueued?: () => void;
|
||||||
|
private cancelScanQueueDrained?: () => void;
|
||||||
|
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
:host {
|
:host {
|
||||||
@@ -635,6 +645,14 @@ export class LibraryManager extends LitElement {
|
|||||||
Events.LibraryScanComplete,
|
Events.LibraryScanComplete,
|
||||||
this.handleScanComplete,
|
this.handleScanComplete,
|
||||||
);
|
);
|
||||||
|
this.cancelScanQueued = EventsOn(
|
||||||
|
Events.LibraryScanQueued,
|
||||||
|
this.handleScanQueued,
|
||||||
|
);
|
||||||
|
this.cancelScanQueueDrained = EventsOn(
|
||||||
|
Events.LibraryScanQueueDrained,
|
||||||
|
this.handleScanQueueDrained,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
override disconnectedCallback(): void {
|
override disconnectedCallback(): void {
|
||||||
@@ -642,6 +660,8 @@ export class LibraryManager extends LitElement {
|
|||||||
this.cancelScanStarted?.();
|
this.cancelScanStarted?.();
|
||||||
this.cancelScanProgress?.();
|
this.cancelScanProgress?.();
|
||||||
this.cancelScanComplete?.();
|
this.cancelScanComplete?.();
|
||||||
|
this.cancelScanQueued?.();
|
||||||
|
this.cancelScanQueueDrained?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async loadCurrentDirectory(): Promise<void> {
|
private async loadCurrentDirectory(): Promise<void> {
|
||||||
@@ -704,14 +724,25 @@ export class LibraryManager extends LitElement {
|
|||||||
): void => {
|
): void => {
|
||||||
if (progress) {
|
if (progress) {
|
||||||
this.scanProgress = progress;
|
this.scanProgress = progress;
|
||||||
|
this.scanQueuedCount =
|
||||||
|
progress.queuedCount ?? 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private handleScanComplete = (
|
private handleScanComplete = (
|
||||||
metrics?: ScanMetrics,
|
metrics?: ScanMetrics,
|
||||||
): void => {
|
): void => {
|
||||||
this.scanning = false;
|
|
||||||
this.scanProgress = null;
|
this.scanProgress = null;
|
||||||
|
|
||||||
|
// If queue still has entries, don't fully reset — next scan will fire ScanStarted
|
||||||
|
if (this.scanQueuedCount > 0) {
|
||||||
|
if (metrics) {
|
||||||
|
this.metrics = metrics;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scanning = false;
|
||||||
this.statusMessage = 'Scan complete.';
|
this.statusMessage = 'Scan complete.';
|
||||||
|
|
||||||
if (metrics) {
|
if (metrics) {
|
||||||
@@ -719,6 +750,15 @@ export class LibraryManager extends LitElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private handleScanQueued = (): void => {
|
||||||
|
this.scanQueuedCount++;
|
||||||
|
};
|
||||||
|
|
||||||
|
private handleScanQueueDrained = (): void => {
|
||||||
|
this.scanQueuedCount = 0;
|
||||||
|
this.scanning = false;
|
||||||
|
};
|
||||||
|
|
||||||
private handleSelectDirectory =
|
private handleSelectDirectory =
|
||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
@@ -756,6 +796,20 @@ export class LibraryManager extends LitElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private handleScanAll = async (): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await ScanAllLibraries();
|
||||||
|
} catch (err) {
|
||||||
|
this.statusMessage =
|
||||||
|
'Scan all libraries completed with errors.';
|
||||||
|
this.scanErrors = String(err);
|
||||||
|
console.error(
|
||||||
|
'Scan all libraries failed:',
|
||||||
|
err,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private handleSoftScan = async (): Promise<void> => {
|
private handleSoftScan = async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
await Scan();
|
await Scan();
|
||||||
@@ -874,11 +928,25 @@ export class LibraryManager extends LitElement {
|
|||||||
|
|
||||||
if (!p) return nothing;
|
if (!p) return nothing;
|
||||||
|
|
||||||
|
const libraryPrefix = p.libraryName
|
||||||
|
? `Scanning: ${p.libraryName}`
|
||||||
|
: '';
|
||||||
|
|
||||||
if (p.phase === 'counting') {
|
if (p.phase === 'counting') {
|
||||||
return html`
|
return html`
|
||||||
<div class="progress-phase">
|
<div class="progress-phase">
|
||||||
|
${libraryPrefix
|
||||||
|
? html`<strong>${libraryPrefix}</strong> \u2014 `
|
||||||
|
: ''}
|
||||||
Counting files\u2026
|
Counting files\u2026
|
||||||
</div>
|
</div>
|
||||||
|
${p.queuedCount > 0
|
||||||
|
? html`<div class="progress-detail">
|
||||||
|
${p.queuedCount}
|
||||||
|
${p.queuedCount === 1 ? 'library' : 'libraries'}
|
||||||
|
queued
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,7 +966,11 @@ export class LibraryManager extends LitElement {
|
|||||||
thumbnails: 'Generating thumbnails',
|
thumbnails: 'Generating thumbnails',
|
||||||
};
|
};
|
||||||
|
|
||||||
const label = phaseLabel[p.phase] ?? 'Scanning';
|
const baseLabel =
|
||||||
|
phaseLabel[p.phase] ?? 'Scanning';
|
||||||
|
const label = p.libraryName
|
||||||
|
? `${baseLabel}: ${p.libraryName}`
|
||||||
|
: baseLabel;
|
||||||
|
|
||||||
const parts: string[] = [];
|
const parts: string[] = [];
|
||||||
|
|
||||||
@@ -939,6 +1011,13 @@ export class LibraryManager extends LitElement {
|
|||||||
style="width: ${percent}%"
|
style="width: ${percent}%"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
${p.queuedCount > 0
|
||||||
|
? html`<div class="progress-detail">
|
||||||
|
${p.queuedCount}
|
||||||
|
${p.queuedCount === 1 ? 'library' : 'libraries'}
|
||||||
|
queued
|
||||||
|
</div>`
|
||||||
|
: nothing}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,6 +1287,15 @@ export class LibraryManager extends LitElement {
|
|||||||
? 'Scanning...'
|
? 'Scanning...'
|
||||||
: 'Full Rescan'}
|
: 'Full Rescan'}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn-primary"
|
||||||
|
?disabled=${this.scanning}
|
||||||
|
@click=${this.handleScanAll}
|
||||||
|
>
|
||||||
|
${this.scanning
|
||||||
|
? 'Scanning...'
|
||||||
|
: 'Scan All Libraries'}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user