@kiberon-labs/behave-graph-flow 2.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/.storybook/manager.ts +6 -0
- package/.storybook/preview.ts +49 -1
- package/.storybook/styles.css +9 -3
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +368 -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/index.css +36 -33
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1865 -550
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14357 -11221
- package/dist/index.js.map +1 -1
- 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/protocol.md +43 -20
- package/package.json +5 -9
- package/src/components/FloatingToolbar/index.module.css +5 -13
- package/src/components/FloatingToolbar/index.tsx +9 -9
- package/src/components/Flow.tsx +34 -23
- package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
- package/src/components/contextMenus/NodePicker.module.css +13 -13
- package/src/components/contextMenus/edge.tsx +9 -95
- package/src/components/contextMenus/node.tsx +9 -149
- package/src/components/contextMenus/selection.tsx +5 -71
- package/src/components/controls/any/AnyControlImpl.tsx +14 -0
- package/src/components/controls/any/index.tsx +13 -2
- package/src/components/edges/index.tsx +75 -69
- package/src/components/layoutController/index.module.css +3 -0
- package/src/components/layoutController/index.tsx +24 -1
- package/src/components/layoutController/utils.ts +46 -3
- package/src/components/menubar/defaults.tsx +55 -19
- package/src/components/menubar/menuItem.module.css +18 -3
- package/src/components/menubar/menuItem.tsx +34 -1
- package/src/components/nodes/behave/NodeContainer.module.css +26 -25
- package/src/components/nodes/group/index.tsx +3 -3
- package/src/components/nodes/wrapper/styles.module.css +6 -32
- package/src/components/panels/alignment/index.module.css +0 -10
- package/src/components/panels/alignment/index.tsx +4 -4
- package/src/components/panels/base/styles.module.css +2 -2
- 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 +14 -5
- package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
- package/src/components/panels/events/styles.module.css +6 -64
- package/src/components/panels/graphProperties/index.tsx +125 -0
- package/src/components/panels/history/index.tsx +2 -2
- package/src/components/panels/history/styles.module.css +0 -9
- package/src/components/panels/keymaps/index.module.css +3 -13
- package/src/components/panels/keymaps/index.tsx +1 -2
- package/src/components/panels/layers/index.tsx +20 -15
- package/src/components/panels/layers/styles.module.css +9 -12
- package/src/components/panels/legend/index.tsx +1 -1
- package/src/components/panels/logs/index.module.css +25 -19
- package/src/components/panels/logs/index.tsx +7 -7
- package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
- package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
- package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
- package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
- package/src/components/panels/nodeInputs/index.module.css +99 -75
- package/src/components/panels/nodeInputs/index.tsx +21 -11
- package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
- package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
- package/src/components/panels/nodePicker/index.tsx +8 -8
- package/src/components/panels/panel/index.module.css +7 -7
- package/src/components/panels/search/index.module.css +0 -50
- package/src/components/panels/search/index.tsx +2 -2
- package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
- package/src/components/panels/systemSettings/index.tsx +221 -176
- package/src/components/panels/systemSettings/styles.module.css +135 -8
- package/src/components/panels/traces/GridLines.tsx +1 -1
- package/src/components/panels/traces/TimeGrid.tsx +3 -3
- package/src/components/panels/traces/TraceLane.tsx +1 -1
- package/src/components/panels/traces/index.module.css +1 -8
- package/src/components/panels/traces/index.tsx +8 -4
- package/src/components/panels/traces/useDerivedSpans.ts +241 -146
- package/src/components/panels/traces/utils.ts +8 -0
- package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
- package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
- package/src/components/panels/variables/index.tsx +2 -2
- package/src/components/panels/variables/styles.module.css +4 -91
- package/src/components/primitives/icon.module.css +4 -4
- package/src/components/sockets/input/index.tsx +9 -2
- package/src/components/sockets/input/styles.module.css +2 -3
- package/src/components/sockets/output/index.tsx +10 -3
- package/src/components/sockets/output/styles.module.css +1 -6
- package/src/css/notes.css +135 -0
- package/src/css/prosemirror.css +3 -3
- package/src/css/rc-dock.css +143 -43
- package/src/css/rc-menu.css +56 -55
- package/src/css/themes/kiberon.css +127 -0
- package/src/css/vars.css +197 -13
- package/src/css/vscode-elements.css +124 -0
- package/src/generators/CallSubgraphGenerator.tsx +136 -0
- package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
- package/src/generators/GraphBoundaryGenerator.module.css +32 -0
- package/src/generators/GraphBoundaryGenerator.tsx +193 -0
- package/src/generators/SequenceGenerator.tsx +2 -2
- package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
- package/src/generators/SwitchOnStringGenerator.tsx +2 -2
- package/src/generators/callSubgraphSync.ts +126 -0
- package/src/generators/registerDefaultGenerators.ts +21 -0
- package/src/generators/registerDefaults.ts +26 -0
- package/src/hooks/useBehaveGraphFlow.ts +2 -2
- package/src/hooks/useFlowHandlers.ts +47 -9
- package/src/hooks/useWasdPan.ts +26 -4
- package/src/index.css +4 -16
- package/src/index.ts +17 -0
- 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 +22 -12
- 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 +2 -4
- package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
- package/src/plugin/docs/panel/index.tsx +15 -194
- package/src/plugin/docs/panel/styles.module.css +8 -8
- package/src/plugin/graphrunner/actions.ts +258 -185
- package/src/plugin/graphrunner/buttons.tsx +34 -26
- package/src/plugin/graphrunner/client.ts +4 -1
- package/src/plugin/graphrunner/index.tsx +29 -100
- package/src/plugin/graphrunner/panel.tsx +2 -2
- package/src/plugin/graphrunner/runController.ts +283 -0
- package/src/plugin/graphrunner/runner.ts +21 -192
- package/src/plugin/graphrunner/store.ts +14 -24
- package/src/plugin/graphrunner/styles.module.css +17 -57
- package/src/plugin/graphrunner/transport.ts +26 -0
- package/src/plugin/graphrunner/types.ts +21 -0
- package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
- package/src/plugin/graphrunner-local/index.tsx +8 -2
- package/src/plugin/graphrunner-local/panel.tsx +131 -175
- package/src/plugin/graphrunner-local/styles.module.css +57 -76
- package/src/plugin/graphrunner-local/transport.ts +151 -184
- package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
- package/src/plugin/graphrunner-webworker/index.tsx +4 -10
- package/src/plugin/graphrunner-webworker/store.ts +9 -0
- package/src/plugin/kitchen-sink/index.ts +38 -0
- package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
- package/src/{layout → plugin/layout}/elk.ts +22 -6
- 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 +58 -4
- package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
- package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
- package/src/specifics/VariableGetSpecific.tsx +2 -2
- package/src/specifics/VariableSetSpecific.tsx +2 -2
- package/src/store/actions.tsx +5 -5
- package/src/store/commands.ts +278 -0
- package/src/store/contextMenu.ts +192 -0
- package/src/store/conversions.ts +47 -0
- package/src/store/flow.tsx +23 -38
- package/src/store/graphMeta.ts +39 -0
- package/src/store/hotKeys.tsx +301 -260
- package/src/store/layers.ts +3 -3
- package/src/store/registry.ts +12 -4
- package/src/store/selection.ts +3 -3
- package/src/store/settings.ts +82 -82
- package/src/store/settingsSchema.ts +210 -0
- package/src/store/tabs.ts +5 -1
- package/src/store/traces.ts +3 -3
- package/src/system/graph.ts +11 -14
- package/src/system/graphSession.ts +172 -0
- package/src/system/index.ts +3 -0
- package/src/system/notifications.ts +13 -0
- package/src/system/persistence.ts +82 -0
- package/src/system/plugin.ts +28 -0
- package/src/system/provider.tsx +64 -0
- package/src/system/system.ts +518 -88
- package/src/system/tabLoader.tsx +70 -32
- package/src/system/undoRedo.ts +1 -1
- package/src/transformers/Uigraph.ts +5 -4
- package/src/transformers/contract.ts +87 -0
- package/src/transformers/flowToBehave.ts +13 -5
- package/src/types/nodes.ts +8 -3
- package/src/types.ts +2 -0
- package/src/util/autoConvert.ts +200 -0
- package/src/util/isValidConnection.ts +23 -2
- package/stories/defaults/defaultStoryProvider.tsx +17 -14
- package/stories/defaults/systemGenerator.ts +6 -1
- package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
- 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/contract.test.ts +51 -0
- package/tests/contractSerialize.test.ts +62 -0
- package/tests/deriveSpans.test.ts +71 -0
- package/tests/flowToBehave.test.ts +2 -1
- 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/persistence.test.ts +51 -0
- package/tests/saveLoad.test.ts +7 -6
- package/tests/settings.test.ts +178 -0
- package/tests/traceStore.test.ts +46 -0
- package/tests/visual/README.md +2 -2
- 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-variables-chromium-win32.png +0 -0
- package/tests/visual/panels.visual.test.tsx +3 -3
- package/tests/wasdPan.test.ts +71 -0
- package/vitest.config.ts +1 -1
- package/vitest.visual.config.ts +7 -0
- package/.storybook/vscode.css +0 -814
- package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
- package/src/components/nodes/comment/comment.tsx +0 -103
- package/src/components/nodes/comment/styles.module.css +0 -150
- package/src/components/panels/conversation/index.module.css +0 -151
- package/src/components/panels/conversation/index.tsx +0 -162
- package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
- package/src/css/vscode.css +0 -13
- package/src/hooks/useDetachNodes.ts +0 -39
- package/src/plugin/graphrunner-webworker/types.ts +0 -17
- package/src/specifics/registerDefaultSpecifics.ts +0 -5
- package/src/store/chat.ts +0 -73
- package/src/store/graphRunnerClient.ts +0 -110
package/src/system/tabLoader.tsx
CHANGED
|
@@ -16,29 +16,34 @@ import { HistoryPanel } from '@/components/panels/history';
|
|
|
16
16
|
import { HotKeys } from '@/components/hotKeys';
|
|
17
17
|
import { NodePickerPanel } from '@/components/panels/nodePicker';
|
|
18
18
|
import { PanelPanel } from '@/components/panels/panel';
|
|
19
|
-
import { ConversationPanel } from '@/components/panels/conversation';
|
|
20
19
|
import { LayersPanel } from '@/components/panels/layers';
|
|
20
|
+
import { GraphPropertiesPanel } from '@/components/panels/graphProperties';
|
|
21
|
+
import { GraphProvider } from './provider';
|
|
22
|
+
import { useStore } from 'zustand';
|
|
23
|
+
import type { GraphSession } from './graphSession';
|
|
24
|
+
import {
|
|
25
|
+
DEFAULT_GRAPH_ID,
|
|
26
|
+
isGraphTabId,
|
|
27
|
+
sessionIdFromTabId,
|
|
28
|
+
tabIdForSession
|
|
29
|
+
} from '@/components/layoutController/utils';
|
|
30
|
+
|
|
31
|
+
/** Live graph tab title , re-renders when the graph is renamed. */
|
|
32
|
+
const GraphTabTitle = ({ session }: { session: GraphSession }) => {
|
|
33
|
+
const name = useStore(session.metaStore, (s) => s.name);
|
|
34
|
+
return <>{name}</>;
|
|
35
|
+
};
|
|
21
36
|
|
|
22
37
|
export class TabLoader {
|
|
23
38
|
public readonly tabs: Record<string, () => TabData> = {};
|
|
39
|
+
private readonly system: System;
|
|
24
40
|
|
|
25
|
-
constructor(
|
|
26
|
-
this.
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
group: 'graph',
|
|
32
|
-
title: 'Graph',
|
|
33
|
-
content: () => (
|
|
34
|
-
<ErrorBoundary fallback={'whoops'}>
|
|
35
|
-
<HotKeys>
|
|
36
|
-
<Flow />
|
|
37
|
-
</HotKeys>
|
|
38
|
-
</ErrorBoundary>
|
|
39
|
-
)
|
|
40
|
-
};
|
|
41
|
-
});
|
|
41
|
+
constructor(system: System) {
|
|
42
|
+
this.system = system;
|
|
43
|
+
|
|
44
|
+
// The default graph tab. Other graphs are loaded dynamically by id
|
|
45
|
+
// (see `loadGraphTab`).
|
|
46
|
+
this.register(DEFAULT_GRAPH_ID, () => this.buildGraphTab(DEFAULT_GRAPH_ID));
|
|
42
47
|
|
|
43
48
|
this.register('system:settings', () => {
|
|
44
49
|
return {
|
|
@@ -95,6 +100,20 @@ export class TabLoader {
|
|
|
95
100
|
)
|
|
96
101
|
};
|
|
97
102
|
});
|
|
103
|
+
|
|
104
|
+
this.register('graphProperties', () => {
|
|
105
|
+
return {
|
|
106
|
+
id: 'graphProperties',
|
|
107
|
+
closable: true,
|
|
108
|
+
title: 'Graph Properties',
|
|
109
|
+
group: 'default',
|
|
110
|
+
content: () => (
|
|
111
|
+
<ErrorBoundary fallback={'whoops'}>
|
|
112
|
+
<GraphPropertiesPanel />
|
|
113
|
+
</ErrorBoundary>
|
|
114
|
+
)
|
|
115
|
+
};
|
|
116
|
+
});
|
|
98
117
|
this.register('find', () => {
|
|
99
118
|
return {
|
|
100
119
|
id: 'find',
|
|
@@ -236,30 +255,49 @@ export class TabLoader {
|
|
|
236
255
|
};
|
|
237
256
|
});
|
|
238
257
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
closable: true,
|
|
243
|
-
cached: true,
|
|
244
|
-
title: 'Conversation',
|
|
245
|
-
group: 'default',
|
|
246
|
-
content: () => (
|
|
247
|
-
<ErrorBoundary fallback={'whoops'}>
|
|
248
|
-
<ConversationPanel />
|
|
249
|
-
</ErrorBoundary>
|
|
250
|
-
)
|
|
251
|
-
};
|
|
252
|
-
});
|
|
258
|
+
// The 'conversation' tab is provided by the AI nodes package's editor
|
|
259
|
+
// plugin (`@kiberon-labs/behave-graph-nodes-ai/ui`), which owns the chat
|
|
260
|
+
// store and panel.
|
|
253
261
|
}
|
|
254
262
|
|
|
255
263
|
load(tab: TabBase): TabData | undefined {
|
|
256
264
|
if (!tab.id) {
|
|
257
265
|
return;
|
|
258
266
|
}
|
|
267
|
+
// Dynamic per-graph tabs (`graph:<sessionId>`) are not in the registry.
|
|
268
|
+
if (isGraphTabId(tab.id) && tab.id !== DEFAULT_GRAPH_ID) {
|
|
269
|
+
return this.buildGraphTab(tab.id);
|
|
270
|
+
}
|
|
259
271
|
return this.tabs[tab.id]?.();
|
|
260
272
|
}
|
|
261
273
|
|
|
262
274
|
register(id: string, loader: () => TabData) {
|
|
263
275
|
this.tabs[id] = loader;
|
|
264
276
|
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Build the TabData for a graph tab, resolving (or lazily creating) its
|
|
280
|
+
* session and wrapping the canvas in a {@link GraphProvider} so it stays bound
|
|
281
|
+
* to its own graph regardless of which tab is focused.
|
|
282
|
+
*/
|
|
283
|
+
private buildGraphTab(tabId: string): TabData {
|
|
284
|
+
const sessionId = sessionIdFromTabId(tabId);
|
|
285
|
+
const session = this.system.getOrCreateSession(sessionId);
|
|
286
|
+
return {
|
|
287
|
+
id: tabIdForSession(sessionId),
|
|
288
|
+
closable: true,
|
|
289
|
+
cached: true,
|
|
290
|
+
group: 'graph',
|
|
291
|
+
title: <GraphTabTitle session={session} />,
|
|
292
|
+
content: () => (
|
|
293
|
+
<ErrorBoundary fallback={'whoops'}>
|
|
294
|
+
<GraphProvider value={session}>
|
|
295
|
+
<HotKeys>
|
|
296
|
+
<Flow />
|
|
297
|
+
</HotKeys>
|
|
298
|
+
</GraphProvider>
|
|
299
|
+
</ErrorBoundary>
|
|
300
|
+
)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
265
303
|
}
|
package/src/system/undoRedo.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { GraphSession } from '@/system/graphSession';
|
|
2
2
|
import { annotatedTitle, uiVersion } from '@/annotations';
|
|
3
3
|
import type { UIGraphJSON } from '@/types/graph';
|
|
4
4
|
|
|
@@ -18,7 +18,7 @@ function getStringAnnotation(
|
|
|
18
18
|
/**
|
|
19
19
|
* Assembles the full UI graph definition for saving.
|
|
20
20
|
*/
|
|
21
|
-
export function buildUIGraphJSON(system:
|
|
21
|
+
export function buildUIGraphJSON(system: GraphSession): UIGraphJSON {
|
|
22
22
|
system.flowStore.getState().invalidateCache();
|
|
23
23
|
|
|
24
24
|
const flow = system.flowStore.getState().getGraph();
|
|
@@ -34,8 +34,9 @@ export function buildUIGraphJSON(system: System): UIGraphJSON {
|
|
|
34
34
|
const graphVersion =
|
|
35
35
|
getStringAnnotation(annotations, uiVersion) ?? DEFAULT_UI_GRAPH_VERSION;
|
|
36
36
|
const graphName =
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
system.metaStore.getState().name ||
|
|
38
|
+
getStringAnnotation(annotations, annotatedTitle) ||
|
|
39
|
+
flow.name ||
|
|
39
40
|
DEFAULT_UI_GRAPH_NAME;
|
|
40
41
|
|
|
41
42
|
const viewports = system.graph.viewports.length
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { Node } from 'reactflow';
|
|
2
|
+
import type { GraphSocketJSON } from '@kiberon-labs/behave-graph';
|
|
3
|
+
import type { Socket } from '@/types';
|
|
4
|
+
|
|
5
|
+
export const GRAPH_INPUT_TYPE = 'graph/input';
|
|
6
|
+
export const GRAPH_OUTPUT_TYPE = 'graph/output';
|
|
7
|
+
export const CALL_SUBGRAPH_TYPE = 'flow/callSubgraph';
|
|
8
|
+
|
|
9
|
+
export type ContractParam = {
|
|
10
|
+
/** Stable identifier (socket key / contract key). Independent of the name. */
|
|
11
|
+
id?: string;
|
|
12
|
+
/** User-facing display name; editable without breaking wiring. */
|
|
13
|
+
name: string;
|
|
14
|
+
valueTypeName: string;
|
|
15
|
+
defaultValue?: any;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type GraphContract = {
|
|
19
|
+
graphInputs: GraphSocketJSON[];
|
|
20
|
+
graphOutputs: GraphSocketJSON[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Stable identity of a param , its id, falling back to name for legacy data. */
|
|
24
|
+
export const paramId = (param: ContractParam): string => param.id ?? param.name;
|
|
25
|
+
|
|
26
|
+
const readParams = (node: Node): ContractParam[] => {
|
|
27
|
+
const params = (node.data as any)?.configuration?.parameters;
|
|
28
|
+
return Array.isArray(params) ? (params as ContractParam[]) : [];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const toSocket = (param: ContractParam): GraphSocketJSON => ({
|
|
32
|
+
key: paramId(param),
|
|
33
|
+
valueType: param.valueTypeName,
|
|
34
|
+
...(param.defaultValue !== undefined
|
|
35
|
+
? { defaultValue: param.defaultValue }
|
|
36
|
+
: {}),
|
|
37
|
+
label: param.name
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Derive a graph's contract from its boundary nodes. The `graph/input` /
|
|
42
|
+
* `graph/output` nodes are the source of truth; their configured parameters
|
|
43
|
+
* become the graph's `graphInputs` / `graphOutputs`.
|
|
44
|
+
*/
|
|
45
|
+
export const deriveContract = (nodes: Node[]): GraphContract => {
|
|
46
|
+
const graphInputs: GraphSocketJSON[] = [];
|
|
47
|
+
const graphOutputs: GraphSocketJSON[] = [];
|
|
48
|
+
|
|
49
|
+
for (const node of nodes) {
|
|
50
|
+
const type = (node.data as any)?.type;
|
|
51
|
+
if (type === GRAPH_INPUT_TYPE) {
|
|
52
|
+
graphInputs.push(...readParams(node).map(toSocket));
|
|
53
|
+
} else if (type === GRAPH_OUTPUT_TYPE) {
|
|
54
|
+
graphOutputs.push(...readParams(node).map(toSocket));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { graphInputs, graphOutputs };
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convert a derived contract's sockets back into editable {@link ContractParam}s
|
|
63
|
+
* , the form stored in a Call Subgraph node's configuration. The socket `key`
|
|
64
|
+
* is the stable param id; its `label` is the display name.
|
|
65
|
+
*/
|
|
66
|
+
export const contractToParams = (sockets: GraphSocketJSON[]): ContractParam[] =>
|
|
67
|
+
sockets.map((s) => ({
|
|
68
|
+
id: s.key,
|
|
69
|
+
name: s.label ?? s.key,
|
|
70
|
+
valueTypeName: s.valueType,
|
|
71
|
+
...(s.defaultValue !== undefined ? { defaultValue: s.defaultValue } : {})
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Convert contract params into dynamic-port sockets. The socket identity
|
|
76
|
+
* (name/key/handle id) is the stable param id; the display label is the name.
|
|
77
|
+
*/
|
|
78
|
+
export const paramsToSockets = (params: ContractParam[]): Socket[] =>
|
|
79
|
+
params.map((p) => {
|
|
80
|
+
const id = paramId(p);
|
|
81
|
+
return {
|
|
82
|
+
name: id,
|
|
83
|
+
key: id,
|
|
84
|
+
label: p.name || id,
|
|
85
|
+
valueType: p.valueTypeName || 'string'
|
|
86
|
+
};
|
|
87
|
+
});
|
|
@@ -4,15 +4,16 @@ import type {
|
|
|
4
4
|
NodeSpecJSON
|
|
5
5
|
} from '@kiberon-labs/behave-graph';
|
|
6
6
|
import type { Edge, Node } from 'reactflow';
|
|
7
|
-
import {
|
|
7
|
+
import type { GraphSession } from '../system/graphSession';
|
|
8
8
|
import { writeVariablesToJSON } from '../util/serializeVariables';
|
|
9
9
|
import { isBehaveNode } from '@/util/isBehaveNode';
|
|
10
|
+
import { deriveContract } from './contract';
|
|
10
11
|
|
|
11
12
|
const isNullish = (value: any): value is null | undefined =>
|
|
12
13
|
value === undefined || value === null;
|
|
13
14
|
|
|
14
15
|
export const flowToBehave = (
|
|
15
|
-
|
|
16
|
+
session: GraphSession,
|
|
16
17
|
nodes: Node[],
|
|
17
18
|
edges: Edge[],
|
|
18
19
|
nodeSpecJSON: NodeSpecJSON[]
|
|
@@ -20,11 +21,11 @@ export const flowToBehave = (
|
|
|
20
21
|
const graph: GraphJSON = {
|
|
21
22
|
nodes: [],
|
|
22
23
|
variables: [],
|
|
23
|
-
customEvents:
|
|
24
|
+
customEvents: session.eventsStore.getState().getCustomEvents()
|
|
24
25
|
};
|
|
25
26
|
|
|
26
|
-
const registry =
|
|
27
|
-
const varStore =
|
|
27
|
+
const registry = session.editor.registry.getState();
|
|
28
|
+
const varStore = session.variableStore.getState().variables;
|
|
28
29
|
|
|
29
30
|
nodes.forEach((node) => {
|
|
30
31
|
if (!isBehaveNode(node)) return;
|
|
@@ -109,5 +110,12 @@ export const flowToBehave = (
|
|
|
109
110
|
if (Object.keys(varStore).length > 0) {
|
|
110
111
|
graph.variables = writeVariablesToJSON(registry, varStore);
|
|
111
112
|
}
|
|
113
|
+
|
|
114
|
+
// Derive the graph's contract (inputs/outputs) from its boundary nodes so
|
|
115
|
+
// callers and the runtime can read it.
|
|
116
|
+
const { graphInputs, graphOutputs } = deriveContract(nodes);
|
|
117
|
+
if (graphInputs.length > 0) graph.graphInputs = graphInputs;
|
|
118
|
+
if (graphOutputs.length > 0) graph.graphOutputs = graphOutputs;
|
|
119
|
+
|
|
112
120
|
return graph;
|
|
113
121
|
};
|
package/src/types/nodes.ts
CHANGED
|
@@ -15,8 +15,13 @@ export type IBehaveNode = Omit<Node, 'data' | 'type'> & {
|
|
|
15
15
|
};
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
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';
|
|
20
25
|
data: {
|
|
21
26
|
annotations?: Record<string, any>;
|
|
22
27
|
text: string;
|
|
@@ -41,5 +46,5 @@ export type IAINode = Omit<Node, 'data' | 'type'> & {
|
|
|
41
46
|
};
|
|
42
47
|
};
|
|
43
48
|
|
|
44
|
-
export type AnyNode = IBehaveNode |
|
|
49
|
+
export type AnyNode = IBehaveNode | INoteNode | IAINode | IGroupNode;
|
|
45
50
|
export type AnyNodeType = AnyNode['type'];
|
package/src/types.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { ChoiceJSON } from '@kiberon-labs/behave-graph';
|
|
|
3
3
|
export interface SocketBase {
|
|
4
4
|
name: string;
|
|
5
5
|
key: string;
|
|
6
|
+
/** Optional display label; falls back to `name` when absent. */
|
|
7
|
+
label?: string;
|
|
6
8
|
choices?: ChoiceJSON;
|
|
7
9
|
valueType: string;
|
|
8
10
|
defaultValue?: any;
|
|
@@ -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
|
+
};
|
|
@@ -3,12 +3,15 @@ import type { Connection, ReactFlowInstance } from 'reactflow';
|
|
|
3
3
|
import { getSocketsByNodeTypeAndHandleType } from './getSocketsByNodeTypeAndHandleType.js';
|
|
4
4
|
import { isHandleConnected } from './isHandleConnected.js';
|
|
5
5
|
import { mergeSockets } from './mergeSockets.js';
|
|
6
|
+
import { resolveConverter } from './autoConvert.js';
|
|
7
|
+
import type { ConversionRule } from '@/store/conversions';
|
|
6
8
|
import type { IBehaveNode } from '@/types/nodes.js';
|
|
7
9
|
|
|
8
10
|
export const isValidConnection = (
|
|
9
11
|
connection: Connection,
|
|
10
12
|
instance: ReactFlowInstance,
|
|
11
|
-
specJSON: NodeSpecJSON[]
|
|
13
|
+
specJSON: NodeSpecJSON[],
|
|
14
|
+
options?: { autoConvert?: boolean; conversions?: ConversionRule[] }
|
|
12
15
|
) => {
|
|
13
16
|
if (connection.source === null || connection.target === null) return false;
|
|
14
17
|
|
|
@@ -60,5 +63,23 @@ export const isValidConnection = (
|
|
|
60
63
|
return false;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
|
|
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;
|
|
64
85
|
};
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { SystemProvider } from '@/system/provider';
|
|
1
|
+
import { SystemProvider, GraphProvider } from '@/system/provider';
|
|
4
2
|
import { System } from '@/system/system';
|
|
5
3
|
import {
|
|
6
4
|
registerCoreProfile,
|
|
7
5
|
type ValueType
|
|
8
6
|
} from '@kiberon-labs/behave-graph';
|
|
9
7
|
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
8
|
+
import { kitchenSinkPlugin } from '@/plugin/kitchen-sink';
|
|
9
|
+
import { localGraphRunnerPlugin } from '@/index';
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
const ColorValue: ValueType = {
|
|
14
12
|
name: 'color',
|
|
15
13
|
creator: () => '#000000',
|
|
16
14
|
deserialize: (value: string) => value,
|
|
@@ -37,13 +35,14 @@ const nodeRegistry = {
|
|
|
37
35
|
//Basic system generator for tests and stories
|
|
38
36
|
export const systemGenerator = () => {
|
|
39
37
|
const defaultSys = new System(nodeRegistry);
|
|
38
|
+
defaultSys.registerPlugin(kitchenSinkPlugin);
|
|
40
39
|
return defaultSys;
|
|
41
40
|
};
|
|
42
41
|
|
|
43
42
|
const defaultSys = new System(nodeRegistry);
|
|
43
|
+
const defaultSession = defaultSys.createSession('graph');
|
|
44
44
|
|
|
45
|
-
defaultSys.registerPlugin(
|
|
46
|
-
defaultSys.registerPlugin(docsPlugin);
|
|
45
|
+
defaultSys.registerPlugin(kitchenSinkPlugin);
|
|
47
46
|
defaultSys.registerPlugin(localGraphRunnerPlugin, {
|
|
48
47
|
registry: coreRegistry,
|
|
49
48
|
events: [
|
|
@@ -73,11 +72,11 @@ defaultSys.registerPlugin(localGraphRunnerPlugin, {
|
|
|
73
72
|
]
|
|
74
73
|
});
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
// Saving is wired by default on the System (download-to-file); no per-story
|
|
76
|
+
// subscription is needed. Override with defaultSys.enablePersistence(...) only
|
|
77
|
+
// when a story needs to demonstrate a custom sink.
|
|
79
78
|
|
|
80
|
-
|
|
79
|
+
defaultSession.flowStore.getState().setGraph({
|
|
81
80
|
nodes: [
|
|
82
81
|
{
|
|
83
82
|
type: 'lifecycle/onStart',
|
|
@@ -151,7 +150,7 @@ const exampleLogTime = (h: number, m: number, s: number, ms: number) =>
|
|
|
151
150
|
message: 'debug/log: failed to resolve socket "value" on node 3.'
|
|
152
151
|
}
|
|
153
152
|
].forEach((entry, index) => {
|
|
154
|
-
|
|
153
|
+
defaultSession.logsStore.getState().append({
|
|
155
154
|
type: entry.type,
|
|
156
155
|
data: { message: entry.message },
|
|
157
156
|
time: exampleLogTime(13, 45, 30 + index, 120 + index * 37)
|
|
@@ -163,5 +162,9 @@ export const DefaultSystemProvider = ({
|
|
|
163
162
|
}: {
|
|
164
163
|
children: React.ReactElement;
|
|
165
164
|
}) => {
|
|
166
|
-
return
|
|
165
|
+
return (
|
|
166
|
+
<SystemProvider value={defaultSys}>
|
|
167
|
+
<GraphProvider value={defaultSession}>{children}</GraphProvider>
|
|
168
|
+
</SystemProvider>
|
|
169
|
+
);
|
|
167
170
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { System } from '@/system/system';
|
|
2
|
+
import { kitchenSinkPlugin } from '@/plugin/kitchen-sink';
|
|
2
3
|
import {
|
|
3
4
|
registerCoreProfile,
|
|
4
5
|
writeNodeSpecsToJSON,
|
|
5
6
|
type ValueType
|
|
6
7
|
} from '@kiberon-labs/behave-graph';
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
const ColorValue: ValueType = {
|
|
9
10
|
name: 'color',
|
|
10
11
|
creator: () => '#000000',
|
|
11
12
|
deserialize: (value: string) => value,
|
|
@@ -34,5 +35,9 @@ const nodeRegistry = {
|
|
|
34
35
|
//Basic system generator for tests and stories
|
|
35
36
|
export const systemGenerator = () => {
|
|
36
37
|
const defaultSys = new System(nodeRegistry);
|
|
38
|
+
defaultSys.createSession('graph');
|
|
39
|
+
// Standard editor UI bundle (docs, alignment, layout, notes) so stories built
|
|
40
|
+
// on this generator get the full editor without wiring plugins per story.
|
|
41
|
+
defaultSys.registerPlugin(kitchenSinkPlugin);
|
|
37
42
|
return defaultSys;
|
|
38
43
|
};
|