@eventcatalog/core 3.42.0 → 3.43.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/count-resources.cjs +1 -0
  4. package/dist/analytics/count-resources.js +1 -1
  5. package/dist/analytics/log-build.cjs +3 -1
  6. package/dist/analytics/log-build.js +4 -4
  7. package/dist/{chunk-KE6YTTLB.js → chunk-2GQO7I7E.js} +1 -1
  8. package/dist/{chunk-6FAGUEM4.js → chunk-C6S5P57F.js} +1 -1
  9. package/dist/{chunk-3DVHEVHQ.js → chunk-DAOXTQVS.js} +1 -0
  10. package/dist/{chunk-VPZ77Y6E.js → chunk-KV5FCOV4.js} +1 -1
  11. package/dist/{chunk-L66TCSM7.js → chunk-OOX6HAE4.js} +3 -2
  12. package/dist/{chunk-UQIDXF2V.js → chunk-Z5QHV4ZY.js} +1 -1
  13. package/dist/{chunk-QMORF42U.js → chunk-ZONBICNH.js} +8 -0
  14. package/dist/constants.cjs +1 -1
  15. package/dist/constants.js +1 -1
  16. package/dist/eventcatalog.cjs +11 -1
  17. package/dist/eventcatalog.js +7 -7
  18. package/dist/generate.cjs +1 -1
  19. package/dist/generate.js +3 -3
  20. package/dist/search-indexer.cjs +8 -0
  21. package/dist/search-indexer.js +1 -1
  22. package/dist/utils/cli-logger.cjs +1 -1
  23. package/dist/utils/cli-logger.js +2 -2
  24. package/eventcatalog/src/components/MDX/Attachments.astro +3 -3
  25. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +11 -2
  26. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +100 -2
  27. package/eventcatalog/src/components/Tables/Discover/columns.tsx +53 -1
  28. package/eventcatalog/src/content.config.ts +61 -0
  29. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +19 -0
  30. package/eventcatalog/src/layouts/DiscoverLayout.astro +12 -1
  31. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +98 -46
  32. package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -0
  33. package/eventcatalog/src/pages/discover/[type]/index.astro +17 -0
  34. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +68 -2
  36. package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +1 -0
  37. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +26 -1
  38. package/eventcatalog/src/pages/docs/users/[id]/index.astro +26 -1
  39. package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +150 -0
  40. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +2 -0
  41. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +50 -0
  42. package/eventcatalog/src/stores/sidebar-store/state.ts +209 -68
  43. package/eventcatalog/src/types/index.ts +2 -0
  44. package/eventcatalog/src/utils/collection-colors.ts +2 -0
  45. package/eventcatalog/src/utils/collections/adr-constants.ts +53 -0
  46. package/eventcatalog/src/utils/collections/adrs.ts +146 -0
  47. package/eventcatalog/src/utils/collections/icons.ts +2 -0
  48. package/eventcatalog/src/utils/collections/teams.ts +6 -1
  49. package/eventcatalog/src/utils/collections/users.ts +17 -10
  50. package/eventcatalog/src/utils/collections/util.ts +2 -0
  51. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
  52. package/package.json +4 -4
@@ -29,10 +29,31 @@ import {
29
29
  ClockIcon,
30
30
  } from '@heroicons/react/24/outline';
31
31
  import { ArrowsRightLeftIcon } from '@heroicons/react/20/solid';
32
- import { Bot, Box, Boxes, SquarePenIcon, DatabaseIcon, DatabaseZapIcon, ShieldCheckIcon, AlignLeft, Package } from 'lucide-react';
32
+ import {
33
+ Bot,
34
+ Box,
35
+ Boxes,
36
+ SquarePenIcon,
37
+ DatabaseIcon,
38
+ DatabaseZapIcon,
39
+ ShieldCheckIcon,
40
+ AlignLeft,
41
+ Package,
42
+ BookText,
43
+ CalendarDays,
44
+ } from 'lucide-react';
33
45
 
34
46
  import { getSpecificationsForService } from '@utils/collections/services';
35
47
  import { resourceToCollectionMap, collectionToResourceMap, getDeprecatedDetails } from '@utils/collections/util';
48
+ import {
49
+ createAdrStatusBadge,
50
+ formatAdrDate,
51
+ getAdrRelationships,
52
+ getAdrs,
53
+ isAdrCollection,
54
+ isDeprecatedAdr,
55
+ isSupersededAdr,
56
+ } from '@utils/collections/adrs';
36
57
  import { getSchemasFromResource } from '@utils/collections/schemas';
37
58
  import { getIcon } from '@utils/badges';
38
59
  import { buildUrl, buildEditUrlForResource } from '@utils/url-builder';
@@ -59,6 +80,10 @@ export const getStaticPaths = Page.getStaticPaths;
59
80
  const props = await Page.getData(Astro);
60
81
 
61
82
  const { Content, headings } = await render(props);
83
+ const isAdrPage = isAdrCollection(props.collection);
84
+ const allAdrs = isAdrPage ? await getAdrs({ getAllVersions: true }) : [];
85
+ const adrRelationships = isAdrPage ? getAdrRelationships(props as any, allAdrs) : null;
86
+ const supersededByAdrs = adrRelationships?.supersededBy || [];
62
87
 
63
88
  const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
64
89
  const contentBadges = props.data.badges || [];
@@ -121,6 +146,14 @@ const getBadge = () => {
121
146
  return badges;
122
147
  }
123
148
 
149
+ if (isAdrPage) {
150
+ return [
151
+ createResourceBadge('Decision Record', BookText),
152
+ createResourceBadge(formatAdrDate(props.data.date), CalendarDays),
153
+ createAdrStatusBadge(props.data.status),
154
+ ];
155
+ }
156
+
124
157
  if (props.collection === 'services') {
125
158
  return [createResourceBadge('Service', ServerIcon)];
126
159
  }
@@ -258,6 +291,7 @@ const {
258
291
  let friendlyCollectionName = props.collection.slice(0, props.collection.length - 1);
259
292
  friendlyCollectionName = friendlyCollectionName === 'querie' ? 'query' : friendlyCollectionName;
260
293
  friendlyCollectionName = friendlyCollectionName === 'entitie' ? 'entity' : friendlyCollectionName;
294
+ friendlyCollectionName = friendlyCollectionName === 'adr' ? 'architecture decision' : friendlyCollectionName;
261
295
 
262
296
  const schemasForResource = getSchemasFromResource(props);
263
297
 
@@ -327,7 +361,7 @@ const httpMethodStyle = httpOperation?.method
327
361
  : undefined;
328
362
 
329
363
  // This will render the graph for this page. Flow pages can already render their graph explicitly via <Flow />.
330
- if (!hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
364
+ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
331
365
  nodeGraphs.push({
332
366
  ...currentPageNodeGraph,
333
367
  search: true,
@@ -422,6 +456,38 @@ if (!hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
422
456
  )
423
457
  }
424
458
 
459
+ {
460
+ isSupersededAdr(props) && (
461
+ <Admonition type="warning" title="This architecture decision has been superseded">
462
+ <div>
463
+ {supersededByAdrs.length > 0 ? (
464
+ <p>
465
+ You are looking at a previous architecture decision. It has been superseded by{' '}
466
+ {supersededByAdrs.map((adr: any, index: number) => (
467
+ <>
468
+ <a class="underline" href={buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}`)}>
469
+ {adr.data.name}
470
+ </a>
471
+ {index < supersededByAdrs.length - 1 ? ', ' : '.'}
472
+ </>
473
+ ))}
474
+ </p>
475
+ ) : (
476
+ <p>This architecture decision has been marked as superseded.</p>
477
+ )}
478
+ </div>
479
+ </Admonition>
480
+ )
481
+ }
482
+
483
+ {
484
+ isDeprecatedAdr(props) && (
485
+ <Admonition type="warning" title="This architecture decision has been deprecated">
486
+ <p>This architecture decision has been marked as deprecated.</p>
487
+ </Admonition>
488
+ )
489
+ }
490
+
425
491
  {
426
492
  isMarkedAsDeprecated && hasDeprecated && (
427
493
  <Admonition
@@ -72,6 +72,7 @@ export const GET: APIRoute = async ({ params, request }) => {
72
72
  const content = resources
73
73
  .map((item) => {
74
74
  if (!item.filePath) return '';
75
+ if (!fs.existsSync(item.filePath)) return '';
75
76
 
76
77
  let file = fs.readFileSync(item.filePath, 'utf8');
77
78
 
@@ -7,6 +7,7 @@ import type { CollectionEntry } from 'astro:content';
7
7
  import OwnersList from '@components/Lists/OwnersList';
8
8
  import PillListFlat from '@components/Lists/PillListFlat';
9
9
  import EnvelopeIcon from '@heroicons/react/16/solid/EnvelopeIcon';
10
+ import { formatAdrStatus } from '@utils/collections/adrs';
10
11
  import { buildUrl } from '@utils/url-builder';
11
12
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
12
13
  import { Page } from './_index.data';
@@ -28,6 +29,7 @@ const services = props.data.ownedServices as CollectionEntry<'services'>[];
28
29
  const events = props.data.ownedEvents as CollectionEntry<'events'>[];
29
30
  const commands = props.data.ownedCommands as CollectionEntry<'commands'>[];
30
31
  const queries = props.data.ownedQueries as CollectionEntry<'queries'>[];
32
+ const adrs = props.data.ownedAdrs as CollectionEntry<'adrs'>[];
31
33
 
32
34
  const membersList = members.map((o) => ({
33
35
  label: o.data.name,
@@ -67,6 +69,14 @@ const ownedMessagesList = [...events, ...commands, ...queries].map((p) => ({
67
69
  tag: `v${p.data.version}`,
68
70
  }));
69
71
 
72
+ const ownedAdrsList = adrs.map((p) => ({
73
+ label: `${p.data.name}`,
74
+ href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
75
+ collection: p.collection,
76
+ tag: `v${p.data.version}`,
77
+ description: formatAdrStatus(p.data.status),
78
+ }));
79
+
70
80
  const pageTitle = `Team | ${props.data.name}`;
71
81
  ---
72
82
 
@@ -135,7 +145,7 @@ const pageTitle = `Team | ${props.data.name}`;
135
145
  </div>
136
146
  </div>
137
147
  <div class="border-b border-[rgb(var(--ec-page-border))] py-4" data-pagefind-ignore>
138
- <dl class="grid grid-cols-2 gap-3 sm:grid-cols-5">
148
+ <dl class="grid grid-cols-2 gap-3 sm:grid-cols-6">
139
149
  <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
140
150
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Domains</dt>
141
151
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedDomainsList.length}</dd>
@@ -152,6 +162,10 @@ const pageTitle = `Team | ${props.data.name}`;
152
162
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Messages</dt>
153
163
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedMessagesList.length}</dd>
154
164
  </div>
165
+ <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
166
+ <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Decisions</dt>
167
+ <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedAdrsList.length}</dd>
168
+ </div>
155
169
  <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
156
170
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Members</dt>
157
171
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{membersList.length}</dd>
@@ -211,6 +225,17 @@ const pageTitle = `Team | ${props.data.name}`;
211
225
  />
212
226
  )
213
227
  }
228
+ {
229
+ ownedAdrsList.length > 0 && (
230
+ <PillListFlat
231
+ color="orange"
232
+ title={`Owned ADRs (${ownedAdrsList.length})`}
233
+ pills={ownedAdrsList}
234
+ emptyMessage={`This team does not own any decision records.`}
235
+ client:load
236
+ />
237
+ )
238
+ }
214
239
  {
215
240
  membersList.length > 0 && (
216
241
  <OwnersList
@@ -7,6 +7,7 @@ import type { CollectionEntry } from 'astro:content';
7
7
  import OwnersList from '@components/Lists/OwnersList';
8
8
  import PillListFlat from '@components/Lists/PillListFlat';
9
9
  import EnvelopeIcon from '@heroicons/react/16/solid/EnvelopeIcon';
10
+ import { formatAdrStatus } from '@utils/collections/adrs';
10
11
  import { buildUrl } from '@utils/url-builder';
11
12
  import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
12
13
  import { Page } from './_index.data';
@@ -25,6 +26,7 @@ const services = props.data.ownedServices as CollectionEntry<'services'>[];
25
26
  const events = props.data.ownedEvents as CollectionEntry<'events'>[];
26
27
  const commands = props.data.ownedCommands as CollectionEntry<'commands'>[];
27
28
  const queries = props.data.ownedQueries as CollectionEntry<'queries'>[];
29
+ const adrs = props.data.ownedAdrs as CollectionEntry<'adrs'>[];
28
30
  const teams = props.data.associatedTeams as CollectionEntry<'teams'>[];
29
31
 
30
32
  const ownedDomainsList = domains.map((p) => ({
@@ -57,6 +59,14 @@ const ownedMessageList = [...events, ...commands, ...queries].map((p) => ({
57
59
  href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
58
60
  }));
59
61
 
62
+ const ownedAdrsList = adrs.map((p) => ({
63
+ label: `${p.data.name}`,
64
+ href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
65
+ collection: p.collection,
66
+ tag: `v${p.data.version}`,
67
+ description: formatAdrStatus(p.data.status),
68
+ }));
69
+
60
70
  const associatedTeams = teams.map((o) => ({
61
71
  label: o.data.name,
62
72
  type: o.collection,
@@ -136,7 +146,7 @@ const pageTitle = `User | ${props.data.name}`;
136
146
  </div>
137
147
  </div>
138
148
  <div class="border-b border-[rgb(var(--ec-page-border))] py-4" data-pagefind-ignore>
139
- <dl class="grid grid-cols-2 gap-3 sm:grid-cols-5">
149
+ <dl class="grid grid-cols-2 gap-3 sm:grid-cols-6">
140
150
  <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
141
151
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Domains</dt>
142
152
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedDomainsList.length}</dd>
@@ -153,6 +163,10 @@ const pageTitle = `User | ${props.data.name}`;
153
163
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Messages</dt>
154
164
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedMessageList.length}</dd>
155
165
  </div>
166
+ <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
167
+ <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Decisions</dt>
168
+ <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{ownedAdrsList.length}</dd>
169
+ </div>
156
170
  <div class="flex flex-col p-4 bg-[rgb(var(--ec-content-hover))] rounded-lg">
157
171
  <dt class="text-xs font-medium text-[rgb(var(--ec-page-text-muted))]">Teams</dt>
158
172
  <dd class="text-2xl font-semibold text-[rgb(var(--ec-page-text))] mt-1">{associatedTeams.length}</dd>
@@ -212,6 +226,17 @@ const pageTitle = `User | ${props.data.name}`;
212
226
  />
213
227
  )
214
228
  }
229
+ {
230
+ ownedAdrsList.length > 0 && (
231
+ <PillListFlat
232
+ color="orange"
233
+ title={`Owned ADRs (${ownedAdrsList.length})`}
234
+ pills={ownedAdrsList}
235
+ emptyMessage={`${props.data.name} does not own any decision records.`}
236
+ client:load
237
+ />
238
+ )
239
+ }
215
240
  {
216
241
  associatedTeams.length > 0 && (
217
242
  <OwnersList
@@ -0,0 +1,150 @@
1
+ import { buildUrl } from '@utils/url-builder';
2
+ import {
3
+ getAdrRelationships,
4
+ getAdrNodeKey,
5
+ getAdrResourceNodeKey,
6
+ resolveAdrPointers,
7
+ type Adr,
8
+ type AdrResource,
9
+ } from '@utils/collections/adrs';
10
+ import { collectionToResourceMap, createVersionedMap, findInMap } from '@utils/collections/util';
11
+ import type { ChildRef, NavNode, ResourceGroupContext } from './shared';
12
+ import {
13
+ buildAttachmentsSection,
14
+ buildOwnersSection,
15
+ buildQuickReferenceSection,
16
+ buildRepositorySection,
17
+ shouldRenderSideBarSection,
18
+ } from './shared';
19
+ import { isChangelogEnabled } from '@utils/feature';
20
+
21
+ const firstClassResourceCollections = [
22
+ 'agents',
23
+ 'services',
24
+ 'events',
25
+ 'commands',
26
+ 'queries',
27
+ 'flows',
28
+ 'channels',
29
+ 'domains',
30
+ 'users',
31
+ 'teams',
32
+ 'containers',
33
+ 'entities',
34
+ 'diagrams',
35
+ 'data-products',
36
+ ] as const;
37
+
38
+ const getCollectionForAdrResourceType = (type: string) => {
39
+ const match = Object.entries(collectionToResourceMap).find(([, resourceType]) => resourceType === type);
40
+ return match?.[0];
41
+ };
42
+
43
+ const getResourcesForCollection = (collection: string, context: ResourceGroupContext): AdrResource[] => {
44
+ const resourcesByCollection: Partial<Record<(typeof firstClassResourceCollections)[number], AdrResource[]>> = {
45
+ agents: context.agents || [],
46
+ services: context.services,
47
+ events: context.events,
48
+ commands: context.commands,
49
+ queries: context.queries,
50
+ flows: context.flows,
51
+ channels: context.channels || [],
52
+ domains: context.domains,
53
+ users: context.users || [],
54
+ teams: context.teams || [],
55
+ containers: context.containers,
56
+ entities: context.entities || [],
57
+ diagrams: context.diagrams,
58
+ 'data-products': context.dataProducts,
59
+ };
60
+
61
+ return resourcesByCollection[collection as (typeof firstClassResourceCollections)[number]] || [];
62
+ };
63
+
64
+ const resolveAppliedResourceRefs = (adr: Adr, context: ResourceGroupContext) => {
65
+ return (adr.data.appliesTo || [])
66
+ .map((pointer) => {
67
+ const collection = getCollectionForAdrResourceType(pointer.type);
68
+ if (!collection) return undefined;
69
+
70
+ const resourceMap = createVersionedMap(getResourcesForCollection(collection, context) as any[]);
71
+ const resource = findInMap(resourceMap, pointer.id, pointer.version) as AdrResource | undefined;
72
+ return resource ? getAdrResourceNodeKey(resource) : undefined;
73
+ })
74
+ .filter((ref): ref is string => !!ref);
75
+ };
76
+
77
+ const buildAdrRelationshipSection = (title: string, icon: string, refs: Adr[]): NavNode | null => {
78
+ if (refs.length === 0) return null;
79
+
80
+ return {
81
+ type: 'group',
82
+ title,
83
+ icon,
84
+ pages: refs.map(getAdrNodeKey),
85
+ };
86
+ };
87
+
88
+ const buildDecisionMakersSection = (decisionMakers: any[]): NavNode | null => {
89
+ if (decisionMakers.length === 0) return null;
90
+
91
+ return {
92
+ type: 'group',
93
+ title: 'Decision makers',
94
+ icon: 'UserCheck',
95
+ pages: decisionMakers.map((owner) => ({
96
+ type: 'item',
97
+ title: owner?.data.name ?? '',
98
+ href: buildUrl(`/docs/${owner?.collection}/${owner?.data.id}`),
99
+ })),
100
+ };
101
+ };
102
+
103
+ export const buildAdrNode = (adr: Adr, owners: any[], decisionMakers: any[], context: ResourceGroupContext): NavNode => {
104
+ const relationships = getAdrRelationships(adr, context.adrs);
105
+ const appliesToRefs = resolveAppliedResourceRefs(adr, context);
106
+ const hasAttachments = adr.data.attachments && adr.data.attachments.length > 0;
107
+ const renderOwners = owners.length > 0 && shouldRenderSideBarSection(adr, 'owners');
108
+ const renderDecisionMakers = decisionMakers.length > 0 && shouldRenderSideBarSection(adr, 'decisionMakers');
109
+ const renderRepository = adr.data.repository && shouldRenderSideBarSection(adr, 'repository');
110
+
111
+ return {
112
+ type: 'item',
113
+ title: adr.data.name,
114
+ badge: 'Decision record',
115
+ summary: adr.data.summary,
116
+ icon: 'BookText',
117
+ pages: [
118
+ buildQuickReferenceSection(
119
+ [
120
+ { title: 'Overview', href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}`) },
121
+ isChangelogEnabled() &&
122
+ shouldRenderSideBarSection(adr, 'changelog') && {
123
+ title: 'Changelog',
124
+ href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}/changelog`),
125
+ },
126
+ ].filter(Boolean) as { title: string; href: string }[]
127
+ ),
128
+ appliesToRefs.length > 0 &&
129
+ shouldRenderSideBarSection(adr, 'appliesTo') && {
130
+ type: 'group',
131
+ title: 'Applies to',
132
+ icon: 'GitBranch',
133
+ pages: appliesToRefs,
134
+ },
135
+ shouldRenderSideBarSection(adr, 'relationships') &&
136
+ buildAdrRelationshipSection('Supersedes', 'History', relationships.supersedes),
137
+ shouldRenderSideBarSection(adr, 'relationships') &&
138
+ buildAdrRelationshipSection('Superseded by', 'History', relationships.supersededBy),
139
+ shouldRenderSideBarSection(adr, 'relationships') && buildAdrRelationshipSection('Amends', 'Pencil', relationships.amends),
140
+ shouldRenderSideBarSection(adr, 'relationships') &&
141
+ buildAdrRelationshipSection('Amended by', 'Pencil', relationships.amendedBy),
142
+ shouldRenderSideBarSection(adr, 'relationships') &&
143
+ buildAdrRelationshipSection('Related decisions', 'Link', resolveAdrPointers(adr.data.related, context.adrs)),
144
+ renderDecisionMakers && buildDecisionMakersSection(decisionMakers),
145
+ renderOwners && buildOwnersSection(owners),
146
+ renderRepository && buildRepositorySection(adr.data.repository as { url: string; language: string }),
147
+ hasAttachments && buildAttachmentsSection(adr.data.attachments as any[]),
148
+ ].filter(Boolean) as ChildRef[],
149
+ };
150
+ };
@@ -14,6 +14,7 @@ import {
14
14
  import { isVisualiserEnabled, isChangelogEnabled } from '@utils/feature';
15
15
  import { pluralizeMessageType } from '@utils/collections/messages';
16
16
  import { getSpecificationsForDomain } from '@utils/collections/domains';
17
+ import { iconFieldsForResource } from '@utils/icon';
17
18
 
18
19
  export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[], context: ResourceGroupContext): NavNode => {
19
20
  const agentsInDomain = domain.data.agents || [];
@@ -79,6 +80,7 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
79
80
  title: domain.data.name,
80
81
  badge: 'Domain',
81
82
  summary: domain.data.summary,
83
+ ...iconFieldsForResource(domain.data, 'Boxes'),
82
84
  pages: [
83
85
  buildQuickReferenceSection(
84
86
  [
@@ -1,6 +1,7 @@
1
1
  import type { ResourceGroup } from '@eventcatalog/sdk';
2
2
  import type { CollectionEntry } from 'astro:content';
3
3
  import { getLatestVersionInCollectionById } from '@utils/collections/util';
4
+ import { getAdrNodeKey, getAdrsForResource, type Adr, type AdrResource } from '@utils/collections/adrs';
4
5
  import { buildUrl } from '@utils/url-builder';
5
6
  import {
6
7
  getGroupedResourceDocsByType,
@@ -61,9 +62,14 @@ export type ResourceGroupContext = {
61
62
  commands: CollectionEntry<'commands'>[];
62
63
  queries: CollectionEntry<'queries'>[];
63
64
  flows: CollectionEntry<'flows'>[];
65
+ channels?: CollectionEntry<'channels'>[];
64
66
  containers: CollectionEntry<'containers'>[];
67
+ entities?: CollectionEntry<'entities'>[];
65
68
  dataProducts: CollectionEntry<'data-products'>[];
66
69
  diagrams: CollectionEntry<'diagrams'>[];
70
+ adrs: Adr[];
71
+ users?: CollectionEntry<'users'>[];
72
+ teams?: CollectionEntry<'teams'>[];
67
73
  resourceDocs: ResourceDocEntry[];
68
74
  resourceDocCategories: ResourceDocCategoryEntry[];
69
75
  };
@@ -94,6 +100,50 @@ export const buildOwnersSection = (owners: any[]): NavNode | null => {
94
100
  };
95
101
  };
96
102
 
103
+ export const buildArchitectureDecisionsSection = (resource: AdrResource, adrs: Adr[]): NavNode | null => {
104
+ const relatedAdrs = getAdrsForResource(resource, adrs);
105
+ if (relatedAdrs.length === 0) return null;
106
+
107
+ return {
108
+ type: 'group',
109
+ title: 'Decision Records',
110
+ icon: 'BookText',
111
+ pages: relatedAdrs.map(getAdrNodeKey),
112
+ };
113
+ };
114
+
115
+ const isOwnersSection = (page: ChildRef) => typeof page !== 'string' && page.title === 'Owners';
116
+
117
+ const insertBeforeOwnersSection = (pages: ChildRef[], section: NavNode) => {
118
+ const ownersSectionIndex = pages.findIndex(isOwnersSection);
119
+ if (ownersSectionIndex === -1) return [...pages, section];
120
+
121
+ return [...pages.slice(0, ownersSectionIndex), section, ...pages.slice(ownersSectionIndex)];
122
+ };
123
+
124
+ const getPagesForDecisionSection = (node: NavNode): ChildRef[] => {
125
+ if (node.pages && node.pages.length > 0) return node.pages;
126
+ if (!node.href) return [];
127
+
128
+ return [
129
+ {
130
+ type: 'item',
131
+ title: 'Overview',
132
+ href: node.href,
133
+ },
134
+ ];
135
+ };
136
+
137
+ export const withArchitectureDecisionsSection = (node: NavNode, resource: AdrResource, adrs: Adr[]): NavNode => {
138
+ const section = buildArchitectureDecisionsSection(resource, adrs);
139
+ if (!section || !shouldRenderSideBarSection(resource, 'architectureDecisions')) return node;
140
+
141
+ return {
142
+ ...node,
143
+ pages: insertBeforeOwnersSection(getPagesForDecisionSection(node), section),
144
+ };
145
+ };
146
+
97
147
  export const buildRepositorySection = (repository: { url: string; language: string }): NavNode | null => {
98
148
  if (!repository) return null;
99
149
  return {