diff --git a/src/features/execute/ExecutePage.tsx b/src/features/execute/ExecutePage.tsx index 51a8b91..24c7754 100644 --- a/src/features/execute/ExecutePage.tsx +++ b/src/features/execute/ExecutePage.tsx @@ -122,10 +122,36 @@ export function ExecutePage() { const errors = totalCounts.error ?? 0; const jobs = data?.jobs ?? []; + const running = totalCounts.running ?? 0; + const allDone = totalCounts.all > 0 && pending === 0 && running === 0; + return (
-
-

Execute Jobs

+

Execute Jobs

+ +
+ {totalCounts.all === 0 && !loading && ( + No jobs yet. Go to Review and approve items first. + )} + {totalCounts.all === 0 && loading && ( + Loading... + )} + {allDone && ( + All jobs completed + )} + {running > 0 && ( + {running} job{running !== 1 ? 's' : ''} running + )} + {pending > 0 && ( + <> + {pending} job{pending !== 1 ? 's' : ''} pending + + + + )} + {(done > 0 || errors > 0) && ( + + )}
navigate({ to: '/execute', search: { filter: key } as never })} /> -
- {pending > 0 && } - {pending > 0 && } - {(done > 0 || errors > 0) && } - {totalCounts.all === 0 && !loading && ( -

- No jobs yet. Go to Review and approve items first. -

- )} -
- {loading && !data &&
Loading…
} {jobs.length > 0 && ( diff --git a/src/features/paths/PathsPage.tsx b/src/features/paths/PathsPage.tsx index a3438fc..6ba2932 100644 --- a/src/features/paths/PathsPage.tsx +++ b/src/features/paths/PathsPage.tsx @@ -24,19 +24,31 @@ export function PathsPage() { useEffect(() => { if (cache === null) load(); }, []); + const allGood = paths.length > 0 && paths.every((p) => p.accessible); + const hasBroken = paths.some((p) => !p.accessible); + return (
-
-

Paths

+

Paths

+ +
+ {paths.length === 0 && !loading && ( + No media items scanned yet. Run a scan first. + )} + {paths.length === 0 && loading && ( + Checking paths... + )} + {allGood && ( + All {paths.length} paths accessible + )} + {hasBroken && ( + {paths.filter((p) => !p.accessible).length} path{paths.filter((p) => !p.accessible).length !== 1 ? 's' : ''} not mounted + )}
- {paths.length === 0 && !loading && ( -

No media items scanned yet. Run a scan first.

- )} - {paths.length > 0 && ( <> diff --git a/src/features/review/AudioListPage.tsx b/src/features/review/AudioListPage.tsx index 41578c2..b2276ad 100644 --- a/src/features/review/AudioListPage.tsx +++ b/src/features/review/AudioListPage.tsx @@ -231,12 +231,19 @@ export function AudioListPage() { return (
-
-

Audio Review

- {hasPending && } +

Audio Review

+ +
+ {hasPending ? ( + <> + {totalCounts.needs_action} item{totalCounts.needs_action !== 1 ? 's' : ''} need{totalCounts.needs_action === 1 ? 's' : ''} review + + + ) : ( + All items reviewed + )}
- {/* Filter tabs */} -
-

Library Scan

-
+

Library Scan

- {/* Status card */} -
-
- {statusLabel || (running ? 'Scan in progress…' : 'Scan idle')} +
+
+ {statusLabel || (running ? 'Scan in progress…' : 'Scan idle')} {running ? ( ) : ( diff --git a/src/features/subtitles/SubtitleExtractPage.tsx b/src/features/subtitles/SubtitleExtractPage.tsx index 6a98b47..bf55ce1 100644 --- a/src/features/subtitles/SubtitleExtractPage.tsx +++ b/src/features/subtitles/SubtitleExtractPage.tsx @@ -76,14 +76,12 @@ function StatusPills({ g }: { g: SubSeriesGroup }) { ); } -// ─── Extraction bar ────────────────────────────────────────────────────────── +// ─── Action box ────────────────────────────────────────────────────────────── -function ExtractionBar({ count, onExtract }: { count: number; onExtract: () => void }) { +function ActionBox({ count, onExtract }: { count: number | null; onExtract: () => void }) { const [extracting, setExtracting] = useState(false); const [result, setResult] = useState(''); - if (count === 0) return null; - const handleExtract = async () => { setExtracting(true); setResult(''); @@ -95,14 +93,20 @@ function ExtractionBar({ count, onExtract }: { count: number; onExtract: () => v setExtracting(false); }; + const allDone = count !== null && count === 0; + return ( -
- - {count} item{count !== 1 ? 's have' : ' has'} embedded subtitles ready to extract - - +
+ {count === null && Loading...} + {allDone && All subtitles extracted} + {count !== null && count > 0 && ( + <> + {count} item{count !== 1 ? 's have' : ' has'} embedded subtitles to extract + + + )} {result && {result}}
); @@ -219,9 +223,7 @@ export function SubtitleExtractPage() {

Subtitle Extraction

- {embeddedCount !== null && ( - - )} + Loading...
; if (!summary) return
Failed to load subtitle summary.
; + const totalFiles = summary.categories.reduce((sum, c) => sum + c.fileCount, 0); + const langCount = new Set(summary.categories.map((c) => c.language)).size; + const hasFiles = totalFiles > 0; + return (

Subtitle Manager

+
+ {hasFiles ? ( + {totalFiles} extracted file{totalFiles !== 1 ? 's' : ''} across {langCount} language{langCount !== 1 ? 's' : ''} — select which to keep below + ) : ( + No extracted subtitle files yet. Extract subtitles first. + )} +
+