diff --git a/ui/src/pages/Exchanges/ExchangeHeader.module.css b/ui/src/pages/Exchanges/ExchangeHeader.module.css
index a178c68d..c686646e 100644
--- a/ui/src/pages/Exchanges/ExchangeHeader.module.css
+++ b/ui/src/pages/Exchanges/ExchangeHeader.module.css
@@ -185,6 +185,11 @@
font-weight: 500;
}
+.replayIcon {
+ color: var(--amber);
+ flex-shrink: 0;
+}
+
.chainDuration {
color: var(--text-muted);
font-size: 9px;
diff --git a/ui/src/pages/Exchanges/ExchangeHeader.tsx b/ui/src/pages/Exchanges/ExchangeHeader.tsx
index 9d13fda9..2ef8d2d2 100644
--- a/ui/src/pages/Exchanges/ExchangeHeader.tsx
+++ b/ui/src/pages/Exchanges/ExchangeHeader.tsx
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { useNavigate } from 'react-router';
-import { GitBranch, Server } from 'lucide-react';
+import { GitBranch, Server, RotateCcw } from 'lucide-react';
import { StatusDot, MonoText, Badge } from '@cameleer/design-system';
import { useCorrelationChain } from '../../api/queries/correlation';
import { useAgents } from '../../api/queries/agents';
@@ -122,6 +122,7 @@ export function ExchangeHeader({ detail, onCorrelatedSelect, onClearSelection }:
{showChain ? chain.map((ce: any, i: number) => {
const isCurrent = ce.executionId === detail.executionId;
const variant = statusVariant(ce.status);
+ const isReplay = ce.attributes?._replay != null;
const statusCls =
variant === 'success' ? styles.chainNodeSuccess
: variant === 'error' ? styles.chainNodeError
@@ -137,9 +138,10 @@ export function ExchangeHeader({ detail, onCorrelatedSelect, onClearSelection }:
onCorrelatedSelect(ce.executionId, ce.applicationName ?? detail.applicationName, ce.routeId);
}
}}
- title={`${ce.executionId}\n${ce.routeId} \u2014 ${formatDuration(ce.durationMs)}`}
+ title={`${ce.executionId}\n${ce.routeId} \u2014 ${formatDuration(ce.durationMs)}${isReplay ? '\n(replay)' : ''}`}
>
+ {isReplay && }
{ce.routeId}
{formatDuration(ce.durationMs)}