@eventcatalog/core 3.42.0 → 3.43.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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/count-resources.cjs +1 -0
- package/dist/analytics/count-resources.js +1 -1
- package/dist/analytics/log-build.cjs +3 -1
- package/dist/analytics/log-build.js +4 -4
- package/dist/{chunk-6FAGUEM4.js → chunk-2EI3M7OO.js} +1 -1
- package/dist/{chunk-UQIDXF2V.js → chunk-7M5IQL3J.js} +1 -1
- package/dist/{chunk-3DVHEVHQ.js → chunk-DAOXTQVS.js} +1 -0
- package/dist/{chunk-VPZ77Y6E.js → chunk-KY74BE42.js} +1 -1
- package/dist/{chunk-L66TCSM7.js → chunk-QV2PKXZM.js} +3 -2
- package/dist/{chunk-QMORF42U.js → chunk-ZONBICNH.js} +8 -0
- package/dist/{chunk-KE6YTTLB.js → chunk-ZQHBDPIY.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +11 -1
- package/dist/eventcatalog.js +7 -7
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/search-indexer.cjs +8 -0
- package/dist/search-indexer.js +1 -1
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/src/components/MDX/Attachments.astro +3 -3
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +11 -2
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +100 -2
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +53 -1
- package/eventcatalog/src/content.config.ts +61 -0
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +19 -0
- package/eventcatalog/src/layouts/DiscoverLayout.astro +12 -1
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +98 -46
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -0
- package/eventcatalog/src/pages/discover/[type]/index.astro +17 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +68 -2
- package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +1 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +26 -1
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +26 -1
- package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +150 -0
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +2 -0
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +50 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +209 -68
- package/eventcatalog/src/types/index.ts +2 -0
- package/eventcatalog/src/utils/collection-colors.ts +2 -0
- package/eventcatalog/src/utils/collections/adr-constants.ts +53 -0
- package/eventcatalog/src/utils/collections/adrs.ts +146 -0
- package/eventcatalog/src/utils/collections/icons.ts +2 -0
- package/eventcatalog/src/utils/collections/teams.ts +6 -1
- package/eventcatalog/src/utils/collections/users.ts +17 -10
- package/eventcatalog/src/utils/collections/util.ts +2 -0
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +3 -3
|
@@ -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 {
|
|
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
|
|
@@ -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-
|
|
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-
|
|
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 {
|