@kiberon-labs/behave-graph-flow 1.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.fallowrc.json +16 -0
- package/.storybook/main.ts +32 -0
- package/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +64 -0
- package/.storybook/styles.css +16 -0
- package/.turbo/turbo-build.log +7 -0
- package/CHANGELOG.md +368 -0
- package/LICENSE +6 -0
- package/README.md +2 -2
- package/data/Polynomial.json +510 -0
- package/data/sequence.json +337 -0
- package/data/trigger-event.json +241 -0
- package/data/variable-change.json +210 -0
- package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
- package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
- package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
- package/dist/entry.css +4 -0
- package/dist/index.css +42 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +3597 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18009 -0
- package/dist/index.js.map +1 -0
- package/dist/noteImpl-KkrrWgJd.js +242 -0
- package/dist/noteImpl-KkrrWgJd.js.map +1 -0
- package/dist/styles.module-CvmpDkZj.css +3 -0
- package/dist/styles.module-CvmpDkZj.css.map +1 -0
- package/dist/styles.module-DZxg8aW9.js +271 -0
- package/dist/styles.module-DZxg8aW9.js.map +1 -0
- package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
- package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
- package/docs/notifications.md +246 -0
- package/docs/protocol.md +702 -0
- package/docs/specifics.md +191 -0
- package/package.json +82 -22
- package/postcss.config.ts +3 -4
- package/src/annotations/index.ts +32 -0
- package/src/components/FloatingToolbar/index.module.css +37 -0
- package/src/components/FloatingToolbar/index.tsx +256 -0
- package/src/components/Flow.tsx +287 -75
- package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
- package/src/components/contextMenus/NodePicker.module.css +274 -0
- package/src/components/contextMenus/NodePicker.tsx +481 -0
- package/src/components/contextMenus/edge.tsx +22 -0
- package/src/components/contextMenus/node.tsx +15 -0
- package/src/components/contextMenus/selection.tsx +11 -0
- package/src/components/controls/any/AnyControlImpl.tsx +14 -0
- package/src/components/controls/any/index.tsx +19 -0
- package/src/components/controls/boolean/index.tsx +13 -0
- package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
- package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
- package/src/components/controls/colorPicker/index.module.css +18 -0
- package/src/components/controls/colorPicker/index.tsx +61 -0
- package/src/components/controls/number/index.tsx +35 -0
- package/src/components/controls/string/index.tsx +16 -0
- package/src/components/edges/index.tsx +475 -0
- package/src/components/edges/offsetBezier.ts +134 -0
- package/src/components/hotKeys.tsx +20 -0
- package/src/components/layoutController/index.module.css +13 -0
- package/src/components/layoutController/index.tsx +140 -0
- package/src/components/layoutController/utils.ts +248 -0
- package/src/components/menubar/defaults.tsx +516 -0
- package/src/components/menubar/index.tsx +49 -0
- package/src/components/menubar/menuItem.module.css +31 -0
- package/src/components/menubar/menuItem.tsx +65 -0
- package/src/components/nodes/behave/Node.module.css +23 -0
- package/src/components/nodes/behave/Node.tsx +176 -0
- package/src/components/nodes/behave/NodeContainer.module.css +88 -0
- package/src/components/nodes/behave/NodeContainer.tsx +46 -0
- package/src/components/nodes/behave/index.tsx +14 -0
- package/src/components/nodes/group/index.tsx +109 -0
- package/src/components/nodes/wrapper/index.tsx +73 -0
- package/src/components/nodes/wrapper/styles.module.css +87 -0
- package/src/components/notifications/NotificationProvider.tsx +81 -0
- package/src/components/notifications/index.ts +2 -0
- package/src/components/notifications/utils.ts +71 -0
- package/src/components/panels/alignment/index.module.css +10 -0
- package/src/components/panels/alignment/index.tsx +244 -0
- package/src/components/panels/base/index.tsx +5 -0
- package/src/components/panels/base/styles.module.css +12 -0
- package/src/components/panels/common/PanelHeader.module.css +24 -0
- package/src/components/panels/common/PanelHeader.tsx +22 -0
- package/src/components/panels/common/SectionTitle.module.css +13 -0
- package/src/components/panels/common/SectionTitle.tsx +10 -0
- package/src/components/panels/events/EditEventPanel.tsx +324 -0
- package/src/components/panels/events/ManageEventsPanel.tsx +101 -0
- package/src/components/panels/events/index.tsx +23 -0
- package/src/components/panels/events/styles.module.css +178 -0
- package/src/components/panels/graphProperties/index.tsx +125 -0
- package/src/components/panels/history/index.tsx +92 -0
- package/src/components/panels/history/styles.module.css +97 -0
- package/src/components/panels/keymaps/index.module.css +68 -0
- package/src/components/panels/keymaps/index.tsx +166 -0
- package/src/components/panels/layers/index.tsx +245 -0
- package/src/components/panels/layers/styles.module.css +107 -0
- package/src/components/panels/legend/index.module.css +6 -0
- package/src/components/panels/legend/index.tsx +76 -0
- package/src/components/panels/logs/index.module.css +218 -0
- package/src/components/panels/logs/index.tsx +288 -0
- package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
- package/src/components/panels/nodeInputs/InputsGroup.tsx +65 -0
- package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +55 -0
- package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
- package/src/components/panels/nodeInputs/index.module.css +308 -0
- package/src/components/panels/nodeInputs/index.tsx +349 -0
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +153 -0
- package/src/components/panels/nodePicker/index.tsx +115 -0
- package/src/components/panels/panel/index.module.css +66 -0
- package/src/components/panels/panel/index.tsx +88 -0
- package/src/components/panels/search/index.module.css +16 -0
- package/src/components/panels/search/index.tsx +215 -0
- package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
- package/src/components/panels/systemSettings/index.tsx +251 -0
- package/src/components/panels/systemSettings/styles.module.css +138 -0
- package/src/components/panels/traces/GridLines.tsx +38 -0
- package/src/components/panels/traces/TimeGrid.tsx +48 -0
- package/src/components/panels/traces/TraceLane.tsx +62 -0
- package/src/components/panels/traces/TraceTooltip.tsx +22 -0
- package/src/components/panels/traces/TracesHeader.tsx +56 -0
- package/src/components/panels/traces/index.module.css +159 -0
- package/src/components/panels/traces/index.tsx +298 -0
- package/src/components/panels/traces/types.ts +48 -0
- package/src/components/panels/traces/useDerivedSpans.ts +307 -0
- package/src/components/panels/traces/utils.ts +33 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
- package/src/components/panels/variables/ManageVariablesScreen.tsx +147 -0
- package/src/components/panels/variables/index.tsx +125 -0
- package/src/components/panels/variables/styles.module.css +149 -0
- package/src/components/primitives/icon.module.css +45 -0
- package/src/components/primitives/icon.tsx +38 -0
- package/src/components/sockets/input/index.tsx +83 -0
- package/src/components/sockets/input/styles.module.css +26 -0
- package/src/components/sockets/output/index.tsx +68 -0
- package/src/components/sockets/output/styles.module.css +22 -0
- package/src/css/notes.css +135 -0
- package/src/css/prosemirror.css +57 -0
- package/src/css/rc-dock.css +212 -0
- package/src/css/rc-menu.css +101 -0
- package/src/css/themes/kiberon.css +127 -0
- package/src/css/vars.css +198 -0
- package/src/css/vscode-elements.css +124 -0
- package/src/entry.css +4 -0
- package/src/generators/CallSubgraphGenerator.tsx +136 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
- package/src/generators/GraphBoundaryGenerator.module.css +32 -0
- package/src/generators/GraphBoundaryGenerator.tsx +193 -0
- package/src/generators/SequenceGenerator.tsx +104 -0
- package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
- package/src/generators/SwitchOnStringGenerator.tsx +263 -0
- package/src/generators/callSubgraphSync.ts +126 -0
- package/src/generators/registerDefaultGenerators.ts +55 -0
- package/src/generators/registerDefaults.ts +26 -0
- package/src/hooks/useBehaveGraphFlow.ts +17 -16
- package/src/hooks/useFlowHandlers.ts +154 -30
- package/src/hooks/useWasdPan.ts +210 -0
- package/src/index.css +134 -0
- package/src/index.ts +53 -18
- package/src/manifest/contributionRegistry.ts +93 -0
- package/src/manifest/index.ts +4 -0
- package/src/manifest/loadManifest.ts +82 -0
- package/src/manifest/manifestPlugin.ts +29 -0
- package/src/manifest/passthroughValueType.ts +40 -0
- package/src/plugin/alignment/index.ts +91 -0
- package/src/plugin/autosave/controller.ts +366 -0
- package/src/plugin/autosave/index.tsx +114 -0
- package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
- package/src/plugin/autosave/panel/index.tsx +1 -0
- package/src/plugin/autosave/panel/styles.module.css +56 -0
- package/src/plugin/autosave/settings.ts +65 -0
- package/src/plugin/autosave/storage.ts +147 -0
- package/src/plugin/docs/index.tsx +297 -0
- package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
- package/src/plugin/docs/panel/index.tsx +21 -0
- package/src/plugin/docs/panel/styles.module.css +174 -0
- package/src/plugin/graphrunner/actions.ts +326 -0
- package/src/plugin/graphrunner/buttons.tsx +95 -0
- package/src/plugin/graphrunner/client.ts +707 -0
- package/src/plugin/graphrunner/index.tsx +184 -0
- package/src/plugin/graphrunner/panel.tsx +386 -0
- package/src/plugin/graphrunner/runController.ts +283 -0
- package/src/plugin/graphrunner/runner.ts +187 -0
- package/src/plugin/graphrunner/session.ts +243 -0
- package/src/plugin/graphrunner/store.ts +196 -0
- package/src/plugin/graphrunner/styles.module.css +171 -0
- package/src/plugin/graphrunner/transport.ts +250 -0
- package/src/plugin/graphrunner/types.ts +693 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +637 -0
- package/src/plugin/graphrunner-local/index.tsx +172 -0
- package/src/plugin/graphrunner-local/panel.tsx +187 -0
- package/src/plugin/graphrunner-local/store.ts +41 -0
- package/src/plugin/graphrunner-local/styles.module.css +82 -0
- package/src/plugin/graphrunner-local/transport.ts +1339 -0
- package/src/plugin/graphrunner-local/types.ts +10 -0
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +635 -0
- package/src/plugin/graphrunner-webworker/index.tsx +140 -0
- package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
- package/src/plugin/graphrunner-webworker/store.ts +98 -0
- package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
- package/src/plugin/kitchen-sink/index.ts +38 -0
- package/src/plugin/layout/dagre.ts +131 -0
- package/src/plugin/layout/elk.ts +216 -0
- package/src/plugin/layout/index.ts +80 -0
- package/src/plugin/notes/FormatToolbar.tsx +200 -0
- package/src/plugin/notes/index.tsx +191 -0
- package/src/plugin/notes/nodeActions.ts +100 -0
- package/src/plugin/notes/note.tsx +20 -0
- package/src/plugin/notes/noteImpl.tsx +89 -0
- package/src/plugin/realtime/realtimeRunner.ts +624 -0
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
- package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
- package/src/specifics/VariableGetSpecific.tsx +110 -0
- package/src/specifics/VariableSetSpecific.tsx +110 -0
- package/src/store/actions.tsx +698 -0
- package/src/store/commands.ts +278 -0
- package/src/store/contextMenu.ts +192 -0
- package/src/store/controls.tsx +62 -0
- package/src/store/conversions.ts +47 -0
- package/src/store/documentation.tsx +69 -0
- package/src/store/events.tsx +116 -0
- package/src/store/flow.tsx +230 -0
- package/src/store/graphMeta.ts +39 -0
- package/src/store/hotKeys.tsx +364 -0
- package/src/store/layers.ts +259 -0
- package/src/store/legend.tsx +76 -0
- package/src/store/logs.ts +28 -0
- package/src/store/menubar.ts +41 -0
- package/src/store/refs.ts +84 -0
- package/src/store/registry.ts +51 -0
- package/src/store/selection.ts +22 -0
- package/src/store/settings.ts +99 -0
- package/src/store/settingsSchema.ts +210 -0
- package/src/store/socketGenerator.tsx +54 -0
- package/src/store/specific.tsx +75 -0
- package/src/store/specs.tsx +35 -0
- package/src/store/tabs.ts +282 -0
- package/src/store/toolbar.tsx +45 -0
- package/src/store/traces.ts +240 -0
- package/src/store/variables.ts +37 -0
- package/src/system/graph.ts +131 -0
- package/src/system/graphSession.ts +172 -0
- package/src/system/index.ts +6 -0
- package/src/system/notifications.ts +111 -0
- package/src/system/persistence.ts +82 -0
- package/src/system/plugin.ts +55 -0
- package/src/system/provider.tsx +86 -0
- package/src/system/pubsub.ts +323 -0
- package/src/system/system.ts +653 -0
- package/src/system/tabLoader.tsx +303 -0
- package/src/system/undoRedo.ts +103 -0
- package/src/transformers/Uigraph.ts +61 -0
- package/src/transformers/behaveToFlow.ts +16 -4
- package/src/transformers/contract.ts +87 -0
- package/src/transformers/flowToBehave.ts +40 -12
- package/src/types/NodeMetadata.ts +27 -0
- package/src/types/graph.ts +49 -0
- package/src/types/nodes.ts +50 -0
- package/src/types.ts +18 -0
- package/src/util/autoConvert.ts +200 -0
- package/src/util/colors.ts +1 -29
- package/src/util/downloadJson.ts +18 -0
- package/src/util/extractNodeMetadata.ts +16 -0
- package/src/util/getPickerFilters.ts +1 -1
- package/src/util/isBehaveNode.ts +6 -0
- package/src/util/isValidConnection.ts +51 -17
- package/src/util/mergeSockets.ts +29 -0
- package/src/util/serializeVariables.ts +66 -0
- package/src/util/sockets.ts +43 -0
- package/stories/apex/layoutController/example-graph.worker.ts +39 -0
- package/stories/apex/layoutController/index.stories.tsx +48 -0
- package/stories/apex/layoutController/webworker.stories.tsx +103 -0
- package/stories/apex/menubar/menubar.stories.tsx +19 -0
- package/stories/components/colorpicker/index.stories.tsx +20 -0
- package/stories/components/contextMenus/edge.stories.tsx +32 -0
- package/stories/components/contextMenus/node.stories.tsx +26 -0
- package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
- package/stories/components/controls/any/index.stories.tsx +19 -0
- package/stories/components/controls/boolean/index.stories.tsx +19 -0
- package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
- package/stories/components/controls/number/index.stories.tsx +19 -0
- package/stories/components/controls/string/index.stories.tsx +19 -0
- package/stories/components/nodes/behaveNode.stories.tsx +108 -0
- package/stories/components/panels/alignment.stories.tsx +24 -0
- package/stories/components/panels/events.stories.tsx +38 -0
- package/stories/components/panels/graphRunner.stories.tsx +317 -0
- package/stories/components/panels/history.stories.tsx +37 -0
- package/stories/components/panels/keymaps.stories.tsx +21 -0
- package/stories/components/panels/legend.stories.tsx +37 -0
- package/stories/components/panels/logs.stories.tsx +24 -0
- package/stories/components/panels/nodeInputs.stories.tsx +21 -0
- package/stories/components/panels/nodePicker.stories.tsx +37 -0
- package/stories/components/panels/panel.stories.tsx +39 -0
- package/stories/components/panels/search.stories.tsx +24 -0
- package/stories/components/panels/systemSettings.stories.tsx +26 -0
- package/stories/components/panels/traces.stories.tsx +225 -0
- package/stories/components/panels/variables.stories.tsx +24 -0
- package/stories/defaults/defaultStoryProvider.tsx +170 -0
- package/stories/defaults/systemGenerator.ts +43 -0
- package/stories/plugins/notes.stories.tsx +100 -0
- package/tests/autoConvert.test.ts +329 -0
- package/tests/autosavePlugin.test.ts +204 -0
- package/tests/callSubgraphSync.test.ts +148 -0
- package/tests/commandRegistry.test.ts +137 -0
- package/tests/components/edges/offsetBezier.test.ts +51 -0
- package/tests/components/layoutController/utils.test.ts +68 -0
- package/tests/components/panels/traces/utils.test.ts +52 -0
- package/tests/contract.test.ts +51 -0
- package/tests/contractSerialize.test.ts +62 -0
- package/tests/deriveSpans.test.ts +71 -0
- package/tests/flowToBehave.test.ts +27 -4
- package/tests/hotkeys.test.ts +79 -0
- package/tests/keepAliveLifecycle.test.ts +167 -0
- package/tests/loadManifest.test.ts +113 -0
- package/tests/noteMarkdown.test.ts +65 -0
- package/tests/notesPlugin.test.ts +162 -0
- package/tests/notifications.test.ts +87 -0
- package/tests/persistence.test.ts +51 -0
- package/tests/saveLoad.test.ts +373 -0
- package/tests/settings.test.ts +178 -0
- package/tests/traceStore.test.ts +46 -0
- package/tests/util/calculateNewEdge.test.ts +98 -0
- package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
- package/tests/util/hasPositionMetaData.test.ts +33 -0
- package/tests/util/isBehaveNode.test.ts +22 -0
- package/tests/util/isHandleConnected.test.ts +37 -0
- package/tests/util/mergeSockets.test.ts +43 -0
- package/tests/visual/README.md +64 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
- package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +76 -0
- package/tests/wasdPan.test.ts +71 -0
- package/tsconfig.base.json +39 -0
- package/tsconfig.json +18 -59
- package/tsconfig.prod.json +23 -0
- package/tsdown.config.ts +15 -3
- package/typedoc.json +7 -7
- package/vite.config.js +7 -0
- package/vitest.config.ts +5 -2
- package/vitest.visual.config.ts +55 -0
- package/src/components/AutoSizeInput.tsx +0 -65
- package/src/components/Controls.tsx +0 -87
- package/src/components/InputSocket.tsx +0 -142
- package/src/components/Node.tsx +0 -68
- package/src/components/NodeContainer.tsx +0 -46
- package/src/components/NodePicker.tsx +0 -77
- package/src/components/OutputSocket.tsx +0 -58
- package/src/components/modals/ClearModal.tsx +0 -40
- package/src/components/modals/HelpModal.tsx +0 -36
- package/src/components/modals/LoadModal.tsx +0 -96
- package/src/components/modals/Modal.tsx +0 -64
- package/src/components/modals/SaveModal.tsx +0 -60
- package/src/hooks/useCustomNodeTypes.tsx +0 -31
- package/src/hooks/useGraphRunner.ts +0 -104
- package/src/hooks/useMergeMap.ts +0 -14
- package/src/hooks/useNodeSpecJson.ts +0 -20
- package/src/hooks/useQueriableDefinitions.ts +0 -22
- package/src/styles.css +0 -8
- package/tailwind.config.ts +0 -19
- package/tests/tsconfig.json +0 -10
- /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { lazy, Suspense } from 'react';
|
|
2
|
+
import styles from './styles.module.css';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The documentation panel embeds a tiptap/prosemirror editor (~320 KB) to render
|
|
6
|
+
* node markdown. Load it lazily so that weight only enters the bundle when the
|
|
7
|
+
* panel is actually opened.
|
|
8
|
+
*/
|
|
9
|
+
const LazyPanel = lazy(() =>
|
|
10
|
+
import('./DocumentationBrowserPanelImpl').then((m) => ({
|
|
11
|
+
default: m.DocumentationBrowserPanelImpl
|
|
12
|
+
}))
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export function DocumentationBrowserPanel() {
|
|
16
|
+
return (
|
|
17
|
+
<Suspense fallback={<div className={styles.container} />}>
|
|
18
|
+
<LazyPanel />
|
|
19
|
+
</Suspense>
|
|
20
|
+
);
|
|
21
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
width: 100%;
|
|
3
|
+
height: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
background: var(--colors-bgCanvas);
|
|
7
|
+
color: var(--colors-fg);
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.header {
|
|
12
|
+
padding: 1rem;
|
|
13
|
+
border-bottom: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
14
|
+
background: var(--colors-bgPanel);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.titleSection {
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: flex-start;
|
|
20
|
+
gap: 0.75rem;
|
|
21
|
+
margin-bottom: 0.75rem;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.iconLarge {
|
|
25
|
+
width: 48px;
|
|
26
|
+
height: 48px;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
border-radius: 0.5rem;
|
|
31
|
+
border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
32
|
+
background: var(--colors-bgCanvas);
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.iconLarge svg {
|
|
37
|
+
width: 32px;
|
|
38
|
+
height: 32px;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.title {
|
|
42
|
+
margin: 0;
|
|
43
|
+
font-size: 1.25rem;
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
line-height: 1.3;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.nodeType {
|
|
49
|
+
font-size: 0.75rem;
|
|
50
|
+
opacity: 0.7;
|
|
51
|
+
margin-top: 0.25rem;
|
|
52
|
+
font-family: monospace;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.tags {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-wrap: wrap;
|
|
58
|
+
gap: 0.5rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.tag {
|
|
62
|
+
font-size: 0.75rem;
|
|
63
|
+
padding: 0.25rem 0.5rem;
|
|
64
|
+
border-radius: 0.25rem;
|
|
65
|
+
background: var(--ds-badge-bg, #4d4d4d);
|
|
66
|
+
color: var(--ds-badge-fg, #ffffff);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.content {
|
|
70
|
+
flex: 1;
|
|
71
|
+
overflow-y: auto;
|
|
72
|
+
padding: 1rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.description {
|
|
76
|
+
font-size: 1rem;
|
|
77
|
+
line-height: 1.5;
|
|
78
|
+
margin-bottom: 1.5rem;
|
|
79
|
+
padding: 0.75rem;
|
|
80
|
+
background: var(--ds-blockquote-bg, rgba(127, 127, 127, 0.1));
|
|
81
|
+
border-left: 4px solid var(--ds-blockquote-border, #007acc);
|
|
82
|
+
border-radius: 0.25rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
.noContent {
|
|
87
|
+
padding: 2rem;
|
|
88
|
+
text-align: center;
|
|
89
|
+
opacity: 0.6;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.section {
|
|
93
|
+
margin-top: 2rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.sectionTitle {
|
|
97
|
+
font-size: 1rem;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
margin-bottom: 0.75rem;
|
|
100
|
+
padding-bottom: 0.25rem;
|
|
101
|
+
border-bottom: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.socketList {
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-direction: column;
|
|
107
|
+
gap: 0.5rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.socketItem {
|
|
111
|
+
display: flex;
|
|
112
|
+
gap: 0.75rem;
|
|
113
|
+
align-items: center;
|
|
114
|
+
padding: 0.5rem;
|
|
115
|
+
background: var(--colors-bgPanel);
|
|
116
|
+
border-radius: 0.25rem;
|
|
117
|
+
border: 1px solid var(--ds-input-border, var(--colors-borderSubtle));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.socketIcon {
|
|
121
|
+
width: 20px;
|
|
122
|
+
height: 20px;
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
justify-content: center;
|
|
126
|
+
flex-shrink: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.socketIcon svg {
|
|
130
|
+
width: 16px;
|
|
131
|
+
height: 16px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.socketName {
|
|
135
|
+
font-weight: 500;
|
|
136
|
+
flex: 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.socketType {
|
|
140
|
+
font-family: monospace;
|
|
141
|
+
font-size: 0.85rem;
|
|
142
|
+
font-weight: 500;
|
|
143
|
+
padding: 0.125rem 0.5rem;
|
|
144
|
+
border-radius: 0.25rem;
|
|
145
|
+
background: rgba(0, 0, 0, 0.2);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.empty {
|
|
149
|
+
height: 100%;
|
|
150
|
+
display: flex;
|
|
151
|
+
flex-direction: column;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: center;
|
|
154
|
+
padding: 2rem;
|
|
155
|
+
text-align: center;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.emptyIcon {
|
|
159
|
+
font-size: 4rem;
|
|
160
|
+
margin-bottom: 1rem;
|
|
161
|
+
opacity: 0.3;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.emptyText {
|
|
165
|
+
font-size: 1.25rem;
|
|
166
|
+
font-weight: 500;
|
|
167
|
+
margin-bottom: 0.5rem;
|
|
168
|
+
opacity: 0.8;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.emptySub {
|
|
172
|
+
font-size: 0.9rem;
|
|
173
|
+
opacity: 0.6;
|
|
174
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
2
|
+
import type { GraphRunnerClient } from './client';
|
|
3
|
+
import type { GraphRunner } from './runner';
|
|
4
|
+
import { executing } from '@/annotations';
|
|
5
|
+
import { type ValueJSON } from '@kiberon-labs/behave-graph';
|
|
6
|
+
import type { TraceBatchEvent } from './types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Per-session batcher for the `executing` node annotation.
|
|
10
|
+
*
|
|
11
|
+
* Trace events arrive per node execution (start + end), which at display-rate
|
|
12
|
+
* ticking means hundreds of events per frame. Writing the annotation straight
|
|
13
|
+
* through did a full O(nodes) copy-map of the node array per event; instead,
|
|
14
|
+
* accumulate the net executing state here and apply it once per animation
|
|
15
|
+
* frame with a single identity-preserving setNodes pass.
|
|
16
|
+
*/
|
|
17
|
+
type ExecutingBatch = {
|
|
18
|
+
pending: Map<string, boolean>;
|
|
19
|
+
scheduled: boolean;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const executingBatches = new WeakMap<GraphSession, ExecutingBatch>();
|
|
23
|
+
|
|
24
|
+
const scheduleFrame = (cb: () => void): void => {
|
|
25
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
26
|
+
requestAnimationFrame(cb);
|
|
27
|
+
} else {
|
|
28
|
+
setTimeout(cb, 16);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function flushExecutingState(session: GraphSession, batch: ExecutingBatch) {
|
|
33
|
+
batch.scheduled = false;
|
|
34
|
+
if (batch.pending.size === 0) return;
|
|
35
|
+
const updates = batch.pending;
|
|
36
|
+
batch.pending = new Map();
|
|
37
|
+
|
|
38
|
+
session.nodeStore.getState().setNodes((nodes) => {
|
|
39
|
+
let changed = false;
|
|
40
|
+
const next = nodes.map((node) => {
|
|
41
|
+
if (!('data' in node)) return node;
|
|
42
|
+
const target = updates.get(node.id);
|
|
43
|
+
if (target === undefined) return node;
|
|
44
|
+
if (Boolean(node.data.annotations?.[executing]) === target) return node;
|
|
45
|
+
changed = true;
|
|
46
|
+
return {
|
|
47
|
+
...node,
|
|
48
|
+
data: {
|
|
49
|
+
...node.data,
|
|
50
|
+
annotations: {
|
|
51
|
+
...node.data.annotations,
|
|
52
|
+
[executing]: target
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
// Keep the original array identity when nothing changed so selector-based
|
|
58
|
+
// subscribers (the React Flow canvas) skip the re-render entirely.
|
|
59
|
+
return changed ? next : nodes;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function markExecuting(session: GraphSession, nodeId: string, state: boolean) {
|
|
64
|
+
let batch = executingBatches.get(session);
|
|
65
|
+
if (!batch) {
|
|
66
|
+
batch = { pending: new Map(), scheduled: false };
|
|
67
|
+
executingBatches.set(session, batch);
|
|
68
|
+
}
|
|
69
|
+
batch.pending.set(nodeId, state);
|
|
70
|
+
if (!batch.scheduled) {
|
|
71
|
+
batch.scheduled = true;
|
|
72
|
+
scheduleFrame(() => flushExecutingState(session, batch));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Clear executing state from all nodes of a session, dropping any queued
|
|
77
|
+
// per-node updates so a pending flush can't re-highlight after the run ended.
|
|
78
|
+
function clearAllExecutingStates(session: GraphSession) {
|
|
79
|
+
const batch = executingBatches.get(session);
|
|
80
|
+
if (batch) batch.pending.clear();
|
|
81
|
+
session.nodeStore.getState().setNodes((nodes) => {
|
|
82
|
+
let changed = false;
|
|
83
|
+
const next = nodes.map((node) => {
|
|
84
|
+
if ('data' in node && node.data.annotations?.[executing]) {
|
|
85
|
+
changed = true;
|
|
86
|
+
return {
|
|
87
|
+
...node,
|
|
88
|
+
data: {
|
|
89
|
+
...node.data,
|
|
90
|
+
annotations: {
|
|
91
|
+
...node.data.annotations,
|
|
92
|
+
[executing]: false
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return node;
|
|
98
|
+
});
|
|
99
|
+
return changed ? next : nodes;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Apply one trace event to the session's trace spans + executing annotation. */
|
|
104
|
+
function processTraceEvent(session: GraphSession, ev: TraceBatchEvent) {
|
|
105
|
+
const traceStore = session.traceStore.getState();
|
|
106
|
+
if (ev.event === 'start') {
|
|
107
|
+
let name = ev.nodeId;
|
|
108
|
+
if (ev.data && typeof ev.data === 'object' && 'typeName' in ev.data) {
|
|
109
|
+
const typeName = (ev.data as { typeName?: unknown }).typeName;
|
|
110
|
+
if (typeof typeName === 'string') {
|
|
111
|
+
name = typeName;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
traceStore.addSpan({
|
|
115
|
+
nodeId: ev.nodeId,
|
|
116
|
+
name,
|
|
117
|
+
// `??` not `||`: the worker sends run-relative ms, so 0 is a valid (and
|
|
118
|
+
// common, for the first node) start , `||` fell back to the main thread's
|
|
119
|
+
// performance.now(), producing huge, wrong-clock timestamps.
|
|
120
|
+
start: ev.timestamp ?? performance.now(),
|
|
121
|
+
// Open span: NaN until the matching `end` event arrives. The store/render
|
|
122
|
+
// treat NaN as "still running"; a literal end let it render mis-sized.
|
|
123
|
+
end: Number.NaN
|
|
124
|
+
// lane omitted: let the store allocate/free lanes so concurrent spans
|
|
125
|
+
// stack instead of all piling into lane 0.
|
|
126
|
+
});
|
|
127
|
+
markExecuting(session, ev.nodeId, true);
|
|
128
|
+
} else if (ev.event === 'end') {
|
|
129
|
+
traceStore.updateSpan(ev.nodeId, {
|
|
130
|
+
end: ev.timestamp ?? performance.now()
|
|
131
|
+
});
|
|
132
|
+
markExecuting(session, ev.nodeId, false);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Clients that already have listeners attached. Guards against double-wiring when
|
|
138
|
+
* both the plugin's `runner.connect()` and a host (e.g. the webworker runner)
|
|
139
|
+
* call {@link setupClientEventListeners} on the same client , which would record
|
|
140
|
+
* every trace span, log and event twice.
|
|
141
|
+
*/
|
|
142
|
+
const wiredClients = new WeakSet<GraphRunnerClient>();
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Setup persistent event listeners on the shared client. Registered once when
|
|
146
|
+
* the client connects; every message is routed to the session that started its
|
|
147
|
+
* run (via {@link GraphRunner.runIndex}), so concurrent graphs stay isolated.
|
|
148
|
+
*
|
|
149
|
+
* Idempotent per client: calling it again with the same client is a no-op.
|
|
150
|
+
*/
|
|
151
|
+
export function setupClientEventListeners(
|
|
152
|
+
client: GraphRunnerClient,
|
|
153
|
+
runner: GraphRunner
|
|
154
|
+
) {
|
|
155
|
+
if (wiredClients.has(client)) return;
|
|
156
|
+
wiredClients.add(client);
|
|
157
|
+
|
|
158
|
+
// Resolve the session that owns a given run id, or null if unknown.
|
|
159
|
+
const sessionFor = (runId: string): GraphSession | null =>
|
|
160
|
+
runner.runIndex.get(runId)?.session ?? null;
|
|
161
|
+
|
|
162
|
+
// Batched trace events (one message per flush window, many events inside).
|
|
163
|
+
client.on('traceBatch', (message) => {
|
|
164
|
+
const session = sessionFor(message.runId);
|
|
165
|
+
if (!session) return;
|
|
166
|
+
for (const ev of message.events) {
|
|
167
|
+
processTraceEvent(session, ev);
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Single trace events , kept for remote servers that predate `traceBatch`.
|
|
172
|
+
client.on('trace', (message) => {
|
|
173
|
+
const session = sessionFor(message.runId);
|
|
174
|
+
if (!session) return;
|
|
175
|
+
processTraceEvent(session, message);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// Listen for log messages
|
|
179
|
+
client.on('log', (message) => {
|
|
180
|
+
const session = sessionFor(message.runId);
|
|
181
|
+
if (!session) return;
|
|
182
|
+
const formattedMessage = `[${message.runId}/${message.graphId}] ${message.message}${message.data !== undefined ? ` ${JSON.stringify(message.data)}` : ''}`;
|
|
183
|
+
session.logsStore.getState().append({
|
|
184
|
+
time: new Date(),
|
|
185
|
+
data: {
|
|
186
|
+
message: formattedMessage
|
|
187
|
+
},
|
|
188
|
+
type: message.level as any
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Listen for variable change events from server. A tick-driven graph writes
|
|
193
|
+
// variables every frame, so coalesce to the latest value per variable and
|
|
194
|
+
// apply once per animation frame instead of one store write per change.
|
|
195
|
+
const pendingVariableUpdates = new Map<GraphSession, Map<string, unknown>>();
|
|
196
|
+
let variableFlushScheduled = false;
|
|
197
|
+
|
|
198
|
+
const flushVariableUpdates = () => {
|
|
199
|
+
variableFlushScheduled = false;
|
|
200
|
+
for (const [session, updates] of pendingVariableUpdates) {
|
|
201
|
+
const variableStore = session.variableStore.getState();
|
|
202
|
+
for (const [id, newValue] of updates) {
|
|
203
|
+
const existingVariable = variableStore.variables[id];
|
|
204
|
+
if (existingVariable) {
|
|
205
|
+
variableStore.setVariable(id, {
|
|
206
|
+
...existingVariable,
|
|
207
|
+
initialValue: newValue as ValueJSON
|
|
208
|
+
});
|
|
209
|
+
} else {
|
|
210
|
+
const inferredType = typeof newValue;
|
|
211
|
+
variableStore.setVariable(id, {
|
|
212
|
+
id,
|
|
213
|
+
name: id,
|
|
214
|
+
valueTypeName: inferredType === 'object' ? 'string' : inferredType,
|
|
215
|
+
initialValue: newValue as ValueJSON
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
pendingVariableUpdates.clear();
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
client.on('variableChanged', (message) => {
|
|
224
|
+
const session = sessionFor(message.runId);
|
|
225
|
+
if (!session) return;
|
|
226
|
+
let updates = pendingVariableUpdates.get(session);
|
|
227
|
+
if (!updates) {
|
|
228
|
+
updates = new Map();
|
|
229
|
+
pendingVariableUpdates.set(session, updates);
|
|
230
|
+
}
|
|
231
|
+
updates.set(message.variableName, message.newValue);
|
|
232
|
+
if (!variableFlushScheduled) {
|
|
233
|
+
variableFlushScheduled = true;
|
|
234
|
+
scheduleFrame(flushVariableUpdates);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Run lifecycle events
|
|
239
|
+
client.on('completed', (message) => {
|
|
240
|
+
const controller = runner.runIndex.get(message.runId);
|
|
241
|
+
if (!controller) return;
|
|
242
|
+
controller.session.editor.notifications.success(
|
|
243
|
+
`Graph completed: ${message.graphId}`
|
|
244
|
+
);
|
|
245
|
+
controller.finishRun();
|
|
246
|
+
clearAllExecutingStates(controller.session);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
client.on('error', (message) => {
|
|
250
|
+
if (!message.runId) return;
|
|
251
|
+
const controller = runner.runIndex.get(message.runId);
|
|
252
|
+
if (!controller) return;
|
|
253
|
+
controller.session.editor.notifications.error(
|
|
254
|
+
`Graph failed: ${message.graphId}`
|
|
255
|
+
);
|
|
256
|
+
controller.finishRun();
|
|
257
|
+
clearAllExecutingStates(controller.session);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
client.on('stopped', (message) => {
|
|
261
|
+
const controller = runner.runIndex.get(message.runId);
|
|
262
|
+
if (!controller) return;
|
|
263
|
+
controller.session.editor.notifications.info(
|
|
264
|
+
`Graph stopped: ${message.graphId}`
|
|
265
|
+
);
|
|
266
|
+
controller.finishRun();
|
|
267
|
+
clearAllExecutingStates(controller.session);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Realtime state change listeners
|
|
271
|
+
client.on('nodeRemoved', (message) => {
|
|
272
|
+
const session = sessionFor(message.runId);
|
|
273
|
+
if (!session) return;
|
|
274
|
+
session.nodeStore
|
|
275
|
+
.getState()
|
|
276
|
+
.setNodes((nodes) => nodes.filter((node) => node.id !== message.nodeId));
|
|
277
|
+
session.editor.notifications.info(`Node removed: ${message.nodeId}`);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
client.on('linkCreated', (message) => {
|
|
281
|
+
const session = sessionFor(message.runId);
|
|
282
|
+
if (!session) return;
|
|
283
|
+
session.editor.notifications.info(
|
|
284
|
+
`Link created: ${message.fromNodeId}/${message.fromSocket} -> ${message.toNodeId}/${message.toSocket}`
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
client.on('linkRemoved', (message) => {
|
|
289
|
+
const session = sessionFor(message.runId);
|
|
290
|
+
if (!session) return;
|
|
291
|
+
session.editor.notifications.info(
|
|
292
|
+
`Link removed: ${message.fromNodeId}/${message.fromSocket} -> ${message.toNodeId}/${message.toSocket}`
|
|
293
|
+
);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
client.on('nodeParamUpdated', (message) => {
|
|
297
|
+
const session = sessionFor(message.runId);
|
|
298
|
+
if (!session) return;
|
|
299
|
+
session.editor.notifications.info(`Parameter updated on ${message.nodeId}`);
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
client.on('affectedNodes', (message) => {
|
|
303
|
+
const session = sessionFor(message.runId);
|
|
304
|
+
if (!session) return;
|
|
305
|
+
session.nodeStore.getState().setNodes((nodes) =>
|
|
306
|
+
nodes.map((node) => {
|
|
307
|
+
if (message.nodeIds.includes(node.id)) {
|
|
308
|
+
return {
|
|
309
|
+
...node,
|
|
310
|
+
data: {
|
|
311
|
+
...node.data,
|
|
312
|
+
annotations: {
|
|
313
|
+
...node.data?.annotations,
|
|
314
|
+
[executing]: true
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
return node;
|
|
320
|
+
})
|
|
321
|
+
);
|
|
322
|
+
session.editor.notifications.info(
|
|
323
|
+
`Executing ${message.reason}: ${message.nodeIds.length} node(s)`
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { VscodeButton } from '@vscode-elements/react-elements';
|
|
2
|
+
import { useStore, type StoreApi } from 'zustand';
|
|
3
|
+
import { Play, PauseWindow, Square, ArrowRight } from 'iconoir-react';
|
|
4
|
+
import { useGraph } from '@/system/provider';
|
|
5
|
+
import type { GraphRunnerClientStore } from './store';
|
|
6
|
+
import type { GraphRunController } from './runController';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Execution controls for the graph in the surrounding tab. Connection state
|
|
10
|
+
* comes from the shared runner connection; run state comes from this graph's own
|
|
11
|
+
* run controller, so each open graph has independent controls.
|
|
12
|
+
*/
|
|
13
|
+
export const GraphRunnerButtons = () => {
|
|
14
|
+
const session = useGraph();
|
|
15
|
+
const controller = session.runController;
|
|
16
|
+
if (!controller) return null;
|
|
17
|
+
return (
|
|
18
|
+
<Buttons
|
|
19
|
+
controller={controller}
|
|
20
|
+
connectionStore={session.editor.runner.store}
|
|
21
|
+
/>
|
|
22
|
+
);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const Buttons = ({
|
|
26
|
+
controller,
|
|
27
|
+
connectionStore
|
|
28
|
+
}: {
|
|
29
|
+
controller: GraphRunController;
|
|
30
|
+
connectionStore: StoreApi<GraphRunnerClientStore>;
|
|
31
|
+
}) => {
|
|
32
|
+
const connectionState = useStore(connectionStore, (s) => s.connectionState);
|
|
33
|
+
const isExecuting = useStore(controller.store, (s) => s.isExecuting);
|
|
34
|
+
const isPaused = useStore(controller.store, (s) => s.isPaused);
|
|
35
|
+
|
|
36
|
+
const isConnected = connectionState === 'connected';
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
{!isExecuting && (
|
|
41
|
+
<VscodeButton
|
|
42
|
+
secondary
|
|
43
|
+
iconOnly
|
|
44
|
+
title="Play Graph"
|
|
45
|
+
onClick={() => controller.play()}
|
|
46
|
+
disabled={!isConnected}
|
|
47
|
+
>
|
|
48
|
+
<Play />
|
|
49
|
+
</VscodeButton>
|
|
50
|
+
)}
|
|
51
|
+
{isExecuting && !isPaused && (
|
|
52
|
+
<VscodeButton
|
|
53
|
+
secondary
|
|
54
|
+
iconOnly
|
|
55
|
+
title="Pause Graph"
|
|
56
|
+
onClick={() => controller.pause()}
|
|
57
|
+
disabled={!isConnected}
|
|
58
|
+
>
|
|
59
|
+
<PauseWindow />
|
|
60
|
+
</VscodeButton>
|
|
61
|
+
)}
|
|
62
|
+
{isExecuting && isPaused && (
|
|
63
|
+
<>
|
|
64
|
+
<VscodeButton
|
|
65
|
+
secondary
|
|
66
|
+
iconOnly
|
|
67
|
+
title="Resume Graph"
|
|
68
|
+
onClick={() => controller.resume()}
|
|
69
|
+
disabled={!isConnected}
|
|
70
|
+
>
|
|
71
|
+
<Play />
|
|
72
|
+
</VscodeButton>
|
|
73
|
+
<VscodeButton
|
|
74
|
+
secondary
|
|
75
|
+
iconOnly
|
|
76
|
+
title="Step Forward"
|
|
77
|
+
onClick={() => controller.step()}
|
|
78
|
+
disabled={!isConnected}
|
|
79
|
+
>
|
|
80
|
+
<ArrowRight />
|
|
81
|
+
</VscodeButton>
|
|
82
|
+
</>
|
|
83
|
+
)}
|
|
84
|
+
<VscodeButton
|
|
85
|
+
secondary
|
|
86
|
+
iconOnly
|
|
87
|
+
title="Stop Graph"
|
|
88
|
+
onClick={() => controller.stop()}
|
|
89
|
+
disabled={!isExecuting}
|
|
90
|
+
>
|
|
91
|
+
<Square />
|
|
92
|
+
</VscodeButton>
|
|
93
|
+
</>
|
|
94
|
+
);
|
|
95
|
+
};
|