feat: show analysis progress with per-file counter and cached tally
Day highlights: replaces the static "Analysing N files…" spinner with a
live progress bar, current filename ("3 / 8 — recording.wav"), and a
running tally of cached vs freshly-analysed files. Completes with a
summary line ("Done — 8 files (6 cached, 2 analysed)").
Single-file analyse: adds a small "cached" badge in the waveform box
when the result was served from cache.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -704,6 +704,11 @@ button.chip:hover{background:#6c1f08;border-color:#9a3412}
|
||||
button.chip:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
|
||||
.quiet{color:var(--muted);font-size:12px;margin-top:6px}
|
||||
.spin{color:var(--muted);font-style:italic;font-size:12px;padding:6px 0}
|
||||
.prog-bar{height:3px;background:var(--brd);border-radius:2px;margin:6px 0 4px;overflow:hidden}
|
||||
.prog-fill{height:100%;background:var(--accent);border-radius:2px;transition:width 0.15s ease}
|
||||
.prog-file{font-size:12px;color:var(--muted);font-style:italic;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
|
||||
.prog-tally{font-size:11px;color:var(--muted);margin-top:3px}
|
||||
.cached-badge{font-size:10px;color:var(--muted);background:var(--surf);border:1px solid var(--brd);border-radius:3px;padding:1px 5px;margin-left:6px;vertical-align:middle;font-style:normal}
|
||||
.empty{text-align:center;padding:60px;color:var(--muted)}
|
||||
/* player row */
|
||||
.player-row td{padding:0 10px 10px;background:var(--bg);border-bottom:1px solid var(--brd)}
|
||||
@@ -955,6 +960,12 @@ async function analyse(idx, filename, cell, btn) {
|
||||
}
|
||||
const box = document.createElement('div'); box.className='wbox';
|
||||
box.appendChild(drawWave(d.rms_display||[], d.sections||[], d.duration||0, filename));
|
||||
if (d.cached) {
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'cached-badge'; badge.textContent = 'cached';
|
||||
badge.title = 'Result loaded from cache — change threshold/gap and re-analyse to recompute';
|
||||
box.firstChild.after(badge);
|
||||
}
|
||||
|
||||
const chips = document.createElement('div');
|
||||
chips.className='chips';
|
||||
@@ -1323,22 +1334,43 @@ async function dayHighlights(dayId, analyzableFiles) {
|
||||
|
||||
hlRow.hidden = false;
|
||||
const n = analyzableFiles.length;
|
||||
contentEl.innerHTML = `<div class="spin" aria-live="polite" aria-busy="true">Analysing ${n} file${n!==1?'s':''}…</div>`;
|
||||
if (btn) btn.disabled = true;
|
||||
|
||||
// Build progress UI
|
||||
const progWrap = document.createElement('div');
|
||||
progWrap.setAttribute('aria-live', 'polite'); progWrap.setAttribute('aria-busy', 'true');
|
||||
const progBar = document.createElement('div'); progBar.className = 'prog-bar';
|
||||
const progFill = document.createElement('div'); progFill.className = 'prog-fill'; progFill.style.width = '0%';
|
||||
progBar.appendChild(progFill);
|
||||
const progFile = document.createElement('div'); progFile.className = 'prog-file';
|
||||
const progTally = document.createElement('div'); progTally.className = 'prog-tally';
|
||||
progWrap.appendChild(progBar); progWrap.appendChild(progFile); progWrap.appendChild(progTally);
|
||||
contentEl.innerHTML = ''; contentEl.appendChild(progWrap);
|
||||
|
||||
const threshold = document.getElementById('threshold-input').value || '0.05';
|
||||
const minGap = document.getElementById('min-gap-input').value || '2';
|
||||
|
||||
const results = [];
|
||||
for (const f of analyzableFiles) {
|
||||
let nCached = 0, nLive = 0;
|
||||
for (let i = 0; i < analyzableFiles.length; i++) {
|
||||
const f = analyzableFiles[i];
|
||||
progFile.textContent = `${i + 1} / ${n} — ${f.name}`;
|
||||
progFill.style.width = `${(i / n) * 100}%`;
|
||||
const tallyParts = [];
|
||||
if (nCached) tallyParts.push(`${nCached} cached`);
|
||||
if (nLive) tallyParts.push(`${nLive} analysed`);
|
||||
progTally.textContent = tallyParts.join(' · ');
|
||||
try {
|
||||
const r = await fetch('/api/analyze?file=' + encodeURIComponent(f.name)
|
||||
+ '&threshold=' + encodeURIComponent(threshold)
|
||||
+ '&min_gap=' + encodeURIComponent(minGap));
|
||||
const d = await r.json();
|
||||
if (!d.error) results.push({ f, data: d });
|
||||
if (!d.error) { results.push({ f, data: d }); d.cached ? nCached++ : nLive++; }
|
||||
} catch(e) {}
|
||||
}
|
||||
progFill.style.width = '100%';
|
||||
progFile.textContent = `Done — ${n} file${n!==1?'s':''} (${nCached} cached, ${nLive} analysed)`;
|
||||
progTally.textContent = '';
|
||||
|
||||
if (!results.length) {
|
||||
contentEl.innerHTML = '<div class="quiet">No analysable results.</div>';
|
||||
|
||||
Reference in New Issue
Block a user