// HLA Typing Lab — hub dashboards.
//
// One component per built lab hub, rendered by HubHome in place of the Cascade
// dashboards (see the LAB_HUB_DASH lookup at the bottom). Plain JSX and the
// .lab-* classes in newhub.css — no framework injection, because these pages
// are representative rather than a port of a design document.
//
// Data comes from lab_data.jsx. Nothing here computes: the numbers are written
// down, the same way Cascade's dashboards read from generated content.
function LabStatRow({ stats }) {
return (
{stats.map((s) => (
{s.label}
{s.value}
{s.sub}
))}
);
}
function LabPanel({ title, sub, children, action }) {
return (
);
}
function LabTable({ cols, rows, render }) {
return (
{cols.map((c) => | {c} | )}
{rows.map(render)}
);
}
// ── Typing hub ────────────────────────────────────────────────────────────
function LabTypingDashboard() {
const rr = window.LAB_RERESOLVE;
const [reresolved, setReresolved] = React.useState(false);
return (
{/* The claim the whole lab model rests on, made visible: a new release
lands and the archive re-derives instead of going stale. */}
setReresolved(true)} disabled={reresolved}>
{reresolved ? 'Re-resolved ✓' : 'Re-resolve archive'}
}>
{rr.buckets.map((b) => (
{b.n}
{b.kind}
{b.note}
))}
(
| {r.id} |
{r.study} |
{r.a} |
{r.b} |
{r.c} |
{r.drb1} |
{r.dqb1} |
{r.res} |
{r.method} |
{r.release} |
{r.status}
|
)}
/>
(
| {r.id} |
{r.locus} |
{r.str} |
{r.cause} |
{r.owner}
{r.route}
|
)}
/>
(
| {r.method} |
{r.years} |
{r.runs} |
{r.first} |
{r.amb} |
{r.conc} |
)}
/>
);
}
// ── Studies & Cohorts hub ─────────────────────────────────────────────────
function LabStudiesDashboard() {
const studies = window.LAB_STUDIES;
const active = studies.filter((s) => s.status === 'Active').length;
const reusable = studies.filter((s) => s.reuse === 'Yes').reduce((n, s) => n + s.n, 0);
return (
n + s.n, 0).toLocaleString(), sub: 'typed for someone else’s question' },
{ label: 'Reusable', value: reusable.toLocaleString(), sub: 'consent covers secondary use' },
{ label: 'Locked', value: '186', sub: 'closed cohort — deliver, don’t reuse' },
]} />
(
| {s.id} |
{s.name} |
{s.pi} |
{s.n} |
{s.need} |
{s.out} |
{s.reuse} |
{s.status} |
)}
/>
subjects where A*02:01 and DRB1*04:01 and consent.reuse = true
→ 61 subjects across HSCT-2026, VAX-COV, HIV-PROG
ARBO-OUT is excluded: 186 subjects, typed, matching — and not reusable. That
exclusion is the model doing its job.
);
}
const LAB_HUB_DASH = {
Typing: LabTypingDashboard,
'Studies & Cohorts': LabStudiesDashboard,
};
window.LabTypingDashboard = LabTypingDashboard;
window.LabStudiesDashboard = LabStudiesDashboard;
window.LAB_HUB_DASH = LAB_HUB_DASH;