feat: render doTry/doCatch/doFinally like route-level handler sections
Backend: DO_TRY compounds now use a virtual _TRY_BODY wrapper with LR layout for the try body, while DO_CATCH/DO_FINALLY stack below as separate sections (TB). Edges from DO_TRY are skipped like route-level handler edges. Removes ELK-v2 debug logging. Frontend: _TRY_BODY renders as transparent wrapper, DO_CATCH as red tinted section, DO_FINALLY as teal section. DO_FINALLY color changed from red to teal (completion handler, not error). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -265,10 +265,11 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process main flow nodes into the root ELK graph
|
// Process main flow nodes into the root ELK graph
|
||||||
|
Set<String> doTryNodeIds = new HashSet<>();
|
||||||
for (RouteNode rn : mainNodes) {
|
for (RouteNode rn : mainNodes) {
|
||||||
if (!elkNodeMap.containsKey(rn.getId())) {
|
if (!elkNodeMap.containsKey(rn.getId())) {
|
||||||
createElkNodeRecursive(rn, rootNode, factory, elkNodeMap, nodeColors,
|
createElkNodeRecursive(rn, rootNode, factory, elkNodeMap, nodeColors,
|
||||||
compoundNodeIds, childNodeIds);
|
compoundNodeIds, childNodeIds, doTryNodeIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,13 +288,20 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
NodePlacementStrategy.LINEAR_SEGMENTS);
|
NodePlacementStrategy.LINEAR_SEGMENTS);
|
||||||
|
|
||||||
createElkNodeRecursive(rn, handlerRoot, factory, elkNodeMap, nodeColors,
|
createElkNodeRecursive(rn, handlerRoot, factory, elkNodeMap, nodeColors,
|
||||||
compoundNodeIds, childNodeIds);
|
compoundNodeIds, childNodeIds, doTryNodeIds);
|
||||||
handlerRoots.add(handlerRoot);
|
handlerRoots.add(handlerRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create ELK edges — skip edges that cross between different ELK root graphs
|
// Create ELK edges — skip edges that cross between different ELK root graphs
|
||||||
if (graph.getEdges() != null) {
|
if (graph.getEdges() != null) {
|
||||||
for (RouteEdge re : graph.getEdges()) {
|
for (RouteEdge re : graph.getEdges()) {
|
||||||
|
// Skip all edges originating from DO_TRY nodes — these are entry/handler
|
||||||
|
// edges that don't need layout (try body has its own internal flow,
|
||||||
|
// handler edges are like route-level ON_EXCEPTION edges)
|
||||||
|
if (doTryNodeIds.contains(re.getSource())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
ElkNode sourceElk = elkNodeMap.get(re.getSource());
|
ElkNode sourceElk = elkNodeMap.get(re.getSource());
|
||||||
ElkNode targetElk = elkNodeMap.get(re.getTarget());
|
ElkNode targetElk = elkNodeMap.get(re.getTarget());
|
||||||
if (sourceElk == null || targetElk == null) {
|
if (sourceElk == null || targetElk == null) {
|
||||||
@@ -322,17 +330,6 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
engine.layout(handlerRoot, new BasicProgressMonitor());
|
engine.layout(handlerRoot, new BasicProgressMonitor());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug: log root dimensions and children after layout
|
|
||||||
System.out.println("[ELK-v2] rootNode " + rootNode.getWidth() + "x" + rootNode.getHeight()
|
|
||||||
+ " children=" + rootNode.getChildren().size()
|
|
||||||
+ " mainNodes=" + mainNodes.size() + " handlerNodes=" + handlerNodes.size());
|
|
||||||
for (ElkNode child : rootNode.getChildren()) {
|
|
||||||
System.out.println("[ELK-v2] " + child.getIdentifier()
|
|
||||||
+ " x=" + String.format("%.1f", child.getX())
|
|
||||||
+ " y=" + String.format("%.1f", child.getY())
|
|
||||||
+ " parent=" + (child.getParent() != null ? child.getParent().getIdentifier() : "null"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract positioned nodes
|
// Extract positioned nodes
|
||||||
List<PositionedNode> positionedNodes = new ArrayList<>();
|
List<PositionedNode> positionedNodes = new ArrayList<>();
|
||||||
Map<String, CompoundInfo> compoundInfos = new HashMap<>();
|
Map<String, CompoundInfo> compoundInfos = new HashMap<>();
|
||||||
@@ -533,7 +530,8 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
private void createElkNodeRecursive(
|
private void createElkNodeRecursive(
|
||||||
RouteNode rn, ElkNode parentElk, ElkGraphFactory factory,
|
RouteNode rn, ElkNode parentElk, ElkGraphFactory factory,
|
||||||
Map<String, ElkNode> elkNodeMap, Map<String, Color> nodeColors,
|
Map<String, ElkNode> elkNodeMap, Map<String, Color> nodeColors,
|
||||||
Set<String> compoundNodeIds, Set<String> childNodeIds) {
|
Set<String> compoundNodeIds, Set<String> childNodeIds,
|
||||||
|
Set<String> doTryNodeIds) {
|
||||||
|
|
||||||
boolean isCompound = rn.getType() != null && COMPOUND_TYPES.contains(rn.getType())
|
boolean isCompound = rn.getType() != null && COMPOUND_TYPES.contains(rn.getType())
|
||||||
&& rn.getChildren() != null && !rn.getChildren().isEmpty();
|
&& rn.getChildren() != null && !rn.getChildren().isEmpty();
|
||||||
@@ -542,7 +540,63 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
elkNode.setIdentifier(rn.getId());
|
elkNode.setIdentifier(rn.getId());
|
||||||
elkNode.setParent(parentElk);
|
elkNode.setParent(parentElk);
|
||||||
|
|
||||||
if (isCompound) {
|
if (isCompound && rn.getType() == NodeType.DO_TRY) {
|
||||||
|
// DO_TRY: vertical container with a virtual _TRY_BODY wrapper for the try body
|
||||||
|
// and DO_CATCH/DO_FINALLY as separate children below
|
||||||
|
doTryNodeIds.add(rn.getId());
|
||||||
|
compoundNodeIds.add(rn.getId());
|
||||||
|
elkNode.setWidth(200);
|
||||||
|
elkNode.setHeight(100);
|
||||||
|
elkNode.setProperty(CoreOptions.ALGORITHM, "org.eclipse.elk.layered");
|
||||||
|
elkNode.setProperty(CoreOptions.DIRECTION, Direction.DOWN);
|
||||||
|
elkNode.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING * 0.6);
|
||||||
|
elkNode.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING * 0.5);
|
||||||
|
elkNode.setProperty(CoreOptions.PADDING,
|
||||||
|
new org.eclipse.elk.core.math.ElkPadding(COMPOUND_TOP_PADDING,
|
||||||
|
COMPOUND_SIDE_PADDING, COMPOUND_SIDE_PADDING, COMPOUND_SIDE_PADDING));
|
||||||
|
|
||||||
|
// Separate try body children from handler children
|
||||||
|
List<RouteNode> tryBodyChildren = new ArrayList<>();
|
||||||
|
List<RouteNode> handlerChildren = new ArrayList<>();
|
||||||
|
for (RouteNode child : rn.getChildren()) {
|
||||||
|
if (child.getType() == NodeType.DO_CATCH || child.getType() == NodeType.DO_FINALLY) {
|
||||||
|
handlerChildren.add(child);
|
||||||
|
} else {
|
||||||
|
tryBodyChildren.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Virtual _TRY_BODY wrapper with LR direction for horizontal try body chain
|
||||||
|
if (!tryBodyChildren.isEmpty()) {
|
||||||
|
String wrapperId = rn.getId() + "._try_body";
|
||||||
|
ElkNode wrapper = factory.createElkNode();
|
||||||
|
wrapper.setIdentifier(wrapperId);
|
||||||
|
wrapper.setParent(elkNode);
|
||||||
|
wrapper.setWidth(200);
|
||||||
|
wrapper.setHeight(40);
|
||||||
|
wrapper.setProperty(CoreOptions.ALGORITHM, "org.eclipse.elk.layered");
|
||||||
|
wrapper.setProperty(CoreOptions.DIRECTION, Direction.RIGHT);
|
||||||
|
wrapper.setProperty(CoreOptions.SPACING_NODE_NODE, NODE_SPACING * 0.5);
|
||||||
|
wrapper.setProperty(CoreOptions.SPACING_EDGE_NODE, EDGE_SPACING * 0.5);
|
||||||
|
wrapper.setProperty(CoreOptions.PADDING,
|
||||||
|
new org.eclipse.elk.core.math.ElkPadding(8, 8, 8, 8));
|
||||||
|
compoundNodeIds.add(wrapperId);
|
||||||
|
elkNodeMap.put(wrapperId, wrapper);
|
||||||
|
|
||||||
|
for (RouteNode child : tryBodyChildren) {
|
||||||
|
childNodeIds.add(child.getId());
|
||||||
|
createElkNodeRecursive(child, wrapper, factory, elkNodeMap, nodeColors,
|
||||||
|
compoundNodeIds, childNodeIds, doTryNodeIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handler children are direct children of DO_TRY (stacked below)
|
||||||
|
for (RouteNode child : handlerChildren) {
|
||||||
|
childNodeIds.add(child.getId());
|
||||||
|
createElkNodeRecursive(child, elkNode, factory, elkNodeMap, nodeColors,
|
||||||
|
compoundNodeIds, childNodeIds, doTryNodeIds);
|
||||||
|
}
|
||||||
|
} else if (isCompound) {
|
||||||
compoundNodeIds.add(rn.getId());
|
compoundNodeIds.add(rn.getId());
|
||||||
elkNode.setWidth(200);
|
elkNode.setWidth(200);
|
||||||
elkNode.setHeight(100);
|
elkNode.setHeight(100);
|
||||||
@@ -557,7 +611,7 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
for (RouteNode child : rn.getChildren()) {
|
for (RouteNode child : rn.getChildren()) {
|
||||||
childNodeIds.add(child.getId());
|
childNodeIds.add(child.getId());
|
||||||
createElkNodeRecursive(child, elkNode, factory, elkNodeMap, nodeColors,
|
createElkNodeRecursive(child, elkNode, factory, elkNodeMap, nodeColors,
|
||||||
compoundNodeIds, childNodeIds);
|
compoundNodeIds, childNodeIds, doTryNodeIds);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
elkNode.setWidth(NODE_WIDTH);
|
elkNode.setWidth(NODE_WIDTH);
|
||||||
@@ -583,11 +637,47 @@ public class ElkDiagramRenderer implements DiagramRenderer {
|
|||||||
List<PositionedNode> children = List.of();
|
List<PositionedNode> children = List.of();
|
||||||
if (compoundNodeIds.contains(rn.getId()) && rn.getChildren() != null) {
|
if (compoundNodeIds.contains(rn.getId()) && rn.getChildren() != null) {
|
||||||
children = new ArrayList<>();
|
children = new ArrayList<>();
|
||||||
for (RouteNode child : rn.getChildren()) {
|
|
||||||
ElkNode childElk = elkNodeMap.get(child.getId());
|
if (rn.getType() == NodeType.DO_TRY) {
|
||||||
if (childElk != null) {
|
// DO_TRY: extract virtual _TRY_BODY wrapper first, then handler children
|
||||||
children.add(extractPositionedNode(child, childElk, elkNodeMap,
|
String wrapperId = rn.getId() + "._try_body";
|
||||||
compoundNodeIds, compoundInfos, rootNode));
|
ElkNode wrapperElk = elkNodeMap.get(wrapperId);
|
||||||
|
if (wrapperElk != null) {
|
||||||
|
List<PositionedNode> wrapperChildren = new ArrayList<>();
|
||||||
|
for (RouteNode child : rn.getChildren()) {
|
||||||
|
if (child.getType() != NodeType.DO_CATCH && child.getType() != NodeType.DO_FINALLY) {
|
||||||
|
ElkNode childElk = elkNodeMap.get(child.getId());
|
||||||
|
if (childElk != null) {
|
||||||
|
wrapperChildren.add(extractPositionedNode(child, childElk, elkNodeMap,
|
||||||
|
compoundNodeIds, compoundInfos, rootNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
children.add(new PositionedNode(
|
||||||
|
wrapperId, "", "_TRY_BODY",
|
||||||
|
getAbsoluteX(wrapperElk, rootNode),
|
||||||
|
getAbsoluteY(wrapperElk, rootNode),
|
||||||
|
wrapperElk.getWidth(), wrapperElk.getHeight(),
|
||||||
|
wrapperChildren));
|
||||||
|
compoundInfos.put(wrapperId, new CompoundInfo(wrapperId, Color.WHITE));
|
||||||
|
}
|
||||||
|
// Handler children (DO_CATCH, DO_FINALLY)
|
||||||
|
for (RouteNode child : rn.getChildren()) {
|
||||||
|
if (child.getType() == NodeType.DO_CATCH || child.getType() == NodeType.DO_FINALLY) {
|
||||||
|
ElkNode childElk = elkNodeMap.get(child.getId());
|
||||||
|
if (childElk != null) {
|
||||||
|
children.add(extractPositionedNode(child, childElk, elkNodeMap,
|
||||||
|
compoundNodeIds, compoundInfos, rootNode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (RouteNode child : rn.getChildren()) {
|
||||||
|
ElkNode childElk = elkNodeMap.get(child.getId());
|
||||||
|
if (childElk != null) {
|
||||||
|
children.add(extractPositionedNode(child, childElk, elkNodeMap,
|
||||||
|
compoundNodeIds, compoundInfos, rootNode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compoundInfos.put(rn.getId(), new CompoundInfo(rn.getId(), colorForType(rn.getType())));
|
compoundInfos.put(rn.getId(), new CompoundInfo(rn.getId(), colorForType(rn.getType())));
|
||||||
|
|||||||
@@ -59,6 +59,47 @@ export function CompoundNode({
|
|||||||
e => descendantIds.has(e.sourceId) && descendantIds.has(e.targetId),
|
e => descendantIds.has(e.sourceId) && descendantIds.has(e.targetId),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const childProps = {
|
||||||
|
edges, selectedNodeId, hoveredNodeId, nodeConfigs, executionOverlay,
|
||||||
|
overlayActive, iterationState, onIterationChange,
|
||||||
|
onNodeClick, onNodeDoubleClick, onNodeEnter, onNodeLeave,
|
||||||
|
};
|
||||||
|
|
||||||
|
// _TRY_BODY: transparent wrapper — no header, no border, just layout
|
||||||
|
if (node.type === '_TRY_BODY') {
|
||||||
|
return (
|
||||||
|
<g transform={`translate(${x}, ${y})`}>
|
||||||
|
{renderInternalEdges(internalEdges, absX, absY, executionOverlay)}
|
||||||
|
{renderChildren(node, absX, absY, childProps)}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// DO_CATCH / DO_FINALLY: section-like styling (tinted bg, thin border, label)
|
||||||
|
if (node.type === 'DO_CATCH' || node.type === 'DO_FINALLY') {
|
||||||
|
const sectionLabel = node.type === 'DO_CATCH'
|
||||||
|
? (node.label ? `catch: ${node.label}` : 'catch')
|
||||||
|
: (node.label ? `finally: ${node.label}` : 'finally');
|
||||||
|
|
||||||
|
return (
|
||||||
|
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
||||||
|
{/* Tinted background */}
|
||||||
|
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||||
|
fill={color} fillOpacity={0.06} />
|
||||||
|
{/* Border */}
|
||||||
|
<rect x={0} y={0} width={w} height={h} rx={CORNER_RADIUS}
|
||||||
|
fill="none" stroke={color} strokeWidth={1} strokeOpacity={0.4} />
|
||||||
|
{/* Section label */}
|
||||||
|
<text x={8} y={12} fill={color} fontSize={10} fontWeight={600}>
|
||||||
|
{sectionLabel}
|
||||||
|
</text>
|
||||||
|
{renderInternalEdges(internalEdges, absX, absY, executionOverlay)}
|
||||||
|
{renderChildren(node, absX, absY, childProps)}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default compound rendering (DO_TRY, EIP_CHOICE, etc.)
|
||||||
return (
|
return (
|
||||||
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
<g data-node-id={node.id} transform={`translate(${x}, ${y})`}>
|
||||||
{/* Container body */}
|
{/* Container body */}
|
||||||
@@ -110,46 +151,56 @@ export function CompoundNode({
|
|||||||
</foreignObject>
|
</foreignObject>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Internal edges (rendered after background, before children) */}
|
{renderInternalEdges(internalEdges, absX, absY, executionOverlay)}
|
||||||
<g className="edges">
|
{renderChildren(node, absX, absY, childProps)}
|
||||||
{internalEdges.map((edge, i) => {
|
</g>
|
||||||
const isTraversed = executionOverlay
|
);
|
||||||
? (executionOverlay.has(edge.sourceId) && executionOverlay.has(edge.targetId))
|
}
|
||||||
: undefined;
|
|
||||||
return (
|
|
||||||
<DiagramEdge
|
|
||||||
key={`${edge.sourceId}-${edge.targetId}-${i}`}
|
|
||||||
edge={{
|
|
||||||
...edge,
|
|
||||||
points: edge.points.map(p => [p[0] - absX, p[1] - absY]),
|
|
||||||
}}
|
|
||||||
traversed={isTraversed}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</g>
|
|
||||||
|
|
||||||
{/* Children — recurse into compound children, render leaves as DiagramNode */}
|
/** Render internal edges adjusted for compound coordinates */
|
||||||
|
function renderInternalEdges(
|
||||||
|
internalEdges: DiagramEdgeType[],
|
||||||
|
absX: number, absY: number,
|
||||||
|
executionOverlay?: Map<string, NodeExecutionState>,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<g className="edges">
|
||||||
|
{internalEdges.map((edge, i) => {
|
||||||
|
const isTraversed = executionOverlay
|
||||||
|
? (executionOverlay.has(edge.sourceId) && executionOverlay.has(edge.targetId))
|
||||||
|
: undefined;
|
||||||
|
return (
|
||||||
|
<DiagramEdge
|
||||||
|
key={`${edge.sourceId}-${edge.targetId}-${i}`}
|
||||||
|
edge={{
|
||||||
|
...edge,
|
||||||
|
points: edge.points.map(p => [p[0] - absX, p[1] - absY]),
|
||||||
|
}}
|
||||||
|
traversed={isTraversed}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Render children — compounds recurse, leaves become DiagramNode */
|
||||||
|
function renderChildren(
|
||||||
|
node: DiagramNodeType,
|
||||||
|
absX: number, absY: number,
|
||||||
|
props: Omit<CompoundNodeProps, 'node' | 'parentX' | 'parentY'>,
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
{node.children?.map(child => {
|
{node.children?.map(child => {
|
||||||
if (isCompoundType(child.type) && child.children && child.children.length > 0) {
|
if (isCompoundType(child.type) && child.children && child.children.length > 0) {
|
||||||
return (
|
return (
|
||||||
<CompoundNode
|
<CompoundNode
|
||||||
key={child.id}
|
key={child.id}
|
||||||
node={child}
|
node={child}
|
||||||
edges={edges}
|
|
||||||
parentX={absX}
|
parentX={absX}
|
||||||
parentY={absY}
|
parentY={absY}
|
||||||
selectedNodeId={selectedNodeId}
|
{...props}
|
||||||
hoveredNodeId={hoveredNodeId}
|
|
||||||
nodeConfigs={nodeConfigs}
|
|
||||||
executionOverlay={executionOverlay}
|
|
||||||
overlayActive={overlayActive}
|
|
||||||
iterationState={iterationState}
|
|
||||||
onIterationChange={onIterationChange}
|
|
||||||
onNodeClick={onNodeClick}
|
|
||||||
onNodeDoubleClick={onNodeDoubleClick}
|
|
||||||
onNodeEnter={onNodeEnter}
|
|
||||||
onNodeLeave={onNodeLeave}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -161,19 +212,19 @@ export function CompoundNode({
|
|||||||
x: (child.x ?? 0) - absX,
|
x: (child.x ?? 0) - absX,
|
||||||
y: (child.y ?? 0) - absY,
|
y: (child.y ?? 0) - absY,
|
||||||
}}
|
}}
|
||||||
isHovered={hoveredNodeId === child.id}
|
isHovered={props.hoveredNodeId === child.id}
|
||||||
isSelected={selectedNodeId === child.id}
|
isSelected={props.selectedNodeId === child.id}
|
||||||
config={child.id ? nodeConfigs?.get(child.id) : undefined}
|
config={child.id ? props.nodeConfigs?.get(child.id) : undefined}
|
||||||
executionState={executionOverlay?.get(child.id ?? '')}
|
executionState={props.executionOverlay?.get(child.id ?? '')}
|
||||||
overlayActive={overlayActive}
|
overlayActive={props.overlayActive}
|
||||||
onClick={() => child.id && onNodeClick(child.id)}
|
onClick={() => child.id && props.onNodeClick(child.id)}
|
||||||
onDoubleClick={() => child.id && onNodeDoubleClick?.(child.id)}
|
onDoubleClick={() => child.id && props.onNodeDoubleClick?.(child.id)}
|
||||||
onMouseEnter={() => child.id && onNodeEnter(child.id)}
|
onMouseEnter={() => child.id && props.onNodeEnter(child.id)}
|
||||||
onMouseLeave={onNodeLeave}
|
onMouseLeave={props.onNodeLeave}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</g>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const TYPE_MAP: Record<string, string> = {
|
|||||||
TRY_CATCH: ERROR_COLOR,
|
TRY_CATCH: ERROR_COLOR,
|
||||||
DO_TRY: ERROR_COLOR,
|
DO_TRY: ERROR_COLOR,
|
||||||
DO_CATCH: ERROR_COLOR,
|
DO_CATCH: ERROR_COLOR,
|
||||||
DO_FINALLY: ERROR_COLOR,
|
DO_FINALLY: '#1A7F8E', // teal — completion handler, not error
|
||||||
|
|
||||||
ON_COMPLETION: '#1A7F8E', // --running (teal, lifecycle handler)
|
ON_COMPLETION: '#1A7F8E', // --running (teal, lifecycle handler)
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ const TYPE_MAP: Record<string, string> = {
|
|||||||
const COMPOUND_TYPES = new Set([
|
const COMPOUND_TYPES = new Set([
|
||||||
'EIP_CHOICE', 'EIP_WHEN', 'EIP_OTHERWISE',
|
'EIP_CHOICE', 'EIP_WHEN', 'EIP_OTHERWISE',
|
||||||
'EIP_SPLIT', 'TRY_CATCH',
|
'EIP_SPLIT', 'TRY_CATCH',
|
||||||
'DO_TRY', 'DO_CATCH', 'DO_FINALLY',
|
'DO_TRY', 'DO_CATCH', 'DO_FINALLY', '_TRY_BODY',
|
||||||
'EIP_LOOP', 'EIP_MULTICAST', 'EIP_AGGREGATE',
|
'EIP_LOOP', 'EIP_MULTICAST', 'EIP_AGGREGATE',
|
||||||
'ON_EXCEPTION', 'ERROR_HANDLER',
|
'ON_EXCEPTION', 'ERROR_HANDLER',
|
||||||
'ON_COMPLETION',
|
'ON_COMPLETION',
|
||||||
|
|||||||
Reference in New Issue
Block a user