Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit d70dceccc4a3215a35381704782b902863fe9c44
parent 735984720c1a253ad8f8a262b05ffcd2ab11e7cb
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 21 Sep 2026 01:45:04 -0400

deliver: refresh the counts the job just changed, and stat instead of reading

Three things found reading it back.

The panel's counts are SERVER-RENDERED off the directory and the job is what
changes the directory, so a finished cut left "cut 2 confirmed clips" on screen
until somebody reloaded. Refreshed once, when the job reaches a terminal state
-- not on a timer, which would fight the log being read.

`exists()` was a readFile. It is asked about `orig/<clip>.mp4` twice per clip
in a batch, so a 53-clip batch read a hundred megabytes to answer a yes/no.

And a timeline with no clips renders no panel at all: a card-only cut has
nothing to deliver, and a row of zeroes on every such project is noise on a
page that is already long.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mumtool/components/projects/DeliverActions.tsx | 10+++++++++-
Mumtool/components/projects/DeliverSection.tsx | 4+++-
Mumtool/lib/report/deliver.mjs | 5+++--
3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/umtool/components/projects/DeliverActions.tsx b/umtool/components/projects/DeliverActions.tsx @@ -1,6 +1,7 @@ "use client"; import { useCallback, useEffect, useRef, useState } from "react"; +import { useRouter } from "next/navigation"; import { buttonVariants } from "@/components/ui/button"; // --------------------------------------------------------------------------- @@ -65,6 +66,7 @@ export default function DeliverActions({ const [partial, setPartial] = useState(false); const [name, setName] = useState(nextName); const since = useRef(0); + const router = useRouter(); // Adopt a job already running, so a reload does not lose one. Also how a // second tab sees the first tab's cut. @@ -90,9 +92,15 @@ export default function DeliverActions({ const j = (await r.json()) as JobView; since.current = j.next; setJob((prev) => (prev ? { ...j, log: [...prev.log, ...j.log] } : j)); + // The counts above this panel are SERVER-RENDERED off the directory, and + // the job just changed the directory: a cut that finished leaves "cut 2 + // confirmed clips" on screen until something re-reads it. Refreshed + // here, once, when the job ends -- not on a timer, which would fight the + // log the operator is reading. + if (j.state !== "running") router.refresh(); }, 700); return () => clearInterval(t); - }, [job]); + }, [job, router]); const post = useCallback( async (action: string, extra: Record<string, unknown> = {}) => { diff --git a/umtool/components/projects/DeliverSection.tsx b/umtool/components/projects/DeliverSection.tsx @@ -57,7 +57,9 @@ export default async function DeliverSection({ entries: unknown[]; }) { const state = (await deliverStateOf(project, { manifest, entries })) as State | null; - if (!state) return null; + // A timeline with no clips has nothing to deliver, and a panel of zeroes on + // every card-only cut is noise on a page that is already long. + if (!state || !state.review.total) return null; const { review } = state; return ( diff --git a/umtool/lib/report/deliver.mjs b/umtool/lib/report/deliver.mjs @@ -14,7 +14,7 @@ // Plain ESM with no Next imports, because the batch builder is also spawned as // a script by lib/jobs.ts -- one implementation, whether a button or a terminal // asked for it. -import { copyFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises"; +import { copyFile, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises"; import { execFile } from "node:child_process"; import path from "node:path"; import { promisify } from "node:util"; @@ -279,7 +279,8 @@ export async function deliverStateOf(project, { manifest = null, entries = null }; } -const exists = (p) => readFile(p).then(() => true, () => false); +/** Is there a file here? `stat`, not a read: an `orig/` mp4 is megabytes. */ +const exists = (p) => stat(p).then((st) => st.isFile(), () => false); /** The batch's own manifest, in the shape the first one shipped. */ export function renderListMd(project, name, sections, { excluded }) {