From 08bac437f71a1c9b439e7bbb5c002ccb6aa748b4 Mon Sep 17 00:00:00 2001
From: hsiegeln <37154749+hsiegeln@users.noreply.github.com>
Date: Tue, 24 Mar 2026 12:29:45 +0100
Subject: [PATCH] refactor: replace raw HTML tables in AgentHealth with
DataTable composite
Replace hand-rolled
// markup in the AgentHealth page
with the existing DataTable composite, using column definitions with custom
render functions for StatusDot, Badge, and MonoText cells. Uses flush prop
for seamless GroupCard integration and pageSize=50 to avoid pagination.
Removes unused table-specific CSS classes (.instanceTable, .instanceRow,
.thStatus, .tdStatus, .instanceRowActive, .instanceCountBadge).
Co-Authored-By: Claude Opus 4.6 (1M context)
---
src/pages/AgentHealth/AgentHealth.module.css | 66 ---------
src/pages/AgentHealth/AgentHealth.tsx | 135 +++++++++++--------
2 files changed, 76 insertions(+), 125 deletions(-)
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}
>
-
-
-
- |
- Instance |
- State |
- Uptime |
- TPS |
- Errors |
- Heartbeat |
-
-
-
- {group.instances.map((inst) => (
- handleInstanceClick(inst)}
- >
- |
-
- |
-
- {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
+ />
))}