@bian-womp/spark-workbench 0.1.19 → 0.1.21

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/lib/cjs/index.cjs CHANGED
@@ -819,7 +819,10 @@ function useQueryParamString(key, defaultValue) {
819
819
 
820
820
  function resolveOutputDisplay(raw, declared) {
821
821
  if (sparkGraph.isTypedOutput(raw)) {
822
- return { typeId: String(raw.__spark_type), value: raw.__spark_value };
822
+ return {
823
+ typeId: sparkGraph.getTypedOutputTypeId(raw),
824
+ value: sparkGraph.getTypedOutputValue(raw),
825
+ };
823
826
  }
824
827
  let typeId = undefined;
825
828
  if (Array.isArray(declared)) {
@@ -841,7 +844,7 @@ function preformatValueForDisplay(typeId, value, registry) {
841
844
  return "";
842
845
  // Unwrap typed outputs
843
846
  if (sparkGraph.isTypedOutput(value)) {
844
- return preformatValueForDisplay(String(value.__spark_type), value.__spark_value, registry);
847
+ return preformatValueForDisplay(sparkGraph.getTypedOutputTypeId(value), sparkGraph.getTypedOutputValue(value), registry);
845
848
  }
846
849
  // Enums
847
850
  if (typeId && typeId.includes("enum:") && registry) {
@@ -885,7 +888,7 @@ function summarizeDeep(value) {
885
888
  }
886
889
  // Typed output wrapper
887
890
  if (sparkGraph.isTypedOutput(value)) {
888
- return summarizeDeep(value.__spark_value);
891
+ return summarizeDeep(sparkGraph.getTypedOutputValue(value));
889
892
  }
890
893
  // Arrays
891
894
  if (Array.isArray(value)) {
@@ -1078,6 +1081,21 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1078
1081
  const def = wb.export();
1079
1082
  const inputsMap = React.useMemo(() => runner.getInputs(def), [runner, def, valuesTick]);
1080
1083
  const outputsMap = React.useMemo(() => runner.getOutputs(def), [runner, def, valuesTick]);
1084
+ const outputTypesMap = React.useMemo(() => {
1085
+ const out = {};
1086
+ // Local: runtimeTypeId is not stored; derive from typed wrapper in outputsMap
1087
+ for (const n of def.nodes) {
1088
+ const handles = Object.keys(registry.nodes.get(n.typeId)?.outputs ?? {});
1089
+ const cur = {};
1090
+ for (const h of handles) {
1091
+ const v = outputsMap[n.nodeId]?.[h];
1092
+ cur[h] = sparkGraph.getTypedOutputTypeId(v);
1093
+ }
1094
+ if (Object.keys(cur).length > 0)
1095
+ out[n.nodeId] = cur;
1096
+ }
1097
+ return out;
1098
+ }, [def, outputsMap, registry]);
1081
1099
  // Initialize nodes as invalidated by default until first successful run
1082
1100
  React.useEffect(() => {
1083
1101
  setNodeStatus((prev) => {
@@ -1425,6 +1443,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1425
1443
  valuesTick,
1426
1444
  inputsMap,
1427
1445
  outputsMap,
1446
+ outputTypesMap,
1428
1447
  validationByNode,
1429
1448
  validationByEdge,
1430
1449
  validationGlobal,
@@ -1521,7 +1540,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1521
1540
  return String(value ?? "");
1522
1541
  }
1523
1542
  };
1524
- const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, } = useWorkbenchContext();
1543
+ const { registry, def, selectedNodeId, selectedEdgeId, inputsMap, outputsMap, outputTypesMap, nodeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, } = useWorkbenchContext();
1525
1544
  const nodeValidationIssues = validationByNode.issues;
1526
1545
  const edgeValidationIssues = validationByEdge.issues;
1527
1546
  const nodeValidationHandles = validationByNode;
@@ -1644,7 +1663,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1644
1663
  if (e.key === "Escape")
1645
1664
  revert();
1646
1665
  }, ...commonProps }))] }, h));
1647
- }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Outputs" }), outputHandles.length === 0 ? (jsxRuntime.jsx("div", { className: "text-gray-500", children: "No outputs" })) : (outputHandles.map((h) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("label", { className: "w-20", children: h }), jsxRuntime.jsx("div", { className: "flex-1", children: (() => {
1666
+ }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Outputs" }), outputHandles.length === 0 ? (jsxRuntime.jsx("div", { className: "text-gray-500", children: "No outputs" })) : (outputHandles.map((h) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsxs("label", { className: "w-20 flex flex-col", children: [jsxRuntime.jsx("span", { children: h }), jsxRuntime.jsx("span", { className: "text-gray-500 text-[11px]", children: outputTypesMap[selectedNodeId]?.[h] ?? "" })] }), jsxRuntime.jsx("div", { className: "flex-1", children: (() => {
1648
1667
  const { typeId, value } = resolveOutputDisplay(nodeOutputs[h], selectedDesc?.outputs?.[h]);
1649
1668
  return toElement(typeId, value);
1650
1669
  })() }), (() => {
@@ -1960,7 +1979,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement }, r
1960
1979
  return (jsxRuntime.jsx("div", { className: "w-full h-full", onContextMenu: onContextMenu, children: jsxRuntime.jsxs(ReactFlow, { nodes: nodes, edges: edges, nodeTypes: nodeTypes, selectionOnDrag: true, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onSelectionChange: onSelectionChange, deleteKeyCode: ["Backspace", "Delete"], fitView: true, onInit: (inst) => (rfInstanceRef.current = inst), children: [jsxRuntime.jsx(ReactFlow.Background, {}), jsxRuntime.jsx(ReactFlow.MiniMap, {}), jsxRuntime.jsx(ReactFlow.Controls, {}), jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, onAdd: addNodeAt, onClose: () => setMenuOpen(false) }), jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, onClose: () => setNodeMenuOpen(false) })] }) }));
1961
1980
  });
1962
1981
 
1963
- function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, }) {
1982
+ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
1964
1983
  const { wb, runner, registry, def, selectedNodeId, runAutoLayout } = useWorkbenchContext();
1965
1984
  const selectedNode = def.nodes.find((n) => n.nodeId === selectedNodeId);
1966
1985
  const selectedDesc = selectedNode
@@ -2009,6 +2028,54 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2009
2028
  const lastAutoLaunched = React.useRef(undefined);
2010
2029
  const autoLayoutRan = React.useRef(false);
2011
2030
  const canvasRef = React.useRef(null);
2031
+ // Expose init callback with setInitialGraph helper
2032
+ const initCalled = React.useRef(false);
2033
+ React.useEffect(() => {
2034
+ if (initCalled.current)
2035
+ return;
2036
+ initCalled.current = true;
2037
+ if (!onInit)
2038
+ return;
2039
+ const setInitialGraph = async (d, inputs) => {
2040
+ await wb.load(d);
2041
+ try {
2042
+ runner.build(wb.export());
2043
+ }
2044
+ catch { }
2045
+ if (inputs) {
2046
+ for (const [nodeId, map] of Object.entries(inputs)) {
2047
+ runner.setInputs(nodeId, map);
2048
+ }
2049
+ }
2050
+ runAutoLayout();
2051
+ };
2052
+ onInit({ wb, runner, setInitialGraph });
2053
+ }, [onInit, wb, runner, runAutoLayout]);
2054
+ // Expose change callback on graph/value changes
2055
+ React.useEffect(() => {
2056
+ if (!onChange)
2057
+ return;
2058
+ const off1 = wb.on("graphChanged", () => {
2059
+ try {
2060
+ const cur = wb.export();
2061
+ const inputs = runner.getInputs(cur);
2062
+ onChange({ def: cur, inputs });
2063
+ }
2064
+ catch { }
2065
+ });
2066
+ const off2 = runner.on("value", () => {
2067
+ try {
2068
+ const cur = wb.export();
2069
+ const inputs = runner.getInputs(cur);
2070
+ onChange({ def: cur, inputs });
2071
+ }
2072
+ catch { }
2073
+ });
2074
+ return () => {
2075
+ off1();
2076
+ off2();
2077
+ };
2078
+ }, [wb, runner, onChange]);
2012
2079
  const applyExample = React.useCallback(async (key) => {
2013
2080
  if (runner.isRunning()) {
2014
2081
  alert(`Stop engine before switching example.`);
@@ -2260,7 +2327,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2260
2327
  return "";
2261
2328
  // Normalize typed wrapper
2262
2329
  if (sparkGraph.isTypedOutput(value)) {
2263
- return baseToString(String(value.__spark_type), value.__spark_value);
2330
+ return baseToString(sparkGraph.getTypedOutputTypeId(value), sparkGraph.getTypedOutputValue(value));
2264
2331
  }
2265
2332
  const pre = preformatValueForDisplay(typeId, value, registry);
2266
2333
  if (pre !== undefined)
@@ -2352,7 +2419,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2352
2419
  }
2353
2420
  }, disabled: !engine, children: "Start" })), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded px-2 py-1.5", onClick: runAutoLayout, children: "Auto Layout" }), jsxRuntime.jsx("button", { className: "ml-2 border border-gray-300 rounded px-2 py-1.5", onClick: () => canvasRef.current?.fitView?.(), title: "Fit View", children: "Fit View" }), jsxRuntime.jsx("button", { className: "ml-2 border border-gray-300 rounded px-2 py-1.5", onClick: downloadGraph, children: "Download Graph" }), jsxRuntime.jsxs("label", { className: "ml-2 flex items-center gap-1", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: debug, onChange: (e) => onDebugChange(e.target.checked) }), jsxRuntime.jsx("span", { children: "Debug events" })] }), jsxRuntime.jsxs("label", { className: "ml-2 flex items-center gap-1", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: showValues, onChange: (e) => onShowValuesChange(e.target.checked) }), jsxRuntime.jsx("span", { children: "Show values in nodes" })] })] }), jsxRuntime.jsxs("div", { className: "flex flex-1 min-h-0", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: jsxRuntime.jsx(WorkbenchCanvas, { ref: canvasRef, showValues: showValues, toString: toString, toElement: toElement }) }), jsxRuntime.jsx(Inspector, { setInput: setInput, debug: debug, autoScroll: autoScroll, hideWorkbench: hideWorkbench, onAutoScrollChange: onAutoScrollChange, onHideWorkbenchChange: onHideWorkbenchChange, toString: toString, toElement: toElement })] })] }));
2354
2421
  }
2355
- function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, overrides, }) {
2422
+ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, overrides, onInit, onChange, }) {
2356
2423
  const [registry, setRegistry] = React.useState(sparkGraph.createSimpleGraphRegistry());
2357
2424
  const [wb] = React.useState(() => new InMemoryWorkbench({ ui: new DefaultUIExtensionRegistry() }));
2358
2425
  const runner = React.useMemo(() => {
@@ -2373,7 +2440,7 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
2373
2440
  if (runner.isRunning())
2374
2441
  runner.dispose();
2375
2442
  onBackendKindChange(v);
2376
- }, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides }) }));
2443
+ }, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides, onInit: onInit, onChange: onChange }) }));
2377
2444
  }
2378
2445
 
2379
2446
  exports.AbstractWorkbench = AbstractWorkbench;