fix: add groupName to ExecutionSummary, locale format stat values, inspect column, fix duplicate keys
Some checks failed
CI / build (push) Failing after 40s
CI / cleanup-branch (push) Has been skipped
CI / docker (push) Has been skipped
CI / deploy (push) Has been skipped
CI / deploy-feature (push) Has been skipped

- Added groupName field to ExecutionSummary Java record and OpenSearch mapper
- Dashboard stat cards use locale-formatted numbers (en-US)
- Added inspect column (↗) linking directly to exchange detail page
- Fixed duplicate React key warning from two columns sharing executionId key

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-23 20:41:46 +01:00
parent 4572230c9c
commit a72b0954db
4 changed files with 35 additions and 4 deletions

View File

@@ -323,6 +323,7 @@ public class OpenSearchIndex implements SearchIndex {
(String) src.get("execution_id"), (String) src.get("execution_id"),
(String) src.get("route_id"), (String) src.get("route_id"),
(String) src.get("agent_id"), (String) src.get("agent_id"),
(String) src.get("group_name"),
(String) src.get("status"), (String) src.get("status"),
src.get("start_time") != null ? Instant.parse((String) src.get("start_time")) : null, src.get("start_time") != null ? Instant.parse((String) src.get("start_time")) : null,
src.get("end_time") != null ? Instant.parse((String) src.get("end_time")) : null, src.get("end_time") != null ? Instant.parse((String) src.get("end_time")) : null,

View File

@@ -23,6 +23,7 @@ public record ExecutionSummary(
String executionId, String executionId,
String routeId, String routeId,
String agentId, String agentId,
String groupName,
String status, String status,
Instant startTime, Instant startTime,
Instant endTime, Instant endTime,

View File

@@ -83,6 +83,24 @@
padding-top: 2px; padding-top: 2px;
} }
.inspectLink {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
font-size: 14px;
color: var(--text-muted);
text-decoration: none;
border-radius: 4px;
transition: color 0.15s, background 0.15s;
}
.inspectLink:hover {
color: var(--accent, #c6820e);
background: var(--bg-hover);
}
.openDetailLink { .openDetailLink {
display: inline-block; display: inline-block;
font-size: 13px; font-size: 13px;

View File

@@ -84,6 +84,17 @@ export default function Dashboard() {
</span> </span>
), ),
}, },
{
key: '_inspect' as any, header: '', width: '36px',
render: (_v, row) => (
<a
href={`/exchanges/${row.executionId}`}
onClick={(e) => { e.stopPropagation(); e.preventDefault(); navigate(`/exchanges/${row.executionId}`); }}
className={styles.inspectLink}
title="Open full details"
>&#x2197;</a>
),
},
{ key: 'routeId', header: 'Route', sortable: true, render: (v) => <span>{String(v)}</span> }, { key: 'routeId', header: 'Route', sortable: true, render: (v) => <span>{String(v)}</span> },
{ key: 'groupName', header: 'Application', sortable: true, render: (v) => <span>{String(v ?? '')}</span> }, { key: 'groupName', header: 'Application', sortable: true, render: (v) => <span>{String(v ?? '')}</span> },
{ key: 'executionId', header: 'Exchange ID', sortable: true, render: (v) => <MonoText size="xs">{String(v)}</MonoText> }, { key: 'executionId', header: 'Exchange ID', sortable: true, render: (v) => <MonoText size="xs">{String(v)}</MonoText> },
@@ -193,7 +204,7 @@ export default function Dashboard() {
<div className={styles.healthStrip}> <div className={styles.healthStrip}>
<StatCard <StatCard
label="Exchanges" label="Exchanges"
value={totalCount.toLocaleString()} value={totalCount.toLocaleString('en-US')}
detail={`${successRate.toFixed(1)}% success rate`} detail={`${successRate.toFixed(1)}% success rate`}
trend={exchangeTrend > 0 ? 'up' : exchangeTrend < 0 ? 'down' : 'neutral'} trend={exchangeTrend > 0 ? 'up' : exchangeTrend < 0 ? 'down' : 'neutral'}
trendValue={exchangeTrend > 0 ? `+${exchangeTrend.toFixed(0)}%` : `${exchangeTrend.toFixed(0)}%`} trendValue={exchangeTrend > 0 ? `+${exchangeTrend.toFixed(0)}%` : `${exchangeTrend.toFixed(0)}%`}
@@ -203,7 +214,7 @@ export default function Dashboard() {
<StatCard <StatCard
label="Success Rate" label="Success Rate"
value={`${successRate.toFixed(1)}%`} value={`${successRate.toFixed(1)}%`}
detail={`${(totalCount - failedCount).toLocaleString()} ok / ${failedCount} error`} detail={`${(totalCount - failedCount).toLocaleString('en-US')} ok / ${failedCount} error`}
trend={successRateDelta >= 0 ? 'up' : 'down'} trend={successRateDelta >= 0 ? 'up' : 'down'}
trendValue={`${successRateDelta >= 0 ? '+' : ''}${successRateDelta.toFixed(1)}%`} trendValue={`${successRateDelta >= 0 ? '+' : ''}${successRateDelta.toFixed(1)}%`}
accent="success" accent="success"
@@ -226,8 +237,8 @@ export default function Dashboard() {
/> />
<StatCard <StatCard
label="Latency p99" label="Latency p99"
value={stats?.p99LatencyMs ?? 0} value={(stats?.p99LatencyMs ?? 0).toLocaleString('en-US')}
detail={`${stats?.p99LatencyMs ?? 0}ms`} detail={`${(stats?.p99LatencyMs ?? 0).toLocaleString('en-US')}ms`}
sparkline={sparkLatency} sparkline={sparkLatency}
accent="warning" accent="warning"
/> />