From 73f6bdb36c08989f119c7c4007adada6deac28ea Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Wed, 18 Mar 2026 15:54:27 +0100 Subject: [PATCH] =?UTF-8?q?refactor:=20unify=20"Executions"=20=E2=86=92=20?= =?UTF-8?q?"Exchanges"=20terminology?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../specs/2026-03-18-design-system-design.md | 10 +- .../CommandPalette/CommandPalette.test.tsx | 10 +- .../CommandPalette/CommandPalette.tsx | 8 +- .../composites/CommandPalette/types.ts | 2 +- .../composites/Tabs/Tabs.test.tsx | 4 +- src/design-system/layout/Sidebar/Sidebar.tsx | 8 +- src/mocks/{executions.ts => exchanges.ts} | 4 +- src/mocks/metrics.ts | 12 +-- src/mocks/routes.ts | 16 +-- src/pages/AgentHealth/AgentHealth.tsx | 10 +- src/pages/Dashboard/Dashboard.tsx | 102 +++++++++--------- src/pages/ExchangeDetail/ExchangeDetail.tsx | 60 +++++------ src/pages/Metrics/Metrics.tsx | 16 +-- src/pages/RouteDetail/RouteDetail.module.css | 2 +- src/pages/RouteDetail/RouteDetail.tsx | 76 ++++++------- 15 files changed, 169 insertions(+), 171 deletions(-) rename src/mocks/{executions.ts => exchanges.ts} (99%) diff --git a/docs/superpowers/specs/2026-03-18-design-system-design.md b/docs/superpowers/specs/2026-03-18-design-system-design.md index ada892c..7dc10d9 100644 --- a/docs/superpowers/specs/2026-03-18-design-system-design.md +++ b/docs/superpowers/specs/2026-03-18-design-system-design.md @@ -184,7 +184,7 @@ src/ │ ├── ExchangeDetail/ │ └── AgentHealth/ ├── mocks/ # Static TypeScript mock data -│ ├── executions.ts +│ ├── exchanges.ts │ ├── routes.ts │ ├── agents.ts │ └── metrics.ts @@ -361,7 +361,7 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### CommandPalette - Full-screen overlay modal triggered by Ctrl+K - Search input with scoped filter tags (removable, amber-styled) -- Category tabs with counts (All, Executions, Routes, Exchanges, Agents) +- Category tabs with counts (All, Exchanges, Routes, Agents) - Grouped results by category with section headers - Result items: icon + title + badges + meta + timestamp - Inline expandable detail (JSON preview with match highlighting) @@ -371,7 +371,7 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li - Props: `open: boolean`, `onClose`, `onSelect: (result: SearchResult) => void`, `data: SearchResult[]` - `SearchResult` interface: ```ts - type SearchCategory = 'execution' | 'route' | 'exchange' | 'agent' + type SearchCategory = 'exchange' | 'route' | 'agent' interface SearchResult { id: string category: SearchCategory @@ -451,7 +451,7 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### ProcessorTimeline - Gantt-style horizontal bar timeline for exchange processor steps - Each bar: processor name (left label), colored bar (green=ok, amber=slow, red=fail), duration label (right) -- Bar width proportional to duration relative to total execution time +- Bar width proportional to duration relative to total exchange time - Clickable bars (select processor) - Props: `processors: { name: string; type: string; durationMs: number; status: 'ok' | 'slow' | 'fail'; startMs: number }[]`, `totalMs: number`, `onProcessorClick?` @@ -518,7 +518,7 @@ Pages are built after the design system layer is complete. Static TypeScript objects in `src/mocks/` providing realistic data matching the HTML mockups: -- `executions.ts` — execution rows with status, duration, order IDs, error messages +- `exchanges.ts` — exchange rows with status, duration, order IDs, error messages - `routes.ts` — route definitions with processor lists - `agents.ts` — agent health data (name, version, status, tps, last-seen) - `metrics.ts` — KPI values, chart data points diff --git a/src/design-system/composites/CommandPalette/CommandPalette.test.tsx b/src/design-system/composites/CommandPalette/CommandPalette.test.tsx index 47f37a9..571b9bb 100644 --- a/src/design-system/composites/CommandPalette/CommandPalette.test.tsx +++ b/src/design-system/composites/CommandPalette/CommandPalette.test.tsx @@ -7,8 +7,8 @@ import type { SearchResult } from './types' const mockData: SearchResult[] = [ { id: '1', - category: 'execution', - title: 'order-intake execution', + category: 'exchange', + title: 'order-intake exchange', meta: 'cmr-1234 · 142ms', timestamp: '2s ago', badges: [{ label: 'Completed' }], @@ -63,7 +63,7 @@ describe('CommandPalette', () => { data={mockData} />, ) - expect(screen.getByText('order-intake execution')).toBeInTheDocument() + expect(screen.getByText('order-intake exchange')).toBeInTheDocument() expect(screen.getByText('content-based-routing')).toBeInTheDocument() }) @@ -80,7 +80,7 @@ describe('CommandPalette', () => { await user.type(screen.getByRole('textbox', { name: 'Search' }), 'routing') // The title is split into fragments by mark highlight, so use a partial text match expect(screen.getByText(/content-based/)).toBeInTheDocument() - expect(screen.queryByText('order-intake execution')).not.toBeInTheDocument() + expect(screen.queryByText('order-intake exchange')).not.toBeInTheDocument() }) it('calls onClose when Escape is pressed', async () => { @@ -143,7 +143,7 @@ describe('CommandPalette', () => { ) await user.click(screen.getByRole('tab', { name: /Routes/i })) expect(screen.getByText('content-based-routing')).toBeInTheDocument() - expect(screen.queryByText('order-intake execution')).not.toBeInTheDocument() + expect(screen.queryByText('order-intake exchange')).not.toBeInTheDocument() }) it('shows category tabs with counts', () => { diff --git a/src/design-system/composites/CommandPalette/CommandPalette.tsx b/src/design-system/composites/CommandPalette/CommandPalette.tsx index 93dec01..29b2102 100644 --- a/src/design-system/composites/CommandPalette/CommandPalette.tsx +++ b/src/design-system/composites/CommandPalette/CommandPalette.tsx @@ -16,17 +16,15 @@ interface CommandPaletteProps { const CATEGORY_LABELS: Record = { all: 'All', - execution: 'Executions', - route: 'Routes', exchange: 'Exchanges', + route: 'Routes', agent: 'Agents', } const ALL_CATEGORIES: Array = [ 'all', - 'execution', - 'route', 'exchange', + 'route', 'agent', ] @@ -203,7 +201,7 @@ export function CommandPalette({ open, onClose, onSelect, data, onOpen }: Comman ref={inputRef} type="text" className={styles.input} - placeholder="Search executions, routes, exchanges, agents…" + placeholder="Search exchanges, routes, agents…" value={query} onChange={(e) => { setQuery(e.target.value) diff --git a/src/design-system/composites/CommandPalette/types.ts b/src/design-system/composites/CommandPalette/types.ts index 80d9c63..af2541c 100644 --- a/src/design-system/composites/CommandPalette/types.ts +++ b/src/design-system/composites/CommandPalette/types.ts @@ -1,6 +1,6 @@ import type { ReactNode } from 'react' -export type SearchCategory = 'execution' | 'route' | 'exchange' | 'agent' +export type SearchCategory = 'exchange' | 'route' | 'agent' export interface SearchResult { id: string diff --git a/src/design-system/composites/Tabs/Tabs.test.tsx b/src/design-system/composites/Tabs/Tabs.test.tsx index 4c36b2f..366fa32 100644 --- a/src/design-system/composites/Tabs/Tabs.test.tsx +++ b/src/design-system/composites/Tabs/Tabs.test.tsx @@ -6,14 +6,14 @@ import { Tabs } from './Tabs' describe('Tabs', () => { const tabs = [ { label: 'All', count: 14, value: 'all' }, - { label: 'Executions', count: 8, value: 'executions' }, + { label: 'Exchanges', count: 8, value: 'exchanges' }, { label: 'Routes', count: 3, value: 'routes' }, ] it('renders all tab labels', () => { render( {}} />) expect(screen.getByText('All')).toBeInTheDocument() - expect(screen.getByText('Executions')).toBeInTheDocument() + expect(screen.getByText('Exchanges')).toBeInTheDocument() }) it('shows count badges', () => { diff --git a/src/design-system/layout/Sidebar/Sidebar.tsx b/src/design-system/layout/Sidebar/Sidebar.tsx index fa1b2b5..616feb9 100644 --- a/src/design-system/layout/Sidebar/Sidebar.tsx +++ b/src/design-system/layout/Sidebar/Sidebar.tsx @@ -8,13 +8,13 @@ export interface App { name: string agentCount: number health: 'live' | 'stale' | 'dead' - execCount: number + exchangeCount: number } export interface Route { id: string name: string - execCount: number + exchangeCount: number } export interface Agent { @@ -163,7 +163,7 @@ export function Sidebar({
{app.name}
{app.agentCount} agent{app.agentCount !== 1 ? 's' : ''}
- {app.execCount.toLocaleString()} + {app.exchangeCount.toLocaleString()} ))} @@ -195,7 +195,7 @@ export function Sidebar({
{route.name}
- {route.execCount.toLocaleString()} + {route.exchangeCount.toLocaleString()} ))} diff --git a/src/mocks/executions.ts b/src/mocks/exchanges.ts similarity index 99% rename from src/mocks/executions.ts rename to src/mocks/exchanges.ts index e8e669e..ad1ec5a 100644 --- a/src/mocks/executions.ts +++ b/src/mocks/exchanges.ts @@ -6,7 +6,7 @@ export interface ProcessorData { startMs: number } -export interface Execution { +export interface Exchange { id: string orderId: string customer: string @@ -22,7 +22,7 @@ export interface Execution { processors: ProcessorData[] } -export const executions: Execution[] = [ +export const exchanges: Exchange[] = [ { id: 'E-2026-03-18-00201', orderId: 'OP-92184', diff --git a/src/mocks/metrics.ts b/src/mocks/metrics.ts index 76f80c5..5f6abe5 100644 --- a/src/mocks/metrics.ts +++ b/src/mocks/metrics.ts @@ -44,7 +44,7 @@ function generateTimeSeries( // KPI stat cards data export const kpiMetrics: KpiMetric[] = [ { - label: 'Executions (shift)', + label: 'Exchanges (shift)', value: '3,241', trend: 'up', trendValue: '+12%', @@ -147,7 +147,7 @@ export const errorCountSeries: MetricSeries[] = [ export interface RouteMetricRow { routeId: string routeName: string - execCount: number + exchangeCount: number successRate: number avgDurationMs: number p99DurationMs: number @@ -159,7 +159,7 @@ export const routeMetrics: RouteMetricRow[] = [ { routeId: 'order-intake', routeName: 'order-intake', - execCount: 892, + exchangeCount: 892, successRate: 99.2, avgDurationMs: 88, p99DurationMs: 142, @@ -169,7 +169,7 @@ export const routeMetrics: RouteMetricRow[] = [ { routeId: 'order-enrichment', routeName: 'order-enrichment', - execCount: 541, + exchangeCount: 541, successRate: 97.6, avgDurationMs: 156, p99DurationMs: 287, @@ -179,7 +179,7 @@ export const routeMetrics: RouteMetricRow[] = [ { routeId: 'payment-process', routeName: 'payment-process', - execCount: 414, + exchangeCount: 414, successRate: 96.1, avgDurationMs: 234, p99DurationMs: 412, @@ -189,7 +189,7 @@ export const routeMetrics: RouteMetricRow[] = [ { routeId: 'shipment-dispatch', routeName: 'shipment-dispatch', - execCount: 387, + exchangeCount: 387, successRate: 98.4, avgDurationMs: 118, p99DurationMs: 248, diff --git a/src/mocks/routes.ts b/src/mocks/routes.ts index 85a11b2..30b171e 100644 --- a/src/mocks/routes.ts +++ b/src/mocks/routes.ts @@ -3,7 +3,7 @@ export interface RouteDefinition { name: string group: string description: string - execCount: number + exchangeCount: number successRate: number avgDurationMs: number p99DurationMs: number @@ -17,7 +17,7 @@ export const routes: RouteDefinition[] = [ name: 'order-intake', group: 'order-flow', description: 'Ingests new orders from JMS queue, validates schema, enriches with customer data', - execCount: 892, + exchangeCount: 892, successRate: 99.2, avgDurationMs: 88, p99DurationMs: 142, @@ -29,7 +29,7 @@ export const routes: RouteDefinition[] = [ name: 'order-enrichment', group: 'order-flow', description: 'Enriches order with inventory availability, pricing, and shipment options', - execCount: 541, + exchangeCount: 541, successRate: 97.6, avgDurationMs: 156, p99DurationMs: 287, @@ -41,7 +41,7 @@ export const routes: RouteDefinition[] = [ name: 'payment-process', group: 'payment-flow', description: 'Processes payment through gateway, handles retries and partial failures', - execCount: 414, + exchangeCount: 414, successRate: 96.1, avgDurationMs: 234, p99DurationMs: 412, @@ -53,7 +53,7 @@ export const routes: RouteDefinition[] = [ name: 'payment-validate', group: 'payment-flow', description: 'Validates payment details and performs fraud check before processing', - execCount: 498, + exchangeCount: 498, successRate: 99.8, avgDurationMs: 142, p99DurationMs: 198, @@ -65,7 +65,7 @@ export const routes: RouteDefinition[] = [ name: 'shipment-dispatch', group: 'shipment-flow', description: 'Dispatches shipment to carrier after order confirmation', - execCount: 387, + exchangeCount: 387, successRate: 98.4, avgDurationMs: 118, p99DurationMs: 248, @@ -77,7 +77,7 @@ export const routes: RouteDefinition[] = [ name: 'shipment-track', group: 'shipment-flow', description: 'Polls carrier APIs for shipment status updates and notifies customers', - execCount: 923, + exchangeCount: 923, successRate: 99.5, avgDurationMs: 94, p99DurationMs: 167, @@ -89,7 +89,7 @@ export const routes: RouteDefinition[] = [ name: 'notification-dispatch', group: 'notification-flow', description: 'Sends email and SMS notifications to customers for order events', - execCount: 471, + exchangeCount: 471, successRate: 98.9, avgDurationMs: 62, p99DurationMs: 124, diff --git a/src/pages/AgentHealth/AgentHealth.tsx b/src/pages/AgentHealth/AgentHealth.tsx index 9b3928a..80c8794 100644 --- a/src/pages/AgentHealth/AgentHealth.tsx +++ b/src/pages/AgentHealth/AgentHealth.tsx @@ -22,16 +22,16 @@ import { routes } from '../../mocks/routes' // ─── 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, })) // ─── Build trend data for each agent ───────────────────────────────────────── diff --git a/src/pages/Dashboard/Dashboard.tsx b/src/pages/Dashboard/Dashboard.tsx index 70d5fcd..e3976be 100644 --- a/src/pages/Dashboard/Dashboard.tsx +++ b/src/pages/Dashboard/Dashboard.tsx @@ -24,24 +24,24 @@ import { MonoText } from '../../design-system/primitives/MonoText/MonoText' import { Badge } from '../../design-system/primitives/Badge/Badge' // Mock data -import { executions, type Execution } from '../../mocks/executions' +import { exchanges, type Exchange } from '../../mocks/exchanges' import { routes } from '../../mocks/routes' import { agents } from '../../mocks/agents' import { kpiMetrics } from '../../mocks/metrics' // ─── Sidebar app list (static) ─────────────────────────────────────────────── 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 }, ] // ─── Sidebar routes (top 3) ─────────────────────────────────────────────────── const SIDEBAR_ROUTES = routes.slice(0, 3).map((r) => ({ id: r.id, name: r.name, - execCount: r.execCount, + exchangeCount: r.exchangeCount, })) // ─── Helpers ───────────────────────────────────────────────────────────────── @@ -55,7 +55,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' @@ -64,7 +64,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 statusLabel(status: Execution['status']): string { } // ─── Table columns ──────────────────────────────────────────────────────────── -const COLUMNS: Column[] = [ +const COLUMNS: Column[] = [ { key: 'status', header: 'Status', @@ -142,7 +142,7 @@ const COLUMNS: Column[] = [ }, ] -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 @@ -154,10 +154,10 @@ function durationClass(ms: number, status: Execution['status']): string { function buildSearchData(): SearchResult[] { const results: SearchResult[] = [] - for (const exec of executions) { + for (const exec of exchanges) { results.push({ id: exec.id, - category: 'execution', + category: 'exchange', title: `${exec.orderId} — ${exec.route}`, badges: [{ label: statusLabel(exec.status), color: statusToVariant(exec.status) }], meta: `${exec.correlationId} · ${formatDuration(exec.durationMs)} · ${exec.customer}`, @@ -171,7 +171,7 @@ function buildSearchData(): SearchResult[] { category: 'route', title: route.name, badges: [{ label: route.group }], - meta: `${route.execCount.toLocaleString()} executions · ${route.successRate}% success`, + meta: `${route.exchangeCount.toLocaleString()} exchanges · ${route.successRate}% success`, }) } @@ -192,11 +192,11 @@ const SEARCH_DATA = buildSearchData() // ─── Filter options ─────────────────────────────────────────────────────────── const STATUS_FILTERS = [ - { label: 'All', value: 'all', count: executions.length }, - { label: 'OK', value: 'completed', count: executions.filter((e) => e.status === 'completed').length, color: 'success' as const }, - { label: 'Warn', value: 'warning', count: executions.filter((e) => e.status === 'warning').length }, - { label: 'Error', value: 'failed', count: executions.filter((e) => e.status === 'failed').length, color: 'error' as const }, - { label: 'Running', value: 'running', count: executions.filter((e) => e.status === 'running').length, color: 'running' as const }, + { label: 'All', value: 'all', count: exchanges.length }, + { label: 'OK', value: 'completed', count: exchanges.filter((e) => e.status === 'completed').length, color: 'success' as const }, + { label: 'Warn', value: 'warning', count: exchanges.filter((e) => e.status === 'warning').length }, + { label: 'Error', value: 'failed', count: exchanges.filter((e) => e.status === 'failed').length, color: 'error' as const }, + { label: 'Running', value: 'running', count: exchanges.filter((e) => e.status === 'running').length, color: 'running' as const }, ] const SHORTCUTS = [ @@ -213,12 +213,12 @@ export function Dashboard() { const [search, setSearch] = useState('') const [selectedId, setSelectedId] = useState() const [panelOpen, setPanelOpen] = useState(false) - const [selectedExecution, setSelectedExecution] = useState(null) + const [selectedExchange, setSelectedExchange] = useState(null) const [paletteOpen, setPaletteOpen] = useState(false) - // Filter executions - const filteredExecutions = useMemo(() => { - let data = executions + // Filter exchanges + const filteredExchanges = useMemo(() => { + let data = exchanges const statusFilter = activeFilters.find((f) => ['completed', 'failed', 'running', 'warning', 'all'].includes(f.value), @@ -242,20 +242,20 @@ export function Dashboard() { return data }, [activeFilters, search]) - function handleRowClick(row: Execution) { + function handleRowClick(row: Exchange) { setSelectedId(row.id) - setSelectedExecution(row) + setSelectedExchange(row) setPanelOpen(true) } - function handleRowAccent(row: Execution): 'error' | 'warning' | undefined { + function handleRowAccent(row: Exchange): 'error' | 'warning' | undefined { if (row.status === 'failed') return 'error' if (row.status === 'warning') return 'warning' return undefined } - // Build detail panel tabs for selected execution - const detailTabs = selectedExecution + // Build detail panel tabs for selected exchange + const detailTabs = selectedExchange ? [ { label: 'Overview', @@ -264,43 +264,43 @@ export function Dashboard() {
Order ID - {selectedExecution.orderId} + {selectedExchange.orderId}
Route - {selectedExecution.route} + {selectedExchange.route}
Status - - {statusLabel(selectedExecution.status)} + + {statusLabel(selectedExchange.status)}
Duration - {formatDuration(selectedExecution.durationMs)} + {formatDuration(selectedExchange.durationMs)}
Customer - {selectedExecution.customer} + {selectedExchange.customer}
Agent - {selectedExecution.agent} + {selectedExchange.agent}
Correlation ID - {selectedExecution.correlationId} + {selectedExchange.correlationId}
Timestamp - {selectedExecution.timestamp.toISOString()} + {selectedExchange.timestamp.toISOString()}
- {selectedExecution.errorMessage && ( + {selectedExchange.errorMessage && (
-
{selectedExecution.errorClass}
-
{selectedExecution.errorMessage}
+
{selectedExchange.errorClass}
+
{selectedExchange.errorMessage}
)}
@@ -312,8 +312,8 @@ export function Dashboard() { content: (
), @@ -332,13 +332,13 @@ export function Dashboard() { value: 'error', content: (
- {selectedExecution.errorMessage ? ( + {selectedExchange.errorMessage ? ( <> -
{selectedExecution.errorClass}
-
{selectedExecution.errorMessage}
+
{selectedExchange.errorClass}
+
{selectedExchange.errorMessage}
) : ( -
No error for this execution.
+
No error for this exchange.
)}
), @@ -358,11 +358,11 @@ export function Dashboard() { /> } detail={ - selectedExecution ? ( + selectedExchange ? ( setPanelOpen(false)} - title={`${selectedExecution.orderId} — ${selectedExecution.route}`} + title={`${selectedExchange.orderId} — ${selectedExchange.route}`} tabs={detailTabs} /> ) : undefined @@ -410,13 +410,13 @@ export function Dashboard() { className={styles.filterBar} /> - {/* Executions table */} + {/* Exchanges table */}
- Recent Executions + Recent Exchanges
- {filteredExecutions.length.toLocaleString()} of {executions.length.toLocaleString()} executions + {filteredExchanges.length.toLocaleString()} of {exchanges.length.toLocaleString()} exchanges
@@ -424,7 +424,7 @@ export function Dashboard() { ({ id: r.id, name: r.name, - execCount: r.execCount, + exchangeCount: r.exchangeCount, })) // ─── Helpers ────────────────────────────────────────────────────────────────── @@ -121,7 +121,7 @@ export function ExchangeDetail() { const navigate = useNavigate() const [activeItem, setActiveItem] = useState('') - const execution = useMemo(() => executions.find((e) => e.id === id), [id]) + const exchange = useMemo(() => exchanges.find((e) => e.id === id), [id]) function handleItemClick(itemId: string) { setActiveItem(itemId) @@ -130,7 +130,7 @@ export function ExchangeDetail() { } // Not found state - if (!execution) { + if (!exchange) { return (
- {execution.id} + {exchange.id}
- Route: navigate(`/routes/${execution.route}`)}>{execution.route} + Route: navigate(`/routes/${exchange.route}`)}>{exchange.route} · - Order: {execution.orderId} + Order: {exchange.orderId} · - Customer: {execution.customer} + Customer: {exchange.customer}
Duration
-
{formatDuration(execution.durationMs)}
+
{formatDuration(exchange.durationMs)}
Agent
-
{execution.agent}
+
{exchange.agent}
Started
- {execution.timestamp.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' })} + {exchange.timestamp.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
Processors
-
{execution.processors.length}
+
{exchange.processors.length}
@@ -236,12 +236,12 @@ export function ExchangeDetail() {
Processor Timeline - Total: {formatDuration(execution.durationMs)} + Total: {formatDuration(exchange.durationMs)}
@@ -250,11 +250,11 @@ export function ExchangeDetail() {
Exchange Inspector - {execution.processors.length} processor steps + {exchange.processors.length} processor steps
- {execution.processors.map((proc, index) => { - const snapshot = generateExchangeSnapshot(proc, execution.orderId, execution.customer, index) + {exchange.processors.map((proc, index) => { + const snapshot = generateExchangeSnapshot(proc, exchange.orderId, exchange.customer, index) const stepStatusClass = proc.status === 'fail' ? styles.stepFail @@ -307,18 +307,18 @@ export function ExchangeDetail() {
{/* Error block (if failed) */} - {execution.status === 'failed' && execution.errorMessage && ( + {exchange.status === 'failed' && exchange.errorMessage && (
Error Details
-
{execution.errorClass}
-
{execution.errorMessage}
+
{exchange.errorClass}
+
{exchange.errorMessage}
Failed at processor: - {execution.processors.find((p) => p.status === 'fail')?.name ?? 'unknown'} + {exchange.processors.find((p) => p.status === 'fail')?.name ?? 'unknown'}
diff --git a/src/pages/Metrics/Metrics.tsx b/src/pages/Metrics/Metrics.tsx index ec87c77..a88a6c3 100644 --- a/src/pages/Metrics/Metrics.tsx +++ b/src/pages/Metrics/Metrics.tsx @@ -34,16 +34,16 @@ 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, })) // ─── Metrics KPI cards (5 cards per spec) ───────────────────────────────────── @@ -115,11 +115,11 @@ const ROUTE_COLUMNS: Column[] = [ ), }, { - key: 'execCount', - header: 'Executions', + key: 'exchangeCount', + header: 'Exchanges', sortable: true, render: (_, row) => ( - {row.execCount.toLocaleString()} + {row.exchangeCount.toLocaleString()} ), }, { diff --git a/src/pages/RouteDetail/RouteDetail.module.css b/src/pages/RouteDetail/RouteDetail.module.css index c52cdbf..a3ac57a 100644 --- a/src/pages/RouteDetail/RouteDetail.module.css +++ b/src/pages/RouteDetail/RouteDetail.module.css @@ -136,7 +136,7 @@ color: var(--text-muted); } -/* Executions table */ +/* Exchanges table */ .tableSection { background: var(--bg-surface); border: 1px solid var(--border-subtle); diff --git a/src/pages/RouteDetail/RouteDetail.tsx b/src/pages/RouteDetail/RouteDetail.tsx index 41478f3..ba82b9c 100644 --- a/src/pages/RouteDetail/RouteDetail.tsx +++ b/src/pages/RouteDetail/RouteDetail.tsx @@ -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[] = [ +// ─── Columns for exchanges table ──────────────────────────────────────────── +const EXCHANGE_COLUMNS: Column[] = [ { key: 'status', header: 'Status', @@ -97,7 +97,7 @@ const EXEC_COLUMNS: Column[] = [ }, { key: 'id', - header: 'Execution ID', + header: 'Exchange ID', render: (_, row) => {row.id}, }, { @@ -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 = {} - 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 */}
-
Total Executions
-
{route.execCount.toLocaleString()}
+
Total Exchanges
+
{route.exchangeCount.toLocaleString()}
Success Rate
@@ -331,7 +331,7 @@ export function RouteDetail() {
Processor Performance (aggregate avg) - Based on {routeExecutions.length} executions + Based on {routeExchanges.length} exchanges
{aggregateProcessors.length > 0 ? ( ) : ( -
No execution data for this route in mock set.
+
No exchange data for this route in mock set.
)}
- {/* Recent executions table */} + {/* Recent exchanges table */}
- Recent Executions + Recent Exchanges
- {routeExecutions.length} executions · {errorCount} errors + {routeExchanges.length} exchanges · {errorCount} errors
{ if (row.status === 'failed') return 'error'