From ce4abaf862428eeb26a69f3816baa6e2adaa0927 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Wed, 1 Apr 2026 17:37:47 +0200 Subject: [PATCH] fix: infer compound node color from descendants when no own overlay state Path containers (EIP_WHEN, EIP_OTHERWISE, etc.) don't have their own processor records, so they never get an overlay entry. Now inferred from descendants: green if any descendant executed, red if any failed. Gated (amber) only when no descendants executed at all. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../ProcessDiagram/CompoundNode.tsx | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/ui/src/components/ProcessDiagram/CompoundNode.tsx b/ui/src/components/ProcessDiagram/CompoundNode.tsx index 549b1fae..9a8e45e1 100644 --- a/ui/src/components/ProcessDiagram/CompoundNode.tsx +++ b/ui/src/components/ProcessDiagram/CompoundNode.tsx @@ -68,18 +68,19 @@ export function CompoundNode({ // Execution overlay state for this compound const ownState = node.id ? executionOverlay?.get(node.id) : undefined; - const hasExecutedChild = ownState && hasExecutedDescendant(node, executionOverlay); + const executedDescendant = hasExecutedDescendant(node, executionOverlay); const isCompleted = ownState?.status === 'COMPLETED'; const isFailed = ownState?.status === 'FAILED'; + const descendantFailed = executedDescendant && hasFailedDescendant(node, executionOverlay); - // Gated = gate processor (filter/idempotent) blocked all children from executing - const isGated = ownState && !hasExecutedChild + // Gated = gate processor blocked all children from executing + const isGated = ownState && !executedDescendant && (ownState.filterMatched === false || ownState.duplicateMessage === true); - // Color priority: gated (amber) > failed (red) > completed (green) > default + // Color: own status first, then infer from descendants (for path containers like when/otherwise) const effectiveColor = isGated ? 'var(--amber)' - : isFailed ? '#C0392B' - : isCompleted ? '#3D7C47' + : isFailed || descendantFailed ? '#C0392B' + : isCompleted || executedDescendant ? '#3D7C47' : color; // Dim compound when overlay is active but neither the compound nor any @@ -295,3 +296,18 @@ function hasExecutedDescendant( } return false; } + +function hasFailedDescendant( + node: DiagramNodeType, + overlay?: Map, +): boolean { + if (!overlay || !node.children) return false; + for (const child of node.children) { + if (child.id) { + const state = overlay.get(child.id); + if (state?.status === 'FAILED') return true; + } + if (child.children && hasFailedDescendant(child, overlay)) return true; + } + return false; +}