// screens-jobs.jsx — Jobs queue with real-time progress visualization const { JOBS: ALL_JOBS } = window.ZAMPP_DATA; function Jobs({ navigate }) { const [tab, setTab] = React.useState("all"); const [jobs, setJobs] = React.useState(ALL_JOBS); React.useEffect(() => { const i = setInterval(() => { setJobs(js => js.map(j => { if (j.status !== "running") return j; const next = Math.min(100, j.progress + Math.random() * 3); if (next >= 100) return { ...j, progress: 100, status: "done", eta: "—" }; const [m, s] = j.eta.split(":").map(Number); const total = m * 60 + s - 1; const newEta = total > 0 ? `${String(Math.floor(total / 60)).padStart(2, "0")}:${String(total % 60).padStart(2, "0")}` : "00:00"; return { ...j, progress: next, eta: newEta }; })); }, 1200); return () => clearInterval(i); }, []); const counts = { all: jobs.length, running: jobs.filter(j => j.status === "running").length, queued: jobs.filter(j => j.status === "queued").length, done: jobs.filter(j => j.status === "done").length, failed: jobs.filter(j => j.status === "failed").length, }; const filtered = tab === "all" ? jobs : jobs.filter(j => j.status === tab); const throughput = [12, 14, 13, 16, 15, 18, 22, 24, 22, 28, 32, 38, 42, 40]; return (

Jobs

Proxy generation, transcoding, AMPP sync — live across worker pool
Throughput
42 / min
+18% vs last hour
Avg duration
4.2 min
Proxy: 6.1m · Transcode: 2.4m
Worker pool
3 / 4 active
GPU util: 67%
Failed (24h)
{counts.failed}
0 ? "var(--warning)" : "var(--text-3)" }}> {counts.failed > 0 ? "1 needs attention" : "All good"}
{[ { id: "all", label: `All · ${counts.all}` }, { id: "running", label: `Running · ${counts.running}` }, { id: "queued", label: `Queued · ${counts.queued}` }, { id: "done", label: `Done · ${counts.done}` }, { id: "failed", label: `Failed · ${counts.failed}` }, ].map(t => ( ))}
Job
Asset
Node
Progress
ETA
Priority
{filtered.map(j => )}
); } function JobRow({ job }) { return (
{job.kind}
{job.asset}
{job.node}
{job.status === "running" && (
{Math.round(job.progress)}%
)} {job.status === "done" && ( Complete )} {job.status === "queued" && ( Waiting… )} {job.status === "failed" && ( {job.error} )}
{job.eta}
{job.priority}
{job.status === "running" && } {job.status === "failed" && } {(job.status === "queued" || job.status === "done") && }
); } function iconForJob(kind) { return { Proxy: "proxy", Transcode: "film", Thumbnail: "image", "AMPP Sync": "refresh" }[kind] || "jobs"; } window.Jobs = Jobs;