@bian-womp/spark-workbench 0.2.51 → 0.2.53

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
@@ -103,6 +103,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
103
103
  nodes: [],
104
104
  edges: [],
105
105
  };
106
+ this.viewport = null;
106
107
  }
107
108
  setRegistry(registry) {
108
109
  this.registry = registry;
@@ -260,6 +261,43 @@ class InMemoryWorkbench extends AbstractWorkbench {
260
261
  edges: [...this.selection.edges],
261
262
  };
262
263
  }
264
+ setViewport(viewport) {
265
+ this.viewport = { ...viewport };
266
+ }
267
+ getViewport() {
268
+ return this.viewport ? { ...this.viewport } : null;
269
+ }
270
+ getUIState() {
271
+ return {
272
+ positions: Object.keys(this.positions).length > 0
273
+ ? { ...this.positions }
274
+ : undefined,
275
+ selection: this.selection.nodes.length > 0 || this.selection.edges.length > 0
276
+ ? {
277
+ nodes: [...this.selection.nodes],
278
+ edges: [...this.selection.edges],
279
+ }
280
+ : undefined,
281
+ viewport: this.viewport ? { ...this.viewport } : undefined,
282
+ };
283
+ }
284
+ setUIState(ui) {
285
+ if (!ui)
286
+ return;
287
+ if (ui.positions) {
288
+ this.positions = { ...ui.positions };
289
+ }
290
+ if (ui.selection) {
291
+ this.selection = {
292
+ nodes: [...ui.selection.nodes],
293
+ edges: [...ui.selection.edges],
294
+ };
295
+ this.emit("selectionChanged", this.selection);
296
+ }
297
+ if (ui.viewport) {
298
+ this.viewport = { ...ui.viewport };
299
+ }
300
+ }
263
301
  on(event, handler) {
264
302
  if (!this.listeners.has(event))
265
303
  this.listeners.set(event, new Set());
@@ -1044,6 +1082,10 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1044
1082
  return value;
1045
1083
  }
1046
1084
  }
1085
+ async setExtData(data) {
1086
+ const client = await this.ensureClient();
1087
+ await client.setExtData(data);
1088
+ }
1047
1089
  async snapshotFull() {
1048
1090
  const client = await this.ensureClient();
1049
1091
  try {
@@ -3284,10 +3326,14 @@ function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
3284
3326
  });
3285
3327
  nodeIds.push(newId);
3286
3328
  }
3287
- runner.update(wb.export());
3288
- await runner.whenIdle();
3289
- for (let idx = 0; idx < coercedItems.length; idx++) {
3290
- runner.setInputs(nodeIds[idx], { [elemTarget.inputHandle]: coercedItems[idx] });
3329
+ if (nodeIds.length > 0) {
3330
+ runner.update(wb.export());
3331
+ await runner.whenIdle();
3332
+ for (let idx = 0; idx < coercedItems.length; idx++) {
3333
+ runner.setInputs(nodeIds[idx], {
3334
+ [elemTarget.inputHandle]: coercedItems[idx],
3335
+ });
3336
+ }
3291
3337
  }
3292
3338
  return;
3293
3339
  }
@@ -3608,18 +3654,48 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
3608
3654
  const addNodeAt = React.useCallback((typeId, pos) => {
3609
3655
  wb.addNode({ typeId, position: pos });
3610
3656
  }, [wb]);
3611
- React.useCallback((inst) => {
3612
- rfInstanceRef.current = inst;
3613
- }, []);
3614
3657
  const onCloseMenu = React.useCallback(() => {
3615
3658
  setMenuOpen(false);
3616
3659
  }, []);
3617
3660
  const onCloseNodeMenu = React.useCallback(() => {
3618
3661
  setNodeMenuOpen(false);
3619
3662
  }, []);
3663
+ const onMoveEnd = React.useCallback(() => {
3664
+ if (rfInstanceRef.current) {
3665
+ const viewport = rfInstanceRef.current.getViewport();
3666
+ wb.setViewport({ x: viewport.x, y: viewport.y, zoom: viewport.zoom });
3667
+ }
3668
+ }, [wb]);
3669
+ const viewportRef = React.useRef(null);
3670
+ React.useEffect(() => {
3671
+ if (!rfInstanceRef.current)
3672
+ return;
3673
+ const currentViewport = wb.getViewport();
3674
+ if (currentViewport &&
3675
+ (!viewportRef.current ||
3676
+ viewportRef.current.x !== currentViewport.x ||
3677
+ viewportRef.current.y !== currentViewport.y ||
3678
+ viewportRef.current.zoom !== currentViewport.zoom)) {
3679
+ viewportRef.current = currentViewport;
3680
+ rfInstanceRef.current.setViewport({
3681
+ x: currentViewport.x,
3682
+ y: currentViewport.y,
3683
+ zoom: currentViewport.zoom,
3684
+ });
3685
+ }
3686
+ });
3620
3687
  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, selectionOnDrag: true, onInit: (inst) => {
3621
3688
  rfInstanceRef.current = inst;
3622
- }, 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, { id: "workbench-canvas-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: onCloseMenu }), !!nodeAtMenu && (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, onClose: onCloseNodeMenu }))] }) }) }));
3689
+ const savedViewport = wb.getViewport();
3690
+ if (savedViewport) {
3691
+ viewportRef.current = savedViewport;
3692
+ inst.setViewport({
3693
+ x: savedViewport.x,
3694
+ y: savedViewport.y,
3695
+ zoom: savedViewport.zoom,
3696
+ });
3697
+ }
3698
+ }, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", fitView: true, children: [jsxRuntime.jsx(react.Background, { id: "workbench-canvas-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: onCloseMenu }), !!nodeAtMenu && (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, onClose: onCloseNodeMenu }))] }) }) }));
3623
3699
  });
3624
3700
 
3625
3701
  function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
@@ -3709,8 +3785,6 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3709
3785
  return overrides.getExamples(defaultExamples);
3710
3786
  return defaultExamples;
3711
3787
  }, [overrides, defaultExamples]);
3712
- const lastAutoLaunched = React.useRef(undefined);
3713
- const autoLayoutRan = React.useRef(false);
3714
3788
  const canvasRef = React.useRef(null);
3715
3789
  const uploadInputRef = React.useRef(null);
3716
3790
  const [registryReady, setRegistryReady] = React.useState(() => {
@@ -3735,7 +3809,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3735
3809
  }
3736
3810
  };
3737
3811
  onInit({ wb, runner, setInitialGraph });
3738
- }, [onInit, wb, runner, runAutoLayout, registry, setRegistry]);
3812
+ }, [onInit, wb, runner]);
3739
3813
  // Expose change callback on graph/value changes
3740
3814
  React.useEffect(() => {
3741
3815
  if (!onChange)
@@ -3870,7 +3944,6 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3870
3944
  }
3871
3945
  }
3872
3946
  }
3873
- runAutoLayout();
3874
3947
  }
3875
3948
  catch (err) {
3876
3949
  const message = err instanceof Error ? err.message : String(err);
@@ -3881,7 +3954,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3881
3954
  if (uploadInputRef.current)
3882
3955
  uploadInputRef.current.value = "";
3883
3956
  }
3884
- }, [wb, runner, runAutoLayout]);
3957
+ }, [wb, runner]);
3885
3958
  const triggerUpload = React.useCallback(() => {
3886
3959
  uploadInputRef.current?.click();
3887
3960
  }, []);
@@ -3923,32 +3996,13 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
3923
3996
  const d = wb.export();
3924
3997
  if (!d.nodes || d.nodes.length === 0)
3925
3998
  return;
3926
- if (lastAutoLaunched.current === engine)
3927
- return;
3928
3999
  try {
3929
4000
  runner.launch(d, { engine: engine });
3930
- lastAutoLaunched.current = engine;
3931
4001
  }
3932
4002
  catch {
3933
4003
  // ignore
3934
4004
  }
3935
4005
  }, [engine, runner, isGraphRunning, wb, backendKind]);
3936
- // Registry is automatically fetched by RemoteGraphRunner when it connects
3937
- // Run auto layout after registry is hydrated (for remote backends)
3938
- React.useEffect(() => {
3939
- if (autoLayoutRan.current)
3940
- return;
3941
- // Wait for registry to be ready for remote backends
3942
- if (backendKind !== "local" && !registryReady)
3943
- return;
3944
- const cur = wb.export();
3945
- const positions = wb.getPositions();
3946
- const allMissing = cur.nodes.every((n) => !positions[n.nodeId]);
3947
- if (allMissing) {
3948
- autoLayoutRan.current = true;
3949
- runAutoLayout();
3950
- }
3951
- }, [wb, runAutoLayout, backendKind, registryReady, registry]);
3952
4006
  const baseSetInput = React.useCallback((handle, raw) => {
3953
4007
  if (!selectedNodeId)
3954
4008
  return;