'use client'; import Link from 'next/link'; import { useCallback, useEffect, useState } from 'react'; import { Bars } from '@/components/charts/bars'; import { SensorTierBadge, StatusBadge } from '@/components/ui/badges'; import { LiveAgo } from '@/components/ui/live'; import { Note } from '@/components/ui/section'; import { SkeletonRows } from '@/components/ui/skeleton'; import { useAdminToken } from '@/lib/admin'; import { adminApi } from '@/lib/client-api'; import { fmt1, fmtBytes, fmtDateTime, fmtInt, fmtPct, fmtScore, fmtUsd, pathOf } from '@/lib/format'; import { routes } from '@/lib/site'; import type { AdminCompany, AdminConnector, AdminCosts, AdminFailure, AdminLlmJob, AdminOverview, AdminQuality, AdminQueueItem, AdminReview, AdminSensor, Page } from '@/lib/types'; import { AdminError, AdminShell, AdminTable, KpiRow } from './admin-shell'; /** Generic loader: fetches with the admin token, exposes refresh; children render data. */ function useAdminData(loader: (api: ReturnType, signal: AbortSignal) => Promise, deps: unknown[] = []) { const token = useAdminToken(); const [data, setData] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [tick, setTick] = useState(0); const refresh = useCallback(() => setTick((t) => t + 1), []); useEffect(() => { if (!token) return; const ctrl = new AbortController(); setLoading(true); loader(adminApi(token), ctrl.signal) .then((d) => { setData(d); setError(null); }) .catch((e: Error) => { if (e.name !== 'AbortError') setError(e.message); }) .finally(() => setLoading(false)); return () => ctrl.abort(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [token, tick, ...deps]); return { data, error, loading, refresh, token }; } const entries = (o: Record | undefined) => Object.entries(o ?? {}).sort((a, b) => b[1] - a[1]); /* -------------------------------------------------------------------------------------------------------------- overview */ export function OverviewModule() { const { data, error, loading, refresh } = useAdminData((api, s) => api.overview(s)); return ( {!data ? ( ) : (
300 ? 'warning' : undefined }, { label: 'Dead jobs', value: fmtInt(data.queue.dead), tone: data.queue.dead ? 'danger' : undefined }, { label: 'Fetch / h', value: fmtInt(data.fetch_rate_1h) }, { label: 'Changes / h', value: fmtInt(data.change_rate_1h), hint: `${fmtInt(data.meaningful_rate_1h)} meaningful` }, { label: 'LLM pending', value: fmtInt(data.llm.pending), hint: `${fmtInt(data.llm.done_today)} done · ${fmtInt(data.llm.failed_today)} failed today` }, { label: 'Cost today', value: fmtUsd(data.cost_today.fetch + data.cost_today.browser + data.cost_today.llm), hint: `fetch ${fmtUsd(data.cost_today.fetch)} · browser ${fmtUsd(data.cost_today.browser)} · llm ${fmtUsd(data.cost_today.llm)}` }, ]} />

Sensors by status

({ key: k, label: k, value: v, color: k === 'failing' ? 'var(--danger)' : k === 'active' ? 'var(--positive)' : undefined }))} />

Sensors by tier

({ key: k, label: `Tier ${k}`, value: v }))} />

Failures 24 h by class

({ key: k, label: k, value: v, color: 'var(--danger)', href: `/admin/failures?class=${k}` }))} />

Companies by status

({ key: k, label: k, value: v }))} />

Workers

Name Last seen In flight } > {data.workers.map((w) => ( {w.name} {w.inflight} ))}

Storage

{fmtInt(data.storage.objects)} objects · {fmtBytes(data.storage.bytes)} · LLM budget left {data.llm.budget_left === null ? '—' : fmtPct(data.llm.budget_left, 0)}

)}
); } /* -------------------------------------------------------------------------------------------------------------- connectors */ export function ConnectorsModule() { const { data, error, loading, refresh } = useAdminData<{ items: AdminConnector[] }>((api, s) => api.connectors(s)); return ( {!data ? ( ) : ( Connector Version Category Enabled Active Failing Success 24 h Latency Change rate Errors 24 h Last run } > {data.items.map((c) => ( {c.name} {c.id} {c.version} {c.category} {c.enabled ? : } {fmtInt(c.sensors_active)} {fmtInt(c.sensors_failing)} {fmtPct(c.success_rate_24h, 1)} {c.avg_latency_ms === null ? '—' : `${fmtInt(c.avg_latency_ms)} ms`} {fmtPct(c.change_rate_24h, 1)} {fmtInt(c.errors_24h)} ))} )} ); } /* -------------------------------------------------------------------------------------------------------------- sensors */ const SENSOR_FILTERS = ['', 'healthy', 'failing', 'stale', 'blocked', 'redirected', 'low_quality', 'high_activity']; const ACTIONS = ['pause', 'resume', 'retry', 'rediscover', 'retire', 'run_now']; export function SensorsModule({ initial }: { initial: Record }) { const [filter, setFilter] = useState(initial.filter ?? ''); const [domain, setDomain] = useState(initial.domain ?? ''); const [connector, setConnector] = useState(initial.connector ?? ''); const [page, setPage] = useState(1); const [msg, setMsg] = useState(null); const { data, error, loading, refresh, token } = useAdminData>((api, s) => api.sensors({ filter: filter || undefined, domain: domain || undefined, connector: connector || undefined, page, per_page: 50 }, s), [filter, domain, connector, page]); const act = async (id: string, action: string) => { if (!token) return; const body: Record = {}; if (action === 'set_interval') { const v = prompt('New interval in seconds'); if (!v) return; body.interval_s = Number(v); } try { await adminApi(token).sensorAction(id, action, body); setMsg(`${action} → ${id}`); refresh(); } catch (e) { setMsg(`failed: ${(e as Error).message}`); } }; return (
{SENSOR_FILTERS.map((f) => ( ))}
{ setDomain(e.target.value); setPage(1); }} placeholder="domain contains…" className="field h-9 w-44 text-xs" aria-label="Domain filter" /> { setConnector(e.target.value); setPage(1); }} placeholder="connector id" className="field h-9 w-40 text-xs" aria-label="Connector filter" /> {msg && {msg}}
{!data ? ( ) : ( <> Company Surface URL Status Tier Q Fails Last success Interval Actions } > {data.items.map((s) => ( {s.company.display_name} {s.surface} {pathOf(s.url)} {s.last_failure_class && {s.last_failure_class}} {fmtScore(s.quality_score)} {s.consecutive_failures} {fmtInt(s.current_interval_s)} s {ACTIONS.filter((a) => (s.status === 'paused' ? a !== 'pause' : a !== 'resume')).map((a) => ( ))} ))}
page {data.page} / {data.pages} · {fmtInt(data.total)} sensors
)}
); } /* -------------------------------------------------------------------------------------------------------------- companies */ export function CompaniesModule() { const [status, setStatus] = useState(''); const [page, setPage] = useState(1); const [form, setForm] = useState({ website: '', display_name: '', country: '', industries: '' }); const [msg, setMsg] = useState(null); const { data, error, loading, refresh, token } = useAdminData>((api, s) => api.companies({ onboarding_status: status || undefined, page, per_page: 50 }, s), [status, page]); const submit = async (e: React.FormEvent) => { e.preventDefault(); if (!token || !form.website) return; try { await adminApi(token).createCompany({ website: form.website, display_name: form.display_name || undefined, country: form.country || undefined, industries: form.industries ? form.industries.split(',').map((s) => s.trim()).filter(Boolean) : undefined }); setMsg(`queued discovery for ${form.website}`); setForm({ website: '', display_name: '', country: '', industries: '' }); refresh(); } catch (err) { setMsg(`failed: ${(err as Error).message}`); } }; return (
setForm({ ...form, website: e.target.value })} placeholder="https://example.com (required)" className="field text-sm" aria-label="Website" required /> setForm({ ...form, display_name: e.target.value })} placeholder="Display name" className="field text-sm" aria-label="Display name" /> setForm({ ...form, country: e.target.value.toUpperCase() })} placeholder="CC" maxLength={2} className="field text-sm" aria-label="Country code" /> setForm({ ...form, industries: e.target.value })} placeholder="industries, comma-separated" className="field text-sm" aria-label="Industries" />
{msg &&

{msg}

}
{['', 'pending', 'discovering', 'active', 'failed'].map((s) => ( ))}
{!data ? ( ) : ( Company Domain Country Status Onboarding Tier Sensors Events Last observed } > {data.items.map((c) => ( {c.display_name} {c.canonical_domain} {c.country ?? '—'} {c.tier} {fmtInt(c.counts.sensors)} {fmtInt(c.counts.events)} ))} )}
); } /* -------------------------------------------------------------------------------------------------------------- failures */ export function FailuresModule({ initialClass }: { initialClass?: string }) { const [cls, setCls] = useState(initialClass ?? ''); const { data, error, loading, refresh } = useAdminData>((api, s) => api.failures({ class: cls || undefined, per_page: 100 }, s), [cls]); return (
setCls(e.target.value.toUpperCase())} placeholder="class (TIMEOUT, HTTP_4XX, BOT_CHALLENGE…)" className="field h-9 w-72 text-xs" aria-label="Failure class" />
{!data ? ( ) : ( When Class HTTP Company Domain Message Retry } > {data.items.map((f) => ( {fmtDateTime(f.occurred_at)} {f.failure_class} {f.status_code || '—'} {f.company ? {f.company.display_name} : '—'} {f.domain ?? '—'} {f.message ?? '—'} {f.retry_at ? : '—'} ))} )}
); } /* -------------------------------------------------------------------------------------------------------------- queue */ export function QueueModule() { const [kind, setKind] = useState(''); const [status, setStatus] = useState(''); const [msg, setMsg] = useState(null); const { data, error, loading, refresh, token } = useAdminData<{ items: AdminQueueItem[]; counts?: Record } | Page>((api, s) => api.queue({ kind: kind || undefined, status: status || undefined }, s), [kind, status]); const items = data?.items ?? []; const counts = data && 'counts' in data ? data.counts : undefined; return (
{counts && {Object.entries(counts).map(([k, v]) => `${k} ${v}`).join(' · ')}} {msg && {msg}}
{!data ? ( ) : ( Id Kind Status Prio Attempts Scheduled Worker Ref Error } > {items.map((j) => ( {j.id} {j.kind} {j.priority} {j.attempts} {j.worker ?? '—'} {j.ref ?? '—'} {j.error ?? ''} ))} )}
); } /* -------------------------------------------------------------------------------------------------------------- llm */ export function LlmModule() { const [status, setStatus] = useState(''); const { data, error, loading, refresh } = useAdminData>((api, s) => api.llm({ status: status || undefined, per_page: 100 }, s), [status]); return (
{['', 'pending', 'done', 'failed'].map((s) => ( ))}
{!data ? ( ) : ( Created Kind Status Model Prompt Tokens in / out Cost Change Event Error } > {data.items.map((j) => ( {fmtDateTime(j.created_at)} {j.kind} {j.model ?? '—'} {j.prompt_version ?? '—'} {fmtInt(j.tokens_in)} / {fmtInt(j.tokens_out)} {j.cost_estimate === null ? '—' : `$${j.cost_estimate.toFixed(3)}`} {j.change_id ? {j.change_id.slice(0, 12)}… : '—'} {j.event_id ? {j.event_id.slice(0, 12)}… : '—'} {j.error ?? ''} ))} )}
); } /* -------------------------------------------------------------------------------------------------------------- reviews */ export function ReviewsModule() { const [status, setStatus] = useState('open'); const [msg, setMsg] = useState(null); const { data, error, loading, refresh, token } = useAdminData<{ items: AdminReview[] } | Page>((api, s) => api.reviews({ status: status || undefined }, s), [status]); const resolve = async (id: string, resolution: 'accepted' | 'rejected') => { if (!token) return; try { await adminApi(token).resolveReview(id, resolution); setMsg(`${resolution}: ${id}`); refresh(); } catch (e) { setMsg((e as Error).message); } }; const retract = async (eventId: string) => { if (!token) return; const reason = prompt('Retraction reason (kept in the audit history)'); if (!reason) return; try { await adminApi(token).retractEvent(eventId, reason); setMsg(`retracted ${eventId}`); } catch (e) { setMsg((e as Error).message); } }; return (
{['open', 'resolved', ''].map((s) => ( ))} {msg && {msg}}
{!data ? ( ) : (
    {data.items.map((r) => (
  • {r.kind.replace(/_/g, ' ')} {r.company && ( {r.company.display_name} )} {fmtDateTime(r.created_at)}

    {r.subject}

    {r.reason &&

    reason: {r.reason}

    } {r.status === 'open' && (
    {r.ref_id?.startsWith('evt_') && ( <> Open event )}
    )}
  • ))}
)}
); } /* -------------------------------------------------------------------------------------------------------------- quality */ export function QualityModule() { const { data, error, loading, refresh } = useAdminData((api, s) => api.quality(s)); return ( {!data ? ( ) : (
3 ? 'warning' : undefined }, { label: 'Event confidence', value: data.event_confidence_avg === null ? '—' : fmt1(data.event_confidence_avg * 100) + ' %' }, { label: 'Failed sensors', value: fmtInt(data.failed_sensors), tone: data.failed_sensors ? 'danger' : undefined, hint: `${fmtInt(data.unknown_surfaces)} unknown surfaces` }, ]} />

Calibration (human-labelled sample)

({ key: k, label: k, value: v, color: k === 'correct' ? 'var(--positive)' : k === 'misclassified' ? 'var(--danger)' : 'var(--warning)' }))} />
Calibration counts feed the evaluation set used before changing extractors, normalisers or prompts.
)}
); } /* -------------------------------------------------------------------------------------------------------------- costs */ export function CostsModule() { const [days, setDays] = useState(30); const { data, error, loading, refresh } = useAdminData((api, s) => api.costs(days, s), [days]); const byDim: Record = {}; for (const i of data?.items ?? []) { const k = `${i.dimension} · ${i.key}`; byDim[k] ??= { units: 0, cost: 0 }; byDim[k].units += i.units; byDim[k].cost += i.cost_estimate; } return (
{[7, 30, 90].map((d) => ( ))}
{!data ? ( ) : (
a + b.cost, 0)) }, ]} /> Dimension Units Cost estimate } > {Object.entries(byDim) .sort((a, b) => b[1].cost - a[1].cost) .map(([k, v]) => ( {k} {fmtInt(v.units)} {fmtUsd(v.cost)} ))}
)}
); }