import { useEffect, useState } from "react";
import { Activity, ShieldAlert, Clock, Flame } from "lucide-react";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Badge } from "@/components/ui/badge";
import { InfoTip } from "@/components/ui/popover";
import { LoadingState, ErrorState } from "@/components/ui/feedback";
import {
MetricStat,
ConfusionMatrix,
HBarChart,
OperatingPointsChart,
ChartCard,
} from "@/components/charts";
import { api } from "@/lib/api";
import type {
MetricsData,
TaskMetrics,
DurationMetrics,
HotspotMetrics,
} from "@/lib/types";
import { pct, num, minutesToHuman, titleCase } from "@/lib/format";
function FigureImage({ name, alt }: { name: string; alt: string }) {
const [ok, setOk] = useState(true);
if (!ok) return null;
return (
setOk(false)}
className="w-full rounded-md border border-border bg-white"
/>
);
}
function Hero({
headline,
unit,
caption,
badge,
}: {
headline: string;
unit?: string;
caption: string;
badge?: { text: string; variant: "success" | "warning" | "danger" | "accent" };
}) {
return (
{headline}
{unit && {unit}}
{caption}
{badge &&
{badge.text}}
);
}
/* ----------------------------- Priority ----------------------------- */
function PriorityPanel({ m }: { m: TaskMetrics }) {
return (
);
}
/* ----------------------------- Closure ----------------------------- */
function ClosurePanel({ m }: { m: TaskMetrics }) {
const ops = m.operating_points;
const opData = [
{ key: "mcc_optimal", name: "Balanced" },
{ key: "f2_optimal", name: "Deployed (F2)" },
{ key: "recall>=0.8", name: "Never-miss" },
]
.filter((o) => ops[o.key])
.map((o) => ({
name: o.name,
recall: ops[o.key].recall,
precision: ops[o.key].precision,
mcc: ops[o.key].mcc,
}));
return (
);
}
/* ----------------------------- Duration ----------------------------- */
function DurationPanel({ m }: { m: DurationMetrics }) {
return (
{minutesToHuman(m.median_ae_min)}
median absolute error
p10
median width {num(m.interval_width_med_min)} min
p90
);
}
function ScaleBar({
label,
value,
max,
color,
reference,
}: {
label: string;
value: number;
max: number;
color: string;
reference?: number;
}) {
return (
{label}
{value.toFixed(3)}
{reference != null && (
)}
);
}
/* ----------------------------- Hotspot ----------------------------- */
function HotspotPanel({ m }: { m: HotspotMetrics }) {
const t = m.test;
const ops = m.test_operating_points;
const opData = [
{ key: "mcc_optimal", name: "Balanced" },
{ key: "f2_optimal", name: "Deployed (F2)" },
]
.filter((o) => ops[o.key])
.map((o) => ({
name: o.name,
recall: ops[o.key].recall,
precision: ops[o.key].precision,
mcc: ops[o.key].mcc,
}));
const topFeatures = Object.entries(m.top_features)
.slice(0, 12)
.map(([name, value]) => ({ name: name, value }))
.reverse();
return (
);
}
/* ----------------------------- Page ----------------------------- */
export default function Models() {
const [metrics, setMetrics] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
api.metrics().then(setMetrics).catch((e) => setError((e as Error).message));
}, []);
if (error) return ;
if (!metrics) return ;
return (
Model report
Four leakage-controlled targets on a chronological hold-out (train on
the past, test on the future). {metrics.dataset.n_events_scored.toLocaleString()} events ·{" "}
{metrics.dataset.date_span}. Tap any{" "}
ⓘ for the “why”.
Priority
Closure
Duration
Hotspot
);
}