From b519e065cbfbde2df889ad3ac69a8fad04cd2a33 Mon Sep 17 00:00:00 2001 From: tocmo Date: Sun, 5 Apr 2026 01:25:41 -0400 Subject: [PATCH] Fix discovery phase appearing frozen Scanner now updates message every 250 files during os.walk so the UI shows a live count. Progress bar switches to an indeterminate animated pulse during discovery and takeout phases (no known total yet), then reverts to a normal percentage bar once indexing begins. Co-Authored-By: Claude Sonnet 4.6 --- app/scanner.py | 6 ++++++ templates/index.html | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/app/scanner.py b/app/scanner.py index 8a38fbd..a0b3ed0 100644 --- a/app/scanner.py +++ b/app/scanner.py @@ -492,6 +492,12 @@ def run_scan(folder_path: str, scan_id: int, mode: str = "incremental"): ext = Path(fname).suffix.lower() if ext in SUPPORTED_EXT: all_files.append(os.path.join(root, fname)) + # Live count update every 250 files so UI doesn't look frozen + if len(all_files) % 250 == 0: + scan_state["message"] = f"Discovering... {len(all_files):,} files found" + + if scan_state["cancel_requested"]: + break scan_state["total"] = len(all_files) scan_state["message"] = f"Found {len(all_files):,} files" diff --git a/templates/index.html b/templates/index.html index 3d9fb81..3204388 100644 --- a/templates/index.html +++ b/templates/index.html @@ -212,6 +212,14 @@ background: var(--accent); transition: width .3s; } + .progress-bar-fill.indeterminate { + width: 40% !important; + animation: indeterminate 1.4s ease-in-out infinite; + } + @keyframes indeterminate { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(300%); } + } .progress-msg { font-size: 12px; color: var(--text-dim); } .phase-pills { display: flex; @@ -1057,8 +1065,13 @@ function updateScanUI(s) { if (isRunning) { el('progress-msg').textContent = s.message || ''; - const pct = s.total > 0 ? Math.round((s.progress / s.total) * 100) : 0; - el('progress-fill').style.width = pct + '%'; + const indeterminate = s.phase === 'discovery' || s.phase === 'takeout' || s.total === 0; + const fill = el('progress-fill'); + fill.classList.toggle('indeterminate', indeterminate); + if (!indeterminate) { + const pct = Math.round((s.progress / s.total) * 100); + fill.style.width = pct + '%'; + } el('progress-count').textContent = s.total > 0 ? `${fmt(s.progress)} / ${fmt(s.total)}` : ''; const phaseIdx = PHASES.indexOf(s.phase);