Compare commits
2 Commits
26de222884
...
30e9b55379
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30e9b55379 | ||
|
|
3091754b0f |
@@ -90,7 +90,7 @@ export function DetailPanel({
|
|||||||
<div className={styles.detailPanel}>
|
<div className={styles.detailPanel}>
|
||||||
{/* Header bar */}
|
{/* Header bar */}
|
||||||
<div className={styles.processorHeader}>
|
<div className={styles.processorHeader}>
|
||||||
<span className={styles.processorName}>Details</span>
|
<span className={styles.processorName}>{selectedProcessor ? 'Processor Details' : 'Exchange Details'}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tab bar */}
|
{/* Tab bar */}
|
||||||
|
|||||||
@@ -20,15 +20,46 @@ interface ExecutionDiagramProps {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ITERATION_WRAPPER_TYPES = new Set([
|
||||||
|
'loopIteration', 'splitIteration', 'multicastBranch',
|
||||||
|
]);
|
||||||
|
|
||||||
|
function wrapperIndex(proc: ProcessorNode): number | undefined {
|
||||||
|
return proc.loopIndex ?? proc.splitIndex ?? proc.multicastIndex ?? undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a processor in the tree, respecting iteration filtering.
|
||||||
|
* Only recurses into the selected iteration wrapper so the returned
|
||||||
|
* ProcessorNode has data from the correct iteration.
|
||||||
|
*/
|
||||||
function findProcessorInTree(
|
function findProcessorInTree(
|
||||||
nodes: ProcessorNode[] | undefined,
|
nodes: ProcessorNode[] | undefined,
|
||||||
processorId: string | null,
|
processorId: string | null,
|
||||||
|
iterationState?: Map<string, import('./types').IterationInfo>,
|
||||||
|
parentId?: string,
|
||||||
): ProcessorNode | null {
|
): ProcessorNode | null {
|
||||||
if (!nodes || !processorId) return null;
|
if (!nodes || !processorId) return null;
|
||||||
for (const n of nodes) {
|
for (const n of nodes) {
|
||||||
|
if (!n.processorId) continue;
|
||||||
|
|
||||||
|
// Iteration wrapper: only recurse into the selected iteration
|
||||||
|
if (ITERATION_WRAPPER_TYPES.has(n.processorType)) {
|
||||||
|
if (parentId && iterationState?.has(parentId)) {
|
||||||
|
const info = iterationState.get(parentId)!;
|
||||||
|
const idx = wrapperIndex(n);
|
||||||
|
if (idx != null && idx !== info.current) continue;
|
||||||
|
}
|
||||||
|
if (n.children) {
|
||||||
|
const found = findProcessorInTree(n.children, processorId, iterationState, n.processorId);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (n.processorId === processorId) return n;
|
if (n.processorId === processorId) return n;
|
||||||
if (n.children) {
|
if (n.children) {
|
||||||
const found = findProcessorInTree(n.children, processorId);
|
const found = findProcessorInTree(n.children, processorId, iterationState, n.processorId);
|
||||||
if (found) return found;
|
if (found) return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,7 +235,11 @@ export function ExecutionDiagram({
|
|||||||
{/* Detail panel */}
|
{/* Detail panel */}
|
||||||
<div className={styles.detailArea} style={{ height: `${100 - splitPercent}%` }}>
|
<div className={styles.detailArea} style={{ height: `${100 - splitPercent}%` }}>
|
||||||
<DetailPanel
|
<DetailPanel
|
||||||
selectedProcessor={findProcessorInTree(detail.processors, selectedProcessorId || null)}
|
selectedProcessor={
|
||||||
|
selectedProcessorId && overlay.has(selectedProcessorId)
|
||||||
|
? findProcessorInTree(detail.processors, selectedProcessorId, iterationState)
|
||||||
|
: null
|
||||||
|
}
|
||||||
executionDetail={detail}
|
executionDetail={detail}
|
||||||
executionId={executionId}
|
executionId={executionId}
|
||||||
onSelectProcessor={setSelectedProcessorId}
|
onSelectProcessor={setSelectedProcessorId}
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ export function CompoundNode({
|
|||||||
const isGated = ownState?.filterMatched === false || ownState?.duplicateMessage === true;
|
const isGated = ownState?.filterMatched === false || ownState?.duplicateMessage === true;
|
||||||
const effectiveColor = isGated ? 'var(--amber)' : color;
|
const effectiveColor = isGated ? 'var(--amber)' : color;
|
||||||
|
|
||||||
|
// Dim compound when overlay is active but neither the compound nor any
|
||||||
|
// descendant was executed in the current iteration.
|
||||||
|
const isSkipped = overlayActive && !ownState && !hasExecutedDescendant(node, executionOverlay);
|
||||||
|
|
||||||
// _TRY_BODY / _CB_MAIN: transparent wrapper — no header, no border, just layout
|
// _TRY_BODY / _CB_MAIN: transparent wrapper — no header, no border, just layout
|
||||||
if (node.type === '_TRY_BODY' || node.type === '_CB_MAIN') {
|
if (node.type === '_TRY_BODY' || node.type === '_CB_MAIN') {
|
||||||
return (
|
return (
|
||||||
@@ -85,7 +89,7 @@ export function CompoundNode({
|
|||||||
if (node.type === '_CB_FALLBACK') {
|
if (node.type === '_CB_FALLBACK') {
|
||||||
const fallbackColor = '#7C3AED'; // EIP purple
|
const fallbackColor = '#7C3AED'; // EIP purple
|
||||||
return (
|
return (
|
||||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
<g data-node-id={node.id} transform={`translate(${x}, ${y})`} opacity={isSkipped ? 0.35 : undefined}>
|
||||||
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||||
fill={fallbackColor} fillOpacity={0.06} />
|
fill={fallbackColor} fillOpacity={0.06} />
|
||||||
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||||
@@ -106,7 +110,7 @@ export function CompoundNode({
|
|||||||
: (node.label ? `finally: ${node.label}` : 'finally');
|
: (node.label ? `finally: ${node.label}` : 'finally');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
<g data-node-id={node.id} transform={`translate(${x}, ${y})`} opacity={isSkipped ? 0.35 : undefined}>
|
||||||
{/* Tinted background */}
|
{/* Tinted background */}
|
||||||
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||||
fill={color} fillOpacity={0.06} />
|
fill={color} fillOpacity={0.06} />
|
||||||
@@ -126,7 +130,7 @@ export function CompoundNode({
|
|||||||
// Default compound rendering (DO_TRY, EIP_CHOICE, EIP_FILTER, EIP_IDEMPOTENT_CONSUMER, etc.)
|
// Default compound rendering (DO_TRY, EIP_CHOICE, EIP_FILTER, EIP_IDEMPOTENT_CONSUMER, etc.)
|
||||||
const containerFill = isGated ? 'var(--amber-bg)' : 'white';
|
const containerFill = isGated ? 'var(--amber-bg)' : 'white';
|
||||||
return (
|
return (
|
||||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
<g data-node-id={node.id} transform={`translate(${x}, ${y})`} opacity={isSkipped ? 0.35 : undefined}>
|
||||||
{/* Container body */}
|
{/* Container body */}
|
||||||
<rect
|
<rect
|
||||||
x={0}
|
x={0}
|
||||||
@@ -268,3 +272,15 @@ function collectIds(nodes: DiagramNodeType[], set: Set<string>) {
|
|||||||
if (n.children) collectIds(n.children, set);
|
if (n.children) collectIds(n.children, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasExecutedDescendant(
|
||||||
|
node: DiagramNodeType,
|
||||||
|
overlay?: Map<string, NodeExecutionState>,
|
||||||
|
): boolean {
|
||||||
|
if (!overlay || !node.children) return false;
|
||||||
|
for (const child of node.children) {
|
||||||
|
if (child.id && overlay.has(child.id)) return true;
|
||||||
|
if (child.children && hasExecutedDescendant(child, overlay)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user