feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
import { useMemo } from 'react'
import { useParams , Link } from 'react-router-dom'
2026-03-27 23:25:43 +01:00
import { ChevronRight } from 'lucide-react'
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
import styles from './AgentInstance.module.css'
// Layout
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
// Composites
import { LineChart } from '../../design-system/composites/LineChart/LineChart'
import { AreaChart } from '../../design-system/composites/AreaChart/AreaChart'
import { EventFeed } from '../../design-system/composites/EventFeed/EventFeed'
import { Tabs } from '../../design-system/composites/Tabs/Tabs'
2026-03-24 15:22:41 +01:00
import { LogViewer } from '../../design-system/composites/LogViewer/LogViewer'
import type { LogEntry } from '../../design-system/composites/LogViewer/LogViewer'
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
// Primitives
import { StatusDot } from '../../design-system/primitives/StatusDot/StatusDot'
import { MonoText } from '../../design-system/primitives/MonoText/MonoText'
import { Badge } from '../../design-system/primitives/Badge/Badge'
import { StatCard } from '../../design-system/primitives/StatCard/StatCard'
import { SectionHeader } from '../../design-system/primitives/SectionHeader/SectionHeader'
// Global filters
import { useGlobalFilters } from '../../design-system/providers/GlobalFilterProvider'
// Data
import { agents } from '../../mocks/agents'
import { agentEvents } from '../../mocks/agentEvents'
import { useState } from 'react'
// ── Mock trend data ──────────────────────────────────────────────────────────
function buildTimeSeries ( baseValue : number , variance : number , points = 30 ) {
const now = Date . now ( )
const interval = ( 6 * 60 * 60 * 1000 ) / points
return Array . from ( { length : points } , ( _ , i ) = > ( {
x : new Date ( now - ( points - i ) * interval ) ,
y : Math.max ( 0 , baseValue + ( Math . random ( ) - 0.5 ) * variance * 2 ) ,
} ) )
}
function buildMemoryHistory ( currentPct : number ) {
return [
{ label : 'Heap Used' , data : buildTimeSeries ( currentPct * 0.7 , 10 ) } ,
{ label : 'Heap Total' , data : buildTimeSeries ( currentPct * 0.9 , 5 ) } ,
]
}
// ── Mock log entries ─────────────────────────────────────────────────────────
2026-03-24 15:22:41 +01:00
function buildLogEntries ( agentName : string ) : LogEntry [ ] {
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
const now = Date . now ( )
const MIN = 60 _000
return [
2026-03-24 15:22:41 +01:00
{ timestamp : new Date ( now - 1 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.impl.DefaultCamelContext] Route order-validation started and consuming from: direct:validate ` } ,
{ timestamp : new Date ( now - 2 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.impl.DefaultCamelContext] Total 3 routes, of which 3 are started ` } ,
{ timestamp : new Date ( now - 5 * MIN ) . toISOString ( ) , level : 'warn' , message : ` [o.a.c.processor.errorhandler] Failed delivery for exchangeId: ID- ${ agentName } -1710847200000-0-1. Exhausted after 3 attempts. ` } ,
{ timestamp : new Date ( now - 8 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.health.HealthCheckHelper] Health check [routes] is UP ` } ,
{ timestamp : new Date ( now - 12 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.health.HealthCheckHelper] Health check [consumers] is UP ` } ,
{ timestamp : new Date ( now - 15 * MIN ) . toISOString ( ) , level : 'debug' , message : ` [o.a.c.component.kafka] KafkaConsumer[order-events] poll returned 42 records in 18ms ` } ,
{ timestamp : new Date ( now - 18 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.impl.engine.InternalRouteStartup] Route order-enrichment started and consuming from: kafka:order-events ` } ,
{ timestamp : new Date ( now - 25 * MIN ) . toISOString ( ) , level : 'warn' , message : ` [o.a.c.component.http] HTTP endpoint https://payment-api.internal/verify returned 503 — will retry ` } ,
{ timestamp : new Date ( now - 30 * MIN ) . toISOString ( ) , level : 'info' , message : ` [o.a.c.impl.DefaultCamelContext] Apache Camel ${ agentName } (CamelContext) is starting ` } ,
{ timestamp : new Date ( now - 32 * MIN ) . toISOString ( ) , level : 'info' , message : ` [org.springframework.boot] Started ${ agentName } in 4.231 seconds (process running for 4.892) ` } ,
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
]
}
// ── Mock JVM / process info ──────────────────────────────────────────────────
function buildProcessInfo ( agent : typeof agents [ 0 ] ) {
return {
jvmVersion : 'OpenJDK 21.0.2+13' ,
camelVersion : '4.4.0' ,
springBootVersion : '3.2.4' ,
pid : Math.floor ( 1000 + Math . random ( ) * 90000 ) ,
startTime : new Date ( Date . now ( ) - parseDuration ( agent . uptime ) ) . toISOString ( ) ,
heapMax : '512 MB' ,
heapUsed : ` ${ Math . round ( 512 * agent . memoryUsagePct / 100 ) } MB ` ,
nonHeapUsed : ` ${ Math . round ( 80 + Math . random ( ) * 40 ) } MB ` ,
threadCount : Math.floor ( 20 + Math . random ( ) * 30 ) ,
peakThreads : Math.floor ( 45 + Math . random ( ) * 20 ) ,
gcCollections : Math.floor ( Math . random ( ) * 500 ) ,
gcPauseTotal : ` ${ ( Math . random ( ) * 2 ) . toFixed ( 2 ) } s ` ,
classesLoaded : Math.floor ( 8000 + Math . random ( ) * 4000 ) ,
openFileDescriptors : Math.floor ( 50 + Math . random ( ) * 200 ) ,
maxFileDescriptors : 65536 ,
}
}
function parseDuration ( s : string ) : number {
let ms = 0
const dMatch = s . match ( /(\d+)d/ )
const hMatch = s . match ( /(\d+)h/ )
const mMatch = s . match ( /(\d+)m/ )
if ( dMatch ) ms += parseInt ( dMatch [ 1 ] ) * 86400000
if ( hMatch ) ms += parseInt ( hMatch [ 1 ] ) * 3600000
if ( mMatch ) ms += parseInt ( mMatch [ 1 ] ) * 60000
return ms || 60000
}
// ── Component ────────────────────────────────────────────────────────────────
const LOG_TABS = [
{ label : 'All' , value : 'all' } ,
{ label : 'Warnings' , value : 'warn' } ,
{ label : 'Errors' , value : 'error' } ,
]
export function AgentInstance() {
const { appId , instanceId } = useParams < { appId : string ; instanceId : string } > ( )
const { isInTimeRange } = useGlobalFilters ( )
const [ logFilter , setLogFilter ] = useState ( 'all' )
const agent = agents . find ( ( a ) = > a . appId === appId && a . id === instanceId )
const instanceEvents = useMemo ( ( ) = > {
if ( ! agent ) return [ ]
return agentEvents
. filter ( ( e ) = > e . searchText ? . toLowerCase ( ) . includes ( agent . name . toLowerCase ( ) ) )
. filter ( ( e ) = > isInTimeRange ( e . timestamp ) )
} , [ agent , isInTimeRange ] )
if ( ! agent ) {
return (
2026-04-02 18:09:16 +02:00
< >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
< TopBar breadcrumb = { [ { label : 'Agents' , href : '/agents' } , { label : 'Not Found' } ] } environment = "PRODUCTION" user = { { name : 'hendrik' } } / >
< div className = { styles . content } >
< div className = { styles . notFound } > Agent instance not found . < / div >
< / div >
2026-04-02 18:09:16 +02:00
< / >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
)
}
const processInfo = buildProcessInfo ( agent )
const logEntries = buildLogEntries ( agent . name )
const filteredLogs = logFilter === 'all'
? logEntries
2026-03-24 15:22:41 +01:00
: logEntries . filter ( ( l ) = > l . level === logFilter )
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
const cpuData = buildTimeSeries ( agent . cpuUsagePct , 15 )
const memSeries = buildMemoryHistory ( agent . memoryUsagePct )
const tpsSeries = [ { label : 'Throughput' , data : buildTimeSeries ( agent . tps , 5 ) } ]
const errorSeries = [ { label : 'Errors' , data : buildTimeSeries ( agent . errorRate ? parseFloat ( agent . errorRate ) : 0.2 , 2 ) , color : 'var(--error)' } ]
const threadSeries = [ { label : 'Threads' , data : buildTimeSeries ( processInfo . threadCount , 8 ) } ]
const gcSeries = [ { label : 'GC Pause' , data : buildTimeSeries ( 4 , 6 ) } ]
const statusVariant = agent . status === 'live' ? 'live' : agent . status === 'stale' ? 'stale' : 'dead'
const statusColor = agent . status === 'live' ? 'success' : agent . status === 'stale' ? 'warning' : 'error'
return (
2026-04-02 18:09:16 +02:00
< >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
< TopBar
breadcrumb = { [
{ label : 'Applications' , href : '/apps' } ,
{ label : 'Agents' , href : '/agents' } ,
{ label : appId ! , href : ` /agents/ ${ appId } ` } ,
{ label : instanceId ! } ,
] }
environment = "PRODUCTION"
user = { { name : 'hendrik' } }
/ >
< div className = { styles . content } >
{ /* Stat strip — 5 columns matching /agents */ }
< div className = { styles . statStrip } >
< StatCard label = "CPU" value = { ` ${ agent . cpuUsagePct } % ` } accent = { agent . cpuUsagePct > 85 ? 'error' : agent . cpuUsagePct > 70 ? 'warning' : 'success' } / >
< StatCard label = "Memory" value = { ` ${ agent . memoryUsagePct } % ` } accent = { agent . memoryUsagePct > 85 ? 'error' : agent . memoryUsagePct > 70 ? 'warning' : 'success' } detail = { ` ${ processInfo . heapUsed } / ${ processInfo . heapMax } ` } / >
< StatCard label = "Throughput" value = { ` ${ agent . tps . toFixed ( 1 ) } /s ` } accent = "amber" detail = "msg/s" / >
< StatCard label = "Errors" value = { agent . errorRate ? ? '0 err/h' } accent = { agent . errorRate ? 'error' : 'success' } / >
< StatCard label = "Uptime" value = { agent . uptime || '—' } accent = "running" detail = { ` since ${ new Date ( processInfo . startTime ) . toLocaleDateString ( ) } ` } / >
< / div >
{ /* Scope trail + badges */ }
< div className = { styles . scopeTrail } >
< Link to = "/agents" className = { styles . scopeLink } > All Agents < / Link >
2026-03-27 23:25:43 +01:00
< span className = { styles . scopeSep } > < ChevronRight size = { 12 } / > < / span >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
< Link to = { ` /agents/ ${ appId } ` } className = { styles . scopeLink } > { appId } < / Link >
2026-03-27 23:25:43 +01:00
< span className = { styles . scopeSep } > < ChevronRight size = { 12 } / > < / span >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
< span className = { styles . scopeCurrent } > { agent . name } < / span >
< Badge label = { agent . status . toUpperCase ( ) } color = { statusColor } / >
< Badge label = { agent . version } color = "auto" variant = "outlined" / >
< Badge label = { ` ${ agent . activeRoutes } / ${ agent . totalRoutes } routes ` } color = { agent . activeRoutes < agent . totalRoutes ? 'warning' : 'success' } / >
< / div >
{ /* Process info card — right below stat strip */ }
< div className = { styles . processCard } >
< SectionHeader > Process Information < / SectionHeader >
< div className = { styles . processGrid } >
< span className = { styles . processLabel } > JVM < / span >
< MonoText size = "xs" > { processInfo . jvmVersion } < / MonoText >
< span className = { styles . processLabel } > Camel < / span >
< MonoText size = "xs" > { processInfo . camelVersion } < / MonoText >
< span className = { styles . processLabel } > Spring Boot < / span >
< MonoText size = "xs" > { processInfo . springBootVersion } < / MonoText >
< span className = { styles . processLabel } > Started < / span >
< MonoText size = "xs" > { new Date ( processInfo . startTime ) . toLocaleString ( ) } < / MonoText >
< span className = { styles . processLabel } > File Descriptors < / span >
< MonoText size = "xs" > { processInfo . openFileDescriptors } / { processInfo . maxFileDescriptors . toLocaleString ( ) } < / MonoText >
< / div >
< / div >
{ /* Charts grid — 3x2 (CPU, Memory, Throughput, Errors, Threads, GC) */ }
< div className = { styles . chartsGrid } >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > CPU Usage < / span >
< span className = { styles . chartMeta } > { agent . cpuUsagePct } % current < / span >
< / div >
< AreaChart
series = { [ { label : 'CPU %' , data : cpuData } ] }
height = { 160 }
yLabel = "%"
thresholdValue = { 85 }
thresholdLabel = "Alert"
/ >
< / div >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > Memory ( Heap ) < / span >
< span className = { styles . chartMeta } > { processInfo . heapUsed } / { processInfo . heapMax } < / span >
< / div >
< AreaChart
series = { memSeries }
height = { 160 }
yLabel = "MB"
/ >
< / div >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > Throughput < / span >
< span className = { styles . chartMeta } > { agent . tps . toFixed ( 1 ) } msg / s < / span >
< / div >
< LineChart
series = { tpsSeries }
height = { 160 }
yLabel = "msg/s"
/ >
< / div >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > Error Rate < / span >
< span className = { styles . chartMeta } > { agent . errorRate ? ? '0 err/h' } < / span >
< / div >
< LineChart
series = { errorSeries }
height = { 160 }
yLabel = "err/h"
/ >
< / div >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > Thread Count < / span >
< span className = { styles . chartMeta } > { processInfo . threadCount } active < / span >
< / div >
< LineChart series = { threadSeries } height = { 160 } yLabel = "threads" / >
< / div >
< div className = { styles . chartCard } >
< div className = { styles . chartHeader } >
< span className = { styles . chartTitle } > GC Pauses < / span >
< span className = { styles . chartMeta } > { processInfo . gcPauseTotal } total < / span >
< / div >
< LineChart series = { gcSeries } height = { 160 } yLabel = "ms" / >
< / div >
< / div >
{ /* Log + Timeline side by side */ }
< div className = { styles . bottomRow } >
{ /* Log viewer */ }
< div className = { styles . logCard } >
< div className = { styles . logHeader } >
< SectionHeader > Application Log < / SectionHeader >
< Tabs tabs = { LOG_TABS } active = { logFilter } onChange = { setLogFilter } / >
< / div >
2026-03-24 15:22:41 +01:00
< LogViewer entries = { filteredLogs } maxHeight = { 360 } / >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
< / div >
{ /* Timeline */ }
< div className = { styles . timelineCard } >
< div className = { styles . timelineHeader } >
< span className = { styles . chartTitle } > Timeline < / span >
< span className = { styles . chartMeta } > { instanceEvents . length } events < / span >
< / div >
{ instanceEvents . length > 0 ? (
< EventFeed events = { instanceEvents } / >
) : (
< div className = { styles . logEmpty } > No events in the selected time range . < / div >
) }
< / div >
< / div >
< / div >
2026-04-02 18:09:16 +02:00
< / >
feat: add AgentInstance detail page and improve AgentHealth
- New /agents/:appId/:instanceId page with process info, 3x2 charts
grid (CPU, memory, throughput, errors, threads, GC), application
log viewer with level filtering, and instance-scoped timeline
- AgentHealth now uses slide-in DetailPanel for quick instance preview
- Stat strip enhanced: colored StatusDot breakdowns, route ratio with
state-colored values, Groups renamed to Applications
- Unified page structure: stat strip → scope trail with inline badges
(removed duplicate section headers from both pages)
- StatCard value/detail props now accept ReactNode
- Log and timeline displayed side by side
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:51:13 +01:00
)
}