--- title: Progress --- ```js const API = "http://127.0.0.1:8000"; const POLL = 15_000; ``` ```js const progState = (async function*() { while (true) { let data = [], ok = false; try { const r = await fetch(`${API}/progress/?limit=500`); ok = r.ok; data = ok ? await r.json() : []; } catch {} yield {data, ok, ts: new Date()}; await new Promise(res => setTimeout(res, POLL)); } })(); ``` ```js const data = progState.data ?? []; const _ok = progState.ok ?? false; const _ts = progState.ts; ``` # Progress Log ```js import {injectTocTop} from "./components/toc-sidebar.js"; import {withDocHelp} from "./components/doc-overlay.js"; const _liveEl = html`
make api`}
No events in the last 30 days.
` : Plot.plot({ title: "Progress events per day (30-day window)", x: {label: "Date", tickRotate: -30}, y: {label: "Events", grid: true}, marks: [ Plot.areaY(byDay, {x: "day", y: "count", fill: "steelblue", fillOpacity: 0.3}), Plot.lineY(byDay, {x: "day", y: "count", stroke: "steelblue"}), Plot.ruleY([0]), ], marginBottom: 60, width: 750, }) ); ``` ## Event Log ```js const authorOpts = ["(all)", ...new Set(data.map(e => e.author ?? "unknown"))].sort(); const typeOpts = ["(all)", ...new Set(data.map(e => e.event_type))].sort(); const authorFilter = view(Inputs.select(authorOpts, {label: "Author"})); const typeFilter = view(Inputs.select(typeOpts, {label: "Event type"})); const sinceFilter = view(Inputs.date({label: "Since"})); ``` ```js const filtered = data.filter(e => (authorFilter === "(all)" || (e.author ?? "unknown") === authorFilter) && (typeFilter === "(all)" || e.event_type === typeFilter) && (!sinceFilter || new Date(e.created_at) >= sinceFilter) ); display(html`${filtered.length} events shown (append-only, no deletions).
`); display(Inputs.table(filtered.map(e => ({ Time: new Date(e.created_at).toLocaleString(), Type: e.event_type, Author: e.author ?? "—", Summary: e.summary, })), {rows: 50})); ```