@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
@@ -0,0 +1,225 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { TracesPanel } from '@/components/panels/traces';
3
+ import {
4
+ DefaultSystemProvider,
5
+ systemGenerator
6
+ } from '~/defaults/defaultStoryProvider';
7
+ import { SystemProvider } from '@/system';
8
+
9
+ const meta: Meta<typeof TracesPanel> = {
10
+ title: 'Components/Panels/TracesPanel',
11
+ component: TracesPanel,
12
+ decorators: [
13
+ (Story) => (
14
+ <DefaultSystemProvider>
15
+ <Story />
16
+ </DefaultSystemProvider>
17
+ )
18
+ ],
19
+ parameters: {
20
+ docs: {
21
+ description: {
22
+ component: 'TracesPanel component for displaying execution traces.'
23
+ }
24
+ }
25
+ }
26
+ };
27
+ export default meta;
28
+
29
+ type Story = StoryObj<typeof TracesPanel>;
30
+
31
+ function Injector() {
32
+ // Keep the original provider for the simple empty/default story.
33
+ // Other stories will create their own System with a prefilled collector.
34
+ return <TracesPanel />;
35
+ }
36
+
37
+ function makeCollector(
38
+ spans: Array<{
39
+ nodeId: string;
40
+ name: string;
41
+ start: number;
42
+ end: number;
43
+ lane: number;
44
+ }>
45
+ ) {
46
+ const capacity = 1000;
47
+ const arr: any[] = Array.from({ length: capacity });
48
+ let maxLane = -1;
49
+ for (let i = 0; i < spans.length; i++) {
50
+ const s = spans[i];
51
+ arr[i] = {
52
+ id: i + 1,
53
+ nodeId: s.nodeId,
54
+ name: s.name,
55
+ start: s.start,
56
+ end: s.end,
57
+ lane: s.lane
58
+ };
59
+ maxLane = Math.max(maxLane, s.lane);
60
+ }
61
+
62
+ const laneOpen = Array.from(
63
+ { length: Math.max(1, maxLane + 1) },
64
+ () => false
65
+ );
66
+ // mark lanes with open spans
67
+ for (const s of spans) {
68
+ if (Number.isNaN(s.end)) laneOpen[s.lane] = true;
69
+ }
70
+
71
+ return {
72
+ capacity,
73
+ spans: arr,
74
+ writeIndex: spans.length % capacity,
75
+ size: spans.length,
76
+ nextId: spans.length + 1,
77
+ openByNodeId: new Map<string, number[]>(),
78
+ laneOpen
79
+ };
80
+ }
81
+
82
+ export const Default: Story = {
83
+ render: () => (
84
+ <DefaultSystemProvider>
85
+ <Injector mode="empty" />
86
+ </DefaultSystemProvider>
87
+ ),
88
+ parameters: {
89
+ docs: {
90
+ description: {
91
+ story: 'Default TracesPanel (no spans).'
92
+ }
93
+ }
94
+ }
95
+ };
96
+
97
+ export const SampleTraces: Story = {
98
+ render: () => {
99
+ const sys = systemGenerator();
100
+ // create a few sample closed spans
101
+ const now = performance.now();
102
+ const spans = [
103
+ {
104
+ nodeId: 'node-a',
105
+ name: 'Node A',
106
+ start: now - 900,
107
+ end: now - 800,
108
+ lane: 0
109
+ },
110
+ {
111
+ nodeId: 'node-b',
112
+ name: 'Node B',
113
+ start: now - 700,
114
+ end: now - 600,
115
+ lane: 1
116
+ },
117
+ {
118
+ nodeId: 'node-c',
119
+ name: 'Worker C',
120
+ start: now - 950,
121
+ end: now - 500,
122
+ lane: 2
123
+ }
124
+ ];
125
+ const collector = makeCollector(spans);
126
+ sys.traceStore.setState({
127
+ collector,
128
+ version: sys.traceStore.getState().version + 1
129
+ });
130
+
131
+ return (
132
+ <SystemProvider value={sys}>
133
+ <TracesPanel />
134
+ </SystemProvider>
135
+ );
136
+ },
137
+ parameters: {
138
+ docs: {
139
+ description: {
140
+ story: 'TracesPanel with a few sample spans (closed).'
141
+ }
142
+ }
143
+ }
144
+ };
145
+
146
+ export const WithOpenSpan: Story = {
147
+ render: () => {
148
+ const sys = systemGenerator();
149
+ const now = performance.now();
150
+ const spans = [
151
+ {
152
+ nodeId: 'node-closed',
153
+ name: 'Closed Node',
154
+ start: now - 400,
155
+ end: now - 300,
156
+ lane: 0
157
+ },
158
+ {
159
+ nodeId: 'node-open',
160
+ name: 'Open Node',
161
+ start: now - 200,
162
+ end: Number.NaN,
163
+ lane: 1
164
+ }
165
+ ];
166
+ const collector = makeCollector(spans);
167
+ sys.traceStore.setState({
168
+ collector,
169
+ version: sys.traceStore.getState().version + 1
170
+ });
171
+
172
+ return (
173
+ <SystemProvider value={sys}>
174
+ <TracesPanel />
175
+ </SystemProvider>
176
+ );
177
+ },
178
+ parameters: {
179
+ docs: {
180
+ description: {
181
+ story:
182
+ 'TracesPanel showing an open (ongoing) span alongside closed spans.'
183
+ }
184
+ }
185
+ }
186
+ };
187
+
188
+ export const ManyTraces: Story = {
189
+ render: () => {
190
+ const sys = systemGenerator();
191
+ const now = performance.now();
192
+ const spans: Array<any> = [];
193
+ for (let i = 0; i < 80; i++) {
194
+ const lane = i % 6;
195
+ const start = now - (800 - i * 5);
196
+ const end = start + 30 + (i % 5);
197
+ spans.push({
198
+ nodeId: `node-${lane}`,
199
+ name: `Node ${lane}`,
200
+ start,
201
+ end,
202
+ lane
203
+ });
204
+ }
205
+ const collector = makeCollector(spans);
206
+ sys.traceStore.setState({
207
+ collector,
208
+ version: sys.traceStore.getState().version + 1
209
+ });
210
+
211
+ return (
212
+ <SystemProvider value={sys}>
213
+ <TracesPanel />
214
+ </SystemProvider>
215
+ );
216
+ },
217
+ parameters: {
218
+ docs: {
219
+ description: {
220
+ story:
221
+ 'TracesPanel populated with many short spans to test layout and performance.'
222
+ }
223
+ }
224
+ }
225
+ };
@@ -0,0 +1,24 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { VariablesPanel } from '@/components/panels/variables';
3
+ import { DefaultSystemProvider } from '~/defaults/defaultStoryProvider';
4
+
5
+ const meta: Meta<typeof VariablesPanel> = {
6
+ title: 'Components/Panels/Variables',
7
+ component: VariablesPanel,
8
+ parameters: {
9
+ layout: 'fullscreen'
10
+ }
11
+ };
12
+
13
+ export default meta;
14
+ type Story = StoryObj<typeof VariablesPanel>;
15
+ export const Default: Story = {
16
+ render: () => {
17
+ return (
18
+ <DefaultSystemProvider>
19
+ <VariablesPanel />
20
+ </DefaultSystemProvider>
21
+ );
22
+ },
23
+ args: {}
24
+ };
@@ -0,0 +1,167 @@
1
+ import { docsPlugin } from '@/plugin/docs';
2
+
3
+ import { SystemProvider } from '@/system/provider';
4
+ import { System } from '@/system/system';
5
+ import {
6
+ registerCoreProfile,
7
+ type ValueType
8
+ } from '@kiberon-labs/behave-graph';
9
+
10
+ import { alignmentPlugin } from '@/plugin/alignment';
11
+ import { downloadJson, localGraphRunnerPlugin } from '@/index';
12
+
13
+ export const ColorValue: ValueType = {
14
+ name: 'color',
15
+ creator: () => '#000000',
16
+ deserialize: (value: string) => value,
17
+ serialize: (value: string) => value,
18
+ lerp: (start: string, end: string, t: number) => (t < 0.5 ? start : end),
19
+ equals: (a: string, b: string) => a === b,
20
+ clone: (value: string) => value
21
+ };
22
+
23
+ // Create the old-style registry for node definitions
24
+ let coreRegistry = registerCoreProfile({
25
+ nodes: {},
26
+ values: {
27
+ color: ColorValue
28
+ },
29
+ dependencies: {}
30
+ });
31
+ // Convert to INodeRegistry
32
+ const nodeRegistry = {
33
+ values: coreRegistry.values,
34
+ specs: []
35
+ };
36
+
37
+ //Basic system generator for tests and stories
38
+ export const systemGenerator = () => {
39
+ const defaultSys = new System(nodeRegistry);
40
+ return defaultSys;
41
+ };
42
+
43
+ const defaultSys = new System(nodeRegistry);
44
+
45
+ defaultSys.registerPlugin(alignmentPlugin);
46
+ defaultSys.registerPlugin(docsPlugin);
47
+ defaultSys.registerPlugin(localGraphRunnerPlugin, {
48
+ registry: coreRegistry,
49
+ events: [
50
+ {
51
+ id: '0',
52
+ name: 'Example Event',
53
+ parameters: [
54
+ {
55
+ name: 'exampleParam',
56
+ valueTypeName: 'string',
57
+ defaultValue: 'Foo'
58
+ }
59
+ ],
60
+ description: 'An example event for demonstration purposes.',
61
+ readonly: true
62
+ }
63
+ ],
64
+ variables: [
65
+ {
66
+ id: '0',
67
+ name: 'Example Variable',
68
+ valueTypeName: 'string',
69
+ initialValue: 'Hello, World!',
70
+ description: 'An example variable for demonstration purposes.',
71
+ readonly: true
72
+ }
73
+ ]
74
+ });
75
+
76
+ defaultSys.pubsub.subscribe('graph:saved', (_, graph) => {
77
+ downloadJson('graph.json', graph);
78
+ });
79
+
80
+ defaultSys.flowStore.getState().setGraph({
81
+ nodes: [
82
+ {
83
+ type: 'lifecycle/onStart',
84
+ id: '0',
85
+ flows: {
86
+ flow: {
87
+ nodeId: '1',
88
+ socket: 'flow'
89
+ }
90
+ }
91
+ },
92
+ {
93
+ type: 'flow/branch',
94
+ id: '1',
95
+ parameters: {
96
+ condition: {
97
+ value: false
98
+ }
99
+ },
100
+ flows: {
101
+ true: {
102
+ nodeId: '2',
103
+ socket: 'flow'
104
+ },
105
+ false: {
106
+ nodeId: '3',
107
+ socket: 'flow'
108
+ }
109
+ }
110
+ },
111
+ {
112
+ type: 'debug/log',
113
+ id: '2',
114
+ parameters: {
115
+ text: {
116
+ value: 'Condition is true!'
117
+ }
118
+ }
119
+ },
120
+ {
121
+ type: 'debug/log',
122
+ id: '3',
123
+ parameters: {
124
+ text: {
125
+ value: 'Condition is false!'
126
+ }
127
+ }
128
+ }
129
+ ]
130
+ });
131
+
132
+ // Seed a few example log entries so the Logs panel renders representative
133
+ // content in stories and visual tests. Timestamps use fixed local components so
134
+ // they render deterministically regardless of timezone.
135
+ const exampleLogTime = (h: number, m: number, s: number, ms: number) =>
136
+ new Date(2024, 0, 1, h, m, s, ms);
137
+
138
+ [
139
+ { type: 'info' as const, message: 'Graph compiled successfully.' },
140
+ { type: 'verbose' as const, message: 'lifecycle/onStart fired (node 0).' },
141
+ {
142
+ type: 'info' as const,
143
+ message: 'flow/branch evaluated condition = false.'
144
+ },
145
+ {
146
+ type: 'warning' as const,
147
+ message: 'Variable "Example Variable" is unused.'
148
+ },
149
+ {
150
+ type: 'error' as const,
151
+ message: 'debug/log: failed to resolve socket "value" on node 3.'
152
+ }
153
+ ].forEach((entry, index) => {
154
+ defaultSys.logsStore.getState().append({
155
+ type: entry.type,
156
+ data: { message: entry.message },
157
+ time: exampleLogTime(13, 45, 30 + index, 120 + index * 37)
158
+ });
159
+ });
160
+
161
+ export const DefaultSystemProvider = ({
162
+ children
163
+ }: {
164
+ children: React.ReactElement;
165
+ }) => {
166
+ return <SystemProvider value={defaultSys}>{children}</SystemProvider>;
167
+ };
@@ -0,0 +1,38 @@
1
+ import { System } from '@/system/system';
2
+ import {
3
+ registerCoreProfile,
4
+ writeNodeSpecsToJSON,
5
+ type ValueType
6
+ } from '@kiberon-labs/behave-graph';
7
+
8
+ export const ColorValue: ValueType = {
9
+ name: 'color',
10
+ creator: () => '#000000',
11
+ deserialize: (value: string) => value,
12
+ serialize: (value: string) => value,
13
+ lerp: (start: string, end: string, t: number) => (t < 0.5 ? start : end),
14
+ equals: (a: string, b: string) => a === b,
15
+ clone: (value: string) => value
16
+ };
17
+
18
+ // Create the old-style registry for node definitions
19
+ let coreRegistry = registerCoreProfile({
20
+ nodes: {},
21
+ values: {
22
+ color: ColorValue
23
+ },
24
+ dependencies: {} as Parameters<typeof registerCoreProfile>[0]['dependencies']
25
+ });
26
+
27
+ // Convert to INodeRegistry
28
+ const nodeSpecs = writeNodeSpecsToJSON(coreRegistry);
29
+ const nodeRegistry = {
30
+ values: coreRegistry.values,
31
+ specs: nodeSpecs
32
+ };
33
+
34
+ //Basic system generator for tests and stories
35
+ export const systemGenerator = () => {
36
+ const defaultSys = new System(nodeRegistry);
37
+ return defaultSys;
38
+ };
@@ -0,0 +1,51 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { Position } from 'reactflow';
3
+ import { getBetterBezierPath } from '@/components/edges/offsetBezier';
4
+
5
+ describe('getBetterBezierPath', () => {
6
+ it('returns a bezier path string plus label/offset coordinates', () => {
7
+ const result = getBetterBezierPath({
8
+ sourceX: 0,
9
+ sourceY: 0,
10
+ targetX: 0,
11
+ targetY: 200
12
+ });
13
+
14
+ expect(result).toHaveLength(5);
15
+ const [path, labelX, labelY] = result;
16
+ expect(typeof path).toBe('string');
17
+ expect(path.startsWith('M0,0 C')).toBe(true);
18
+ expect(typeof labelX).toBe('number');
19
+ expect(typeof labelY).toBe('number');
20
+ });
21
+
22
+ it('offsets the control points vertically for bottom->top connections', () => {
23
+ const [path] = getBetterBezierPath({
24
+ sourceX: 0,
25
+ sourceY: 0,
26
+ sourcePosition: Position.Bottom,
27
+ targetX: 0,
28
+ targetY: 200,
29
+ targetPosition: Position.Top,
30
+ offset: 75
31
+ });
32
+
33
+ // source control = (0, 0 + 75), target control = (0, 200 - 75)
34
+ expect(path).toBe('M0,0 C0,75 0,125 0,200');
35
+ });
36
+
37
+ it('offsets the control points horizontally for left/right connections', () => {
38
+ const [path] = getBetterBezierPath({
39
+ sourceX: 0,
40
+ sourceY: 0,
41
+ sourcePosition: Position.Right,
42
+ targetX: 200,
43
+ targetY: 0,
44
+ targetPosition: Position.Left,
45
+ offset: 50
46
+ });
47
+
48
+ // source control = (0 + 50, 0), target control = (200 - 50, 0)
49
+ expect(path).toBe('M0,0 C50,0 150,0 200,0');
50
+ });
51
+ });
@@ -0,0 +1,68 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type { LayoutBase } from 'rc-dock';
3
+ import {
4
+ findGraphPanel,
5
+ findTabInLayout,
6
+ removeTabFromLayout
7
+ } from '@/components/layoutController/utils';
8
+
9
+ const makeLayout = (): LayoutBase =>
10
+ ({
11
+ dockbox: {
12
+ id: 'root',
13
+ mode: 'horizontal',
14
+ children: [
15
+ {
16
+ id: 'graphs',
17
+ tabs: [{ id: 'tab-a' }, { id: 'tab-b' }]
18
+ },
19
+ {
20
+ id: 'sidebar',
21
+ tabs: [{ id: 'tab-c' }]
22
+ }
23
+ ]
24
+ }
25
+ }) as unknown as LayoutBase;
26
+
27
+ describe('layoutController/utils', () => {
28
+ describe('findGraphPanel', () => {
29
+ it('locates the panel whose id is "graphs"', () => {
30
+ const panel = findGraphPanel(makeLayout());
31
+ expect(panel?.id).toBe('graphs');
32
+ });
33
+
34
+ it('returns null when no graph panel exists', () => {
35
+ const layout = {
36
+ dockbox: { id: 'root', children: [{ id: 'other', tabs: [] }] }
37
+ } as unknown as LayoutBase;
38
+ expect(findGraphPanel(layout)).toBeNull();
39
+ });
40
+ });
41
+
42
+ describe('findTabInLayout', () => {
43
+ it('finds the panel that owns a given tab', () => {
44
+ expect(findTabInLayout(makeLayout(), 'tab-b')?.id).toBe('graphs');
45
+ expect(findTabInLayout(makeLayout(), 'tab-c')?.id).toBe('sidebar');
46
+ });
47
+
48
+ it('returns null for an unknown tab', () => {
49
+ expect(findTabInLayout(makeLayout(), 'missing')).toBeNull();
50
+ });
51
+ });
52
+
53
+ describe('removeTabFromLayout', () => {
54
+ it('removes a tab while keeping the panel that still has tabs', () => {
55
+ const updated = removeTabFromLayout(makeLayout(), 'tab-a');
56
+ const graphsPanel = findTabInLayout(updated, 'tab-b');
57
+ expect(graphsPanel?.id).toBe('graphs');
58
+ expect(findTabInLayout(updated, 'tab-a')).toBeNull();
59
+ });
60
+
61
+ it('does not mutate the original layout', () => {
62
+ const layout = makeLayout();
63
+ removeTabFromLayout(layout, 'tab-a');
64
+ // original still has tab-a
65
+ expect(findTabInLayout(layout, 'tab-a')?.id).toBe('graphs');
66
+ });
67
+ });
68
+ });
@@ -0,0 +1,52 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ calculateTimeInterval,
4
+ clamp,
5
+ hashToHue
6
+ } from '@/components/panels/traces/utils';
7
+
8
+ describe('traces/utils', () => {
9
+ describe('hashToHue', () => {
10
+ it('is deterministic for the same input', () => {
11
+ expect(hashToHue('node-a')).toBe(hashToHue('node-a'));
12
+ });
13
+
14
+ it('always returns a hue in the [0, 360) range', () => {
15
+ for (const s of ['', 'a', 'flow/branch', 'a-very-long-identifier-123']) {
16
+ const hue = hashToHue(s);
17
+ expect(hue).toBeGreaterThanOrEqual(0);
18
+ expect(hue).toBeLessThan(360);
19
+ expect(Number.isInteger(hue)).toBe(true);
20
+ }
21
+ });
22
+
23
+ it('generally produces different hues for different inputs', () => {
24
+ expect(hashToHue('alpha')).not.toBe(hashToHue('beta'));
25
+ });
26
+ });
27
+
28
+ describe('clamp', () => {
29
+ it('returns the value when within range', () => {
30
+ expect(clamp(5, 0, 10)).toBe(5);
31
+ });
32
+ it('clamps below the minimum', () => {
33
+ expect(clamp(-3, 0, 10)).toBe(0);
34
+ });
35
+ it('clamps above the maximum', () => {
36
+ expect(clamp(42, 0, 10)).toBe(10);
37
+ });
38
+ });
39
+
40
+ describe('calculateTimeInterval', () => {
41
+ it('picks a "nice" interval roughly targeting 8 ticks', () => {
42
+ expect(calculateTimeInterval(8)).toBe(1);
43
+ expect(calculateTimeInterval(80)).toBe(10);
44
+ expect(calculateTimeInterval(800)).toBe(100);
45
+ expect(calculateTimeInterval(8000)).toBe(1000);
46
+ });
47
+
48
+ it('caps at the largest nice interval for very large ranges', () => {
49
+ expect(calculateTimeInterval(10_000_000)).toBe(10000);
50
+ });
51
+ });
52
+ });
@@ -8,18 +8,40 @@ import rawFlowGraph from '../../../graphs/react-flow/graph.json';
8
8
  import { behaveToFlow } from '../src/transformers/behaveToFlow.js';
9
9
  import { flowToBehave } from '../src/transformers/flowToBehave.js';
10
10
  import { it, expect } from 'vitest';
11
+ import { System } from '@/system/system';
11
12
 
12
13
  const flowGraph = rawFlowGraph as GraphJSON;
13
14
 
14
15
  const [nodes, edges] = behaveToFlow(flowGraph);
15
16
 
16
17
  it('transforms from flow to behave', () => {
17
- const registry = registerCoreProfile({
18
+ const coreRegistry = registerCoreProfile({
18
19
  nodes: {},
19
20
  values: {},
20
21
  dependencies: {}
21
22
  });
22
- const specJSON = writeNodeSpecsToJSON(registry);
23
- const output = flowToBehave(nodes, edges, specJSON);
24
- expect(output).toEqual(flowGraph);
23
+ const specJSON = writeNodeSpecsToJSON(coreRegistry);
24
+ const registry = {
25
+ values: coreRegistry.values,
26
+ specs: specJSON
27
+ };
28
+ const system = new System(registry);
29
+ const output = flowToBehave(system, nodes, edges, specJSON);
30
+
31
+ // Remove position metadata from expected graph since we no longer include it
32
+ const expectedGraph = {
33
+ ...flowGraph,
34
+ nodes: flowGraph.nodes.map((node) => {
35
+ const { metadata, ...rest } = node as any;
36
+ if (metadata) {
37
+ const { positionX, positionY, ...remainingMetadata } = metadata;
38
+ return Object.keys(remainingMetadata).length > 0
39
+ ? { ...rest, metadata: remainingMetadata }
40
+ : rest;
41
+ }
42
+ return node;
43
+ })
44
+ };
45
+
46
+ expect(output).toEqual(expectedGraph);
25
47
  });