diff --git a/ui/src/components/ProcessDiagram/CompoundNode.tsx b/ui/src/components/ProcessDiagram/CompoundNode.tsx index 2e20f5d4..3e96d029 100644 --- a/ui/src/components/ProcessDiagram/CompoundNode.tsx +++ b/ui/src/components/ProcessDiagram/CompoundNode.tsx @@ -71,6 +71,10 @@ export function CompoundNode({ const isGated = ownState?.filterMatched === false || ownState?.duplicateMessage === true; 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 if (node.type === '_TRY_BODY' || node.type === '_CB_MAIN') { return ( @@ -85,7 +89,7 @@ export function CompoundNode({ if (node.type === '_CB_FALLBACK') { const fallbackColor = '#7C3AED'; // EIP purple return ( - + + {/* Tinted background */} @@ -126,7 +130,7 @@ export function CompoundNode({ // Default compound rendering (DO_TRY, EIP_CHOICE, EIP_FILTER, EIP_IDEMPOTENT_CONSUMER, etc.) const containerFill = isGated ? 'var(--amber-bg)' : 'white'; return ( - + {/* Container body */} ) { if (n.children) collectIds(n.children, set); } } + +function hasExecutedDescendant( + node: DiagramNodeType, + overlay?: Map, +): 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; +}