diff --git a/ui/src/pages/AgentHealth/AgentHealth.tsx b/ui/src/pages/AgentHealth/AgentHealth.tsx index 6280750f..fd0da9d5 100644 --- a/ui/src/pages/AgentHealth/AgentHealth.tsx +++ b/ui/src/pages/AgentHealth/AgentHealth.tsx @@ -2,15 +2,14 @@ import { useState, useMemo, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router'; import { ExternalLink, RefreshCw, Pencil } from 'lucide-react'; import { - StatCard, StatusDot, Badge, MonoText, ProgressBar, - GroupCard, DataTable, LineChart, EventFeed, DetailPanel, + StatCard, StatusDot, Badge, MonoText, + GroupCard, DataTable, EventFeed, LogViewer, ButtonGroup, SectionHeader, Toggle, useToast, } from '@cameleer/design-system'; import type { Column, FeedEvent, LogEntry, ButtonGroupItem } from '@cameleer/design-system'; import styles from './AgentHealth.module.css'; import { useAgents, useAgentEvents } from '../../api/queries/agents'; import { useApplicationLogs } from '../../api/queries/logs'; -import { useAgentMetrics } from '../../api/queries/agent-metrics'; import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands'; import type { AgentInstance } from '../../api/types'; @@ -96,132 +95,6 @@ function appHealth(group: AppGroup): 'success' | 'warning' | 'error' { // ── Detail sub-components ──────────────────────────────────────────────────── -function AgentOverviewContent({ agent }: { agent: AgentInstance }) { - const { data: memMetrics } = useAgentMetrics( - agent.id, - ['jvm.memory.heap.used', 'jvm.memory.heap.max'], - 1, - ); - const { data: cpuMetrics } = useAgentMetrics(agent.id, ['jvm.cpu.process'], 1); - - const cpuValue = cpuMetrics?.metrics?.['jvm.cpu.process']?.[0]?.value; - const heapUsed = memMetrics?.metrics?.['jvm.memory.heap.used']?.[0]?.value; - const heapMax = memMetrics?.metrics?.['jvm.memory.heap.max']?.[0]?.value; - - const heapPercent = - heapUsed != null && heapMax != null && heapMax > 0 - ? Math.round((heapUsed / heapMax) * 100) - : undefined; - const cpuPercent = cpuValue != null ? Math.round(cpuValue * 100) : undefined; - - const ns = normalizeStatus(agent.status); - - return ( -
-
- Status - -
-
- Application - {agent.application} -
-
- Uptime - {formatUptime(agent.uptimeSeconds)} -
-
- Last Seen - {timeAgo(agent.lastHeartbeat)} -
-
- Throughput - {agent.tps != null ? `${agent.tps.toFixed(1)}/s` : '\u2014'} -
-
- Errors - - {formatErrorRate(agent.errorRate)} - -
-
- Routes - {agent.activeRoutes ?? 0}/{agent.totalRoutes ?? 0} active -
-
- Heap Memory - {heapPercent != null ? ( -
- 85 ? 'error' : heapPercent > 70 ? 'warning' : 'success'} - size="sm" - /> - {heapPercent}% -
- ) : ( - N/A - )} -
-
- CPU - {cpuPercent != null ? ( -
- 80 ? 'error' : cpuPercent > 60 ? 'warning' : 'success'} - size="sm" - /> - {cpuPercent}% -
- ) : ( - N/A - )} -
-
- ); -} - -function AgentPerformanceContent({ agent }: { agent: AgentInstance }) { - const { data: tpsMetrics } = useAgentMetrics(agent.id, ['cameleer.tps'], 60); - const { data: errMetrics } = useAgentMetrics(agent.id, ['cameleer.error.rate'], 60); - - const tpsSeries = useMemo(() => { - const raw = tpsMetrics?.metrics?.['cameleer.tps'] ?? []; - return [{ label: 'TPS', data: raw.map((p) => ({ x: new Date(p.time), y: p.value })) }]; - }, [tpsMetrics]); - - const errSeries = useMemo(() => { - const raw = errMetrics?.metrics?.['cameleer.error.rate'] ?? []; - return [{ - label: 'Error Rate', - data: raw.map((p) => ({ x: new Date(p.time), y: p.value * 100 })), - color: 'var(--error)', - }]; - }, [errMetrics]); - - return ( -
-
-
Throughput (msg/s)
- {tpsSeries[0].data.length > 0 ? ( - - ) : ( -
No data available
- )} -
-
-
Error Rate (%)
- {errSeries[0].data.length > 0 ? ( - - ) : ( -
No data available
- )} -
-
- ); -} - const LOG_LEVEL_ITEMS: ButtonGroupItem[] = [ { value: 'error', label: 'Error', color: 'var(--error)' }, { value: 'warn', label: 'Warn', color: 'var(--warning)' }, @@ -301,9 +174,6 @@ export default function AgentHealth() { .filter((l) => logLevels.size === 0 || logLevels.has(l.level)) .filter((l) => !logSearchLower || l.message.toLowerCase().includes(logSearchLower)); - const [selectedInstance, setSelectedInstance] = useState(null); - const [panelOpen, setPanelOpen] = useState(false); - const agentList = agents ?? []; const groups = useMemo(() => groupByApp(agentList), [agentList]); @@ -428,26 +298,9 @@ export default function AgentHealth() { ); function handleInstanceClick(inst: AgentInstance) { - setSelectedInstance(inst); - setPanelOpen(true); + navigate(`/runtime/${inst.application}/${inst.id}`); } - // Detail panel tabs - const detailTabs = selectedInstance - ? [ - { - label: 'Overview', - value: 'overview', - content: , - }, - { - label: 'Performance', - value: 'performance', - content: , - }, - ] - : []; - const isFullWidth = !!appId; return ( @@ -677,7 +530,6 @@ export default function AgentHealth() { columns={instanceColumns} data={group.instances} onRowClick={handleInstanceClick} - selectedId={panelOpen ? selectedInstance?.id : undefined} pageSize={50} flush /> @@ -758,15 +610,6 @@ export default function AgentHealth() { - {/* Detail panel — auto-portals to AppShell level via design system */} - {selectedInstance && ( - { setPanelOpen(false); setSelectedInstance(null); }} - title={selectedInstance.name ?? selectedInstance.id} - tabs={detailTabs} - /> - )} ); }