@pipelex/mthds-ui 0.12.0 → 0.13.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.
@@ -1,11 +1,6 @@
1
1
  "use client";
2
2
  import {
3
3
  DEFAULT_GRAPH_CONFIG,
4
- EDGE_TYPE,
5
- FOLD_MODE,
6
- GRAPH_DIRECTION,
7
- GRAPH_THEME,
8
- GRAPH_THEME_MODE,
9
4
  MAX_VISIBLE_CONTROLLER_CHILDREN,
10
5
  applyControllers,
11
6
  applyFolds,
@@ -15,11 +10,24 @@ import {
15
10
  getPaletteForTheme,
16
11
  getPipeBlueprint,
17
12
  resolveConceptRef,
13
+ validateGraphSpec
14
+ } from "../../chunk-XCZLRCEJ.js";
15
+ import {
16
+ EDGE_TYPE,
17
+ FOLD_MODE,
18
+ GRAPH_DIRECTION,
19
+ GRAPH_SPEC_MODE,
20
+ GRAPH_THEME,
21
+ GRAPH_THEME_MODE,
22
+ TOOLBAR_POSITION,
23
+ VALIDATION_STATE,
24
+ graphSpecMode,
25
+ isDryGraphSpec,
26
+ isStaticGraphSpec,
18
27
  stuffDigestFromId,
19
28
  toolbarOrientation,
20
- toolbarSide,
21
- validateGraphSpec
22
- } from "../../chunk-R34J4GFM.js";
29
+ toolbarSide
30
+ } from "../../chunk-IMQ7MVYL.js";
23
31
  import {
24
32
  __spreadProps,
25
33
  __spreadValues
@@ -32,7 +40,7 @@ import "./stuff/StuffViewer.css";
32
40
  import "./viewer/GraphToolbar.css";
33
41
 
34
42
  // src/graph/react/viewer/GraphViewer.tsx
35
- import React9 from "react";
43
+ import React10 from "react";
36
44
  import {
37
45
  ReactFlow,
38
46
  useNodesState,
@@ -1264,6 +1272,8 @@ function PipeDetailPanel({ node, spec, onConceptClick }) {
1264
1272
  var _a, _b, _c, _d, _e, _f, _g;
1265
1273
  const pipeType = node.pipe_type;
1266
1274
  const isController = CONTROLLER_TYPES.has(pipeType);
1275
+ const isStatic = isStaticGraphSpec(spec);
1276
+ const showsGeneratedData = !isStatic && !isDryGraphSpec(spec);
1267
1277
  const badge = PIPE_TYPE_BADGES[pipeType];
1268
1278
  const status = node.status;
1269
1279
  const statusColor = (_a = STATUS_COLORS[status]) != null ? _a : "#6272a4";
@@ -1299,7 +1309,7 @@ function PipeDetailPanel({ node, spec, onConceptClick }) {
1299
1309
  }
1300
1310
  )
1301
1311
  ] }),
1302
- /* @__PURE__ */ jsxs14("div", { className: "detail-status", children: [
1312
+ !isStatic && /* @__PURE__ */ jsxs14("div", { className: "detail-status", children: [
1303
1313
  /* @__PURE__ */ jsx14("span", { className: "detail-status-dot", style: { background: statusColor } }),
1304
1314
  /* @__PURE__ */ jsx14("span", { className: "detail-status-label", style: { color: statusColor }, children: status }),
1305
1315
  ((_g = node.timing) == null ? void 0 : _g.duration) != null && /* @__PURE__ */ jsx14("span", { className: "detail-duration", children: formatDuration(node.timing.duration) })
@@ -1339,8 +1349,14 @@ function PipeDetailPanel({ node, spec, onConceptClick }) {
1339
1349
  ] }),
1340
1350
  (inputs.length > 0 || outputs.length > 0) && /* @__PURE__ */ jsx14("div", { style: { borderTop: "1px solid rgba(255,255,255,0.06)", margin: "4px 0" } })
1341
1351
  ] }),
1342
- blueprint && /* @__PURE__ */ jsx14(BlueprintSection, { blueprint, executionData: node.execution_data }),
1343
- node.execution_data && Object.keys(node.execution_data).length > 0 && /* @__PURE__ */ jsx14(
1352
+ blueprint && /* @__PURE__ */ jsx14(
1353
+ BlueprintSection,
1354
+ {
1355
+ blueprint,
1356
+ executionData: showsGeneratedData ? node.execution_data : void 0
1357
+ }
1358
+ ),
1359
+ showsGeneratedData && node.execution_data && Object.keys(node.execution_data).length > 0 && /* @__PURE__ */ jsx14(
1344
1360
  ExecutionDataSection,
1345
1361
  {
1346
1362
  executionData: node.execution_data,
@@ -1353,7 +1369,7 @@ function PipeDetailPanel({ node, spec, onConceptClick }) {
1353
1369
  /* @__PURE__ */ jsx14("div", { className: "detail-error-message", children: node.error.message }),
1354
1370
  node.error.stack && /* @__PURE__ */ jsx14("div", { className: "detail-error-stack", children: node.error.stack })
1355
1371
  ] }),
1356
- node.metrics && Object.keys(node.metrics).length > 0 && /* @__PURE__ */ jsxs14("div", { children: [
1372
+ showsGeneratedData && node.metrics && Object.keys(node.metrics).length > 0 && /* @__PURE__ */ jsxs14("div", { children: [
1357
1373
  /* @__PURE__ */ jsx14("div", { className: "detail-section-label", children: "Metrics" }),
1358
1374
  Object.entries(node.metrics).map(([key, value]) => /* @__PURE__ */ jsx14(
1359
1375
  KV,
@@ -1724,10 +1740,125 @@ function hydrateLabels(nodes) {
1724
1740
  }
1725
1741
 
1726
1742
  // src/graph/react/viewer/GraphToolbar.tsx
1743
+ import React8 from "react";
1727
1744
  import { Panel } from "@xyflow/react";
1728
- import { Fragment as Fragment12, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1745
+
1746
+ // src/graph/react/viewer/ValidationPanel.tsx
1747
+ import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
1748
+ function validationLabel(state, issueCount) {
1749
+ const issues = issueCount === 1 ? "1 issue" : `${issueCount} issues`;
1750
+ switch (state) {
1751
+ case VALIDATION_STATE.VALIDATING:
1752
+ return issueCount > 0 ? `Validating method\u2026 \u2014 ${issues}` : "Validating method\u2026";
1753
+ case VALIDATION_STATE.VALID:
1754
+ return issueCount > 0 ? `Method is valid \u2014 ${issues}` : "Method is valid";
1755
+ case VALIDATION_STATE.INVALID:
1756
+ return `Method is invalid \u2014 ${issues}`;
1757
+ case VALIDATION_STATE.ERROR:
1758
+ return "Validation could not run";
1759
+ default: {
1760
+ const _exhaustive = state;
1761
+ return _exhaustive;
1762
+ }
1763
+ }
1764
+ }
1765
+ function validationPanelPlacement(position) {
1766
+ switch (position) {
1767
+ case TOOLBAR_POSITION.TOP_LEFT:
1768
+ case TOOLBAR_POSITION.TOP_CENTER:
1769
+ return "down-start";
1770
+ case TOOLBAR_POSITION.TOP_RIGHT:
1771
+ return "down-end";
1772
+ case TOOLBAR_POSITION.BOTTOM_LEFT:
1773
+ case TOOLBAR_POSITION.BOTTOM_CENTER:
1774
+ return "up-start";
1775
+ case TOOLBAR_POSITION.BOTTOM_RIGHT:
1776
+ return "up-end";
1777
+ case TOOLBAR_POSITION.CENTER_LEFT:
1778
+ return "side-end";
1779
+ case TOOLBAR_POSITION.CENTER_RIGHT:
1780
+ return "side-start";
1781
+ default: {
1782
+ const _exhaustive = position;
1783
+ return _exhaustive;
1784
+ }
1785
+ }
1786
+ }
1787
+ function validationEmptyText(state) {
1788
+ switch (state) {
1789
+ case VALIDATION_STATE.VALIDATING:
1790
+ return "Validating\u2026";
1791
+ case VALIDATION_STATE.VALID:
1792
+ return "No issues found.";
1793
+ case VALIDATION_STATE.INVALID:
1794
+ return "No details available.";
1795
+ case VALIDATION_STATE.ERROR:
1796
+ return "Validation could not run.";
1797
+ default: {
1798
+ const _exhaustive = state;
1799
+ return _exhaustive;
1800
+ }
1801
+ }
1802
+ }
1803
+ function ValidationPanel({
1804
+ state,
1805
+ issues,
1806
+ onIssueClick,
1807
+ placement,
1808
+ id
1809
+ }) {
1810
+ return /* @__PURE__ */ jsxs17(
1811
+ "div",
1812
+ {
1813
+ id,
1814
+ className: `graph-validation-panel graph-validation-panel--${placement}`,
1815
+ role: "region",
1816
+ "aria-label": "Validation issues",
1817
+ children: [
1818
+ /* @__PURE__ */ jsx17("div", { className: "graph-validation-panel-header", children: validationLabel(state, issues.length) }),
1819
+ issues.length === 0 ? /* @__PURE__ */ jsx17("div", { className: "graph-validation-empty", children: validationEmptyText(state) }) : /* @__PURE__ */ jsx17("ul", { className: "graph-validation-issues", role: "list", children: issues.map((issue, index) => {
1820
+ const clickable = onIssueClick !== void 0;
1821
+ const meta = (issue.context || issue.file) && /* @__PURE__ */ jsxs17("div", { className: "graph-validation-issue-meta", children: [
1822
+ issue.context && /* @__PURE__ */ jsx17("span", { className: "graph-validation-issue-context", children: issue.context }),
1823
+ issue.file && /* @__PURE__ */ jsx17("span", { className: "graph-validation-issue-file", children: issue.file })
1824
+ ] });
1825
+ return /* @__PURE__ */ jsx17(
1826
+ "li",
1827
+ {
1828
+ className: `graph-validation-issue graph-validation-issue--${issue.severity}` + (clickable ? " graph-validation-issue--clickable" : ""),
1829
+ children: /* @__PURE__ */ jsxs17(
1830
+ "div",
1831
+ {
1832
+ className: "graph-validation-issue-body",
1833
+ role: clickable ? "button" : void 0,
1834
+ tabIndex: clickable ? 0 : void 0,
1835
+ onClick: clickable ? () => onIssueClick(index, issue) : void 0,
1836
+ onKeyDown: clickable ? (event) => {
1837
+ if (event.key === "Enter" || event.key === " ") {
1838
+ event.preventDefault();
1839
+ onIssueClick(index, issue);
1840
+ }
1841
+ } : void 0,
1842
+ children: [
1843
+ meta,
1844
+ /* @__PURE__ */ jsx17("div", { className: "graph-validation-issue-message", children: issue.message }),
1845
+ issue.suggestedFix && /* @__PURE__ */ jsx17("div", { className: "graph-validation-issue-fix", children: issue.suggestedFix })
1846
+ ]
1847
+ }
1848
+ )
1849
+ },
1850
+ index
1851
+ );
1852
+ }) })
1853
+ ]
1854
+ }
1855
+ );
1856
+ }
1857
+
1858
+ // src/graph/react/viewer/GraphToolbar.tsx
1859
+ import { Fragment as Fragment12, jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
1729
1860
  var REACTFLOW_PANEL_MARGIN = 15;
1730
- var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs17(
1861
+ var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs18(
1731
1862
  "svg",
1732
1863
  {
1733
1864
  viewBox: "0 0 24 24",
@@ -1739,12 +1870,12 @@ var ARROW_RIGHT_ICON = /* @__PURE__ */ jsxs17(
1739
1870
  strokeLinecap: "round",
1740
1871
  strokeLinejoin: "round",
1741
1872
  children: [
1742
- /* @__PURE__ */ jsx17("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
1743
- /* @__PURE__ */ jsx17("polyline", { points: "12 5 19 12 12 19" })
1873
+ /* @__PURE__ */ jsx18("line", { x1: "5", y1: "12", x2: "19", y2: "12" }),
1874
+ /* @__PURE__ */ jsx18("polyline", { points: "12 5 19 12 12 19" })
1744
1875
  ]
1745
1876
  }
1746
1877
  );
1747
- var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs17(
1878
+ var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs18(
1748
1879
  "svg",
1749
1880
  {
1750
1881
  viewBox: "0 0 24 24",
@@ -1756,12 +1887,12 @@ var ARROW_DOWN_ICON = /* @__PURE__ */ jsxs17(
1756
1887
  strokeLinecap: "round",
1757
1888
  strokeLinejoin: "round",
1758
1889
  children: [
1759
- /* @__PURE__ */ jsx17("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1760
- /* @__PURE__ */ jsx17("polyline", { points: "19 12 12 19 5 12" })
1890
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1891
+ /* @__PURE__ */ jsx18("polyline", { points: "19 12 12 19 5 12" })
1761
1892
  ]
1762
1893
  }
1763
1894
  );
1764
- var MINUS_ICON = /* @__PURE__ */ jsx17(
1895
+ var MINUS_ICON = /* @__PURE__ */ jsx18(
1765
1896
  "svg",
1766
1897
  {
1767
1898
  viewBox: "0 0 24 24",
@@ -1772,10 +1903,10 @@ var MINUS_ICON = /* @__PURE__ */ jsx17(
1772
1903
  strokeWidth: "2",
1773
1904
  strokeLinecap: "round",
1774
1905
  strokeLinejoin: "round",
1775
- children: /* @__PURE__ */ jsx17("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1906
+ children: /* @__PURE__ */ jsx18("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1776
1907
  }
1777
1908
  );
1778
- var PLUS_ICON = /* @__PURE__ */ jsxs17(
1909
+ var PLUS_ICON = /* @__PURE__ */ jsxs18(
1779
1910
  "svg",
1780
1911
  {
1781
1912
  viewBox: "0 0 24 24",
@@ -1787,12 +1918,12 @@ var PLUS_ICON = /* @__PURE__ */ jsxs17(
1787
1918
  strokeLinecap: "round",
1788
1919
  strokeLinejoin: "round",
1789
1920
  children: [
1790
- /* @__PURE__ */ jsx17("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1791
- /* @__PURE__ */ jsx17("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1921
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
1922
+ /* @__PURE__ */ jsx18("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
1792
1923
  ]
1793
1924
  }
1794
1925
  );
1795
- var FIT_VIEW_ICON = /* @__PURE__ */ jsxs17(
1926
+ var FIT_VIEW_ICON = /* @__PURE__ */ jsxs18(
1796
1927
  "svg",
1797
1928
  {
1798
1929
  viewBox: "0 0 24 24",
@@ -1804,14 +1935,14 @@ var FIT_VIEW_ICON = /* @__PURE__ */ jsxs17(
1804
1935
  strokeLinecap: "round",
1805
1936
  strokeLinejoin: "round",
1806
1937
  children: [
1807
- /* @__PURE__ */ jsx17("polyline", { points: "15 3 21 3 21 9" }),
1808
- /* @__PURE__ */ jsx17("polyline", { points: "9 21 3 21 3 15" }),
1809
- /* @__PURE__ */ jsx17("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1810
- /* @__PURE__ */ jsx17("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1938
+ /* @__PURE__ */ jsx18("polyline", { points: "15 3 21 3 21 9" }),
1939
+ /* @__PURE__ */ jsx18("polyline", { points: "9 21 3 21 3 15" }),
1940
+ /* @__PURE__ */ jsx18("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
1941
+ /* @__PURE__ */ jsx18("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
1811
1942
  ]
1812
1943
  }
1813
1944
  );
1814
- var BOXES_ICON = /* @__PURE__ */ jsxs17(
1945
+ var BOXES_ICON = /* @__PURE__ */ jsxs18(
1815
1946
  "svg",
1816
1947
  {
1817
1948
  viewBox: "0 0 24 24",
@@ -1823,22 +1954,22 @@ var BOXES_ICON = /* @__PURE__ */ jsxs17(
1823
1954
  strokeLinecap: "round",
1824
1955
  strokeLinejoin: "round",
1825
1956
  children: [
1826
- /* @__PURE__ */ jsx17("path", { d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" }),
1827
- /* @__PURE__ */ jsx17("path", { d: "m7 16.5-4.74-2.85" }),
1828
- /* @__PURE__ */ jsx17("path", { d: "m7 16.5 5-3" }),
1829
- /* @__PURE__ */ jsx17("path", { d: "M7 16.5v5.17" }),
1830
- /* @__PURE__ */ jsx17("path", { d: "M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" }),
1831
- /* @__PURE__ */ jsx17("path", { d: "m17 16.5-5-3" }),
1832
- /* @__PURE__ */ jsx17("path", { d: "m17 16.5 4.74-2.85" }),
1833
- /* @__PURE__ */ jsx17("path", { d: "M17 16.5v5.17" }),
1834
- /* @__PURE__ */ jsx17("path", { d: "M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" }),
1835
- /* @__PURE__ */ jsx17("path", { d: "M12 8 7.26 5.15" }),
1836
- /* @__PURE__ */ jsx17("path", { d: "m12 8 4.74-2.85" }),
1837
- /* @__PURE__ */ jsx17("path", { d: "M12 13.5V8" })
1957
+ /* @__PURE__ */ jsx18("path", { d: "M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" }),
1958
+ /* @__PURE__ */ jsx18("path", { d: "m7 16.5-4.74-2.85" }),
1959
+ /* @__PURE__ */ jsx18("path", { d: "m7 16.5 5-3" }),
1960
+ /* @__PURE__ */ jsx18("path", { d: "M7 16.5v5.17" }),
1961
+ /* @__PURE__ */ jsx18("path", { d: "M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" }),
1962
+ /* @__PURE__ */ jsx18("path", { d: "m17 16.5-5-3" }),
1963
+ /* @__PURE__ */ jsx18("path", { d: "m17 16.5 4.74-2.85" }),
1964
+ /* @__PURE__ */ jsx18("path", { d: "M17 16.5v5.17" }),
1965
+ /* @__PURE__ */ jsx18("path", { d: "M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z" }),
1966
+ /* @__PURE__ */ jsx18("path", { d: "M12 8 7.26 5.15" }),
1967
+ /* @__PURE__ */ jsx18("path", { d: "m12 8 4.74-2.85" }),
1968
+ /* @__PURE__ */ jsx18("path", { d: "M12 13.5V8" })
1838
1969
  ]
1839
1970
  }
1840
1971
  );
1841
- var FOLD_ALL_ICON = /* @__PURE__ */ jsxs17(
1972
+ var FOLD_ALL_ICON = /* @__PURE__ */ jsxs18(
1842
1973
  "svg",
1843
1974
  {
1844
1975
  viewBox: "0 0 24 24",
@@ -1850,15 +1981,15 @@ var FOLD_ALL_ICON = /* @__PURE__ */ jsxs17(
1850
1981
  strokeLinecap: "round",
1851
1982
  strokeLinejoin: "round",
1852
1983
  children: [
1853
- /* @__PURE__ */ jsx17("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }),
1854
- /* @__PURE__ */ jsx17("polyline", { points: "2 2 6 6 2 6" }),
1855
- /* @__PURE__ */ jsx17("polyline", { points: "22 2 18 6 22 6" }),
1856
- /* @__PURE__ */ jsx17("polyline", { points: "2 22 6 18 2 18" }),
1857
- /* @__PURE__ */ jsx17("polyline", { points: "22 22 18 18 22 18" })
1984
+ /* @__PURE__ */ jsx18("rect", { x: "6", y: "6", width: "12", height: "12", rx: "2" }),
1985
+ /* @__PURE__ */ jsx18("polyline", { points: "2 2 6 6 2 6" }),
1986
+ /* @__PURE__ */ jsx18("polyline", { points: "22 2 18 6 22 6" }),
1987
+ /* @__PURE__ */ jsx18("polyline", { points: "2 22 6 18 2 18" }),
1988
+ /* @__PURE__ */ jsx18("polyline", { points: "22 22 18 18 22 18" })
1858
1989
  ]
1859
1990
  }
1860
1991
  );
1861
- var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs17(
1992
+ var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs18(
1862
1993
  "svg",
1863
1994
  {
1864
1995
  viewBox: "0 0 24 24",
@@ -1870,15 +2001,15 @@ var EXPAND_ALL_ICON = /* @__PURE__ */ jsxs17(
1870
2001
  strokeLinecap: "round",
1871
2002
  strokeLinejoin: "round",
1872
2003
  children: [
1873
- /* @__PURE__ */ jsx17("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }),
1874
- /* @__PURE__ */ jsx17("polyline", { points: "3 3 7 7 3 7" }),
1875
- /* @__PURE__ */ jsx17("polyline", { points: "21 3 17 7 21 7" }),
1876
- /* @__PURE__ */ jsx17("polyline", { points: "3 21 7 17 3 17" }),
1877
- /* @__PURE__ */ jsx17("polyline", { points: "21 21 17 17 21 17" })
2004
+ /* @__PURE__ */ jsx18("rect", { x: "9", y: "9", width: "6", height: "6", rx: "1" }),
2005
+ /* @__PURE__ */ jsx18("polyline", { points: "3 3 7 7 3 7" }),
2006
+ /* @__PURE__ */ jsx18("polyline", { points: "21 3 17 7 21 7" }),
2007
+ /* @__PURE__ */ jsx18("polyline", { points: "3 21 7 17 3 17" }),
2008
+ /* @__PURE__ */ jsx18("polyline", { points: "21 21 17 17 21 17" })
1878
2009
  ]
1879
2010
  }
1880
2011
  );
1881
- var SUN_ICON = /* @__PURE__ */ jsxs17(
2012
+ var SUN_ICON = /* @__PURE__ */ jsxs18(
1882
2013
  "svg",
1883
2014
  {
1884
2015
  viewBox: "0 0 24 24",
@@ -1890,19 +2021,19 @@ var SUN_ICON = /* @__PURE__ */ jsxs17(
1890
2021
  strokeLinecap: "round",
1891
2022
  strokeLinejoin: "round",
1892
2023
  children: [
1893
- /* @__PURE__ */ jsx17("circle", { cx: "12", cy: "12", r: "4" }),
1894
- /* @__PURE__ */ jsx17("line", { x1: "12", y1: "2", x2: "12", y2: "4" }),
1895
- /* @__PURE__ */ jsx17("line", { x1: "12", y1: "20", x2: "12", y2: "22" }),
1896
- /* @__PURE__ */ jsx17("line", { x1: "4.93", y1: "4.93", x2: "6.34", y2: "6.34" }),
1897
- /* @__PURE__ */ jsx17("line", { x1: "17.66", y1: "17.66", x2: "19.07", y2: "19.07" }),
1898
- /* @__PURE__ */ jsx17("line", { x1: "2", y1: "12", x2: "4", y2: "12" }),
1899
- /* @__PURE__ */ jsx17("line", { x1: "20", y1: "12", x2: "22", y2: "12" }),
1900
- /* @__PURE__ */ jsx17("line", { x1: "4.93", y1: "19.07", x2: "6.34", y2: "17.66" }),
1901
- /* @__PURE__ */ jsx17("line", { x1: "17.66", y1: "6.34", x2: "19.07", y2: "4.93" })
2024
+ /* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "4" }),
2025
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "2", x2: "12", y2: "4" }),
2026
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "20", x2: "12", y2: "22" }),
2027
+ /* @__PURE__ */ jsx18("line", { x1: "4.93", y1: "4.93", x2: "6.34", y2: "6.34" }),
2028
+ /* @__PURE__ */ jsx18("line", { x1: "17.66", y1: "17.66", x2: "19.07", y2: "19.07" }),
2029
+ /* @__PURE__ */ jsx18("line", { x1: "2", y1: "12", x2: "4", y2: "12" }),
2030
+ /* @__PURE__ */ jsx18("line", { x1: "20", y1: "12", x2: "22", y2: "12" }),
2031
+ /* @__PURE__ */ jsx18("line", { x1: "4.93", y1: "19.07", x2: "6.34", y2: "17.66" }),
2032
+ /* @__PURE__ */ jsx18("line", { x1: "17.66", y1: "6.34", x2: "19.07", y2: "4.93" })
1902
2033
  ]
1903
2034
  }
1904
2035
  );
1905
- var MOON_ICON = /* @__PURE__ */ jsx17(
2036
+ var MOON_ICON = /* @__PURE__ */ jsx18(
1906
2037
  "svg",
1907
2038
  {
1908
2039
  viewBox: "0 0 24 24",
@@ -1913,10 +2044,10 @@ var MOON_ICON = /* @__PURE__ */ jsx17(
1913
2044
  strokeWidth: "2",
1914
2045
  strokeLinecap: "round",
1915
2046
  strokeLinejoin: "round",
1916
- children: /* @__PURE__ */ jsx17("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
2047
+ children: /* @__PURE__ */ jsx18("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
1917
2048
  }
1918
2049
  );
1919
- var MONITOR_ICON = /* @__PURE__ */ jsxs17(
2050
+ var MONITOR_ICON = /* @__PURE__ */ jsxs18(
1920
2051
  "svg",
1921
2052
  {
1922
2053
  viewBox: "0 0 24 24",
@@ -1928,12 +2059,93 @@ var MONITOR_ICON = /* @__PURE__ */ jsxs17(
1928
2059
  strokeLinecap: "round",
1929
2060
  strokeLinejoin: "round",
1930
2061
  children: [
1931
- /* @__PURE__ */ jsx17("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
1932
- /* @__PURE__ */ jsx17("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
1933
- /* @__PURE__ */ jsx17("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
2062
+ /* @__PURE__ */ jsx18("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2" }),
2063
+ /* @__PURE__ */ jsx18("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
2064
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
1934
2065
  ]
1935
2066
  }
1936
2067
  );
2068
+ var SPINNER_ICON = /* @__PURE__ */ jsx18(
2069
+ "svg",
2070
+ {
2071
+ className: "graph-toolbar-validation-spin",
2072
+ viewBox: "0 0 24 24",
2073
+ width: "14",
2074
+ height: "14",
2075
+ fill: "none",
2076
+ stroke: "currentColor",
2077
+ strokeWidth: "2",
2078
+ strokeLinecap: "round",
2079
+ strokeLinejoin: "round",
2080
+ children: /* @__PURE__ */ jsx18("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" })
2081
+ }
2082
+ );
2083
+ var CHECK_ICON2 = /* @__PURE__ */ jsx18(
2084
+ "svg",
2085
+ {
2086
+ viewBox: "0 0 24 24",
2087
+ width: "14",
2088
+ height: "14",
2089
+ fill: "none",
2090
+ stroke: "currentColor",
2091
+ strokeWidth: "2",
2092
+ strokeLinecap: "round",
2093
+ strokeLinejoin: "round",
2094
+ children: /* @__PURE__ */ jsx18("polyline", { points: "20 6 9 17 4 12" })
2095
+ }
2096
+ );
2097
+ var X_CIRCLE_ICON = /* @__PURE__ */ jsxs18(
2098
+ "svg",
2099
+ {
2100
+ viewBox: "0 0 24 24",
2101
+ width: "14",
2102
+ height: "14",
2103
+ fill: "none",
2104
+ stroke: "currentColor",
2105
+ strokeWidth: "2",
2106
+ strokeLinecap: "round",
2107
+ strokeLinejoin: "round",
2108
+ children: [
2109
+ /* @__PURE__ */ jsx18("circle", { cx: "12", cy: "12", r: "10" }),
2110
+ /* @__PURE__ */ jsx18("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
2111
+ /* @__PURE__ */ jsx18("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
2112
+ ]
2113
+ }
2114
+ );
2115
+ var ALERT_TRIANGLE_ICON = /* @__PURE__ */ jsxs18(
2116
+ "svg",
2117
+ {
2118
+ viewBox: "0 0 24 24",
2119
+ width: "14",
2120
+ height: "14",
2121
+ fill: "none",
2122
+ stroke: "currentColor",
2123
+ strokeWidth: "2",
2124
+ strokeLinecap: "round",
2125
+ strokeLinejoin: "round",
2126
+ children: [
2127
+ /* @__PURE__ */ jsx18("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" }),
2128
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
2129
+ /* @__PURE__ */ jsx18("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
2130
+ ]
2131
+ }
2132
+ );
2133
+ function validationIcon(state) {
2134
+ switch (state) {
2135
+ case VALIDATION_STATE.VALIDATING:
2136
+ return SPINNER_ICON;
2137
+ case VALIDATION_STATE.VALID:
2138
+ return CHECK_ICON2;
2139
+ case VALIDATION_STATE.INVALID:
2140
+ return X_CIRCLE_ICON;
2141
+ case VALIDATION_STATE.ERROR:
2142
+ return ALERT_TRIANGLE_ICON;
2143
+ default: {
2144
+ const _exhaustive = state;
2145
+ return _exhaustive;
2146
+ }
2147
+ }
2148
+ }
1937
2149
  var THEME_MODE_CYCLE = [
1938
2150
  GRAPH_THEME_MODE.SYSTEM,
1939
2151
  GRAPH_THEME_MODE.LIGHT,
@@ -1972,10 +2184,37 @@ function GraphToolbar({
1972
2184
  themeMode,
1973
2185
  onThemeModeChange,
1974
2186
  rightOffset = 0,
1975
- position
2187
+ position,
2188
+ validationState,
2189
+ validationIssues = [],
2190
+ onValidationIssueClick
1976
2191
  }) {
1977
2192
  const themeToggleEnabled = themeMode !== void 0 && onThemeModeChange !== void 0;
1978
2193
  const orientation = toolbarOrientation(position);
2194
+ const [validationOpen, setValidationOpen] = React8.useState(false);
2195
+ const validationRef = React8.useRef(null);
2196
+ const validationPanelId = React8.useId();
2197
+ React8.useEffect(() => {
2198
+ if (validationState === void 0) setValidationOpen(false);
2199
+ }, [validationState]);
2200
+ React8.useEffect(() => {
2201
+ if (!validationOpen) return;
2202
+ const onPointerDown = (event) => {
2203
+ const wrapper = validationRef.current;
2204
+ if (wrapper && event.target instanceof Node && !wrapper.contains(event.target)) {
2205
+ setValidationOpen(false);
2206
+ }
2207
+ };
2208
+ const onKeyDown = (event) => {
2209
+ if (event.key === "Escape") setValidationOpen(false);
2210
+ };
2211
+ document.addEventListener("mousedown", onPointerDown);
2212
+ document.addEventListener("keydown", onKeyDown);
2213
+ return () => {
2214
+ document.removeEventListener("mousedown", onPointerDown);
2215
+ document.removeEventListener("keydown", onKeyDown);
2216
+ };
2217
+ }, [validationOpen]);
1979
2218
  const dodgesDetailPanel = toolbarSide(position) === "right" && rightOffset > 0;
1980
2219
  const panelStyle = dodgesDetailPanel ? { marginRight: REACTFLOW_PANEL_MARGIN + rightOffset } : void 0;
1981
2220
  const isVertical = direction === GRAPH_DIRECTION.TB || direction === GRAPH_DIRECTION.BT;
@@ -1984,8 +2223,40 @@ function GraphToolbar({
1984
2223
  const foldAllSection = onFoldAll || onExpandAll;
1985
2224
  const foldAllTitle = foldAllDisabled ? "Fold all controllers (nothing to fold)" : "Fold all controllers";
1986
2225
  const expandAllTitle = expandAllDisabled ? "Expand all controllers (nothing to expand)" : "Expand all controllers";
1987
- return /* @__PURE__ */ jsx17(Panel, { position, className: "graph-toolbar-panel", style: panelStyle, children: /* @__PURE__ */ jsxs17("div", { className: `graph-toolbar graph-toolbar--${orientation}`, children: [
1988
- onFoldAll && /* @__PURE__ */ jsx17(
2226
+ return /* @__PURE__ */ jsx18(Panel, { position, className: "graph-toolbar-panel", style: panelStyle, children: /* @__PURE__ */ jsxs18("div", { className: `graph-toolbar graph-toolbar--${orientation}`, children: [
2227
+ validationState !== void 0 && /* @__PURE__ */ jsxs18(Fragment12, { children: [
2228
+ /* @__PURE__ */ jsxs18("div", { className: "graph-toolbar-validation", ref: validationRef, children: [
2229
+ /* @__PURE__ */ jsxs18(
2230
+ "button",
2231
+ {
2232
+ type: "button",
2233
+ className: `graph-toolbar-btn graph-toolbar-validation-btn graph-toolbar-validation-btn--${validationState}`,
2234
+ onClick: () => setValidationOpen((open) => !open),
2235
+ title: validationLabel(validationState, validationIssues.length),
2236
+ "aria-label": validationLabel(validationState, validationIssues.length),
2237
+ "aria-expanded": validationOpen,
2238
+ "aria-haspopup": "true",
2239
+ "aria-controls": validationPanelId,
2240
+ children: [
2241
+ validationIcon(validationState),
2242
+ validationIssues.length > 0 && /* @__PURE__ */ jsx18("span", { className: "graph-toolbar-validation-badge", children: validationIssues.length > 99 ? "99+" : validationIssues.length })
2243
+ ]
2244
+ }
2245
+ ),
2246
+ validationOpen && /* @__PURE__ */ jsx18(
2247
+ ValidationPanel,
2248
+ {
2249
+ id: validationPanelId,
2250
+ state: validationState,
2251
+ issues: validationIssues,
2252
+ onIssueClick: onValidationIssueClick,
2253
+ placement: validationPanelPlacement(position)
2254
+ }
2255
+ )
2256
+ ] }),
2257
+ /* @__PURE__ */ jsx18("div", { className: "graph-toolbar-separator" })
2258
+ ] }),
2259
+ onFoldAll && /* @__PURE__ */ jsx18(
1989
2260
  "button",
1990
2261
  {
1991
2262
  type: "button",
@@ -1997,7 +2268,7 @@ function GraphToolbar({
1997
2268
  children: FOLD_ALL_ICON
1998
2269
  }
1999
2270
  ),
2000
- onExpandAll && /* @__PURE__ */ jsx17(
2271
+ onExpandAll && /* @__PURE__ */ jsx18(
2001
2272
  "button",
2002
2273
  {
2003
2274
  type: "button",
@@ -2009,8 +2280,8 @@ function GraphToolbar({
2009
2280
  children: EXPAND_ALL_ICON
2010
2281
  }
2011
2282
  ),
2012
- foldAllSection && /* @__PURE__ */ jsx17("div", { className: "graph-toolbar-separator" }),
2013
- /* @__PURE__ */ jsx17(
2283
+ foldAllSection && /* @__PURE__ */ jsx18("div", { className: "graph-toolbar-separator" }),
2284
+ /* @__PURE__ */ jsx18(
2014
2285
  "button",
2015
2286
  {
2016
2287
  type: "button",
@@ -2021,7 +2292,7 @@ function GraphToolbar({
2021
2292
  children: BOXES_ICON
2022
2293
  }
2023
2294
  ),
2024
- /* @__PURE__ */ jsx17(
2295
+ /* @__PURE__ */ jsx18(
2025
2296
  "button",
2026
2297
  {
2027
2298
  type: "button",
@@ -2032,8 +2303,8 @@ function GraphToolbar({
2032
2303
  children: isVertical ? ARROW_RIGHT_ICON : ARROW_DOWN_ICON
2033
2304
  }
2034
2305
  ),
2035
- (onZoomOut || onZoomIn || onFitView) && /* @__PURE__ */ jsx17("div", { className: "graph-toolbar-separator" }),
2036
- onZoomOut && /* @__PURE__ */ jsx17(
2306
+ (onZoomOut || onZoomIn || onFitView) && /* @__PURE__ */ jsx18("div", { className: "graph-toolbar-separator" }),
2307
+ onZoomOut && /* @__PURE__ */ jsx18(
2037
2308
  "button",
2038
2309
  {
2039
2310
  type: "button",
@@ -2044,7 +2315,7 @@ function GraphToolbar({
2044
2315
  children: MINUS_ICON
2045
2316
  }
2046
2317
  ),
2047
- onZoomIn && /* @__PURE__ */ jsx17(
2318
+ onZoomIn && /* @__PURE__ */ jsx18(
2048
2319
  "button",
2049
2320
  {
2050
2321
  type: "button",
@@ -2055,7 +2326,7 @@ function GraphToolbar({
2055
2326
  children: PLUS_ICON
2056
2327
  }
2057
2328
  ),
2058
- onFitView && /* @__PURE__ */ jsx17(
2329
+ onFitView && /* @__PURE__ */ jsx18(
2059
2330
  "button",
2060
2331
  {
2061
2332
  type: "button",
@@ -2066,9 +2337,9 @@ function GraphToolbar({
2066
2337
  children: FIT_VIEW_ICON
2067
2338
  }
2068
2339
  ),
2069
- themeToggleEnabled && /* @__PURE__ */ jsxs17(Fragment12, { children: [
2070
- /* @__PURE__ */ jsx17("div", { className: "graph-toolbar-separator" }),
2071
- /* @__PURE__ */ jsx17(
2340
+ themeToggleEnabled && /* @__PURE__ */ jsxs18(Fragment12, { children: [
2341
+ /* @__PURE__ */ jsx18("div", { className: "graph-toolbar-separator" }),
2342
+ /* @__PURE__ */ jsx18(
2072
2343
  "button",
2073
2344
  {
2074
2345
  type: "button",
@@ -2084,7 +2355,7 @@ function GraphToolbar({
2084
2355
  }
2085
2356
 
2086
2357
  // src/graph/react/nodes/controller/ControllerGroupNode.tsx
2087
- import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
2358
+ import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
2088
2359
  var CONTROLLER_CONFIG = {
2089
2360
  PipeSequence: { badge: "Sequence", icon: "\u2192" },
2090
2361
  PipeParallel: { badge: "Parallel", icon: "//" },
@@ -2106,12 +2377,12 @@ function ControllerGroupNode({ data }) {
2106
2377
  const modifier = getControllerModifier(data.pipeType);
2107
2378
  const isCollapsible = (data.pipeType === "PipeParallel" || data.pipeType === "PipeBatch") && ((_a = data.childCount) != null ? _a : 0) > MAX_VISIBLE_CONTROLLER_CHILDREN;
2108
2379
  const hiddenCount = isCollapsible ? ((_b = data.childCount) != null ? _b : 0) - MAX_VISIBLE_CONTROLLER_CHILDREN : 0;
2109
- return /* @__PURE__ */ jsxs18("div", { className: `controller-group-node ${modifier}`, children: [
2110
- /* @__PURE__ */ jsxs18("div", { className: "controller-group-header", children: [
2111
- /* @__PURE__ */ jsx18("span", { className: "controller-group-icon", children: config.icon }),
2112
- /* @__PURE__ */ jsx18("span", { className: "controller-group-badge", children: config.badge }),
2113
- data.label && /* @__PURE__ */ jsx18("span", { className: "controller-group-label", children: data.label }),
2114
- data.onToggleFold && /* @__PURE__ */ jsx18(
2380
+ return /* @__PURE__ */ jsxs19("div", { className: `controller-group-node ${modifier}`, children: [
2381
+ /* @__PURE__ */ jsxs19("div", { className: "controller-group-header", children: [
2382
+ /* @__PURE__ */ jsx19("span", { className: "controller-group-icon", children: config.icon }),
2383
+ /* @__PURE__ */ jsx19("span", { className: "controller-group-badge", children: config.badge }),
2384
+ data.label && /* @__PURE__ */ jsx19("span", { className: "controller-group-label", children: data.label }),
2385
+ data.onToggleFold && /* @__PURE__ */ jsx19(
2115
2386
  "button",
2116
2387
  {
2117
2388
  type: "button",
@@ -2127,7 +2398,7 @@ function ControllerGroupNode({ data }) {
2127
2398
  }
2128
2399
  )
2129
2400
  ] }),
2130
- isCollapsible && /* @__PURE__ */ jsx18(
2401
+ isCollapsible && /* @__PURE__ */ jsx19(
2131
2402
  "button",
2132
2403
  {
2133
2404
  className: "controller-group-collapse",
@@ -2148,7 +2419,7 @@ import { Handle, Position } from "@xyflow/react";
2148
2419
 
2149
2420
  // src/graph/react/nodes/pipe/PipeCardBase.tsx
2150
2421
  import { useState as useState2 } from "react";
2151
- import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
2422
+ import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
2152
2423
  var PIPE_TYPE_BADGES2 = {
2153
2424
  PipeLLM: "LLM",
2154
2425
  PipeExtract: "Extract",
@@ -2185,11 +2456,15 @@ function getBadge(pipeType) {
2185
2456
  return PIPE_TYPE_BADGES2[pipeType];
2186
2457
  }
2187
2458
  function PipeCardBase({ data, children }) {
2459
+ var _a, _b;
2188
2460
  const badge = getBadge(data.pipeType);
2189
2461
  const statusConfig = STATUS_CONFIG[data.status];
2190
2462
  const isRunning = data.status === "running";
2191
2463
  const isController = isControllerType(data.pipeType);
2192
2464
  const isSignature = data.pipeType === "PipeSignature";
2465
+ const isStatic = data.graphMode === "static";
2466
+ const outcome = isStatic ? (_a = data.tags) == null ? void 0 : _a.outcome : void 0;
2467
+ const batchMultiplicity = isStatic ? (_b = data.tags) == null ? void 0 : _b.batch_multiplicity : void 0;
2193
2468
  const [inputsExpanded, setInputsExpanded] = useState2(false);
2194
2469
  const hasMany = data.inputs.length > MAX_VISIBLE_INPUTS;
2195
2470
  const visibleInputs = hasMany && !inputsExpanded ? data.inputs.slice(0, MAX_VISIBLE_INPUTS) : data.inputs;
@@ -2197,18 +2472,19 @@ function PipeCardBase({ data, children }) {
2197
2472
  const dirClass = data.direction === "TB" ? "pipe-card--tb" : "pipe-card--lr";
2198
2473
  const controllerClass = isController ? " pipe-card--controller" : "";
2199
2474
  const signatureClass = isSignature ? " pipe-card--signature" : "";
2475
+ const staticClass = isStatic ? " pipe-card--static" : "";
2200
2476
  const badgeClass = isController ? "pipe-card-badge pipe-card-badge--controller" : isSignature ? "pipe-card-badge pipe-card-badge--signature" : "pipe-card-badge";
2201
- return /* @__PURE__ */ jsxs19("div", { className: `pipe-card ${dirClass}${controllerClass}${signatureClass}`, children: [
2202
- /* @__PURE__ */ jsxs19("div", { className: "pipe-card-header", children: [
2203
- /* @__PURE__ */ jsx19("span", { className: badgeClass, children: badge }),
2204
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-code", title: data.pipeCode, children: data.pipeCode }),
2205
- /* @__PURE__ */ jsx19(
2477
+ return /* @__PURE__ */ jsxs20("div", { className: `pipe-card ${dirClass}${controllerClass}${signatureClass}${staticClass}`, children: [
2478
+ /* @__PURE__ */ jsxs20("div", { className: "pipe-card-header", children: [
2479
+ /* @__PURE__ */ jsx20("span", { className: badgeClass, children: badge }),
2480
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-code", title: data.pipeCode, children: data.pipeCode }),
2481
+ !isStatic && /* @__PURE__ */ jsx20(
2206
2482
  "span",
2207
2483
  {
2208
2484
  className: "pipe-card-status",
2209
2485
  style: { color: statusConfig.color },
2210
2486
  title: statusConfig.label,
2211
- children: /* @__PURE__ */ jsx19(
2487
+ children: /* @__PURE__ */ jsx20(
2212
2488
  "span",
2213
2489
  {
2214
2490
  className: `pipe-card-status-dot ${isRunning ? "pipe-card-status-dot--pulse" : ""}`,
@@ -2217,7 +2493,7 @@ function PipeCardBase({ data, children }) {
2217
2493
  )
2218
2494
  }
2219
2495
  ),
2220
- data.onExpand && /* @__PURE__ */ jsx19(
2496
+ data.onExpand && /* @__PURE__ */ jsx20(
2221
2497
  "button",
2222
2498
  {
2223
2499
  type: "button",
@@ -2225,31 +2501,38 @@ function PipeCardBase({ data, children }) {
2225
2501
  title: "Expand controller (alt/option: only this one)",
2226
2502
  "aria-label": "Expand controller",
2227
2503
  onClick: (e) => {
2228
- var _a;
2504
+ var _a2;
2229
2505
  e.stopPropagation();
2230
- (_a = data.onExpand) == null ? void 0 : _a.call(data, { soloMode: e.altKey });
2506
+ (_a2 = data.onExpand) == null ? void 0 : _a2.call(data, { soloMode: e.altKey });
2231
2507
  },
2232
2508
  children: "\u2922"
2233
2509
  }
2234
2510
  )
2235
2511
  ] }),
2236
- data.description && /* @__PURE__ */ jsx19("span", { className: "pipe-card-description", title: data.description, children: data.description }),
2237
- data.inputs.length > 0 && /* @__PURE__ */ jsxs19("div", { className: "pipe-card-io", children: [
2238
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-label", children: "INPUTS" }),
2239
- /* @__PURE__ */ jsxs19("div", { className: "pipe-card-io-pills", children: [
2240
- visibleInputs.map((input) => /* @__PURE__ */ jsxs19(
2512
+ (outcome || batchMultiplicity) && /* @__PURE__ */ jsxs20("div", { className: "pipe-card-annotations", children: [
2513
+ outcome && /* @__PURE__ */ jsxs20("span", { className: "pipe-card-annotation pipe-card-annotation--outcome", children: [
2514
+ "outcome: ",
2515
+ outcome
2516
+ ] }),
2517
+ batchMultiplicity && /* @__PURE__ */ jsx20("span", { className: "pipe-card-annotation pipe-card-annotation--batch", children: batchMultiplicity })
2518
+ ] }),
2519
+ data.description && /* @__PURE__ */ jsx20("span", { className: "pipe-card-description", title: data.description, children: data.description }),
2520
+ data.inputs.length > 0 && /* @__PURE__ */ jsxs20("div", { className: "pipe-card-io", children: [
2521
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-label", children: "INPUTS" }),
2522
+ /* @__PURE__ */ jsxs20("div", { className: "pipe-card-io-pills", children: [
2523
+ visibleInputs.map((input) => /* @__PURE__ */ jsxs20(
2241
2524
  "span",
2242
2525
  {
2243
2526
  className: "pipe-card-io-pill",
2244
2527
  title: `${input.name}: ${input.concept}`,
2245
2528
  children: [
2246
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-pill-name", children: input.name }),
2247
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-pill-concept", children: input.concept })
2529
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-pill-name", children: input.name }),
2530
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-pill-concept", children: input.concept })
2248
2531
  ]
2249
2532
  },
2250
2533
  input.name
2251
2534
  )),
2252
- hasMany && /* @__PURE__ */ jsx19(
2535
+ hasMany && /* @__PURE__ */ jsx20(
2253
2536
  "button",
2254
2537
  {
2255
2538
  className: "pipe-card-io-more",
@@ -2262,16 +2545,16 @@ function PipeCardBase({ data, children }) {
2262
2545
  )
2263
2546
  ] })
2264
2547
  ] }),
2265
- data.outputs.length > 0 && /* @__PURE__ */ jsxs19("div", { className: "pipe-card-io", children: [
2266
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-label", children: "OUTPUT" }),
2267
- /* @__PURE__ */ jsx19("div", { className: "pipe-card-io-pills", children: data.outputs.map((output) => /* @__PURE__ */ jsxs19(
2548
+ data.outputs.length > 0 && /* @__PURE__ */ jsxs20("div", { className: "pipe-card-io", children: [
2549
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-label", children: "OUTPUT" }),
2550
+ /* @__PURE__ */ jsx20("div", { className: "pipe-card-io-pills", children: data.outputs.map((output) => /* @__PURE__ */ jsxs20(
2268
2551
  "span",
2269
2552
  {
2270
2553
  className: "pipe-card-io-pill",
2271
2554
  title: `${output.name}: ${output.concept}`,
2272
2555
  children: [
2273
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-pill-name", children: output.name }),
2274
- /* @__PURE__ */ jsx19("span", { className: "pipe-card-io-pill-concept", children: output.concept })
2556
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-pill-name", children: output.name }),
2557
+ /* @__PURE__ */ jsx20("span", { className: "pipe-card-io-pill-concept", children: output.concept })
2275
2558
  ]
2276
2559
  },
2277
2560
  output.name
@@ -2301,11 +2584,11 @@ function getPipeCardComponent(pipeType) {
2301
2584
  }
2302
2585
 
2303
2586
  // src/graph/react/nodes/pipe/PipeCardNode.tsx
2304
- import { Fragment as Fragment13, jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
2587
+ import { Fragment as Fragment13, jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
2305
2588
  function PipeCardNode({ data }) {
2306
2589
  var _a;
2307
2590
  const Card = (_a = getPipeCardComponent(data.pipeType)) != null ? _a : PipeCardBase;
2308
- return /* @__PURE__ */ jsx20(Card, { data });
2591
+ return /* @__PURE__ */ jsx21(Card, { data });
2309
2592
  }
2310
2593
  function PipeCardRFNode({
2311
2594
  data,
@@ -2314,15 +2597,15 @@ function PipeCardRFNode({
2314
2597
  }) {
2315
2598
  const payload = data.pipeCardData;
2316
2599
  if (!payload) return null;
2317
- return /* @__PURE__ */ jsxs20(Fragment13, { children: [
2318
- /* @__PURE__ */ jsx20(Handle, { type: "target", position: targetPosition }),
2319
- /* @__PURE__ */ jsx20(PipeCardNode, { data: payload }),
2320
- /* @__PURE__ */ jsx20(Handle, { type: "source", position: sourcePosition })
2600
+ return /* @__PURE__ */ jsxs21(Fragment13, { children: [
2601
+ /* @__PURE__ */ jsx21(Handle, { type: "target", position: targetPosition }),
2602
+ /* @__PURE__ */ jsx21(PipeCardNode, { data: payload }),
2603
+ /* @__PURE__ */ jsx21(Handle, { type: "source", position: sourcePosition })
2321
2604
  ] });
2322
2605
  }
2323
2606
 
2324
2607
  // src/graph/react/viewer/GraphViewer.tsx
2325
- import { Fragment as Fragment14, jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
2608
+ import { Fragment as Fragment14, jsx as jsx22, jsxs as jsxs22 } from "react/jsx-runtime";
2326
2609
  var nodeTypes = __spreadProps(__spreadValues({}, controllerNodeTypes), {
2327
2610
  pipeCard: PipeCardRFNode
2328
2611
  });
@@ -2335,19 +2618,21 @@ function StuffNodeDetail({
2335
2618
  onOpenExternally
2336
2619
  }) {
2337
2620
  const conceptInfo = stuffData.concept && graphspec ? resolveConceptRef(graphspec, stuffData.concept) : void 0;
2338
- return /* @__PURE__ */ jsx21(Fragment14, { children: conceptInfo ? /* @__PURE__ */ jsx21(
2621
+ const isDryRun = graphSpecMode(graphspec) === GRAPH_SPEC_MODE.DRY;
2622
+ return /* @__PURE__ */ jsx22(Fragment14, { children: conceptInfo ? /* @__PURE__ */ jsx22(
2339
2623
  ConceptDetailPanel,
2340
2624
  {
2341
2625
  concept: conceptInfo,
2342
2626
  ioData: stuffData,
2627
+ isDryRun,
2343
2628
  instanceKey: nodeId,
2344
2629
  resolveStorageUrl,
2345
2630
  canEmbedPdf,
2346
2631
  onOpenExternally
2347
2632
  }
2348
- ) : (
2633
+ ) : isDryRun ? /* @__PURE__ */ jsx22("div", { className: "detail-not-available", children: "Dry run data hidden" }) : (
2349
2634
  /* Fallback: just show the StuffViewer if no concept info */
2350
- /* @__PURE__ */ jsx21(
2635
+ /* @__PURE__ */ jsx22(
2351
2636
  StuffViewer,
2352
2637
  {
2353
2638
  stuff: stuffData,
@@ -2383,11 +2668,14 @@ function cloneCachedNodes(nodes) {
2383
2668
  function applyStatusOverrides(nodes, statusMap) {
2384
2669
  if (!statusMap || Object.keys(statusMap).length === 0) return nodes;
2385
2670
  return nodes.map((node) => {
2386
- var _a;
2671
+ var _a, _b;
2672
+ if (node.data.graphMode === "static" || ((_a = node.data.pipeCardData) == null ? void 0 : _a.graphMode) === "static") {
2673
+ return node;
2674
+ }
2387
2675
  const pipeCode = node.data.pipeCode;
2388
2676
  if (!pipeCode || !Object.hasOwn(statusMap, pipeCode)) return node;
2389
2677
  const newStatus = statusMap[pipeCode];
2390
- if (((_a = node.data.pipeCardData) == null ? void 0 : _a.status) === newStatus) return node;
2678
+ if (((_b = node.data.pipeCardData) == null ? void 0 : _b.status) === newStatus) return node;
2391
2679
  return __spreadProps(__spreadValues({}, node), {
2392
2680
  data: __spreadProps(__spreadValues({}, node.data), {
2393
2681
  nodeData: node.data.nodeData ? __spreadProps(__spreadValues({}, node.data.nodeData), { status: newStatus }) : node.data.nodeData,
@@ -2419,22 +2707,25 @@ function GraphViewer(props) {
2419
2707
  renderDetailExtra,
2420
2708
  resolveStorageUrl,
2421
2709
  canEmbedPdf,
2422
- onOpenExternally
2710
+ onOpenExternally,
2711
+ validationState,
2712
+ validationIssues,
2713
+ onValidationIssueClick
2423
2714
  } = props;
2424
- const graphspec = React9.useMemo(
2715
+ const graphspec = React10.useMemo(
2425
2716
  () => graphspecProp === null ? null : validateGraphSpec(graphspecProp),
2426
2717
  [graphspecProp]
2427
2718
  );
2428
- const [direction, setDirection] = React9.useState(
2719
+ const [direction, setDirection] = React10.useState(
2429
2720
  () => {
2430
2721
  var _a2, _b2;
2431
2722
  return (_b2 = (_a2 = initialDirection != null ? initialDirection : config.direction) != null ? _a2 : DEFAULT_GRAPH_CONFIG.direction) != null ? _b2 : GRAPH_DIRECTION.TB;
2432
2723
  }
2433
2724
  );
2434
2725
  const externalMode = resolveExternalThemeMode(themeProp, config.theme);
2435
- const [mode, setMode] = React9.useState(externalMode);
2436
- const prevExternalModeRef = React9.useRef(externalMode);
2437
- React9.useEffect(() => {
2726
+ const [mode, setMode] = React10.useState(externalMode);
2727
+ const prevExternalModeRef = React10.useRef(externalMode);
2728
+ React10.useEffect(() => {
2438
2729
  if (externalMode !== prevExternalModeRef.current) {
2439
2730
  prevExternalModeRef.current = externalMode;
2440
2731
  setMode(externalMode);
@@ -2442,13 +2733,13 @@ function GraphViewer(props) {
2442
2733
  }, [externalMode]);
2443
2734
  const systemTheme = useSystemTheme(systemThemeProp);
2444
2735
  const resolvedTheme = resolveActiveTheme(mode, systemTheme);
2445
- const onThemeChangeRef = React9.useRef(onThemeChange);
2736
+ const onThemeChangeRef = React10.useRef(onThemeChange);
2446
2737
  onThemeChangeRef.current = onThemeChange;
2447
- const prevReportedRef = React9.useRef({
2738
+ const prevReportedRef = React10.useRef({
2448
2739
  mode,
2449
2740
  resolvedTheme
2450
2741
  });
2451
- React9.useEffect(() => {
2742
+ React10.useEffect(() => {
2452
2743
  var _a2;
2453
2744
  const prev = prevReportedRef.current;
2454
2745
  if (prev.mode !== mode || prev.resolvedTheme !== resolvedTheme) {
@@ -2457,26 +2748,26 @@ function GraphViewer(props) {
2457
2748
  }
2458
2749
  }, [mode, resolvedTheme]);
2459
2750
  const effectiveFoldMode = (_b = (_a = initialFoldMode != null ? initialFoldMode : config.foldMode) != null ? _a : DEFAULT_GRAPH_CONFIG.foldMode) != null ? _b : FOLD_MODE.EXPANDED;
2460
- const [showControllers, setShowControllers] = React9.useState(() => {
2751
+ const [showControllers, setShowControllers] = React10.useState(() => {
2461
2752
  var _a2, _b2;
2462
2753
  if (effectiveFoldMode === FOLD_MODE.FOLDED) return true;
2463
2754
  return (_b2 = (_a2 = initialShowControllers != null ? initialShowControllers : config.showControllers) != null ? _a2 : DEFAULT_GRAPH_CONFIG.showControllers) != null ? _b2 : false;
2464
2755
  });
2465
- const foldModeRef = React9.useRef(effectiveFoldMode);
2756
+ const foldModeRef = React10.useRef(effectiveFoldMode);
2466
2757
  foldModeRef.current = effectiveFoldMode;
2467
- const containerRef = React9.useRef(null);
2468
- const [detailSelection, setDetailSelection] = React9.useState(null);
2469
- const [conceptOverride, setConceptOverride] = React9.useState(null);
2758
+ const containerRef = React10.useRef(null);
2759
+ const [detailSelection, setDetailSelection] = React10.useState(null);
2760
+ const [conceptOverride, setConceptOverride] = React10.useState(null);
2470
2761
  const {
2471
2762
  width: panelWidth,
2472
2763
  isDragging: isPanelDragging,
2473
2764
  handleMouseDown: onResizeMouseDown
2474
2765
  } = useResizable({ defaultWidth: 380, minWidth: 280, maxWidth: 800, containerRef });
2475
- React9.useEffect(() => {
2766
+ React10.useEffect(() => {
2476
2767
  setDetailSelection(null);
2477
2768
  setConceptOverride(null);
2478
2769
  }, [graphspec]);
2479
- React9.useEffect(() => {
2770
+ React10.useEffect(() => {
2480
2771
  const el = containerRef.current;
2481
2772
  if (!el) return;
2482
2773
  const themePalette = getPaletteForTheme(resolvedTheme);
@@ -2493,12 +2784,12 @@ function GraphViewer(props) {
2493
2784
  }, [config.paletteColors, resolvedTheme]);
2494
2785
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
2495
2786
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
2496
- const reactFlowRef = React9.useRef(null);
2497
- const initialDataRef = React9.useRef(null);
2498
- const rawGraphDataRef = React9.useRef(null);
2499
- const layoutCacheRef = React9.useRef(null);
2500
- const [expandedControllers, setExpandedControllers] = React9.useState(/* @__PURE__ */ new Set());
2501
- const toggleCollapse = React9.useCallback((controllerId) => {
2787
+ const reactFlowRef = React10.useRef(null);
2788
+ const initialDataRef = React10.useRef(null);
2789
+ const rawGraphDataRef = React10.useRef(null);
2790
+ const layoutCacheRef = React10.useRef(null);
2791
+ const [expandedControllers, setExpandedControllers] = React10.useState(/* @__PURE__ */ new Set());
2792
+ const toggleCollapse = React10.useCallback((controllerId) => {
2502
2793
  setExpandedControllers((prev) => {
2503
2794
  const next = new Set(prev);
2504
2795
  if (next.has(controllerId)) next.delete(controllerId);
@@ -2506,8 +2797,8 @@ function GraphViewer(props) {
2506
2797
  return next;
2507
2798
  });
2508
2799
  }, []);
2509
- const [foldedControllers, setFoldedControllers] = React9.useState(/* @__PURE__ */ new Set());
2510
- const toggleFold = React9.useCallback((controllerId, options) => {
2800
+ const [foldedControllers, setFoldedControllers] = React10.useState(/* @__PURE__ */ new Set());
2801
+ const toggleFold = React10.useCallback((controllerId, options) => {
2511
2802
  setFoldedControllers((prev) => {
2512
2803
  const next = new Set(prev);
2513
2804
  const shouldFold = !next.has(controllerId);
@@ -2521,34 +2812,34 @@ function GraphViewer(props) {
2521
2812
  });
2522
2813
  }, []);
2523
2814
  const edgeType = config.edgeType || EDGE_TYPE.DEFAULT;
2524
- const layoutConfig = React9.useMemo(
2815
+ const layoutConfig = React10.useMemo(
2525
2816
  () => ({ nodesep: config.nodesep, ranksep: config.ranksep }),
2526
2817
  [config.nodesep, config.ranksep]
2527
2818
  );
2528
- const showControllersRef = React9.useRef(showControllers);
2819
+ const showControllersRef = React10.useRef(showControllers);
2529
2820
  showControllersRef.current = showControllers;
2530
- const directionRef = React9.useRef(direction);
2821
+ const directionRef = React10.useRef(direction);
2531
2822
  directionRef.current = direction;
2532
- const layoutConfigRef = React9.useRef(layoutConfig);
2823
+ const layoutConfigRef = React10.useRef(layoutConfig);
2533
2824
  layoutConfigRef.current = layoutConfig;
2534
- const initialZoomRef = React9.useRef(config.initialZoom);
2825
+ const initialZoomRef = React10.useRef(config.initialZoom);
2535
2826
  initialZoomRef.current = config.initialZoom;
2536
- const panToTopRef = React9.useRef(config.panToTop);
2827
+ const panToTopRef = React10.useRef(config.panToTop);
2537
2828
  panToTopRef.current = config.panToTop;
2538
- const expandedRef = React9.useRef(expandedControllers);
2829
+ const expandedRef = React10.useRef(expandedControllers);
2539
2830
  expandedRef.current = expandedControllers;
2540
- const toggleCollapseRef = React9.useRef(toggleCollapse);
2831
+ const toggleCollapseRef = React10.useRef(toggleCollapse);
2541
2832
  toggleCollapseRef.current = toggleCollapse;
2542
- const foldedRef = React9.useRef(foldedControllers);
2833
+ const foldedRef = React10.useRef(foldedControllers);
2543
2834
  foldedRef.current = foldedControllers;
2544
- const toggleFoldRef = React9.useRef(toggleFold);
2835
+ const toggleFoldRef = React10.useRef(toggleFold);
2545
2836
  toggleFoldRef.current = toggleFold;
2546
- const isFirstFoldEffect = React9.useRef(true);
2547
- const prevFoldSizeRef = React9.useRef(0);
2548
- const skipNextFoldEffectRef = React9.useRef(false);
2549
- const statusMapRef = React9.useRef(statusMap);
2837
+ const isFirstFoldEffect = React10.useRef(true);
2838
+ const prevFoldSizeRef = React10.useRef(0);
2839
+ const skipNextFoldEffectRef = React10.useRef(false);
2840
+ const statusMapRef = React10.useRef(statusMap);
2550
2841
  statusMapRef.current = statusMap;
2551
- React9.useEffect(() => {
2842
+ React10.useEffect(() => {
2552
2843
  if (!initialDataRef.current) return;
2553
2844
  let cancelled = false;
2554
2845
  void (async () => {
@@ -2600,7 +2891,7 @@ function GraphViewer(props) {
2600
2891
  cancelled = true;
2601
2892
  };
2602
2893
  }, [direction, layoutConfig]);
2603
- React9.useEffect(() => {
2894
+ React10.useEffect(() => {
2604
2895
  if (!layoutCacheRef.current || !initialDataRef.current) return;
2605
2896
  const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
2606
2897
  const cachedEdges = layoutCacheRef.current.edges;
@@ -2620,7 +2911,7 @@ function GraphViewer(props) {
2620
2911
  );
2621
2912
  setEdges(toAppEdges(withControllers.edges));
2622
2913
  }, [showControllers, expandedControllers, toggleCollapse, toggleFold]);
2623
- React9.useEffect(() => {
2914
+ React10.useEffect(() => {
2624
2915
  if (!graphspec) {
2625
2916
  initialDataRef.current = null;
2626
2917
  rawGraphDataRef.current = null;
@@ -2724,7 +3015,7 @@ function GraphViewer(props) {
2724
3015
  cancelled = true;
2725
3016
  };
2726
3017
  }, [graphspec, edgeType]);
2727
- React9.useEffect(() => {
3018
+ React10.useEffect(() => {
2728
3019
  if (isFirstFoldEffect.current) {
2729
3020
  isFirstFoldEffect.current = false;
2730
3021
  prevFoldSizeRef.current = foldedControllers.size;
@@ -2804,7 +3095,7 @@ function GraphViewer(props) {
2804
3095
  cancelled = true;
2805
3096
  };
2806
3097
  }, [foldedControllers, toggleFold]);
2807
- React9.useEffect(() => {
3098
+ React10.useEffect(() => {
2808
3099
  if (!layoutCacheRef.current || !initialDataRef.current) return;
2809
3100
  const cachedNodes = cloneCachedNodes(layoutCacheRef.current.nodes);
2810
3101
  const cachedEdges = layoutCacheRef.current.edges;
@@ -2822,7 +3113,7 @@ function GraphViewer(props) {
2822
3113
  setNodes(applyStatusOverrides(toAppNodes(hydrateLabels(withControllers.nodes)), statusMap));
2823
3114
  setEdges(toAppEdges(withControllers.edges));
2824
3115
  }, [statusMap]);
2825
- const onNodeClick = React9.useCallback(
3116
+ const onNodeClick = React10.useCallback(
2826
3117
  (event, node) => {
2827
3118
  var _a2;
2828
3119
  const nodeData = node.data;
@@ -2864,7 +3155,7 @@ function GraphViewer(props) {
2864
3155
  conceptOverride
2865
3156
  ]
2866
3157
  );
2867
- const onInit = React9.useCallback(
3158
+ const onInit = React10.useCallback(
2868
3159
  (reactFlowInstance) => {
2869
3160
  reactFlowRef.current = reactFlowInstance;
2870
3161
  if (onReactFlowInit) {
@@ -2873,12 +3164,12 @@ function GraphViewer(props) {
2873
3164
  },
2874
3165
  [onReactFlowInit]
2875
3166
  );
2876
- const handlePaneClick = React9.useCallback(() => {
3167
+ const handlePaneClick = React10.useCallback(() => {
2877
3168
  setDetailSelection(null);
2878
3169
  setConceptOverride(null);
2879
3170
  onPaneClick == null ? void 0 : onPaneClick();
2880
3171
  }, [onPaneClick]);
2881
- const handleConceptClick = React9.useCallback(
3172
+ const handleConceptClick = React10.useCallback(
2882
3173
  (conceptCode) => {
2883
3174
  if (!graphspec) return;
2884
3175
  const info = resolveConceptRef(graphspec, conceptCode);
@@ -2894,7 +3185,7 @@ function GraphViewer(props) {
2894
3185
  );
2895
3186
  const rawAnalysis = (_c = rawGraphDataRef.current) == null ? void 0 : _c.analysis;
2896
3187
  const allControllerIds = rawAnalysis == null ? void 0 : rawAnalysis.controllerNodeIds;
2897
- const foldAllProps = React9.useMemo(() => {
3188
+ const foldAllProps = React10.useMemo(() => {
2898
3189
  if (!showControllers || !allControllerIds || allControllerIds.size === 0) {
2899
3190
  return {
2900
3191
  onFoldAll: void 0,
@@ -2910,13 +3201,13 @@ function GraphViewer(props) {
2910
3201
  expandAllDisabled: foldedControllers.size === 0
2911
3202
  };
2912
3203
  }, [showControllers, allControllerIds, foldedControllers]);
2913
- return /* @__PURE__ */ jsxs21(
3204
+ return /* @__PURE__ */ jsxs22(
2914
3205
  "div",
2915
3206
  {
2916
3207
  ref: containerRef,
2917
3208
  className: `react-flow-container react-flow-container--theme-${resolvedTheme} react-flow-container--mode-${mode}`,
2918
3209
  children: [
2919
- /* @__PURE__ */ jsxs21(
3210
+ /* @__PURE__ */ jsxs22(
2920
3211
  ReactFlow,
2921
3212
  {
2922
3213
  nodes,
@@ -2935,7 +3226,7 @@ function GraphViewer(props) {
2935
3226
  proOptions: { hideAttribution: true },
2936
3227
  panActivationKeyCode: null,
2937
3228
  children: [
2938
- /* @__PURE__ */ jsx21(
3229
+ /* @__PURE__ */ jsx22(
2939
3230
  Background,
2940
3231
  {
2941
3232
  variant: BackgroundVariant.Dots,
@@ -2944,7 +3235,7 @@ function GraphViewer(props) {
2944
3235
  color: "var(--color-bg-dots)"
2945
3236
  }
2946
3237
  ),
2947
- !hideToolbar && /* @__PURE__ */ jsx21(
3238
+ !hideToolbar && /* @__PURE__ */ jsx22(
2948
3239
  GraphToolbar,
2949
3240
  {
2950
3241
  direction,
@@ -2970,13 +3261,16 @@ function GraphViewer(props) {
2970
3261
  themeMode: showThemeToggle ? mode : void 0,
2971
3262
  onThemeModeChange: showThemeToggle ? setMode : void 0,
2972
3263
  rightOffset: detailOpen ? panelWidth : 0,
2973
- position: effectiveToolbarPosition
3264
+ position: effectiveToolbarPosition,
3265
+ validationState,
3266
+ validationIssues,
3267
+ onValidationIssueClick
2974
3268
  }
2975
3269
  )
2976
3270
  ]
2977
3271
  }
2978
3272
  ),
2979
- /* @__PURE__ */ jsxs21(
3273
+ /* @__PURE__ */ jsxs22(
2980
3274
  DetailPanel,
2981
3275
  {
2982
3276
  isOpen: detailOpen,
@@ -2985,14 +3279,14 @@ function GraphViewer(props) {
2985
3279
  isDragging: isPanelDragging,
2986
3280
  onResizeHandleMouseDown: onResizeMouseDown,
2987
3281
  children: [
2988
- conceptOverride ? /* @__PURE__ */ jsx21(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx21(
3282
+ conceptOverride ? /* @__PURE__ */ jsx22(ConceptDetailPanel, { concept: conceptOverride }) : selectedSpecNode && graphspec ? /* @__PURE__ */ jsx22(
2989
3283
  PipeDetailPanel,
2990
3284
  {
2991
3285
  node: selectedSpecNode,
2992
3286
  spec: graphspec,
2993
3287
  onConceptClick: handleConceptClick
2994
3288
  }
2995
- ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx21(
3289
+ ) : (detailSelection == null ? void 0 : detailSelection.stuffData) ? /* @__PURE__ */ jsx22(
2996
3290
  StuffNodeDetail,
2997
3291
  {
2998
3292
  nodeId: detailSelection.nodeId,
@@ -3020,6 +3314,7 @@ export {
3020
3314
  PipeCardNode,
3021
3315
  PipeDetailPanel,
3022
3316
  StuffViewer,
3317
+ ValidationPanel,
3023
3318
  applyStatusOverrides,
3024
3319
  controllerNodeTypes,
3025
3320
  detectSystemTheme,
@@ -3037,6 +3332,8 @@ export {
3037
3332
  toAppEdges,
3038
3333
  toAppNodes,
3039
3334
  useResizable,
3040
- useSystemTheme
3335
+ useSystemTheme,
3336
+ validationLabel,
3337
+ validationPanelPlacement
3041
3338
  };
3042
3339
  //# sourceMappingURL=index.js.map