@eventcatalog/core 5.0.0-beta.9 → 5.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 (460) hide show
  1. package/LICENSE +13 -12
  2. package/README.md +5 -5
  3. package/dist/analytics/analytics.cjs +1 -1
  4. package/dist/analytics/analytics.js +2 -2
  5. package/dist/analytics/log-build.cjs +91 -44
  6. package/dist/analytics/log-build.d.cts +2 -2
  7. package/dist/analytics/log-build.d.ts +2 -2
  8. package/dist/analytics/log-build.js +6 -5
  9. package/dist/analytics/studio-usage.cjs +90 -0
  10. package/dist/analytics/studio-usage.d.cts +5 -0
  11. package/dist/analytics/studio-usage.d.ts +5 -0
  12. package/dist/analytics/studio-usage.js +10 -0
  13. package/dist/catalog-runtime.cjs +1 -1
  14. package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
  15. package/dist/{chunk-AWOO63ME.js → chunk-AD7CL772.js} +11 -4
  16. package/dist/chunk-CA6WCQ2T.js +54 -0
  17. package/dist/{chunk-GAHKCOQM.js → chunk-JZN4RSMF.js} +1 -1
  18. package/dist/{chunk-JQMYHZWI.js → chunk-NEAVAFSJ.js} +16 -8
  19. package/dist/{chunk-4CFZUHGG.js → chunk-NIVST4WY.js} +1 -1
  20. package/dist/{chunk-ENAG6UH7.js → chunk-NKNOXQ62.js} +1 -6
  21. package/dist/{chunk-ZEY2XUJN.js → chunk-OX6TSVHY.js} +6 -6
  22. package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
  23. package/dist/{chunk-EUNQJO3J.js → chunk-RE7UTPWH.js} +1 -1
  24. package/dist/chunk-S5GWAUG5.js +29 -0
  25. package/dist/{chunk-TZVDMWQX.js → chunk-YQGRMDRB.js} +4 -2
  26. package/dist/constants.cjs +1 -1
  27. package/dist/constants.js +1 -1
  28. package/dist/docs/api/02-config.md +57 -7
  29. package/dist/docs/development/00-why-eventcatalog.md +11 -11
  30. package/dist/docs/development/01-fundamentals.md +20 -13
  31. package/dist/docs/development/01-getting-started/configuration-overview.md +2 -2
  32. package/dist/docs/development/01-getting-started/installation.md +9 -1
  33. package/dist/docs/development/_getting-started.mdx +1 -1
  34. package/dist/docs/development/ask-your-architecture/01-intro.md +5 -5
  35. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/01-what-is-eventcatalog-assistant.md +0 -4
  36. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +15 -3
  37. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/03-bring-your-own-tools.md +0 -3
  38. package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/_category_.json +1 -1
  39. package/dist/docs/development/ask-your-architecture/02-llms.txt.md +1 -1
  40. package/dist/docs/development/ask-your-architecture/{05-skills/01-introduction.md → 03-install-skills.md} +57 -7
  41. package/dist/docs/development/ask-your-architecture/03-mcp-server/_category_.json +1 -1
  42. package/dist/docs/development/ask-your-architecture/03-mcp-server/getting-started.md +86 -33
  43. package/dist/docs/development/ask-your-architecture/03-mcp-server/introduction.md +14 -4
  44. package/dist/docs/development/ask-your-architecture/03-schemas.txt.md +1 -1
  45. package/dist/docs/development/ask-your-architecture/04-agents/_category_.json +1 -1
  46. package/dist/docs/development/authentication/01-introduction.md +2 -23
  47. package/dist/docs/development/authentication/02-enabling-authentication.md +0 -20
  48. package/dist/docs/development/authentication/07-rbac-middleware.md +0 -2
  49. package/dist/docs/development/authentication/providers/03-setting-up-github.md +0 -2
  50. package/dist/docs/development/authentication/providers/03a-setting-up-google.md +0 -2
  51. package/dist/docs/development/authentication/providers/04-setting-up-azure-ad.md +0 -2
  52. package/dist/docs/development/authentication/providers/05-setting-up-okta.md +0 -3
  53. package/dist/docs/development/authentication/providers/06-setting-up-auth0.md +0 -2
  54. package/dist/docs/development/bring-your-own-documentation/01-introduction.md +0 -4
  55. package/dist/docs/development/bring-your-own-documentation/custom-pages/01-introduction.md +0 -3
  56. package/dist/docs/development/bring-your-own-documentation/custom-pages/02-adding-custom-docs.md +0 -17
  57. package/dist/docs/development/bring-your-own-documentation/custom-pages/03-components.md +0 -4
  58. package/dist/docs/development/bring-your-own-documentation/custom-pages/04-owners.md +0 -2
  59. package/dist/docs/development/bring-your-own-documentation/resource-docs/01-introduction.md +1 -3
  60. package/dist/docs/development/bring-your-own-documentation/resource-docs/02-adding-resource-docs.md +1 -4
  61. package/dist/docs/development/bring-your-own-documentation/resource-docs/03-categories.md +0 -2
  62. package/dist/docs/development/bring-your-own-documentation/resource-docs/04-versioning.md +1 -3
  63. package/dist/docs/development/components/components/11-flow.md +17 -0
  64. package/dist/docs/development/components/components/15-nodegraph.md +43 -10
  65. package/dist/docs/development/components/components/18-remote-schema.md +1 -4
  66. package/dist/docs/development/components/custom-components/07-reference.md +14 -0
  67. package/dist/docs/development/customization/02-themes.md +0 -5
  68. package/dist/docs/development/customization/03-search.md +1 -1
  69. package/dist/docs/development/customization/05-custom-pages-and-api-routes/01-introduction.md +0 -2
  70. package/dist/docs/development/customization/05-custom-pages-and-api-routes/04-reference.md +7 -1
  71. package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
  72. package/dist/docs/development/customization/09-embed-eventcatalog.md +20 -25
  73. package/dist/docs/development/deployment/hosting-options.md +7 -2
  74. package/dist/docs/development/developer-tools/eventcatalog-linter/how-to/05-fix-common-problems.md +16 -0
  75. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/03-rules.md +31 -1
  76. package/dist/docs/development/developer-tools/eventcatalog-linter/reference/05-supported-resources.md +1 -1
  77. package/dist/docs/development/governance/architecture-change-detection/01-introduction.md +0 -10
  78. package/dist/docs/development/governance/architecture-change-detection/06-pipeline-gates.md +0 -4
  79. package/dist/docs/development/guides/97-architecture-graph.md +1 -1
  80. package/dist/docs/development/guides/99-adding-analytics.md +0 -7
  81. package/dist/docs/development/guides/domains/03-model-subdomains.md +2 -2
  82. package/dist/docs/development/guides/domains/04-add-resources-to-domains/01-add-systems-to-domains.md +3 -1
  83. package/dist/docs/development/guides/domains/04-add-resources-to-domains/02-add-services-to-domains.md +5 -1
  84. package/dist/docs/development/guides/domains/04-add-resources-to-domains/03-add-messages-to-domains.md +2 -2
  85. package/dist/docs/development/guides/domains/04-add-resources-to-domains/05-add-entities-to-domains.md +1 -1
  86. package/dist/docs/development/guides/domains/04-add-resources-to-domains/06-domain-resources-page.md +40 -0
  87. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-diagram.md +89 -0
  88. package/dist/docs/development/guides/domains/06-visualize-domains/_category_.json +1 -2
  89. package/dist/docs/development/guides/domains/09-reference.md +4 -4
  90. package/dist/docs/development/guides/owners/automated-teams-and-users/create-your-own-connector.md +0 -2
  91. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-github.md +0 -3
  92. package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-microsoft-entra.md +0 -2
  93. package/dist/docs/development/guides/resources/adrs/03-linking-resources.md +8 -0
  94. package/dist/docs/development/guides/resources/adrs/06-reference.md +4 -4
  95. package/dist/docs/development/guides/resources/agents/11-reference.md +1 -1
  96. package/dist/docs/development/guides/resources/data/04-reference.md +1 -1
  97. package/dist/docs/development/guides/resources/data-products/07-reference.md +1 -1
  98. package/dist/docs/development/guides/resources/entities/05-entity-maps.md +1 -1
  99. package/dist/docs/development/guides/resources/entities/06-reference.md +2 -2
  100. package/dist/docs/development/guides/resources/flows/01-introduction.md +11 -1
  101. package/dist/docs/development/guides/resources/flows/03-model-flow-steps.md +65 -6
  102. package/dist/docs/development/guides/resources/flows/05-explore-flows.md +112 -0
  103. package/dist/docs/development/guides/resources/flows/06-reference.md +25 -4
  104. package/dist/docs/development/guides/resources/messages/01-what-are-messages.md +19 -0
  105. package/dist/docs/development/guides/resources/messages/04-message-channels/01-introduction.md +16 -0
  106. package/dist/docs/development/guides/resources/messages/04-message-channels/05-reference.md +2 -1
  107. package/dist/docs/development/guides/resources/messages/10-reference.md +6 -3
  108. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/01-schema-explorer.md +2 -2
  109. package/dist/docs/development/guides/resources/schemas/04-explore-schemas/02-fields-explorer.md +0 -9
  110. package/dist/docs/development/guides/resources/schemas/05-schema-api.md +0 -3
  111. package/dist/docs/development/guides/resources/schemas/06-schema-mcp.md +11 -3
  112. package/dist/docs/development/guides/resources/services/04-add-resources-to-services/03-add-entities-to-services.md +1 -1
  113. package/dist/docs/development/guides/resources/services/05-resources-page.md +50 -0
  114. package/dist/docs/development/guides/resources/services/08-reference.md +2 -1
  115. package/dist/docs/development/guides/systems/01-introduction.md +1 -1
  116. package/dist/docs/development/guides/systems/02-create-system.md +2 -2
  117. package/dist/docs/development/guides/systems/03-add-resources-to-systems.md +35 -9
  118. package/dist/docs/development/guides/systems/04-model-relationships-and-actors.md +5 -3
  119. package/dist/docs/development/guides/systems/05-system-context-maps.md +39 -22
  120. package/dist/docs/development/guides/systems/06-reference.md +4 -4
  121. package/dist/docs/development/license/01-license-file.md +151 -0
  122. package/dist/docs/development/license/_category_.json +12 -0
  123. package/dist/docs/development/license-keys/_category_.json +3 -3
  124. package/dist/docs/development/license-keys/integrations.md +7 -37
  125. package/dist/docs/development/license-keys/license-validation.md +4 -0
  126. package/dist/docs/development/license-keys/overview.md +5 -1
  127. package/dist/docs/development/license-keys/plans.md +4 -2
  128. package/dist/docs/development/studio/01-introduction.md +60 -0
  129. package/dist/docs/development/studio/02-create-a-canvas.md +103 -0
  130. package/dist/docs/development/studio/03-set-up-persistent-storage.md +59 -0
  131. package/dist/docs/development/studio/04-collaborate-on-a-canvas.md +78 -0
  132. package/dist/docs/development/studio/05-connect-your-agent.md +102 -0
  133. package/dist/docs/development/studio/06-run-studio-in-production.md +54 -0
  134. package/dist/docs/development/studio/07-reference.md +294 -0
  135. package/dist/docs/development/studio/_category_.json +12 -0
  136. package/dist/docs/development/upgrading/v5.md +345 -0
  137. package/dist/docs/federation/00-overview.md +2 -8
  138. package/dist/docs/federation/01-first-federation.md +6 -18
  139. package/dist/docs/federation/explanation/how-it-works.md +0 -4
  140. package/dist/docs/federation/explanation/lockfile-and-cache.md +0 -4
  141. package/dist/docs/federation/explanation/mvp-status-and-feedback.md +0 -4
  142. package/dist/docs/federation/explanation/ownership-and-references.md +0 -4
  143. package/dist/docs/federation/how-to/configure-github-sources.md +6 -5
  144. package/dist/docs/federation/how-to/configure-validation-rules.md +0 -4
  145. package/dist/docs/federation/how-to/run-in-ci.md +2 -9
  146. package/dist/docs/federation/how-to/share-assets-and-components.md +0 -4
  147. package/dist/docs/federation/how-to/use-local-sources.md +0 -4
  148. package/dist/docs/federation/legacy-federation/00-introduction.md +4 -22
  149. package/dist/docs/federation/legacy-federation/01-installation.md +7 -58
  150. package/dist/docs/federation/legacy-federation/02-plugin-configuration.md +3 -21
  151. package/dist/docs/federation/legacy-federation/03-examples.md +3 -5
  152. package/dist/docs/federation/legacy-federation/04-configuration.md +3 -8
  153. package/dist/docs/federation/legacy-federation/05-setup-team-catalog.md +3 -6
  154. package/dist/docs/federation/reference/cli.md +2 -8
  155. package/dist/docs/federation/reference/configuration.md +0 -4
  156. package/dist/docs/federation/reference/diagnostic-rules.md +0 -5
  157. package/dist/docs/federation/reference/generated-output.md +0 -4
  158. package/dist/docs/federation/reference/supported-content.md +0 -4
  159. package/dist/docs/federation/reference/troubleshooting.md +0 -14
  160. package/dist/docs/plugins/02-generators.md +1 -1
  161. package/dist/docs/plugins/amazon-apigateway/00-intro.md +3 -28
  162. package/dist/docs/plugins/amazon-apigateway/01-installation.md +4 -56
  163. package/dist/docs/plugins/amazon-apigateway/02-plugin-configuration.md +1 -6
  164. package/dist/docs/plugins/apicurio/00-intro.md +2 -31
  165. package/dist/docs/plugins/apicurio/01-installation.md +2 -26
  166. package/dist/docs/plugins/apicurio/02-plugin-configuration.md +5 -13
  167. package/dist/docs/plugins/apicurio/03-features.md +1 -3
  168. package/dist/docs/plugins/asyncapi/00-intro.md +2 -28
  169. package/dist/docs/plugins/asyncapi/01-installation.md +3 -54
  170. package/dist/docs/plugins/asyncapi/02-plugin-configuration.md +2 -1
  171. package/dist/docs/plugins/aws-glue-registry/00-intro.md +4 -32
  172. package/dist/docs/plugins/aws-glue-registry/00a-installation.md +3 -53
  173. package/dist/docs/plugins/azure-schema-registry/00-intro.md +4 -32
  174. package/dist/docs/plugins/azure-schema-registry/01-installation.md +6 -33
  175. package/dist/docs/plugins/azure-schema-registry/02-plugin-configuration.md +1 -14
  176. package/dist/docs/plugins/azure-schema-registry/04-examples.md +0 -2
  177. package/dist/docs/plugins/backstage/00-overview.md +1 -7
  178. package/dist/docs/plugins/backstage/01-get-started.md +6 -15
  179. package/dist/docs/plugins/backstage/06-configuration.md +2 -8
  180. package/dist/docs/plugins/confluent-schema-registry/00-intro.md +2 -29
  181. package/dist/docs/plugins/confluent-schema-registry/01-installation.md +2 -26
  182. package/dist/docs/plugins/eventbridge/00-intro.md +0 -4
  183. package/dist/docs/plugins/eventbridge/00a-installation.md +1 -87
  184. package/dist/docs/plugins/eventbridge/03-api.md +2 -20
  185. package/dist/docs/plugins/github/00-intro.md +0 -31
  186. package/dist/docs/plugins/github/01-installation.md +2 -34
  187. package/dist/docs/plugins/graphql/00-intro.md +0 -30
  188. package/dist/docs/plugins/graphql/01-installation.md +1 -53
  189. package/dist/docs/plugins/graphql/02-plugin-configuration.md +0 -1
  190. package/dist/docs/plugins/hookdeck/01-intro.md +1 -1
  191. package/dist/docs/plugins/openapi/00-intro.md +0 -30
  192. package/dist/docs/plugins/openapi/01-installation.md +1 -57
  193. package/dist/docs/plugins/openapi/02-plugin-configuration.md +0 -5
  194. package/dist/docs/plugins/openapi/03-features.md +0 -4
  195. package/dist/eventcatalog-config-file-utils.cjs +34 -41
  196. package/dist/eventcatalog-config-file-utils.d.cts +56 -58
  197. package/dist/eventcatalog-config-file-utils.d.ts +56 -58
  198. package/dist/eventcatalog-config-file-utils.js +1 -1
  199. package/dist/eventcatalog.cjs +340 -249
  200. package/dist/eventcatalog.config.d.cts +18 -15
  201. package/dist/eventcatalog.config.d.ts +18 -15
  202. package/dist/eventcatalog.js +51 -33
  203. package/dist/features.cjs +36 -49
  204. package/dist/features.d.cts +1 -3
  205. package/dist/features.d.ts +1 -3
  206. package/dist/features.js +4 -6
  207. package/dist/federation/federate.cjs +37 -44
  208. package/dist/federation/federate.js +5 -5
  209. package/dist/federation/source-provider.js +2 -2
  210. package/dist/generate.cjs +37 -42
  211. package/dist/generate.js +4 -4
  212. package/dist/resolve-catalog-dependencies.cjs +34 -41
  213. package/dist/resolve-catalog-dependencies.js +2 -2
  214. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  215. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  216. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  217. package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
  218. package/dist/runtime-dependencies/manifest.json +5 -1
  219. package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
  220. package/dist/utils/child-process-signals.cjs +53 -0
  221. package/dist/utils/child-process-signals.d.cts +19 -0
  222. package/dist/utils/child-process-signals.d.ts +19 -0
  223. package/dist/utils/child-process-signals.js +6 -0
  224. package/dist/utils/cli-logger.cjs +1 -1
  225. package/dist/utils/cli-logger.js +2 -2
  226. package/dist/utils/license-status.cjs +11 -4
  227. package/dist/utils/license-status.d.cts +3 -2
  228. package/dist/utils/license-status.d.ts +3 -2
  229. package/dist/utils/license-status.js +1 -1
  230. package/eventcatalog/astro.config.mjs +21 -1
  231. package/eventcatalog/integrations/config-loader.mjs +56 -58
  232. package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
  233. package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
  234. package/eventcatalog/integrations/storage.mjs +20 -0
  235. package/eventcatalog/integrations/studio-server.mjs +4 -1
  236. package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
  237. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
  238. package/eventcatalog/src/components/Homepage/CatalogDashboard.astro +342 -0
  239. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +60 -4
  240. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
  241. package/eventcatalog/src/components/NavigationProgress.astro +7 -0
  242. package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
  243. package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
  244. package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
  245. package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
  246. package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
  247. package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
  248. package/eventcatalog/src/components/Search/search-utils.ts +26 -0
  249. package/eventcatalog/src/components/Seo.astro +5 -1
  250. package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +53 -48
  251. package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +183 -178
  252. package/eventcatalog/src/components/Settings/LicenseSettings.tsx +140 -31
  253. package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +40 -35
  254. package/eventcatalog/src/components/Settings/LogoUpload.tsx +1 -1
  255. package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +9 -8
  256. package/eventcatalog/src/components/Settings/Row.tsx +7 -4
  257. package/eventcatalog/src/components/Settings/SettingsShared.tsx +3 -3
  258. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +37 -76
  259. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
  260. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +122 -1
  261. package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
  262. package/eventcatalog/src/components/TrialBadge.astro +20 -9
  263. package/eventcatalog/src/content.config.ts +19 -2
  264. package/eventcatalog/src/features/auth/error.astro +4 -2
  265. package/eventcatalog/src/features/auth/login.astro +2 -1
  266. package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +21 -1
  267. package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
  268. package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
  269. package/eventcatalog/src/features/integrations/eventcatalog-features.ts +13 -7
  270. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
  271. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
  272. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
  273. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
  274. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +123 -98
  275. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +118 -101
  276. package/eventcatalog/src/features/mcp/mcp-server.ts +20 -4
  277. package/eventcatalog/src/features/server/start.ts +25 -0
  278. package/eventcatalog/src/features/storage/database.ts +88 -0
  279. package/eventcatalog/src/features/storage/migrations.ts +85 -0
  280. package/eventcatalog/src/features/storage/sql/database.sql +5 -0
  281. package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
  282. package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
  283. package/eventcatalog/src/features/storage/sql.ts +28 -0
  284. package/eventcatalog/src/features/studio/agent-choreography.ts +13 -10
  285. package/eventcatalog/src/features/studio/agents.ts +28 -0
  286. package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
  287. package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
  288. package/eventcatalog/src/features/studio/api/client.ts +40 -0
  289. package/eventcatalog/src/features/studio/canvas-actions.ts +160 -34
  290. package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
  291. package/eventcatalog/src/features/studio/catalog.ts +16 -14
  292. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +274 -105
  293. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +15 -14
  294. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
  295. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
  296. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
  297. package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
  298. package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
  299. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +122 -230
  300. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  301. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
  302. package/eventcatalog/src/features/studio/components/Presence.tsx +52 -45
  303. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
  304. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  305. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1314 -385
  306. package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
  307. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  308. package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
  309. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
  310. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
  311. package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
  312. package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +8 -3
  313. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +244 -32
  314. package/eventcatalog/src/features/studio/identity.ts +25 -1
  315. package/eventcatalog/src/features/studio/limits.ts +2 -0
  316. package/eventcatalog/src/features/studio/pages/[id].astro +42 -16
  317. package/eventcatalog/src/features/studio/pages/index.astro +596 -373
  318. package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +12 -15
  319. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +8 -23
  320. package/eventcatalog/src/features/studio/server/runtime.ts +150 -46
  321. package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
  322. package/eventcatalog/src/features/studio/server/storage.ts +53 -73
  323. package/eventcatalog/src/features/studio/webmcp-relay/LICENSE +21 -0
  324. package/eventcatalog/src/features/studio/webmcp-relay/README.md +5 -0
  325. package/eventcatalog/src/features/studio/webmcp-relay/embed.js +2 -0
  326. package/eventcatalog/src/features/studio/webmcp-relay/widget.html +10 -0
  327. package/eventcatalog/src/features/studio/webmcp-relay/widget.js +1 -0
  328. package/eventcatalog/src/features/tools/catalog-tools.ts +3 -1
  329. package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
  330. package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
  331. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +3 -2
  332. package/eventcatalog/src/pages/_index.astro +5 -342
  333. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +2 -3
  334. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +0 -7
  335. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -1
  336. package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +0 -7
  337. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +1 -0
  338. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +1 -0
  339. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +5 -7
  340. package/eventcatalog/src/pages/directory/[type]/index.astro +3 -1
  341. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -7
  342. package/eventcatalog/src/pages/discover/[type]/index.astro +3 -1
  343. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +0 -7
  344. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -0
  345. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +0 -7
  346. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -0
  347. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +0 -7
  348. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +3 -1
  349. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +0 -7
  350. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +0 -7
  351. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -0
  352. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +1 -0
  353. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/_[...filename].data.ts +0 -4
  354. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +0 -7
  355. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/index.astro +1 -0
  356. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +3 -1
  357. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/_[filename].data.ts +0 -7
  358. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
  359. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +2 -3
  360. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +0 -7
  361. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +1 -0
  362. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +1 -0
  363. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +0 -7
  364. package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +0 -7
  365. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +2 -1
  366. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/_index.data.ts +0 -7
  367. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -0
  368. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +0 -7
  369. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +1 -0
  370. package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +0 -7
  371. package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +1 -0
  372. package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +1 -1
  373. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +1 -0
  374. package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +1 -1
  375. package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +1 -1
  376. package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +1 -1
  377. package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +1 -1
  378. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +0 -7
  379. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -0
  380. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +0 -7
  381. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -0
  382. package/eventcatalog/src/pages/index.astro +4 -2
  383. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +0 -7
  384. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +9 -1
  385. package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +0 -7
  386. package/eventcatalog/src/pages/schemas/explorer/index.astro +4 -2
  387. package/eventcatalog/src/pages/settings/license.astro +9 -1
  388. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/_index.data.ts +0 -7
  389. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +1 -0
  390. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +0 -7
  391. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +0 -7
  392. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +1 -0
  393. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/_index.data.ts +0 -7
  394. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -0
  395. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -0
  396. package/eventcatalog/src/pages/visualiser/[type]/[id]/_index.data.ts +38 -0
  397. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +18 -41
  398. package/eventcatalog/src/pages/visualiser/designs/[id]/_index.data.ts +0 -7
  399. package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -1
  400. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +0 -7
  401. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -0
  402. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +1 -0
  403. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +0 -7
  404. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +1 -0
  405. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +0 -7
  406. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +1 -0
  407. package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +1 -0
  408. package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
  409. package/eventcatalog/src/utils/collections/flows.ts +20 -7
  410. package/eventcatalog/src/utils/collections/resource-owners.ts +8 -2
  411. package/eventcatalog/src/utils/collections/resources.ts +2 -0
  412. package/eventcatalog/src/utils/collections/util.ts +8 -4
  413. package/eventcatalog/src/utils/git.ts +11 -0
  414. package/eventcatalog/src/utils/homepage-dashboard.ts +143 -0
  415. package/eventcatalog/src/utils/license.ts +1 -1
  416. package/eventcatalog/src/utils/link-validation.ts +25 -19
  417. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
  418. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
  419. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +4 -2
  420. package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
  421. package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
  422. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
  423. package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +4 -15
  424. package/eventcatalog/src/utils/page-title.ts +15 -0
  425. package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
  426. package/eventcatalog/src/utils/trial.ts +13 -0
  427. package/package.json +11 -11
  428. package/dist/docs/development/ask-your-architecture/05-skills/02-installation.md +0 -60
  429. package/dist/docs/development/ask-your-architecture/05-skills/_category_.json +0 -11
  430. package/dist/docs/development/ask-your-architecture/06-slack-integration/01-introduction.md +0 -63
  431. package/dist/docs/development/ask-your-architecture/06-slack-integration/02-slack-app-setup.md +0 -154
  432. package/dist/docs/development/ask-your-architecture/06-slack-integration/03-installation.md +0 -169
  433. package/dist/docs/development/ask-your-architecture/06-slack-integration/04-deployment.md +0 -236
  434. package/dist/docs/development/ask-your-architecture/06-slack-integration/05-usage.md +0 -140
  435. package/dist/docs/development/ask-your-architecture/06-slack-integration/06-troubleshooting.md +0 -268
  436. package/dist/docs/development/ask-your-architecture/06-slack-integration/_category_.json +0 -13
  437. package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-integration-map.md +0 -40
  438. package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +0 -3
  439. package/eventcatalog/src/features/studio/canvas-doc.ts +0 -409
  440. package/eventcatalog/src/features/studio/clipboard.ts +0 -97
  441. package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -154
  442. package/eventcatalog/src/features/studio/components/Comments.tsx +0 -770
  443. package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
  444. package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
  445. package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
  446. package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
  447. package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -255
  448. package/eventcatalog/src/features/studio/components/icons.ts +0 -53
  449. package/eventcatalog/src/features/studio/components/status.ts +0 -51
  450. package/eventcatalog/src/features/studio/edges.ts +0 -56
  451. package/eventcatalog/src/features/studio/flow-state.ts +0 -92
  452. package/eventcatalog/src/features/studio/grouping.ts +0 -226
  453. package/eventcatalog/src/features/studio/layout.ts +0 -42
  454. package/eventcatalog/src/features/studio/levels.ts +0 -282
  455. package/eventcatalog/src/features/studio/node-types.ts +0 -205
  456. package/eventcatalog/src/features/studio/pages/new.astro +0 -24
  457. package/eventcatalog/src/features/studio/pages/wake.ts +0 -15
  458. package/eventcatalog/src/features/studio/placement.ts +0 -197
  459. package/eventcatalog/src/features/studio/studio.css +0 -273
  460. package/dist/{chunk-A2RZR3U4.js → chunk-6K7XZAYI.js} +3 -3
@@ -1,26 +1,58 @@
1
1
  import { memo, useEffect, useRef, useState, type ReactNode } from 'react';
2
- import { Bot, ChevronDown, Link2, Pencil, Plus, UserPlus } from 'lucide-react';
2
+ import {
3
+ CircleHelp,
4
+ Download,
5
+ FolderOpen,
6
+ ImageDown,
7
+ Link2,
8
+ MoreVertical,
9
+ Pencil,
10
+ Plug,
11
+ Plus,
12
+ Share2,
13
+ Trash2,
14
+ Users,
15
+ } from 'lucide-react';
16
+ import {
17
+ DIAGRAM_MENU,
18
+ DIAGRAM_MENU_BUTTON_ICON,
19
+ DIAGRAM_MENU_ITEM,
20
+ DIAGRAM_MENU_ITEM_ICON,
21
+ DIAGRAM_MENU_SEPARATOR,
22
+ DIAGRAM_MENU_TITLE,
23
+ } from '@eventcatalog/visualiser';
3
24
  import { usePeople, type Peer, type PresenceStore } from '../hooks/presence-store';
25
+ import { MAX_NAME_LENGTH, PERSON_COLORS } from '../identity';
4
26
  import type { WebMcpStatus } from '../hooks/use-canvas-webmcp';
5
27
  import type { Status, Transport } from '../hooks/use-studio-flow';
6
- import type { CanvasStatus, StatusChange } from '../canvas-doc';
28
+ import { type CanvasStatus, type StatusChange, STATUS, Picture, AgentMark } from '@eventcatalog/visualiser/studio';
7
29
  import CanvasStatusMenu from './CanvasStatusMenu';
8
- import { CONNECTION_DOT, STATUS } from './status';
9
- import Picture from './Picture';
30
+
31
+ /** The dot showing whether the canvas is connected */
32
+ const CONNECTION_DOT: Record<Status, string> = {
33
+ connected: STATUS.success.dot,
34
+ connecting: STATUS.warning.dot,
35
+ disconnected: STATUS.danger.dot,
36
+ };
10
37
 
11
38
  /**
12
- * The canvas's header, like Figma or Miro: two small floating bars. On the left the canvas (its title, and a
13
- * menu), on the right who's here, connecting an agent and sharing.
39
+ * The canvas's header, as Studio on the web's top bar: on the left the canvas (its title, its status and a menu), on
40
+ * the right who's here, connecting an agent and sharing, each a small card over the canvas. Its menus look like the
41
+ * visualiser's (`DIAGRAM_MENU_*`).
14
42
  */
15
43
 
16
44
  const barClass =
17
- 'pointer-events-auto flex h-10 items-center rounded-xl border shadow-md bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))]';
45
+ 'pointer-events-auto flex h-[38px] items-center rounded-[9px] border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] shadow-sm';
18
46
  // The header lets the pointer through to the canvas around its bars, so its menus take it back
19
- const menuClass =
20
- 'pointer-events-auto absolute top-full z-50 mt-2 min-w-52 rounded-xl border p-1 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]';
21
- const menuItemClass =
22
- 'flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-left text-xs hover:bg-[rgb(var(--ec-page-border)/0.5)]';
47
+ const popoverClass = 'pointer-events-auto absolute top-full mt-2';
48
+ const menuClass = `${popoverClass} ${DIAGRAM_MENU}`;
49
+ const menuItemClass = `${DIAGRAM_MENU_ITEM} w-full text-left`;
23
50
  const MAX_AVATARS = 4;
51
+ const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);
52
+ const MOD = isMac ? 'Cmd' : 'Ctrl';
53
+ const itemClass =
54
+ 'flex h-[34px] w-full cursor-pointer items-center gap-3 rounded-[7px] px-2 text-left text-sm outline-none hover:bg-[rgb(var(--ec-content-hover))]';
55
+ const itemIconClass = 'flex flex-none [&_svg]:h-[17px] [&_svg]:w-[17px] [&_svg]:stroke-[1.75]';
24
56
 
25
57
  /** Closes a popover on outside clicks and Escape */
26
58
  function usePopover() {
@@ -48,7 +80,7 @@ function Avatar({ peer, size = 28, children }: { peer: Peer; size?: number; chil
48
80
  className="relative flex items-center justify-center rounded-full text-[11px] font-semibold text-white ring-2 ring-[rgb(var(--ec-card-bg))]"
49
81
  style={{ backgroundColor: peer.color, width: size, height: size }}
50
82
  >
51
- {children ?? (peer.agent ? <Bot size={14} /> : peer.name.slice(0, 2).toUpperCase())}
83
+ {children ?? (peer.agent ? <AgentMark name={peer.name} size={14} /> : peer.name.slice(0, 2).toUpperCase())}
52
84
  {!children && <Picture src={peer.picture} />}
53
85
  </span>
54
86
  );
@@ -61,14 +93,35 @@ function CanvasMenu({
61
93
  onRetitle,
62
94
  shareUrl,
63
95
  newCanvasUrl,
96
+ onConnectAgent,
97
+ webMcp,
98
+ agentsHere,
99
+ onDelete,
100
+ onOpenFile,
101
+ onSaveToFile,
102
+ onExportImage,
103
+ onLiveCollaboration,
104
+ onHelp,
64
105
  children,
65
106
  }: {
107
+ /** Opens a .eventcatalog file as a new canvas (not offered when not given, e.g. inside a chat) */
108
+ onOpenFile?: () => void;
109
+ onSaveToFile: () => void;
110
+ onExportImage: () => void;
111
+ onLiveCollaboration: () => void;
112
+ onHelp: () => void;
66
113
  title?: string;
67
114
  status: Status;
68
115
  transport: Transport;
69
116
  onRetitle: (title: string) => void;
70
117
  shareUrl?: string;
71
118
  newCanvasUrl?: string;
119
+ onConnectAgent: () => void;
120
+ webMcp: WebMcpStatus;
121
+ /** An AI agent is on the canvas */
122
+ agentsHere: boolean;
123
+ /** Asks to delete the canvas (not offered when not given, e.g. inside a chat) */
124
+ onDelete?: () => void;
72
125
  /** Shown after the title (the canvas's status) */
73
126
  children?: ReactNode;
74
127
  }) {
@@ -81,10 +134,29 @@ function CanvasMenu({
81
134
  disconnected: 'Offline, reconnecting…',
82
135
  }[status];
83
136
  const statusColor = CONNECTION_DOT[status];
137
+ /** A menu item, as Studio on the web's: its icon, what it does, and its shortcut (or something else on the right) */
138
+ const item = (icon: ReactNode, label: string, onSelect: () => void, shortcut?: ReactNode, className = '') => (
139
+ <button
140
+ type="button"
141
+ className={`${itemClass} ${className}`}
142
+ onClick={() => {
143
+ menu.setOpen(false);
144
+ onSelect();
145
+ }}
146
+ >
147
+ <span className={itemIconClass}>{icon}</span>
148
+ <span className="min-w-0 flex-1 truncate">{label}</span>
149
+ {typeof shortcut === 'string' ? (
150
+ <span className="flex-none text-xs font-normal text-[rgb(var(--ec-page-text-muted))]">{shortcut}</span>
151
+ ) : (
152
+ shortcut
153
+ )}
154
+ </button>
155
+ );
84
156
 
85
157
  return (
86
158
  <div ref={menu.ref} className="relative">
87
- <div className={`${barClass} gap-1 pl-3 pr-1`}>
159
+ <div className={`${barClass} gap-1.5 pl-3 pr-1`}>
88
160
  <span title={statusLabel} className={`h-2 w-2 shrink-0 rounded-full ${statusColor}`} />
89
161
  <input
90
162
  ref={titleInput}
@@ -98,45 +170,57 @@ function CanvasMenu({
98
170
  }}
99
171
  onKeyDown={(e) => e.key === 'Enter' && e.currentTarget.blur()}
100
172
  size={Math.max(12, (draft ?? title ?? 'Untitled canvas').length)}
101
- className="max-w-64 truncate rounded-md bg-transparent px-1.5 py-1 text-sm font-semibold placeholder:font-semibold placeholder:text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.4)] focus:bg-[rgb(var(--ec-input-bg))] focus:outline-none"
173
+ className={`${DIAGRAM_MENU_TITLE} max-w-64 truncate rounded-md bg-transparent px-1.5 py-1 placeholder:text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.4)] focus:bg-[rgb(var(--ec-input-bg))] focus:outline-none`}
102
174
  />
103
175
  {children}
104
176
  <button
105
177
  aria-label="Canvas menu"
106
178
  onClick={() => menu.setOpen((open) => !open)}
107
- className="rounded-md p-1.5 text-[rgb(var(--ec-icon-color))] hover:bg-[rgb(var(--ec-page-border)/0.5)]"
179
+ className="group rounded-md p-1 hover:bg-[rgb(var(--ec-accent-subtle))]"
108
180
  >
109
- <ChevronDown size={14} />
181
+ <MoreVertical className={DIAGRAM_MENU_BUTTON_ICON} />
110
182
  </button>
111
183
  </div>
112
184
  {menu.open && (
113
- <div className={`${menuClass} left-0`}>
114
- <button
115
- className={menuItemClass}
116
- onClick={() => {
117
- menu.setOpen(false);
118
- titleInput.current?.focus();
119
- titleInput.current?.select();
120
- }}
121
- >
122
- <Pencil size={14} /> Rename canvas
123
- </button>
124
- <button
125
- className={menuItemClass}
126
- onClick={() => {
127
- void navigator.clipboard.writeText(shareUrl ?? window.location.href);
128
- menu.setOpen(false);
129
- }}
130
- >
131
- <Link2 size={14} /> Copy link
132
- </button>
185
+ <div
186
+ className={`${popoverClass} left-0 z-50 w-72 rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] p-1.5 text-[rgb(var(--ec-page-text))] shadow-xl`}
187
+ >
188
+ {/* As Studio on the web's menu: files and images, people and agents, help */}
189
+ {onOpenFile && item(<FolderOpen />, 'Open…', onOpenFile, `${MOD}+O`)}
190
+ {item(<Download />, 'Save to file…', onSaveToFile, `${MOD}+S`)}
191
+ {item(<ImageDown />, 'Export image…', onExportImage, `${MOD}+Shift+E`)}
192
+ {item(<Users />, 'Live collaboration…', onLiveCollaboration)}
193
+ {item(
194
+ <Plug />,
195
+ agentsHere ? 'AI agent connected' : 'Connect your AI agent…',
196
+ onConnectAgent,
197
+ webMcp.state === 'on' || agentsHere ? (
198
+ <span className={`h-1.5 w-1.5 rounded-full ${STATUS.success.dot}`} />
199
+ ) : undefined
200
+ )}
201
+ {item(<CircleHelp />, 'Help', onHelp, '?')}
202
+ <div className="my-1.5 h-px bg-[rgb(var(--ec-page-border))]" />
203
+ {item(<Pencil />, 'Rename canvas', () => {
204
+ titleInput.current?.focus();
205
+ titleInput.current?.select();
206
+ })}
207
+ {item(<Link2 />, 'Copy link', () => void navigator.clipboard.writeText(shareUrl ?? window.location.href))}
133
208
  {newCanvasUrl && (
134
- <a className={menuItemClass} href={newCanvasUrl}>
135
- <Plus size={14} /> New canvas
209
+ <a className={itemClass} href={newCanvasUrl}>
210
+ <span className={itemIconClass}>
211
+ <Plus />
212
+ </span>
213
+ <span className="min-w-0 flex-1 truncate">New canvas</span>
136
214
  </a>
137
215
  )}
138
- <div className="my-1 h-px bg-[rgb(var(--ec-page-border))]" />
139
- <p className="flex items-center gap-2 px-2.5 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]">
216
+ {onDelete && (
217
+ <>
218
+ <div className="my-1.5 h-px bg-[rgb(var(--ec-page-border))]" />
219
+ {item(<Trash2 />, 'Delete canvas', onDelete, undefined, `${STATUS.danger.text} ${STATUS.danger.hover}`)}
220
+ </>
221
+ )}
222
+ <div className="my-1.5 h-px bg-[rgb(var(--ec-page-border))]" />
223
+ <p className="flex items-center gap-2 px-2 py-1.5 text-[11px] text-[rgb(var(--ec-page-text-muted))]">
140
224
  <span className={`h-1.5 w-1.5 rounded-full ${statusColor}`} />
141
225
  {statusLabel}
142
226
  </p>
@@ -146,48 +230,106 @@ function CanvasMenu({
146
230
  );
147
231
  }
148
232
 
149
- /** You: change the name others see you by (unless you're signed in, when it's the name you signed in with) */
150
- function YouAvatar({ peer, onRename }: { peer: Peer; onRename?: (name: string) => void }) {
233
+ const initialsOf = (name: string) => {
234
+ const words = name.trim().split(/\s+/).filter(Boolean);
235
+ return (words.length > 1 ? words.map((word) => word[0]).join('') : name.trim()).slice(0, 2).toUpperCase();
236
+ };
237
+
238
+ /**
239
+ * Who you are here, top right (as Studio on the web's): your avatar, opening your name and colour to change. They're
240
+ * on your pointer and comments. Signed in, your name and picture are the ones you signed in with.
241
+ */
242
+ function ProfileMenu({
243
+ me,
244
+ onRename,
245
+ onRecolor,
246
+ }: {
247
+ me: { name: string; color: string; picture?: string; agent?: boolean };
248
+ /** Not given when you're signed in */
249
+ onRename?: (name: string) => void;
250
+ onRecolor: (color: string) => void;
251
+ }) {
151
252
  const popover = usePopover();
152
- const [draft, setDraft] = useState(peer.name);
153
- const commit = () => {
154
- const trimmed = draft.trim();
155
- if (trimmed && trimmed !== peer.name) onRename?.(trimmed);
156
- popover.setOpen(false);
253
+ const [draft, setDraft] = useState(me.name);
254
+ useEffect(() => setDraft(me.name), [me.name]);
255
+ const save = () => {
256
+ const next = draft.trim();
257
+ if (!next) return setDraft(me.name);
258
+ if (next !== me.name) onRename?.(next);
157
259
  };
158
-
159
- // Signed in: you're shown in the app's header already
160
- if (!onRename) return null;
260
+ const avatar = (size: string, text: string) => (
261
+ <span
262
+ className={`relative flex ${size} flex-none items-center justify-center rounded-full text-[10px] font-semibold text-white`}
263
+ style={{ background: me.color }}
264
+ >
265
+ {initialsOf(text)}
266
+ <Picture src={me.picture} />
267
+ </span>
268
+ );
269
+ // Here as an AI agent (e.g. a chat's view, as the chat's agent): who you are is its logo, not yours to change
270
+ if (me.agent)
271
+ return (
272
+ <span title={`You're here as ${me.name} (AI agent)`} className={`${barClass} pointer-events-auto w-[38px] justify-center`}>
273
+ <span className="flex h-6 w-6 items-center justify-center rounded-full text-white" style={{ background: me.color }}>
274
+ <AgentMark name={me.name} size={14} />
275
+ </span>
276
+ </span>
277
+ );
161
278
  return (
162
- <div ref={popover.ref} className="relative">
279
+ <div ref={popover.ref} className="pointer-events-auto relative">
163
280
  <button
164
- title={`${peer.name} (you)`}
165
- onClick={() => {
166
- setDraft(peer.name);
167
- popover.setOpen((open) => !open);
168
- }}
169
- className="block rounded-full transition-transform hover:scale-110"
281
+ type="button"
282
+ title={onRename ? `${me.name}: change your name and colour` : `${me.name}: change your colour`}
283
+ onClick={() => popover.setOpen((open) => !open)}
284
+ className={`${barClass} w-[38px] justify-center hover:bg-[rgb(var(--ec-content-hover))]`}
170
285
  >
171
- <Avatar peer={peer} />
286
+ {avatar('h-6 w-6', me.name)}
172
287
  </button>
173
288
  {popover.open && (
174
- <div className={`${menuClass} right-0 w-60 space-y-2 p-3`}>
175
- <label className="block space-y-1.5 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))]">
176
- Your name on this canvas
177
- <input
178
- autoFocus
179
- value={draft}
180
- onChange={(e) => setDraft(e.target.value)}
181
- onKeyDown={(e) => e.key === 'Enter' && commit()}
182
- className="w-full rounded-md border px-2 py-1.5 text-xs bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-input-text))]"
183
- />
184
- </label>
185
- <button
186
- onClick={commit}
187
- className="w-full rounded-md px-2 py-1.5 text-xs font-medium bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))]"
188
- >
189
- Save
190
- </button>
289
+ <div
290
+ className={`${popoverClass} right-0 z-[70] w-72 rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] p-4 text-[rgb(var(--ec-page-text))] shadow-xl`}
291
+ >
292
+ <div className="flex items-center gap-3">
293
+ {avatar('h-9 w-9 text-xs', draft || me.name)}
294
+ <div className="min-w-0">
295
+ <p className="truncate text-sm font-semibold">{draft || me.name}</p>
296
+ <p className="text-xs text-[rgb(var(--ec-page-text-muted))]">On your pointer and comments</p>
297
+ </div>
298
+ </div>
299
+ {onRename && (
300
+ <label className="mt-4 block text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">
301
+ Your name
302
+ <input
303
+ value={draft}
304
+ maxLength={MAX_NAME_LENGTH}
305
+ onChange={(event) => setDraft(event.target.value)}
306
+ onBlur={save}
307
+ onKeyDown={(event) => event.key === 'Enter' && event.currentTarget.blur()}
308
+ className="mt-1.5 block h-9 w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-3 text-sm text-[rgb(var(--ec-page-text))] outline-none focus:border-[rgb(var(--ec-accent))]"
309
+ />
310
+ </label>
311
+ )}
312
+ <div className="mt-3 text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">
313
+ Your colour
314
+ <div role="radiogroup" aria-label="Your colour" className="mt-2 flex gap-2">
315
+ {PERSON_COLORS.map((color) => (
316
+ <button
317
+ key={color}
318
+ type="button"
319
+ role="radio"
320
+ aria-checked={color === me.color}
321
+ aria-label={color}
322
+ onClick={() => onRecolor(color)}
323
+ className={`h-6 w-6 rounded-full transition-transform hover:scale-110 ${
324
+ color === me.color
325
+ ? 'ring-2 ring-[rgb(var(--ec-page-text))] ring-offset-2 ring-offset-[rgb(var(--ec-card-bg))]'
326
+ : ''
327
+ }`}
328
+ style={{ background: color }}
329
+ />
330
+ ))}
331
+ </div>
332
+ </div>
191
333
  </div>
192
334
  )}
193
335
  </div>
@@ -195,20 +337,34 @@ function YouAvatar({ peer, onRename }: { peer: Peer; onRename?: (name: string) =
195
337
  }
196
338
 
197
339
  /** Who's here: click someone to jump to them; everyone past the first few is in a list */
340
+ /**
341
+ * Who else is here. An agent is shown once, however many places it's in (e.g. its MCP tools and its chat's canvas
342
+ * view), and not at all when it's you.
343
+ */
344
+ const othersHere = (peers: Peer[], clientId: number | null, me: { name: string; agent?: boolean }) => {
345
+ const agentsSeen = new Set(me.agent ? [me.name] : []);
346
+ return peers.filter((peer) => {
347
+ if (peer.clientId === clientId) return false;
348
+ if (!peer.agent) return true;
349
+ if (agentsSeen.has(peer.name)) return false;
350
+ agentsSeen.add(peer.name);
351
+ return true;
352
+ });
353
+ };
354
+
198
355
  function People({
199
356
  peers,
200
357
  clientId,
358
+ me,
201
359
  onJumpTo,
202
- onRename,
203
360
  }: {
204
361
  peers: Peer[];
205
362
  clientId: number | null;
363
+ me: { name: string; agent?: boolean };
206
364
  onJumpTo: (peer: Peer) => void;
207
- onRename?: (name: string) => void;
208
365
  }) {
209
366
  const overflow = usePopover();
210
- const you = peers.find((peer) => peer.clientId === clientId);
211
- const others = peers.filter((peer) => peer.clientId !== clientId);
367
+ const others = othersHere(peers, clientId, me);
212
368
  const shown = others.slice(0, MAX_AVATARS);
213
369
  const hidden = others.slice(MAX_AVATARS);
214
370
  const describe = (peer: Peer) => `${peer.name}${peer.agent ? ` (AI agent)${peer.activity ? `: ${peer.activity}` : ''}` : ''}`;
@@ -255,7 +411,6 @@ function People({
255
411
  </div>
256
412
  )}
257
413
  </div>
258
- {you && <YouAvatar peer={you} onRename={onRename} />}
259
414
  </div>
260
415
  );
261
416
  }
@@ -268,15 +423,23 @@ export default memo(function CanvasHeader({
268
423
  presence,
269
424
  clientId,
270
425
  onJumpTo,
426
+ me,
271
427
  onRename,
428
+ onRecolor,
272
429
  onConnectAgent,
273
430
  webMcp,
274
431
  shareUrl,
275
432
  newCanvasUrl,
276
433
  onShare,
434
+ onOpenFile,
435
+ onSaveToFile,
436
+ onExportImage,
437
+ onLiveCollaboration,
438
+ onHelp,
277
439
  canvasStatus,
278
440
  statusHistory,
279
441
  onStatusChange,
442
+ onDelete,
280
443
  }: {
281
444
  title?: string;
282
445
  onRetitle: (title: string) => void;
@@ -288,17 +451,30 @@ export default memo(function CanvasHeader({
288
451
  presence: PresenceStore | null;
289
452
  clientId: number | null;
290
453
  onJumpTo: (peer: Peer) => void;
454
+ /** You: your name, colour and (signed in) picture */
455
+ me: { name: string; color: string; picture?: string; agent?: boolean };
291
456
  /** Not given when you're signed in */
292
457
  onRename?: (name: string) => void;
458
+ onRecolor: (color: string) => void;
293
459
  onConnectAgent: () => void;
294
460
  webMcp: WebMcpStatus;
295
461
  shareUrl?: string;
296
462
  newCanvasUrl?: string;
297
463
  /** Open the share dialog */
298
464
  onShare: () => void;
465
+ /** Opens a .eventcatalog file as a new canvas (not given where it can't, e.g. inside a chat) */
466
+ onOpenFile?: () => void;
467
+ onSaveToFile: () => void;
468
+ onExportImage: () => void;
469
+ onLiveCollaboration: () => void;
470
+ onHelp: () => void;
471
+ /** Ask to delete the canvas (not given where it can't be, e.g. inside a chat) */
472
+ onDelete?: () => void;
299
473
  }) {
300
474
  const peers = usePeople(presence);
301
475
  const agentsHere = peers.some((peer) => peer.agent);
476
+ // Who else is here (you're your own avatar, next to it)
477
+ const showPeople = othersHere(peers, clientId, me).length > 0;
302
478
 
303
479
  return (
304
480
  <div className="pointer-events-none absolute left-3 right-3 top-3 z-10 flex items-start justify-between gap-3">
@@ -309,38 +485,31 @@ export default memo(function CanvasHeader({
309
485
  onRetitle={onRetitle}
310
486
  shareUrl={shareUrl}
311
487
  newCanvasUrl={newCanvasUrl}
488
+ onConnectAgent={onConnectAgent}
489
+ webMcp={webMcp}
490
+ agentsHere={agentsHere}
491
+ onDelete={onDelete}
492
+ onOpenFile={onOpenFile}
493
+ onSaveToFile={onSaveToFile}
494
+ onExportImage={onExportImage}
495
+ onLiveCollaboration={onLiveCollaboration}
496
+ onHelp={onHelp}
312
497
  >
313
498
  <CanvasStatusMenu status={canvasStatus} history={statusHistory} onChange={onStatusChange} />
314
499
  </CanvasMenu>
315
500
 
316
- <div className={`${barClass} gap-2 px-1.5`}>
317
- <div className="pl-1">
318
- <People peers={peers} clientId={clientId} onJumpTo={onJumpTo} onRename={onRename} />
319
- </div>
320
- <div className="h-5 w-px bg-[rgb(var(--ec-page-border))]" />
321
- <button
322
- onClick={onConnectAgent}
323
- title={
324
- webMcp.state === 'on'
325
- ? `Connect an AI agent to this canvas. WebMCP is on in this tab${webMcp.lastCall ? ` (last: ${webMcp.lastCall})` : ''}`
326
- : 'Connect an AI agent to this canvas'
327
- }
328
- // A button of its own next to Share (the two ways to bring someone in): people, or an AI agent
329
- className="relative flex h-7 items-center gap-1.5 rounded-lg border px-2.5 text-xs font-semibold transition-colors border-[rgb(var(--ec-accent)/0.35)] bg-[rgb(var(--ec-accent-subtle))] text-[rgb(var(--ec-accent))] hover:border-[rgb(var(--ec-accent)/0.7)] hover:bg-[rgb(var(--ec-accent)/0.15)]"
330
- >
331
- <Bot size={15} />
332
- {agentsHere ? 'Agent connected' : 'Connect agent'}
333
- {(webMcp.state === 'on' || agentsHere) && (
334
- <span
335
- className={`absolute -right-1 -top-1 h-2.5 w-2.5 rounded-full ring-2 ring-[rgb(var(--ec-card-bg))] ${STATUS.success.dot}`}
336
- />
337
- )}
338
- </button>
501
+ <div className="flex items-center gap-2">
502
+ {showPeople && (
503
+ <div className={`${barClass} px-1.5`}>
504
+ <People peers={peers} clientId={clientId} me={me} onJumpTo={onJumpTo} />
505
+ </div>
506
+ )}
507
+ <ProfileMenu me={me} onRename={onRename} onRecolor={onRecolor} />
339
508
  <button
340
509
  onClick={onShare}
341
- className="flex h-7 items-center gap-1.5 rounded-lg px-3 text-xs font-semibold bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))] hover:bg-[rgb(var(--ec-button-bg-hover))]"
510
+ className="pointer-events-auto inline-flex h-[38px] items-center gap-2 rounded-[9px] bg-[rgb(var(--ec-page-text))] px-4 text-sm font-semibold text-[rgb(var(--ec-page-bg))] shadow-sm transition-colors hover:bg-[rgb(var(--ec-page-text)/0.85)]"
342
511
  >
343
- <UserPlus size={14} />
512
+ <Share2 size={16} aria-hidden />
344
513
  Share
345
514
  </button>
346
515
  </div>
@@ -1,8 +1,13 @@
1
1
  import { memo, useEffect, useRef, useState } from 'react';
2
2
  import { Check, ChevronDown } from 'lucide-react';
3
- import { CANVAS_STATUSES, type CanvasStatus, type StatusChange } from '../canvas-doc';
4
- import { timeAgo } from './Comments';
5
- import { CANVAS_STATUS_LOOK } from './status';
3
+ import { DIAGRAM_MENU, DIAGRAM_MENU_ITEM, DIAGRAM_MENU_SEPARATOR } from '@eventcatalog/visualiser';
4
+ import {
5
+ CANVAS_STATUSES,
6
+ type CanvasStatus,
7
+ type StatusChange,
8
+ timeAgo,
9
+ CANVAS_STATUS_LOOK,
10
+ } from '@eventcatalog/visualiser/studio';
6
11
 
7
12
  /** Status changes shown in the menu, newest first */
8
13
  const HISTORY_SHOWN = 8;
@@ -58,18 +63,14 @@ export default memo(function CanvasStatusMenu({
58
63
  <ChevronDown size={12} />
59
64
  </button>
60
65
  {open && (
61
- <div className="absolute left-0 top-full z-50 mt-2 w-72 rounded-xl border p-1 shadow-xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]">
62
- <p className="px-2.5 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]">
66
+ <div className={`absolute left-0 top-full mt-2 w-72 ${DIAGRAM_MENU}`}>
67
+ <p className="px-3 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]">
63
68
  Status
64
69
  </p>
65
70
  {CANVAS_STATUSES.map((value) => {
66
71
  const option = CANVAS_STATUS_LOOK[value];
67
72
  return (
68
- <button
69
- key={value}
70
- onClick={() => choose(value)}
71
- className="flex w-full items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-left hover:bg-[rgb(var(--ec-page-border)/0.5)]"
72
- >
73
+ <button key={value} onClick={() => choose(value)} className={`${DIAGRAM_MENU_ITEM} w-full text-left`}>
73
74
  <span className={`h-2 w-2 shrink-0 rounded-full ${option.dot}`} />
74
75
  <span className="min-w-0 flex-1">
75
76
  <span className="block text-xs font-medium">{option.label}</span>
@@ -79,7 +80,7 @@ export default memo(function CanvasStatusMenu({
79
80
  </button>
80
81
  );
81
82
  })}
82
- <div className="px-2.5 py-2">
83
+ <div className="px-3 py-2">
83
84
  <input
84
85
  value={note}
85
86
  onChange={(event) => setNote(event.target.value)}
@@ -90,11 +91,11 @@ export default memo(function CanvasStatusMenu({
90
91
  </div>
91
92
  {recent.length > 0 && (
92
93
  <>
93
- <div className="my-1 h-px bg-[rgb(var(--ec-page-border))]" />
94
- <p className="px-2.5 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]">
94
+ <div className={DIAGRAM_MENU_SEPARATOR} />
95
+ <p className="px-3 pb-1 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]">
95
96
  History
96
97
  </p>
97
- <ul className="max-h-48 space-y-1.5 overflow-y-auto px-2.5 pb-2">
98
+ <ul className="max-h-48 space-y-1.5 overflow-y-auto px-3 pb-2">
98
99
  {recent.map((change) => (
99
100
  <li key={`${change.at}-${change.status}`} className="text-[11px]">
100
101
  <span className="flex items-center gap-1.5">