@kiberon-labs/behave-graph-flow 1.0.0 → 2.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.
Files changed (314) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/preview.ts +16 -0
  4. package/.storybook/styles.css +10 -0
  5. package/.storybook/vscode.css +814 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/LICENSE +6 -0
  8. package/README.md +2 -2
  9. package/data/Polynomial.json +510 -0
  10. package/data/sequence.json +337 -0
  11. package/data/trigger-event.json +241 -0
  12. package/data/variable-change.json +210 -0
  13. package/dist/entry.css +4 -0
  14. package/dist/index.css +39 -0
  15. package/dist/index.css.map +1 -0
  16. package/dist/index.d.ts +2282 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +14873 -0
  19. package/dist/index.js.map +1 -0
  20. package/docs/notifications.md +246 -0
  21. package/docs/protocol.md +679 -0
  22. package/docs/specifics.md +191 -0
  23. package/package.json +85 -21
  24. package/postcss.config.ts +3 -4
  25. package/src/annotations/index.ts +32 -0
  26. package/src/components/FloatingToolbar/index.module.css +45 -0
  27. package/src/components/FloatingToolbar/index.tsx +256 -0
  28. package/src/components/Flow.tsx +276 -75
  29. package/src/components/contextMenus/NodePicker.module.css +274 -0
  30. package/src/components/contextMenus/NodePicker.tsx +481 -0
  31. package/src/components/contextMenus/edge.tsx +108 -0
  32. package/src/components/contextMenus/node.tsx +155 -0
  33. package/src/components/contextMenus/selection.tsx +77 -0
  34. package/src/components/controls/any/index.tsx +8 -0
  35. package/src/components/controls/boolean/index.tsx +13 -0
  36. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  37. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  38. package/src/components/controls/colorPicker/index.module.css +18 -0
  39. package/src/components/controls/colorPicker/index.tsx +61 -0
  40. package/src/components/controls/number/index.tsx +35 -0
  41. package/src/components/controls/string/index.tsx +16 -0
  42. package/src/components/edges/index.tsx +469 -0
  43. package/src/components/edges/offsetBezier.ts +134 -0
  44. package/src/components/hotKeys.tsx +20 -0
  45. package/src/components/layoutController/index.module.css +10 -0
  46. package/src/components/layoutController/index.tsx +117 -0
  47. package/src/components/layoutController/utils.ts +205 -0
  48. package/src/components/menubar/defaults.tsx +480 -0
  49. package/src/components/menubar/index.tsx +49 -0
  50. package/src/components/menubar/menuItem.module.css +16 -0
  51. package/src/components/menubar/menuItem.tsx +32 -0
  52. package/src/components/nodes/behave/Node.module.css +23 -0
  53. package/src/components/nodes/behave/Node.tsx +176 -0
  54. package/src/components/nodes/behave/NodeContainer.module.css +87 -0
  55. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  56. package/src/components/nodes/behave/index.tsx +14 -0
  57. package/src/components/nodes/comment/FormatToolbar.tsx +118 -0
  58. package/src/components/nodes/comment/comment.tsx +103 -0
  59. package/src/components/nodes/comment/styles.module.css +150 -0
  60. package/src/components/nodes/group/index.tsx +109 -0
  61. package/src/components/nodes/wrapper/index.tsx +73 -0
  62. package/src/components/nodes/wrapper/styles.module.css +113 -0
  63. package/src/components/notifications/NotificationProvider.tsx +81 -0
  64. package/src/components/notifications/index.ts +2 -0
  65. package/src/components/notifications/utils.ts +71 -0
  66. package/src/components/panels/alignment/index.module.css +20 -0
  67. package/src/components/panels/alignment/index.tsx +244 -0
  68. package/src/components/panels/base/index.tsx +5 -0
  69. package/src/components/panels/base/styles.module.css +12 -0
  70. package/src/components/panels/conversation/index.module.css +151 -0
  71. package/src/components/panels/conversation/index.tsx +162 -0
  72. package/src/components/panels/events/CustomEventsEditor.tsx +384 -0
  73. package/src/components/panels/events/EditEventPanel.tsx +315 -0
  74. package/src/components/panels/events/ManageEventsPanel.tsx +98 -0
  75. package/src/components/panels/events/index.tsx +23 -0
  76. package/src/components/panels/events/styles.module.css +236 -0
  77. package/src/components/panels/history/index.tsx +92 -0
  78. package/src/components/panels/history/styles.module.css +106 -0
  79. package/src/components/panels/keymaps/index.module.css +78 -0
  80. package/src/components/panels/keymaps/index.tsx +167 -0
  81. package/src/components/panels/layers/index.tsx +240 -0
  82. package/src/components/panels/layers/styles.module.css +110 -0
  83. package/src/components/panels/legend/index.module.css +6 -0
  84. package/src/components/panels/legend/index.tsx +76 -0
  85. package/src/components/panels/logs/index.module.css +212 -0
  86. package/src/components/panels/logs/index.tsx +288 -0
  87. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  88. package/src/components/panels/nodeInputs/InputsGroup.tsx +64 -0
  89. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  90. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  91. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  92. package/src/components/panels/nodeInputs/OutputsGroup.tsx +65 -0
  93. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  94. package/src/components/panels/nodeInputs/index.module.css +284 -0
  95. package/src/components/panels/nodeInputs/index.tsx +339 -0
  96. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  97. package/src/components/panels/nodeInputs/useNodeInputsData.ts +173 -0
  98. package/src/components/panels/nodePicker/index.tsx +115 -0
  99. package/src/components/panels/panel/index.module.css +66 -0
  100. package/src/components/panels/panel/index.tsx +88 -0
  101. package/src/components/panels/search/index.module.css +66 -0
  102. package/src/components/panels/search/index.tsx +215 -0
  103. package/src/components/panels/systemSettings/index.tsx +206 -0
  104. package/src/components/panels/systemSettings/styles.module.css +11 -0
  105. package/src/components/panels/traces/GridLines.tsx +38 -0
  106. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  107. package/src/components/panels/traces/TraceLane.tsx +62 -0
  108. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  109. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  110. package/src/components/panels/traces/index.module.css +166 -0
  111. package/src/components/panels/traces/index.tsx +294 -0
  112. package/src/components/panels/traces/types.ts +48 -0
  113. package/src/components/panels/traces/useDerivedSpans.ts +212 -0
  114. package/src/components/panels/traces/utils.ts +25 -0
  115. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  116. package/src/components/panels/variables/ManageVariablesScreen.tsx +144 -0
  117. package/src/components/panels/variables/index.tsx +125 -0
  118. package/src/components/panels/variables/styles.module.css +236 -0
  119. package/src/components/primitives/icon.module.css +45 -0
  120. package/src/components/primitives/icon.tsx +38 -0
  121. package/src/components/sockets/input/index.tsx +76 -0
  122. package/src/components/sockets/input/styles.module.css +27 -0
  123. package/src/components/sockets/output/index.tsx +61 -0
  124. package/src/components/sockets/output/styles.module.css +27 -0
  125. package/src/css/prosemirror.css +57 -0
  126. package/src/css/rc-dock.css +112 -0
  127. package/src/css/rc-menu.css +100 -0
  128. package/src/css/vars.css +14 -0
  129. package/src/css/vscode.css +13 -0
  130. package/src/entry.css +4 -0
  131. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  132. package/src/generators/SequenceGenerator.tsx +104 -0
  133. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  134. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  135. package/src/generators/registerDefaultGenerators.ts +34 -0
  136. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  137. package/src/hooks/useDetachNodes.ts +39 -0
  138. package/src/hooks/useFlowHandlers.ts +115 -29
  139. package/src/hooks/useWasdPan.ts +188 -0
  140. package/src/index.css +146 -0
  141. package/src/index.ts +36 -18
  142. package/src/layout/dagre.tsx +119 -0
  143. package/src/layout/elk.ts +200 -0
  144. package/src/plugin/alignment/index.ts +81 -0
  145. package/src/plugin/docs/index.tsx +299 -0
  146. package/src/plugin/docs/panel/index.tsx +200 -0
  147. package/src/plugin/docs/panel/styles.module.css +174 -0
  148. package/src/plugin/graphrunner/actions.ts +253 -0
  149. package/src/plugin/graphrunner/buttons.tsx +87 -0
  150. package/src/plugin/graphrunner/client.ts +704 -0
  151. package/src/plugin/graphrunner/index.tsx +255 -0
  152. package/src/plugin/graphrunner/panel.tsx +386 -0
  153. package/src/plugin/graphrunner/runner.ts +358 -0
  154. package/src/plugin/graphrunner/session.ts +243 -0
  155. package/src/plugin/graphrunner/store.ts +206 -0
  156. package/src/plugin/graphrunner/styles.module.css +211 -0
  157. package/src/plugin/graphrunner/transport.ts +224 -0
  158. package/src/plugin/graphrunner/types.ts +672 -0
  159. package/src/plugin/graphrunner-local/execution-utils.ts +457 -0
  160. package/src/plugin/graphrunner-local/index.tsx +166 -0
  161. package/src/plugin/graphrunner-local/panel.tsx +231 -0
  162. package/src/plugin/graphrunner-local/store.ts +41 -0
  163. package/src/plugin/graphrunner-local/styles.module.css +101 -0
  164. package/src/plugin/graphrunner-local/transport.ts +1372 -0
  165. package/src/plugin/graphrunner-local/types.ts +10 -0
  166. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +633 -0
  167. package/src/plugin/graphrunner-webworker/index.tsx +146 -0
  168. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  169. package/src/plugin/graphrunner-webworker/store.ts +89 -0
  170. package/src/plugin/graphrunner-webworker/types.ts +17 -0
  171. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  172. package/src/plugin/realtime/realtimeRunner.ts +570 -0
  173. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  174. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  175. package/src/specifics/VariableGetSpecific.tsx +110 -0
  176. package/src/specifics/VariableSetSpecific.tsx +110 -0
  177. package/src/specifics/registerDefaultSpecifics.ts +5 -0
  178. package/src/store/actions.tsx +698 -0
  179. package/src/store/chat.ts +73 -0
  180. package/src/store/controls.tsx +62 -0
  181. package/src/store/documentation.tsx +69 -0
  182. package/src/store/events.tsx +116 -0
  183. package/src/store/flow.tsx +245 -0
  184. package/src/store/graphRunnerClient.ts +110 -0
  185. package/src/store/hotKeys.tsx +323 -0
  186. package/src/store/layers.ts +259 -0
  187. package/src/store/legend.tsx +76 -0
  188. package/src/store/logs.ts +28 -0
  189. package/src/store/menubar.ts +41 -0
  190. package/src/store/refs.ts +84 -0
  191. package/src/store/registry.ts +43 -0
  192. package/src/store/selection.ts +22 -0
  193. package/src/store/settings.ts +99 -0
  194. package/src/store/socketGenerator.tsx +54 -0
  195. package/src/store/specific.tsx +75 -0
  196. package/src/store/specs.tsx +35 -0
  197. package/src/store/tabs.ts +278 -0
  198. package/src/store/toolbar.tsx +45 -0
  199. package/src/store/traces.ts +240 -0
  200. package/src/store/variables.ts +37 -0
  201. package/src/system/graph.ts +134 -0
  202. package/src/system/index.ts +3 -0
  203. package/src/system/notifications.ts +98 -0
  204. package/src/system/plugin.ts +27 -0
  205. package/src/system/provider.tsx +22 -0
  206. package/src/system/pubsub.ts +323 -0
  207. package/src/system/system.ts +223 -0
  208. package/src/system/tabLoader.tsx +265 -0
  209. package/src/system/undoRedo.ts +103 -0
  210. package/src/transformers/Uigraph.ts +60 -0
  211. package/src/transformers/behaveToFlow.ts +16 -4
  212. package/src/transformers/flowToBehave.ts +32 -12
  213. package/src/types/NodeMetadata.ts +27 -0
  214. package/src/types/graph.ts +49 -0
  215. package/src/types/nodes.ts +45 -0
  216. package/src/types.ts +16 -0
  217. package/src/util/colors.ts +1 -29
  218. package/src/util/downloadJson.ts +18 -0
  219. package/src/util/extractNodeMetadata.ts +16 -0
  220. package/src/util/getPickerFilters.ts +1 -1
  221. package/src/util/isBehaveNode.ts +6 -0
  222. package/src/util/isValidConnection.ts +28 -15
  223. package/src/util/mergeSockets.ts +29 -0
  224. package/src/util/serializeVariables.ts +66 -0
  225. package/src/util/sockets.ts +43 -0
  226. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  227. package/stories/apex/layoutController/index.stories.tsx +48 -0
  228. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  229. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  230. package/stories/components/colorpicker/index.stories.tsx +20 -0
  231. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  232. package/stories/components/contextMenus/node.stories.tsx +26 -0
  233. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  234. package/stories/components/controls/any/index.stories.tsx +19 -0
  235. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  236. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  237. package/stories/components/controls/number/index.stories.tsx +19 -0
  238. package/stories/components/controls/string/index.stories.tsx +19 -0
  239. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  240. package/stories/components/nodes/comment.stories.tsx +106 -0
  241. package/stories/components/panels/alignment.stories.tsx +24 -0
  242. package/stories/components/panels/events.stories.tsx +38 -0
  243. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  244. package/stories/components/panels/history.stories.tsx +37 -0
  245. package/stories/components/panels/keymaps.stories.tsx +21 -0
  246. package/stories/components/panels/legend.stories.tsx +37 -0
  247. package/stories/components/panels/logs.stories.tsx +24 -0
  248. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  249. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  250. package/stories/components/panels/panel.stories.tsx +39 -0
  251. package/stories/components/panels/search.stories.tsx +24 -0
  252. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  253. package/stories/components/panels/traces.stories.tsx +225 -0
  254. package/stories/components/panels/variables.stories.tsx +24 -0
  255. package/stories/defaults/defaultStoryProvider.tsx +167 -0
  256. package/stories/defaults/systemGenerator.ts +38 -0
  257. package/tests/components/edges/offsetBezier.test.ts +51 -0
  258. package/tests/components/layoutController/utils.test.ts +68 -0
  259. package/tests/components/panels/traces/utils.test.ts +52 -0
  260. package/tests/flowToBehave.test.ts +26 -4
  261. package/tests/notifications.test.ts +87 -0
  262. package/tests/saveLoad.test.ts +372 -0
  263. package/tests/util/calculateNewEdge.test.ts +98 -0
  264. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  265. package/tests/util/hasPositionMetaData.test.ts +33 -0
  266. package/tests/util/isBehaveNode.test.ts +22 -0
  267. package/tests/util/isHandleConnected.test.ts +37 -0
  268. package/tests/util/mergeSockets.test.ts +43 -0
  269. package/tests/visual/README.md +64 -0
  270. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  271. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  272. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  273. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  274. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  275. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  276. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  277. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  278. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  279. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  280. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  281. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  282. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  283. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  284. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  285. package/tests/visual/panels.visual.test.tsx +76 -0
  286. package/tsconfig.base.json +39 -0
  287. package/tsconfig.json +18 -59
  288. package/tsconfig.prod.json +23 -0
  289. package/tsdown.config.ts +15 -3
  290. package/typedoc.json +7 -7
  291. package/vite.config.js +7 -0
  292. package/vitest.config.ts +5 -2
  293. package/vitest.visual.config.ts +48 -0
  294. package/src/components/AutoSizeInput.tsx +0 -65
  295. package/src/components/Controls.tsx +0 -87
  296. package/src/components/InputSocket.tsx +0 -142
  297. package/src/components/Node.tsx +0 -68
  298. package/src/components/NodeContainer.tsx +0 -46
  299. package/src/components/NodePicker.tsx +0 -77
  300. package/src/components/OutputSocket.tsx +0 -58
  301. package/src/components/modals/ClearModal.tsx +0 -40
  302. package/src/components/modals/HelpModal.tsx +0 -36
  303. package/src/components/modals/LoadModal.tsx +0 -96
  304. package/src/components/modals/Modal.tsx +0 -64
  305. package/src/components/modals/SaveModal.tsx +0 -60
  306. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  307. package/src/hooks/useGraphRunner.ts +0 -104
  308. package/src/hooks/useMergeMap.ts +0 -14
  309. package/src/hooks/useNodeSpecJson.ts +0 -20
  310. package/src/hooks/useQueriableDefinitions.ts +0 -22
  311. package/src/styles.css +0 -8
  312. package/tailwind.config.ts +0 -19
  313. package/tests/tsconfig.json +0 -10
  314. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -4,40 +4,59 @@ import type {
4
4
  NodeSpecJSON
5
5
  } from '@kiberon-labs/behave-graph';
6
6
  import type { Edge, Node } from 'reactflow';
7
+ import { System } from '../system/system';
8
+ import { writeVariablesToJSON } from '../util/serializeVariables';
9
+ import { isBehaveNode } from '@/util/isBehaveNode';
7
10
 
8
11
  const isNullish = (value: any): value is null | undefined =>
9
12
  value === undefined || value === null;
10
13
 
11
14
  export const flowToBehave = (
15
+ system: System,
12
16
  nodes: Node[],
13
17
  edges: Edge[],
14
18
  nodeSpecJSON: NodeSpecJSON[]
15
19
  ): GraphJSON => {
16
- const graph: GraphJSON = { nodes: [], variables: [], customEvents: [] };
20
+ const graph: GraphJSON = {
21
+ nodes: [],
22
+ variables: [],
23
+ customEvents: system.eventsStore.getState().getCustomEvents()
24
+ };
25
+
26
+ const registry = system.registry.getState();
27
+ const varStore = system.variableStore.getState().variables;
17
28
 
18
29
  nodes.forEach((node) => {
19
- if (node.type === undefined) return;
30
+ if (!isBehaveNode(node)) return;
31
+
32
+ const nodeType = node.data.type as string;
20
33
 
21
34
  const nodeSpec = nodeSpecJSON.find(
22
- (nodeSpec) => nodeSpec.type === node.type
35
+ (nodeSpec) => nodeSpec.type === nodeType
23
36
  );
24
37
 
25
38
  if (nodeSpec === undefined) return;
26
39
 
27
40
  const behaveNode: NodeJSON = {
28
41
  id: node.id,
29
- type: node.type,
30
- metadata: {
31
- positionX: String(node.position.x),
32
- positionY: String(node.position.y)
33
- }
42
+ type: nodeType
34
43
  };
35
44
 
36
- Object.entries(node.data).forEach(([key, value]) => {
45
+ const configuration = node.data?.configuration;
46
+ if (
47
+ configuration &&
48
+ typeof configuration === 'object' &&
49
+ Array.isArray(configuration) === false &&
50
+ Object.keys(configuration).length > 0
51
+ ) {
52
+ behaveNode.configuration = { ...configuration };
53
+ }
54
+
55
+ Object.entries(node.data.ports ?? {}).forEach(([key, value]) => {
37
56
  if (behaveNode.parameters === undefined) {
38
57
  behaveNode.parameters = {};
39
58
  }
40
- behaveNode.parameters[key] = { value: value as string };
59
+ behaveNode.parameters[key] = { value: value };
41
60
  });
42
61
 
43
62
  edges
@@ -56,7 +75,6 @@ export const flowToBehave = (
56
75
  if (isNullish(edge.targetHandle)) return;
57
76
  if (isNullish(edge.sourceHandle)) return;
58
77
 
59
- // TODO: some of these are flow outputs, and should be saved differently. -Ben, Oct 11, 2022
60
78
  behaveNode.parameters[edge.targetHandle] = {
61
79
  link: { nodeId: edge.source, socket: edge.sourceHandle }
62
80
  };
@@ -77,7 +95,6 @@ export const flowToBehave = (
77
95
  if (isNullish(edge.targetHandle)) return;
78
96
  if (isNullish(edge.sourceHandle)) return;
79
97
 
80
- // TODO: some of these are flow outputs, and should be saved differently. -Ben, Oct 11, 2022
81
98
  behaveNode.flows[edge.sourceHandle] = {
82
99
  nodeId: edge.target,
83
100
  socket: edge.targetHandle
@@ -89,5 +106,8 @@ export const flowToBehave = (
89
106
  graph.nodes?.push(behaveNode);
90
107
  });
91
108
 
109
+ if (Object.keys(varStore).length > 0) {
110
+ graph.variables = writeVariablesToJSON(registry, varStore);
111
+ }
92
112
  return graph;
93
113
  };
@@ -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,45 @@
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
+ export type ICommentNode = Omit<Node, 'data' | 'type'> & {
19
+ type: 'commentNode';
20
+ data: {
21
+ annotations?: Record<string, any>;
22
+ text: string;
23
+ fontSize?: string;
24
+ };
25
+ };
26
+
27
+ export type IGroupNode = Omit<Node, 'data' | 'type'> & {
28
+ type: 'group';
29
+ data: {
30
+ color: string;
31
+ };
32
+ };
33
+
34
+ export type IAINode = Omit<Node, 'data' | 'type'> & {
35
+ type: 'behaveNode:ai';
36
+ data: {
37
+ annotations?: Record<string, any>;
38
+ type: string;
39
+ ports?: DynamicPorts;
40
+ configuration: Record<string, any>;
41
+ };
42
+ };
43
+
44
+ export type AnyNode = IBehaveNode | ICommentNode | IAINode | IGroupNode;
45
+ export type AnyNodeType = AnyNode['type'];
package/src/types.ts ADDED
@@ -0,0 +1,16 @@
1
+ import type { ChoiceJSON } from '@kiberon-labs/behave-graph';
2
+
3
+ export interface SocketBase {
4
+ name: string;
5
+ key: string;
6
+ choices?: ChoiceJSON;
7
+ valueType: string;
8
+ defaultValue?: any;
9
+ }
10
+
11
+ export type Socket = SocketBase;
12
+
13
+ export interface DynamicPorts {
14
+ inputs?: SocketBase[];
15
+ outputs?: SocketBase[];
16
+ }
@@ -1,34 +1,6 @@
1
1
  import type { NodeSpecJSON } from '@kiberon-labs/behave-graph';
2
2
 
3
- export type color =
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 = (
@@ -0,0 +1,6 @@
1
+ import type { IBehaveNode } from '@/types/nodes';
2
+ import type { Node } from 'reactflow';
3
+
4
+ export function isBehaveNode(node: Node): node is IBehaveNode {
5
+ return typeof node.type === 'string' && node.type.startsWith('behaveNode');
6
+ }
@@ -1,8 +1,9 @@
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 type { IBehaveNode } from '@/types/nodes.js';
6
7
 
7
8
  export const isValidConnection = (
8
9
  connection: Connection,
@@ -11,30 +12,42 @@ export const isValidConnection = (
11
12
  ) => {
12
13
  if (connection.source === null || connection.target === null) return false;
13
14
 
14
- const sourceNode = instance.getNode(connection.source);
15
- const targetNode = instance.getNode(connection.target);
15
+ const sourceNode = instance.getNode(connection.source) as IBehaveNode;
16
+ const targetNode = instance.getNode(connection.target) as IBehaveNode;
16
17
  const edges = instance.getEdges();
17
18
 
18
19
  if (sourceNode === undefined || targetNode === undefined) return false;
19
20
 
20
- const sourceSockets = getSocketsByNodeTypeAndHandleType(
21
+ // Get spec sockets
22
+ const sourceSpecSockets = getSocketsByNodeTypeAndHandleType(
21
23
  specJSON,
22
- sourceNode.type,
24
+ sourceNode.data?.type,
23
25
  'source'
24
26
  );
25
-
26
- const sourceSocket = sourceSockets?.find(
27
- (socket) => socket.name === connection.sourceHandle
28
- );
29
-
30
- const targetSockets = getSocketsByNodeTypeAndHandleType(
27
+ const targetSpecSockets = getSocketsByNodeTypeAndHandleType(
31
28
  specJSON,
32
- targetNode.type,
29
+ targetNode.data?.type,
33
30
  'target'
34
31
  );
35
32
 
36
- const targetSocket = targetSockets?.find(
37
- (socket) => socket.name === connection.targetHandle
33
+ if (sourceSpecSockets === undefined || targetSpecSockets === undefined)
34
+ return false;
35
+
36
+ // Merge spec sockets with dynamic ports
37
+ const sourceSockets = mergeSockets(
38
+ sourceSpecSockets,
39
+ sourceNode.data.dynamicPorts?.outputs
40
+ );
41
+ const targetSockets = mergeSockets(
42
+ targetSpecSockets,
43
+ targetNode.data.dynamicPorts?.inputs
44
+ );
45
+
46
+ const sourceSocket = sourceSockets.find(
47
+ (s) => s.name === connection.sourceHandle
48
+ );
49
+ const targetSocket = targetSockets.find(
50
+ (s) => s.name === connection.targetHandle
38
51
  );
39
52
 
40
53
  if (sourceSocket === undefined || targetSocket === undefined) return false;
@@ -42,7 +55,7 @@ export const isValidConnection = (
42
55
  // only flow sockets can have two inputs
43
56
  if (
44
57
  targetSocket.valueType !== 'flow' &&
45
- isHandleConnected(edges, targetNode.id, targetSocket.name, 'target')
58
+ isHandleConnected(edges, targetNode.id, targetSocket.key, 'target')
46
59
  ) {
47
60
  return false;
48
61
  }
@@ -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
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Example Web Worker for executing behavior graphs
3
+ *
4
+ * This shows the SIMPLEST way to create a custom worker:
5
+ * 1. Set up your registry
6
+ * 2. Import the reference implementation
7
+ * 3. That's it!
8
+ */
9
+
10
+ import {
11
+ registerCoreProfile,
12
+ type IRegistry
13
+ } from '@kiberon-labs/behave-graph';
14
+ import { initializeGraphWorker } from '@/plugin/graphrunner-webworker/graph-executor.worker.js';
15
+ import type { ValueType } from '@kiberon-labs/behave-graph';
16
+
17
+ // ============================================================================
18
+ // STEP 1: Set up your registry with your custom nodes
19
+ // ============================================================================
20
+
21
+ const ColorValue: ValueType = {
22
+ name: 'color',
23
+ creator: () => '#000000',
24
+ deserialize: (value: string) => value,
25
+ serialize: (value: string) => value,
26
+ lerp: (start: string, end: string, t: number) => (t < 0.5 ? start : end),
27
+ equals: (a: string, b: string) => a === b,
28
+ clone: (value: string) => value
29
+ };
30
+
31
+ const registry: IRegistry = registerCoreProfile({
32
+ nodes: {},
33
+ values: {
34
+ color: ColorValue
35
+ },
36
+ dependencies: {}
37
+ });
38
+
39
+ initializeGraphWorker({ registry });
@@ -0,0 +1,48 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { LayoutController } from '@/components/layoutController';
3
+ import {
4
+ DefaultSystemProvider,
5
+ systemGenerator
6
+ } from '~/defaults/defaultStoryProvider';
7
+ import { SystemProvider } from '@/system';
8
+
9
+ const meta: Meta<typeof LayoutController> = {
10
+ component: LayoutController,
11
+ title: 'Apex/Layout Controller',
12
+ decorators: [(Story) => <Story />],
13
+ parameters: {
14
+ layout: 'fullscreen'
15
+ }
16
+ };
17
+
18
+ export default meta;
19
+
20
+ type Story = StoryObj<typeof meta>;
21
+
22
+ export const Default: Story = {
23
+ render: () => {
24
+ return (
25
+ <div className="h-dvh">
26
+ <DefaultSystemProvider>
27
+ <LayoutController />
28
+ </DefaultSystemProvider>
29
+ </div>
30
+ );
31
+ },
32
+ args: {}
33
+ };
34
+
35
+ const emptySystem = systemGenerator();
36
+
37
+ export const Empty: Story = {
38
+ render: () => {
39
+ return (
40
+ <div className="h-dvh">
41
+ <SystemProvider value={emptySystem}>
42
+ <LayoutController />
43
+ </SystemProvider>
44
+ </div>
45
+ );
46
+ },
47
+ args: {}
48
+ };