footprint-explainable-ui 0.25.0 → 0.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flowchart.cjs +301 -120
- package/dist/flowchart.cjs.map +1 -1
- package/dist/flowchart.d.cts +87 -13
- package/dist/flowchart.d.ts +87 -13
- package/dist/flowchart.js +238 -57
- package/dist/flowchart.js.map +1 -1
- package/dist/index.cjs +326 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -16
- package/dist/index.d.ts +15 -16
- package/dist/index.js +255 -11
- package/dist/index.js.map +1 -1
- package/package.json +31 -12
package/dist/index.cjs
CHANGED
|
@@ -2280,7 +2280,7 @@ function TimeTravelControls({
|
|
|
2280
2280
|
}
|
|
2281
2281
|
|
|
2282
2282
|
// src/components/ExplainableShell/ExplainableShell.tsx
|
|
2283
|
-
var
|
|
2283
|
+
var import_react31 = require("react");
|
|
2284
2284
|
|
|
2285
2285
|
// src/utils/narrativeSync.ts
|
|
2286
2286
|
function buildEntryRangeIndex(entries) {
|
|
@@ -3403,8 +3403,8 @@ var SubflowBreadcrumb = (0, import_react14.memo)(function SubflowBreadcrumb2({
|
|
|
3403
3403
|
});
|
|
3404
3404
|
|
|
3405
3405
|
// src/components/FlowchartView/TracedFlow.tsx
|
|
3406
|
-
var
|
|
3407
|
-
var
|
|
3406
|
+
var import_react25 = require("react");
|
|
3407
|
+
var import_react26 = require("@xyflow/react");
|
|
3408
3408
|
|
|
3409
3409
|
// src/components/FlowchartView/_internal/dagreTraceLayout.ts
|
|
3410
3410
|
var import_dagre = __toESM(require("dagre"), 1);
|
|
@@ -3516,6 +3516,163 @@ function dagreTraceLayout(graph, options = {}) {
|
|
|
3516
3516
|
});
|
|
3517
3517
|
return { nodes: positioned, edges: graph.edges };
|
|
3518
3518
|
}
|
|
3519
|
+
function createDagreTraceLayout(options = {}) {
|
|
3520
|
+
return (graph) => dagreTraceLayout(graph, options);
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
// src/components/FlowchartView/_internal/devWarn.ts
|
|
3524
|
+
function isDevModeEnv() {
|
|
3525
|
+
const proc = globalThis.process;
|
|
3526
|
+
return proc?.env?.NODE_ENV !== "production";
|
|
3527
|
+
}
|
|
3528
|
+
function devWarn(messageFn, ...extras) {
|
|
3529
|
+
if (!isDevModeEnv()) return;
|
|
3530
|
+
console.warn(messageFn(), ...extras);
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
// src/components/FlowchartView/_internal/snapLinearSuccessors.ts
|
|
3534
|
+
function snapLinearSuccessors(graph, options = {}) {
|
|
3535
|
+
if (graph.nodes.length === 0) return graph;
|
|
3536
|
+
const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W;
|
|
3537
|
+
const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H;
|
|
3538
|
+
const byId = /* @__PURE__ */ new Map();
|
|
3539
|
+
const width = /* @__PURE__ */ new Map();
|
|
3540
|
+
for (const n of graph.nodes) {
|
|
3541
|
+
byId.set(n.id, n);
|
|
3542
|
+
width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
|
|
3543
|
+
}
|
|
3544
|
+
const preds = /* @__PURE__ */ new Map();
|
|
3545
|
+
const outDegree = /* @__PURE__ */ new Map();
|
|
3546
|
+
const seenEdge = /* @__PURE__ */ new Set();
|
|
3547
|
+
for (const e of graph.edges) {
|
|
3548
|
+
if (e.data?.kind === "loop") continue;
|
|
3549
|
+
if (!byId.has(e.source) || !byId.has(e.target)) continue;
|
|
3550
|
+
const key = `${e.source}\0${e.target}`;
|
|
3551
|
+
if (seenEdge.has(key)) continue;
|
|
3552
|
+
seenEdge.add(key);
|
|
3553
|
+
const list = preds.get(e.target);
|
|
3554
|
+
if (list) list.push(e.source);
|
|
3555
|
+
else preds.set(e.target, [e.source]);
|
|
3556
|
+
outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
|
|
3557
|
+
}
|
|
3558
|
+
const workingX = /* @__PURE__ */ new Map();
|
|
3559
|
+
for (const n of graph.nodes) workingX.set(n.id, n.position.x);
|
|
3560
|
+
const centerX = (id) => workingX.get(id) + width.get(id) / 2;
|
|
3561
|
+
const order = [...graph.nodes].sort(
|
|
3562
|
+
(a, b) => a.position.y - b.position.y || a.position.x - b.position.x || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
3563
|
+
);
|
|
3564
|
+
for (const n of order) {
|
|
3565
|
+
const p = preds.get(n.id);
|
|
3566
|
+
if (!p || p.length !== 1) continue;
|
|
3567
|
+
const pid = p[0];
|
|
3568
|
+
if ((outDegree.get(pid) ?? 0) !== 1) continue;
|
|
3569
|
+
const P = byId.get(pid);
|
|
3570
|
+
if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
|
|
3571
|
+
workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
|
|
3572
|
+
}
|
|
3573
|
+
const nodes = graph.nodes.map((n) => {
|
|
3574
|
+
const nx = workingX.get(n.id);
|
|
3575
|
+
return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
|
|
3576
|
+
});
|
|
3577
|
+
return { nodes, edges: graph.edges };
|
|
3578
|
+
}
|
|
3579
|
+
function createSnappedDagreLayout(base, options = {}) {
|
|
3580
|
+
return (graph) => snapLinearSuccessors(base(graph), options);
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
// src/components/FlowchartView/_internal/centerForkParents.ts
|
|
3584
|
+
function centerForkParents(graph, options = {}) {
|
|
3585
|
+
if (graph.nodes.length === 0) return graph;
|
|
3586
|
+
const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W;
|
|
3587
|
+
const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H;
|
|
3588
|
+
const byId = /* @__PURE__ */ new Map();
|
|
3589
|
+
const width = /* @__PURE__ */ new Map();
|
|
3590
|
+
for (const n of graph.nodes) {
|
|
3591
|
+
byId.set(n.id, n);
|
|
3592
|
+
width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
|
|
3593
|
+
}
|
|
3594
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
3595
|
+
const predsOf = /* @__PURE__ */ new Map();
|
|
3596
|
+
const outDegree = /* @__PURE__ */ new Map();
|
|
3597
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
3598
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3599
|
+
for (const e of graph.edges) {
|
|
3600
|
+
if (e.data?.kind === "loop") continue;
|
|
3601
|
+
if (!byId.has(e.source) || !byId.has(e.target)) continue;
|
|
3602
|
+
const key = `${e.source} ${e.target}`;
|
|
3603
|
+
if (seen.has(key)) continue;
|
|
3604
|
+
seen.add(key);
|
|
3605
|
+
const cl = childrenOf.get(e.source);
|
|
3606
|
+
if (cl) cl.push(e.target);
|
|
3607
|
+
else childrenOf.set(e.source, [e.target]);
|
|
3608
|
+
const pl = predsOf.get(e.target);
|
|
3609
|
+
if (pl) pl.push(e.source);
|
|
3610
|
+
else predsOf.set(e.target, [e.source]);
|
|
3611
|
+
outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
|
|
3612
|
+
inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
|
|
3613
|
+
}
|
|
3614
|
+
const workingX = /* @__PURE__ */ new Map();
|
|
3615
|
+
for (const n of graph.nodes) workingX.set(n.id, n.position.x);
|
|
3616
|
+
const centerX = (id) => workingX.get(id) + width.get(id) / 2;
|
|
3617
|
+
const nodeSep = options.nodeSep ?? 60;
|
|
3618
|
+
const clampX = (id, desiredX) => {
|
|
3619
|
+
const w = width.get(id);
|
|
3620
|
+
const x0 = workingX.get(id);
|
|
3621
|
+
const self = byId.get(id);
|
|
3622
|
+
let minX = -Infinity;
|
|
3623
|
+
let maxX = Infinity;
|
|
3624
|
+
for (const m of graph.nodes) {
|
|
3625
|
+
if (m.id === id || m.parentId !== self.parentId) continue;
|
|
3626
|
+
if (Math.abs(m.position.y - self.position.y) > 1) continue;
|
|
3627
|
+
const mLeft = workingX.get(m.id);
|
|
3628
|
+
const mRight = mLeft + width.get(m.id);
|
|
3629
|
+
if (mRight <= x0) minX = Math.max(minX, mRight + nodeSep);
|
|
3630
|
+
else if (mLeft >= x0 + w) maxX = Math.min(maxX, mLeft - nodeSep - w);
|
|
3631
|
+
}
|
|
3632
|
+
return minX <= maxX ? Math.max(minX, Math.min(maxX, desiredX)) : x0;
|
|
3633
|
+
};
|
|
3634
|
+
const order = [...graph.nodes].sort(
|
|
3635
|
+
(a, b) => b.position.y - a.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id)
|
|
3636
|
+
);
|
|
3637
|
+
for (const n of order) {
|
|
3638
|
+
const outD = outDegree.get(n.id) ?? 0;
|
|
3639
|
+
const inD = inDegree.get(n.id) ?? 0;
|
|
3640
|
+
const isFork = outD >= 2 && inD <= 1;
|
|
3641
|
+
const isMerge = inD >= 2 && outD <= 1;
|
|
3642
|
+
if (!isFork && !isMerge) continue;
|
|
3643
|
+
const kin = ((isFork ? childrenOf.get(n.id) : predsOf.get(n.id)) ?? []).filter(
|
|
3644
|
+
(k) => byId.get(k)?.parentId === n.parentId
|
|
3645
|
+
// same compound only
|
|
3646
|
+
);
|
|
3647
|
+
if (kin.length < 2) continue;
|
|
3648
|
+
const centers = kin.map(centerX);
|
|
3649
|
+
const wN = width.get(n.id);
|
|
3650
|
+
const span = (Math.min(...centers) + Math.max(...centers)) / 2;
|
|
3651
|
+
workingX.set(n.id, clampX(n.id, span - wN / 2));
|
|
3652
|
+
const stepOf = isFork ? predsOf : childrenOf;
|
|
3653
|
+
let curId = n.id;
|
|
3654
|
+
const walked = /* @__PURE__ */ new Set([curId]);
|
|
3655
|
+
for (; ; ) {
|
|
3656
|
+
const nexts = stepOf.get(curId);
|
|
3657
|
+
if (!nexts || nexts.length !== 1) break;
|
|
3658
|
+
const m = nexts[0];
|
|
3659
|
+
if (walked.has(m)) break;
|
|
3660
|
+
if ((outDegree.get(m) ?? 0) > 1) break;
|
|
3661
|
+
if ((inDegree.get(m) ?? 0) > 1) break;
|
|
3662
|
+
if (byId.get(m)?.parentId !== byId.get(curId)?.parentId) break;
|
|
3663
|
+
workingX.set(m, clampX(m, centerX(curId) - width.get(m) / 2));
|
|
3664
|
+
walked.add(m);
|
|
3665
|
+
curId = m;
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
const nodes = graph.nodes.map(
|
|
3669
|
+
(n) => workingX.get(n.id) === n.position.x ? n : { ...n, position: { x: workingX.get(n.id), y: n.position.y } }
|
|
3670
|
+
);
|
|
3671
|
+
return { nodes, edges: graph.edges };
|
|
3672
|
+
}
|
|
3673
|
+
function withForkCentering(base, options = {}) {
|
|
3674
|
+
return (graph) => centerForkParents(base(graph), options);
|
|
3675
|
+
}
|
|
3519
3676
|
|
|
3520
3677
|
// src/components/FlowchartView/createTraceRuntimeOverlay.ts
|
|
3521
3678
|
function sliceOverlay(overlay, index) {
|
|
@@ -3955,7 +4112,7 @@ var StageNode = (0, import_react15.memo)(function StageNode2({
|
|
|
3955
4112
|
background: bg,
|
|
3956
4113
|
border: `${isHero ? "2.5px" : isMuted ? "1px" : "2px"} ${isLazyUnresolved ? "dashed" : "solid"} ${borderColor}`,
|
|
3957
4114
|
borderRadius: theme.radius,
|
|
3958
|
-
padding: description ? `${Math.round(
|
|
4115
|
+
padding: description ? `${Math.round(6 * sizeScale)}px ${Math.round(12 * sizeScale)}px` : `${Math.round(7 * sizeScale)}px ${Math.round(14 * sizeScale)}px`,
|
|
3959
4116
|
display: "flex",
|
|
3960
4117
|
flexDirection: "column",
|
|
3961
4118
|
alignItems: "center",
|
|
@@ -4576,6 +4733,14 @@ function staggeredBendY(sourceBottom, targetTop, others, minGapFromTarget = 8) {
|
|
|
4576
4733
|
if (lowestSkippedBottom === -Infinity) return null;
|
|
4577
4734
|
return Math.min((lowestSkippedBottom + targetTop) / 2, targetTop - minGapFromTarget);
|
|
4578
4735
|
}
|
|
4736
|
+
function forkFanBendY(sourceBottom, childTops, minGapFromTarget = 8) {
|
|
4737
|
+
if (childTops.length < 2) return null;
|
|
4738
|
+
const nearestTop = Math.min(...childTops);
|
|
4739
|
+
return Math.min((sourceBottom + nearestTop) / 2, nearestTop - minGapFromTarget);
|
|
4740
|
+
}
|
|
4741
|
+
function resolveStepBendY(forkBend, staggeredBend) {
|
|
4742
|
+
return staggeredBend ?? forkBend;
|
|
4743
|
+
}
|
|
4579
4744
|
|
|
4580
4745
|
// src/components/SmartStepEdge/SmartStepEdge.tsx
|
|
4581
4746
|
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
@@ -4598,6 +4763,16 @@ function SmartStepEdge({
|
|
|
4598
4763
|
if (!src || !tgt) return null;
|
|
4599
4764
|
const sourceBottom = src.internals.positionAbsolute.y + (src.measured.height ?? 0);
|
|
4600
4765
|
const targetTop = tgt.internals.positionAbsolute.y;
|
|
4766
|
+
const childTops = [];
|
|
4767
|
+
for (const e of s.edges) {
|
|
4768
|
+
if (e.source !== source) continue;
|
|
4769
|
+
if (e.data?.kind === "loop") continue;
|
|
4770
|
+
const c = s.nodeLookup.get(e.target);
|
|
4771
|
+
if (c && c.type !== GROUP_CONTAINER_NODE_TYPE) {
|
|
4772
|
+
childTops.push(c.internals.positionAbsolute.y);
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
const fan = forkFanBendY(sourceBottom, childTops);
|
|
4601
4776
|
const others = [];
|
|
4602
4777
|
for (const n of s.nodeLookup.values()) {
|
|
4603
4778
|
if (n.id === source || n.id === target) continue;
|
|
@@ -4605,7 +4780,8 @@ function SmartStepEdge({
|
|
|
4605
4780
|
const top = n.internals.positionAbsolute.y;
|
|
4606
4781
|
others.push({ top, bottom: top + (n.measured.height ?? 0) });
|
|
4607
4782
|
}
|
|
4608
|
-
|
|
4783
|
+
const staggered = staggeredBendY(sourceBottom, targetTop, others);
|
|
4784
|
+
return resolveStepBendY(fan, staggered);
|
|
4609
4785
|
});
|
|
4610
4786
|
const [path] = (0, import_react21.getSmoothStepPath)({
|
|
4611
4787
|
sourceX,
|
|
@@ -4621,6 +4797,49 @@ function SmartStepEdge({
|
|
|
4621
4797
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react21.BaseEdge, { id, path, markerEnd, style });
|
|
4622
4798
|
}
|
|
4623
4799
|
|
|
4800
|
+
// src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
|
|
4801
|
+
var import_react23 = require("react");
|
|
4802
|
+
var import_react24 = require("@xyflow/react");
|
|
4803
|
+
|
|
4804
|
+
// src/components/FlowchartView/_internal/measuredFootprints.ts
|
|
4805
|
+
function extractMeasuredFootprints(entries) {
|
|
4806
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
4807
|
+
for (const [id, node] of entries) {
|
|
4808
|
+
const width = node.measured?.width;
|
|
4809
|
+
const height = node.measured?.height;
|
|
4810
|
+
if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
|
|
4811
|
+
sizes.set(id, { width: Math.round(width), height: Math.round(height) });
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
return sizes;
|
|
4815
|
+
}
|
|
4816
|
+
function sameFootprints(a, b) {
|
|
4817
|
+
if (a === b) return true;
|
|
4818
|
+
if (a.size !== b.size) return false;
|
|
4819
|
+
for (const [id, s] of a) {
|
|
4820
|
+
const t = b.get(id);
|
|
4821
|
+
if (!t || t.width !== s.width || t.height !== s.height) return false;
|
|
4822
|
+
}
|
|
4823
|
+
return true;
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
// src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
|
|
4827
|
+
function MeasuredNodeSizes({
|
|
4828
|
+
onSizes,
|
|
4829
|
+
includeHiddenNodes = false
|
|
4830
|
+
}) {
|
|
4831
|
+
const initialized = (0, import_react24.useNodesInitialized)({ includeHiddenNodes });
|
|
4832
|
+
const sizes = (0, import_react24.useStore)(
|
|
4833
|
+
(s) => extractMeasuredFootprints(s.nodeLookup),
|
|
4834
|
+
sameFootprints
|
|
4835
|
+
);
|
|
4836
|
+
(0, import_react23.useEffect)(() => {
|
|
4837
|
+
if (!initialized || sizes.size === 0) return;
|
|
4838
|
+
onSizes(sizes);
|
|
4839
|
+
}, [initialized, sizes, onSizes]);
|
|
4840
|
+
return null;
|
|
4841
|
+
}
|
|
4842
|
+
|
|
4624
4843
|
// src/components/FlowchartView/TracedFlow.tsx
|
|
4625
4844
|
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
4626
4845
|
var DEFAULT_COLORS = {
|
|
@@ -4730,7 +4949,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
|
|
|
4730
4949
|
type: kind === "loop" ? "loopBack" : "smartStep",
|
|
4731
4950
|
animated: isLeadingEdge,
|
|
4732
4951
|
style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
|
|
4733
|
-
markerEnd: { type:
|
|
4952
|
+
markerEnd: { type: import_react26.MarkerType.ArrowClosed, color, width: 16, height: 16 }
|
|
4734
4953
|
};
|
|
4735
4954
|
if (kind === "loop") {
|
|
4736
4955
|
styled.style = { ...styled.style, strokeDasharray: "4 3" };
|
|
@@ -4760,21 +4979,28 @@ function TracedFlow({
|
|
|
4760
4979
|
style
|
|
4761
4980
|
}) {
|
|
4762
4981
|
const layout = layoutProp ?? dagreTraceLayout;
|
|
4763
|
-
|
|
4982
|
+
(0, import_react25.useEffect)(() => {
|
|
4983
|
+
if (layoutProp === dagreTraceLayout) {
|
|
4984
|
+
devWarn(
|
|
4985
|
+
() => "[footprint-explainable-ui] <TracedFlow layout={dagreTraceLayout}> bypasses the built-in measure-then-layout pipeline (content-exact sizing, fork/merge centering, straight spines). OMIT the `layout` prop to use it \u2014 passing the raw dagreTraceLayout silently forfeits every layout improvement eui ships."
|
|
4986
|
+
);
|
|
4987
|
+
}
|
|
4988
|
+
}, [layoutProp]);
|
|
4989
|
+
const colors = (0, import_react25.useMemo)(
|
|
4764
4990
|
() => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
|
|
4765
4991
|
[colorOverrides]
|
|
4766
4992
|
);
|
|
4767
|
-
const mergedNodeTypes = (0,
|
|
4993
|
+
const mergedNodeTypes = (0, import_react25.useMemo)(
|
|
4768
4994
|
() => userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES,
|
|
4769
4995
|
[userNodeTypes]
|
|
4770
4996
|
);
|
|
4771
|
-
const mergedEdgeTypes = (0,
|
|
4997
|
+
const mergedEdgeTypes = (0, import_react25.useMemo)(
|
|
4772
4998
|
() => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES,
|
|
4773
4999
|
[userEdgeTypes]
|
|
4774
5000
|
);
|
|
4775
5001
|
const drill = useSubflowDrill(graph, onSubflowChange);
|
|
4776
|
-
const groupedSet = (0,
|
|
4777
|
-
const filteredGraph = (0,
|
|
5002
|
+
const groupedSet = (0, import_react25.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
|
|
5003
|
+
const filteredGraph = (0, import_react25.useMemo)(() => {
|
|
4778
5004
|
const base = filterGraphForDrill(graph, drill.currentSubflowId);
|
|
4779
5005
|
if (groupedSet.size === 0) return base;
|
|
4780
5006
|
const baseIds = new Set(base.nodes.map((n) => n.id));
|
|
@@ -4789,12 +5015,23 @@ function TracedFlow({
|
|
|
4789
5015
|
);
|
|
4790
5016
|
return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
|
|
4791
5017
|
}, [graph, drill.currentSubflowId, groupedSet]);
|
|
4792
|
-
const breadcrumb = (0,
|
|
5018
|
+
const breadcrumb = (0, import_react25.useMemo)(
|
|
4793
5019
|
() => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
|
|
4794
5020
|
[graph, drill.currentSubflowId]
|
|
4795
5021
|
);
|
|
4796
|
-
const
|
|
4797
|
-
|
|
5022
|
+
const [measuredSizes, setMeasuredSizes] = (0, import_react25.useState)(null);
|
|
5023
|
+
const positioned = (0, import_react25.useMemo)(() => {
|
|
5024
|
+
const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
|
|
5025
|
+
const sizeOpts = nodeSize ? { nodeSize } : {};
|
|
5026
|
+
const dagreBase = withForkCentering(
|
|
5027
|
+
createSnappedDagreLayout(
|
|
5028
|
+
createDagreTraceLayout({ ...sizeOpts, rankSep: 52, nodeSep: 36 }),
|
|
5029
|
+
sizeOpts
|
|
5030
|
+
),
|
|
5031
|
+
{ ...sizeOpts, nodeSep: 36 }
|
|
5032
|
+
// same nodeSep → clamp preserves dagre's reserved gap
|
|
5033
|
+
);
|
|
5034
|
+
const realBase = layout === "passthrough" ? (g) => g : layoutProp === void 0 ? dagreBase : layout;
|
|
4798
5035
|
if (groupedSet.size > 0) {
|
|
4799
5036
|
const grouped = applyGroupLayout(filteredGraph, {
|
|
4800
5037
|
groupedSubflowIds: [...groupedSet],
|
|
@@ -4805,9 +5042,9 @@ function TracedFlow({
|
|
|
4805
5042
|
if (mainChartBox) {
|
|
4806
5043
|
return wrapInMainChartBox(filteredGraph, { baseLayout: realBase, ...mainChartBox });
|
|
4807
5044
|
}
|
|
4808
|
-
return
|
|
4809
|
-
}, [filteredGraph, layout, groupedSet, mainChartBox]);
|
|
4810
|
-
const slice = (0,
|
|
5045
|
+
return realBase(filteredGraph);
|
|
5046
|
+
}, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
|
|
5047
|
+
const slice = (0, import_react25.useMemo)(() => {
|
|
4811
5048
|
const empty = {
|
|
4812
5049
|
doneStageIds: /* @__PURE__ */ new Set(),
|
|
4813
5050
|
activeStageId: null,
|
|
@@ -4819,7 +5056,7 @@ function TracedFlow({
|
|
|
4819
5056
|
const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
|
|
4820
5057
|
return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
|
|
4821
5058
|
}, [overlay, scrubIndex, graph, drill.currentSubflowId]);
|
|
4822
|
-
const reactFlowNodes = (0,
|
|
5059
|
+
const reactFlowNodes = (0, import_react25.useMemo)(
|
|
4823
5060
|
() => positioned.nodes.map(
|
|
4824
5061
|
(n) => toStageNodeWithOverlay(
|
|
4825
5062
|
n,
|
|
@@ -4832,13 +5069,13 @@ function TracedFlow({
|
|
|
4832
5069
|
),
|
|
4833
5070
|
[positioned.nodes, slice, coActiveStageIds]
|
|
4834
5071
|
);
|
|
4835
|
-
const reactFlowEdges = (0,
|
|
5072
|
+
const reactFlowEdges = (0, import_react25.useMemo)(
|
|
4836
5073
|
() => positioned.edges.map(
|
|
4837
5074
|
(e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
|
|
4838
5075
|
),
|
|
4839
5076
|
[positioned.edges, slice, colors]
|
|
4840
5077
|
);
|
|
4841
|
-
const handleNodeClick = (0,
|
|
5078
|
+
const handleNodeClick = (0, import_react25.useCallback)(
|
|
4842
5079
|
(_, node) => {
|
|
4843
5080
|
const data = node.data ?? {};
|
|
4844
5081
|
if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
|
|
@@ -4848,9 +5085,13 @@ function TracedFlow({
|
|
|
4848
5085
|
},
|
|
4849
5086
|
[drill, onNodeClick, groupedSet]
|
|
4850
5087
|
);
|
|
4851
|
-
const wrapperRef = (0,
|
|
4852
|
-
const [rfInstance, setRfInstance] = (0,
|
|
4853
|
-
useChartAutoRefit(wrapperRef, rfInstance, {
|
|
5088
|
+
const wrapperRef = (0, import_react25.useRef)(null);
|
|
5089
|
+
const [rfInstance, setRfInstance] = (0, import_react25.useState)(null);
|
|
5090
|
+
useChartAutoRefit(wrapperRef, rfInstance, {
|
|
5091
|
+
// Re-fit on drill AND after the measured-size re-layout settles.
|
|
5092
|
+
refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
|
|
5093
|
+
padding: 0.18
|
|
5094
|
+
});
|
|
4854
5095
|
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
4855
5096
|
"div",
|
|
4856
5097
|
{
|
|
@@ -4873,7 +5114,7 @@ function TracedFlow({
|
|
|
4873
5114
|
}
|
|
4874
5115
|
),
|
|
4875
5116
|
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
4876
|
-
|
|
5117
|
+
import_react26.ReactFlow,
|
|
4877
5118
|
{
|
|
4878
5119
|
nodes: reactFlowNodes,
|
|
4879
5120
|
edges: reactFlowEdges,
|
|
@@ -4882,9 +5123,12 @@ function TracedFlow({
|
|
|
4882
5123
|
onNodeClick: handleNodeClick,
|
|
4883
5124
|
onInit: setRfInstance,
|
|
4884
5125
|
fitView: true,
|
|
5126
|
+
fitViewOptions: { padding: 0.18 },
|
|
5127
|
+
minZoom: 0.1,
|
|
4885
5128
|
proOptions: { hideAttribution: true },
|
|
4886
5129
|
children: [
|
|
4887
|
-
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
5130
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
|
|
5131
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react26.Background, { variant: import_react26.BackgroundVariant.Dots, gap: 20, size: 1 }),
|
|
4888
5132
|
children
|
|
4889
5133
|
]
|
|
4890
5134
|
}
|
|
@@ -4895,12 +5139,12 @@ function TracedFlow({
|
|
|
4895
5139
|
}
|
|
4896
5140
|
|
|
4897
5141
|
// src/components/InspectorPanel/InspectorPanel.tsx
|
|
4898
|
-
var
|
|
5142
|
+
var import_react28 = require("react");
|
|
4899
5143
|
|
|
4900
5144
|
// src/components/DataTracePanel/DataTracePanel.tsx
|
|
4901
|
-
var
|
|
5145
|
+
var import_react27 = require("react");
|
|
4902
5146
|
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
4903
|
-
var DataTracePanel = (0,
|
|
5147
|
+
var DataTracePanel = (0, import_react27.memo)(function DataTracePanel2({
|
|
4904
5148
|
frames,
|
|
4905
5149
|
selectedStageId,
|
|
4906
5150
|
onFrameClick,
|
|
@@ -4970,7 +5214,7 @@ var DataTracePanel = (0, import_react25.memo)(function DataTracePanel2({
|
|
|
4970
5214
|
))
|
|
4971
5215
|
] });
|
|
4972
5216
|
});
|
|
4973
|
-
var DataTraceFrame = (0,
|
|
5217
|
+
var DataTraceFrame = (0, import_react27.memo)(function DataTraceFrame2({
|
|
4974
5218
|
frame,
|
|
4975
5219
|
isFirst,
|
|
4976
5220
|
isLast,
|
|
@@ -5056,14 +5300,14 @@ var DataTraceFrame = (0, import_react25.memo)(function DataTraceFrame2({
|
|
|
5056
5300
|
|
|
5057
5301
|
// src/components/InspectorPanel/InspectorPanel.tsx
|
|
5058
5302
|
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
5059
|
-
var InspectorPanel = (0,
|
|
5303
|
+
var InspectorPanel = (0, import_react28.memo)(function InspectorPanel2({
|
|
5060
5304
|
snapshots,
|
|
5061
5305
|
selectedIndex,
|
|
5062
5306
|
dataTraceFrames,
|
|
5063
5307
|
selectedStageId,
|
|
5064
5308
|
onNavigateToStage
|
|
5065
5309
|
}) {
|
|
5066
|
-
const [tab, setTab] = (0,
|
|
5310
|
+
const [tab, setTab] = (0, import_react28.useState)("state");
|
|
5067
5311
|
const currentSnapshot = snapshots[selectedIndex];
|
|
5068
5312
|
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
5069
5313
|
"div",
|
|
@@ -5171,9 +5415,9 @@ function TabButton({
|
|
|
5171
5415
|
}
|
|
5172
5416
|
|
|
5173
5417
|
// src/components/InsightPanel/InsightPanel.tsx
|
|
5174
|
-
var
|
|
5418
|
+
var import_react29 = require("react");
|
|
5175
5419
|
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
5176
|
-
var InsightPanel = (0,
|
|
5420
|
+
var InsightPanel = (0, import_react29.memo)(function InsightPanel2({
|
|
5177
5421
|
insights,
|
|
5178
5422
|
expandedId,
|
|
5179
5423
|
mode
|
|
@@ -5186,11 +5430,11 @@ var InsightPanel = (0, import_react27.memo)(function InsightPanel2({
|
|
|
5186
5430
|
}
|
|
5187
5431
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(InsightTabs, { insights, defaultId: expandedId });
|
|
5188
5432
|
});
|
|
5189
|
-
var InsightTabs = (0,
|
|
5433
|
+
var InsightTabs = (0, import_react29.memo)(function InsightTabs2({
|
|
5190
5434
|
insights,
|
|
5191
5435
|
defaultId
|
|
5192
5436
|
}) {
|
|
5193
|
-
const [activeId, setActiveId] = (0,
|
|
5437
|
+
const [activeId, setActiveId] = (0, import_react29.useState)(defaultId ?? insights[0]?.id);
|
|
5194
5438
|
const active = insights.find((i) => i.id === activeId) ?? insights[0];
|
|
5195
5439
|
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
|
|
5196
5440
|
"div",
|
|
@@ -5237,7 +5481,7 @@ var InsightTabs = (0, import_react27.memo)(function InsightTabs2({
|
|
|
5237
5481
|
}
|
|
5238
5482
|
);
|
|
5239
5483
|
});
|
|
5240
|
-
var InsightGrid = (0,
|
|
5484
|
+
var InsightGrid = (0, import_react29.memo)(function InsightGrid2({
|
|
5241
5485
|
insights
|
|
5242
5486
|
}) {
|
|
5243
5487
|
const cols = insights.length <= 2 ? 1 : 2;
|
|
@@ -5302,14 +5546,14 @@ var InsightGrid = (0, import_react27.memo)(function InsightGrid2({
|
|
|
5302
5546
|
});
|
|
5303
5547
|
|
|
5304
5548
|
// src/components/CompactTimeline/CompactTimeline.tsx
|
|
5305
|
-
var
|
|
5549
|
+
var import_react30 = require("react");
|
|
5306
5550
|
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
5307
|
-
var CompactTimeline = (0,
|
|
5551
|
+
var CompactTimeline = (0, import_react30.memo)(function CompactTimeline2({
|
|
5308
5552
|
snapshots,
|
|
5309
5553
|
selectedIndex,
|
|
5310
5554
|
defaultExpanded = false
|
|
5311
5555
|
}) {
|
|
5312
|
-
const [expanded, setExpanded] = (0,
|
|
5556
|
+
const [expanded, setExpanded] = (0, import_react30.useState)(defaultExpanded);
|
|
5313
5557
|
if (snapshots.length === 0) return null;
|
|
5314
5558
|
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: [
|
|
5315
5559
|
/* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
@@ -5394,7 +5638,7 @@ var CompactTimeline = (0, import_react28.memo)(function CompactTimeline2({
|
|
|
5394
5638
|
|
|
5395
5639
|
// src/components/ExplainableShell/ExplainableShell.tsx
|
|
5396
5640
|
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
5397
|
-
var HLinePill = (0,
|
|
5641
|
+
var HLinePill = (0, import_react31.memo)(function HLinePill2({
|
|
5398
5642
|
label,
|
|
5399
5643
|
detail,
|
|
5400
5644
|
expanded,
|
|
@@ -5440,7 +5684,7 @@ var HLinePill = (0, import_react29.memo)(function HLinePill2({
|
|
|
5440
5684
|
/* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { flex: 1, height: 1, background: theme.border } })
|
|
5441
5685
|
] });
|
|
5442
5686
|
});
|
|
5443
|
-
var VLinePill = (0,
|
|
5687
|
+
var VLinePill = (0, import_react31.memo)(function VLinePill2({
|
|
5444
5688
|
label,
|
|
5445
5689
|
expanded,
|
|
5446
5690
|
side = "right",
|
|
@@ -5522,9 +5766,9 @@ function KeyedRecorderView({
|
|
|
5522
5766
|
snapshots,
|
|
5523
5767
|
selectedIndex
|
|
5524
5768
|
}) {
|
|
5525
|
-
const [showAggregate, setShowAggregate] = (0,
|
|
5526
|
-
const detected = (0,
|
|
5527
|
-
const visibleKeys = (0,
|
|
5769
|
+
const [showAggregate, setShowAggregate] = (0, import_react31.useState)(false);
|
|
5770
|
+
const detected = (0, import_react31.useMemo)(() => detectKeyedSteps(data), [data]);
|
|
5771
|
+
const visibleKeys = (0, import_react31.useMemo)(() => {
|
|
5528
5772
|
const keys = /* @__PURE__ */ new Set();
|
|
5529
5773
|
for (let i = 0; i <= selectedIndex && i < snapshots.length; i++) {
|
|
5530
5774
|
const snap = snapshots[i];
|
|
@@ -5634,7 +5878,7 @@ function KeyedRecorderView({
|
|
|
5634
5878
|
] })
|
|
5635
5879
|
] });
|
|
5636
5880
|
}
|
|
5637
|
-
var DetailsContent = (0,
|
|
5881
|
+
var DetailsContent = (0, import_react31.memo)(function DetailsContent2({
|
|
5638
5882
|
snapshots,
|
|
5639
5883
|
selectedIndex,
|
|
5640
5884
|
narrativeEntries,
|
|
@@ -5655,9 +5899,9 @@ var DetailsContent = (0, import_react29.memo)(function DetailsContent2({
|
|
|
5655
5899
|
}
|
|
5656
5900
|
];
|
|
5657
5901
|
const allViews = [...builtInViews, ...extraViews ?? []];
|
|
5658
|
-
const [activeViewId, setActiveViewId] = (0,
|
|
5902
|
+
const [activeViewId, setActiveViewId] = (0, import_react31.useState)(allViews[0]?.id ?? "memory");
|
|
5659
5903
|
const viewIds = allViews.map((v2) => v2.id).join(",");
|
|
5660
|
-
(0,
|
|
5904
|
+
(0, import_react31.useEffect)(() => {
|
|
5661
5905
|
if (!allViews.find((v2) => v2.id === activeViewId)) {
|
|
5662
5906
|
setActiveViewId(allViews[0]?.id ?? "memory");
|
|
5663
5907
|
}
|
|
@@ -5764,7 +6008,7 @@ function buildDataTrace(commitLog, targetRuntimeStageId, maxDepth = 10) {
|
|
|
5764
6008
|
}
|
|
5765
6009
|
return frames;
|
|
5766
6010
|
}
|
|
5767
|
-
var RightPanel = (0,
|
|
6011
|
+
var RightPanel = (0, import_react31.memo)(function RightPanel2({
|
|
5768
6012
|
mode,
|
|
5769
6013
|
onModeChange,
|
|
5770
6014
|
snapshots,
|
|
@@ -5871,7 +6115,7 @@ function ExplainableShell({
|
|
|
5871
6115
|
className,
|
|
5872
6116
|
style
|
|
5873
6117
|
}) {
|
|
5874
|
-
const derivedFromRuntime = (0,
|
|
6118
|
+
const derivedFromRuntime = (0, import_react31.useMemo)(() => {
|
|
5875
6119
|
if (!runtimeSnapshot) return null;
|
|
5876
6120
|
try {
|
|
5877
6121
|
const snaps = toVisualizationSnapshots(runtimeSnapshot, narrativeEntries);
|
|
@@ -5882,7 +6126,7 @@ function ExplainableShell({
|
|
|
5882
6126
|
}, [runtimeSnapshot, narrativeEntries]);
|
|
5883
6127
|
const snapshots = snapshotsProp ?? derivedFromRuntime?.snapshots ?? [];
|
|
5884
6128
|
const resultData = resultDataProp ?? derivedFromRuntime?.resultData ?? null;
|
|
5885
|
-
const tracedFlowRenderer = (0,
|
|
6129
|
+
const tracedFlowRenderer = (0, import_react31.useMemo)(() => {
|
|
5886
6130
|
if (!traceGraph) return void 0;
|
|
5887
6131
|
return ({ selectedIndex, snapshots: snapshots2, onNodeClick }) => {
|
|
5888
6132
|
const activeRsid = snapshots2[selectedIndex]?.runtimeStageId;
|
|
@@ -5911,10 +6155,10 @@ function ExplainableShell({
|
|
|
5911
6155
|
const leftLabel = panelLabels?.topology ?? "Topology";
|
|
5912
6156
|
const rightLabel = panelLabels?.details ?? "Details";
|
|
5913
6157
|
const bottomLabel = panelLabels?.timeline ?? "Timeline";
|
|
5914
|
-
const shellRef = (0,
|
|
5915
|
-
const [isNarrow, setIsNarrow] = (0,
|
|
5916
|
-
const [isMedium, setIsMedium] = (0,
|
|
5917
|
-
(0,
|
|
6158
|
+
const shellRef = (0, import_react31.useRef)(null);
|
|
6159
|
+
const [isNarrow, setIsNarrow] = (0, import_react31.useState)(false);
|
|
6160
|
+
const [isMedium, setIsMedium] = (0, import_react31.useState)(false);
|
|
6161
|
+
(0, import_react31.useEffect)(() => {
|
|
5918
6162
|
const el = shellRef.current;
|
|
5919
6163
|
if (!el) return;
|
|
5920
6164
|
const ro = new ResizeObserver(([entry]) => {
|
|
@@ -5926,14 +6170,14 @@ function ExplainableShell({
|
|
|
5926
6170
|
ro.observe(el);
|
|
5927
6171
|
return () => ro.disconnect();
|
|
5928
6172
|
}, []);
|
|
5929
|
-
const autoRecorderViews = (0,
|
|
6173
|
+
const autoRecorderViews = (0, import_react31.useMemo)(() => {
|
|
5930
6174
|
const recorders = runtimeSnapshot?.recorders;
|
|
5931
6175
|
if (!recorders?.length) return [];
|
|
5932
6176
|
const explicitIds = new Set((recorderViews ?? []).map((v2) => v2.id));
|
|
5933
6177
|
return recorders.filter((r) => !explicitIds.has(r.id)).map((r) => ({ id: r.id, name: r.name, description: r.description, preferredOperation: r.preferredOperation, data: r.data }));
|
|
5934
6178
|
}, [runtimeSnapshot, recorderViews]);
|
|
5935
6179
|
const hasNarrative = !!narrativeEntries?.length;
|
|
5936
|
-
const allTabs = (0,
|
|
6180
|
+
const allTabs = (0, import_react31.useMemo)(() => {
|
|
5937
6181
|
const tabs2 = [
|
|
5938
6182
|
{ id: "result", name: "Result", description: "Final output and console logs" },
|
|
5939
6183
|
{ id: "memory", name: "Memory", description: "Accumulator \u2014 progressive shared state at each stage" }
|
|
@@ -5952,38 +6196,38 @@ function ExplainableShell({
|
|
|
5952
6196
|
}, [hasNarrative, recorderViews, autoRecorderViews, hideTabsProp]);
|
|
5953
6197
|
const validTabIds = new Set(allTabs.map((t) => t.id));
|
|
5954
6198
|
const resolvedDefault = defaultTab && validTabIds.has(defaultTab) ? defaultTab : allTabs[0]?.id ?? "result";
|
|
5955
|
-
const [activeTab, setActiveTab] = (0,
|
|
5956
|
-
const [snapshotIdx, setSnapshotIdx] = (0,
|
|
5957
|
-
const [drillDownStack, setDrillDownStack] = (0,
|
|
5958
|
-
const [rightExpanded, setRightExpanded] = (0,
|
|
5959
|
-
const [rightPanelMode, setRightPanelMode] = (0,
|
|
5960
|
-
const [leftExpanded, setLeftExpanded] = (0,
|
|
5961
|
-
const [timelineExpanded, setTimelineExpanded] = (0,
|
|
5962
|
-
(0,
|
|
6199
|
+
const [activeTab, setActiveTab] = (0, import_react31.useState)(resolvedDefault);
|
|
6200
|
+
const [snapshotIdx, setSnapshotIdx] = (0, import_react31.useState)(0);
|
|
6201
|
+
const [drillDownStack, setDrillDownStack] = (0, import_react31.useState)([]);
|
|
6202
|
+
const [rightExpanded, setRightExpanded] = (0, import_react31.useState)(defaultExpanded?.details ?? true);
|
|
6203
|
+
const [rightPanelMode, setRightPanelMode] = (0, import_react31.useState)("insights");
|
|
6204
|
+
const [leftExpanded, setLeftExpanded] = (0, import_react31.useState)(defaultExpanded?.topology ?? false);
|
|
6205
|
+
const [timelineExpanded, setTimelineExpanded] = (0, import_react31.useState)(defaultExpanded?.timeline ?? false);
|
|
6206
|
+
(0, import_react31.useEffect)(() => {
|
|
5963
6207
|
if (isNarrow) {
|
|
5964
6208
|
setLeftExpanded(false);
|
|
5965
6209
|
setRightExpanded(false);
|
|
5966
6210
|
setTimelineExpanded(false);
|
|
5967
6211
|
}
|
|
5968
6212
|
}, [isNarrow]);
|
|
5969
|
-
const triggerReflow = (0,
|
|
6213
|
+
const triggerReflow = (0, import_react31.useCallback)(() => {
|
|
5970
6214
|
requestAnimationFrame(() => window.dispatchEvent(new Event("resize")));
|
|
5971
6215
|
setTimeout(() => window.dispatchEvent(new Event("resize")), 320);
|
|
5972
6216
|
}, []);
|
|
5973
|
-
const toggleLeft = (0,
|
|
6217
|
+
const toggleLeft = (0, import_react31.useCallback)((v2) => {
|
|
5974
6218
|
setLeftExpanded(v2);
|
|
5975
6219
|
triggerReflow();
|
|
5976
6220
|
}, [triggerReflow]);
|
|
5977
|
-
const toggleRight = (0,
|
|
6221
|
+
const toggleRight = (0, import_react31.useCallback)((v2) => {
|
|
5978
6222
|
setRightExpanded(v2);
|
|
5979
6223
|
triggerReflow();
|
|
5980
6224
|
}, [triggerReflow]);
|
|
5981
|
-
const toggleTimeline = (0,
|
|
6225
|
+
const toggleTimeline = (0, import_react31.useCallback)(() => {
|
|
5982
6226
|
setTimelineExpanded((p) => !p);
|
|
5983
6227
|
triggerReflow();
|
|
5984
6228
|
}, [triggerReflow]);
|
|
5985
6229
|
const isInSubflow = drillDownStack.length > 0;
|
|
5986
|
-
const currentLevel = (0,
|
|
6230
|
+
const currentLevel = (0, import_react31.useMemo)(() => {
|
|
5987
6231
|
if (drillDownStack.length > 0) {
|
|
5988
6232
|
const top = drillDownStack[drillDownStack.length - 1];
|
|
5989
6233
|
return { spec: top.spec, snapshots: top.snapshots };
|
|
@@ -5994,30 +6238,30 @@ function ExplainableShell({
|
|
|
5994
6238
|
const activeSpec = currentLevel.spec;
|
|
5995
6239
|
const safeIdx = activeSnapshots.length > 0 ? Math.max(0, Math.min(snapshotIdx, activeSnapshots.length - 1)) : 0;
|
|
5996
6240
|
const activeNarrativeEntries = isInSubflow ? void 0 : narrativeEntries;
|
|
5997
|
-
const breadcrumbs = (0,
|
|
6241
|
+
const breadcrumbs = (0, import_react31.useMemo)(() => {
|
|
5998
6242
|
const root = { label: title || "Flowchart", spec, description: spec?.description };
|
|
5999
6243
|
return [root, ...drillDownStack.map((e) => ({ label: e.label, spec: e.spec, description: void 0 }))];
|
|
6000
6244
|
}, [spec, title, drillDownStack]);
|
|
6001
|
-
const showTreeSidebar = (0,
|
|
6245
|
+
const showTreeSidebar = (0, import_react31.useMemo)(() => {
|
|
6002
6246
|
if (traceGraph?.nodes?.length) {
|
|
6003
6247
|
return traceGraph.nodes.some((n) => n.data?.isSubflow === true);
|
|
6004
6248
|
}
|
|
6005
6249
|
return !!spec && hasSubflowNodes(spec);
|
|
6006
6250
|
}, [traceGraph, spec]);
|
|
6007
|
-
const rootOverlay = (0,
|
|
6251
|
+
const rootOverlay = (0, import_react31.useMemo)(() => {
|
|
6008
6252
|
if (isInSubflow || !snapshots.length) return { activeStage: void 0, doneStages: void 0 };
|
|
6009
6253
|
const doneStages = new Set(snapshots.slice(0, safeIdx).map((s) => s.stageLabel));
|
|
6010
6254
|
const activeStage = snapshots[safeIdx]?.stageLabel ?? null;
|
|
6011
6255
|
return { activeStage, doneStages };
|
|
6012
6256
|
}, [isInSubflow, snapshots, safeIdx]);
|
|
6013
|
-
const handleTabChange = (0,
|
|
6257
|
+
const handleTabChange = (0, import_react31.useCallback)((tab) => {
|
|
6014
6258
|
setActiveTab(tab);
|
|
6015
6259
|
setDrillDownStack([]);
|
|
6016
6260
|
}, []);
|
|
6017
|
-
const handleSnapshotChange = (0,
|
|
6261
|
+
const handleSnapshotChange = (0, import_react31.useCallback)((idx) => {
|
|
6018
6262
|
if (typeof idx === "number") setSnapshotIdx(idx);
|
|
6019
6263
|
}, []);
|
|
6020
|
-
const handleDrillDown = (0,
|
|
6264
|
+
const handleDrillDown = (0, import_react31.useCallback)(
|
|
6021
6265
|
(nodeName) => {
|
|
6022
6266
|
if (!activeSpec) return;
|
|
6023
6267
|
const entry = resolveSubflowLevel(activeSpec, activeSnapshots, nodeName, narrativeEntries);
|
|
@@ -6028,14 +6272,14 @@ function ExplainableShell({
|
|
|
6028
6272
|
},
|
|
6029
6273
|
[activeSpec, activeSnapshots, narrativeEntries, snapshotIdx]
|
|
6030
6274
|
);
|
|
6031
|
-
const handleBreadcrumbNavigate = (0,
|
|
6275
|
+
const handleBreadcrumbNavigate = (0, import_react31.useCallback)((level) => {
|
|
6032
6276
|
setDrillDownStack((prev) => {
|
|
6033
6277
|
const popped = level === 0 ? prev[0] : prev[level];
|
|
6034
6278
|
if (popped) setSnapshotIdx(popped.parentSnapshotIdx);
|
|
6035
6279
|
return level === 0 ? [] : prev.slice(0, level);
|
|
6036
6280
|
});
|
|
6037
6281
|
}, []);
|
|
6038
|
-
const handleNodeClick = (0,
|
|
6282
|
+
const handleNodeClick = (0, import_react31.useCallback)(
|
|
6039
6283
|
(indexOrId) => {
|
|
6040
6284
|
if (typeof indexOrId === "number") {
|
|
6041
6285
|
setSnapshotIdx(indexOrId);
|
|
@@ -6053,7 +6297,7 @@ function ExplainableShell({
|
|
|
6053
6297
|
},
|
|
6054
6298
|
[activeSpec, activeSnapshots, handleDrillDown]
|
|
6055
6299
|
);
|
|
6056
|
-
const handleTreeNodeSelect = (0,
|
|
6300
|
+
const handleTreeNodeSelect = (0, import_react31.useCallback)(
|
|
6057
6301
|
(name, isSubflow) => {
|
|
6058
6302
|
if (isSubflow && spec) {
|
|
6059
6303
|
setDrillDownStack([]);
|
|
@@ -6088,7 +6332,7 @@ function ExplainableShell({
|
|
|
6088
6332
|
] });
|
|
6089
6333
|
}
|
|
6090
6334
|
const showTopology = !!effectiveRenderFlowchart && !!activeSpec;
|
|
6091
|
-
const detailsContent = (0,
|
|
6335
|
+
const detailsContent = (0, import_react31.useMemo)(() => {
|
|
6092
6336
|
if (activeTab === "result") {
|
|
6093
6337
|
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(ResultPanel, { data: resultData ?? null, logs, hideConsole, size });
|
|
6094
6338
|
}
|
|
@@ -6270,7 +6514,7 @@ function ExplainableShell({
|
|
|
6270
6514
|
|
|
6271
6515
|
// src/components/TraceViewer/TraceViewer.tsx
|
|
6272
6516
|
var React = __toESM(require("react"), 1);
|
|
6273
|
-
var
|
|
6517
|
+
var import_react32 = require("react");
|
|
6274
6518
|
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
6275
6519
|
function parseTrace(input) {
|
|
6276
6520
|
if (input == null) {
|
|
@@ -6334,11 +6578,11 @@ function TraceViewer({
|
|
|
6334
6578
|
recorderViews,
|
|
6335
6579
|
renderFlowchart
|
|
6336
6580
|
}) {
|
|
6337
|
-
const parsed = (0,
|
|
6581
|
+
const parsed = (0, import_react32.useMemo)(() => parseTrace(trace), [trace]);
|
|
6338
6582
|
React.useEffect(() => {
|
|
6339
6583
|
if (!parsed.ok && onError) onError(parsed.error);
|
|
6340
6584
|
}, [parsed, onError]);
|
|
6341
|
-
const snapshots = (0,
|
|
6585
|
+
const snapshots = (0, import_react32.useMemo)(() => {
|
|
6342
6586
|
if (!parsed.ok || !parsed.trace.snapshot) return [];
|
|
6343
6587
|
try {
|
|
6344
6588
|
return toVisualizationSnapshots(
|