@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,131 @@
|
|
|
1
|
+
import type { Viewport } from 'reactflow';
|
|
2
|
+
import type { GraphSession } from './graphSession';
|
|
3
|
+
import type { Edge } from 'reactflow';
|
|
4
|
+
import type { UIGraphJSON } from '@/types/graph';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This is our internal graph representation that we use to perform transformations on
|
|
8
|
+
* It represents the general graph structure, not the underlying behavior graph instance
|
|
9
|
+
*/
|
|
10
|
+
export class Graph {
|
|
11
|
+
public readonly viewports: Viewport[] = [];
|
|
12
|
+
private sys: GraphSession;
|
|
13
|
+
|
|
14
|
+
constructor(session: GraphSession) {
|
|
15
|
+
this.sys = session;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
setViewport(index: number, viewport: Viewport) {
|
|
19
|
+
this.viewports[index] = viewport;
|
|
20
|
+
this.sys.pubsub.publish('saveViewport', {
|
|
21
|
+
index: index,
|
|
22
|
+
viewport: viewport
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Clears the graph
|
|
28
|
+
*/
|
|
29
|
+
clear() {
|
|
30
|
+
const nodes = this.sys.nodeStore.getState().nodes;
|
|
31
|
+
const edges = this.sys.edgeStore.getState().edges;
|
|
32
|
+
this.sys.undoManager.execute({
|
|
33
|
+
name: 'Clear graph',
|
|
34
|
+
undo: () => {
|
|
35
|
+
this.sys.nodeStore.getState().setNodes(Object.values(nodes));
|
|
36
|
+
this.sys.edgeStore.getState().setEdges(Object.values(edges));
|
|
37
|
+
},
|
|
38
|
+
execute: () => {
|
|
39
|
+
this.sys.nodeStore.getState().setNodes([]);
|
|
40
|
+
this.sys.edgeStore.getState().setEdges([]);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Return all edges that point into the nodes inputs.
|
|
47
|
+
* O(m) the amount of edges
|
|
48
|
+
*/
|
|
49
|
+
inEdges(nodeId: string, sourceHandle?: string): Edge[] {
|
|
50
|
+
//Get the edges
|
|
51
|
+
const edges = this.sys.edgeStore.getState().edges;
|
|
52
|
+
|
|
53
|
+
return Object.values(edges).filter((x) => {
|
|
54
|
+
if (x.target !== nodeId) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (sourceHandle) {
|
|
58
|
+
return x.targetHandle === sourceHandle;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Return all edges that are pointed out by node v.
|
|
66
|
+
* O(m) the amount of edges
|
|
67
|
+
*/
|
|
68
|
+
outEdges(nodeId: string, targetHandle?: string): Edge[] {
|
|
69
|
+
//Get the edges
|
|
70
|
+
const edges = this.sys.edgeStore.getState().edges;
|
|
71
|
+
|
|
72
|
+
return Object.values(edges).filter((x) => {
|
|
73
|
+
if (x.source !== nodeId) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (targetHandle) {
|
|
77
|
+
return x.targetHandle === targetHandle;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
serialize(): UIGraphJSON {
|
|
84
|
+
const meta = this.sys.metaStore.getState();
|
|
85
|
+
return {
|
|
86
|
+
v: '1.0.0',
|
|
87
|
+
name: meta.name,
|
|
88
|
+
user: {
|
|
89
|
+
viewport: this.viewports[0] || { x: 0, y: 0, zoom: 1 }
|
|
90
|
+
},
|
|
91
|
+
annotations: { ...meta.metadata },
|
|
92
|
+
data: {
|
|
93
|
+
layers: this.sys.layerStore.getState().serialize()
|
|
94
|
+
},
|
|
95
|
+
flow: {},
|
|
96
|
+
nodes: Object.values(this.sys.nodeStore.getState().nodes),
|
|
97
|
+
edges: Object.values(this.sys.edgeStore.getState().edges)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getAnnotations() {
|
|
102
|
+
return { ...this.sys.metaStore.getState().metadata };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
setAnnotations(annotations: { [key: string]: any }) {
|
|
106
|
+
this.sys.metaStore.getState().mergeMetadata(annotations);
|
|
107
|
+
this.sys.pubsub.publish('graphAnnotationsChanged', this.getAnnotations());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
deseralize(data: UIGraphJSON) {
|
|
111
|
+
//Load nodes
|
|
112
|
+
this.sys.nodeStore.getState().setNodes(data.nodes);
|
|
113
|
+
this.sys.edgeStore.getState().setEdges(data.edges);
|
|
114
|
+
this.sys.metaStore.getState().setMetadata(data.annotations || {});
|
|
115
|
+
if (data.name) this.sys.metaStore.getState().setName(data.name);
|
|
116
|
+
this.sys.layerStore.getState().deserialize(data.data?.layers);
|
|
117
|
+
|
|
118
|
+
// Restore viewport
|
|
119
|
+
if (data.user?.viewport) {
|
|
120
|
+
const reactflow = this.sys.refStore.getState().getRef('reactflow');
|
|
121
|
+
if (reactflow) {
|
|
122
|
+
reactflow.setViewport(data.user.viewport);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Restore multiple viewports if they exist
|
|
127
|
+
if (data.user?.viewports) {
|
|
128
|
+
this.viewports.splice(0, this.viewports.length, ...data.user.viewports);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { type StoreApi } from 'zustand';
|
|
2
|
+
import { UndoManager } from './undoRedo';
|
|
3
|
+
import { PubSub } from './pubsub';
|
|
4
|
+
import { Graph } from './graph';
|
|
5
|
+
import type { System, GraphPubSys } from './system';
|
|
6
|
+
import {
|
|
7
|
+
edgeStoreFactory,
|
|
8
|
+
flowStoreFactory,
|
|
9
|
+
nodeStoreFactory,
|
|
10
|
+
type EdgeStore,
|
|
11
|
+
type FlowStore,
|
|
12
|
+
type NodeStore
|
|
13
|
+
} from '@/store/flow';
|
|
14
|
+
import { controlsStoreFactory, type ControlsStore } from '@/store/controls';
|
|
15
|
+
import { variableStoreFactory, type VariableStore } from '@/store/variables';
|
|
16
|
+
import { selectionStoreFactory, type SelectionStore } from '@/store/selection';
|
|
17
|
+
import { refStoreFactory, type RefStore } from '@/store/refs';
|
|
18
|
+
import { actionStoreFactory, type ActionStore } from '@/store/actions';
|
|
19
|
+
import { traceStoreFactory, type TraceStore } from '@/store/traces';
|
|
20
|
+
import { eventsStoreFactory, type EventsStore } from '@/store/events';
|
|
21
|
+
import { layerStoreFactory, type LayerStore } from '@/store/layers';
|
|
22
|
+
import { logStoreFactory, type LogStore } from '@/store/logs';
|
|
23
|
+
import { graphMetaStoreFactory, type GraphMetaStore } from '@/store/graphMeta';
|
|
24
|
+
import type { UIGraphJSON } from '@/types/graph';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Augmentable surface for per-graph state contributed by plugins. Mirrors
|
|
28
|
+
* {@link ISystem} at the editor level: a plugin adds typed properties to every
|
|
29
|
+
* graph by augmenting this interface and assigning them via
|
|
30
|
+
* {@link GraphSession.decorate} from inside a session extension.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* declare module '@/system/graphSession' {
|
|
34
|
+
* interface IGraphSession {
|
|
35
|
+
* myController?: MyController;
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
*/
|
|
39
|
+
export interface IGraphSession {}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Merge the augmentable surface into the class instance type. Declaration
|
|
43
|
+
* merging (same-named interface + class) makes plugin-added members , set via
|
|
44
|
+
* {@link GraphSession.decorate} , readable as `session.x`, which `implements`
|
|
45
|
+
* alone would NOT provide.
|
|
46
|
+
*/
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
48
|
+
export interface GraphSession extends IGraphSession {}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A single open graph. Owns all per-graph state , nodes, edges, variables,
|
|
52
|
+
* selection, traces, layers, logs, undo history and a private pubsub , so that
|
|
53
|
+
* multiple graphs can be open simultaneously in complete isolation.
|
|
54
|
+
*
|
|
55
|
+
* Shared, editor-level resources (registry, specs, settings, notifications, ...)
|
|
56
|
+
* are reached through {@link GraphSession.editor}.
|
|
57
|
+
*
|
|
58
|
+
* Per-graph state contributed by editor plugins is attached on creation via
|
|
59
|
+
* session extensions (`system.registerSessionExtension`), which may register
|
|
60
|
+
* teardown through {@link GraphSession.onDispose}.
|
|
61
|
+
*/
|
|
62
|
+
export class GraphSession {
|
|
63
|
+
public readonly id: string;
|
|
64
|
+
public readonly editor: System;
|
|
65
|
+
/** Reactive graph-level properties (name + metadata). */
|
|
66
|
+
public readonly metaStore: StoreApi<GraphMetaStore>;
|
|
67
|
+
public readonly pubsub = new PubSub<GraphPubSys>();
|
|
68
|
+
public readonly undoManager = new UndoManager();
|
|
69
|
+
|
|
70
|
+
/** Display name, used as the graph tab title. Backed by {@link metaStore}. */
|
|
71
|
+
get name(): string {
|
|
72
|
+
return this.metaStore.getState().name;
|
|
73
|
+
}
|
|
74
|
+
set name(value: string) {
|
|
75
|
+
this.metaStore.getState().setName(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public readonly controlStore: StoreApi<ControlsStore>;
|
|
79
|
+
public readonly variableStore: StoreApi<VariableStore>;
|
|
80
|
+
public readonly refStore: StoreApi<RefStore>;
|
|
81
|
+
public readonly logsStore: StoreApi<LogStore>;
|
|
82
|
+
public readonly eventsStore: StoreApi<EventsStore>;
|
|
83
|
+
public readonly nodeStore: StoreApi<NodeStore>;
|
|
84
|
+
public readonly edgeStore: StoreApi<EdgeStore>;
|
|
85
|
+
public readonly flowStore: StoreApi<FlowStore>;
|
|
86
|
+
public readonly selectionStore: StoreApi<SelectionStore>;
|
|
87
|
+
public readonly actionStore: StoreApi<ActionStore>;
|
|
88
|
+
public readonly layerStore: StoreApi<LayerStore>;
|
|
89
|
+
public readonly traceStore: StoreApi<TraceStore>;
|
|
90
|
+
public readonly graph: Graph;
|
|
91
|
+
|
|
92
|
+
/** Cleanups registered by session extensions, run (LIFO) on {@link dispose}. */
|
|
93
|
+
private readonly disposers: Array<() => void> = [];
|
|
94
|
+
|
|
95
|
+
constructor(editor: System, id = 'graph', name = 'Graph') {
|
|
96
|
+
this.id = id;
|
|
97
|
+
this.editor = editor;
|
|
98
|
+
this.metaStore = graphMetaStoreFactory(name);
|
|
99
|
+
|
|
100
|
+
// Construction order preserves the dependency wiring of the old System ctor.
|
|
101
|
+
this.controlStore = controlsStoreFactory();
|
|
102
|
+
this.variableStore = variableStoreFactory();
|
|
103
|
+
this.refStore = refStoreFactory();
|
|
104
|
+
this.logsStore = logStoreFactory();
|
|
105
|
+
this.eventsStore = eventsStoreFactory();
|
|
106
|
+
this.nodeStore = nodeStoreFactory(this);
|
|
107
|
+
this.edgeStore = edgeStoreFactory(this);
|
|
108
|
+
this.flowStore = flowStoreFactory(this);
|
|
109
|
+
this.selectionStore = selectionStoreFactory(this);
|
|
110
|
+
this.actionStore = actionStoreFactory(this);
|
|
111
|
+
this.layerStore = layerStoreFactory(this);
|
|
112
|
+
this.traceStore = traceStoreFactory(this);
|
|
113
|
+
this.graph = new Graph(this);
|
|
114
|
+
|
|
115
|
+
// Per-session behaviours (alignment, ...) are contributed by opt-in plugins
|
|
116
|
+
// via system.registerSessionExtension(...), not wired here. See the
|
|
117
|
+
// alignment plugin (`@/plugin/alignment`).
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Convenience access to the shared editor notifications service.
|
|
122
|
+
*/
|
|
123
|
+
get notifications() {
|
|
124
|
+
return this.editor.notifications;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Attach a plugin-contributed property to this session. The companion to the
|
|
129
|
+
* {@link IGraphSession} augmentation; mirrors {@link System.decorate}.
|
|
130
|
+
*/
|
|
131
|
+
decorate<K extends keyof IGraphSession>(
|
|
132
|
+
name: K,
|
|
133
|
+
val: IGraphSession[K]
|
|
134
|
+
): void {
|
|
135
|
+
(this as IGraphSession)[name] = val;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Register a cleanup to run when this session is disposed. Session extensions
|
|
140
|
+
* use this (via their returned cleanup) to tear down per-graph state they
|
|
141
|
+
* attached. Cleanups run in reverse registration order.
|
|
142
|
+
*/
|
|
143
|
+
onDispose(cleanup: () => void): void {
|
|
144
|
+
this.disposers.push(cleanup);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
serialize(): UIGraphJSON {
|
|
148
|
+
return this.graph.serialize();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Tear down this session's reactive wiring. Called when its tab is closed so
|
|
153
|
+
* its pubsub subscriptions and trace flush loop don't leak. Extension-supplied
|
|
154
|
+
* cleanups run first (LIFO), then the built-in teardown.
|
|
155
|
+
*/
|
|
156
|
+
dispose(): void {
|
|
157
|
+
for (let i = this.disposers.length - 1; i >= 0; i--) {
|
|
158
|
+
try {
|
|
159
|
+
this.disposers[i]!();
|
|
160
|
+
} catch (err) {
|
|
161
|
+
console.error('GraphSession disposer failed', err);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
this.disposers.length = 0;
|
|
165
|
+
|
|
166
|
+
// Per-session plugin state (e.g. the graph runner's runController) is torn
|
|
167
|
+
// down by the extension cleanups registered above via onDispose , core no
|
|
168
|
+
// longer reaches into plugin-owned fields here.
|
|
169
|
+
this.traceStore.getState().connectEngine(undefined);
|
|
170
|
+
this.pubsub.clearAllSubscriptions();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { System } from '@/system/system';
|
|
2
|
+
import type { Renderable, Toast } from 'react-hot-toast';
|
|
3
|
+
|
|
4
|
+
export type NotificationType = 'info' | 'success' | 'error' | 'loading';
|
|
5
|
+
|
|
6
|
+
export interface NotificationData {
|
|
7
|
+
type: NotificationType;
|
|
8
|
+
message: string;
|
|
9
|
+
options?: {
|
|
10
|
+
id?: string;
|
|
11
|
+
duration?: number;
|
|
12
|
+
position?: any;
|
|
13
|
+
icon?: Renderable;
|
|
14
|
+
style?: React.CSSProperties;
|
|
15
|
+
className?: string;
|
|
16
|
+
ariaLive?: any;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export interface NotificationOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Toast ID for programmatic dismissal
|
|
22
|
+
*/
|
|
23
|
+
id?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Duration in milliseconds. Set to Infinity to persist until manually dismissed
|
|
26
|
+
*/
|
|
27
|
+
duration?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Position on screen
|
|
30
|
+
*/
|
|
31
|
+
position?: Toast['position'];
|
|
32
|
+
/**
|
|
33
|
+
* Custom icon
|
|
34
|
+
*/
|
|
35
|
+
icon?: Renderable;
|
|
36
|
+
/**
|
|
37
|
+
* Custom styles
|
|
38
|
+
*/
|
|
39
|
+
style?: React.CSSProperties;
|
|
40
|
+
/**
|
|
41
|
+
* Custom class name
|
|
42
|
+
*/
|
|
43
|
+
className?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Accessible aria-live value
|
|
46
|
+
*/
|
|
47
|
+
ariaLive?: Toast['ariaProps'];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class Notifications {
|
|
51
|
+
private readonly system: System;
|
|
52
|
+
constructor(system: System) {
|
|
53
|
+
this.system = system;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Dismiss a specific toast or all toasts
|
|
57
|
+
*/
|
|
58
|
+
dismissNotification(toastId?: string): void {
|
|
59
|
+
this.system.pubsub.publish('notification:dismiss', { toastId });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Show a notification toast
|
|
64
|
+
*/
|
|
65
|
+
notify(
|
|
66
|
+
message: string,
|
|
67
|
+
type: NotificationType = 'info',
|
|
68
|
+
options?: NotificationOptions
|
|
69
|
+
): void {
|
|
70
|
+
this.system.pubsub.publish('notification', {
|
|
71
|
+
type,
|
|
72
|
+
message,
|
|
73
|
+
options
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Show a success notification
|
|
79
|
+
*/
|
|
80
|
+
success(message: string, options?: NotificationOptions): void {
|
|
81
|
+
this.notify(message, 'success', options);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Show an error notification
|
|
86
|
+
*/
|
|
87
|
+
error(message: string, options?: NotificationOptions): void {
|
|
88
|
+
this.notify(message, 'error', options);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Show a loading notification
|
|
93
|
+
*/
|
|
94
|
+
loading(message: string, options?: NotificationOptions): void {
|
|
95
|
+
this.notify(message, 'loading', options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Show an info notification
|
|
100
|
+
*/
|
|
101
|
+
info(message: string, options?: NotificationOptions): void {
|
|
102
|
+
this.notify(message, 'info', options);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Dismiss a specific toast or all toasts
|
|
107
|
+
*/
|
|
108
|
+
dismiss(toastId?: string): void {
|
|
109
|
+
this.system.pubsub.publish('notification:dismiss', { toastId });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { LayoutBase } from 'rc-dock';
|
|
2
|
+
import type { GraphJSON } from '@kiberon-labs/behave-graph';
|
|
3
|
+
import type { UIGraphJSON } from '@/types/graph';
|
|
4
|
+
import { downloadJson } from '@/util/downloadJson';
|
|
5
|
+
import type { System } from './system';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sinks invoked when the editor emits its save events. Each entry maps one
|
|
9
|
+
* editor-level pubsub topic to the side effect that persists it (write the JSON
|
|
10
|
+
* somewhere). Override any subset to redirect where saved data goes; sinks left
|
|
11
|
+
* unspecified keep the built-in file-download behaviour.
|
|
12
|
+
*
|
|
13
|
+
* Loading is not represented here: the menubar's "Load" items already read a
|
|
14
|
+
* file from disk and deserialize it into the focused graph by default, so there
|
|
15
|
+
* is nothing host-specific to wire for the common case.
|
|
16
|
+
*/
|
|
17
|
+
export interface PersistenceAdapter {
|
|
18
|
+
/** Persist a full UI graph save (`graph:saved`). */
|
|
19
|
+
saveGraph: (graph: UIGraphJSON) => void;
|
|
20
|
+
/** Persist a raw inner behave-graph save (`graph:inner:saved`). */
|
|
21
|
+
saveInnerGraph: (graph: GraphJSON) => void;
|
|
22
|
+
/** Persist a dock layout save (`layout:saved`). */
|
|
23
|
+
saveLayout: (layout: LayoutBase) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Whether the file-download default can run. Guards the built-in sinks so that
|
|
28
|
+
* constructing a `System` in a non-DOM context (tests, SSR, the compiler) never
|
|
29
|
+
* throws , the subscriptions are harmless, only the download body is skipped.
|
|
30
|
+
*/
|
|
31
|
+
const canDownload = (): boolean =>
|
|
32
|
+
typeof document !== 'undefined' && typeof URL !== 'undefined';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The built-in persistence: saving triggers a browser download of the
|
|
36
|
+
* corresponding JSON file. This is the default so a freshly constructed editor
|
|
37
|
+
* has working Save actions without any per-host or per-story wiring.
|
|
38
|
+
*/
|
|
39
|
+
export const defaultPersistenceAdapter: PersistenceAdapter = {
|
|
40
|
+
saveGraph: (graph) => {
|
|
41
|
+
if (canDownload()) downloadJson('graph.json', graph);
|
|
42
|
+
},
|
|
43
|
+
saveInnerGraph: (graph) => {
|
|
44
|
+
if (canDownload()) downloadJson('graph.behave.json', graph);
|
|
45
|
+
},
|
|
46
|
+
saveLayout: (layout) => {
|
|
47
|
+
if (canDownload()) downloadJson('layout.json', layout);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe the given (or default) persistence sinks to the editor's save
|
|
53
|
+
* topics. Any sink not provided falls back to {@link defaultPersistenceAdapter}.
|
|
54
|
+
* Returns a disposer that removes every subscription it added.
|
|
55
|
+
*/
|
|
56
|
+
export function installPersistence(
|
|
57
|
+
system: System,
|
|
58
|
+
adapter: Partial<PersistenceAdapter> = {}
|
|
59
|
+
): () => void {
|
|
60
|
+
const resolved: PersistenceAdapter = {
|
|
61
|
+
...defaultPersistenceAdapter,
|
|
62
|
+
...adapter
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const tokens = [
|
|
66
|
+
system.pubsub.subscribe('graph:saved', (_, graph) =>
|
|
67
|
+
resolved.saveGraph(graph)
|
|
68
|
+
),
|
|
69
|
+
system.pubsub.subscribe('graph:inner:saved', (_, graph) =>
|
|
70
|
+
resolved.saveInnerGraph(graph)
|
|
71
|
+
),
|
|
72
|
+
system.pubsub.subscribe('layout:saved', (_, layout) =>
|
|
73
|
+
resolved.saveLayout(layout)
|
|
74
|
+
)
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
return () => {
|
|
78
|
+
for (const token of tokens) {
|
|
79
|
+
if (typeof token === 'string') system.pubsub.unsubscribe(token);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { System } from '.';
|
|
2
|
+
import type { GraphSession } from './graphSession';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Plugin initialization function type
|
|
6
|
+
* @template TOptions - Type of options object passed to the plugin
|
|
7
|
+
*/
|
|
8
|
+
export interface Plugin<TOptions = void> {
|
|
9
|
+
(system: System, options: TOptions): void | Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Cleanup returned by a {@link SessionExtension}. Run when the session it was
|
|
14
|
+
* applied to is disposed (its tab closed).
|
|
15
|
+
*/
|
|
16
|
+
export type SessionExtensionCleanup = () => void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Extends a single {@link GraphSession}. Registered at the editor level via
|
|
20
|
+
* `system.registerSessionExtension(...)`, it runs against every graph , those
|
|
21
|
+
* already open at registration time and any created afterwards , so an editor
|
|
22
|
+
* plugin can attach per-graph state (extra stores, controllers, pubsub
|
|
23
|
+
* subscriptions) to each new graph instance.
|
|
24
|
+
*
|
|
25
|
+
* Return a cleanup to tear that per-graph state down when the session is
|
|
26
|
+
* disposed.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* system.registerSessionExtension((session) => {
|
|
30
|
+
* const controller = new MyController(session);
|
|
31
|
+
* session.decorate('myController', controller);
|
|
32
|
+
* return () => controller.dispose();
|
|
33
|
+
* });
|
|
34
|
+
*/
|
|
35
|
+
export interface SessionExtension {
|
|
36
|
+
(session: GraphSession): void | SessionExtensionCleanup;
|
|
37
|
+
}
|
|
38
|
+
export type PluginOpts = {
|
|
39
|
+
name: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type LoadablePlugin<TOptions = void> = {
|
|
43
|
+
loader: Plugin<TOptions>;
|
|
44
|
+
opts: PluginOpts;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const plugin = <TOptions = void>(
|
|
48
|
+
registerfunc: Plugin<TOptions>,
|
|
49
|
+
opts: PluginOpts
|
|
50
|
+
): LoadablePlugin<TOptions> => {
|
|
51
|
+
return {
|
|
52
|
+
loader: registerfunc,
|
|
53
|
+
opts: opts
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { createContext, useContext, type ReactNode } from 'react';
|
|
2
|
+
import { useStore } from 'zustand';
|
|
3
|
+
import type { System } from './system';
|
|
4
|
+
import type { GraphSession } from './graphSession';
|
|
5
|
+
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Editor system context
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
export const SystemContext = createContext<System | undefined>(undefined);
|
|
11
|
+
|
|
12
|
+
export type SystemProviderProps = {
|
|
13
|
+
children: ReactNode;
|
|
14
|
+
value: System;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Provides the editor-level {@link System} to the React tree.
|
|
19
|
+
*/
|
|
20
|
+
export function SystemProvider({ children, value }: SystemProviderProps) {
|
|
21
|
+
return <SystemContext value={value}>{children}</SystemContext>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Alias for {@link SystemProvider} expressing its editor-level role. */
|
|
25
|
+
export const EditorProvider = SystemProvider;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Access the editor-level {@link System}.
|
|
29
|
+
*/
|
|
30
|
+
export function useSystem(): System {
|
|
31
|
+
const context = useContext(SystemContext);
|
|
32
|
+
|
|
33
|
+
if (context === undefined) {
|
|
34
|
+
throw new Error('useSystem must be used within a SystemProvider');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return context;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Alias for {@link useSystem}. */
|
|
41
|
+
export const useEditor = useSystem;
|
|
42
|
+
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Per-graph session context
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
const GraphContext = createContext<GraphSession | undefined>(undefined);
|
|
48
|
+
|
|
49
|
+
export type GraphProviderProps = {
|
|
50
|
+
children: ReactNode;
|
|
51
|
+
value: GraphSession;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Provides a single {@link GraphSession} to the subtree rendered inside a graph
|
|
56
|
+
* tab. Components within use {@link useGraph} to read per-graph state bound to
|
|
57
|
+
* their own tab, regardless of which tab is currently focused.
|
|
58
|
+
*/
|
|
59
|
+
export function GraphProvider({ children, value }: GraphProviderProps) {
|
|
60
|
+
return <GraphContext value={value}>{children}</GraphContext>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Access the {@link GraphSession} of the surrounding graph tab.
|
|
65
|
+
*/
|
|
66
|
+
export function useGraph(): GraphSession {
|
|
67
|
+
const context = useContext(GraphContext);
|
|
68
|
+
|
|
69
|
+
if (context === undefined) {
|
|
70
|
+
throw new Error('useGraph must be used within a GraphProvider');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return context;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Access the currently focused {@link GraphSession}, or undefined when no graph
|
|
78
|
+
* is open. Subscribes to the editor's active-graph store, so panels rendered
|
|
79
|
+
* outside of a graph tab re-render when the focused graph changes.
|
|
80
|
+
*/
|
|
81
|
+
export function useActiveGraph(): GraphSession | undefined {
|
|
82
|
+
const editor = useSystem();
|
|
83
|
+
return useStore(editor.activeGraph, (s) =>
|
|
84
|
+
s.activeGraphId ? s.sessions[s.activeGraphId] : undefined
|
|
85
|
+
);
|
|
86
|
+
}
|