fix(web): scan progress — correct percentages, no layout shift, refresh-survivable

Bug: the admin 'Scanning Libraries' widget fed the server's 0-1
progress straight into percent strings and bar widths, so the overall
and per-library percentages capped at '1%' and the bars never filled.
Both now scale by 100 (matching the setup page, which was already
correct).

Bug: scan state only reached clients via websocket events, so a page
opened (or refreshed) mid-scan showed nothing until the next tick —
and the admin widget never re-attached at all. The worker now exposes
active jobs (with their library_id so rows keep their names), served
as GET /api/scanner/active (admin, re-attaches the widget + polling)
and GET /api/scanner/active-summary (any user, restores the sidebar
indicator on load). Idle hides both, exactly as before.

Annoyance: the sidebar's 'Scanning… N%' was a block element between
the logo and the nav, shoving every menu entry down while a scan ran.
The percent now lives inside the fixed-height logo row next to the
spinner (spinner last, so growing digits extend leftward); nothing
below it moves.
This commit is contained in:
John O'Keefe committed 2026-10-15 08:29:04 -04:00
1 parent 9bc149f3d9
commit fd6f0e3353
11 files changed
+245 -38

No files matched your search

+7 -1
View File
@@ -7,12 +7,18 @@ import (
)
// registerScannerRoutes registers all scanner-related endpoints
func registerScannerRoutes(admin *echo.Group, h *handlers.Handler) {
func registerScannerRoutes(protected, admin *echo.Group, h *handlers.Handler) {
// Any authenticated user: the sitewide sidebar indicator needs to
// know a scan is running after a page refresh (websocket events
// only reach pages that were already open).
protected.GET("/scanner/active-summary", h.GetScanSummary)
// Scanner routes (admin only)
admin.POST("/scanner/scan", h.ScanLibrary)
admin.POST("/scanner/start", h.StartScanner)
admin.POST("/scanner/stop", h.StopScanner)
admin.GET("/scanner/status/:jobId", h.GetScanStatus)
admin.GET("/scanner/active", h.GetActiveScans)
// Watch mode routes (admin only)
admin.POST("/scanner/watch/start", h.StartWatchMode)