@eventcatalog/core 4.12.3 → 5.0.0-beta.1

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 (267) hide show
  1. package/LICENSE +226 -95
  2. package/NOTICE +30 -0
  3. package/README.md +3 -2
  4. package/dist/analytics/analytics.cjs +2 -1
  5. package/dist/analytics/analytics.js +2 -2
  6. package/dist/analytics/log-build.cjs +44 -16
  7. package/dist/analytics/log-build.d.cts +6 -5
  8. package/dist/analytics/log-build.d.ts +6 -5
  9. package/dist/analytics/log-build.js +4 -3
  10. package/dist/{chunk-U4YJSTGV.js → chunk-AYNZXUB5.js} +2 -10
  11. package/dist/{chunk-5BPN6QEC.js → chunk-K2ACDO7Y.js} +1 -1
  12. package/dist/{chunk-ZYTCBNB3.js → chunk-KYJZJLBD.js} +2 -1
  13. package/dist/{chunk-TV3YAWKQ.js → chunk-Q6SD5SNQ.js} +1 -1
  14. package/dist/{chunk-HPC6KUDQ.js → chunk-S2QGT7ZF.js} +1 -1
  15. package/dist/chunk-TQLRG35T.js +203 -0
  16. package/dist/{chunk-M577VUOX.js → chunk-UDS3SYLZ.js} +13 -16
  17. package/dist/constants.cjs +1 -1
  18. package/dist/constants.js +1 -1
  19. package/dist/eventcatalog.cjs +408 -291
  20. package/dist/eventcatalog.config.d.cts +2 -3
  21. package/dist/eventcatalog.config.d.ts +2 -3
  22. package/dist/eventcatalog.js +35 -98
  23. package/dist/federation/content-cache.d.cts +0 -5
  24. package/dist/federation/content-cache.d.ts +0 -5
  25. package/dist/federation/diagnostics.d.cts +0 -5
  26. package/dist/federation/diagnostics.d.ts +0 -5
  27. package/dist/federation/federate.cjs +0 -9
  28. package/dist/federation/federate.d.cts +0 -5
  29. package/dist/federation/federate.d.ts +0 -5
  30. package/dist/federation/federate.js +4 -5
  31. package/dist/federation/filesystem-source-provider.d.cts +0 -5
  32. package/dist/federation/filesystem-source-provider.d.ts +0 -5
  33. package/dist/federation/github-source-provider.d.cts +0 -5
  34. package/dist/federation/github-source-provider.d.ts +0 -5
  35. package/dist/federation/output-transaction.d.cts +0 -4
  36. package/dist/federation/output-transaction.d.ts +0 -4
  37. package/dist/federation/public-assets.d.cts +0 -5
  38. package/dist/federation/public-assets.d.ts +0 -5
  39. package/dist/federation/source-provider.d.cts +0 -5
  40. package/dist/federation/source-provider.d.ts +0 -5
  41. package/dist/federation/types.d.cts +0 -5
  42. package/dist/federation/types.d.ts +0 -5
  43. package/dist/generate.cjs +1 -1
  44. package/dist/generate.js +3 -3
  45. package/dist/license-C1y-56bb.d.cts +23 -0
  46. package/dist/license-C1y-56bb.d.ts +23 -0
  47. package/dist/runtime-dependencies/@eventcatalog__visualiser__layout.mjs +3 -0
  48. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps.mjs +3 -0
  49. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__react.mjs +3 -0
  50. package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__server.mjs +3 -0
  51. package/dist/runtime-dependencies/@modelcontextprotocol__sdk__types.js.mjs +3 -0
  52. package/dist/runtime-dependencies/manifest.json +12 -1
  53. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__graphql.mjs +3 -0
  54. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__json.mjs +3 -0
  55. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__markup.mjs +3 -0
  56. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__protobuf.mjs +3 -0
  57. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__yaml.mjs +3 -0
  58. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-dark.mjs +3 -0
  59. package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-light.mjs +3 -0
  60. package/dist/utils/cli-logger.cjs +1 -1
  61. package/dist/utils/cli-logger.js +2 -2
  62. package/dist/utils/license-status.cjs +240 -0
  63. package/dist/utils/license-status.d.cts +28 -0
  64. package/dist/utils/license-status.d.ts +28 -0
  65. package/dist/utils/license-status.js +12 -0
  66. package/eventcatalog/astro.config.mjs +1 -1
  67. package/eventcatalog/integrations/eventcatalog-runtime.mjs +1 -1
  68. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +29 -19
  69. package/eventcatalog/src/components/ChatPanel/OfflineReply.tsx +74 -0
  70. package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +24 -28
  71. package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +16 -11
  72. package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +4 -218
  73. package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +27 -36
  74. package/eventcatalog/src/components/Header.astro +43 -58
  75. package/eventcatalog/src/components/Lists/PillListFlat.styles.css +17 -17
  76. package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +1 -1
  77. package/eventcatalog/src/components/MDX/Flow/Flow.astro +4 -0
  78. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +14 -0
  79. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +49 -18
  80. package/eventcatalog/src/components/MDX/RemoteFile.astro +2 -24
  81. package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +59 -93
  82. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -32
  83. package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +20 -67
  84. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -11
  85. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +11 -60
  86. package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -3
  87. package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +0 -3
  88. package/eventcatalog/src/components/SchemaExplorer/VersionHistoryModal.tsx +2 -9
  89. package/eventcatalog/src/components/SchemaExplorer/parse-schema.ts +46 -0
  90. package/eventcatalog/src/components/SchemaExplorer/utils.ts +11 -0
  91. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +2 -9
  92. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +288 -0
  93. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +3 -19
  94. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +85 -30
  95. package/eventcatalog/src/components/Settings/SettingsShared.tsx +7 -75
  96. package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +2 -2
  97. package/eventcatalog/src/components/TrialBadge.astro +82 -0
  98. package/eventcatalog/src/content.config.ts +9 -96
  99. package/eventcatalog/src/{enterprise → features}/ai/chat-api.ts +22 -34
  100. package/eventcatalog/src/{enterprise → features}/analytics/adapters/ga4.ts +0 -5
  101. package/eventcatalog/src/{enterprise → features}/analytics/adapters/gtm.ts +0 -5
  102. package/eventcatalog/src/{enterprise → features}/analytics/adapters/posthog.ts +0 -5
  103. package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsHead.astro +2 -4
  104. package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsTracker.astro +2 -4
  105. package/eventcatalog/src/{enterprise → features}/analytics/tracker.ts +0 -5
  106. package/eventcatalog/src/{enterprise → features}/api/catalog.ts +0 -5
  107. package/eventcatalog/src/{enterprise → features}/auth/[...auth].ts +0 -5
  108. package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware-auth.ts +0 -5
  109. package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware.ts +0 -5
  110. package/eventcatalog/src/{enterprise → features}/collections/custom-pages.ts +0 -5
  111. package/eventcatalog/src/{enterprise → features}/collections/index.ts +0 -5
  112. package/eventcatalog/src/{enterprise → features}/collections/resource-docs.ts +0 -5
  113. package/eventcatalog/src/{enterprise → features}/custom-documentation/collection.ts +0 -5
  114. package/eventcatalog/src/features/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
  115. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -5
  116. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +1 -6
  117. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +0 -5
  118. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/index.tsx +1 -6
  119. package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/types.ts +0 -5
  120. package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/index.astro → features/custom-documentation/components/CustomDocumentationPage.astro} +5 -5
  121. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/badge-styles.ts +0 -5
  122. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/custom-docs.ts +1 -6
  123. package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/docs-search.ts +0 -5
  124. package/eventcatalog/src/{enterprise → features}/custom-pages/routes.ts +0 -5
  125. package/eventcatalog/src/{enterprise → features}/directory/user-team-directory.ts +0 -5
  126. package/eventcatalog/src/{enterprise → features}/fields/field-extractor.ts +0 -5
  127. package/eventcatalog/src/{enterprise → features}/fields/field-indexer.ts +0 -5
  128. package/eventcatalog/src/{enterprise → features}/fields/fields-db.ts +0 -5
  129. package/eventcatalog/src/{enterprise → features}/fields/pages/api/fields.ts +1 -6
  130. package/eventcatalog/src/{enterprise → features}/fields/pages/fields.astro +1 -2
  131. package/eventcatalog/src/{enterprise → features}/integrations/eventcatalog-features.ts +17 -75
  132. package/eventcatalog/src/features/mcp/apps/architecture-diagram/links.ts +59 -0
  133. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +299 -0
  134. package/eventcatalog/src/features/mcp/apps/architecture-diagram/shared.ts +14 -0
  135. package/eventcatalog/src/features/mcp/apps/architecture-diagram/view.tsx +454 -0
  136. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +432 -0
  137. package/eventcatalog/src/features/mcp/apps/mermaid-stub.ts +10 -0
  138. package/eventcatalog/src/features/mcp/apps/schema-viewer/schema-code.tsx +65 -0
  139. package/eventcatalog/src/features/mcp/apps/schema-viewer/shared.ts +23 -0
  140. package/eventcatalog/src/features/mcp/apps/schema-viewer/view.tsx +170 -0
  141. package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +98 -0
  142. package/eventcatalog/src/features/mcp/apps/shared/resource-types.ts +15 -0
  143. package/eventcatalog/src/features/mcp/apps/viewer/shared.ts +24 -0
  144. package/eventcatalog/src/features/mcp/apps/viewer/styles.css +25 -0
  145. package/eventcatalog/src/features/mcp/apps/viewer/view.tsx +59 -0
  146. package/eventcatalog/src/features/mcp/mcp-app-icons.ts +63 -0
  147. package/eventcatalog/src/features/mcp/mcp-apps.ts +160 -0
  148. package/eventcatalog/src/{enterprise → features}/mcp/mcp-auth.ts +0 -5
  149. package/eventcatalog/src/{enterprise → features}/mcp/mcp-scope.ts +7 -7
  150. package/eventcatalog/src/{enterprise → features}/mcp/mcp-scoped-tools.ts +47 -40
  151. package/eventcatalog/src/{enterprise → features}/mcp/mcp-server.ts +347 -34
  152. package/eventcatalog/src/{enterprise → features}/mcp/oauth-protected-resource.ts +0 -5
  153. package/eventcatalog/src/features/mcp/schema-viewer.ts +24 -0
  154. package/eventcatalog/src/{enterprise → features}/tools/catalog-tools.ts +133 -102
  155. package/eventcatalog/src/features/tools/index.ts +5 -0
  156. package/eventcatalog/src/{enterprise → features}/visualizer-layout/reset.ts +0 -5
  157. package/eventcatalog/src/{enterprise → features}/visualizer-layout/save.ts +0 -5
  158. package/eventcatalog/src/layouts/BaseLayout.astro +2 -2
  159. package/eventcatalog/src/layouts/Footer.astro +31 -39
  160. package/eventcatalog/src/layouts/SettingsLayout.astro +6 -6
  161. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -37
  162. package/eventcatalog/src/{enterprise → pages}/api/schemas/[collection]/[id]/[version]/index.ts +0 -22
  163. package/eventcatalog/src/{enterprise → pages}/api/schemas/services/[id]/[version]/[specification]/index.ts +0 -19
  164. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +2 -6
  165. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -5
  166. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +2 -6
  167. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -5
  168. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].md.ts +2 -6
  169. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +2 -6
  170. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +9 -5
  171. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +12 -0
  172. package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/root-index.astro → pages/docs/custom/index.astro} +1 -23
  173. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +4 -9
  174. package/eventcatalog/src/pages/docs/llm/llms.txt.ts +4 -4
  175. package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +0 -11
  176. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +2 -2
  177. package/eventcatalog/src/pages/index.astro +2 -2
  178. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +0 -3
  179. package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -4
  180. package/eventcatalog/src/pages/settings/assistant.astro +2 -4
  181. package/eventcatalog/src/pages/settings/license.astro +18 -0
  182. package/eventcatalog/src/pages/settings/llm-access.astro +1 -4
  183. package/eventcatalog/src/pages/settings/mcp.astro +33 -4
  184. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -2
  185. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +2 -45
  186. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -1
  187. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +7 -109
  188. package/eventcatalog/src/pages/visualiser/_mermaid-route.ts +78 -0
  189. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/_index.data.ts +44 -0
  190. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -1
  191. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +56 -0
  192. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +3 -40
  193. package/eventcatalog/src/pages/visualiser/domains/[id]/[version].mermaid.ts +20 -0
  194. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/_index.data.ts +29 -0
  195. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +3 -38
  196. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +56 -0
  197. package/eventcatalog/src/pages/visualiser/systems/[id]/[version].mermaid.ts +20 -0
  198. package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +1 -1
  199. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +1 -1
  200. package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +1 -1
  201. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +7 -32
  202. package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +1 -1
  203. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
  204. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +2 -8
  205. package/eventcatalog/src/stores/sidebar-store/builders/system.ts +2 -12
  206. package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +0 -10
  207. package/eventcatalog/src/stores/sidebar-store/state.ts +4 -6
  208. package/eventcatalog/src/styles/theme.css +22 -18
  209. package/eventcatalog/src/styles/themes/forest.css +8 -8
  210. package/eventcatalog/src/styles/themes/ocean.css +8 -8
  211. package/eventcatalog/src/styles/themes/sapphire.css +8 -8
  212. package/eventcatalog/src/styles/themes/sunset.css +8 -8
  213. package/eventcatalog/src/utils/clipboard.ts +4 -4
  214. package/eventcatalog/src/utils/collections/flow-step-schema.ts +117 -0
  215. package/eventcatalog/src/utils/collections/pointer-schema.ts +7 -0
  216. package/eventcatalog/src/utils/collections/resource-docs.ts +677 -14
  217. package/eventcatalog/src/utils/collections/schema-loader.ts +0 -5
  218. package/eventcatalog/src/utils/feature.ts +14 -23
  219. package/eventcatalog/src/utils/license.ts +114 -0
  220. package/eventcatalog/src/utils/node-graphs/architecture-diagram-types.ts +32 -0
  221. package/eventcatalog/src/utils/node-graphs/architecture-diagram.ts +84 -0
  222. package/eventcatalog/src/utils/node-graphs/channel-node-graph.ts +4 -25
  223. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -39
  224. package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +11 -27
  225. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +679 -0
  226. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +3 -20
  227. package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +51 -4
  228. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +8 -23
  229. package/eventcatalog/src/utils/node-graphs/flow-lanes.ts +119 -0
  230. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +133 -47
  231. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +28 -0
  232. package/eventcatalog/src/utils/node-graphs/layout-persistence.ts +3 -3
  233. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +16 -34
  234. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +11 -25
  235. package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +18 -54
  236. package/eventcatalog/src/utils/node-graphs/system-levels-node-graph.ts +59 -0
  237. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +20 -80
  238. package/eventcatalog/src/utils/node-graphs/utils/utils.ts +1 -78
  239. package/eventcatalog/src/utils/trial.ts +36 -0
  240. package/eventcatalog/tsconfig.json +1 -1
  241. package/package.json +11 -11
  242. package/dist/chunk-FV56YFM4.js +0 -7
  243. package/dist/federation/entitlement.cjs +0 -31
  244. package/dist/federation/entitlement.d.cts +0 -12
  245. package/dist/federation/entitlement.d.ts +0 -12
  246. package/dist/federation/entitlement.js +0 -6
  247. package/dist/runtime-dependencies/dagre.mjs +0 -3
  248. package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +0 -265
  249. package/eventcatalog/src/enterprise/LICENSE +0 -57
  250. package/eventcatalog/src/enterprise/README.md +0 -5
  251. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +0 -691
  252. package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +0 -9
  253. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/[...path]/index.astro +0 -18
  254. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/feature.astro +0 -171
  255. package/eventcatalog/src/enterprise/feature.ts +0 -75
  256. package/eventcatalog/src/enterprise/tools/index.ts +0 -10
  257. package/eventcatalog/src/hooks/eventcatalog-visualizer.ts +0 -126
  258. package/eventcatalog/src/pages/settings/billing.astro +0 -17
  259. package/eventcatalog/src/pages/visualiser/domain-integrations/index.astro +0 -26
  260. package/eventcatalog/src/types/mcp-modules.d.ts +0 -67
  261. package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +0 -261
  262. package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +0 -91
  263. /package/eventcatalog/src/{enterprise → features}/auth/error.astro +0 -0
  264. /package/eventcatalog/src/{enterprise → features}/auth/login.astro +0 -0
  265. /package/eventcatalog/src/{enterprise → features}/auth/unauthorized.astro +0 -0
  266. /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path]/_index.data.ts +0 -0
  267. /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path].mdx.ts +0 -0
@@ -1,13 +1,11 @@
1
1
  import { getCollection } from 'astro:content';
2
2
  import {
3
- createDagreGraph,
4
- calculatedNodes,
5
3
  generateIdForNode,
6
4
  getEdgeLabelForServiceAsTarget,
7
5
  generatedIdForEdge,
8
6
  createEdge,
9
- layoutDagreGraph,
10
7
  } from '@utils/node-graphs/utils/utils';
8
+ import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
11
9
  import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
12
10
  import { getNodesAndEdges as getAgentsNodeAndEdges } from './agents-node-graph';
13
11
  import { getNodesAndEdges as getDataProductsNodeAndEdges } from './data-products-node-graph';
@@ -16,12 +14,9 @@ import { createVersionedMap, findInMap } from '@utils/collections/util';
16
14
  import { getProducersOfMessage } from '@utils/collections/services';
17
15
  import { getProducersOfMessage as getAgentProducersOfMessage } from '@utils/collections/agents';
18
16
 
19
- type DagreGraph = any;
20
-
21
17
  interface NodesAndEdgesProps {
22
18
  id: string;
23
19
  version: string;
24
- defaultFlow?: DagreGraph;
25
20
  mode: 'simple' | 'full';
26
21
  group?: boolean;
27
22
  channelRenderMode?: 'single' | 'flat';
@@ -31,13 +26,11 @@ interface NodesAndEdgesProps {
31
26
  export const getNodesAndEdges = async ({
32
27
  id,
33
28
  version,
34
- defaultFlow,
35
29
  mode = 'simple',
36
30
  group = false,
37
31
  channelRenderMode = 'flat',
38
32
  layout = true,
39
33
  }: NodesAndEdgesProps) => {
40
- const flow = defaultFlow || createDagreGraph({ ranksep: 360, nodesep: 50, edgesep: 50 });
41
34
  let nodes = new Map(),
42
35
  edges = new Map();
43
36
 
@@ -97,7 +90,6 @@ export const getNodesAndEdges = async ({
97
90
  const { nodes: serviceNodes, edges: serviceEdges } = await getServicesNodeAndEdges({
98
91
  id: service.id,
99
92
  version: service.version,
100
- defaultFlow: flow,
101
93
  mode,
102
94
  renderAllEdges: true,
103
95
  channelRenderMode,
@@ -122,7 +114,6 @@ export const getNodesAndEdges = async ({
122
114
  const { nodes: agentNodes, edges: agentEdges } = await getAgentsNodeAndEdges({
123
115
  id: agent.id,
124
116
  version: agent.version,
125
- defaultFlow: flow,
126
117
  mode,
127
118
  renderAllEdges: true,
128
119
  channelRenderMode,
@@ -139,7 +130,6 @@ export const getNodesAndEdges = async ({
139
130
  const { nodes: dataProductNodes, edges: dataProductEdges } = await getDataProductsNodeAndEdges({
140
131
  id: dataProduct.id,
141
132
  version: dataProduct.version,
142
- defaultFlow: flow,
143
133
  mode,
144
134
  layout: false,
145
135
  });
@@ -154,7 +144,6 @@ export const getNodesAndEdges = async ({
154
144
  const { nodes: subDomainNodes, edges: subDomainEdges } = await getNodesAndEdges({
155
145
  id: subDomain.id,
156
146
  version: subDomain.version,
157
- defaultFlow: flow,
158
147
  mode,
159
148
  group: true,
160
149
  channelRenderMode,
@@ -175,12 +164,6 @@ export const getNodesAndEdges = async ({
175
164
  });
176
165
  }
177
166
 
178
- if (layout) {
179
- layoutDagreGraph(flow);
180
- }
181
-
182
- return {
183
- nodes: calculatedNodes(flow, Array.from(nodes.values())),
184
- edges: [...edges.values()],
185
- };
167
+ const graph = { nodes: [...nodes.values()], edges: [...edges.values()] };
168
+ return layout ? layoutNodeGraph(graph) : graph;
186
169
  };
@@ -33,6 +33,9 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
33
33
  channel: ['[(', ')]'],
34
34
  domains: ['[', ']'], // rectangle
35
35
  domain: ['[', ']'],
36
+ 'context-domain': ['[', ']'], // another domain, shown as a single card
37
+ systems: ['[[', ']]'], // a system shown as a single node
38
+ 'context-actor': ['((', '))'], // circle
36
39
  flows: ['([', '])'], // stadium (rounded)
37
40
  flow: ['([', '])'],
38
41
  systems: ['[[', ']]'],
@@ -52,6 +55,9 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
52
55
  note: ['[', ']'], // rectangle
53
56
  };
54
57
 
58
+ /** Node types that are boundaries around other nodes, rendered as subgraphs */
59
+ const GROUP_NODE_TYPES = new Set(['system-group', 'domain-group']);
60
+
55
61
  /**
56
62
  * Mermaid class definitions for styling different node types
57
63
  */
@@ -72,6 +78,9 @@ const NODE_STYLE_CLASSES: Record<string, string> = {
72
78
  channel: 'fill:#6b7280,stroke:#374151,color:#fff',
73
79
  domains: 'fill:#eab308,stroke:#a16207,color:#000',
74
80
  domain: 'fill:#eab308,stroke:#a16207,color:#000',
81
+ 'context-domain': 'fill:#eab308,stroke:#a16207,color:#000',
82
+ systems: 'fill:#7c3aed,stroke:#5b21b6,color:#fff',
83
+ 'context-actor': 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
75
84
  flows: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
76
85
  flow: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
77
86
  systems: 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
@@ -176,6 +185,16 @@ export function getNodeLabel(node: Node): string {
176
185
  return formatLabelWithVersion(name, version);
177
186
  }
178
187
 
188
+ if (type === 'systems' || type === 'system-group') {
189
+ const system = (data as any).system;
190
+ return formatLabelWithVersion(system?.name || system?.id || node.id, system?.version);
191
+ }
192
+
193
+ if (type === 'context-domain' || type === 'domain-group') {
194
+ const domain = (data as any).domain;
195
+ return formatLabelWithVersion(domain?.name || domain?.id || node.id, domain?.version);
196
+ }
197
+
179
198
  if (type === 'domains' || type === 'domain') {
180
199
  const domain = (data as any).domain;
181
200
  // Domain data can be nested in .data
@@ -230,6 +249,11 @@ export function getNodeLabel(node: Node): string {
230
249
  return entity?.name || entity?.id || node.id;
231
250
  }
232
251
 
252
+ if (type === 'custom') {
253
+ const custom = (data as any).custom ?? {};
254
+ return custom.title || (data as any).step?.title || node.id;
255
+ }
256
+
233
257
  if (type === 'note') {
234
258
  return (data as any).text || (data as any).label || 'Note';
235
259
  }
@@ -286,16 +310,37 @@ export function convertToMermaid(nodes: Node[], edges: Edge[], options: MermaidE
286
310
  });
287
311
  }
288
312
 
289
- // Add node definitions
313
+ // Add node definitions. Nodes inside a group (a system or domain boundary)
314
+ // are nested in a subgraph for that group, so containment is kept
290
315
  lines.push('');
291
316
  lines.push(' %% Nodes');
292
317
 
318
+ const nodeIds = new Set(nodes.map((node) => node.id));
319
+ const childrenOf = new Map<string, Node[]>();
320
+ const topLevelNodes: Node[] = [];
293
321
  nodes.forEach((node) => {
322
+ if (node.parentId && nodeIds.has(node.parentId)) {
323
+ childrenOf.set(node.parentId, [...(childrenOf.get(node.parentId) ?? []), node]);
324
+ } else {
325
+ topLevelNodes.push(node);
326
+ }
327
+ });
328
+
329
+ const addNode = (node: Node, depth: number) => {
330
+ const indent = ' '.repeat(depth);
294
331
  const sanitizedId = sanitizeMermaidId(node.id);
295
332
  const label = escapeMermaidLabel(getNodeLabel(node));
296
- const [prefix, suffix] = getMermaidNodeShape(node.type || 'custom');
333
+ const children = childrenOf.get(node.id);
297
334
 
298
- let nodeLine = ` ${sanitizedId}${prefix}"${label}"${suffix}`;
335
+ if (children || GROUP_NODE_TYPES.has(node.type ?? '')) {
336
+ lines.push(`${indent}subgraph ${sanitizedId}["${label}"]`);
337
+ children?.forEach((child) => addNode(child, depth + 1));
338
+ lines.push(`${indent}end`);
339
+ return;
340
+ }
341
+
342
+ const [prefix, suffix] = getMermaidNodeShape(node.type || 'custom');
343
+ let nodeLine = `${indent}${sanitizedId}${prefix}"${label}"${suffix}`;
299
344
 
300
345
  // Add class reference if styles are enabled
301
346
  if (includeStyles && node.type && usedTypes.has(node.type)) {
@@ -303,7 +348,9 @@ export function convertToMermaid(nodes: Node[], edges: Edge[], options: MermaidE
303
348
  }
304
349
 
305
350
  lines.push(nodeLine);
306
- });
351
+ };
352
+
353
+ topLevelNodes.forEach((node) => addNode(node, 1));
307
354
 
308
355
  // Add edge definitions
309
356
  lines.push('');
@@ -1,15 +1,6 @@
1
1
  import type { Node, Edge } from '@xyflow/react';
2
- import dagre from 'dagre';
3
- import {
4
- createDagreGraph,
5
- calculatedNodes,
6
- createEdge,
7
- createNode,
8
- buildContextMenuForMessage,
9
- buildContextMenuForService,
10
- DEFAULT_NODE_WIDTH,
11
- DEFAULT_NODE_HEIGHT,
12
- } from './utils/utils';
2
+ import { createEdge, createNode, buildContextMenuForMessage, buildContextMenuForService } from './utils/utils';
3
+ import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
13
4
 
14
5
  export interface FieldOccurrence {
15
6
  messageId: string;
@@ -28,15 +19,16 @@ interface Props {
28
19
  fieldType: string;
29
20
  occurrences: FieldOccurrence[];
30
21
  mode?: 'simple' | 'full';
22
+ layout?: boolean;
31
23
  }
32
24
 
33
- export const getNodesAndEdges = ({
25
+ export const getNodesAndEdges = async ({
34
26
  fieldPath,
35
27
  fieldType,
36
28
  occurrences,
37
29
  mode = 'full',
38
- }: Props): { nodes: Node[]; edges: Edge[] } => {
39
- const flow = createDagreGraph({ ranksep: 200, nodesep: 50 });
30
+ layout = true,
31
+ }: Props): Promise<{ nodes: Node[]; edges: Edge[] }> => {
40
32
  const nodes: Node[] = [];
41
33
  const edges: Edge[] = [];
42
34
  const addedNodes = new Set<string>();
@@ -179,14 +171,7 @@ export const getNodesAndEdges = ({
179
171
  }
180
172
  }
181
173
 
182
- // Apply layout
183
- for (const node of nodes) {
184
- flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
185
- }
186
- for (const edge of edges) {
187
- flow.setEdge(edge.source, edge.target);
188
- }
189
- dagre.layout(flow);
174
+ if (!layout) return { nodes, edges };
190
175
 
191
- return { nodes: calculatedNodes(flow, nodes), edges };
176
+ return layoutNodeGraph({ nodes, edges });
192
177
  };
@@ -0,0 +1,119 @@
1
+ import type { CollectionEntry } from 'astro:content';
2
+
3
+ export type Lane = { id: string; name: string };
4
+
5
+ /**
6
+ * The lanes a flow step's resource belongs to, for grouping a flow into
7
+ * swimlanes by domain, system or owning team. Only set for resources that
8
+ * belong somewhere themselves (services, agents, data stores, data products,
9
+ * systems);
10
+ * the visualiser puts other steps (messages, custom steps, sub-flows) in the
11
+ * lane of the step that leads to them. `external` steps (actors and external
12
+ * systems) get a lane of their own.
13
+ */
14
+ export type StepLanes = {
15
+ domain?: Lane;
16
+ system?: Lane;
17
+ team?: Lane;
18
+ external?: boolean;
19
+ };
20
+
21
+ type LaneCollections = {
22
+ domains: CollectionEntry<'domains'>[];
23
+ systems: CollectionEntry<'systems'>[];
24
+ teams: CollectionEntry<'teams'>[];
25
+ users: CollectionEntry<'users'>[];
26
+ };
27
+
28
+ /** A resource a step points at (a service, agent, data store, data product or system) */
29
+ type Resource = { data: { id: string; name?: string; owners?: (string | { id: string })[] } };
30
+
31
+ // Lanes use the latest version of each domain and system (as the collection
32
+ // utils do when they don't ask for every version)
33
+ const isLatest = (entry: { filePath?: string }) => !entry.filePath?.includes('versioned');
34
+ const toLane = (entry: Resource): Lane => ({ id: entry.data.id, name: entry.data.name || entry.data.id });
35
+ const pointerIds = (pointers?: { id: string }[]) => (pointers || []).map((pointer) => pointer.id);
36
+
37
+ /**
38
+ * Indexes which domain, system and team each resource belongs to (by id).
39
+ * A resource listed by a domain directly belongs to that domain, otherwise to
40
+ * the domain of the system it's in. Built once per flow from the collections,
41
+ * rather than asking `getDomainsForService`, `getOwner` and so on for each step,
42
+ * so it follows their rules: latest versions only, and hidden teams and users
43
+ * are left out.
44
+ */
45
+ export const createLaneIndex = ({ domains, systems, teams, users }: LaneCollections) => {
46
+ const systemOf = new Map<string, Lane>();
47
+ const domainOf = new Map<string, Lane>();
48
+
49
+ const latestSystems = systems.filter(isLatest);
50
+ for (const system of latestSystems) {
51
+ for (const id of [...pointerIds(system.data.services), ...pointerIds(system.data.containers)]) {
52
+ if (!systemOf.has(id)) systemOf.set(id, toLane(system));
53
+ }
54
+ }
55
+
56
+ const latestDomains = domains.filter(isLatest);
57
+ // Resources a domain lists directly win over ones it gets through its systems
58
+ for (const domain of latestDomains) {
59
+ const direct = [
60
+ ...pointerIds(domain.data.services),
61
+ ...pointerIds(domain.data.agents),
62
+ ...pointerIds(domain.data['data-products']),
63
+ ...pointerIds(domain.data.systems),
64
+ ];
65
+ for (const id of direct) {
66
+ if (!domainOf.has(id)) domainOf.set(id, toLane(domain));
67
+ }
68
+ }
69
+ for (const system of latestSystems) {
70
+ const domain = domainOf.get(system.data.id);
71
+ if (!domain) continue;
72
+ for (const id of [...pointerIds(system.data.services), ...pointerIds(system.data.containers)]) {
73
+ if (!domainOf.has(id)) domainOf.set(id, domain);
74
+ }
75
+ }
76
+
77
+ const owners = new Map<string, { lane: Lane; isTeam: boolean }>();
78
+ const hiddenOwners = new Set<string>();
79
+ for (const [entries, isTeam] of [
80
+ [users, false],
81
+ [teams, true],
82
+ ] as const) {
83
+ for (const owner of entries) {
84
+ if (owner.data.hidden) hiddenOwners.add(owner.data.id);
85
+ else owners.set(owner.data.id, { lane: toLane(owner), isTeam });
86
+ }
87
+ }
88
+
89
+ // A team owner wins over a user owner
90
+ const teamOf = (resource: Resource): Lane | undefined => {
91
+ const resolved = (resource.data.owners || [])
92
+ .map((owner) => (typeof owner === 'string' ? owner : owner.id))
93
+ .filter((id) => !hiddenOwners.has(id))
94
+ .map((id) => owners.get(id) ?? { lane: { id, name: id }, isTeam: false })
95
+ .sort((a, b) => Number(b.isTeam) - Number(a.isTeam));
96
+ return resolved[0]?.lane;
97
+ };
98
+
99
+ const lanesFor = (resource: Resource): StepLanes | undefined => {
100
+ const id = resource.data.id;
101
+ const team = teamOf(resource);
102
+ const lanes: StepLanes = {
103
+ ...(domainOf.has(id) && { domain: domainOf.get(id) }),
104
+ ...(systemOf.has(id) && { system: systemOf.get(id) }),
105
+ ...(team && { team }),
106
+ };
107
+ return Object.keys(lanes).length > 0 ? lanes : undefined;
108
+ };
109
+
110
+ /** A system is in its own system lane (and the domain that lists it) */
111
+ const lanesForSystem = (system: Resource): StepLanes => ({
112
+ ...lanesFor(system),
113
+ system: toLane(system),
114
+ });
115
+
116
+ return { lanesFor, lanesForSystem };
117
+ };
118
+
119
+ export type LaneIndex = ReturnType<typeof createLaneIndex>;
@@ -1,26 +1,20 @@
1
1
  import { getCollection, type CollectionEntry } from 'astro:content';
2
2
  import {
3
- createDagreGraph,
4
- calculatedNodes,
5
- DEFAULT_NODE_WIDTH,
6
- DEFAULT_NODE_HEIGHT,
7
3
  buildContextMenuForResource,
8
4
  buildContextMenuForService,
9
5
  buildContextMenuForSystem,
10
- layoutDagreGraph,
11
6
  } from '@utils/node-graphs/utils/utils';
7
+ import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
12
8
  import { MarkerType } from '@xyflow/react';
13
9
  import type { Node as NodeType } from '@xyflow/react';
14
10
  import { createVersionedMap, findInMap } from '@utils/collections/util';
15
-
16
- type DagreGraph = any;
11
+ import { createLaneIndex, type LaneIndex } from '@utils/node-graphs/flow-lanes';
17
12
 
18
13
  interface Props {
19
14
  id: string;
20
15
  version: string;
21
- defaultFlow?: DagreGraph;
22
16
  mode?: 'simple' | 'full';
23
- renderAllEdges?: boolean;
17
+ layout?: boolean;
24
18
  }
25
19
 
26
20
  interface Maps {
@@ -31,6 +25,8 @@ interface Maps {
31
25
  containerMap: Map<string, any[]>;
32
26
  dataProductMap: Map<string, any[]>;
33
27
  systemMap: Map<string, any[]>;
28
+ channelMap: Map<string, any[]>;
29
+ laneIndex: LaneIndex;
34
30
  }
35
31
 
36
32
  const getServiceNode = (step: any, serviceMap: Map<string, any[]>) => {
@@ -90,6 +86,15 @@ const getSystemNode = (step: any, systemMap: Map<string, any[]>) => {
90
86
  };
91
87
  };
92
88
 
89
+ const getChannelNode = (step: any, channelMap: Map<string, any[]>) => {
90
+ const channel = findInMap(channelMap, step.channel.id, step.channel.version);
91
+ return {
92
+ ...step,
93
+ type: channel ? 'channels' : 'step',
94
+ channel,
95
+ };
96
+ };
97
+
93
98
  const getMessageNode = (step: any, messageMap: Map<string, any[]>) => {
94
99
  const message = findInMap(messageMap, step.message.id, step.message.version);
95
100
  return {
@@ -99,6 +104,68 @@ const getMessageNode = (step: any, messageMap: Map<string, any[]>) => {
99
104
  };
100
105
  };
101
106
 
107
+ // The whole graph is sent to the browser, so a step's resource is in its node's
108
+ // data once (e.g. `data.service`), without what's only needed to build the
109
+ // catalog (its markdown body, file path, ...), and the step is just the step
110
+ const RESOURCE_KEYS = ['message', 'agent', 'service', 'flow', 'container', 'dataProduct', 'system', 'channel'];
111
+ const resourceForNode = (entry: any) => {
112
+ // Only what the nodes read: its id, collection and frontmatter (nested, as
113
+ // e.g. the sub-flow node reads `flow.data`, and spread on top)
114
+ const { id, collection, data } = entry;
115
+ return { id, collection, data, ...data };
116
+ };
117
+ const stepForNode = (step: any) => {
118
+ const own = { ...step, ...step.data };
119
+ RESOURCE_KEYS.forEach((key) => delete own[key]);
120
+ return { ...own, title: titleOf(step) };
121
+ };
122
+
123
+ // A step without a title is named after what it points at (or its id). A
124
+ // custom step is labelled with its own title first, as its node is.
125
+ const titleOf = (step: any): string => {
126
+ if (step.custom?.title) return step.custom.title;
127
+ if (step.title) return step.title;
128
+ const resource = RESOURCE_KEYS.map((key) => step[key]).find((entry) => entry?.data);
129
+ return resource?.data.name || resource?.data.id || step.actor?.name || step.externalSystem?.name || String(step.id);
130
+ };
131
+
132
+ // Mistakes in a flow (a typo in a next step, a resource that was renamed)
133
+ // would otherwise just drop an arrow or draw a plain box, so they're logged,
134
+ // once each (a flow is drawn on several pages). Once per process on purpose:
135
+ // in `astro dev` a problem that's fixed and then made again isn't logged again
136
+ // until the server restarts, which is fine for a warning.
137
+ const warned = new Set<string>();
138
+ const warnOnce = (flow: any, problem: string) => {
139
+ const message = `[flows] Flow "${flow.data.id}" (${flow.data.version}): ${problem}`;
140
+ if (warned.has(message)) return;
141
+ warned.add(message);
142
+ console.warn(message);
143
+ };
144
+
145
+ // The keys a step points at a resource with, as authors write them
146
+ const POINTER_KEYS: Record<string, string> = {
147
+ message: 'message',
148
+ agent: 'agent',
149
+ service: 'service',
150
+ systems: 'system',
151
+ system: 'system',
152
+ channel: 'channel',
153
+ flow: 'flow',
154
+ container: 'container',
155
+ dataProduct: 'data product',
156
+ };
157
+ const warnAboutMissingResource = (flow: any, step: any, hydrated: any) => {
158
+ for (const [key, kind] of Object.entries(POINTER_KEYS)) {
159
+ const pointer = step[key];
160
+ const resourceKey = key === 'systems' ? 'system' : key;
161
+ if (!pointer || hydrated[resourceKey]) continue;
162
+ warnOnce(
163
+ flow,
164
+ `step "${step.id}" points at ${kind} "${pointer.id}" (${pointer.version ?? 'latest'}), which is not in the catalog, so it is shown as a plain step.`
165
+ );
166
+ }
167
+ };
168
+
102
169
  // Rewrite every id/source/target in a precomputed sub-flow graph with a
103
170
  // namespace prefix so inlined copies don't collide with the parent. Nested
104
171
  // `data.expandedNodes` / `data.expandedEdges` payloads are rewritten too so
@@ -145,6 +212,7 @@ const buildFlowGraphInternal = (
145
212
  if (step.flow) return getFlowNode(step, maps.flowMap);
146
213
  if (step.container) return getContainerNode(step, maps.containerMap);
147
214
  if (step.dataProduct) return getDataProductNode(step, maps.dataProductMap);
215
+ if (step.channel) return getChannelNode(step, maps.channelMap);
148
216
  if (step.message) return getMessageNode(step, maps.messageMap);
149
217
  if (step.actor) return { ...step, type: 'actor', actor: step.actor };
150
218
  if (step.custom) return { ...step, type: 'custom', custom: step.custom };
@@ -152,23 +220,26 @@ const buildFlowGraphInternal = (
152
220
  return { ...step, type: 'step' };
153
221
  });
154
222
 
155
- hydratedSteps.forEach((step: any, index: number) => {
223
+ steps.forEach((step: any, index: number) => warnAboutMissingResource(flow, step, hydratedSteps[index]));
224
+ const stepIds = new Set(steps.map((step: any) => String(step.id)));
225
+
226
+ hydratedSteps.forEach((step: any) => {
156
227
  const node: NodeType = {
157
228
  id: stepNodeId(step.id),
158
229
  sourcePosition: 'right',
159
230
  targetPosition: 'left',
160
231
  data: {
161
232
  mode,
162
- step: { ...step, ...step.data },
233
+ step: stepForNode(step),
163
234
  showTarget: true,
164
235
  showSource: true,
165
236
  },
166
- position: { x: 250, y: index * 150 },
237
+ position: { x: 0, y: 0 },
167
238
  type: step.type,
168
239
  } as NodeType;
169
240
 
170
241
  if (step.agent) {
171
- node.data.agent = { ...step.agent, ...step.agent.data };
242
+ node.data.agent = resourceForNode(step.agent);
172
243
  node.data.contextMenu = buildContextMenuForResource({
173
244
  collection: 'agents',
174
245
  id: step.agent.data.id,
@@ -176,7 +247,7 @@ const buildFlowGraphInternal = (
176
247
  });
177
248
  }
178
249
  if (step.service) {
179
- node.data.service = { ...step.service, ...step.service.data };
250
+ node.data.service = resourceForNode(step.service);
180
251
  node.data.contextMenu = buildContextMenuForService({
181
252
  id: step.service.data.id,
182
253
  version: step.service.data.version,
@@ -185,14 +256,14 @@ const buildFlowGraphInternal = (
185
256
  });
186
257
  }
187
258
  if (step.system?.data) {
188
- node.data.system = { ...step.system.data };
259
+ node.data.system = resourceForNode(step.system);
189
260
  node.data.contextMenu = buildContextMenuForSystem({
190
261
  id: step.system.data.id,
191
262
  version: step.system.data.version,
192
263
  });
193
264
  }
194
265
  if (step.flow) {
195
- node.data.flow = { ...step.flow, ...step.flow.data };
266
+ node.data.flow = resourceForNode(step.flow);
196
267
  node.data.contextMenu = buildContextMenuForResource({
197
268
  collection: 'flows',
198
269
  id: step.flow.data.id,
@@ -215,7 +286,7 @@ const buildFlowGraphInternal = (
215
286
  }
216
287
  }
217
288
  if (step.message) {
218
- node.data.message = { ...step.message, ...step.message.data };
289
+ node.data.message = resourceForNode(step.message);
219
290
  node.data.contextMenu = buildContextMenuForResource({
220
291
  collection: step.message.collection,
221
292
  id: step.message.data.id,
@@ -224,15 +295,23 @@ const buildFlowGraphInternal = (
224
295
  }
225
296
  if (step.container?.data) {
226
297
  node.data.data = { ...step.container.data };
227
- node.data.container = { ...step.container, ...step.container.data };
298
+ node.data.container = resourceForNode(step.container);
228
299
  node.data.contextMenu = buildContextMenuForResource({
229
300
  collection: 'containers',
230
301
  id: step.container.data.id,
231
302
  version: step.container.data.version,
232
303
  });
233
304
  }
305
+ if (step.channel?.data) {
306
+ node.data.channel = resourceForNode(step.channel);
307
+ node.data.contextMenu = buildContextMenuForResource({
308
+ collection: 'channels',
309
+ id: step.channel.data.id,
310
+ version: step.channel.data.version,
311
+ });
312
+ }
234
313
  if (step.dataProduct?.data) {
235
- node.data.dataProduct = { ...step.dataProduct, ...step.dataProduct.data };
314
+ node.data.dataProduct = resourceForNode(step.dataProduct);
236
315
  node.data.contextMenu = buildContextMenuForResource({
237
316
  collection: 'data-products',
238
317
  id: step.dataProduct.data.id,
@@ -245,6 +324,17 @@ const buildFlowGraphInternal = (
245
324
  }
246
325
  if (step.externalSystem) node.data.externalSystem = { ...step.externalSystem, ...step.externalSystem.data };
247
326
  if (step.custom) node.data.custom = { ...step.custom, ...step.custom.data };
327
+
328
+ // Which domain, system and team the step belongs to, for swimlanes
329
+ const resource = step.agent || step.service || step.container || step.dataProduct;
330
+ const lanes =
331
+ step.actor || step.externalSystem
332
+ ? { external: true }
333
+ : step.system?.data
334
+ ? maps.laneIndex.lanesForSystem(step.system)
335
+ : resource && maps.laneIndex.lanesFor(resource);
336
+ if (lanes) node.data.lanes = lanes;
337
+
248
338
  nodes.push(node);
249
339
  });
250
340
 
@@ -267,6 +357,10 @@ const buildFlowGraphInternal = (
267
357
  });
268
358
 
269
359
  paths.forEach((path: any) => {
360
+ if (!stepIds.has(String(path.id))) {
361
+ warnOnce(flow, `step "${step.id}" leads to step "${path.id}", but the flow has no step with that id.`);
362
+ return;
363
+ }
270
364
  edges.push({
271
365
  id: `step-${step.id}-step-${path.id}`,
272
366
  source: stepNodeId(step.id),
@@ -291,20 +385,23 @@ const buildFlowGraphInternal = (
291
385
  return { nodes, edges };
292
386
  };
293
387
 
294
- export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simple', renderAllEdges = false }: Props) => {
295
- const graph = defaultFlow || createDagreGraph({ ranksep: 360, nodesep: 200 });
296
-
297
- const [flows, events, commands, queries, agents, services, containers, dataProducts, systems] = await Promise.all([
298
- getCollection('flows'),
299
- getCollection('events'),
300
- getCollection('commands'),
301
- getCollection('queries'),
302
- getCollection('agents'),
303
- getCollection('services'),
304
- getCollection('containers'),
305
- getCollection('data-products'),
306
- getCollection('systems'),
307
- ]);
388
+ export const getNodesAndEdges = async ({ id, version, mode = 'simple', layout = true }: Props) => {
389
+ const [flows, events, commands, queries, agents, services, containers, dataProducts, domains, systems, channels, teams, users] =
390
+ await Promise.all([
391
+ getCollection('flows'),
392
+ getCollection('events'),
393
+ getCollection('commands'),
394
+ getCollection('queries'),
395
+ getCollection('agents'),
396
+ getCollection('services'),
397
+ getCollection('containers'),
398
+ getCollection('data-products'),
399
+ getCollection('domains'),
400
+ getCollection('systems'),
401
+ getCollection('channels'),
402
+ getCollection('teams'),
403
+ getCollection('users'),
404
+ ]);
308
405
 
309
406
  const flow = flows.find((flow) => flow.data.id === id && flow.data.version === version);
310
407
 
@@ -324,6 +421,8 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
324
421
  containerMap: createVersionedMap(containers),
325
422
  dataProductMap: createVersionedMap(dataProducts),
326
423
  systemMap: createVersionedMap(systems),
424
+ channelMap: createVersionedMap(channels),
425
+ laneIndex: createLaneIndex({ domains, systems, teams, users }),
327
426
  };
328
427
 
329
428
  const subFlowCache = new Map<string, { nodes: any[]; edges: any[] }>();
@@ -335,18 +434,5 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
335
434
  new Set([`${flow.data.id}@${flow.data.version}`])
336
435
  );
337
436
 
338
- nodes.forEach((node: any) => {
339
- graph.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
340
- });
341
-
342
- edges.forEach((edge: any) => {
343
- graph.setEdge(edge.source, edge.target);
344
- });
345
-
346
- layoutDagreGraph(graph);
347
-
348
- return {
349
- nodes: calculatedNodes(graph, nodes),
350
- edges: edges,
351
- };
437
+ return layout ? await layoutNodeGraph({ nodes, edges }) : { nodes, edges };
352
438
  };