1import { Link, useParams } from "react-router";2import type { Agent, Dataset, Debt, ExecutionRow, PackageRow, Project } from "../api";3import { useFetch, fmtDate } from "../hooks";4import { Badge, ErrorBox, JsonTree, KV, Loading, Td } from "../components/ui";5import { DebtTable } from "../components/shared";67type PD = Project & { agents: Agent[]; datasets: Dataset[]; recent_executions: ExecutionRow[]; decisions: { decision: string; n: number }[]; debt: Debt[]; approved_akp_details: PackageRow[] };89export default function ProjectDetail() {10 const { id } = useParams();11 const { data, error, loading, reload } = useFetch<PD>(`projects/${id}`);12 if (loading) return <Loading />; if (error) return <ErrorBox error={error} />; if (!data) return null;13 const p = data;14 return (15 <div>16 <h1>{p.name} <Badge v={p.policy_mode} /></h1>17 <div className="grid c2">18 <div className="card"><KV items={[["Slug", p.slug], ["Policy mode", p.policy_mode], ["Approved AKPs", p.approved_akp_details.length ? p.approved_akp_details.map((k) => <div key={k.id}><Link to={`/akps/${k.id}`}>{k.akp_id} v{k.version}</Link> <Badge v={k.lifecycle} /></div>) : "none"], ["Decisions", p.decisions.map((d) => `${d.decision}: ${d.n}`).join(" · ") || "none"], ["Created", fmtDate(p.created_at)]]} /><h3>Budget</h3><JsonTree data={p.budget} open /><p className="hint">Change mode / approvals in <Link to="/policy">Policy Center</Link>.</p></div>19 <div className="card"><h3>Agents</h3>{p.agents.length ? p.agents.map((a) => <div key={a.id} className="row between" style={{ fontSize: 13 }}><span><b>{a.name}</b> <span className="hint">{a.kind}</span></span><span className="hint">{a.executions ?? 0} executions · {Object.entries(a.permissions).filter(([, v]) => v).map(([k]) => k).join(", ")}</span></div>) : <span className="hint">none</span>}20 <h3>Datasets</h3>{p.datasets.length ? p.datasets.map((d) => <div key={d.id}><Link to={`/datasets/${d.id}`}>{d.name}</Link> <Badge v={d.verification} /> <span className="hint">{d.row_count} rows</span></div>) : <span className="hint">none</span>}</div>21 </div>22 <div className="card"><h3>Recent executions</h3>{p.recent_executions.length ? <table className="tbl"><thead><tr><th>When</th><th>State</th><th>Request</th><th>Status</th></tr></thead><tbody>{p.recent_executions.map((e) => <tr key={e.id}><Td l="when"><Link to={`/executions/${e.id}`}>{fmtDate(e.created_at)}</Link></Td><Td l="state"><Badge v={e.state} /></Td><Td l="request" wide><span className="truncate mono">{e.method} {e.url}</span></Td><Td l="status">{e.status_code ?? "—"}</Td></tr>)}</tbody></table> : <span className="hint">none</span>}</div>23 <div className="card"><h3>Open debt affecting this project</h3><DebtTable debt={p.debt} onChange={reload} /></div>24 </div>25 );26}27