@eventcatalog/core 3.2.2 → 3.3.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 (48) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-7YZYT44Y.js → chunk-I4CMEOEN.js} +1 -1
  6. package/dist/{chunk-34AD2NAO.js → chunk-NGKYYZZP.js} +1 -1
  7. package/dist/{chunk-AETVSFIG.js → chunk-OAUYXPXT.js} +1 -1
  8. package/dist/{chunk-6OFLYNWB.js → chunk-QZF5ZYJB.js} +1 -1
  9. package/dist/{chunk-JPKOTGEV.js → chunk-UPSN5H7S.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +9 -0
  19. package/eventcatalog/src/components/ChatPanel/ChatPanelButton.tsx +11 -1
  20. package/eventcatalog/src/components/CopyAsMarkdown.tsx +47 -28
  21. package/eventcatalog/src/content.config.ts +18 -0
  22. package/eventcatalog/src/enterprise/ai/chat-api.ts +24 -2
  23. package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +57 -0
  24. package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +267 -0
  25. package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +411 -0
  26. package/eventcatalog/src/pages/diagrams/[id]/[version].mdx.ts +47 -0
  27. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
  28. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +3 -2
  29. package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +5 -1
  30. package/eventcatalog/src/pages/docs/[type]/[id]/language.mdx.ts +2 -1
  31. package/eventcatalog/src/pages/docs/custom/[...path].mdx.ts +2 -2
  32. package/eventcatalog/src/pages/docs/teams/[id].md.ts +3 -2
  33. package/eventcatalog/src/pages/docs/teams/[id].mdx.ts +3 -3
  34. package/eventcatalog/src/pages/docs/users/[id].md.ts +3 -2
  35. package/eventcatalog/src/pages/docs/users/[id].mdx.ts +3 -3
  36. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +20 -4
  37. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +20 -12
  38. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +1 -1
  39. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +20 -4
  40. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +18 -6
  41. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +20 -0
  42. package/eventcatalog/src/stores/sidebar-store/state.ts +34 -6
  43. package/eventcatalog/src/types/index.ts +4 -2
  44. package/eventcatalog/src/utils/collections/diagrams.ts +64 -0
  45. package/eventcatalog/src/utils/collections/util.ts +2 -0
  46. package/eventcatalog/src/utils/feature.ts +4 -2
  47. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  48. package/package.json +2 -2
@@ -0,0 +1,47 @@
1
+ // This file exposes the markdown for diagrams in the URL
2
+ // For example http://localhost:3000/diagrams/target-architecture/1.0.0 loads the Page
3
+ // and http://localhost:3000/diagrams/target-architecture/1.0.0.mdx loads the markdown
4
+ // This is used for LLMs to load the markdown for diagrams (llms.txt)
5
+
6
+ import type { APIRoute } from 'astro';
7
+ import { getCollection } from 'astro:content';
8
+ import fs from 'fs';
9
+ import { isLLMSTxtEnabled, isSSR } from '@utils/feature';
10
+
11
+ const diagrams = await getCollection('diagrams');
12
+
13
+ export async function getStaticPaths() {
14
+ // Just return empty array if LLMs are not enabled
15
+ if (!isLLMSTxtEnabled()) {
16
+ return [];
17
+ }
18
+
19
+ return diagrams.map((diagram) => ({
20
+ params: { id: diagram.data.id, version: diagram.data.version },
21
+ props: { content: diagram },
22
+ }));
23
+ }
24
+
25
+ export const GET: APIRoute = async ({ params, props }) => {
26
+ // Just return empty array if LLMs are not enabled
27
+ if (!isLLMSTxtEnabled()) {
28
+ return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
29
+ }
30
+
31
+ if (isSSR()) {
32
+ // For SSR mode, find the diagram and read its file
33
+ const diagram = diagrams.find((d) => d.data.id === params.id && d.data.version === params.version);
34
+ if (!diagram?.filePath) {
35
+ return new Response('Not found', { status: 404 });
36
+ }
37
+ const file = fs.readFileSync(diagram.filePath, 'utf8');
38
+ return new Response(file, { status: 200 });
39
+ } else {
40
+ if (props?.content?.filePath) {
41
+ const file = fs.readFileSync(props.content.filePath, 'utf8');
42
+ return new Response(file, { status: 200 });
43
+ }
44
+ }
45
+
46
+ return new Response('Not found', { status: 404 });
47
+ };
@@ -305,6 +305,7 @@ nodeGraphs.push({
305
305
  markdownDownloadEnabled={isMarkdownDownloadEnabled()}
306
306
  rssFeedEnabled={isRSSEnabled()}
307
307
  editUrl={editUrl}
308
+ preferChatAsDefault={isEventCatalogChatEnabled()}
308
309
  />
309
310
  </div>
310
311
  </div>
@@ -7,6 +7,7 @@ import { getCollection } from 'astro:content';
7
7
  import { getEntities } from '@utils/collections/entities';
8
8
  import config from '@config';
9
9
  import fs from 'fs';
10
+ import { isLLMSTxtEnabled } from '@utils/feature';
10
11
 
11
12
  const events = await getCollection('events');
12
13
  const commands = await getCollection('commands');
@@ -19,7 +20,7 @@ const containers = await getCollection('containers');
19
20
  const entities = await getEntities();
20
21
  export async function getStaticPaths() {
21
22
  // Just return empty array if LLMs are not enabled
22
- if (!config.llmsTxt?.enabled) {
23
+ if (!isLLMSTxtEnabled()) {
23
24
  return [];
24
25
  }
25
26
 
@@ -46,7 +47,7 @@ export async function getStaticPaths() {
46
47
 
47
48
  export const GET: APIRoute = async ({ params, props }) => {
48
49
  // Just return empty array if LLMs are not enabled
49
- if (!config.llmsTxt?.enabled) {
50
+ if (!isLLMSTxtEnabled()) {
50
51
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
51
52
  }
52
53
 
@@ -21,7 +21,7 @@ import utils from '@eventcatalog/sdk';
21
21
 
22
22
  export async function getStaticPaths() {
23
23
  // Just return empty array if LLMs are not enabled
24
- if (!config.llmsTxt?.enabled) {
24
+ if (!isLLMSTxtEnabled()) {
25
25
  return [];
26
26
  }
27
27
  const collections = {
@@ -45,11 +45,15 @@ export async function getStaticPaths() {
45
45
  }
46
46
 
47
47
  export const GET: APIRoute = async ({ params, props }) => {
48
+ console.log('props', props);
49
+
48
50
  // Just return empty array if LLMs are not enabled
49
51
  if (!isLLMSTxtEnabled()) {
50
52
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
51
53
  }
52
54
 
55
+ console.log('params', params);
56
+
53
57
  if (isSSR()) {
54
58
  const { getResourcePath } = utils(process.env.PROJECT_DIR ?? '');
55
59
  const filePath = await getResourcePath(process.env.PROJECT_DIR ?? '', params.id ?? '', params.version ?? '');
@@ -3,6 +3,7 @@ import type { CollectionEntry } from 'astro:content';
3
3
  import type { APIRoute } from 'astro';
4
4
  import config from '@config';
5
5
  import fs from 'fs';
6
+ import { isLLMSTxtEnabled } from '@utils/feature';
6
7
 
7
8
  export async function getStaticPaths() {
8
9
  const domains = await getDomains({ getAllVersions: false });
@@ -25,7 +26,7 @@ export async function getStaticPaths() {
25
26
 
26
27
  export const GET: APIRoute = async ({ params, props }) => {
27
28
  // Just return empty array if LLMs are not enabled
28
- if (!config.llmsTxt?.enabled) {
29
+ if (!isLLMSTxtEnabled()) {
29
30
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
30
31
  }
31
32
 
@@ -4,8 +4,8 @@
4
4
 
5
5
  import type { APIRoute, GetStaticPaths } from 'astro';
6
6
  import { getCollection } from 'astro:content';
7
- import config from '@config';
8
7
  import fs from 'fs';
8
+ import { isLLMSTxtEnabled } from '@utils/feature';
9
9
 
10
10
  export const getStaticPaths = (async () => {
11
11
  const docs = await getCollection('customPages');
@@ -19,7 +19,7 @@ export const getStaticPaths = (async () => {
19
19
 
20
20
  export const GET: APIRoute = async ({ params, props }) => {
21
21
  // Just return empty array if LLMs are not enabled
22
- if (!config.llmsTxt?.enabled) {
22
+ if (!isLLMSTxtEnabled()) {
23
23
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
24
24
  }
25
25
 
@@ -6,12 +6,13 @@ import type { APIRoute } from 'astro';
6
6
  import { getCollection } from 'astro:content';
7
7
  import config from '@config';
8
8
  import fs from 'fs';
9
+ import { isLLMSTxtEnabled } from '@utils/feature';
9
10
 
10
11
  const teams = await getCollection('teams');
11
12
 
12
13
  export async function getStaticPaths() {
13
14
  // Just return empty array if LLMs are not enabled
14
- if (!config.llmsTxt?.enabled) {
15
+ if (!isLLMSTxtEnabled()) {
15
16
  return [];
16
17
  }
17
18
 
@@ -23,7 +24,7 @@ export async function getStaticPaths() {
23
24
 
24
25
  export const GET: APIRoute = async ({ params, props }) => {
25
26
  // Just return empty array if LLMs are not enabled
26
- if (!config.llmsTxt?.enabled) {
27
+ if (!isLLMSTxtEnabled()) {
27
28
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
28
29
  }
29
30
 
@@ -4,14 +4,14 @@
4
4
 
5
5
  import type { APIRoute } from 'astro';
6
6
  import { getCollection } from 'astro:content';
7
- import config from '@config';
7
+ import { isLLMSTxtEnabled } from '@utils/feature';
8
8
  import fs from 'fs';
9
9
 
10
10
  const teams = await getCollection('teams');
11
11
 
12
12
  export async function getStaticPaths() {
13
13
  // Just return empty array if LLMs are not enabled
14
- if (!config.llmsTxt?.enabled) {
14
+ if (!isLLMSTxtEnabled()) {
15
15
  return [];
16
16
  }
17
17
 
@@ -23,7 +23,7 @@ export async function getStaticPaths() {
23
23
 
24
24
  export const GET: APIRoute = async ({ params, props }) => {
25
25
  // Just return empty array if LLMs are not enabled
26
- if (!config.llmsTxt?.enabled) {
26
+ if (!isLLMSTxtEnabled()) {
27
27
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
28
28
  }
29
29
 
@@ -6,12 +6,13 @@ import type { APIRoute } from 'astro';
6
6
  import { getCollection } from 'astro:content';
7
7
  import config from '@config';
8
8
  import fs from 'fs';
9
+ import { isLLMSTxtEnabled } from '@utils/feature';
9
10
 
10
11
  const users = await getCollection('users');
11
12
 
12
13
  export async function getStaticPaths() {
13
14
  // Just return empty array if LLMs are not enabled
14
- if (!config.llmsTxt?.enabled) {
15
+ if (!isLLMSTxtEnabled()) {
15
16
  return [];
16
17
  }
17
18
 
@@ -23,7 +24,7 @@ export async function getStaticPaths() {
23
24
 
24
25
  export const GET: APIRoute = async ({ params, props }) => {
25
26
  // Just return empty array if LLMs are not enabled
26
- if (!config.llmsTxt?.enabled) {
27
+ if (!isLLMSTxtEnabled()) {
27
28
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
28
29
  }
29
30
 
@@ -4,14 +4,14 @@
4
4
 
5
5
  import type { APIRoute } from 'astro';
6
6
  import { getCollection } from 'astro:content';
7
- import config from '@config';
7
+ import { isLLMSTxtEnabled } from '@utils/feature';
8
8
  import fs from 'fs';
9
9
 
10
10
  const users = await getCollection('users');
11
11
 
12
12
  export async function getStaticPaths() {
13
13
  // Just return empty array if LLMs are not enabled
14
- if (!config.llmsTxt?.enabled) {
14
+ if (!isLLMSTxtEnabled()) {
15
15
  return [];
16
16
  }
17
17
 
@@ -23,7 +23,7 @@ export async function getStaticPaths() {
23
23
 
24
24
  export const GET: APIRoute = async ({ params, props }) => {
25
25
  // Just return empty array if LLMs are not enabled
26
- if (!config.llmsTxt?.enabled) {
26
+ if (!isLLMSTxtEnabled()) {
27
27
  return new Response('llms.txt is not enabled for this Catalog.', { status: 404 });
28
28
  }
29
29
 
@@ -1,16 +1,21 @@
1
1
  import type { CollectionEntry } from 'astro:content';
2
2
  import { buildUrl } from '@utils/url-builder';
3
- import type { NavNode, ChildRef } from './shared';
3
+ import type { NavNode, ChildRef, ResourceGroupContext } from './shared';
4
4
  import {
5
5
  buildQuickReferenceSection,
6
6
  buildOwnersSection,
7
7
  shouldRenderSideBarSection,
8
8
  buildRepositorySection,
9
9
  buildAttachmentsSection,
10
+ buildDiagramNavItems,
10
11
  } from './shared';
11
12
  import { isVisualiserEnabled } from '@utils/feature';
12
13
 
13
- export const buildContainerNode = (container: CollectionEntry<'containers'>, owners: any[]): NavNode => {
14
+ export const buildContainerNode = (
15
+ container: CollectionEntry<'containers'>,
16
+ owners: any[],
17
+ context: ResourceGroupContext
18
+ ): NavNode => {
14
19
  const servicesWritingToContainer = container.data.servicesThatWriteToContainer || [];
15
20
  const servicesReadingFromContainer = container.data.servicesThatReadFromContainer || [];
16
21
 
@@ -27,6 +32,11 @@ export const buildContainerNode = (container: CollectionEntry<'containers'>, own
27
32
 
28
33
  const renderRepository = container.data.repository && shouldRenderSideBarSection(container, 'repository');
29
34
 
35
+ // Diagrams
36
+ const containerDiagrams = container.data.diagrams || [];
37
+ const diagramNavItems = buildDiagramNavItems(containerDiagrams, context.diagrams);
38
+ const hasDiagrams = diagramNavItems.length > 0;
39
+
30
40
  return {
31
41
  type: 'item',
32
42
  title: container.data.name,
@@ -41,16 +51,22 @@ export const buildContainerNode = (container: CollectionEntry<'containers'>, own
41
51
  ]),
42
52
  renderVisualiser && {
43
53
  type: 'group',
44
- title: 'Architecture & Design',
54
+ title: 'Architecture',
45
55
  icon: 'Workflow',
46
56
  pages: [
47
57
  {
48
58
  type: 'item',
49
- title: 'Interaction Map',
59
+ title: 'Map',
50
60
  href: buildUrl(`/visualiser/containers/${container.data.id}/${container.data.version}`),
51
61
  },
52
62
  ],
53
63
  },
64
+ hasDiagrams && {
65
+ type: 'group',
66
+ title: 'Diagrams',
67
+ icon: 'FileImage',
68
+ pages: diagramNavItems,
69
+ },
54
70
  renderServicesWritingToContainer && {
55
71
  type: 'group',
56
72
  title: 'Services (Writes)',
@@ -8,6 +8,7 @@ import {
8
8
  shouldRenderSideBarSection,
9
9
  buildRepositorySection,
10
10
  buildAttachmentsSection,
11
+ buildDiagramNavItems,
11
12
  } from './shared';
12
13
  import { isVisualiserEnabled } from '@utils/feature';
13
14
 
@@ -35,6 +36,12 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
35
36
  const hasAttachments = domain.data.attachments && domain.data.attachments.length > 0;
36
37
 
37
38
  const renderRepository = domain.data.repository && shouldRenderSideBarSection(domain, 'repository');
39
+
40
+ // Diagrams
41
+ const domainDiagrams = domain.data.diagrams || [];
42
+ const diagramNavItems = buildDiagramNavItems(domainDiagrams, context.diagrams);
43
+ const hasDiagrams = diagramNavItems.length > 0;
44
+
38
45
  return {
39
46
  type: 'item',
40
47
  title: domain.data.name,
@@ -47,32 +54,33 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
47
54
  ]),
48
55
  {
49
56
  type: 'group',
50
- title: 'Architecture & Design',
57
+ title: 'Architecture',
51
58
  icon: 'Workflow',
52
59
  pages: [
53
60
  {
54
61
  type: 'item',
55
- title: 'Architecture Overview',
62
+ title: 'Overview',
56
63
  href: buildUrl(`/architecture/domains/${domain.data.id}/${domain.data.version}`),
57
64
  },
65
+ renderVisualiser && {
66
+ type: 'item',
67
+ title: 'Map',
68
+ href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
69
+ },
58
70
  renderEntities &&
59
71
  renderVisualiser && {
60
72
  type: 'item',
61
73
  title: 'Entity Map',
62
74
  href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/entity-map`),
63
75
  },
64
- renderVisualiser && {
65
- type: 'item',
66
- title: 'Interaction Map',
67
- href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
68
- },
69
- renderVisualiser && {
70
- type: 'item',
71
- title: 'Global Domain Map',
72
- href: buildUrl(`/visualiser/domain-integrations`),
73
- },
74
76
  ].filter(Boolean) as ChildRef[],
75
77
  },
78
+ hasDiagrams && {
79
+ type: 'group',
80
+ title: 'Diagrams',
81
+ icon: 'FileImage',
82
+ pages: diagramNavItems,
83
+ },
76
84
  renderSubDomains && {
77
85
  type: 'group',
78
86
  title: 'Subdomains',
@@ -14,7 +14,7 @@ export const buildFlowNode = (flow: CollectionEntry<'flows'>): NavNode => {
14
14
  buildQuickReferenceSection([{ title: 'Overview', href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}`) }]),
15
15
  {
16
16
  type: 'group',
17
- title: 'Architecture & Design',
17
+ title: 'Architecture',
18
18
  icon: 'Workflow',
19
19
  pages: [
20
20
  {
@@ -1,17 +1,22 @@
1
1
  import type { CollectionEntry } from 'astro:content';
2
2
  import { buildUrl } from '@utils/url-builder';
3
3
  import { getSchemaFormatFromURL } from '@utils/collections/schemas';
4
- import type { NavNode, ChildRef } from './shared';
4
+ import type { NavNode, ChildRef, ResourceGroupContext } from './shared';
5
5
  import {
6
6
  buildQuickReferenceSection,
7
7
  buildOwnersSection,
8
8
  shouldRenderSideBarSection,
9
9
  buildRepositorySection,
10
10
  buildAttachmentsSection,
11
+ buildDiagramNavItems,
11
12
  } from './shared';
12
13
  import { isVisualiserEnabled } from '@utils/feature';
13
14
 
14
- export const buildMessageNode = (message: CollectionEntry<'events' | 'commands' | 'queries'>, owners: any[]): NavNode => {
15
+ export const buildMessageNode = (
16
+ message: CollectionEntry<'events' | 'commands' | 'queries'>,
17
+ owners: any[],
18
+ context: ResourceGroupContext
19
+ ): NavNode => {
15
20
  const producers = message.data.producers || [];
16
21
  const consumers = message.data.consumers || [];
17
22
  const collection = message.collection;
@@ -35,6 +40,11 @@ export const buildMessageNode = (message: CollectionEntry<'events' | 'commands'
35
40
 
36
41
  const renderOwners = owners.length > 0 && shouldRenderSideBarSection(message, 'owners');
37
42
 
43
+ // Diagrams
44
+ const messageDiagrams = message.data.diagrams || [];
45
+ const diagramNavItems = buildDiagramNavItems(messageDiagrams, context.diagrams);
46
+ const hasDiagrams = diagramNavItems.length > 0;
47
+
38
48
  return {
39
49
  type: 'item',
40
50
  title: message.data.name,
@@ -49,16 +59,22 @@ export const buildMessageNode = (message: CollectionEntry<'events' | 'commands'
49
59
  ]),
50
60
  renderVisualiser && {
51
61
  type: 'group',
52
- title: 'Architecture & Design',
62
+ title: 'Architecture',
53
63
  icon: 'Workflow',
54
64
  pages: [
55
65
  {
56
66
  type: 'item',
57
- title: 'Interaction Map',
67
+ title: 'Map',
58
68
  href: buildUrl(`/visualiser/${collection}/${message.data.id}/${message.data.version}`),
59
69
  },
60
70
  ],
61
71
  },
72
+ hasDiagrams && {
73
+ type: 'group',
74
+ title: 'Diagrams',
75
+ icon: 'FileImage',
76
+ pages: diagramNavItems,
77
+ },
62
78
  hasSchema && {
63
79
  type: 'group',
64
80
  title: `API & Contracts`,
@@ -1,7 +1,7 @@
1
1
  import type { CollectionEntry } from 'astro:content';
2
2
  import { buildUrl } from '@utils/url-builder';
3
3
  import { getSpecificationsForService } from '@utils/collections/services';
4
- import type { NavNode, ChildRef } from './shared';
4
+ import type { NavNode, ChildRef, ResourceGroupContext } from './shared';
5
5
  import {
6
6
  uniqueBy,
7
7
  buildQuickReferenceSection,
@@ -10,11 +10,12 @@ import {
10
10
  buildResourceGroupSections,
11
11
  buildRepositorySection,
12
12
  buildAttachmentsSection,
13
+ buildDiagramNavItems,
13
14
  } from './shared';
14
15
  import { isVisualiserEnabled } from '@utils/feature';
15
16
  import { pluralizeMessageType } from '@utils/collections/messages';
16
17
 
17
- export const buildServiceNode = (service: CollectionEntry<'services'>, owners: any[], context: any): NavNode => {
18
+ export const buildServiceNode = (service: CollectionEntry<'services'>, owners: any[], context: ResourceGroupContext): NavNode => {
18
19
  const sendsMessages = service.data.sends || [];
19
20
  const receivesMessages = service.data.receives || [];
20
21
  const serviceEntities = service.data.entities || [];
@@ -44,6 +45,11 @@ export const buildServiceNode = (service: CollectionEntry<'services'>, owners: a
44
45
  const renderOwners = owners.length > 0 && shouldRenderSideBarSection(service, 'owners');
45
46
  const renderRepository = service.data.repository && shouldRenderSideBarSection(service, 'repository');
46
47
 
48
+ // Diagrams
49
+ const serviceDiagrams = service.data.diagrams || [];
50
+ const diagramNavItems = buildDiagramNavItems(serviceDiagrams, context.diagrams);
51
+ const hasDiagrams = diagramNavItems.length > 0;
52
+
47
53
  return {
48
54
  type: 'item',
49
55
  title: service.data.name,
@@ -55,17 +61,17 @@ export const buildServiceNode = (service: CollectionEntry<'services'>, owners: a
55
61
  ]),
56
62
  {
57
63
  type: 'group',
58
- title: 'Architecture & Design',
64
+ title: 'Architecture',
59
65
  icon: 'Workflow',
60
66
  pages: [
61
67
  {
62
68
  type: 'item',
63
- title: 'Architecture Overview',
69
+ title: 'Overview',
64
70
  href: buildUrl(`/architecture/services/${service.data.id}/${service.data.version}`),
65
71
  },
66
72
  renderVisualiser && {
67
73
  type: 'item',
68
- title: 'Interaction Map',
74
+ title: 'Map',
69
75
  href: buildUrl(`/visualiser/services/${service.data.id}/${service.data.version}`),
70
76
  },
71
77
  renderVisualiser &&
@@ -74,7 +80,13 @@ export const buildServiceNode = (service: CollectionEntry<'services'>, owners: a
74
80
  title: 'Data Map',
75
81
  href: buildUrl(`/visualiser/services/${service.data.id}/${service.data.version}/data`),
76
82
  },
77
- ],
83
+ ].filter(Boolean) as ChildRef[],
84
+ },
85
+ hasDiagrams && {
86
+ type: 'group',
87
+ title: 'Diagrams',
88
+ icon: 'FileImage',
89
+ pages: diagramNavItems,
78
90
  },
79
91
  renderSpecifications && {
80
92
  type: 'group',
@@ -54,6 +54,7 @@ export type ResourceGroupContext = {
54
54
  queries: CollectionEntry<'queries'>[];
55
55
  flows: CollectionEntry<'flows'>[];
56
56
  containers: CollectionEntry<'containers'>[];
57
+ diagrams: CollectionEntry<'diagrams'>[];
57
58
  };
58
59
 
59
60
  export const buildQuickReferenceSection = (items: { title: string; href: string }[]): NavNode => ({
@@ -158,3 +159,22 @@ export const shouldRenderSideBarSection = (resource: any, section: string) => {
158
159
  }
159
160
  return resource.data.detailsPanel[section]?.visible ?? true;
160
161
  };
162
+
163
+ export const buildDiagramNavItems = (
164
+ diagrams: Array<{ id: string; version?: string }> | undefined,
165
+ allDiagrams: CollectionEntry<'diagrams'>[]
166
+ ): NavNode[] => {
167
+ if (!diagrams || diagrams.length === 0) return [];
168
+
169
+ return diagrams.map((ref) => {
170
+ const diagram = allDiagrams.find(
171
+ (d) => d.data.id === ref.id && (ref.version === 'latest' || !ref.version || d.data.version === ref.version)
172
+ );
173
+ const version = diagram?.data.version || ref.version || 'latest';
174
+ return {
175
+ type: 'item' as const,
176
+ title: diagram?.data.name || ref.id,
177
+ href: buildUrl(`/diagrams/${ref.id}/${version}`),
178
+ };
179
+ });
180
+ };
@@ -6,6 +6,7 @@ import { getOwner } from '@utils/collections/owners';
6
6
  import { getFlows } from '@utils/collections/flows';
7
7
  import { getUsers } from '@utils/collections/users';
8
8
  import { getTeams } from '@utils/collections/teams';
9
+ import { getDiagrams } from '@utils/collections/diagrams';
9
10
  import { buildUrl } from '@utils/url-builder';
10
11
  import type { NavigationData, NavNode, ChildRef } from './builders/shared';
11
12
  import { buildDomainNode } from './builders/domain';
@@ -30,7 +31,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
30
31
  return memoryCache;
31
32
  }
32
33
 
33
- const [domains, services, { events, commands, queries }, containers, flows, users, teams, designs, channels] =
34
+ const [domains, services, { events, commands, queries }, containers, flows, users, teams, designs, channels, diagrams] =
34
35
  await Promise.all([
35
36
  getDomains({ getAllVersions: false, includeServicesInSubdomains: false }),
36
37
  getServices({ getAllVersions: false }),
@@ -41,6 +42,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
41
42
  getTeams(),
42
43
  getDesigns(),
43
44
  getChannels({ getAllVersions: false }),
45
+ getDiagrams({ getAllVersions: false }),
44
46
  ]);
45
47
 
46
48
  // Calculate derived lists to avoid extra fetches
@@ -57,6 +59,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
57
59
  queries,
58
60
  flows,
59
61
  containers,
62
+ diagrams,
60
63
  };
61
64
 
62
65
  // Process all domains with their owners first (async)
@@ -136,9 +139,9 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
136
139
  (acc, { message, owners }) => {
137
140
  const type = pluralizeMessageType(message as any);
138
141
 
139
- acc[`${type}:${message.data.id}:${message.data.version}`] = buildMessageNode(message, owners);
142
+ acc[`${type}:${message.data.id}:${message.data.version}`] = buildMessageNode(message, owners, context);
140
143
  if (message.data.latestVersion === message.data.version) {
141
- acc[`${type}:${message.data.id}`] = buildMessageNode(message, owners);
144
+ acc[`${type}:${message.data.id}`] = buildMessageNode(message, owners, context);
142
145
  }
143
146
  return acc;
144
147
  },
@@ -147,9 +150,9 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
147
150
 
148
151
  const containerNodes = containerWithOwners.reduce(
149
152
  (acc, { container, owners }) => {
150
- acc[`container:${container.data.id}:${container.data.version}`] = buildContainerNode(container, owners);
153
+ acc[`container:${container.data.id}:${container.data.version}`] = buildContainerNode(container, owners, context);
151
154
  if (container.data.latestVersion === container.data.version) {
152
- acc[`container:${container.data.id}`] = buildContainerNode(container, owners);
155
+ acc[`container:${container.data.id}`] = buildContainerNode(container, owners, context);
153
156
  }
154
157
  return acc;
155
158
  },
@@ -383,6 +386,25 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
383
386
  ...(allList ? { 'list:all': allList as NavNode } : {}),
384
387
  };
385
388
 
389
+ // System-level views (only show if visualiser is enabled and there are domains)
390
+ const systemNode: Record<string, NavNode> = {};
391
+ const visualiserEnabled = config?.visualiser?.enabled !== false;
392
+
393
+ if (visualiserEnabled && domains.length > 0) {
394
+ systemNode['list:system'] = {
395
+ type: 'group',
396
+ title: 'System',
397
+ icon: 'Globe',
398
+ pages: [
399
+ {
400
+ type: 'item',
401
+ title: 'Domain Map',
402
+ href: buildUrl('/visualiser/domain-integrations'),
403
+ },
404
+ ],
405
+ };
406
+ }
407
+
386
408
  const allGeneratedNodes = {
387
409
  ...rootDomainsNodes,
388
410
  ...domainNodes,
@@ -394,11 +416,17 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
394
416
  ...userNodes,
395
417
  ...teamNodes,
396
418
  ...designNodes,
419
+ ...systemNode,
397
420
  ...allNodes,
398
421
  };
399
422
 
400
423
  // only filter if child is string
401
- const rootNavigationConfig = config?.navigation?.pages || ['list:top-level-domains', 'list:all'];
424
+ const defaultPages = ['list:top-level-domains', 'list:all'];
425
+ // Add system section if it exists
426
+ if (systemNode['list:system']) {
427
+ defaultPages.push('list:system');
428
+ }
429
+ const rootNavigationConfig = config?.navigation?.pages || defaultPages;
402
430
 
403
431
  const navigationConfig = {
404
432
  roots: rootNavigationConfig,
@@ -7,7 +7,8 @@ export type CollectionTypes =
7
7
  | 'flows'
8
8
  | 'channels'
9
9
  | 'entities'
10
- | 'containers';
10
+ | 'containers'
11
+ | 'diagrams';
11
12
  export type CollectionMessageTypes = 'commands' | 'events' | 'queries';
12
13
  export type CollectionUserTypes = 'users';
13
14
  export type PageTypes =
@@ -19,7 +20,8 @@ export type PageTypes =
19
20
  | 'channels'
20
21
  | 'flows'
21
22
  | 'entities'
22
- | 'containers';
23
+ | 'containers'
24
+ | 'diagrams';
23
25
 
24
26
  export type TableConfiguration = {
25
27
  columns: {