@eventcatalog/core 5.0.0-beta.11 → 5.0.0-beta.13

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 (92) hide show
  1. package/README.md +1 -1
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +1 -1
  5. package/dist/analytics/log-build.js +4 -4
  6. package/dist/catalog-runtime.cjs +1 -1
  7. package/dist/{chunk-MFEMKQZ6.js → chunk-BO2HHVZ3.js} +1 -1
  8. package/dist/{chunk-4YFM63DS.js → chunk-JPT3QC5V.js} +1 -1
  9. package/dist/{chunk-76DAAJLV.js → chunk-PLTLW45Q.js} +5 -5
  10. package/dist/{chunk-WM4QYMIA.js → chunk-T75DOVFP.js} +1 -1
  11. package/dist/{chunk-LQZ7IG7B.js → chunk-XA5W6DXX.js} +1 -1
  12. package/dist/constants.cjs +1 -1
  13. package/dist/constants.js +1 -1
  14. package/dist/eventcatalog.cjs +2 -2
  15. package/dist/eventcatalog.js +14 -14
  16. package/dist/federation/federate.js +3 -3
  17. package/dist/generate.cjs +1 -1
  18. package/dist/generate.js +3 -3
  19. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
  20. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
  21. package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
  22. package/dist/runtime-dependencies/manifest.json +3 -0
  23. package/dist/utils/cli-logger.cjs +1 -1
  24. package/dist/utils/cli-logger.js +2 -2
  25. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
  26. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +42 -3
  27. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
  28. package/eventcatalog/src/components/NavigationProgress.astro +7 -0
  29. package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
  30. package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
  31. package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
  32. package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
  33. package/eventcatalog/src/features/mcp/apps/generated/canvas.html +132 -70
  34. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +71 -71
  35. package/eventcatalog/src/features/studio/agent-choreography.ts +13 -10
  36. package/eventcatalog/src/features/studio/agents.ts +28 -0
  37. package/eventcatalog/src/features/studio/api/canvases-api.ts +64 -15
  38. package/eventcatalog/src/features/studio/api/client.ts +6 -1
  39. package/eventcatalog/src/features/studio/canvas-actions.ts +160 -34
  40. package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
  41. package/eventcatalog/src/features/studio/catalog.ts +16 -14
  42. package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +263 -115
  43. package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +15 -14
  44. package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
  45. package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
  46. package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +28 -44
  47. package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
  48. package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
  49. package/eventcatalog/src/features/studio/components/LeftPanel.tsx +119 -230
  50. package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
  51. package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
  52. package/eventcatalog/src/features/studio/components/Presence.tsx +52 -45
  53. package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
  54. package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
  55. package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1286 -411
  56. package/eventcatalog/src/features/studio/document-name.ts +7 -0
  57. package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
  58. package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
  59. package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
  60. package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
  61. package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +8 -3
  62. package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +223 -30
  63. package/eventcatalog/src/features/studio/identity.ts +23 -1
  64. package/eventcatalog/src/features/studio/limits.ts +2 -0
  65. package/eventcatalog/src/features/studio/pages/[id].astro +2 -1
  66. package/eventcatalog/src/features/studio/pages/index.astro +2 -2
  67. package/eventcatalog/src/features/studio/server/canvas-mcp.ts +8 -23
  68. package/eventcatalog/src/features/studio/server/runtime.ts +16 -9
  69. package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
  70. package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
  71. package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
  72. package/package.json +3 -3
  73. package/eventcatalog/src/features/studio/canvas-doc.ts +0 -414
  74. package/eventcatalog/src/features/studio/clipboard.ts +0 -97
  75. package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -154
  76. package/eventcatalog/src/features/studio/components/Comments.tsx +0 -770
  77. package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
  78. package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
  79. package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
  80. package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
  81. package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -255
  82. package/eventcatalog/src/features/studio/components/icons.ts +0 -53
  83. package/eventcatalog/src/features/studio/components/status.ts +0 -53
  84. package/eventcatalog/src/features/studio/edges.ts +0 -56
  85. package/eventcatalog/src/features/studio/flow-state.ts +0 -92
  86. package/eventcatalog/src/features/studio/grouping.ts +0 -226
  87. package/eventcatalog/src/features/studio/layout.ts +0 -42
  88. package/eventcatalog/src/features/studio/levels.ts +0 -282
  89. package/eventcatalog/src/features/studio/node-types.ts +0 -205
  90. package/eventcatalog/src/features/studio/placement.ts +0 -197
  91. package/eventcatalog/src/features/studio/studio.css +0 -273
  92. package/dist/{chunk-KHACCTW2.js → chunk-ZEY2XUJN.js} +4 -4
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <div align="center">
2
2
 
3
3
  <!-- <h1>📖 EventCatalog</h1> -->
4
- <!-- <h3>The open source tool to help you discover and document your event-driven architectures</h3> -->
4
+ <!-- <h3>The source-available tool to help you discover and document your event-driven architectures</h3> -->
5
5
 
6
6
 
7
7
 
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(analytics_exports);
36
36
  var import_os = __toESM(require("os"), 1);
37
37
 
38
38
  // package.json
39
- var version = "5.0.0-beta.11";
39
+ var version = "5.0.0-beta.13";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-4YFM63DS.js";
3
+ } from "../chunk-JPT3QC5V.js";
4
4
  import "../chunk-CPW6G62V.js";
5
- import "../chunk-MFEMKQZ6.js";
5
+ import "../chunk-BO2HHVZ3.js";
6
6
  export {
7
7
  raiseEvent
8
8
  };
@@ -176,7 +176,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
176
176
  var import_os = __toESM(require("os"), 1);
177
177
 
178
178
  // package.json
179
- var version = "5.0.0-beta.11";
179
+ var version = "5.0.0-beta.13";
180
180
 
181
181
  // src/constants.ts
182
182
  var VERSION = version;
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-76DAAJLV.js";
4
- import "../chunk-AWOO63ME.js";
3
+ } from "../chunk-PLTLW45Q.js";
4
+ import "../chunk-JPT3QC5V.js";
5
5
  import "../chunk-ZAZHAVKB.js";
6
- import "../chunk-4YFM63DS.js";
7
6
  import "../chunk-CPW6G62V.js";
8
- import "../chunk-MFEMKQZ6.js";
7
+ import "../chunk-AWOO63ME.js";
8
+ import "../chunk-BO2HHVZ3.js";
9
9
  import "../chunk-RFIXKATC.js";
10
10
  export {
11
11
  log_build_default as default
@@ -36,7 +36,7 @@ __export(catalog_runtime_exports, {
36
36
  });
37
37
  module.exports = __toCommonJS(catalog_runtime_exports);
38
38
 
39
- // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
39
+ // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.29_tsx@4.23.15_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
40
40
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
41
41
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
42
42
 
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "5.0.0-beta.11";
2
+ var version = "5.0.0-beta.13";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-CPW6G62V.js";
5
5
  import {
6
6
  VERSION
7
- } from "./chunk-MFEMKQZ6.js";
7
+ } from "./chunk-BO2HHVZ3.js";
8
8
 
9
9
  // src/analytics/analytics.js
10
10
  import os from "os";
@@ -1,18 +1,18 @@
1
1
  import {
2
- getLicenseAnalytics
3
- } from "./chunk-AWOO63ME.js";
2
+ raiseEvent
3
+ } from "./chunk-JPT3QC5V.js";
4
4
  import {
5
5
  countResources,
6
6
  hashCatalogContent,
7
7
  serializeCounts
8
8
  } from "./chunk-ZAZHAVKB.js";
9
- import {
10
- raiseEvent
11
- } from "./chunk-4YFM63DS.js";
12
9
  import {
13
10
  TELEMETRY_REQUEST_TIMEOUT_MS,
14
11
  isTelemetryDisabled
15
12
  } from "./chunk-CPW6G62V.js";
13
+ import {
14
+ getLicenseAnalytics
15
+ } from "./chunk-AWOO63ME.js";
16
16
  import {
17
17
  getEventCatalogConfigFile,
18
18
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-LQZ7IG7B.js";
3
+ } from "./chunk-XA5W6DXX.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-MFEMKQZ6.js";
3
+ } from "./chunk-BO2HHVZ3.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "5.0.0-beta.11";
28
+ var version = "5.0.0-beta.13";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-MFEMKQZ6.js";
3
+ } from "./chunk-BO2HHVZ3.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -22,7 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  mod
23
23
  ));
24
24
 
25
- // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
25
+ // ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.29_tsx@4.23.15_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
26
26
  var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
27
27
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
28
28
 
@@ -181,7 +181,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
181
181
  var import_picocolors = __toESM(require("picocolors"), 1);
182
182
 
183
183
  // package.json
184
- var version = "5.0.0-beta.11";
184
+ var version = "5.0.0-beta.13";
185
185
 
186
186
  // src/constants.ts
187
187
  var VERSION = version;
@@ -1,28 +1,29 @@
1
+ import {
2
+ log_build_default
3
+ } from "./chunk-PLTLW45Q.js";
4
+ import "./chunk-JPT3QC5V.js";
5
+ import "./chunk-ZAZHAVKB.js";
6
+ import "./chunk-CPW6G62V.js";
1
7
  import {
2
8
  runMigrations
3
9
  } from "./chunk-XUAF2H54.js";
4
10
  import "./chunk-CA4U2JP7.js";
5
- import {
6
- log_build_default
7
- } from "./chunk-76DAAJLV.js";
8
11
  import {
9
12
  getLicenseStatus,
10
13
  printLicenseStatus
11
14
  } from "./chunk-AWOO63ME.js";
12
- import "./chunk-ZAZHAVKB.js";
13
15
  import {
14
16
  FederationConflictError,
15
17
  FederationDiagnosticError,
16
18
  federateCatalog
17
- } from "./chunk-KHACCTW2.js";
18
- import "./chunk-WRNH5C3U.js";
19
- import "./chunk-5EPNFDT5.js";
20
- import "./chunk-A2RZR3U4.js";
21
- import "./chunk-R7Z5ALYI.js";
19
+ } from "./chunk-ZEY2XUJN.js";
22
20
  import {
23
21
  getFederationDiagnosticCounts,
24
22
  getVisibleFederationDiagnostics
25
23
  } from "./chunk-JJPB6EOZ.js";
24
+ import "./chunk-WRNH5C3U.js";
25
+ import "./chunk-5EPNFDT5.js";
26
+ import "./chunk-A2RZR3U4.js";
26
27
  import "./chunk-SDZQJTJW.js";
27
28
  import "./chunk-352FGP6W.js";
28
29
  import {
@@ -33,10 +34,10 @@ import {
33
34
  } from "./chunk-MDWB5HLO.js";
34
35
  import {
35
36
  generate
36
- } from "./chunk-WM4QYMIA.js";
37
+ } from "./chunk-T75DOVFP.js";
37
38
  import {
38
39
  logger
39
- } from "./chunk-LQZ7IG7B.js";
40
+ } from "./chunk-XA5W6DXX.js";
40
41
  import {
41
42
  resolve_catalog_dependencies_default
42
43
  } from "./chunk-36RYTYT5.js";
@@ -50,8 +51,7 @@ import {
50
51
  import {
51
52
  watch
52
53
  } from "./chunk-U63GDPPY.js";
53
- import "./chunk-4YFM63DS.js";
54
- import "./chunk-CPW6G62V.js";
54
+ import "./chunk-R7Z5ALYI.js";
55
55
  import {
56
56
  getAstroConfigPath
57
57
  } from "./chunk-VIJJ7JKH.js";
@@ -67,7 +67,7 @@ import {
67
67
  } from "./chunk-LFQJXLHG.js";
68
68
  import {
69
69
  VERSION
70
- } from "./chunk-MFEMKQZ6.js";
70
+ } from "./chunk-BO2HHVZ3.js";
71
71
  import {
72
72
  getEventCatalogConfigFile,
73
73
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -2,14 +2,14 @@ import {
2
2
  FederationConflictError,
3
3
  FederationDiagnosticError,
4
4
  federateCatalog
5
- } from "../chunk-KHACCTW2.js";
5
+ } from "../chunk-ZEY2XUJN.js";
6
+ import "../chunk-JJPB6EOZ.js";
6
7
  import "../chunk-WRNH5C3U.js";
7
8
  import "../chunk-5EPNFDT5.js";
8
9
  import "../chunk-A2RZR3U4.js";
9
- import "../chunk-R7Z5ALYI.js";
10
- import "../chunk-JJPB6EOZ.js";
11
10
  import "../chunk-SDZQJTJW.js";
12
11
  import "../chunk-352FGP6W.js";
12
+ import "../chunk-R7Z5ALYI.js";
13
13
  import "../chunk-RFIXKATC.js";
14
14
  export {
15
15
  FederationConflictError,
package/dist/generate.cjs CHANGED
@@ -112,7 +112,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
112
112
  var import_picocolors = __toESM(require("picocolors"), 1);
113
113
 
114
114
  // package.json
115
- var version = "5.0.0-beta.11";
115
+ var version = "5.0.0-beta.13";
116
116
 
117
117
  // src/constants.ts
118
118
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-WM4QYMIA.js";
4
- import "./chunk-LQZ7IG7B.js";
5
- import "./chunk-MFEMKQZ6.js";
3
+ } from "./chunk-T75DOVFP.js";
4
+ import "./chunk-XA5W6DXX.js";
5
+ import "./chunk-BO2HHVZ3.js";
6
6
  import "./chunk-RFIXKATC.js";
7
7
  export {
8
8
  generate
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio-fonts.css";
2
+ import * as dependency from "@eventcatalog/visualiser/studio-fonts.css";
3
+ export default dependency.default;
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio.css";
2
+ import * as dependency from "@eventcatalog/visualiser/studio.css";
3
+ export default dependency.default;
@@ -0,0 +1,3 @@
1
+ export * from "@eventcatalog/visualiser/studio";
2
+ import * as dependency from "@eventcatalog/visualiser/studio";
3
+ export default dependency.default;
@@ -21,6 +21,9 @@
21
21
  "@eventcatalog/sdk": "@eventcatalog__sdk.mjs",
22
22
  "@eventcatalog/visualiser": "@eventcatalog__visualiser.mjs",
23
23
  "@eventcatalog/visualiser/layout": "@eventcatalog__visualiser__layout.mjs",
24
+ "@eventcatalog/visualiser/studio": "@eventcatalog__visualiser__studio.mjs",
25
+ "@eventcatalog/visualiser/studio-fonts.css": "@eventcatalog__visualiser__studio-fonts.css.mjs",
26
+ "@eventcatalog/visualiser/studio.css": "@eventcatalog__visualiser__studio.css.mjs",
24
27
  "@eventcatalog/visualiser/styles-core.css": "@eventcatalog__visualiser__styles-core.css.mjs",
25
28
  "@fontsource/inter": "@fontsource__inter.mjs",
26
29
  "@fontsource/inter/400.css": "@fontsource__inter__400.css.mjs",
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(cli_logger_exports);
36
36
  var import_picocolors = __toESM(require("picocolors"), 1);
37
37
 
38
38
  // package.json
39
- var version = "5.0.0-beta.11";
39
+ var version = "5.0.0-beta.13";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "../chunk-LQZ7IG7B.js";
4
- import "../chunk-MFEMKQZ6.js";
3
+ } from "../chunk-XA5W6DXX.js";
4
+ import "../chunk-BO2HHVZ3.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -29,6 +29,8 @@ const CHAT_PANEL_STYLES = `
29
29
  }
30
30
  .ec-chat-surface { font-weight: 400; }
31
31
  .ec-chat-avatar { background: rgb(var(--ec-accent) / .06); animation: ec-chat-breathe 5s ease-in-out infinite; }
32
+ /* The closed panel stays on the page (off screen): a running animation there still costs every frame */
33
+ .ec-chat-surface[aria-hidden='true'] .ec-chat-avatar { animation-play-state: paused; }
32
34
  .ec-chat-suggestion { width: fit-content; max-width: 100%; transition: background 180ms, transform 180ms; }
33
35
  .ec-chat-suggestion:hover { transform: translateX(3px); }
34
36
  .ec-chat-message { animation: fadeInUp 280ms ease-out both; }
@@ -12,10 +12,16 @@
12
12
  * CSS ships in the page head and survives ClientRouter navigations (see NodeGraph.astro).
13
13
  */
14
14
 
15
- import { useCallback, lazy, Suspense } from 'react';
15
+ import { useCallback, useState, lazy, Suspense } from 'react';
16
16
  import type { Node, Edge } from '@xyflow/react';
17
- import type { FlowGroupBy } from '@eventcatalog/visualiser';
17
+ import type { FlowGroupBy, OpenInStudioRequest } from '@eventcatalog/visualiser';
18
18
  import { buildUrl } from '@utils/url-builder';
19
+ import { createCanvasThroughApi } from '@features/studio/api/client';
20
+ import { getStoredName } from '@features/studio/identity';
21
+
22
+ // Studio's canvas code (what turns a diagram into a canvas, and the dialog asking for its name) is only loaded when a
23
+ // diagram is opened in Studio: every page with a diagram would load it otherwise, with Studio on or not
24
+ const OpenInStudioDialog = lazy(() => import('@features/studio/components/OpenInStudioDialog'));
19
25
 
20
26
  const NodeGraph = lazy(() =>
21
27
  import('@eventcatalog/visualiser').then((module) => ({ default: module.NodeGraph }))
@@ -57,9 +63,11 @@ interface AstroNodeGraphProps {
57
63
  preferenceScope?: string;
58
64
  // Group a flow's steps into swimlanes to start with
59
65
  swimlanes?: FlowGroupBy;
66
+ // The Studio API's address, when Studio is on: the menu can then start a canvas from the diagram
67
+ studioApiUrl?: string;
60
68
  }
61
69
 
62
- const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: AstroNodeGraphProps) => {
70
+ const AstroNodeGraph = ({ isDevMode = false, resourceKey, studioApiUrl, ...otherProps }: AstroNodeGraphProps) => {
63
71
  // Astro-specific navigation handler
64
72
  const handleNavigate = useCallback((url: string) => {
65
73
  // Use window.location for navigation since we can't import astro:transitions/client in a React component
@@ -108,6 +116,30 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: Astro
108
116
  }
109
117
  }, []);
110
118
 
119
+ // Opening the diagram in Studio: asks what to call the canvas, then makes it with what the diagram shows and opens
120
+ // it (in this tab) at the level shown. What it shows is only taken once it's named (laying a level out can take a
121
+ // moment), and anything that goes wrong is shown in the dialog.
122
+ const [toOpen, setToOpen] = useState<OpenInStudioRequest | null>(null);
123
+ const closeOpenInStudio = useCallback(() => setToOpen(null), []);
124
+ const openInStudio = useCallback(
125
+ async (title: string | undefined) => {
126
+ if (!studioApiUrl || !toOpen) return;
127
+ const snapshot = await toOpen.getSnapshot();
128
+ const { canvasFromVisualiser } = await import('@features/studio/from-visualiser');
129
+ const { nodes, edges, levels } = canvasFromVisualiser(snapshot);
130
+ if (nodes.length === 0) throw new Error('Nothing on this diagram can go on a canvas yet');
131
+ const canvas = await createCanvasThroughApi(studioApiUrl, {
132
+ title,
133
+ createdBy: getStoredName() ?? undefined,
134
+ nodes,
135
+ edges,
136
+ levels,
137
+ });
138
+ window.location.assign(snapshot.level === 3 ? canvas.url : `${canvas.url}?level=${snapshot.level}`);
139
+ },
140
+ [studioApiUrl, toOpen]
141
+ );
142
+
111
143
  return (
112
144
  <Suspense fallback={<div>Loading graph...</div>}>
113
145
  <NodeGraph
@@ -118,7 +150,14 @@ const AstroNodeGraph = ({ isDevMode = false, resourceKey, ...otherProps }: Astro
118
150
  onBuildUrl={handleBuildUrl}
119
151
  onSaveLayout={handleSaveLayout}
120
152
  onResetLayout={handleResetLayout}
153
+ onOpenInStudio={studioApiUrl ? setToOpen : undefined}
121
154
  />
155
+ {toOpen && (
156
+ // Its own, so the diagram isn't swapped for "Loading graph..." while the dialog loads
157
+ <Suspense fallback={null}>
158
+ <OpenInStudioDialog title={toOpen.title} onOpen={openInStudio} onClose={closeOpenInStudio} />
159
+ </Suspense>
160
+ )}
122
161
  </Suspense>
123
162
  );
124
163
  };
@@ -31,11 +31,14 @@ import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
31
31
  import { getNodesAndEdges as getNodesAndEdgesForContainer } from '@utils/node-graphs/container-node-graph';
32
32
  import { getNodesAndEdges as getNodesAndEdgesForChannel } from '@utils/node-graphs/channel-node-graph';
33
33
  import config from '@config';
34
- import { isEventCatalogChatVisible, isDevMode } from '@utils/feature';
34
+ import { isEventCatalogChatVisible, isDevMode, isCanvasEnabled } from '@utils/feature';
35
+ import { CANVASES_API_PATH } from '@features/studio/api/canvases-api';
35
36
  import { loadSavedLayout, applyLayoutToNodes, buildResourceKey } from '@utils/node-graphs/layout-persistence';
36
37
  import { compactVisualiserGraph } from '@utils/node-graphs/compact-visualiser-graph';
37
38
 
38
39
  const isChatEnabled = isEventCatalogChatVisible();
40
+ // With Studio on, the menu can start a canvas from the diagram
41
+ const studioApiUrl = isCanvasEnabled() ? buildUrl(CANVASES_API_PATH, true) : undefined;
39
42
 
40
43
  interface Props {
41
44
  id: string;
@@ -257,6 +260,7 @@ if (overview && levelsOverview) {
257
260
  hiddenMessagesGraph={hiddenMessagesGraph}
258
261
  preferenceScope={collection}
259
262
  swimlanes={lanes}
263
+ studioApiUrl={studioApiUrl}
260
264
  />
261
265
  </div>
262
266
 
@@ -22,12 +22,19 @@
22
22
  opacity: 1;
23
23
  }
24
24
 
25
+ /* On every page, hidden until a navigation takes a while: paused until then (a running animation costs a style
26
+ recalc and paint on every frame, even when it can't be seen) */
25
27
  .navigation-progress__bar {
26
28
  width: 35%;
27
29
  height: 100%;
28
30
  background: rgb(var(--ec-accent));
29
31
  box-shadow: 0 0 10px rgb(var(--ec-accent) / 0.55);
30
32
  animation: navigation-progress 1.1s ease-in-out infinite;
33
+ animation-play-state: paused;
34
+ }
35
+
36
+ #navigation-progress[data-visible='true'] .navigation-progress__bar {
37
+ animation-play-state: running;
31
38
  }
32
39
 
33
40
  :global([data-navigation-pending='true']) {
@@ -6,7 +6,8 @@
6
6
  import { useEffect, useRef, useState, type FormEvent, type KeyboardEvent, type RefObject } from 'react';
7
7
  import type { Node } from '@xyflow/react';
8
8
  import { Check, Network, SendHorizontal, X } from 'lucide-react';
9
- import type { ArchitectureDiagramCollection } from '@utils/node-graphs/architecture-diagram-types';
9
+ import { isArchitectureDiagramCollection } from '@utils/node-graphs/architecture-diagram-types';
10
+ import { getNodeCatalogResource, getNodeResourceDetails } from '@utils/node-graphs/node-resource';
10
11
  import type { DiagramLink } from './links';
11
12
  import { RESOURCE_TYPE_LABELS } from '../shared/resource-types';
12
13
 
@@ -36,53 +37,13 @@ const NODE_TYPE_LABELS: Record<string, string> = {
36
37
  externalSystem: 'External system',
37
38
  };
38
39
 
39
- // Where each node type keeps the resource it shows
40
- const RESOURCE_DATA_KEYS = [
41
- 'service',
42
- 'agent',
43
- 'message',
44
- 'channel',
45
- 'data',
46
- 'dataProduct',
47
- 'flow',
48
- 'entity',
49
- 'domain',
50
- 'system',
51
- 'custom',
52
- ];
53
-
54
- // The collection of each node type the architecture diagram tool can draw a diagram for
55
- const DIAGRAM_COLLECTIONS: Record<string, ArchitectureDiagramCollection> = {
56
- services: 'services',
57
- agents: 'agents',
58
- events: 'events',
59
- commands: 'commands',
60
- queries: 'queries',
61
- flows: 'flows',
62
- data: 'containers',
63
- containers: 'containers',
64
- 'data-products': 'data-products',
65
- domains: 'domains',
66
- 'context-domain': 'domains',
67
- 'domain-group': 'domains',
68
- systems: 'systems',
69
- 'system-group': 'systems',
70
- };
71
-
72
- // Domain and system boundaries only have their catalog id in the node id: {kind}-group-{id}-{version}
73
- const catalogIdOfGroup = (node: Node, version?: string) => {
74
- const match = node.id.match(/^(?:domain|system)-group-(.+)$/);
75
- if (!match) return undefined;
76
- return version && match[1].endsWith(`-${version}`) ? match[1].slice(0, -(version.length + 1)) : match[1];
77
- };
78
-
79
40
  export function describeNode(node: Node): SelectedNode {
80
41
  const data = (node.data ?? {}) as Record<string, any>;
81
- const resource = RESOURCE_DATA_KEYS.map((key) => data[key]).find(Boolean) ?? data;
82
- const details = resource?.data ?? resource;
42
+ const details = (getNodeResourceDetails(node) ?? data) as Record<string, any>;
83
43
  const version: string | undefined = details?.version;
84
- const id: string = details?.id ?? catalogIdOfGroup(node, version) ?? node.id;
85
- const collection = DIAGRAM_COLLECTIONS[node.type ?? ''];
44
+ const id: string = details?.id ?? node.id;
45
+ const resource = getNodeCatalogResource(node);
46
+ const collection = resource && isArchitectureDiagramCollection(resource.collection) ? resource.collection : undefined;
86
47
 
87
48
  return {
88
49
  nodeId: node.id,
@@ -1,6 +1,6 @@
1
1
  // Shared by the canvas MCP App (client) and the MCP server: no server-only imports here
2
2
  import type { CatalogRelation, CatalogResource } from '../../../studio/catalog-resources';
3
- import type { CanvasStatus } from '../../../studio/canvas-doc';
3
+ import { type CanvasStatus } from '@eventcatalog/visualiser/studio';
4
4
 
5
5
  export const CANVAS_RESOURCE_URI = 'ui://eventcatalog/canvas.html';
6
6
  /** Key of the payload in openCanvas results' `_meta` */
@@ -40,8 +40,8 @@ export type CanvasView = {
40
40
  canvasUrl: string;
41
41
  /** The EventCatalog MCP server, for "Connect your agent" */
42
42
  mcpUrl: string;
43
- /** What to call the user on the canvas, when the agent knows their name */
44
- userName?: string;
43
+ /** The chat's agent: the view joins the canvas as it (its name, colour and logo) */
44
+ agent?: { name: string; color: string };
45
45
  };
46
46
 
47
47
  export type CanvasCatalog = { resources: CatalogResource[]; relations: CatalogRelation[] };
@@ -4,10 +4,12 @@
4
4
  */
5
5
  @import 'tailwindcss' source(none);
6
6
  @import '../../../../styles/theme.css';
7
- @import '../../../studio/studio.css';
7
+ @import '@eventcatalog/visualiser/studio.css';
8
8
 
9
9
  @source './*.tsx';
10
10
  @source '../../../studio/components/*.{ts,tsx}';
11
+ /* Studio's shared canvas (nodes, comments, hotspots), from the visualiser in this repo */
12
+ @source '../../../../../../../visualiser/src/studio';
11
13
 
12
14
  body {
13
15
  margin: 0;
@@ -15,7 +15,8 @@ import type { App } from '@modelcontextprotocol/ext-apps';
15
15
  import styles from './styles.css?inline';
16
16
  import visualiserStyles from '@eventcatalog/visualiser/styles.css?inline';
17
17
  import StudioDesigner, { type SelectedNode } from '@features/studio/components/StudioDesigner';
18
- import { CANVAS_STATUS_LOOK, STATUS } from '@features/studio/components/status';
18
+ import { getAgent } from '@features/studio/agents';
19
+ import { CANVAS_STATUS_LOOK, STATUS } from '@eventcatalog/visualiser/studio';
19
20
  import { getToolResultPayload, mountView, useMcpAppView } from '../shared/app-view';
20
21
  import {
21
22
  CANVAS_CATALOG_TOOL,
@@ -212,10 +213,10 @@ function CanvasApp() {
212
213
  const iconButton =
213
214
  'flex items-center gap-1 rounded-md px-2 py-1 text-xs text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.5)]';
214
215
 
215
- // No join form inside a chat: use the name the agent passed, or name them after the chat they're in
216
+ // No join form inside a chat: it joins as the chat's agent (e.g. ChatGPT or Claude, with its logo), as the agent
217
+ // working on the canvas does, else as the chat it's in
216
218
  const hostName = app?.getHostVersion()?.name;
217
- const userName = (view: CanvasView) =>
218
- view.userName ?? `${hostName ? hostName.replace(/^\w/, (letter) => letter.toUpperCase()) : 'Chat'} user`;
219
+ const agentOf = (view: CanvasView) => view.agent ?? getAgent(undefined, hostName);
219
220
 
220
221
  return (
221
222
  <div className="flex flex-col" style={{ height: fullscreen ? '100vh' : INLINE_HEIGHT }}>
@@ -255,11 +256,12 @@ function CanvasApp() {
255
256
  shareUrl={canvas.canvasUrl}
256
257
  mcpUrl={canvas.mcpUrl}
257
258
  syncViaTools={syncViaTools}
258
- defaultName={userName(canvas)}
259
+ asAgent={agentOf(canvas)}
259
260
  resources={catalog.resources}
260
261
  relations={catalog.relations}
261
262
  onSelectionChange={setSelection}
262
263
  followChanges
264
+ paletteCollapsed
263
265
  />
264
266
  ) : (
265
267
  <CanvasPicker