@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,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure metadata types for visual graph editor
|
|
3
|
+
* NO execution code, NO node factories, NO runtime dependencies
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
7
|
+
|
|
8
|
+
export interface ValueTypeMetadata {
|
|
9
|
+
name: string;
|
|
10
|
+
creator: () => any;
|
|
11
|
+
deserialize?: (value: any) => any;
|
|
12
|
+
serialize?: (value: any) => any;
|
|
13
|
+
lerp?: (start: any, end: any, t: number) => any;
|
|
14
|
+
equals?: (a: any, b: any) => boolean;
|
|
15
|
+
clone?: (value: any) => any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pure metadata registry - no execution capabilities
|
|
20
|
+
* Used by the visual graph editor for rendering nodes
|
|
21
|
+
*/
|
|
22
|
+
export interface INodeRegistry {
|
|
23
|
+
readonly values: Record<string, ValueTypeMetadata>;
|
|
24
|
+
readonly specs: NodeSpecJSON[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type NodeMetadata = Record<string, string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { GraphJSON } from '@kiberon-labs/behave-graph';
|
|
2
|
+
import type { Edge, Node } from 'reactflow';
|
|
3
|
+
import type { SerializedLayers } from '@/store/layers';
|
|
4
|
+
|
|
5
|
+
export type UIGraphData = Record<string, unknown> & {
|
|
6
|
+
layers?: SerializedLayers;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type UIGraphJSON = {
|
|
10
|
+
/**
|
|
11
|
+
* Version of the graph
|
|
12
|
+
*/
|
|
13
|
+
v: string;
|
|
14
|
+
name: string;
|
|
15
|
+
/**
|
|
16
|
+
* Graph annotations as metadata
|
|
17
|
+
*/
|
|
18
|
+
annotations: Record<string, unknown>;
|
|
19
|
+
|
|
20
|
+
/** User specific */
|
|
21
|
+
user?: {
|
|
22
|
+
viewport: {
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
zoom: number;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Saved viewports for multiple positions
|
|
29
|
+
*/
|
|
30
|
+
viewports?: {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
zoom: number;
|
|
34
|
+
}[];
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Arbitrary data associated with the graph.
|
|
39
|
+
* Expected to be used with plugins/extensions. This is seperate from graph annotations
|
|
40
|
+
*/
|
|
41
|
+
data: UIGraphData;
|
|
42
|
+
/**
|
|
43
|
+
* The serialized graph data.
|
|
44
|
+
* This is currently the embedded JSON format from behave-graph
|
|
45
|
+
*/
|
|
46
|
+
flow: GraphJSON;
|
|
47
|
+
nodes: Node[];
|
|
48
|
+
edges: Edge[];
|
|
49
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { DynamicPorts } from '@/types';
|
|
2
|
+
import type { Node } from 'reactflow';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* These are the behave nodes in the scene
|
|
6
|
+
*/
|
|
7
|
+
export type IBehaveNode = Omit<Node, 'data' | 'type'> & {
|
|
8
|
+
type: 'behaveNode';
|
|
9
|
+
data: {
|
|
10
|
+
annotations?: Record<string, any>;
|
|
11
|
+
type: string;
|
|
12
|
+
dynamicPorts: DynamicPorts;
|
|
13
|
+
ports?: Record<string, any>;
|
|
14
|
+
configuration: Record<string, any>;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Presentational markdown note, contributed by the notes plugin
|
|
20
|
+
* (`@/plugin/notes`). `commentNode` is the legacy type string notes carried
|
|
21
|
+
* when they lived in the core editor.
|
|
22
|
+
*/
|
|
23
|
+
export type INoteNode = Omit<Node, 'data' | 'type'> & {
|
|
24
|
+
type: 'noteNode' | 'commentNode';
|
|
25
|
+
data: {
|
|
26
|
+
annotations?: Record<string, any>;
|
|
27
|
+
text: string;
|
|
28
|
+
fontSize?: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type IGroupNode = Omit<Node, 'data' | 'type'> & {
|
|
33
|
+
type: 'group';
|
|
34
|
+
data: {
|
|
35
|
+
color: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type IAINode = Omit<Node, 'data' | 'type'> & {
|
|
40
|
+
type: 'behaveNode:ai';
|
|
41
|
+
data: {
|
|
42
|
+
annotations?: Record<string, any>;
|
|
43
|
+
type: string;
|
|
44
|
+
ports?: DynamicPorts;
|
|
45
|
+
configuration: Record<string, any>;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export type AnyNode = IBehaveNode | INoteNode | IAINode | IGroupNode;
|
|
50
|
+
export type AnyNodeType = AnyNode['type'];
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ChoiceJSON } from '@kiberon-labs/behave-graph';
|
|
2
|
+
|
|
3
|
+
export interface SocketBase {
|
|
4
|
+
name: string;
|
|
5
|
+
key: string;
|
|
6
|
+
/** Optional display label; falls back to `name` when absent. */
|
|
7
|
+
label?: string;
|
|
8
|
+
choices?: ChoiceJSON;
|
|
9
|
+
valueType: string;
|
|
10
|
+
defaultValue?: any;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Socket = SocketBase;
|
|
14
|
+
|
|
15
|
+
export interface DynamicPorts {
|
|
16
|
+
inputs?: SocketBase[];
|
|
17
|
+
outputs?: SocketBase[];
|
|
18
|
+
}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
2
|
+
import type { Connection, Edge, Node, XYPosition } from 'reactflow';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { getSocketsByNodeTypeAndHandleType } from './getSocketsByNodeTypeAndHandleType.js';
|
|
5
|
+
import { mergeSockets } from './mergeSockets.js';
|
|
6
|
+
import type { ConversionRule } from '@/store/conversions';
|
|
7
|
+
import type { IBehaveNode } from '@/types/nodes.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Find a node spec that converts `sourceType` to `targetType` , a pure value
|
|
11
|
+
* function with exactly one value input of the source type and one value output
|
|
12
|
+
* of the target type, and no flow sockets (e.g. `math/toString/integer`).
|
|
13
|
+
*/
|
|
14
|
+
export const findConverterSpec = (
|
|
15
|
+
specs: NodeSpecJSON[],
|
|
16
|
+
sourceType: string,
|
|
17
|
+
targetType: string
|
|
18
|
+
): NodeSpecJSON | undefined =>
|
|
19
|
+
specs.find((spec) => {
|
|
20
|
+
const valueIns = spec.inputs.filter((i) => i.valueType !== 'flow');
|
|
21
|
+
const valueOuts = spec.outputs.filter((o) => o.valueType !== 'flow');
|
|
22
|
+
const hasFlow =
|
|
23
|
+
spec.inputs.some((i) => i.valueType === 'flow') ||
|
|
24
|
+
spec.outputs.some((o) => o.valueType === 'flow');
|
|
25
|
+
return (
|
|
26
|
+
!hasFlow &&
|
|
27
|
+
valueIns.length === 1 &&
|
|
28
|
+
valueOuts.length === 1 &&
|
|
29
|
+
valueIns[0]!.valueType === sourceType &&
|
|
30
|
+
valueOuts[0]!.valueType === targetType
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
export type ResolvedConverter = {
|
|
35
|
+
nodeType: string;
|
|
36
|
+
inputName: string;
|
|
37
|
+
outputName: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const firstValueSocketName = (
|
|
41
|
+
sockets: { name: string; valueType: string }[]
|
|
42
|
+
): string | undefined => sockets.find((s) => s.valueType !== 'flow')?.name;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pick the socket that should carry a value of `valueType`: prefer one whose type
|
|
46
|
+
* matches exactly (so multi-port converter nodes resolve the *right* port), then
|
|
47
|
+
* fall back to the first non-flow socket for single-port nodes.
|
|
48
|
+
*/
|
|
49
|
+
const socketNameForType = (
|
|
50
|
+
sockets: { name: string; valueType: string }[],
|
|
51
|
+
valueType: string
|
|
52
|
+
): string | undefined =>
|
|
53
|
+
sockets.find((s) => s.valueType === valueType)?.name ??
|
|
54
|
+
firstValueSocketName(sockets);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Resolve which converter to use for `from`→`to`. A registered
|
|
58
|
+
* {@link ConversionRule} (e.g. from a custom profile) takes precedence; otherwise
|
|
59
|
+
* fall back to scanning the specs for a generic single-in/single-out converter.
|
|
60
|
+
*
|
|
61
|
+
* A rule's `inputKey`/`outputKey` pin the exact ports to wire (required for
|
|
62
|
+
* converter nodes with more than one input or output). When omitted they are
|
|
63
|
+
* resolved by matching the port's value type to `from`/`to`.
|
|
64
|
+
*/
|
|
65
|
+
export const resolveConverter = (
|
|
66
|
+
specs: NodeSpecJSON[],
|
|
67
|
+
from: string,
|
|
68
|
+
to: string,
|
|
69
|
+
conversions?: ConversionRule[]
|
|
70
|
+
): ResolvedConverter | undefined => {
|
|
71
|
+
const rule = conversions?.find((c) => c.from === from && c.to === to);
|
|
72
|
+
if (rule) {
|
|
73
|
+
const spec = specs.find((s) => s.type === rule.nodeType);
|
|
74
|
+
const inputName =
|
|
75
|
+
rule.inputKey ?? socketNameForType(spec?.inputs ?? [], from);
|
|
76
|
+
const outputName =
|
|
77
|
+
rule.outputKey ?? socketNameForType(spec?.outputs ?? [], to);
|
|
78
|
+
if (inputName && outputName) {
|
|
79
|
+
return { nodeType: rule.nodeType, inputName, outputName };
|
|
80
|
+
}
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const spec = findConverterSpec(specs, from, to);
|
|
85
|
+
if (!spec) return undefined;
|
|
86
|
+
const inputName = firstValueSocketName(spec.inputs);
|
|
87
|
+
const outputName = firstValueSocketName(spec.outputs);
|
|
88
|
+
if (!inputName || !outputName) return undefined;
|
|
89
|
+
return { nodeType: spec.type, inputName, outputName };
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** Resolve a node socket's value type (spec sockets merged with dynamic ports). */
|
|
93
|
+
const getSocketValueType = (
|
|
94
|
+
node: IBehaveNode,
|
|
95
|
+
handleId: string | null | undefined,
|
|
96
|
+
handleType: 'source' | 'target',
|
|
97
|
+
specs: NodeSpecJSON[]
|
|
98
|
+
): string | undefined => {
|
|
99
|
+
if (!handleId) return undefined;
|
|
100
|
+
const specSockets = getSocketsByNodeTypeAndHandleType(
|
|
101
|
+
specs,
|
|
102
|
+
node.data?.type,
|
|
103
|
+
handleType
|
|
104
|
+
);
|
|
105
|
+
if (!specSockets) return undefined;
|
|
106
|
+
const dynamic =
|
|
107
|
+
handleType === 'source'
|
|
108
|
+
? node.data.dynamicPorts?.outputs
|
|
109
|
+
: node.data.dynamicPorts?.inputs;
|
|
110
|
+
const sockets = mergeSockets(specSockets, dynamic);
|
|
111
|
+
return sockets.find((s) => s.name === handleId)?.valueType;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export type ConverterInsertion = { node: IBehaveNode; edges: Edge[] };
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* If a connection joins different-but-convertible value types, build the
|
|
118
|
+
* converter node and the two edges needed to splice it in between source and
|
|
119
|
+
* target. Returns null when the types match, can't be resolved, or no converter
|
|
120
|
+
* is registered.
|
|
121
|
+
*/
|
|
122
|
+
export const buildConverterInsertion = (
|
|
123
|
+
connection: Connection,
|
|
124
|
+
nodes: Node[],
|
|
125
|
+
specs: NodeSpecJSON[],
|
|
126
|
+
conversions?: ConversionRule[]
|
|
127
|
+
): ConverterInsertion | null => {
|
|
128
|
+
if (!connection.source || !connection.target) return null;
|
|
129
|
+
|
|
130
|
+
const sourceNode = nodes.find((n) => n.id === connection.source) as
|
|
131
|
+
| IBehaveNode
|
|
132
|
+
| undefined;
|
|
133
|
+
const targetNode = nodes.find((n) => n.id === connection.target) as
|
|
134
|
+
| IBehaveNode
|
|
135
|
+
| undefined;
|
|
136
|
+
if (!sourceNode || !targetNode) return null;
|
|
137
|
+
|
|
138
|
+
const sourceType = getSocketValueType(
|
|
139
|
+
sourceNode,
|
|
140
|
+
connection.sourceHandle,
|
|
141
|
+
'source',
|
|
142
|
+
specs
|
|
143
|
+
);
|
|
144
|
+
const targetType = getSocketValueType(
|
|
145
|
+
targetNode,
|
|
146
|
+
connection.targetHandle,
|
|
147
|
+
'target',
|
|
148
|
+
specs
|
|
149
|
+
);
|
|
150
|
+
if (!sourceType || !targetType) return null;
|
|
151
|
+
if (sourceType === targetType) return null;
|
|
152
|
+
if (sourceType === 'flow' || targetType === 'flow') return null;
|
|
153
|
+
|
|
154
|
+
const converter = resolveConverter(
|
|
155
|
+
specs,
|
|
156
|
+
sourceType,
|
|
157
|
+
targetType,
|
|
158
|
+
conversions
|
|
159
|
+
);
|
|
160
|
+
if (!converter) return null;
|
|
161
|
+
|
|
162
|
+
const { nodeType, inputName: inName, outputName: outName } = converter;
|
|
163
|
+
|
|
164
|
+
const position: XYPosition = {
|
|
165
|
+
x: (sourceNode.position.x + targetNode.position.x) / 2,
|
|
166
|
+
y: (sourceNode.position.y + targetNode.position.y) / 2
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const convId = uuidv4();
|
|
170
|
+
const node: IBehaveNode = {
|
|
171
|
+
id: convId,
|
|
172
|
+
type: 'behaveNode',
|
|
173
|
+
position,
|
|
174
|
+
data: {
|
|
175
|
+
type: nodeType,
|
|
176
|
+
configuration: {},
|
|
177
|
+
ports: {},
|
|
178
|
+
dynamicPorts: {}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const edges: Edge[] = [
|
|
183
|
+
{
|
|
184
|
+
id: uuidv4(),
|
|
185
|
+
source: connection.source,
|
|
186
|
+
sourceHandle: connection.sourceHandle ?? undefined,
|
|
187
|
+
target: convId,
|
|
188
|
+
targetHandle: inName
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
id: uuidv4(),
|
|
192
|
+
source: convId,
|
|
193
|
+
sourceHandle: outName,
|
|
194
|
+
target: connection.target,
|
|
195
|
+
targetHandle: connection.targetHandle ?? undefined
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
return { node, edges };
|
|
200
|
+
};
|
package/src/util/colors.ts
CHANGED
|
@@ -1,34 +1,6 @@
|
|
|
1
1
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
2
2
|
|
|
3
|
-
export
|
|
4
|
-
| 'red'
|
|
5
|
-
| 'green'
|
|
6
|
-
| 'lime'
|
|
7
|
-
| 'purple'
|
|
8
|
-
| 'blue'
|
|
9
|
-
| 'gray'
|
|
10
|
-
| 'white';
|
|
11
|
-
|
|
12
|
-
export const colors: Record<color, [string, string, string]> = {
|
|
13
|
-
red: ['bg-orange-700', 'border-orange-700', 'text-white'],
|
|
14
|
-
green: ['bg-green-600', 'border-green-600', 'text-white'],
|
|
15
|
-
lime: ['bg-lime-500', 'border-lime-500', 'text-gray-900'],
|
|
16
|
-
purple: ['bg-purple-500', 'border-purple-500', 'text-white'],
|
|
17
|
-
blue: ['bg-cyan-600', 'border-cyan-600', 'text-white'],
|
|
18
|
-
gray: ['bg-gray-500', 'border-gray-500', 'text-white'],
|
|
19
|
-
white: ['bg-white', 'border-white', 'text-gray-700']
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const valueTypeColorMap: Record<string, string> = {
|
|
23
|
-
flow: 'white',
|
|
24
|
-
number: 'green',
|
|
25
|
-
float: 'green',
|
|
26
|
-
integer: 'lime',
|
|
27
|
-
boolean: 'red',
|
|
28
|
-
string: 'purple'
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const categoryColorMap: Record<NodeSpecJSON['category'], color> = {
|
|
3
|
+
export const categoryColorMap: Record<NodeSpecJSON['category'], string> = {
|
|
32
4
|
Event: 'red',
|
|
33
5
|
Logic: 'green',
|
|
34
6
|
Variable: 'purple',
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use this on a subscription to the graph:save event to trigger a download of the graph JSON data. This is useful for users who want to keep a local backup of their graphs, or for debugging purposes.
|
|
3
|
+
* @param filename
|
|
4
|
+
* @param data
|
|
5
|
+
*/
|
|
6
|
+
export function downloadJson(filename: string, data: unknown) {
|
|
7
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], {
|
|
8
|
+
type: 'application/json'
|
|
9
|
+
});
|
|
10
|
+
const url = URL.createObjectURL(blob);
|
|
11
|
+
const link = document.createElement('a');
|
|
12
|
+
link.href = url;
|
|
13
|
+
link.download = filename;
|
|
14
|
+
document.body.appendChild(link);
|
|
15
|
+
link.click();
|
|
16
|
+
link.remove();
|
|
17
|
+
URL.revokeObjectURL(url);
|
|
18
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writeNodeSpecsToJSON,
|
|
3
|
+
type IRegistry
|
|
4
|
+
} from '@kiberon-labs/behave-graph';
|
|
5
|
+
import type { INodeRegistry } from '../types/NodeMetadata.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Extract pure node metadata from a behave-graph registry.
|
|
9
|
+
* Used by the visual graph editor to initialize a System without execution dependencies.
|
|
10
|
+
*/
|
|
11
|
+
export function extractNodeMetadata(registry: IRegistry): INodeRegistry {
|
|
12
|
+
return {
|
|
13
|
+
values: registry.values,
|
|
14
|
+
specs: writeNodeSpecsToJSON(registry)
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
2
2
|
import type { Node, OnConnectStartParams } from 'reactflow';
|
|
3
|
-
import type { NodePickerFilters } from '../components/NodePicker.js';
|
|
3
|
+
import type { NodePickerFilters } from '../components/contextMenus/NodePicker.js';
|
|
4
4
|
import { getSocketsByNodeTypeAndHandleType } from './getSocketsByNodeTypeAndHandleType.js';
|
|
5
5
|
|
|
6
6
|
export const getNodePickerFilters = (
|
|
@@ -1,40 +1,56 @@
|
|
|
1
1
|
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
2
2
|
import type { Connection, ReactFlowInstance } from 'reactflow';
|
|
3
|
-
|
|
4
3
|
import { getSocketsByNodeTypeAndHandleType } from './getSocketsByNodeTypeAndHandleType.js';
|
|
5
4
|
import { isHandleConnected } from './isHandleConnected.js';
|
|
5
|
+
import { mergeSockets } from './mergeSockets.js';
|
|
6
|
+
import { resolveConverter } from './autoConvert.js';
|
|
7
|
+
import type { ConversionRule } from '@/store/conversions';
|
|
8
|
+
import type { IBehaveNode } from '@/types/nodes.js';
|
|
6
9
|
|
|
7
10
|
export const isValidConnection = (
|
|
8
11
|
connection: Connection,
|
|
9
12
|
instance: ReactFlowInstance,
|
|
10
|
-
specJSON: NodeSpecJSON[]
|
|
13
|
+
specJSON: NodeSpecJSON[],
|
|
14
|
+
options?: { autoConvert?: boolean; conversions?: ConversionRule[] }
|
|
11
15
|
) => {
|
|
12
16
|
if (connection.source === null || connection.target === null) return false;
|
|
13
17
|
|
|
14
|
-
const sourceNode = instance.getNode(connection.source);
|
|
15
|
-
const targetNode = instance.getNode(connection.target);
|
|
18
|
+
const sourceNode = instance.getNode(connection.source) as IBehaveNode;
|
|
19
|
+
const targetNode = instance.getNode(connection.target) as IBehaveNode;
|
|
16
20
|
const edges = instance.getEdges();
|
|
17
21
|
|
|
18
22
|
if (sourceNode === undefined || targetNode === undefined) return false;
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
// Get spec sockets
|
|
25
|
+
const sourceSpecSockets = getSocketsByNodeTypeAndHandleType(
|
|
21
26
|
specJSON,
|
|
22
|
-
sourceNode.type,
|
|
27
|
+
sourceNode.data?.type,
|
|
23
28
|
'source'
|
|
24
29
|
);
|
|
25
|
-
|
|
26
|
-
const sourceSocket = sourceSockets?.find(
|
|
27
|
-
(socket) => socket.name === connection.sourceHandle
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
const targetSockets = getSocketsByNodeTypeAndHandleType(
|
|
30
|
+
const targetSpecSockets = getSocketsByNodeTypeAndHandleType(
|
|
31
31
|
specJSON,
|
|
32
|
-
targetNode.type,
|
|
32
|
+
targetNode.data?.type,
|
|
33
33
|
'target'
|
|
34
34
|
);
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
if (sourceSpecSockets === undefined || targetSpecSockets === undefined)
|
|
37
|
+
return false;
|
|
38
|
+
|
|
39
|
+
// Merge spec sockets with dynamic ports
|
|
40
|
+
const sourceSockets = mergeSockets(
|
|
41
|
+
sourceSpecSockets,
|
|
42
|
+
sourceNode.data.dynamicPorts?.outputs
|
|
43
|
+
);
|
|
44
|
+
const targetSockets = mergeSockets(
|
|
45
|
+
targetSpecSockets,
|
|
46
|
+
targetNode.data.dynamicPorts?.inputs
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const sourceSocket = sourceSockets.find(
|
|
50
|
+
(s) => s.name === connection.sourceHandle
|
|
51
|
+
);
|
|
52
|
+
const targetSocket = targetSockets.find(
|
|
53
|
+
(s) => s.name === connection.targetHandle
|
|
38
54
|
);
|
|
39
55
|
|
|
40
56
|
if (sourceSocket === undefined || targetSocket === undefined) return false;
|
|
@@ -42,10 +58,28 @@ export const isValidConnection = (
|
|
|
42
58
|
// only flow sockets can have two inputs
|
|
43
59
|
if (
|
|
44
60
|
targetSocket.valueType !== 'flow' &&
|
|
45
|
-
isHandleConnected(edges, targetNode.id, targetSocket.
|
|
61
|
+
isHandleConnected(edges, targetNode.id, targetSocket.key, 'target')
|
|
46
62
|
) {
|
|
47
63
|
return false;
|
|
48
64
|
}
|
|
49
65
|
|
|
50
|
-
|
|
66
|
+
if (sourceSocket.valueType === targetSocket.valueType) return true;
|
|
67
|
+
|
|
68
|
+
// Different value types are allowed when auto-convert can splice in a
|
|
69
|
+
// converter node (handled on connect).
|
|
70
|
+
if (
|
|
71
|
+
options?.autoConvert &&
|
|
72
|
+
sourceSocket.valueType !== 'flow' &&
|
|
73
|
+
targetSocket.valueType !== 'flow' &&
|
|
74
|
+
resolveConverter(
|
|
75
|
+
specJSON,
|
|
76
|
+
sourceSocket.valueType,
|
|
77
|
+
targetSocket.valueType,
|
|
78
|
+
options.conversions
|
|
79
|
+
)
|
|
80
|
+
) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return false;
|
|
51
85
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
InputSocketSpecJSON,
|
|
3
|
+
OutputSocketSpecJSON
|
|
4
|
+
} from '@kiberon-labs/behave-graph';
|
|
5
|
+
import type { SocketBase } from '../types.js';
|
|
6
|
+
|
|
7
|
+
type SpecSocket = InputSocketSpecJSON | OutputSocketSpecJSON;
|
|
8
|
+
|
|
9
|
+
function toSocketBase(socket: SpecSocket): SocketBase {
|
|
10
|
+
return { ...socket, key: socket.name };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Merges spec sockets with dynamic port overrides.
|
|
15
|
+
* Spec sockets use 'name' as identifier, dynamic ports use 'key'.
|
|
16
|
+
* Dynamic ports can override spec sockets when their key matches the spec socket's name.
|
|
17
|
+
*/
|
|
18
|
+
export function mergeSockets(
|
|
19
|
+
specSockets: SpecSocket[],
|
|
20
|
+
dynamicPorts?: SocketBase[]
|
|
21
|
+
): SocketBase[] {
|
|
22
|
+
const socketsMap = new Map(specSockets.map((s) => [s.name, toSocketBase(s)]));
|
|
23
|
+
|
|
24
|
+
if (dynamicPorts) {
|
|
25
|
+
dynamicPorts.forEach((s) => socketsMap.set(s.key, s));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return Array.from(socketsMap.values());
|
|
29
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Serialize variables to JSON using pure metadata
|
|
3
|
+
* This replaces the need for WriteVariablesToJSON from @kiberon-labs/behave-graph
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { INodeRegistry } from '../types/NodeMetadata';
|
|
7
|
+
|
|
8
|
+
export interface VariableJSON {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
valueTypeName: string;
|
|
12
|
+
initialValue: any;
|
|
13
|
+
label?: string;
|
|
14
|
+
metadata?: Record<string, any>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Variable {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
valueTypeName: string;
|
|
21
|
+
initialValue: any;
|
|
22
|
+
label?: string;
|
|
23
|
+
metadata?: Record<string, any>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Serialize a single variable to JSON
|
|
28
|
+
*/
|
|
29
|
+
export function serializeVariable(
|
|
30
|
+
variable: Variable,
|
|
31
|
+
registry: INodeRegistry
|
|
32
|
+
): VariableJSON {
|
|
33
|
+
const valueType = registry.values[variable.valueTypeName];
|
|
34
|
+
const serializedValue = valueType?.serialize
|
|
35
|
+
? valueType.serialize(variable.initialValue)
|
|
36
|
+
: variable.initialValue;
|
|
37
|
+
|
|
38
|
+
const variableJson: VariableJSON = {
|
|
39
|
+
id: variable.id,
|
|
40
|
+
name: variable.name,
|
|
41
|
+
valueTypeName: variable.valueTypeName,
|
|
42
|
+
initialValue: serializedValue
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
if (variable.label && variable.label.length > 0) {
|
|
46
|
+
variableJson.label = variable.label;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (variable.metadata && Object.keys(variable.metadata).length > 0) {
|
|
50
|
+
variableJson.metadata = variable.metadata;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return variableJson;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Serialize multiple variables to JSON array
|
|
58
|
+
*/
|
|
59
|
+
export function writeVariablesToJSON(
|
|
60
|
+
registry: INodeRegistry,
|
|
61
|
+
variables: Record<string, Variable>
|
|
62
|
+
): VariableJSON[] {
|
|
63
|
+
return Object.values(variables).map((variable) =>
|
|
64
|
+
serializeVariable(variable, registry)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
|
|
2
|
+
|
|
3
|
+
import type { SocketBase, DynamicPorts } from '../types.js';
|
|
4
|
+
import { mergeSockets } from './mergeSockets.js';
|
|
5
|
+
|
|
6
|
+
const getPairs = <T, U>(arr1: T[], arr2: U[]) => {
|
|
7
|
+
const max = Math.max(arr1.length, arr2.length);
|
|
8
|
+
const pairs = [];
|
|
9
|
+
for (let i = 0; i < max; i++) {
|
|
10
|
+
const pair: [T | undefined, U | undefined] = [arr1[i], arr2[i]];
|
|
11
|
+
pairs.push(pair);
|
|
12
|
+
}
|
|
13
|
+
return pairs;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type Configuration = Record<string, any>;
|
|
17
|
+
|
|
18
|
+
export function configureSockets(
|
|
19
|
+
config: Configuration,
|
|
20
|
+
spec: NodeSpecJSON,
|
|
21
|
+
ports?: DynamicPorts
|
|
22
|
+
) {
|
|
23
|
+
const configInputs = config?.socketInputs || [];
|
|
24
|
+
|
|
25
|
+
const configOutputs = config?.socketOutputs || [];
|
|
26
|
+
|
|
27
|
+
// Merge spec sockets with ports overrides (specifics can override subset of sockets)
|
|
28
|
+
const baseInputs = mergeSockets(spec.inputs, ports?.inputs);
|
|
29
|
+
const baseOutputs = mergeSockets(spec.outputs, ports?.outputs);
|
|
30
|
+
|
|
31
|
+
const inputs: SocketBase[] = [...baseInputs, ...configInputs];
|
|
32
|
+
const outputs: SocketBase[] = [...baseOutputs, ...configOutputs];
|
|
33
|
+
|
|
34
|
+
const flowInputs = inputs.filter((input) => input.valueType === 'flow');
|
|
35
|
+
const flowOutputs = outputs.filter((output) => output.valueType === 'flow');
|
|
36
|
+
|
|
37
|
+
const valueInputs = inputs.filter((input) => input.valueType !== 'flow');
|
|
38
|
+
const valueOutputs = outputs.filter((output) => output.valueType !== 'flow');
|
|
39
|
+
|
|
40
|
+
const pairs = getPairs(flowInputs, [...flowOutputs, ...valueOutputs]);
|
|
41
|
+
|
|
42
|
+
return { pairs, valueInputs, valueOutputs, flowInputs, flowOutputs };
|
|
43
|
+
}
|