Archilyzer · Source

archilyzer

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

commit fe9a33301463c5ec9d1ff5396279b9677e07f962
parent bc0161c26db215b060048898e9808fec4cbcc4cf
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Thu, 24 Sep 2026 13:08:09 -0400

widget: ActiveJobsStrip draws JobRow compact; private row and bars deleted

The monitor widget's Active jobs strip draws `<JobRow variant="compact">`
with its config mapped onto `show` (tasks unless compact, jobBar,
headingProgress, eta; no actions, no links). Its private JobRow,
JobProgressBar, TaskBar, TASK_KIND_VERB / TASK_KIND_FILL, METRIC_PREFIX and
jobProgressText are deleted — the glyph labels live on as the compact
variants in jobs/components/JobProgressBars.tsx. Region name "Active jobs"
and the "N running, M queued" meta are unchanged. One visible addition: a
row's `detail` (who asked) now shows in the widget line too, as it does on
every other job row.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

Diffstat:
Meditor/app/widget/components/MonitorWidget.tsx | 241++++---------------------------------------------------------------------------
1 file changed, 11 insertions(+), 230 deletions(-)

diff --git a/editor/app/widget/components/MonitorWidget.tsx b/editor/app/widget/components/MonitorWidget.tsx @@ -1,7 +1,7 @@ "use client"; import { Fragment, useState, type CSSProperties, type ReactNode } from "react"; -import { formatDuration, formatBytes } from "yt-dlp-transcript-common/lib/format"; +import { formatBytes } from "yt-dlp-transcript-common/lib/format"; import { usePolledPayload, useNow } from "../../lib/usePolledPayload"; import { fmtTime } from "../lib/relativeTime"; import type { @@ -9,11 +9,7 @@ import type { DiskStatusView, } from "yt-dlp-transcript-common/views/activeJobs"; import type { JobRowView } from "yt-dlp-transcript-common/views/jobRowView"; -import type { - JobProgressMetric, - JobTaskKind, -} from "yt-dlp-transcript-common/jobs/registry"; -import { jobKindLabel } from "../../jobs/jobKindLabels"; +import { JobRow } from "../../jobs/components/JobRow"; import type { WorkersPayload, WorkerView } from "yt-dlp-transcript-common/views/workers"; import { InlineActionButton } from "../../components/actions/InlineActionButton"; import type { WidgetActionablePayload } from "yt-dlp-transcript-common/views/widgetActionable"; @@ -1017,10 +1013,15 @@ function ActiveJobsStrip({ <li key={j.id}> <JobRow job={j} - compact={compact} - jobBar={jobBar} - headingProgress={headingProgress} - eta={eta} + variant="compact" + show={{ + tasks: !compact, + jobBar, + headingProgress, + eta, + actions: false, + links: false, + }} /> </li> ))} @@ -1030,226 +1031,6 @@ function ActiveJobsStrip({ ); } -function JobRow({ - job, - compact, - jobBar, - headingProgress, - eta, -}: { - job: JobRowView; - compact: boolean; - jobBar: boolean; - headingProgress: boolean; - eta: boolean; -}) { - const statusClass = - job.status === "running" - ? "bg-info-soft text-info" - : "bg-muted text-muted-foreground"; - return ( - <div className="flex flex-col gap-1"> - <div className="flex flex-wrap items-center gap-1.5 text-xs"> - <span - className={`uppercase tracking-wide px-1.5 py-0.5 rounded text-[10px] ${statusClass}`} - > - {job.status} - </span> - <span className="font-mono" title={job.kind}> - {jobKindLabel(job.kind)} - </span> - {job.background && ( - <span - className="uppercase tracking-wide px-1 py-0.5 rounded text-[9px] bg-warning-soft text-warning" - title="Background work — yields to a manual sync/download" - > - auto - </span> - )} - {job.channelSlug && ( - <span className="font-mono text-muted-foreground truncate max-w-[12rem]"> - {job.channelSlug} - </span> - )} - {headingProgress && job.progress && ( - <span className="font-mono text-muted-foreground shrink-0"> - {jobProgressText(job.progress, eta)} - </span> - )} - </div> - {jobBar && job.progress && ( - <JobProgressBar progress={job.progress} showEta={eta} /> - )} - {!compact && - job.tasks && - job.tasks.length > 0 && - job.tasks.map((t) => <TaskBar key={t.id} task={t} />)} - </div> - ); -} - -// Per-task-kind glyph/fill, as Records over JobTaskKind so a new kind is a -// compile error rather than silently rendering as a transcription. -const TASK_KIND_VERB: Record<JobTaskKind, string> = { - download: "\u2193", - transcribe: "\u270e", - digest: "\u00b6", - backfill: "\u21ba", - // A right arrow: a relocate task is a channel's media moving to another disk. - relocate: "\u21e2", -}; - -const TASK_KIND_FILL: Record<JobTaskKind, string> = { - download: "bg-success/60", - transcribe: "bg-success", - digest: "bg-info", - backfill: "bg-warning", - relocate: "bg-info/70", -}; - -// Per-metric glyph for the compact widget line. A Record over JobProgressMetric -// so a new metric is a compile error, not a mislabelled bar (the two copies of -// this ternary previously had to be kept in sync by hand). -const METRIC_PREFIX: Record<JobProgressMetric, string> = { - downloads: "\u2193 ", - transcripts: "", - digests: "\u00b6 ", - backfills: "\u21ba ", - scans: "\u2315 ", -}; - -// One-line textual summary of a job's batch progress, e.g. "↓ 5/10 · ~2m left". -// Shared by the job heading (headingProgress) and the job bar's caption so the -// label/ETA formatting stays in one place. -function jobProgressText( - progress: NonNullable<JobRowView["progress"]>, - showEta: boolean, -): string { - const label = `${METRIC_PREFIX[progress.metric]}${progress.current}/${progress.target}`; - const remaining = progress.target - progress.current; - const etaText = - !showEta || remaining <= 0 - ? null - : typeof progress.etaSeconds === "number" - ? `~${formatDuration(Math.max(1, Math.round(progress.etaSeconds)))} left` - : "…"; - return etaText ? `${label} · ${etaText}` : label; -} - -function JobProgressBar({ - progress, - showEta, -}: { - progress: NonNullable<JobRowView["progress"]>; - showEta: boolean; -}) { - const label = `${METRIC_PREFIX[progress.metric]}${progress.current}/${progress.target}`; - const remaining = progress.target - progress.current; - const etaText = - !showEta || remaining <= 0 - ? null - : typeof progress.etaSeconds === "number" - ? `~${formatDuration(Math.max(1, Math.round(progress.etaSeconds)))} left` - : "…"; - return ( - <div className="flex flex-col gap-0.5"> - <div - role="progressbar" - aria-valuemin={progress.initial} - aria-valuemax={progress.target} - aria-valuenow={progress.current} - aria-label={label} - className="relative h-1.5 w-full overflow-hidden rounded bg-muted" - > - <div - className="absolute inset-y-0 left-0 bg-success" - style={{ width: `${progress.pct}%` }} - /> - </div> - <div className="flex items-baseline justify-between gap-2 text-[11px] text-muted-foreground"> - <span>{label}</span> - {etaText && <span className="shrink-0">{etaText}</span>} - </div> - </div> - ); -} - -function TaskBar({ - task, -}: { - task: NonNullable<JobRowView["tasks"]>[number]; -}) { - const now = useNow(); - const probing = task.phase === "probing"; - const verb = probing ? "🔍" : TASK_KIND_VERB[task.kind]; - // While probing, fill against the estimated probe duration (violet "scanning" - // bar) rather than the frozen download fraction. See TaskProgressBar. - const probeFraction = - probing && - now !== null && - typeof task.probeStartedAt === "number" && - typeof task.probeEtaSeconds === "number" && - task.probeEtaSeconds > 0 - ? Math.max( - 0, - Math.min(1, (now - task.probeStartedAt) / (task.probeEtaSeconds * 1000)), - ) - : undefined; - const hasFraction = probing - ? typeof probeFraction === "number" - : typeof task.fraction === "number"; - const fraction = probing ? probeFraction : task.fraction; - const pct = hasFraction ? Math.round((fraction as number) * 100) : 0; - const fillClass = probing - ? "bg-violet-400 dark:bg-violet-500" - : TASK_KIND_FILL[task.kind]; - const pulseClass = probing - ? "bg-violet-400 dark:bg-violet-500" - : "bg-warning"; - const elapsed = - now === null - ? null - : formatDuration(Math.max(0, Math.round((now - task.startedAt) / 1000))) || - "0:00"; - const meta = [ - elapsed, - hasFraction ? `${pct}%` : null, - probing ? "probing" : task.detail, - ] - .filter(Boolean) - .join(" · "); - return ( - <div className="flex flex-col gap-0.5 pl-2 border-l-2 border-border"> - <div className="flex items-baseline justify-between gap-2 text-[11px]"> - <span className="truncate"> - <span className="text-muted-foreground">{verb} </span> - <span className="font-mono">{task.label}</span> - </span> - <span className="font-mono text-muted-foreground shrink-0">{meta}</span> - </div> - <div - role="progressbar" - aria-valuenow={hasFraction ? pct : undefined} - aria-label={`${task.label}`} - className="relative h-1 w-full overflow-hidden rounded bg-muted" - > - {hasFraction ? ( - <div - className={`absolute inset-y-0 left-0 ${fillClass}`} - style={{ width: `${pct}%` }} - /> - ) : ( - // No fraction yet (just started, an engine that reports no %, or the - // first audio probe): a full-width pulse reads as "working, no - // progress number" — distinct from the emerald fill so it can't be - // mistaken for ~33%. - <div className={`absolute inset-0 animate-pulse ${pulseClass}`} /> - )} - </div> - </div> - ); -} - // The settings gear and its in-place config overlay. The gear anchors to the // widget's own (relative) container; the overlay covers the whole widget window // (fixed inset-0) and hosts the same form the builder uses, so a pinned widget