fix: add groupName to ExecutionDetail, rewrite ExchangeDetail to match mock
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

- Add groupName field to ExecutionDetail record and DetailService
- Dashboard: fix TDZ error (rows referenced before definition), add
  selectedRow fallback for diagram groupName lookup
- ExchangeDetail: rewrite to match mock layout — auto-select first
  processor, Message IN/OUT split panels with header key-value rows,
  error panel for failed processors, Timeline/Flow toggle buttons
- Track diagram-mapping utility (was untracked, caused CI build failure)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-23 21:02:14 +01:00
parent a950feaef1
commit 2ae2871822
6 changed files with 497 additions and 114 deletions

View File

@@ -0,0 +1,55 @@
import type { RouteNode } from '@cameleer/design-system';
// Map NodeType strings to RouteNode types
function mapNodeType(type: string): RouteNode['type'] {
const lower = type?.toLowerCase() || '';
if (lower.includes('from') || lower === 'endpoint') return 'from';
if (lower.includes('to')) return 'to';
if (lower.includes('choice') || lower.includes('when') || lower.includes('otherwise')) return 'choice';
if (lower.includes('error') || lower.includes('dead')) return 'error-handler';
return 'process';
}
function mapStatus(status: string | undefined): RouteNode['status'] {
if (!status) return 'ok';
const s = status.toUpperCase();
if (s === 'FAILED') return 'fail';
if (s === 'RUNNING') return 'slow';
return 'ok';
}
/**
* Maps diagram PositionedNodes + execution ProcessorNodes to RouteFlow RouteNode[] format.
* Joins on diagramNodeId → node.id.
*/
export function mapDiagramToRouteNodes(
diagramNodes: Array<{ id?: string; label?: string; type?: string }>,
processors: Array<{ diagramNodeId?: string; processorId?: string; status?: string; durationMs?: number; children?: any[] }>
): RouteNode[] {
// Flatten processor tree
const flatProcessors: typeof processors = [];
function flatten(nodes: typeof processors) {
for (const n of nodes) {
flatProcessors.push(n);
if (n.children) flatten(n.children);
}
}
flatten(processors || []);
// Build lookup: diagramNodeId → processor
const procMap = new Map<string, (typeof flatProcessors)[0]>();
for (const p of flatProcessors) {
if (p.diagramNodeId) procMap.set(p.diagramNodeId, p);
}
return diagramNodes.map(node => {
const proc = procMap.get(node.id ?? '');
return {
name: node.label || node.id || '',
type: mapNodeType(node.type ?? ''),
durationMs: proc?.durationMs ?? 0,
status: mapStatus(proc?.status),
isBottleneck: false,
};
});
}