2026-03-18 18:22:14 +01:00
import { useMemo } from 'react'
2026-03-18 19:11:58 +01:00
import { useParams , useNavigate , Link } from 'react-router-dom'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
import styles from './AgentHealth.module.css'
// Layout
import { AppShell } from '../../design-system/layout/AppShell/AppShell'
import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar'
import { TopBar } from '../../design-system/layout/TopBar/TopBar'
// Composites
2026-03-18 18:22:14 +01:00
import { GroupCard } from '../../design-system/composites/GroupCard/GroupCard'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
import { LineChart } from '../../design-system/composites/LineChart/LineChart'
2026-03-18 18:22:14 +01:00
import { EventFeed } from '../../design-system/composites/EventFeed/EventFeed'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +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'
2026-03-18 18:22:14 +01:00
import { StatCard } from '../../design-system/primitives/StatCard/StatCard'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
// Mock data
2026-03-18 18:22:14 +01:00
import { agents , type AgentHealth as AgentHealthData } from '../../mocks/agents'
2026-03-18 17:50:41 +01:00
import { SIDEBAR_APPS } from '../../mocks/sidebar'
2026-03-18 18:22:14 +01:00
import { agentEvents } from '../../mocks/agentEvents'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
2026-03-18 18:22:14 +01:00
// ── URL scope parsing ────────────────────────────────────────────────────────
type Scope =
| { level : 'all' }
| { level : 'app' ; appId : string }
| { level : 'instance' ; appId : string ; instanceId : string }
function useScope ( ) : Scope {
const { '*' : rest } = useParams ( )
const segments = rest ? . split ( '/' ) . filter ( Boolean ) ? ? [ ]
if ( segments . length >= 2 ) return { level : 'instance' , appId : segments [ 0 ] , instanceId : segments [ 1 ] }
if ( segments . length === 1 ) return { level : 'app' , appId : segments [ 0 ] }
return { level : 'all' }
}
// ── Data grouping ────────────────────────────────────────────────────────────
interface AppGroup {
appId : string
instances : AgentHealthData [ ]
liveCount : number
staleCount : number
deadCount : number
totalTps : number
totalActiveRoutes : number
totalRoutes : number
}
function groupByApp ( agentList : AgentHealthData [ ] ) : AppGroup [ ] {
const map = new Map < string , AgentHealthData [ ] > ( )
for ( const a of agentList ) {
const list = map . get ( a . appId ) ? ? [ ]
list . push ( a )
map . set ( a . appId , list )
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
}
2026-03-18 18:22:14 +01:00
return Array . from ( map . entries ( ) ) . map ( ( [ appId , instances ] ) = > ( {
appId ,
instances ,
liveCount : instances.filter ( ( i ) = > i . status === 'live' ) . length ,
staleCount : instances.filter ( ( i ) = > i . status === 'stale' ) . length ,
deadCount : instances.filter ( ( i ) = > i . status === 'dead' ) . length ,
totalTps : instances.reduce ( ( s , i ) = > s + i . tps , 0 ) ,
totalActiveRoutes : instances.reduce ( ( s , i ) = > s + i . activeRoutes , 0 ) ,
totalRoutes : instances.reduce ( ( s , i ) = > s + i . totalRoutes , 0 ) ,
} ) )
}
function appHealth ( group : AppGroup ) : 'success' | 'warning' | 'error' {
if ( group . deadCount > 0 ) return 'error'
if ( group . staleCount > 0 ) return 'warning'
return 'success'
}
// ── Trend data (mock) ────────────────────────────────────────────────────────
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
2026-03-18 18:22:14 +01:00
function buildTrendData ( agent : AgentHealthData ) {
const now = Date . now ( )
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
const points = 20
2026-03-18 18:22:14 +01:00
const interval = ( 3 * 60 * 60 * 1000 ) / points
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
2026-03-18 18:22:14 +01:00
const throughput = Array . from ( { length : points } , ( _ , i ) = > ( {
x : new Date ( now - ( points - i ) * interval ) ,
y : Math.max ( 0 , agent . tps + ( Math . random ( ) - 0.5 ) * 4 ) ,
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
} ) )
2026-03-18 18:22:14 +01:00
const errorRate = Array . from ( { length : points } , ( _ , i ) = > ( {
x : new Date ( now - ( points - i ) * interval ) ,
y : Math.max ( 0 , ( agent . errorRate ? parseFloat ( agent . errorRate ) : 0.5 ) + ( Math . random ( ) - 0.5 ) * 2 ) ,
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
} ) )
2026-03-18 18:22:14 +01:00
return { throughput , errorRate }
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
}
2026-03-18 18:22:14 +01:00
// ── Breadcrumb ───────────────────────────────────────────────────────────────
function buildBreadcrumb ( scope : Scope ) {
const crumbs : { label : string ; href? : string } [ ] = [
2026-03-18 19:26:27 +01:00
{ label : 'Applications' , href : '/apps' } ,
2026-03-18 18:22:14 +01:00
{ label : 'Agents' , href : '/agents' } ,
]
if ( scope . level === 'app' || scope . level === 'instance' ) {
crumbs . push ( { label : scope.appId , href : ` /agents/ ${ scope . appId } ` } )
}
if ( scope . level === 'instance' ) {
crumbs . push ( { label : scope.instanceId } )
}
return crumbs
}
// ── AgentHealth page ─────────────────────────────────────────────────────────
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
export function AgentHealth() {
2026-03-18 18:22:14 +01:00
const scope = useScope ( )
2026-03-18 19:11:58 +01:00
const navigate = useNavigate ( )
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
2026-03-18 18:22:14 +01:00
// Filter agents by scope
const filteredAgents = useMemo ( ( ) = > {
if ( scope . level === 'all' ) return agents
if ( scope . level === 'app' ) return agents . filter ( ( a ) = > a . appId === scope . appId )
return agents . filter ( ( a ) = > a . appId === scope . appId && a . id === scope . instanceId )
} , [ scope ] )
const groups = useMemo ( ( ) = > groupByApp ( filteredAgents ) , [ filteredAgents ] )
// Aggregate stats
const totalInstances = filteredAgents . length
const liveCount = filteredAgents . filter ( ( a ) = > a . status === 'live' ) . length
const staleCount = filteredAgents . filter ( ( a ) = > a . status === 'stale' ) . length
const deadCount = filteredAgents . filter ( ( a ) = > a . status === 'dead' ) . length
const totalTps = filteredAgents . reduce ( ( s , a ) = > s + a . tps , 0 )
const totalActiveRoutes = filteredAgents . reduce ( ( s , a ) = > s + a . activeRoutes , 0 )
2026-03-18 19:11:58 +01:00
// Events are a global timeline feed — show all regardless of scope
const filteredEvents = agentEvents
2026-03-18 18:22:14 +01:00
// Single instance for expanded charts
const singleInstance = scope . level === 'instance' ? filteredAgents [ 0 ] : null
const trendData = singleInstance ? buildTrendData ( singleInstance ) : null
const isFullWidth = scope . level !== 'all'
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
return (
2026-03-18 18:22:14 +01:00
< AppShell sidebar = { < Sidebar apps = { SIDEBAR_APPS } / > } >
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
< TopBar
2026-03-18 18:22:14 +01:00
breadcrumb = { buildBreadcrumb ( scope ) }
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
environment = "PRODUCTION"
user = { { name : 'hendrik' } }
/ >
< div className = { styles . content } >
2026-03-18 18:22:14 +01:00
{ /* Stat strip */ }
< div className = { styles . statStrip } >
< StatCard label = "Total Instances" value = { String ( totalInstances ) } / >
< StatCard label = "Live" value = { String ( liveCount ) } accent = "success" / >
< StatCard label = "Stale" value = { String ( staleCount ) } accent = { staleCount > 0 ? 'warning' : undefined } / >
< StatCard label = "Dead" value = { String ( deadCount ) } accent = { deadCount > 0 ? 'error' : undefined } / >
< StatCard label = "Total TPS" value = { ` ${ totalTps . toFixed ( 1 ) } /s ` } / >
< StatCard label = "Active Routes" value = { String ( totalActiveRoutes ) } / >
< / div >
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
2026-03-18 18:22:14 +01:00
{ /* Scope breadcrumb trail */ }
{ scope . level !== 'all' && (
< div className = { styles . scopeTrail } >
< Link to = "/agents" className = { styles . scopeLink } > All Agents < / Link >
{ scope . level === 'instance' && (
< >
< span className = { styles . scopeSep } > & # 9656 ; < / span >
< Link to = { ` /agents/ ${ scope . appId } ` } className = { styles . scopeLink } > { scope . appId } < / Link >
< / >
) }
< span className = { styles . scopeSep } > & # 9656 ; < / span >
< span className = { styles . scopeCurrent } >
{ scope . level === 'app' ? scope.appId : scope.instanceId }
< / span >
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
< / div >
2026-03-18 18:22:14 +01:00
) }
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
{ /* Section header */ }
< div className = { styles . sectionHeaderRow } >
2026-03-18 18:22:14 +01:00
< span className = { styles . sectionTitle } >
2026-03-18 19:11:58 +01:00
{ scope . level === 'all' ? 'Agents' : scope . level === 'app' ? scope.appId : scope.instanceId }
2026-03-18 18:22:14 +01:00
< / span >
2026-03-18 19:11:58 +01:00
< Badge
label = { ` ${ liveCount } / ${ totalInstances } live ` }
color = { deadCount > 0 ? 'error' : staleCount > 0 ? 'warning' : 'success' }
variant = "filled"
/ >
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
< / div >
2026-03-18 18:22:14 +01:00
{ /* Group cards grid */ }
< div className = { isFullWidth ? styles.groupGridSingle : styles.groupGrid } >
{ groups . map ( ( group ) = > (
< GroupCard
key = { group . appId }
title = { group . appId }
accent = { appHealth ( group ) }
headerRight = {
2026-03-18 19:11:58 +01:00
< Badge
label = { ` ${ group . liveCount } / ${ group . instances . length } LIVE ` }
color = { appHealth ( group ) }
variant = "filled"
/ >
2026-03-18 18:22:14 +01:00
}
meta = {
< div className = { styles . groupMeta } >
< span > < strong > { group . totalTps . toFixed ( 1 ) } < / strong > msg / s < / span >
< span > < strong > { group . totalActiveRoutes } < / strong > / { group . totalRoutes } routes < / span >
< span >
< StatusDot variant = { appHealth ( group ) === 'success' ? 'live' : appHealth ( group ) === 'warning' ? 'stale' : 'dead' } / >
< / span >
< / div >
}
footer = { group . deadCount > 0 ? (
< div className = { styles . alertBanner } >
< span className = { styles . alertIcon } > & # 9888 ; < / span >
< span > Single point of failure — { group . deadCount === group . instances . length ? 'no redundancy' : ` ${ group . deadCount } dead instance ${ group . deadCount > 1 ? 's' : '' } ` } < / span >
< / div >
) : undefined }
>
2026-03-18 19:11:58 +01:00
< table className = { styles . instanceTable } >
< thead >
< tr >
< th className = { styles . thStatus } / >
< th > Instance < / th >
< th > State < / th >
< th > Uptime < / th >
< th > TPS < / th >
< th > Errors < / th >
< th > Heartbeat < / th >
< / tr >
< / thead >
< tbody >
{ group . instances . map ( ( inst ) = > (
< >
< tr
key = { inst . id }
className = { [
styles . instanceRow ,
scope . level === 'instance' && scope . instanceId === inst . id ? styles . instanceRowActive : '' ,
] . filter ( Boolean ) . join ( ' ' ) }
onClick = { ( ) = > navigate ( ` /agents/ ${ inst . appId } / ${ inst . id } ` ) }
>
< td className = { styles . tdStatus } >
< StatusDot variant = { inst . status === 'live' ? 'live' : inst . status === 'stale' ? 'stale' : 'dead' } / >
< / td >
< td >
< MonoText size = "sm" className = { styles . instanceName } > { inst . name } < / MonoText >
< / td >
< td >
< Badge
label = { inst . status . toUpperCase ( ) }
color = { inst . status === 'live' ? 'success' : inst . status === 'stale' ? 'warning' : 'error' }
variant = "filled"
/ >
< / td >
< td >
< MonoText size = "xs" className = { styles . instanceMeta } > { inst . uptime } < / MonoText >
< / td >
< td >
< MonoText size = "xs" className = { styles . instanceMeta } > { inst . tps . toFixed ( 1 ) } / s < / MonoText >
< / td >
< td >
< MonoText size = "xs" className = { inst . errorRate ? styles.instanceError : styles.instanceMeta } >
{ inst . errorRate ? ? '0 err/h' }
< / MonoText >
< / td >
< td >
< MonoText size = "xs" className = {
inst . status === 'dead' ? styles . instanceHeartbeatDead :
inst . status === 'stale' ? styles . instanceHeartbeatStale :
styles . instanceMeta
} >
{ inst . lastSeen }
< / MonoText >
< / td >
< / tr >
{ /* Expanded charts for single instance */ }
{ singleInstance ? . id === inst . id && trendData && (
< tr key = { ` ${ inst . id } -charts ` } className = { styles . chartRow } >
< td colSpan = { 7 } >
< div className = { styles . instanceCharts } >
< div className = { styles . chartPanel } >
< div className = { styles . chartTitle } > Throughput ( msg / s ) < / div >
< LineChart
series = { [ { label : 'tps' , data : trendData.throughput } ] }
height = { 160 }
width = { 480 }
yLabel = "msg/s"
/ >
< / div >
< div className = { styles . chartPanel } >
< div className = { styles . chartTitle } > Error Rate ( err / h ) < / div >
< LineChart
series = { [ { label : 'errors' , data : trendData.errorRate , color : 'var(--error)' } ] }
height = { 160 }
width = { 480 }
yLabel = "err/h"
/ >
< / div >
< / div >
< / td >
< / tr >
) }
< / >
) ) }
< / tbody >
< / table >
2026-03-18 18:22:14 +01:00
< / GroupCard >
) ) }
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
< / div >
2026-03-18 18:22:14 +01:00
{ /* EventFeed */ }
{ filteredEvents . length > 0 && (
2026-03-18 19:11:58 +01:00
< div className = { styles . eventCard } >
< div className = { styles . eventCardHeader } >
2026-03-18 18:22:14 +01:00
< span className = { styles . sectionTitle } > Timeline < / span >
2026-03-18 19:11:58 +01:00
< span className = { styles . sectionMeta } > { filteredEvents . length } events < / span >
2026-03-18 18:22:14 +01:00
< / div >
< EventFeed events = { filteredEvents } / >
< / div >
) }
feat: ExchangeDetail and AgentHealth pages
ExchangeDetail (/exchanges/:id): exchange header card with ID/route/
status/duration, ProcessorTimeline for the specific exchange, step-by-
step exchange inspector using Collapsible+CodeBlock for headers/body at
each processor step, and error details block for failed exchanges.
AgentHealth (/agents): 6-card system overview strip, 2-column grid of
agent cards (StatusDot, name, version, tps, uptime, last-seen, CPU/mem
usage, active routes), expandable per-agent LineCharts for throughput
and error rate trends. Both pages use AppShell + shared Sidebar layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 10:22:11 +01:00
< / div >
< / AppShell >
)
}