feat(12-02): show scan progress bar inline in library list entry

Progress bar now renders below the library row being scanned, with
a small status label (phase + percent) after the library name. Removed
the separate status-bar progress display.
This commit is contained in:
2026-03-14 12:30:00 -04:00
parent 771345dd9d
commit df824c6989
@@ -856,8 +856,9 @@ export class ConfigPage extends LitElement {
.library-row { .library-row {
display: flex; display: flex;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 0.75em; gap: 0.5em 0.75em;
padding: 0.6em 0.5em; padding: 0.6em 0.5em;
border-bottom: 1px solid var(--yj-border-subtle, #333); border-bottom: 1px solid var(--yj-border-subtle, #333);
} }
@@ -871,6 +872,22 @@ export class ConfigPage extends LitElement {
border-radius: 4px; border-radius: 4px;
} }
.library-row .inline-progress {
flex-basis: 100%;
padding-left: 1.75em;
}
.library-row .inline-progress .progress-track {
margin-top: 0.25em;
}
.library-scan-status {
font-size: 0.75em;
font-weight: 400;
color: var(--yj-accent, #ffd43b);
white-space: nowrap;
}
.library-name { .library-name {
flex: 1; flex: 1;
cursor: pointer; cursor: pointer;
@@ -2328,7 +2345,24 @@ export class ConfigPage extends LitElement {
</span> </span>
</div> </div>
${this.libraries.map( ${this.libraries.map(
(lib) => html` (lib) => {
const isScanning = this.scanProgress?.libraryId === lib.id
&& this.scanning;
const p = isScanning ? this.scanProgress : null;
const percent = p && p.total > 0
? Math.min(100, Math.round((p.processed / p.total) * 100))
: 0;
const phaseLabels: Record<string, string> = {
counting: 'Counting\u2026',
scanning: `Scanning\u2026 ${percent}%`,
orphans: 'Cleaning up\u2026',
thumbnails: 'Thumbnails\u2026',
};
const statusText = p
? phaseLabels[p.phase] ?? 'Scanning\u2026'
: '';
return html`
<div class="library-row"> <div class="library-row">
<input <input
type="checkbox" type="checkbox"
@@ -2355,6 +2389,9 @@ export class ConfigPage extends LitElement {
> >
${lib.name} ${lib.name}
</span> </span>
${statusText
? html`<span class="library-scan-status">${statusText}</span>`
: nothing}
`} `}
<span class="library-path">${lib.path}</span> <span class="library-path">${lib.path}</span>
<span class="library-count"> <span class="library-count">
@@ -2395,8 +2432,21 @@ export class ConfigPage extends LitElement {
` `
: nothing} : nothing}
</div> </div>
${p && p.phase !== 'counting'
? html`
<div class="inline-progress">
<div class="progress-track">
<div
class="progress-fill"
style="width: ${percent}%"
></div>
</div>
</div>
`
: nothing}
</div> </div>
`, `;
},
)} )}
</div> </div>
` `
@@ -2433,9 +2483,7 @@ export class ConfigPage extends LitElement {
> >
${this.scanPaused ${this.scanPaused
? 'Scan paused.' ? 'Scan paused.'
: this.scanProgress : this.statusMessage || 'Ready.'}
? this.renderScanProgress()
: this.statusMessage || 'Ready.'}
</div> </div>
${this.scanErrors ${this.scanErrors
@@ -2640,105 +2688,6 @@ export class ConfigPage extends LitElement {
`; `;
} }
private renderScanProgress() {
const p = this.scanProgress;
if (!p) return nothing;
const libraryPrefix = p.libraryName
? `Scanning: ${p.libraryName}`
: '';
if (p.phase === 'counting') {
return html`
<div class="progress-phase">
${libraryPrefix
? html`<strong>${libraryPrefix}</strong> \u2014 `
: ''}
Counting files\u2026
</div>
${p.queuedCount > 0
? html`<div class="progress-detail">
${p.queuedCount}
${p.queuedCount === 1 ? 'library' : 'libraries'}
queued
</div>`
: nothing}
`;
}
const percent =
p.total > 0
? Math.min(
100,
Math.round(
(p.processed / p.total) * 100,
),
)
: 0;
const phaseLabel: Record<string, string> = {
scanning: 'Scanning',
orphans: 'Cleaning up',
thumbnails: 'Generating thumbnails',
};
const baseLabel =
phaseLabel[p.phase] ?? 'Scanning';
const label = p.libraryName
? `${baseLabel}: ${p.libraryName}`
: baseLabel;
// Build detail string: "1,247 / 2,013 files (891 new, 23 updated, 356 skipped)"
const parts: string[] = [];
if (p.added > 0)
parts.push(`${p.added.toLocaleString()} new`);
if (p.updated > 0)
parts.push(
`${p.updated.toLocaleString()} updated`,
);
if (p.skipped > 0)
parts.push(
`${p.skipped.toLocaleString()} skipped`,
);
const detail =
p.phase === 'scanning' && p.total > 0
? html`<span class="progress-detail">
${p.processed.toLocaleString()} /
${p.total.toLocaleString()} files${parts.length
? ` (${parts.join(', ')})`
: ''}
</span>`
: nothing;
return html`
<div class="progress-info">
<span class="progress-label">
${label}\u2026
</span>
${detail}
<span class="progress-percent">
${percent}%
</span>
</div>
<div class="progress-track">
<div
class="progress-fill"
style="width: ${percent}%"
></div>
</div>
${p.queuedCount > 0
? html`<div class="progress-detail">
${p.queuedCount}
${p.queuedCount === 1 ? 'library' : 'libraries'}
queued
</div>`
: nothing}
`;
}
private renderMetrics() { private renderMetrics() {
const m = this.metrics; const m = this.metrics;