refactor: unify "Executions" → "Exchanges" terminology
Rename all references from "Execution/executions/execCount" to "Exchange/exchanges/exchangeCount" to align with Apache Camel's native Exchange concept. Java class names (CamelExecutionException, HttpOperationFailedException) are preserved as-is. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -20,21 +20,21 @@ import { InfoCallout } from '../../design-system/primitives/InfoCallout/InfoCall
|
||||
|
||||
// Mock data
|
||||
import { routes } from '../../mocks/routes'
|
||||
import { executions, type Execution } from '../../mocks/executions'
|
||||
import { exchanges, type Exchange } from '../../mocks/exchanges'
|
||||
import { agents } from '../../mocks/agents'
|
||||
|
||||
// ─── Sidebar data (shared) ────────────────────────────────────────────────────
|
||||
const APPS = [
|
||||
{ id: 'order-service', name: 'order-service', agentCount: 2, health: 'live' as const, execCount: 1433 },
|
||||
{ id: 'payment-svc', name: 'payment-svc', agentCount: 1, health: 'live' as const, execCount: 912 },
|
||||
{ id: 'shipment-tracker', name: 'shipment-tracker', agentCount: 2, health: 'live' as const, execCount: 471 },
|
||||
{ id: 'notification-hub', name: 'notification-hub', agentCount: 1, health: 'stale' as const, execCount: 128 },
|
||||
{ id: 'order-service', name: 'order-service', agentCount: 2, health: 'live' as const, exchangeCount: 1433 },
|
||||
{ id: 'payment-svc', name: 'payment-svc', agentCount: 1, health: 'live' as const, exchangeCount: 912 },
|
||||
{ id: 'shipment-tracker', name: 'shipment-tracker', agentCount: 2, health: 'live' as const, exchangeCount: 471 },
|
||||
{ id: 'notification-hub', name: 'notification-hub', agentCount: 1, health: 'stale' as const, exchangeCount: 128 },
|
||||
]
|
||||
|
||||
const SIDEBAR_ROUTES = routes.slice(0, 3).map((r) => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
execCount: r.execCount,
|
||||
exchangeCount: r.exchangeCount,
|
||||
}))
|
||||
|
||||
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
||||
@@ -48,7 +48,7 @@ function formatTimestamp(date: Date): string {
|
||||
return date.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' })
|
||||
}
|
||||
|
||||
function statusToVariant(status: Execution['status']): 'success' | 'error' | 'running' | 'warning' {
|
||||
function statusToVariant(status: Exchange['status']): 'success' | 'error' | 'running' | 'warning' {
|
||||
switch (status) {
|
||||
case 'completed': return 'success'
|
||||
case 'failed': return 'error'
|
||||
@@ -57,7 +57,7 @@ function statusToVariant(status: Execution['status']): 'success' | 'error' | 'ru
|
||||
}
|
||||
}
|
||||
|
||||
function statusLabel(status: Execution['status']): string {
|
||||
function statusLabel(status: Exchange['status']): string {
|
||||
switch (status) {
|
||||
case 'completed': return 'OK'
|
||||
case 'failed': return 'ERR'
|
||||
@@ -74,7 +74,7 @@ function routeStatusVariant(status: 'healthy' | 'degraded' | 'down'): 'success'
|
||||
}
|
||||
}
|
||||
|
||||
function durationClass(ms: number, status: Execution['status']): string {
|
||||
function durationClass(ms: number, status: Exchange['status']): string {
|
||||
if (status === 'failed') return styles.durBreach
|
||||
if (ms < 100) return styles.durFast
|
||||
if (ms < 200) return styles.durNormal
|
||||
@@ -82,8 +82,8 @@ function durationClass(ms: number, status: Execution['status']): string {
|
||||
return styles.durBreach
|
||||
}
|
||||
|
||||
// ─── Columns for executions table ────────────────────────────────────────────
|
||||
const EXEC_COLUMNS: Column<Execution>[] = [
|
||||
// ─── Columns for exchanges table ────────────────────────────────────────────
|
||||
const EXCHANGE_COLUMNS: Column<Exchange>[] = [
|
||||
{
|
||||
key: 'status',
|
||||
header: 'Status',
|
||||
@@ -97,7 +97,7 @@ const EXEC_COLUMNS: Column<Execution>[] = [
|
||||
},
|
||||
{
|
||||
key: 'id',
|
||||
header: 'Execution ID',
|
||||
header: 'Exchange ID',
|
||||
render: (_, row) => <MonoText size="xs">{row.id}</MonoText>,
|
||||
},
|
||||
{
|
||||
@@ -146,15 +146,15 @@ export function RouteDetail() {
|
||||
const [activeItem, setActiveItem] = useState(id ?? '')
|
||||
|
||||
const route = useMemo(() => routes.find((r) => r.id === id), [id])
|
||||
const routeExecutions = useMemo(
|
||||
() => executions.filter((e) => e.route === id),
|
||||
const routeExchanges = useMemo(
|
||||
() => exchanges.filter((e) => e.route === id),
|
||||
[id],
|
||||
)
|
||||
|
||||
// Error patterns grouped by exception class
|
||||
const errorPatterns = useMemo(() => {
|
||||
const patterns: Record<string, { count: number; lastMessage: string; lastTime: Date }> = {}
|
||||
for (const exec of routeExecutions) {
|
||||
for (const exec of routeExchanges) {
|
||||
if (exec.status === 'failed' && exec.errorClass) {
|
||||
if (!patterns[exec.errorClass]) {
|
||||
patterns[exec.errorClass] = {
|
||||
@@ -171,26 +171,26 @@ export function RouteDetail() {
|
||||
}
|
||||
}
|
||||
return Object.entries(patterns)
|
||||
}, [routeExecutions])
|
||||
}, [routeExchanges])
|
||||
|
||||
// Build aggregate processor timeline from all executions for this route
|
||||
// Build aggregate processor timeline from all exchanges for this route
|
||||
const aggregateProcessors = useMemo(() => {
|
||||
if (routeExecutions.length === 0) return []
|
||||
// Use the first execution's processors as the template, with averaged durations
|
||||
const templateExec = routeExecutions[0]
|
||||
if (routeExchanges.length === 0) return []
|
||||
// Use the first exchange's processors as the template, with averaged durations
|
||||
const templateExec = routeExchanges[0]
|
||||
if (!templateExec) return []
|
||||
return templateExec.processors.map((proc) => {
|
||||
const allDurations = routeExecutions
|
||||
const allDurations = routeExchanges
|
||||
.flatMap((e) => e.processors)
|
||||
.filter((p) => p.name === proc.name)
|
||||
.map((p) => p.durationMs)
|
||||
const avgDuration = allDurations.length
|
||||
? Math.round(allDurations.reduce((a, b) => a + b, 0) / allDurations.length)
|
||||
: proc.durationMs
|
||||
const hasFailures = routeExecutions.some((e) =>
|
||||
const hasFailures = routeExchanges.some((e) =>
|
||||
e.processors.some((p) => p.name === proc.name && p.status === 'fail'),
|
||||
)
|
||||
const hasSlows = routeExecutions.some((e) =>
|
||||
const hasSlows = routeExchanges.some((e) =>
|
||||
e.processors.some((p) => p.name === proc.name && p.status === 'slow'),
|
||||
)
|
||||
return {
|
||||
@@ -199,15 +199,15 @@ export function RouteDetail() {
|
||||
status: hasFailures ? ('fail' as const) : hasSlows ? ('slow' as const) : ('ok' as const),
|
||||
}
|
||||
})
|
||||
}, [routeExecutions])
|
||||
}, [routeExchanges])
|
||||
|
||||
const totalAggregateMs = aggregateProcessors.reduce((sum, p) => sum + p.durationMs, 0)
|
||||
|
||||
const inflightCount = routeExecutions.filter((e) => e.status === 'running').length
|
||||
const successCount = routeExecutions.filter((e) => e.status === 'completed').length
|
||||
const errorCount = routeExecutions.filter((e) => e.status === 'failed').length
|
||||
const successRate = routeExecutions.length
|
||||
? ((successCount / routeExecutions.length) * 100).toFixed(1)
|
||||
const inflightCount = routeExchanges.filter((e) => e.status === 'running').length
|
||||
const successCount = routeExchanges.filter((e) => e.status === 'completed').length
|
||||
const errorCount = routeExchanges.filter((e) => e.status === 'failed').length
|
||||
const successRate = routeExchanges.length
|
||||
? ((successCount / routeExchanges.length) * 100).toFixed(1)
|
||||
: '0.0'
|
||||
|
||||
function handleItemClick(itemId: string) {
|
||||
@@ -298,8 +298,8 @@ export function RouteDetail() {
|
||||
{/* KPI strip */}
|
||||
<div className={styles.kpiStrip}>
|
||||
<div className={styles.kpiCard}>
|
||||
<div className={styles.kpiLabel}>Total Executions</div>
|
||||
<div className={styles.kpiValue}>{route.execCount.toLocaleString()}</div>
|
||||
<div className={styles.kpiLabel}>Total Exchanges</div>
|
||||
<div className={styles.kpiValue}>{route.exchangeCount.toLocaleString()}</div>
|
||||
</div>
|
||||
<div className={styles.kpiCard}>
|
||||
<div className={styles.kpiLabel}>Success Rate</div>
|
||||
@@ -331,7 +331,7 @@ export function RouteDetail() {
|
||||
<div className={styles.section}>
|
||||
<div className={styles.sectionHeader}>
|
||||
<span className={styles.sectionTitle}>Processor Performance (aggregate avg)</span>
|
||||
<span className={styles.sectionMeta}>Based on {routeExecutions.length} executions</span>
|
||||
<span className={styles.sectionMeta}>Based on {routeExchanges.length} exchanges</span>
|
||||
</div>
|
||||
{aggregateProcessors.length > 0 ? (
|
||||
<ProcessorTimeline
|
||||
@@ -339,17 +339,17 @@ export function RouteDetail() {
|
||||
totalMs={totalAggregateMs}
|
||||
/>
|
||||
) : (
|
||||
<div className={styles.emptyMsg}>No execution data for this route in mock set.</div>
|
||||
<div className={styles.emptyMsg}>No exchange data for this route in mock set.</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Recent executions table */}
|
||||
{/* Recent exchanges table */}
|
||||
<div className={styles.tableSection}>
|
||||
<div className={styles.tableHeader}>
|
||||
<span className={styles.tableTitle}>Recent Executions</span>
|
||||
<span className={styles.tableTitle}>Recent Exchanges</span>
|
||||
<div className={styles.tableRight}>
|
||||
<span className={styles.tableMeta}>
|
||||
{routeExecutions.length} executions · {errorCount} errors
|
||||
{routeExchanges.length} exchanges · {errorCount} errors
|
||||
</span>
|
||||
<Badge
|
||||
label={`${successRate}% ok`}
|
||||
@@ -358,8 +358,8 @@ export function RouteDetail() {
|
||||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
columns={EXEC_COLUMNS}
|
||||
data={routeExecutions}
|
||||
columns={EXCHANGE_COLUMNS}
|
||||
data={routeExchanges}
|
||||
sortable
|
||||
rowAccent={(row) => {
|
||||
if (row.status === 'failed') return 'error'
|
||||
|
||||
Reference in New Issue
Block a user