import { useMemo } from 'react'; import { useParams } from 'react-router'; import { StatCard, StatusDot, Badge, Card, LineChart, AreaChart, BarChart, EventFeed, Breadcrumb, Spinner, EmptyState, } from '@cameleer/design-system'; import styles from './AgentInstance.module.css'; import { useAgents, useAgentEvents } from '../../api/queries/agents'; import { useStatsTimeseries } from '../../api/queries/executions'; import { useAgentMetrics } from '../../api/queries/agent-metrics'; import { useGlobalFilters } from '@cameleer/design-system'; export default function AgentInstance() { const { appId, instanceId } = useParams(); const { timeRange } = useGlobalFilters(); const timeFrom = timeRange.start.toISOString(); const timeTo = timeRange.end.toISOString(); const { data: agents, isLoading } = useAgents(undefined, appId); const { data: events } = useAgentEvents(appId, instanceId); const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, undefined, appId); const agent = useMemo(() => (agents || []).find((a: any) => a.id === instanceId) as any, [agents, instanceId], ); // Stat card metrics (latest 1 bucket) const { data: latestMetrics } = useAgentMetrics( agent?.id || null, ['jvm.cpu.process', 'jvm.memory.heap.used', 'jvm.memory.heap.max'], 1, ); const cpuPct = latestMetrics?.metrics?.['jvm.cpu.process']?.[0]?.value; const heapUsed = latestMetrics?.metrics?.['jvm.memory.heap.used']?.[0]?.value; const heapMax = latestMetrics?.metrics?.['jvm.memory.heap.max']?.[0]?.value; const memPct = heapMax ? (heapUsed! / heapMax) * 100 : undefined; // Chart metrics (60 buckets) const { data: jvmMetrics } = useAgentMetrics( agent?.id || null, ['jvm.cpu.process', 'jvm.memory.heap.used', 'jvm.memory.heap.max', 'jvm.threads.count', 'jvm.gc.time'], 60, ); const chartData = useMemo(() => (timeseries?.buckets || []).map((b: any) => ({ time: new Date(b.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), throughput: b.totalCount, latency: b.avgDurationMs, errors: b.failedCount, })), [timeseries], ); const feedEvents = useMemo(() => (events || []).filter((e: any) => !instanceId || e.agentId === instanceId).map((e: any) => ({ id: String(e.id), severity: e.eventType === 'WENT_DEAD' ? 'error' as const : e.eventType === 'WENT_STALE' ? 'warning' as const : e.eventType === 'RECOVERED' ? 'success' as const : 'running' as const, message: `${e.eventType}${e.detail ? ' — ' + e.detail : ''}`, timestamp: new Date(e.timestamp), })), [events, instanceId], ); // JVM chart series helpers const cpuSeries = useMemo(() => { const pts = jvmMetrics?.metrics?.['jvm.cpu.process']; if (!pts?.length) return null; return [{ label: 'CPU %', data: pts.map((p: any, i: number) => ({ x: i, y: p.value * 100 })) }]; }, [jvmMetrics]); const heapSeries = useMemo(() => { const pts = jvmMetrics?.metrics?.['jvm.memory.heap.used']; if (!pts?.length) return null; return [{ label: 'Heap MB', data: pts.map((p: any, i: number) => ({ x: i, y: p.value / (1024 * 1024) })) }]; }, [jvmMetrics]); const threadSeries = useMemo(() => { const pts = jvmMetrics?.metrics?.['jvm.threads.count']; if (!pts?.length) return null; return [{ label: 'Threads', data: pts.map((p: any, i: number) => ({ x: i, y: p.value })) }]; }, [jvmMetrics]); const gcSeries = useMemo(() => { const pts = jvmMetrics?.metrics?.['jvm.gc.time']; if (!pts?.length) return null; return [{ label: 'GC ms', data: pts.map((p: any, i: number) => ({ x: String(i), y: p.value })) }]; }, [jvmMetrics]); const throughputSeries = useMemo(() => chartData.length ? [{ label: 'Throughput', data: chartData.map((d: any, i: number) => ({ x: i, y: d.throughput })) }] : null, [chartData], ); const errorSeries = useMemo(() => chartData.length ? [{ label: 'Errors', data: chartData.map((d: any, i: number) => ({ x: i, y: d.errors })) }] : null, [chartData], ); if (isLoading) return ; return (
{agent && ( <>

{agent.name}

{agent.version && }
0 ? 'error' : undefined} />
Process Information
{agent?.capabilities?.jvmVersion && (
JVM {agent.capabilities.jvmVersion}
)} {agent?.capabilities?.camelVersion && (
Camel {agent.capabilities.camelVersion}
)} {agent?.capabilities?.springBootVersion && (
Spring Boot {agent.capabilities.springBootVersion}
)}
Started {agent?.registeredAt ? new Date(agent.registeredAt).toLocaleString() : '—'}
Capabilities {Object.entries(agent?.capabilities || {}) .filter(([, v]) => typeof v === 'boolean' && v) .map(([k]) => ( ))}
Routes
{(agent.routeIds || []).map((r: string) => ( ))}
)}
Performance
CPU Usage
{cpuSeries ? : }
Memory Heap
{heapSeries ? : }
Throughput
{throughputSeries ? : }
Error Rate
{errorSeries ? : }
Thread Count
{threadSeries ? : }
GC Pauses
{gcSeries ? : }
{feedEvents.length > 0 && (
Events
)}
); } function formatUptime(seconds?: number): string { if (!seconds) return '—'; const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const mins = Math.floor((seconds % 3600) / 60); if (days > 0) return `${days}d ${hours}h`; if (hours > 0) return `${hours}h ${mins}m`; return `${mins}m`; }