@pipelex/mthds-ui 0.5.2 → 0.6.0
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/{chunk-DDAAVRWG.js → chunk-2NMEKWO5.js} +15 -2
- package/dist/chunk-IZ4FH2WM.js +1 -0
- package/dist/{chunk-OMJ6DRXM.js → chunk-NISDJYQJ.js} +283 -33
- package/dist/chunk-NISDJYQJ.js.map +1 -0
- package/dist/graph/index.d.ts +52 -4
- package/dist/graph/index.js +15 -3
- package/dist/graph/react/graph-core.css +60 -0
- package/dist/graph/react/index.css +12 -0
- package/dist/graph/react/index.css.map +1 -1
- package/dist/graph/react/index.d.ts +15 -3
- package/dist/graph/react/index.js +319 -35
- package/dist/graph/react/index.js.map +1 -1
- package/dist/graph/react/viewer/GraphToolbar.css +14 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +15 -3
- package/dist/shiki/index.js +1 -1
- package/dist/{types--1tl-afL.d.ts → types-C7rr1Egj.d.ts} +23 -3
- package/package.json +1 -1
- package/dist/chunk-IX35IG2I.js +0 -1
- package/dist/chunk-OMJ6DRXM.js.map +0 -1
- /package/dist/{chunk-DDAAVRWG.js.map → chunk-2NMEKWO5.js.map} +0 -0
- /package/dist/{chunk-IX35IG2I.js.map → chunk-IZ4FH2WM.js.map} +0 -0
|
@@ -2,19 +2,22 @@
|
|
|
2
2
|
import {
|
|
3
3
|
DEFAULT_GRAPH_CONFIG,
|
|
4
4
|
EDGE_TYPE,
|
|
5
|
+
FOLD_MODE,
|
|
5
6
|
GRAPH_DIRECTION,
|
|
6
7
|
MAX_VISIBLE_CONTROLLER_CHILDREN,
|
|
7
8
|
applyControllers,
|
|
9
|
+
applyFolds,
|
|
8
10
|
buildGraph,
|
|
11
|
+
findCousinControllers,
|
|
9
12
|
getLayoutedElements,
|
|
10
13
|
getPipeBlueprint,
|
|
11
14
|
resolveConceptRef,
|
|
12
15
|
stuffDigestFromId
|
|
13
|
-
} from "../../chunk-
|
|
16
|
+
} from "../../chunk-NISDJYQJ.js";
|
|
14
17
|
import {
|
|
15
18
|
__spreadProps,
|
|
16
19
|
__spreadValues
|
|
17
|
-
} from "../../chunk-
|
|
20
|
+
} from "../../chunk-2NMEKWO5.js";
|
|
18
21
|
|
|
19
22
|
// src/graph/react/index.ts
|
|
20
23
|
import "./graph-core.css";
|
|
@@ -1648,6 +1651,46 @@ var BOXES_ICON = /* @__PURE__ */ jsxs16(
|
|
|
1648
1651
|
]
|
|
1649
1652
|
}
|
|
1650
1653
|
);
|
|
1654
|
+
var FOLD_ALL_ICON = /* @__PURE__ */ jsxs16(
|
|
1655
|
+
"svg",
|
|
1656
|
+
{
|
|
1657
|
+
viewBox: "0 0 24 24",
|
|
1658
|
+
width: "14",
|
|
1659
|
+
height: "14",
|
|
1660
|
+
fill: "none",
|
|
1661
|
+
stroke: "currentColor",
|
|
1662
|
+
strokeWidth: "2",
|
|
1663
|
+
strokeLinecap: "round",
|
|
1664
|
+
strokeLinejoin: "round",
|
|
1665
|
+
children: [
|
|
1666
|
+
/* @__PURE__ */ jsx16("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }),
|
|
1667
|
+
/* @__PURE__ */ jsx16("polyline", { points: "2 2 6 6 2 6" }),
|
|
1668
|
+
/* @__PURE__ */ jsx16("polyline", { points: "22 2 18 6 22 6" }),
|
|
1669
|
+
/* @__PURE__ */ jsx16("polyline", { points: "2 22 6 18 2 18" }),
|
|
1670
|
+
/* @__PURE__ */ jsx16("polyline", { points: "22 22 18 18 22 18" })
|
|
1671
|
+
]
|
|
1672
|
+
}
|
|
1673
|
+
);
|
|
1674
|
+
var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs16(
|
|
1675
|
+
"svg",
|
|
1676
|
+
{
|
|
1677
|
+
viewBox: "0 0 24 24",
|
|
1678
|
+
width: "14",
|
|
1679
|
+
height: "14",
|
|
1680
|
+
fill: "none",
|
|
1681
|
+
stroke: "currentColor",
|
|
1682
|
+
strokeWidth: "2",
|
|
1683
|
+
strokeLinecap: "round",
|
|
1684
|
+
strokeLinejoin: "round",
|
|
1685
|
+
children: [
|
|
1686
|
+
/* @__PURE__ */ jsx16("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }),
|
|
1687
|
+
/* @__PURE__ */ jsx16("polyline", { points: "3 3 7 7 3 7" }),
|
|
1688
|
+
/* @__PURE__ */ jsx16("polyline", { points: "21 3 17 7 21 7" }),
|
|
1689
|
+
/* @__PURE__ */ jsx16("polyline", { points: "3 21 7 17 3 17" }),
|
|
1690
|
+
/* @__PURE__ */ jsx16("polyline", { points: "21 21 17 17 21 17" })
|
|
1691
|
+
]
|
|
1692
|
+
}
|
|
1693
|
+
);
|
|
1651
1694
|
function GraphToolbar({
|
|
1652
1695
|
direction,
|
|
1653
1696
|
onDirectionChange,
|
|
@@ -1656,11 +1699,18 @@ function GraphToolbar({
|
|
|
1656
1699
|
onZoomIn,
|
|
1657
1700
|
onZoomOut,
|
|
1658
1701
|
onFitView,
|
|
1702
|
+
onFoldAll,
|
|
1703
|
+
onExpandAll,
|
|
1704
|
+
foldAllDisabled = false,
|
|
1705
|
+
expandAllDisabled = false,
|
|
1659
1706
|
rightOffset = 0
|
|
1660
1707
|
}) {
|
|
1661
1708
|
const isVertical = direction === GRAPH_DIRECTION.TB || direction === GRAPH_DIRECTION.BT;
|
|
1662
1709
|
const directionLabel = isVertical ? "Switch to horizontal layout" : "Switch to vertical layout";
|
|
1663
1710
|
const controllersLabel = showControllers ? "Hide pipe controllers" : "Show pipe controllers \u2014 groups pipes by their controlling pipe";
|
|
1711
|
+
const foldAllSection = onFoldAll || onExpandAll;
|
|
1712
|
+
const foldAllTitle = foldAllDisabled ? "Fold all controllers (nothing to fold)" : "Fold all controllers";
|
|
1713
|
+
const expandAllTitle = expandAllDisabled ? "Expand all controllers (nothing to expand)" : "Expand all controllers";
|
|
1664
1714
|
return /* @__PURE__ */ jsxs16("div", { className: "graph-toolbar", style: { right: `${rightOffset + 8}px` }, children: [
|
|
1665
1715
|
/* @__PURE__ */ jsx16(
|
|
1666
1716
|
"button",
|
|
@@ -1684,6 +1734,31 @@ function GraphToolbar({
|
|
|
1684
1734
|
children: BOXES_ICON
|
|
1685
1735
|
}
|
|
1686
1736
|
),
|
|
1737
|
+
foldAllSection && /* @__PURE__ */ jsx16("div", { className: "graph-toolbar-separator" }),
|
|
1738
|
+
onFoldAll && /* @__PURE__ */ jsx16(
|
|
1739
|
+
"button",
|
|
1740
|
+
{
|
|
1741
|
+
type: "button",
|
|
1742
|
+
className: "graph-toolbar-btn",
|
|
1743
|
+
onClick: onFoldAll,
|
|
1744
|
+
disabled: foldAllDisabled,
|
|
1745
|
+
title: foldAllTitle,
|
|
1746
|
+
"aria-label": foldAllTitle,
|
|
1747
|
+
children: FOLD_ALL_ICON
|
|
1748
|
+
}
|
|
1749
|
+
),
|
|
1750
|
+
onExpandAll && /* @__PURE__ */ jsx16(
|
|
1751
|
+
"button",
|
|
1752
|
+
{
|
|
1753
|
+
type: "button",
|
|
1754
|
+
className: "graph-toolbar-btn",
|
|
1755
|
+
onClick: onExpandAll,
|
|
1756
|
+
disabled: expandAllDisabled,
|
|
1757
|
+
title: expandAllTitle,
|
|
1758
|
+
"aria-label": expandAllTitle,
|
|
1759
|
+
children: EXPAND_ALL_ICON
|
|
1760
|
+
}
|
|
1761
|
+
),
|
|
1687
1762
|
(onZoomOut || onZoomIn || onFitView) && /* @__PURE__ */ jsx16("div", { className: "graph-toolbar-separator" }),
|
|
1688
1763
|
onZoomOut && /* @__PURE__ */ jsx16(
|
|
1689
1764
|
"button",
|
|
@@ -1748,7 +1823,22 @@ function ControllerGroupNode({ data }) {
|
|
|
1748
1823
|
/* @__PURE__ */ jsxs17("div", { className: "controller-group-header", children: [
|
|
1749
1824
|
/* @__PURE__ */ jsx17("span", { className: "controller-group-icon", children: config.icon }),
|
|
1750
1825
|
/* @__PURE__ */ jsx17("span", { className: "controller-group-badge", children: config.badge }),
|
|
1751
|
-
data.label && /* @__PURE__ */ jsx17("span", { className: "controller-group-label", children: data.label })
|
|
1826
|
+
data.label && /* @__PURE__ */ jsx17("span", { className: "controller-group-label", children: data.label }),
|
|
1827
|
+
data.onToggleFold && /* @__PURE__ */ jsx17(
|
|
1828
|
+
"button",
|
|
1829
|
+
{
|
|
1830
|
+
type: "button",
|
|
1831
|
+
className: "controller-group-fold",
|
|
1832
|
+
title: "Fold controller (alt/option: only this one)",
|
|
1833
|
+
"aria-label": "Fold controller",
|
|
1834
|
+
onClick: (e) => {
|
|
1835
|
+
var _a2;
|
|
1836
|
+
e.stopPropagation();
|
|
1837
|
+
(_a2 = data.onToggleFold) == null ? void 0 : _a2.call(data, { soloMode: e.altKey });
|
|
1838
|
+
},
|
|
1839
|
+
children: "\u2921"
|
|
1840
|
+
}
|
|
1841
|
+
)
|
|
1752
1842
|
] }),
|
|
1753
1843
|
isCollapsible && /* @__PURE__ */ jsx17(
|
|
1754
1844
|
"button",
|
|
@@ -1778,8 +1868,21 @@ var PIPE_TYPE_BADGES2 = {
|
|
|
1778
1868
|
PipeCompose: "Compose",
|
|
1779
1869
|
PipeImgGen: "ImgGen",
|
|
1780
1870
|
PipeSearch: "Search",
|
|
1781
|
-
PipeFunc: "Func"
|
|
1871
|
+
PipeFunc: "Func",
|
|
1872
|
+
PipeSequence: "Sequence",
|
|
1873
|
+
PipeParallel: "Parallel",
|
|
1874
|
+
PipeCondition: "Condition",
|
|
1875
|
+
PipeBatch: "Batch"
|
|
1876
|
+
};
|
|
1877
|
+
var CONTROLLER_TYPE_TABLE = {
|
|
1878
|
+
PipeSequence: true,
|
|
1879
|
+
PipeParallel: true,
|
|
1880
|
+
PipeCondition: true,
|
|
1881
|
+
PipeBatch: true
|
|
1782
1882
|
};
|
|
1883
|
+
function isControllerType(pipeType) {
|
|
1884
|
+
return pipeType in CONTROLLER_TYPE_TABLE;
|
|
1885
|
+
}
|
|
1783
1886
|
var STATUS_CONFIG = {
|
|
1784
1887
|
succeeded: { color: "#50FA7B", label: "Succeeded" },
|
|
1785
1888
|
failed: { color: "#FF5555", label: "Failed" },
|
|
@@ -1796,14 +1899,17 @@ function PipeCardBase({ data, children }) {
|
|
|
1796
1899
|
const badge = getBadge(data.pipeType);
|
|
1797
1900
|
const statusConfig = (_a = STATUS_CONFIG[data.status]) != null ? _a : STATUS_CONFIG.scheduled;
|
|
1798
1901
|
const isRunning = data.status === "running";
|
|
1902
|
+
const isController = isControllerType(data.pipeType);
|
|
1799
1903
|
const [inputsExpanded, setInputsExpanded] = useState2(false);
|
|
1800
1904
|
const hasMany = data.inputs.length > MAX_VISIBLE_INPUTS;
|
|
1801
1905
|
const visibleInputs = hasMany && !inputsExpanded ? data.inputs.slice(0, MAX_VISIBLE_INPUTS) : data.inputs;
|
|
1802
1906
|
const hiddenCount = data.inputs.length - MAX_VISIBLE_INPUTS;
|
|
1803
1907
|
const dirClass = data.direction === "TB" ? "pipe-card--tb" : "pipe-card--lr";
|
|
1804
|
-
|
|
1908
|
+
const controllerClass = isController ? " pipe-card--controller" : "";
|
|
1909
|
+
const badgeClass = isController ? "pipe-card-badge pipe-card-badge--controller" : "pipe-card-badge";
|
|
1910
|
+
return /* @__PURE__ */ jsxs18("div", { className: `pipe-card ${dirClass}${controllerClass}`, children: [
|
|
1805
1911
|
/* @__PURE__ */ jsxs18("div", { className: "pipe-card-header", children: [
|
|
1806
|
-
/* @__PURE__ */ jsx18("span", { className:
|
|
1912
|
+
/* @__PURE__ */ jsx18("span", { className: badgeClass, children: badge }),
|
|
1807
1913
|
/* @__PURE__ */ jsx18("span", { className: "pipe-card-code", title: data.pipeCode, children: data.pipeCode }),
|
|
1808
1914
|
/* @__PURE__ */ jsx18(
|
|
1809
1915
|
"span",
|
|
@@ -1819,6 +1925,21 @@ function PipeCardBase({ data, children }) {
|
|
|
1819
1925
|
}
|
|
1820
1926
|
)
|
|
1821
1927
|
}
|
|
1928
|
+
),
|
|
1929
|
+
data.onExpand && /* @__PURE__ */ jsx18(
|
|
1930
|
+
"button",
|
|
1931
|
+
{
|
|
1932
|
+
type: "button",
|
|
1933
|
+
className: "pipe-card-expand",
|
|
1934
|
+
title: "Expand controller (alt/option: only this one)",
|
|
1935
|
+
"aria-label": "Expand controller",
|
|
1936
|
+
onClick: (e) => {
|
|
1937
|
+
var _a2;
|
|
1938
|
+
e.stopPropagation();
|
|
1939
|
+
(_a2 = data.onExpand) == null ? void 0 : _a2.call(data, { soloMode: e.altKey });
|
|
1940
|
+
},
|
|
1941
|
+
children: "\u2922"
|
|
1942
|
+
}
|
|
1822
1943
|
)
|
|
1823
1944
|
] }),
|
|
1824
1945
|
data.description && /* @__PURE__ */ jsx18("span", { className: "pipe-card-description", title: data.description, children: data.description }),
|
|
@@ -1876,7 +1997,11 @@ var PIPE_CARD_REGISTRY = {
|
|
|
1876
1997
|
PipeCompose: PipeCardBase,
|
|
1877
1998
|
PipeImgGen: PipeCardBase,
|
|
1878
1999
|
PipeSearch: PipeCardBase,
|
|
1879
|
-
PipeFunc: PipeCardBase
|
|
2000
|
+
PipeFunc: PipeCardBase,
|
|
2001
|
+
PipeSequence: PipeCardBase,
|
|
2002
|
+
PipeParallel: PipeCardBase,
|
|
2003
|
+
PipeCondition: PipeCardBase,
|
|
2004
|
+
PipeBatch: PipeCardBase
|
|
1880
2005
|
};
|
|
1881
2006
|
function getPipeCardComponent(pipeType) {
|
|
1882
2007
|
return PIPE_CARD_REGISTRY[pipeType];
|
|
@@ -1938,6 +2063,10 @@ function StuffNodeDetail({
|
|
|
1938
2063
|
)
|
|
1939
2064
|
) });
|
|
1940
2065
|
}
|
|
2066
|
+
function seedFoldedControllers(mode, controllerIds) {
|
|
2067
|
+
if (mode === FOLD_MODE.FOLDED) return new Set(controllerIds);
|
|
2068
|
+
return /* @__PURE__ */ new Set();
|
|
2069
|
+
}
|
|
1941
2070
|
function cloneCachedNodes(nodes) {
|
|
1942
2071
|
return nodes.map((n) => __spreadProps(__spreadValues({}, n), {
|
|
1943
2072
|
position: __spreadValues({}, n.position),
|
|
@@ -1962,11 +2091,13 @@ function applyStatusOverrides(nodes, statusMap) {
|
|
|
1962
2091
|
});
|
|
1963
2092
|
}
|
|
1964
2093
|
function GraphViewer(props) {
|
|
2094
|
+
var _a, _b, _c;
|
|
1965
2095
|
const {
|
|
1966
2096
|
graphspec,
|
|
1967
2097
|
config = DEFAULT_GRAPH_CONFIG,
|
|
1968
2098
|
initialDirection,
|
|
1969
2099
|
initialShowControllers,
|
|
2100
|
+
initialFoldMode,
|
|
1970
2101
|
hideToolbar = false,
|
|
1971
2102
|
onNavigateToPipe,
|
|
1972
2103
|
onStuffNodeClick,
|
|
@@ -1981,16 +2112,19 @@ function GraphViewer(props) {
|
|
|
1981
2112
|
} = props;
|
|
1982
2113
|
const [direction, setDirection] = React7.useState(
|
|
1983
2114
|
() => {
|
|
1984
|
-
var
|
|
1985
|
-
return (
|
|
2115
|
+
var _a2, _b2;
|
|
2116
|
+
return (_b2 = (_a2 = initialDirection != null ? initialDirection : config.direction) != null ? _a2 : DEFAULT_GRAPH_CONFIG.direction) != null ? _b2 : GRAPH_DIRECTION.TB;
|
|
1986
2117
|
}
|
|
1987
2118
|
);
|
|
1988
2119
|
const [showControllers, setShowControllers] = React7.useState(
|
|
1989
2120
|
() => {
|
|
1990
|
-
var
|
|
1991
|
-
return (
|
|
2121
|
+
var _a2, _b2;
|
|
2122
|
+
return (_b2 = (_a2 = initialShowControllers != null ? initialShowControllers : config.showControllers) != null ? _a2 : DEFAULT_GRAPH_CONFIG.showControllers) != null ? _b2 : false;
|
|
1992
2123
|
}
|
|
1993
2124
|
);
|
|
2125
|
+
const effectiveFoldMode = (_b = (_a = initialFoldMode != null ? initialFoldMode : config.foldMode) != null ? _a : DEFAULT_GRAPH_CONFIG.foldMode) != null ? _b : FOLD_MODE.EXPANDED;
|
|
2126
|
+
const foldModeRef = React7.useRef(effectiveFoldMode);
|
|
2127
|
+
foldModeRef.current = effectiveFoldMode;
|
|
1994
2128
|
const containerRef = React7.useRef(null);
|
|
1995
2129
|
const [detailSelection, setDetailSelection] = React7.useState(null);
|
|
1996
2130
|
const [conceptOverride, setConceptOverride] = React7.useState(null);
|
|
@@ -2004,10 +2138,10 @@ function GraphViewer(props) {
|
|
|
2004
2138
|
setConceptOverride(null);
|
|
2005
2139
|
}, [graphspec]);
|
|
2006
2140
|
React7.useEffect(() => {
|
|
2007
|
-
var
|
|
2141
|
+
var _a2;
|
|
2008
2142
|
const el = containerRef.current;
|
|
2009
2143
|
if (!el) return;
|
|
2010
|
-
const palette = (
|
|
2144
|
+
const palette = (_a2 = config.paletteColors) != null ? _a2 : DEFAULT_GRAPH_CONFIG.paletteColors;
|
|
2011
2145
|
if (!palette) return;
|
|
2012
2146
|
for (const [cssVar, value] of Object.entries(palette)) {
|
|
2013
2147
|
el.style.setProperty(cssVar, value);
|
|
@@ -2022,6 +2156,7 @@ function GraphViewer(props) {
|
|
|
2022
2156
|
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
|
|
2023
2157
|
const reactFlowRef = React7.useRef(null);
|
|
2024
2158
|
const initialDataRef = React7.useRef(null);
|
|
2159
|
+
const rawGraphDataRef = React7.useRef(null);
|
|
2025
2160
|
const layoutCacheRef = React7.useRef(null);
|
|
2026
2161
|
const [expandedControllers, setExpandedControllers] = React7.useState(/* @__PURE__ */ new Set());
|
|
2027
2162
|
const toggleCollapse = React7.useCallback((controllerId) => {
|
|
@@ -2032,6 +2167,20 @@ function GraphViewer(props) {
|
|
|
2032
2167
|
return next;
|
|
2033
2168
|
});
|
|
2034
2169
|
}, []);
|
|
2170
|
+
const [foldedControllers, setFoldedControllers] = React7.useState(/* @__PURE__ */ new Set());
|
|
2171
|
+
const toggleFold = React7.useCallback((controllerId, options) => {
|
|
2172
|
+
setFoldedControllers((prev) => {
|
|
2173
|
+
const next = new Set(prev);
|
|
2174
|
+
const shouldFold = !next.has(controllerId);
|
|
2175
|
+
const raw = rawGraphDataRef.current;
|
|
2176
|
+
const targets = !(options == null ? void 0 : options.soloMode) && (raw == null ? void 0 : raw.graphspec) && raw.analysis ? findCousinControllers(controllerId, raw.graphspec, raw.analysis.controllerNodeIds) : /* @__PURE__ */ new Set([controllerId]);
|
|
2177
|
+
for (const id of targets) {
|
|
2178
|
+
if (shouldFold) next.add(id);
|
|
2179
|
+
else next.delete(id);
|
|
2180
|
+
}
|
|
2181
|
+
return next;
|
|
2182
|
+
});
|
|
2183
|
+
}, []);
|
|
2035
2184
|
const edgeType = config.edgeType || EDGE_TYPE.DEFAULT;
|
|
2036
2185
|
const layoutConfig = React7.useMemo(
|
|
2037
2186
|
() => ({ nodesep: config.nodesep, ranksep: config.ranksep }),
|
|
@@ -2051,6 +2200,13 @@ function GraphViewer(props) {
|
|
|
2051
2200
|
expandedRef.current = expandedControllers;
|
|
2052
2201
|
const toggleCollapseRef = React7.useRef(toggleCollapse);
|
|
2053
2202
|
toggleCollapseRef.current = toggleCollapse;
|
|
2203
|
+
const foldedRef = React7.useRef(foldedControllers);
|
|
2204
|
+
foldedRef.current = foldedControllers;
|
|
2205
|
+
const toggleFoldRef = React7.useRef(toggleFold);
|
|
2206
|
+
toggleFoldRef.current = toggleFold;
|
|
2207
|
+
const isFirstFoldEffect = React7.useRef(true);
|
|
2208
|
+
const prevFoldSizeRef = React7.useRef(0);
|
|
2209
|
+
const skipNextFoldEffectRef = React7.useRef(false);
|
|
2054
2210
|
const statusMapRef = React7.useRef(statusMap);
|
|
2055
2211
|
statusMapRef.current = statusMap;
|
|
2056
2212
|
React7.useEffect(() => {
|
|
@@ -2082,7 +2238,8 @@ function GraphViewer(props) {
|
|
|
2082
2238
|
showControllersRef.current,
|
|
2083
2239
|
expandedRef.current,
|
|
2084
2240
|
toggleCollapseRef.current,
|
|
2085
|
-
relayouted.controllerPositions
|
|
2241
|
+
relayouted.controllerPositions,
|
|
2242
|
+
toggleFoldRef.current
|
|
2086
2243
|
);
|
|
2087
2244
|
setNodes(
|
|
2088
2245
|
applyStatusOverrides(
|
|
@@ -2116,16 +2273,18 @@ function GraphViewer(props) {
|
|
|
2116
2273
|
showControllers,
|
|
2117
2274
|
expandedControllers,
|
|
2118
2275
|
toggleCollapse,
|
|
2119
|
-
layoutCacheRef.current.controllerPositions
|
|
2276
|
+
layoutCacheRef.current.controllerPositions,
|
|
2277
|
+
toggleFold
|
|
2120
2278
|
);
|
|
2121
2279
|
setNodes(
|
|
2122
2280
|
applyStatusOverrides(toAppNodes(hydrateLabels(withControllers.nodes)), statusMapRef.current)
|
|
2123
2281
|
);
|
|
2124
2282
|
setEdges(toAppEdges(withControllers.edges));
|
|
2125
|
-
}, [showControllers, expandedControllers, toggleCollapse]);
|
|
2283
|
+
}, [showControllers, expandedControllers, toggleCollapse, toggleFold]);
|
|
2126
2284
|
React7.useEffect(() => {
|
|
2127
2285
|
if (!graphspec) {
|
|
2128
2286
|
initialDataRef.current = null;
|
|
2287
|
+
rawGraphDataRef.current = null;
|
|
2129
2288
|
layoutCacheRef.current = null;
|
|
2130
2289
|
setNodes([]);
|
|
2131
2290
|
setEdges([]);
|
|
@@ -2133,30 +2292,51 @@ function GraphViewer(props) {
|
|
|
2133
2292
|
}
|
|
2134
2293
|
let cancelled = false;
|
|
2135
2294
|
setExpandedControllers(/* @__PURE__ */ new Set());
|
|
2295
|
+
expandedRef.current = /* @__PURE__ */ new Set();
|
|
2136
2296
|
const { graphData, analysis } = buildGraph(graphspec, edgeType);
|
|
2137
|
-
|
|
2297
|
+
rawGraphDataRef.current = {
|
|
2138
2298
|
nodes: graphData.nodes,
|
|
2139
2299
|
edges: graphData.edges,
|
|
2140
|
-
|
|
2300
|
+
analysis,
|
|
2301
|
+
graphspec
|
|
2302
|
+
};
|
|
2303
|
+
const seedSet = analysis ? seedFoldedControllers(foldModeRef.current, analysis.controllerNodeIds) : /* @__PURE__ */ new Set();
|
|
2304
|
+
setFoldedControllers(seedSet);
|
|
2305
|
+
foldedRef.current = seedSet;
|
|
2306
|
+
skipNextFoldEffectRef.current = seedSet.size > 0;
|
|
2307
|
+
prevFoldSizeRef.current = seedSet.size;
|
|
2308
|
+
const folded = seedSet.size > 0 && analysis ? applyFolds(
|
|
2309
|
+
{ nodes: graphData.nodes, edges: graphData.edges },
|
|
2310
|
+
analysis,
|
|
2311
|
+
graphspec,
|
|
2312
|
+
seedSet,
|
|
2313
|
+
toggleFoldRef.current
|
|
2314
|
+
) : { nodes: graphData.nodes, edges: graphData.edges, analysis };
|
|
2315
|
+
initialDataRef.current = {
|
|
2316
|
+
nodes: folded.nodes,
|
|
2317
|
+
edges: folded.edges,
|
|
2318
|
+
_analysis: folded.analysis,
|
|
2141
2319
|
_graphspec: graphspec
|
|
2142
2320
|
};
|
|
2143
2321
|
(async () => {
|
|
2144
2322
|
try {
|
|
2145
2323
|
const currentDirection = directionRef.current;
|
|
2146
2324
|
const currentLayoutConfig = layoutConfigRef.current;
|
|
2147
|
-
const needsLayout =
|
|
2325
|
+
const needsLayout = folded.nodes.some(
|
|
2148
2326
|
(n) => !n.position || n.position.x === 0 && n.position.y === 0
|
|
2149
2327
|
);
|
|
2150
2328
|
const layouted = needsLayout ? await getLayoutedElements(
|
|
2151
|
-
|
|
2152
|
-
|
|
2329
|
+
folded.nodes,
|
|
2330
|
+
folded.edges,
|
|
2153
2331
|
currentDirection,
|
|
2154
2332
|
currentLayoutConfig,
|
|
2155
2333
|
graphspec,
|
|
2156
|
-
analysis
|
|
2157
|
-
) :
|
|
2334
|
+
folded.analysis
|
|
2335
|
+
) : {
|
|
2336
|
+
nodes: folded.nodes,
|
|
2337
|
+
edges: folded.edges,
|
|
2158
2338
|
controllerPositions: {}
|
|
2159
|
-
}
|
|
2339
|
+
};
|
|
2160
2340
|
if (cancelled) return;
|
|
2161
2341
|
layoutCacheRef.current = {
|
|
2162
2342
|
nodes: layouted.nodes,
|
|
@@ -2167,11 +2347,12 @@ function GraphViewer(props) {
|
|
|
2167
2347
|
cloneCachedNodes(layouted.nodes),
|
|
2168
2348
|
layouted.edges,
|
|
2169
2349
|
graphspec,
|
|
2170
|
-
analysis,
|
|
2350
|
+
folded.analysis,
|
|
2171
2351
|
showControllersRef.current,
|
|
2172
2352
|
expandedRef.current,
|
|
2173
2353
|
toggleCollapseRef.current,
|
|
2174
|
-
layouted.controllerPositions
|
|
2354
|
+
layouted.controllerPositions,
|
|
2355
|
+
toggleFoldRef.current
|
|
2175
2356
|
);
|
|
2176
2357
|
setNodes(
|
|
2177
2358
|
applyStatusOverrides(
|
|
@@ -2200,6 +2381,86 @@ function GraphViewer(props) {
|
|
|
2200
2381
|
cancelled = true;
|
|
2201
2382
|
};
|
|
2202
2383
|
}, [graphspec, edgeType]);
|
|
2384
|
+
React7.useEffect(() => {
|
|
2385
|
+
if (isFirstFoldEffect.current) {
|
|
2386
|
+
isFirstFoldEffect.current = false;
|
|
2387
|
+
prevFoldSizeRef.current = foldedControllers.size;
|
|
2388
|
+
return;
|
|
2389
|
+
}
|
|
2390
|
+
if (skipNextFoldEffectRef.current) {
|
|
2391
|
+
skipNextFoldEffectRef.current = false;
|
|
2392
|
+
prevFoldSizeRef.current = foldedControllers.size;
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
const prevSize = prevFoldSizeRef.current;
|
|
2396
|
+
prevFoldSizeRef.current = foldedControllers.size;
|
|
2397
|
+
if (prevSize === 0 && foldedControllers.size === 0) return;
|
|
2398
|
+
if (!rawGraphDataRef.current || !rawGraphDataRef.current.analysis) return;
|
|
2399
|
+
const raw = rawGraphDataRef.current;
|
|
2400
|
+
const currentGraphspec = raw.graphspec;
|
|
2401
|
+
const currentAnalysis = raw.analysis;
|
|
2402
|
+
if (!currentGraphspec || !currentAnalysis) return;
|
|
2403
|
+
let cancelled = false;
|
|
2404
|
+
const folded = applyFolds(
|
|
2405
|
+
{ nodes: raw.nodes, edges: raw.edges },
|
|
2406
|
+
currentAnalysis,
|
|
2407
|
+
currentGraphspec,
|
|
2408
|
+
foldedControllers,
|
|
2409
|
+
toggleFold
|
|
2410
|
+
);
|
|
2411
|
+
initialDataRef.current = {
|
|
2412
|
+
nodes: folded.nodes,
|
|
2413
|
+
edges: folded.edges,
|
|
2414
|
+
_analysis: folded.analysis,
|
|
2415
|
+
_graphspec: currentGraphspec
|
|
2416
|
+
};
|
|
2417
|
+
(async () => {
|
|
2418
|
+
try {
|
|
2419
|
+
const layouted = await getLayoutedElements(
|
|
2420
|
+
folded.nodes,
|
|
2421
|
+
folded.edges,
|
|
2422
|
+
directionRef.current,
|
|
2423
|
+
layoutConfigRef.current,
|
|
2424
|
+
currentGraphspec,
|
|
2425
|
+
folded.analysis
|
|
2426
|
+
);
|
|
2427
|
+
if (cancelled) return;
|
|
2428
|
+
layoutCacheRef.current = {
|
|
2429
|
+
nodes: layouted.nodes,
|
|
2430
|
+
edges: layouted.edges,
|
|
2431
|
+
controllerPositions: layouted.controllerPositions
|
|
2432
|
+
};
|
|
2433
|
+
const withControllers = applyControllers(
|
|
2434
|
+
cloneCachedNodes(layouted.nodes),
|
|
2435
|
+
layouted.edges,
|
|
2436
|
+
currentGraphspec,
|
|
2437
|
+
folded.analysis,
|
|
2438
|
+
showControllersRef.current,
|
|
2439
|
+
expandedRef.current,
|
|
2440
|
+
toggleCollapseRef.current,
|
|
2441
|
+
layouted.controllerPositions,
|
|
2442
|
+
toggleFoldRef.current
|
|
2443
|
+
);
|
|
2444
|
+
setNodes(
|
|
2445
|
+
applyStatusOverrides(
|
|
2446
|
+
toAppNodes(hydrateLabels(withControllers.nodes)),
|
|
2447
|
+
statusMapRef.current
|
|
2448
|
+
)
|
|
2449
|
+
);
|
|
2450
|
+
setEdges(toAppEdges(withControllers.edges));
|
|
2451
|
+
setTimeout(() => {
|
|
2452
|
+
if (!cancelled && reactFlowRef.current) {
|
|
2453
|
+
reactFlowRef.current.fitView({ padding: 0.1 });
|
|
2454
|
+
}
|
|
2455
|
+
}, 50);
|
|
2456
|
+
} catch (err) {
|
|
2457
|
+
console.error("[GraphViewer] ELK layout failed:", err);
|
|
2458
|
+
}
|
|
2459
|
+
})();
|
|
2460
|
+
return () => {
|
|
2461
|
+
cancelled = true;
|
|
2462
|
+
};
|
|
2463
|
+
}, [foldedControllers, toggleFold]);
|
|
2203
2464
|
React7.useEffect(() => {
|
|
2204
2465
|
if (!layoutCacheRef.current || !initialDataRef.current) return;
|
|
2205
2466
|
const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
|
|
@@ -2212,20 +2473,21 @@ function GraphViewer(props) {
|
|
|
2212
2473
|
showControllersRef.current,
|
|
2213
2474
|
expandedRef.current,
|
|
2214
2475
|
toggleCollapseRef.current,
|
|
2215
|
-
layoutCacheRef.current.controllerPositions
|
|
2476
|
+
layoutCacheRef.current.controllerPositions,
|
|
2477
|
+
toggleFoldRef.current
|
|
2216
2478
|
);
|
|
2217
2479
|
setNodes(applyStatusOverrides(toAppNodes(hydrateLabels(withControllers.nodes)), statusMap));
|
|
2218
2480
|
setEdges(toAppEdges(withControllers.edges));
|
|
2219
2481
|
}, [statusMap]);
|
|
2220
2482
|
const onNodeClick = React7.useCallback(
|
|
2221
2483
|
(event, node) => {
|
|
2222
|
-
var
|
|
2484
|
+
var _a2;
|
|
2223
2485
|
const nodeData = node.data;
|
|
2224
2486
|
onNodeSelect == null ? void 0 : onNodeSelect(node.id, nodeData, event);
|
|
2225
2487
|
if (nodeData.isController || nodeData.isPipe) {
|
|
2226
2488
|
const code = nodeData.pipeCode || nodeData.labelText;
|
|
2227
2489
|
if (code && onNavigateToPipe) {
|
|
2228
|
-
onNavigateToPipe(code, (
|
|
2490
|
+
onNavigateToPipe(code, (_a2 = nodeData.pipeCardData) == null ? void 0 : _a2.status);
|
|
2229
2491
|
}
|
|
2230
2492
|
} else if (nodeData.isStuff && onStuffNodeClick && graphspec) {
|
|
2231
2493
|
const digest = stuffDigestFromId(node.id);
|
|
@@ -2283,6 +2545,24 @@ function GraphViewer(props) {
|
|
|
2283
2545
|
);
|
|
2284
2546
|
const selectedSpecNode = (detailSelection == null ? void 0 : detailSelection.kind) === "pipe" && graphspec ? graphspec.nodes.find((n) => n.pipe_code === detailSelection.nodeData.pipeCode) : void 0;
|
|
2285
2547
|
const detailOpen = detailSelection !== null || conceptOverride !== null;
|
|
2548
|
+
const rawAnalysis = (_c = rawGraphDataRef.current) == null ? void 0 : _c.analysis;
|
|
2549
|
+
const allControllerIds = rawAnalysis == null ? void 0 : rawAnalysis.controllerNodeIds;
|
|
2550
|
+
const foldAllProps = React7.useMemo(() => {
|
|
2551
|
+
if (!showControllers || !allControllerIds || allControllerIds.size === 0) {
|
|
2552
|
+
return {
|
|
2553
|
+
onFoldAll: void 0,
|
|
2554
|
+
onExpandAll: void 0,
|
|
2555
|
+
foldAllDisabled: false,
|
|
2556
|
+
expandAllDisabled: false
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
return {
|
|
2560
|
+
onFoldAll: () => setFoldedControllers(new Set(allControllerIds)),
|
|
2561
|
+
onExpandAll: () => setFoldedControllers(/* @__PURE__ */ new Set()),
|
|
2562
|
+
foldAllDisabled: foldedControllers.size === allControllerIds.size,
|
|
2563
|
+
expandAllDisabled: foldedControllers.size === 0
|
|
2564
|
+
};
|
|
2565
|
+
}, [showControllers, allControllerIds, foldedControllers]);
|
|
2286
2566
|
return /* @__PURE__ */ jsxs20("div", { ref: containerRef, className: "react-flow-container", children: [
|
|
2287
2567
|
/* @__PURE__ */ jsx20(
|
|
2288
2568
|
ReactFlow,
|
|
@@ -2351,17 +2631,21 @@ function GraphViewer(props) {
|
|
|
2351
2631
|
showControllers,
|
|
2352
2632
|
onShowControllersChange: setShowControllers,
|
|
2353
2633
|
onZoomIn: () => {
|
|
2354
|
-
var
|
|
2355
|
-
return (
|
|
2634
|
+
var _a2;
|
|
2635
|
+
return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomIn();
|
|
2356
2636
|
},
|
|
2357
2637
|
onZoomOut: () => {
|
|
2358
|
-
var
|
|
2359
|
-
return (
|
|
2638
|
+
var _a2;
|
|
2639
|
+
return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.zoomOut();
|
|
2360
2640
|
},
|
|
2361
2641
|
onFitView: () => {
|
|
2362
|
-
var
|
|
2363
|
-
return (
|
|
2642
|
+
var _a2;
|
|
2643
|
+
return (_a2 = reactFlowRef.current) == null ? void 0 : _a2.fitView({ padding: 0.1 });
|
|
2364
2644
|
},
|
|
2645
|
+
onFoldAll: foldAllProps.onFoldAll,
|
|
2646
|
+
onExpandAll: foldAllProps.onExpandAll,
|
|
2647
|
+
foldAllDisabled: foldAllProps.foldAllDisabled,
|
|
2648
|
+
expandAllDisabled: foldAllProps.expandAllDisabled,
|
|
2365
2649
|
rightOffset: detailOpen ? panelWidth : 0
|
|
2366
2650
|
}
|
|
2367
2651
|
)
|