@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.
Files changed (251) hide show
  1. package/.storybook/manager.ts +6 -0
  2. package/.storybook/preview.ts +49 -1
  3. package/.storybook/styles.css +9 -3
  4. package/.turbo/turbo-build.log +1 -1
  5. package/CHANGELOG.md +368 -0
  6. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  7. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  8. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  9. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  10. package/dist/index.css +36 -33
  11. package/dist/index.css.map +1 -1
  12. package/dist/index.d.ts +1865 -550
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +14357 -11221
  15. package/dist/index.js.map +1 -1
  16. package/dist/noteImpl-KkrrWgJd.js +242 -0
  17. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  18. package/dist/styles.module-CvmpDkZj.css +3 -0
  19. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  20. package/dist/styles.module-DZxg8aW9.js +271 -0
  21. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  22. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  23. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  24. package/docs/protocol.md +43 -20
  25. package/package.json +5 -9
  26. package/src/components/FloatingToolbar/index.module.css +5 -13
  27. package/src/components/FloatingToolbar/index.tsx +9 -9
  28. package/src/components/Flow.tsx +34 -23
  29. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  30. package/src/components/contextMenus/NodePicker.module.css +13 -13
  31. package/src/components/contextMenus/edge.tsx +9 -95
  32. package/src/components/contextMenus/node.tsx +9 -149
  33. package/src/components/contextMenus/selection.tsx +5 -71
  34. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  35. package/src/components/controls/any/index.tsx +13 -2
  36. package/src/components/edges/index.tsx +75 -69
  37. package/src/components/layoutController/index.module.css +3 -0
  38. package/src/components/layoutController/index.tsx +24 -1
  39. package/src/components/layoutController/utils.ts +46 -3
  40. package/src/components/menubar/defaults.tsx +55 -19
  41. package/src/components/menubar/menuItem.module.css +18 -3
  42. package/src/components/menubar/menuItem.tsx +34 -1
  43. package/src/components/nodes/behave/NodeContainer.module.css +26 -25
  44. package/src/components/nodes/group/index.tsx +3 -3
  45. package/src/components/nodes/wrapper/styles.module.css +6 -32
  46. package/src/components/panels/alignment/index.module.css +0 -10
  47. package/src/components/panels/alignment/index.tsx +4 -4
  48. package/src/components/panels/base/styles.module.css +2 -2
  49. package/src/components/panels/common/PanelHeader.module.css +24 -0
  50. package/src/components/panels/common/PanelHeader.tsx +22 -0
  51. package/src/components/panels/common/SectionTitle.module.css +13 -0
  52. package/src/components/panels/common/SectionTitle.tsx +10 -0
  53. package/src/components/panels/events/EditEventPanel.tsx +14 -5
  54. package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
  55. package/src/components/panels/events/styles.module.css +6 -64
  56. package/src/components/panels/graphProperties/index.tsx +125 -0
  57. package/src/components/panels/history/index.tsx +2 -2
  58. package/src/components/panels/history/styles.module.css +0 -9
  59. package/src/components/panels/keymaps/index.module.css +3 -13
  60. package/src/components/panels/keymaps/index.tsx +1 -2
  61. package/src/components/panels/layers/index.tsx +20 -15
  62. package/src/components/panels/layers/styles.module.css +9 -12
  63. package/src/components/panels/legend/index.tsx +1 -1
  64. package/src/components/panels/logs/index.module.css +25 -19
  65. package/src/components/panels/logs/index.tsx +7 -7
  66. package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
  67. package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
  68. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
  69. package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
  70. package/src/components/panels/nodeInputs/index.module.css +99 -75
  71. package/src/components/panels/nodeInputs/index.tsx +21 -11
  72. package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
  73. package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
  74. package/src/components/panels/nodePicker/index.tsx +8 -8
  75. package/src/components/panels/panel/index.module.css +7 -7
  76. package/src/components/panels/search/index.module.css +0 -50
  77. package/src/components/panels/search/index.tsx +2 -2
  78. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  79. package/src/components/panels/systemSettings/index.tsx +221 -176
  80. package/src/components/panels/systemSettings/styles.module.css +135 -8
  81. package/src/components/panels/traces/GridLines.tsx +1 -1
  82. package/src/components/panels/traces/TimeGrid.tsx +3 -3
  83. package/src/components/panels/traces/TraceLane.tsx +1 -1
  84. package/src/components/panels/traces/index.module.css +1 -8
  85. package/src/components/panels/traces/index.tsx +8 -4
  86. package/src/components/panels/traces/useDerivedSpans.ts +241 -146
  87. package/src/components/panels/traces/utils.ts +8 -0
  88. package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
  89. package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
  90. package/src/components/panels/variables/index.tsx +2 -2
  91. package/src/components/panels/variables/styles.module.css +4 -91
  92. package/src/components/primitives/icon.module.css +4 -4
  93. package/src/components/sockets/input/index.tsx +9 -2
  94. package/src/components/sockets/input/styles.module.css +2 -3
  95. package/src/components/sockets/output/index.tsx +10 -3
  96. package/src/components/sockets/output/styles.module.css +1 -6
  97. package/src/css/notes.css +135 -0
  98. package/src/css/prosemirror.css +3 -3
  99. package/src/css/rc-dock.css +143 -43
  100. package/src/css/rc-menu.css +56 -55
  101. package/src/css/themes/kiberon.css +127 -0
  102. package/src/css/vars.css +197 -13
  103. package/src/css/vscode-elements.css +124 -0
  104. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  105. package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
  106. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  107. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  108. package/src/generators/SequenceGenerator.tsx +2 -2
  109. package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
  110. package/src/generators/SwitchOnStringGenerator.tsx +2 -2
  111. package/src/generators/callSubgraphSync.ts +126 -0
  112. package/src/generators/registerDefaultGenerators.ts +21 -0
  113. package/src/generators/registerDefaults.ts +26 -0
  114. package/src/hooks/useBehaveGraphFlow.ts +2 -2
  115. package/src/hooks/useFlowHandlers.ts +47 -9
  116. package/src/hooks/useWasdPan.ts +26 -4
  117. package/src/index.css +4 -16
  118. package/src/index.ts +17 -0
  119. package/src/manifest/contributionRegistry.ts +93 -0
  120. package/src/manifest/index.ts +4 -0
  121. package/src/manifest/loadManifest.ts +82 -0
  122. package/src/manifest/manifestPlugin.ts +29 -0
  123. package/src/manifest/passthroughValueType.ts +40 -0
  124. package/src/plugin/alignment/index.ts +22 -12
  125. package/src/plugin/autosave/controller.ts +366 -0
  126. package/src/plugin/autosave/index.tsx +114 -0
  127. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  128. package/src/plugin/autosave/panel/index.tsx +1 -0
  129. package/src/plugin/autosave/panel/styles.module.css +56 -0
  130. package/src/plugin/autosave/settings.ts +65 -0
  131. package/src/plugin/autosave/storage.ts +147 -0
  132. package/src/plugin/docs/index.tsx +2 -4
  133. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  134. package/src/plugin/docs/panel/index.tsx +15 -194
  135. package/src/plugin/docs/panel/styles.module.css +8 -8
  136. package/src/plugin/graphrunner/actions.ts +258 -185
  137. package/src/plugin/graphrunner/buttons.tsx +34 -26
  138. package/src/plugin/graphrunner/client.ts +4 -1
  139. package/src/plugin/graphrunner/index.tsx +29 -100
  140. package/src/plugin/graphrunner/panel.tsx +2 -2
  141. package/src/plugin/graphrunner/runController.ts +283 -0
  142. package/src/plugin/graphrunner/runner.ts +21 -192
  143. package/src/plugin/graphrunner/store.ts +14 -24
  144. package/src/plugin/graphrunner/styles.module.css +17 -57
  145. package/src/plugin/graphrunner/transport.ts +26 -0
  146. package/src/plugin/graphrunner/types.ts +21 -0
  147. package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
  148. package/src/plugin/graphrunner-local/index.tsx +8 -2
  149. package/src/plugin/graphrunner-local/panel.tsx +131 -175
  150. package/src/plugin/graphrunner-local/styles.module.css +57 -76
  151. package/src/plugin/graphrunner-local/transport.ts +151 -184
  152. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
  153. package/src/plugin/graphrunner-webworker/index.tsx +4 -10
  154. package/src/plugin/graphrunner-webworker/store.ts +9 -0
  155. package/src/plugin/kitchen-sink/index.ts +38 -0
  156. package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
  157. package/src/{layout → plugin/layout}/elk.ts +22 -6
  158. package/src/plugin/layout/index.ts +80 -0
  159. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  160. package/src/plugin/notes/index.tsx +191 -0
  161. package/src/plugin/notes/nodeActions.ts +100 -0
  162. package/src/plugin/notes/note.tsx +20 -0
  163. package/src/plugin/notes/noteImpl.tsx +89 -0
  164. package/src/plugin/realtime/realtimeRunner.ts +58 -4
  165. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
  166. package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
  167. package/src/specifics/VariableGetSpecific.tsx +2 -2
  168. package/src/specifics/VariableSetSpecific.tsx +2 -2
  169. package/src/store/actions.tsx +5 -5
  170. package/src/store/commands.ts +278 -0
  171. package/src/store/contextMenu.ts +192 -0
  172. package/src/store/conversions.ts +47 -0
  173. package/src/store/flow.tsx +23 -38
  174. package/src/store/graphMeta.ts +39 -0
  175. package/src/store/hotKeys.tsx +301 -260
  176. package/src/store/layers.ts +3 -3
  177. package/src/store/registry.ts +12 -4
  178. package/src/store/selection.ts +3 -3
  179. package/src/store/settings.ts +82 -82
  180. package/src/store/settingsSchema.ts +210 -0
  181. package/src/store/tabs.ts +5 -1
  182. package/src/store/traces.ts +3 -3
  183. package/src/system/graph.ts +11 -14
  184. package/src/system/graphSession.ts +172 -0
  185. package/src/system/index.ts +3 -0
  186. package/src/system/notifications.ts +13 -0
  187. package/src/system/persistence.ts +82 -0
  188. package/src/system/plugin.ts +28 -0
  189. package/src/system/provider.tsx +64 -0
  190. package/src/system/system.ts +518 -88
  191. package/src/system/tabLoader.tsx +70 -32
  192. package/src/system/undoRedo.ts +1 -1
  193. package/src/transformers/Uigraph.ts +5 -4
  194. package/src/transformers/contract.ts +87 -0
  195. package/src/transformers/flowToBehave.ts +13 -5
  196. package/src/types/nodes.ts +8 -3
  197. package/src/types.ts +2 -0
  198. package/src/util/autoConvert.ts +200 -0
  199. package/src/util/isValidConnection.ts +23 -2
  200. package/stories/defaults/defaultStoryProvider.tsx +17 -14
  201. package/stories/defaults/systemGenerator.ts +6 -1
  202. package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
  203. package/tests/autoConvert.test.ts +329 -0
  204. package/tests/autosavePlugin.test.ts +204 -0
  205. package/tests/callSubgraphSync.test.ts +148 -0
  206. package/tests/commandRegistry.test.ts +137 -0
  207. package/tests/contract.test.ts +51 -0
  208. package/tests/contractSerialize.test.ts +62 -0
  209. package/tests/deriveSpans.test.ts +71 -0
  210. package/tests/flowToBehave.test.ts +2 -1
  211. package/tests/hotkeys.test.ts +79 -0
  212. package/tests/keepAliveLifecycle.test.ts +167 -0
  213. package/tests/loadManifest.test.ts +113 -0
  214. package/tests/noteMarkdown.test.ts +65 -0
  215. package/tests/notesPlugin.test.ts +162 -0
  216. package/tests/persistence.test.ts +51 -0
  217. package/tests/saveLoad.test.ts +7 -6
  218. package/tests/settings.test.ts +178 -0
  219. package/tests/traceStore.test.ts +46 -0
  220. package/tests/visual/README.md +2 -2
  221. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  222. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  223. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  224. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  225. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  226. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  227. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  228. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  229. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  230. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  231. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  232. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  233. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  234. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  235. package/tests/visual/panels.visual.test.tsx +3 -3
  236. package/tests/wasdPan.test.ts +71 -0
  237. package/vitest.config.ts +1 -1
  238. package/vitest.visual.config.ts +7 -0
  239. package/.storybook/vscode.css +0 -814
  240. package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
  241. package/src/components/nodes/comment/comment.tsx +0 -103
  242. package/src/components/nodes/comment/styles.module.css +0 -150
  243. package/src/components/panels/conversation/index.module.css +0 -151
  244. package/src/components/panels/conversation/index.tsx +0 -162
  245. package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
  246. package/src/css/vscode.css +0 -13
  247. package/src/hooks/useDetachNodes.ts +0 -39
  248. package/src/plugin/graphrunner-webworker/types.ts +0 -17
  249. package/src/specifics/registerDefaultSpecifics.ts +0 -5
  250. package/src/store/chat.ts +0 -73
  251. package/src/store/graphRunnerClient.ts +0 -110
@@ -0,0 +1,47 @@
1
+ import { create, type StoreApi } from 'zustand';
2
+
3
+ /**
4
+ * A user/plugin-defined automatic type conversion: "when connecting a `from`
5
+ * socket to a `to` socket, splice in `nodeType`". `inputKey`/`outputKey` name
6
+ * the converter's value sockets; when omitted they're resolved from the node
7
+ * spec (first non-flow input/output).
8
+ */
9
+ export type ConversionRule = {
10
+ from: string;
11
+ to: string;
12
+ nodeType: string;
13
+ inputKey?: string;
14
+ outputKey?: string;
15
+ };
16
+
17
+ export type ConversionStore = {
18
+ conversions: ConversionRule[];
19
+ /** Add (or replace the existing rule for the same from→to pair). */
20
+ registerConversion: (rule: ConversionRule) => void;
21
+ removeConversion: (from: string, to: string) => void;
22
+ setConversions: (rules: ConversionRule[]) => void;
23
+ findConversion: (from: string, to: string) => ConversionRule | undefined;
24
+ };
25
+
26
+ export const conversionStoreFactory = (): StoreApi<ConversionStore> =>
27
+ create<ConversionStore>((set, get) => ({
28
+ conversions: [],
29
+ registerConversion: (rule) =>
30
+ set((s) => ({
31
+ conversions: [
32
+ ...s.conversions.filter(
33
+ (c) => !(c.from === rule.from && c.to === rule.to)
34
+ ),
35
+ rule
36
+ ]
37
+ })),
38
+ removeConversion: (from, to) =>
39
+ set((s) => ({
40
+ conversions: s.conversions.filter(
41
+ (c) => !(c.from === from && c.to === to)
42
+ )
43
+ })),
44
+ setConversions: (conversions) => set({ conversions: [...conversions] }),
45
+ findConversion: (from, to) =>
46
+ get().conversions.find((c) => c.from === from && c.to === to)
47
+ }));
@@ -1,5 +1,5 @@
1
1
  import { CustomEdge } from '@/components/edges';
2
- import type { System } from '@/system';
2
+ import type { GraphSession } from '@/system/graphSession';
3
3
  import { behaveToFlow } from '@/transformers/behaveToFlow';
4
4
  import { flowToBehave } from '@/transformers/flowToBehave';
5
5
  import { autoLayout } from '@/util/autoLayout';
@@ -18,7 +18,6 @@ import {
18
18
  import { create } from 'zustand';
19
19
  import { nonDeletable } from '@/annotations';
20
20
  import GroupNode from '@/components/nodes/group';
21
- import { CommentNode } from '@/components/nodes/comment/comment';
22
21
  import { BehaveNode } from '@/components/nodes/behave';
23
22
 
24
23
  export type FlowStore = {
@@ -38,28 +37,14 @@ export type FlowStore = {
38
37
  ) => void;
39
38
  };
40
39
 
41
- // const specJson = useStore(sys.specStore, (s) => s.specs);
42
- // const [customNodeTypes, setCustomNodeTypes] = useState<NodeTypes>();
43
- // useEffect(() => {
44
- // if (!specJson) return;
45
- // const customNodeTypes: Record<
46
- // AnyNodeType,
47
- // React.ComponentType<any>
48
- // > = getCustomNodeTypes(specJson);
49
-
50
- // customNodeTypes['commentNode'] = CommentNode;
51
- // customNodeTypes['group'] = GroupNode;
52
- // // customNodeTypes['behaveNode:ai'] = AINode;
53
-
54
- // setCustomNodeTypes(customNodeTypes);
55
- // }, [specJson]);
56
-
57
- export const flowStoreFactory = (system: System) => {
40
+ export const flowStoreFactory = (session: GraphSession) => {
58
41
  const flowStore = create<FlowStore>((set, get) => ({
59
42
  graphJson: null,
43
+ // `noteNode` (and its legacy `commentNode` alias) is contributed by the
44
+ // optional notes plugin (`@/plugin/notes`), which owns the heavy
45
+ // tiptap/prosemirror dependency.
60
46
  nodeTypes: {
61
47
  group: GroupNode,
62
- commentNode: CommentNode,
63
48
  behaveNode: BehaveNode
64
49
  },
65
50
  invalidateCache: () => set({ graphJson: null }),
@@ -69,19 +54,19 @@ export const flowStoreFactory = (system: System) => {
69
54
  return cached;
70
55
  }
71
56
 
72
- const nodes = system.nodeStore.getState().nodes;
73
- const edges = system.edgeStore.getState().edges;
74
- const _variables = system.variableStore.getState().variables;
75
- const specs = system.specStore.getState().specs;
57
+ const nodes = session.nodeStore.getState().nodes;
58
+ const edges = session.edgeStore.getState().edges;
59
+ const _variables = session.variableStore.getState().variables;
60
+ const specs = session.editor.specStore.getState().specs;
76
61
 
77
- const computed = flowToBehave(system, nodes, edges, specs);
62
+ const computed = flowToBehave(session, nodes, edges, specs);
78
63
 
79
64
  set({ graphJson: computed });
80
65
  return computed;
81
66
  },
82
67
 
83
68
  setGraph: (graphJson: GraphJSON, options?: { skipLayout?: boolean }) => {
84
- system.eventsStore
69
+ session.eventsStore
85
70
  .getState()
86
71
  .setCustomEvents(
87
72
  Object.fromEntries(
@@ -94,7 +79,7 @@ export const flowStoreFactory = (system: System) => {
94
79
  if (graphJson.variables) {
95
80
  graphJson.variables.forEach((varJson) => {
96
81
  const valueType =
97
- system.registry.getState().values[varJson.valueTypeName];
82
+ session.editor.registry.getState().values[varJson.valueTypeName];
98
83
  const initialValue = valueType?.deserialize
99
84
  ? valueType.deserialize(varJson.initialValue)
100
85
  : varJson.initialValue;
@@ -116,12 +101,12 @@ export const flowStoreFactory = (system: System) => {
116
101
  if (!hasPositionMetaData(graphJson)) {
117
102
  autoLayout(nodes, edges);
118
103
  }
119
- system.nodeStore.getState().setNodes(nodes);
120
- system.edgeStore.getState().setEdges(edges);
104
+ session.nodeStore.getState().setNodes(nodes);
105
+ session.edgeStore.getState().setEdges(edges);
121
106
  }
122
107
 
123
- // custom events stored in system.eventsStore
124
- system.variableStore.getState().setVariables(variables);
108
+ // custom events stored in session.eventsStore
109
+ session.variableStore.getState().setVariables(variables);
125
110
  get().invalidateCache();
126
111
  },
127
112
  edgeTypes: {
@@ -146,11 +131,11 @@ export const flowStoreFactory = (system: System) => {
146
131
  }
147
132
  }));
148
133
 
149
- system.nodeStore.subscribe(() => {
134
+ session.nodeStore.subscribe(() => {
150
135
  flowStore.getState().invalidateCache();
151
136
  });
152
137
 
153
- system.eventsStore.subscribe(() => {
138
+ session.eventsStore.subscribe(() => {
154
139
  flowStore.getState().invalidateCache();
155
140
  });
156
141
 
@@ -165,12 +150,12 @@ export type NodeStore = {
165
150
  applyNodeChanges: (changes: NodeChange[]) => void;
166
151
  };
167
152
 
168
- export const nodeStoreFactory = (system: System) =>
153
+ export const nodeStoreFactory = (session: GraphSession) =>
169
154
  create<NodeStore>((set) => ({
170
155
  nodes: [],
171
156
  addNode(node) {
172
157
  set((x) => ({ nodes: [...x.nodes, node] }));
173
- system.pubsub.publish('node:added', node);
158
+ session.pubsub.publish('node:added', node);
174
159
  },
175
160
  applyNodeChanges(changes: NodeChange[]) {
176
161
  set((p) => {
@@ -183,7 +168,7 @@ export const nodeStoreFactory = (system: System) =>
183
168
  }
184
169
  // Publish nodeRemoved event for deletable nodes
185
170
  if (node) {
186
- system.pubsub.publish('node:removed', node);
171
+ session.pubsub.publish('node:removed', node);
187
172
  }
188
173
  }
189
174
  return true;
@@ -211,7 +196,7 @@ export type EdgeStore = {
211
196
  applyEdgeChanges: (changes: EdgeChange[]) => void;
212
197
  };
213
198
 
214
- export const edgeStoreFactory = (_system: System) =>
199
+ export const edgeStoreFactory = (session: GraphSession) =>
215
200
  create<EdgeStore>((set) => ({
216
201
  edges: [],
217
202
 
@@ -225,7 +210,7 @@ export const edgeStoreFactory = (_system: System) =>
225
210
  if (change.type === 'remove') {
226
211
  const edge = p.edges.find((e) => e.id === change.id);
227
212
  if (edge) {
228
- _system.pubsub.publish('edge:removed', edge);
213
+ session.pubsub.publish('edge:removed', edge);
229
214
  }
230
215
  }
231
216
  });
@@ -0,0 +1,39 @@
1
+ import { create, type StoreApi } from 'zustand';
2
+
3
+ /**
4
+ * Reactive graph-level properties for a single {@link GraphSession}: the display
5
+ * name (also the tab title) and an arbitrary metadata bag (the graph
6
+ * annotations). Backed by a store so the Graph Properties panel, the tab title
7
+ * and anything else stay in sync.
8
+ */
9
+ export type GraphMetaStore = {
10
+ name: string;
11
+ metadata: Record<string, any>;
12
+ setName: (name: string) => void;
13
+ /** Replace the whole metadata bag. */
14
+ setMetadata: (metadata: Record<string, any>) => void;
15
+ /** Shallow-merge into the metadata bag. */
16
+ mergeMetadata: (partial: Record<string, any>) => void;
17
+ setMetadataValue: (key: string, value: any) => void;
18
+ removeMetadataKey: (key: string) => void;
19
+ };
20
+
21
+ export const graphMetaStoreFactory = (
22
+ name = 'Graph'
23
+ ): StoreApi<GraphMetaStore> =>
24
+ create<GraphMetaStore>((set) => ({
25
+ name,
26
+ metadata: {},
27
+ setName: (name) => set({ name }),
28
+ setMetadata: (metadata) => set({ metadata: { ...metadata } }),
29
+ mergeMetadata: (partial) =>
30
+ set((s) => ({ metadata: { ...s.metadata, ...partial } })),
31
+ setMetadataValue: (key, value) =>
32
+ set((s) => ({ metadata: { ...s.metadata, [key]: value } })),
33
+ removeMetadataKey: (key) =>
34
+ set((s) => {
35
+ const next = { ...s.metadata };
36
+ delete next[key];
37
+ return { metadata: next };
38
+ })
39
+ }));