"use client"; import Link from "next/link"; import { useMemo } from "react"; import { AgentFeatures } from "@/components/AgentFeatures"; import { CheckEventsLink } from "@/components/CheckEventsLink"; import { Td, Th } from "@/components/DataPanel"; import { LabelChips } from "@/components/Labels"; import { DateTime } from "@/components/TimeZoneControls"; import type { components } from "@/lib/api-types"; import { withLivenessChecks } from "@/lib/check-groups"; import { statusBadgeClass } from "@/lib/format"; import { usePolling } from "@/lib/usePolling"; type Agent = components["schemas"]["Agent"]; type CheckState = components["schemas"]["CheckState"]; type StoredEvent = components["schemas"]["StoredCheckResultEvent"]; type SortKey = "severity" | "check_id" | "last_seen"; type TabKey = "checks" | "events"; type AgentDetailData = { agent: Agent; checks: CheckState[]; events: StoredEvent[]; }; const severityRank: Record = { critical: 0, warning: 1, unknown: 2, ok: 3, }; export function AgentDetailBrowser({ initialData, sort, tab, }: { initialData: AgentDetailData; sort: SortKey; tab: TabKey; }) { const { data } = usePolling( initialData, `/api/poll/agent?agent_id=${encodeURIComponent(initialData.agent.agent_id)}`, ); const { agent, events } = data; const checks = useMemo( () => sortChecks(withLivenessChecks([agent], data.checks), sort), [agent, data.checks, sort], ); return (
← agents

{agent.agent_id}

hostname
{agent.hostname}
status
{agent.status}
last_seen_at
features
labels
{tab === "checks" ? : }
); } function TabNav({ agentId, current, sort }: { agentId: string; current: TabKey; sort: SortKey }) { const base = `/agents/${encodeURIComponent(agentId)}`; return (
Checks Events
); } function ChecksTable({ agentId, checks, sort, }: { agentId: string; checks: CheckState[]; sort: SortKey; }) { if (checks.length === 0) return
No checks.
; return (
{checks.map((c) => ( ))}
check_id status last_observed_at summary
{c.status} {c.summary ?? "—"}
); } function EventsTable({ events }: { events: StoredEvent[] }) { if (events.length === 0) return
No events.
; return (
{events.map((e) => ( ))}
observed_at check_id status duration_ms
{e.status} {e.duration_ms}
); } function SortLink({ agentId, sort, current, children, }: { agentId: string; sort: SortKey; current: SortKey; children: React.ReactNode; }) { return ( {children} ); } function sortChecks(checks: CheckState[], sort: SortKey): CheckState[] { return [...checks].sort((a, b) => { if (sort === "check_id") return a.check_id.localeCompare(b.check_id); if (sort === "last_seen") return b.last_observed_at.localeCompare(a.last_observed_at); return severityRank[a.status] - severityRank[b.status] || a.check_id.localeCompare(b.check_id); }); }