/* Archive + Report viewer + Settings */ /* ------------------------------ ARCHIVE ------------------------------ */ function ArchiveScreen({ onNav, filterType = "all" }) { const [typeFilter, setTypeFilter] = useState(filterType); const [ragFilter, setRagFilter] = useState("all"); const [query, setQuery] = useState(""); const [view, setView] = useState("timeline"); // timeline | table const [allReports, setAllReports] = useState(null); // null = loading useEffect(() => { setTypeFilter(filterType); }, [filterType]); useEffect(() => { api.get("/api/reports").then(setAllReports).catch(() => setAllReports(DEMO_REPORTS)); }, []); const sourceReports = allReports !== null ? allReports : DEMO_REPORTS; let reports = sourceReports.slice().sort((a, b) => b.date.localeCompare(a.date)); if (typeFilter !== "all") reports = reports.filter(r => r.type === typeFilter); if (ragFilter !== "all") reports = reports.filter(r => (r.overall_rag || r.overall) === ragFilter); if (query) reports = reports.filter(r => { const t = reportTypeMeta(r.type); return (t ? t.name.toLowerCase().includes(query.toLowerCase()) : false) || r.date.includes(query); }); // Group by date for timeline const byDate = {}; reports.forEach(r => { (byDate[r.date] = byDate[r.date] || []).push(r); }); const dates = Object.keys(byDate).sort((a, b) => b.localeCompare(a)); const _rag = (r) => r.overall_rag || r.overall || "amber"; return (
Archive
{allReports === null ? "Loading…" : `${reports.length} reports · browse, filter, and compare past runs.`}
{/* Filter bar */}
setQuery(e.target.value)} placeholder="Search by type or date…" style={{ flex: 1, border: "none", outline: "none", background: "transparent", fontSize: 13, color: "var(--text)", fontFamily: "inherit" }} /> {query && setQuery("")} style={{ color: "var(--text-3)", width: 13, height: 13, cursor: "pointer" }} />}
{[ { id: "all", l: "All" }, ...REPORT_TYPES.map(t => ({ id: t.id, l: t.shortName })), ].map(o => ( ))}
{["all", "red", "amber", "green"].map(r => ( ))}
{[{ id: "timeline", l: "Timeline" }, { id: "table", l: "Table" }].map(v => ( ))}
{view === "timeline" && (
{dates.map(date => { const group = byDate[date]; const overall = _rag(group[0]); const d = new Date(date); const weekday = d.toLocaleDateString("en-GB", { weekday: "long" }); const pretty = d.toLocaleDateString("en-GB", { day: "numeric", month: "long", year: "numeric" }); return (
{pretty}
{weekday} · {group.length} report{group.length !== 1 ? "s" : ""}
{group.map(r => { const t = reportTypeMeta(r.type); const Icon = t.icon; return (
onNav("report", { reportId: r.id })} onMouseEnter={e => { e.currentTarget.style.borderColor = "var(--border-2)"; e.currentTarget.style.boxShadow = "var(--sh-md)"; }} onMouseLeave={e => { e.currentTarget.style.borderColor = "var(--border)"; e.currentTarget.style.boxShadow = "none"; }} >
{t.name}
{r.id}.html
{(r.metrics || {}).velocityPct ?? "—"}% velocity
{(r.metrics || {}).overdue ?? "—"} overdue
); })}
); })}
)} {view === "table" && (
{reports.map(r => { const t = reportTypeMeta(r.type); const Icon = t ? t.icon : I.File; return ( onNav("report", { reportId: r.id })}> ); })}
DateReportOverallVelocityOverdueBlockersAuthor
{r.date}
{t ? t.name : r.type}
{_rag(r) && } {(r.metrics || {}).velocityPct ?? "—"}% {(r.metrics || {}).overdue ?? "—"} {(r.metrics || {}).blockers ?? "—"} {r.author}
)}
); } /* ------------------------------ REPORT VIEWER ------------------------------ */ function ReportViewer({ reportId, onNav }) { const [report, setReport] = useState(null); const [showHtml, setShowHtml] = useState(false); useEffect(() => { // Try API first, fall back to demo data api.get(`/api/reports/${reportId}`) .then(setReport) .catch(() => { const demo = DEMO_REPORTS.find(r => r.id === reportId) || DEMO_REPORTS[0]; setReport(demo); }); }, [reportId]); if (!report) { return
Loading report…
; } const t = reportTypeMeta(report.type); const Icon = t ? t.icon : I.File; const overallRag = report.overall_rag || report.overall || "amber"; return (
{/* Report toolbar */}
{t ? t.name : report.type} · {report.date} {overallRag && }
{report.html_file && ( )}
{showHtml && report.html_file && (