import type { Metadata } from 'next'; import Link from 'next/link'; import { PageHeader } from '@/components/ui/section'; import { Badge, ConfidenceBadge } from '@/components/ui/badge'; import { CompletenessDots } from '@/components/ui/completeness'; import { EmptyState } from '@/components/ui/empty-state'; import { Pagination } from '@/components/ui/pagination'; import { explorerCount, explorerRows, listAnatomicalSites, ENTITY_TYPES, SORTS, type ExplorerFilters, type ExplorerRow } from '@/lib/queries/cancers'; import { fmtInt, humanize } from '@/lib/format'; import { str, int, oneOf, bool, withParams, type SP } from '@/lib/search-params'; export const metadata: Metadata = { title: 'Cancers', description: 'Explore every indexed cancer entity with filters for type, anatomical site, hematologic and pediatric relevance.' }; // Filtered list: rendered per request (searchParams); 600 s is the CDN/ISR hint shared by all list pages. export const revalidate = 600; const PAGE_SIZE = 50; function dataConfidence(r: ExplorerRow): string { const domains = [r.epidemiology_obs_count, r.survival_obs_count, r.gene_count, r.evidence_count, r.drug_count, r.active_trial_count, r.publication_count_5y].filter((n) => (n ?? 0) > 0).length; if (domains >= 5) return 'HIGH'; if (domains >= 3) return 'MEDIUM'; if (domains >= 1) return 'LOW'; return 'INSUFFICIENT_DATA'; } export default async function CancersPage({ searchParams }: { searchParams: Promise }) { const sp = await searchParams; const f: ExplorerFilters = { q: str(sp, 'q'), level: oneOf(sp, 'level', ['top', 'all'] as const, 'all'), entityType: ENTITY_TYPES.includes(str(sp, 'entity_type') as (typeof ENTITY_TYPES)[number]) ? str(sp, 'entity_type') : '', malignant: bool(sp, 'malignant'), hematologic: bool(sp, 'hematologic'), pediatric: bool(sp, 'pediatric'), site: str(sp, 'site'), sort: oneOf(sp, 'sort', SORTS, 'name'), page: int(sp, 'page', 1, 1, 10_000), pageSize: PAGE_SIZE, }; const [total, rows, sites] = await Promise.all([explorerCount(f), explorerRows(f), listAnatomicalSites()]); const current = { q: f.q, level: f.level, entity_type: f.entityType, malignant: f.malignant == null ? '' : f.malignant ? '1' : '0', hematologic: f.hematologic == null ? '' : f.hematologic ? '1' : '0', pediatric: f.pediatric == null ? '' : f.pediatric ? '1' : '0', site: f.site, sort: f.sort }; const href = (o: Record) => `/cancers${withParams({ ...current, level: f.level === 'all' ? '' : f.level }, o)}`; return (

{fmtInt(total)} {total === 1 ? 'entity' : 'entities'} {f.q ? ( <> {' '} matching {f.q} ) : null} {f.level === 'top' && total === 0 ? — the top-level flag is assigned when the NCIt anchor concepts are ingested; until then browse all entities. : null}

{rows.length === 0 ? (
) : ( <>
{rows.map((r) => ( ))}
Cancer Type Parent(s) Active trials (count) Publications 5y (count) Evidence items (count) Children Completeness Data confidence
{r.canonical_name} {r.id} {r.hematologic ? Hematologic : null} {r.pediatric_relevant ? Pediatric : null} {r.rare_cancer === true ? Rare : null} {!r.malignant ? Non-malignant / precursor : null} {humanize(r.entity_type)} {r.parents?.length ? r.parents.map((p, i) => ( {i > 0 ? ', ' : ''} {p.name} )) : root} {r.active_trial_count == null ? — : fmtInt(r.active_trial_count)} {r.publication_count_5y == null ? — : fmtInt(r.publication_count_5y)} {r.evidence_count == null ? — : fmtInt(r.evidence_count)} {fmtInt(r.child_count)}
href({ page: p === 1 ? '' : p })} />

"—" means no counter has been computed for this entity yet (counters appear after the first connector of that domain runs). Data confidence summarizes how many domains hold data; it is not a clinical judgement.

)}
); }