feat: cleaner TopBar + live scan progress wired end-to-end
Two related polish items.
1. Drop dead TopBar buttons
- Removed the hamburger menu (Tab already toggles the sidebar),
the grid/list view-mode toggle (only Grid was ever
implemented), and the FolderOpen / Upload / Settings action
icons (no features behind them).
- TopBar is now: logo + active heap pill | search | filter
toggle. Removed the now-unused Grid/List/Menu/FolderOpen/
Upload/Settings icon imports and the dead viewMode local
state.
2. Wire live scan progress
- The frontend ScanProgress widget was already polling
/api/v1/library/scan/status, but the worker never wrote the
Redis keys that endpoint reads — it only updated celery's
internal task state. So the progress UI was permanently idle.
- Worker now writes scan:active / scan:current_folder /
scan:processed_files / scan:total_files / scan:errors at
every meaningful step. _get_redis() returns None on failure
so a Redis outage degrades gracefully (scan still runs,
progress just doesn't show).
- Pre-walk computes total_files upfront — without it the
progress bar jumped every time os.walk discovered a new
subfolder because the running total was being updated as it
went.
- Errors are RPUSHed to a capped list (MAX_ERROR_ENTRIES=50)
so a noisy scan can't blow up Redis.
- finally: clause guarantees scan:active flips to false even
on a crash, so the UI never sticks at "scanning" forever.
- scan_all_source_roots clears scan:errors and resets counters
before queuing the per-root tasks, so each top-level scan
starts with a clean slate.
Two latent bugs caught and fixed in passing:
- watch_folders was still reading settings.source_roots which
no longer exists since we moved source roots to the DB. Now
it loads them from the DB via a synchronous one-shot async
wrapper at task startup.
- _scan_all_source_roots_async was missing entirely after the
last refactor — defined inline now, reads active source
roots from the DB and dispatches scan_folder per row.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,7 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
import {
|
||||
Search,
|
||||
Grid,
|
||||
List,
|
||||
SlidersHorizontal,
|
||||
FolderOpen,
|
||||
Upload,
|
||||
Settings,
|
||||
Menu,
|
||||
X,
|
||||
ShoppingBasket,
|
||||
} from 'lucide-react'
|
||||
@@ -49,8 +43,6 @@ export function TopBar() {
|
||||
}
|
||||
}, [searchQuery, storeQ, setStoreQ])
|
||||
|
||||
const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid')
|
||||
|
||||
// Currently active heap. Shown as a pill so the user always knows where
|
||||
// their next P-press will land.
|
||||
const { data: heapsList = [] } = useHeapsQuery()
|
||||
@@ -58,17 +50,8 @@ export function TopBar() {
|
||||
|
||||
return (
|
||||
<header className="flex h-12 items-center justify-between border-b border-border bg-surface px-4">
|
||||
{/* Left Section - Menu and App Name */}
|
||||
{/* Left — logo + active heap pill */}
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
className="group relative rounded p-1 text-text-muted hover:bg-surface-2 hover:text-text"
|
||||
title="Toggle sidebar (Tab)"
|
||||
>
|
||||
<Menu className="h-5 w-5" />
|
||||
<kbd className="absolute -bottom-5 left-1/2 -translate-x-1/2 rounded bg-surface-offset px-1 py-0.5 text-[9px] font-medium text-text opacity-0 group-hover:opacity-100">
|
||||
Tab
|
||||
</kbd>
|
||||
</button>
|
||||
<div className="flex items-center gap-2">
|
||||
<img src={muliLogo} alt="Mulita" className="h-7 w-7 object-contain" />
|
||||
<h1 className="text-lg font-semibold text-text">Mulita</h1>
|
||||
@@ -83,8 +66,8 @@ export function TopBar() {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Center Section - Search */}
|
||||
|
||||
{/* Center — search */}
|
||||
<div className="flex max-w-xl flex-1 items-center px-8">
|
||||
<div className="relative w-full">
|
||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-muted" />
|
||||
@@ -117,38 +100,9 @@ export function TopBar() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Section - View Controls and Actions */}
|
||||
|
||||
{/* Right — filter toggle */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* View Mode Toggle */}
|
||||
<div className="flex rounded-md border border-border">
|
||||
<button
|
||||
className={clsx(
|
||||
'rounded-l-md px-2 py-1',
|
||||
viewMode === 'grid'
|
||||
? 'bg-primary text-white'
|
||||
: 'bg-surface text-text-muted hover:bg-surface-2'
|
||||
)}
|
||||
onClick={() => setViewMode('grid')}
|
||||
title="Grid view"
|
||||
>
|
||||
<Grid className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
className={clsx(
|
||||
'rounded-r-md px-2 py-1',
|
||||
viewMode === 'list'
|
||||
? 'bg-primary text-white'
|
||||
: 'bg-surface text-text-muted hover:bg-surface-2'
|
||||
)}
|
||||
onClick={() => setViewMode('list')}
|
||||
title="List view"
|
||||
>
|
||||
<List className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Filter Button */}
|
||||
<button
|
||||
onClick={toggleFilterBar}
|
||||
className={clsx(
|
||||
@@ -164,31 +118,7 @@ export function TopBar() {
|
||||
\
|
||||
</kbd>
|
||||
</button>
|
||||
|
||||
<div className="mx-1 h-6 w-px bg-border" />
|
||||
|
||||
{/* Action Buttons */}
|
||||
<button
|
||||
className="rounded p-1.5 text-text-muted hover:bg-surface-2 hover:text-text"
|
||||
title="Add folder"
|
||||
>
|
||||
<FolderOpen className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="rounded p-1.5 text-text-muted hover:bg-surface-2 hover:text-text"
|
||||
title="Import photos"
|
||||
>
|
||||
<Upload className="h-4 w-4" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="rounded p-1.5 text-text-muted hover:bg-surface-2 hover:text-text"
|
||||
title="Settings"
|
||||
>
|
||||
<Settings className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user