diff --git a/src/pages/AgentHealth/AgentHealth.module.css b/src/pages/AgentHealth/AgentHealth.module.css index 322e6e2..f19bc9f 100644 --- a/src/pages/AgentHealth/AgentHealth.module.css +++ b/src/pages/AgentHealth/AgentHealth.module.css @@ -96,16 +96,6 @@ margin-bottom: 20px; } -/* Instance count badge in group header */ -.instanceCountBadge { - font-size: 11px; - font-family: var(--font-mono); - color: var(--text-muted); - background: var(--bg-inset); - padding: 2px 8px; - border-radius: 10px; -} - /* Group meta row */ .groupMeta { display: flex; @@ -138,62 +128,6 @@ flex-shrink: 0; } -/* Instance table */ -.instanceTable { - width: 100%; - border-collapse: collapse; - font-size: 12px; -} - -.instanceTable thead th { - padding: 4px 12px; - font-size: 9px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--text-faint); - text-align: left; - border-bottom: 1px solid var(--border-subtle); - white-space: nowrap; -} - -.thStatus { - width: 12px; -} - -.tdStatus { - width: 12px; - text-align: center; -} - -/* Instance row */ -.instanceRow { - cursor: pointer; - transition: background 0.1s; -} - -.instanceRow td { - padding: 8px 12px; - border-bottom: 1px solid var(--border-subtle); - white-space: nowrap; -} - -.instanceRow:last-child td { - border-bottom: none; -} - -.instanceRow:hover td { - background: var(--bg-hover); -} - -.instanceRowActive td { - background: var(--amber-bg); -} - -.instanceRowActive td:first-child { - box-shadow: inset 3px 0 0 var(--amber); -} - /* Instance fields */ .instanceName { font-weight: 600; diff --git a/src/pages/AgentHealth/AgentHealth.tsx b/src/pages/AgentHealth/AgentHealth.tsx index 2b74538..54e9b03 100644 --- a/src/pages/AgentHealth/AgentHealth.tsx +++ b/src/pages/AgentHealth/AgentHealth.tsx @@ -9,9 +9,11 @@ import { TopBar } from '../../design-system/layout/TopBar/TopBar' // Composites import { GroupCard } from '../../design-system/composites/GroupCard/GroupCard' +import { DataTable } from '../../design-system/composites/DataTable/DataTable' import { LineChart } from '../../design-system/composites/LineChart/LineChart' import { EventFeed } from '../../design-system/composites/EventFeed/EventFeed' import { DetailPanel } from '../../design-system/composites/DetailPanel/DetailPanel' +import type { Column } from '../../design-system/composites/DataTable/types' // Primitives import { StatusDot } from '../../design-system/primitives/StatusDot/StatusDot' @@ -143,6 +145,72 @@ export function AgentHealth() { // Build trend data for selected instance const trendData = selectedInstance ? buildTrendData(selectedInstance) : null + // Column definitions for the instance DataTable + const instanceColumns: Column[] = useMemo(() => [ + { + key: 'status', + header: '', + width: '12px', + render: (_val, row) => ( + + ), + }, + { + key: 'name', + header: 'Instance', + render: (_val, row) => ( + {row.name} + ), + }, + { + key: 'state', + header: 'State', + render: (_val, row) => ( + + ), + }, + { + key: 'uptime', + header: 'Uptime', + render: (_val, row) => ( + {row.uptime} + ), + }, + { + key: 'tps', + header: 'TPS', + render: (_val, row) => ( + {row.tps.toFixed(1)}/s + ), + }, + { + key: 'errorRate', + header: 'Errors', + render: (_val, row) => ( + + {row.errorRate ?? '0 err/h'} + + ), + }, + { + key: 'lastSeen', + header: 'Heartbeat', + render: (_val, row) => ( + + {row.lastSeen} + + ), + }, + ], []) + function handleInstanceClick(inst: AgentHealthData) { setSelectedInstance(inst) setPanelOpen(true) @@ -362,65 +430,14 @@ export function AgentHealth() { ) : undefined} > - - - - - - - - - - - - - {group.instances.map((inst) => ( - handleInstanceClick(inst)} - > - - - - - - - - - ))} - -
- InstanceStateUptimeTPSErrorsHeartbeat
- - - {inst.name} - - - - {inst.uptime} - - {inst.tps.toFixed(1)}/s - - - {inst.errorRate ?? '0 err/h'} - - - - {inst.lastSeen} - -
+ + columns={instanceColumns} + data={group.instances} + onRowClick={handleInstanceClick} + selectedId={panelOpen ? selectedInstance?.id : undefined} + pageSize={50} + flush + /> ))}