@bian-womp/spark-workbench 0.2.3 → 0.2.5

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.
Files changed (37) hide show
  1. package/lib/cjs/index.cjs +26 -9
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/misc/DefaultContextMenu.d.ts.map +1 -1
  4. package/lib/cjs/src/misc/WorkbenchCanvas.d.ts +4 -0
  5. package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  6. package/lib/cjs/src/misc/WorkbenchStudio.d.ts +4 -0
  7. package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
  8. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +1 -0
  9. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  10. package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  11. package/lib/cjs/src/misc/mapping.d.ts +4 -0
  12. package/lib/cjs/src/misc/mapping.d.ts.map +1 -1
  13. package/lib/cjs/src/runtime/AbstractGraphRunner.d.ts +1 -0
  14. package/lib/cjs/src/runtime/AbstractGraphRunner.d.ts.map +1 -1
  15. package/lib/cjs/src/runtime/IGraphRunner.d.ts +1 -0
  16. package/lib/cjs/src/runtime/IGraphRunner.d.ts.map +1 -1
  17. package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts +1 -0
  18. package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
  19. package/lib/esm/index.js +27 -10
  20. package/lib/esm/index.js.map +1 -1
  21. package/lib/esm/src/misc/DefaultContextMenu.d.ts.map +1 -1
  22. package/lib/esm/src/misc/WorkbenchCanvas.d.ts +4 -0
  23. package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  24. package/lib/esm/src/misc/WorkbenchStudio.d.ts +4 -0
  25. package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
  26. package/lib/esm/src/misc/context/WorkbenchContext.d.ts +1 -0
  27. package/lib/esm/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  28. package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  29. package/lib/esm/src/misc/mapping.d.ts +4 -0
  30. package/lib/esm/src/misc/mapping.d.ts.map +1 -1
  31. package/lib/esm/src/runtime/AbstractGraphRunner.d.ts +1 -0
  32. package/lib/esm/src/runtime/AbstractGraphRunner.d.ts.map +1 -1
  33. package/lib/esm/src/runtime/IGraphRunner.d.ts +1 -0
  34. package/lib/esm/src/runtime/IGraphRunner.d.ts.map +1 -1
  35. package/lib/esm/src/runtime/RemoteGraphRunner.d.ts +1 -0
  36. package/lib/esm/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
  37. package/package.json +4 -4
package/lib/cjs/index.cjs CHANGED
@@ -350,6 +350,9 @@ class AbstractGraphRunner {
350
350
  this.emit("value", { nodeId, handle, value, io: "input" });
351
351
  }
352
352
  }
353
+ triggerExternal(nodeId, event) {
354
+ this.engine?.triggerExternal(nodeId, event);
355
+ }
353
356
  // Batch update multiple inputs on a node and trigger a single run
354
357
  setInputs(nodeId, inputs) {
355
358
  if (!inputs)
@@ -667,6 +670,14 @@ class RemoteGraphRunner extends AbstractGraphRunner {
667
670
  flush() {
668
671
  console.warn("Unsupported operation for remote runner");
669
672
  }
673
+ triggerExternal(nodeId, event) {
674
+ this.ensureRemoteRunner().then(async (runner) => {
675
+ try {
676
+ await runner.getEngine().triggerExternal(nodeId, event);
677
+ }
678
+ catch { }
679
+ });
680
+ }
670
681
  getOutputs(def) {
671
682
  const out = {};
672
683
  const cache = this.valueCache;
@@ -1111,8 +1122,10 @@ function toReactFlow(def, positions, registry, opts) {
1111
1122
  const HEADER_SIZE = NODE_HEADER_HEIGHT_PX;
1112
1123
  const ROW_SIZE = NODE_ROW_HEIGHT_PX;
1113
1124
  const maxRows = Math.max(inputHandles.length, outputHandles.length);
1114
- const initialWidth = opts.showValues ? 320 : 240;
1115
- const initialHeight = HEADER_SIZE + maxRows * ROW_SIZE;
1125
+ // Allow external override to dictate initial size
1126
+ const overrideSize = opts.getDefaultNodeSize?.(n.typeId);
1127
+ const initialWidth = overrideSize?.width ?? (opts.showValues ? 320 : 240);
1128
+ const initialHeight = overrideSize?.height ?? HEADER_SIZE + maxRows * ROW_SIZE;
1116
1129
  // Precompute handle bounds so edges can render immediately without waiting for measurement
1117
1130
  const handles = [
1118
1131
  // Inputs on the left as targets
@@ -1381,8 +1394,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1381
1394
  layers.push(layer);
1382
1395
  q.splice(0, q.length, ...next);
1383
1396
  }
1384
- const X = 960;
1385
- const Y = 480;
1397
+ const X = 720;
1398
+ const Y = 600;
1386
1399
  const pos = {};
1387
1400
  layers.forEach((layer, layerIndex) => {
1388
1401
  layer.forEach((id, itemIndex) => {
@@ -1392,6 +1405,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1392
1405
  wb.setPositions(pos);
1393
1406
  }, [wb]);
1394
1407
  const updateEdgeType = React.useCallback((edgeId, typeId) => wb.updateEdgeType(edgeId, typeId), [wb]);
1408
+ const triggerExternal = React.useCallback((nodeId, event) => runner.triggerExternal(nodeId, event), [runner]);
1395
1409
  // Subscribe to runner/workbench events
1396
1410
  React.useEffect(() => {
1397
1411
  const add = (source, type) => (payload) => setEvents((prev) => {
@@ -1726,6 +1740,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1726
1740
  flush,
1727
1741
  runAutoLayout,
1728
1742
  updateEdgeType,
1743
+ triggerExternal,
1729
1744
  }), [
1730
1745
  wb,
1731
1746
  runner,
@@ -1753,6 +1768,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1753
1768
  flush,
1754
1769
  runAutoLayout,
1755
1770
  wb,
1771
+ runner,
1756
1772
  ]);
1757
1773
  return (jsxRuntime.jsx(WorkbenchContext.Provider, { value: value, children: children }));
1758
1774
  }
@@ -2123,10 +2139,10 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
2123
2139
  onClose();
2124
2140
  };
2125
2141
  const renderTree = (tree, path = []) => {
2126
- const entries = Object.entries(tree.__children).sort((a, b) => a[0].localeCompare(b[0]));
2142
+ const entries = Object.entries(tree?.__children ?? {}).sort((a, b) => a[0].localeCompare(b[0]));
2127
2143
  return (jsxRuntime.jsx("div", { children: entries.map(([key, child]) => {
2128
2144
  const label = key;
2129
- const hasChildren = Object.keys(child.__children).length > 0;
2145
+ const hasChildren = !!child?.__children && Object.keys(child.__children).length > 0;
2130
2146
  const idKey = [...path, key].join(".");
2131
2147
  if (!hasChildren) {
2132
2148
  // Leaf: render only the action button, no group header
@@ -2213,7 +2229,7 @@ function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
2213
2229
  }, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Node (", nodeId, ")"] }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDelete, children: "Delete" }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleDuplicate, children: "Duplicate" }), canRunPull && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleRunPull, children: "Run (pull)" })), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handleCopyId, children: "Copy Node ID" })] }));
2214
2230
  }
2215
2231
 
2216
- const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement }, ref) => {
2232
+ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
2217
2233
  const { wb, registry, inputsMap, outputsMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, } = useWorkbenchContext();
2218
2234
  const nodeValidation = validationByNode;
2219
2235
  const edgeValidation = validationByEdge.errors;
@@ -2316,6 +2332,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement }, r
2316
2332
  edgeValidation,
2317
2333
  selectedNodeIds: new Set(sel.nodes),
2318
2334
  selectedEdgeIds: new Set(sel.edges),
2335
+ getDefaultNodeSize,
2319
2336
  });
2320
2337
  // Retain references for unchanged items
2321
2338
  const stableNodes = retainStabilityById(prevNodesRef.current, out.nodes, isSameNode);
@@ -2442,7 +2459,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement }, r
2442
2459
  const addNodeAt = (typeId, pos) => {
2443
2460
  wb.addNode({ typeId, position: pos });
2444
2461
  };
2445
- return (jsxRuntime.jsx("div", { className: "w-full h-full", onContextMenu: onContextMenu, children: jsxRuntime.jsxs(react.ReactFlow, { nodes: throttled.nodes, edges: throttled.edges, nodeTypes: nodeTypes, onlyRenderVisibleElements: true, selectionOnDrag: true, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, deleteKeyCode: ["Backspace", "Delete"], fitView: true, onInit: (inst) => (rfInstanceRef.current = inst), children: [jsxRuntime.jsx(react.Background, {}), jsxRuntime.jsx(react.MiniMap, {}), jsxRuntime.jsx(react.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) })] }) }));
2462
+ return (jsxRuntime.jsx("div", { className: "w-full h-full", onContextMenu: onContextMenu, children: jsxRuntime.jsx(react.ReactFlowProvider, { children: jsxRuntime.jsxs(react.ReactFlow, { nodes: throttled.nodes, edges: throttled.edges, nodeTypes: nodeTypes, onlyRenderVisibleElements: true, selectionOnDrag: true, onInit: (inst) => (rfInstanceRef.current = inst), onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", fitView: true, children: [jsxRuntime.jsx(react.Background, { variant: react.BackgroundVariant.Dots, gap: 12, size: 1 }), jsxRuntime.jsx(react.MiniMap, {}), jsxRuntime.jsx(react.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) })] }) }) }));
2446
2463
  });
2447
2464
 
2448
2465
  function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
@@ -2896,7 +2913,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2896
2913
  catch (err) {
2897
2914
  alert(String(err?.message ?? err));
2898
2915
  }
2899
- }, 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, contextPanel: overrides?.contextPanel })] })] }));
2916
+ }, 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, getDefaultNodeSize: overrides?.getDefaultNodeSize }) }), jsxRuntime.jsx(Inspector, { setInput: setInput, debug: debug, autoScroll: autoScroll, hideWorkbench: hideWorkbench, onAutoScrollChange: onAutoScrollChange, onHideWorkbenchChange: onHideWorkbenchChange, toString: toString, toElement: toElement, contextPanel: overrides?.contextPanel })] })] }));
2900
2917
  }
2901
2918
  function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, overrides, onInit, onChange, }) {
2902
2919
  const [registry, setRegistry] = React.useState(sparkGraph.createSimpleGraphRegistry());