@eventcatalog/core 4.9.0 → 4.10.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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-HKVOSQTD.js → chunk-OC2RGFPU.js} +1 -1
- package/dist/{chunk-MPHX5C7M.js → chunk-PHG7KEUH.js} +1 -1
- package/dist/{chunk-LVGQ23LR.js → chunk-QIV7LWVJ.js} +1 -1
- package/dist/{chunk-XQHS36GO.js → chunk-SQNVL7PI.js} +1 -1
- package/dist/{chunk-3CGSSMTK.js → chunk-T2HLSITU.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +6 -0
- package/eventcatalog/src/components/Badge.astro +3 -1
- package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +260 -175
- package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +0 -5
- package/eventcatalog/src/components/MDX/ArchitectureGraph/ArchitectureGraph.astro +62 -0
- package/eventcatalog/src/components/MDX/ArchitectureGraph/ArchitectureGraphPortal.tsx +22 -0
- package/eventcatalog/src/components/MDX/ArchitectureGraph/AstroArchitectureGraph.tsx +42 -0
- package/eventcatalog/src/components/MDX/Design/Design.astro +2 -0
- package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +2 -0
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +5 -7
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -0
- package/eventcatalog/src/components/MDX/components.tsx +13 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +121 -88
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +55 -7
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.spec.ts +59 -15
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +53 -7
- package/eventcatalog/src/content.config.ts +70 -0
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +19 -0
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +46 -1
- package/eventcatalog/src/enterprise/fields/pages/fields.astro +2 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +16 -15
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +21 -17
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +45 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +16 -8
- package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +48 -65
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +45 -18
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -1
- package/eventcatalog/src/pages/index.astro +34 -2
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +5 -1
- package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +2 -0
- package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -0
- package/eventcatalog/src/pages/visualiser/graph/index.astro +2 -23
- package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +96 -34
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +167 -75
- package/eventcatalog/src/stores/sidebar-store/builders/container.ts +135 -59
- package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +144 -58
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +306 -188
- package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +108 -39
- package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +147 -63
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +212 -121
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +223 -127
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +3 -23
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +187 -97
- package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +678 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +66 -36
- package/eventcatalog/src/styles/tailwind.css +82 -0
- package/eventcatalog/src/utils/collections/resource-docs.ts +1 -0
- package/eventcatalog/src/utils/node-graphs/catalog-force-graph.ts +41 -0
- package/package.json +1 -1
|
@@ -10,16 +10,75 @@ import {
|
|
|
10
10
|
buildAttachmentsSection,
|
|
11
11
|
buildDiagramNavItems,
|
|
12
12
|
buildResourceDocsSection,
|
|
13
|
+
buildArchitectureDecisionsSection,
|
|
13
14
|
} from './shared';
|
|
14
15
|
import { isVisualiserEnabled, isChangelogEnabled } from '@utils/feature';
|
|
15
16
|
import { pluralizeMessageType } from '@utils/collections/messages';
|
|
16
17
|
import { getSpecificationsForDomain, hasUbiquitousLanguageTermsWithSubdomainsInCollection } from '@utils/collections/domains';
|
|
17
18
|
import { customIconFieldsForResource } from '@utils/icon';
|
|
19
|
+
import { resolveSidebarPages, toCustomSidebarContext, type SidebarSpec } from '../custom-sidebar';
|
|
18
20
|
|
|
19
21
|
// Sort resolved collection entries A-Z by their display name (falling back to id).
|
|
20
22
|
const byResourceName = (a: any, b: any) => (a.data?.name || a.data?.id || '').localeCompare(b.data?.name || b.data?.id || '');
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Predefined sidebar sections for a domain, keyed by the token users reference from
|
|
26
|
+
* `sidebar.json` (e.g. `$quick-reference`). Each token is the kebab-cased title of the
|
|
27
|
+
* section as it appears in the default sidebar.
|
|
28
|
+
*/
|
|
29
|
+
export type DomainSectionKey =
|
|
30
|
+
| 'quick-reference'
|
|
31
|
+
| 'documentation'
|
|
32
|
+
| 'architecture'
|
|
33
|
+
| 'diagrams'
|
|
34
|
+
| 'api-and-contracts'
|
|
35
|
+
| 'systems'
|
|
36
|
+
| 'subdomains'
|
|
37
|
+
| 'resources'
|
|
38
|
+
| 'services'
|
|
39
|
+
| 'flows'
|
|
40
|
+
| 'entities'
|
|
41
|
+
| 'domain-events'
|
|
42
|
+
| 'external-events'
|
|
43
|
+
| 'resource-groups'
|
|
44
|
+
| 'agents'
|
|
45
|
+
| 'external-integrations'
|
|
46
|
+
| 'data-products'
|
|
47
|
+
| 'decision-records'
|
|
48
|
+
| 'owners'
|
|
49
|
+
| 'code'
|
|
50
|
+
| 'attachments';
|
|
51
|
+
|
|
52
|
+
export type DomainSections = Record<DomainSectionKey, NavNode | NavNode[] | null>;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Order of sections in the default (generated) sidebar. `decision-records` is deliberately
|
|
56
|
+
* absent — in default mode it is inserted before Owners by `withArchitectureDecisionsSection`
|
|
57
|
+
* in state.ts, and only becomes a first-class token for custom sidebars.
|
|
58
|
+
*/
|
|
59
|
+
export const DEFAULT_DOMAIN_SECTION_ORDER: DomainSectionKey[] = [
|
|
60
|
+
'quick-reference',
|
|
61
|
+
'documentation',
|
|
62
|
+
'architecture',
|
|
63
|
+
'diagrams',
|
|
64
|
+
'api-and-contracts',
|
|
65
|
+
'systems',
|
|
66
|
+
'subdomains',
|
|
67
|
+
'resources',
|
|
68
|
+
'resource-groups',
|
|
69
|
+
'agents',
|
|
70
|
+
'external-integrations',
|
|
71
|
+
'data-products',
|
|
72
|
+
'owners',
|
|
73
|
+
'code',
|
|
74
|
+
'attachments',
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
export const buildDomainSections = (
|
|
78
|
+
domain: CollectionEntry<'domains'>,
|
|
79
|
+
owners: any[],
|
|
80
|
+
context: ResourceGroupContext
|
|
81
|
+
): DomainSections => {
|
|
23
82
|
const agentsInDomain = domain.data.agents || [];
|
|
24
83
|
const renderAgents = agentsInDomain.length > 0 && shouldRenderSideBarSection(domain, 'agents');
|
|
25
84
|
|
|
@@ -117,6 +176,251 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
117
176
|
const graphQLSpecifications = specifications.filter((specification) => specification.type === 'graphql');
|
|
118
177
|
const renderSpecifications = hasSpecifications && shouldRenderSideBarSection(domain, 'specifications');
|
|
119
178
|
|
|
179
|
+
// Resource subsections. These are built once and shared between the "Resources"
|
|
180
|
+
// umbrella (where they render as subtle subgroups) and their standalone tokens
|
|
181
|
+
// (`$services`, `$entities`, ...) for custom sidebars.
|
|
182
|
+
const servicesSection: NavNode | null = renderServices
|
|
183
|
+
? {
|
|
184
|
+
type: 'group',
|
|
185
|
+
title: 'Services',
|
|
186
|
+
icon: 'Server',
|
|
187
|
+
pages: servicesInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
188
|
+
}
|
|
189
|
+
: null;
|
|
190
|
+
|
|
191
|
+
const flowsSection: NavNode | null = hasFlows
|
|
192
|
+
? {
|
|
193
|
+
type: 'group',
|
|
194
|
+
title: 'Flows',
|
|
195
|
+
icon: 'Waypoints',
|
|
196
|
+
pages: domainFlows.map((flow) => `flow:${(flow as any).data.id}:${(flow as any).data.version}`),
|
|
197
|
+
}
|
|
198
|
+
: null;
|
|
199
|
+
|
|
200
|
+
const entitiesSection: NavNode | null = renderEntities
|
|
201
|
+
? {
|
|
202
|
+
type: 'group',
|
|
203
|
+
title: 'Entities',
|
|
204
|
+
icon: 'Box',
|
|
205
|
+
pages: entitiesInDomain.map((entity) => ({
|
|
206
|
+
type: 'item',
|
|
207
|
+
title: (entity as any).data?.name || (entity as any).data.id,
|
|
208
|
+
href: buildUrl(`/docs/entities/${(entity as any).data.id}/${(entity as any).data.version}`),
|
|
209
|
+
})),
|
|
210
|
+
}
|
|
211
|
+
: null;
|
|
212
|
+
|
|
213
|
+
const domainEventsSection: NavNode | null =
|
|
214
|
+
renderMessages && sendsMessages.length > 0
|
|
215
|
+
? {
|
|
216
|
+
type: 'group',
|
|
217
|
+
title: 'Domain Events',
|
|
218
|
+
icon: 'Mail',
|
|
219
|
+
pages: sortedSendsMessages.map(
|
|
220
|
+
(message) => `${pluralizeMessageType(message as any)}:${(message as any).data.id}:${(message as any).data.version}`
|
|
221
|
+
),
|
|
222
|
+
}
|
|
223
|
+
: null;
|
|
224
|
+
|
|
225
|
+
const externalEventsSection: NavNode | null =
|
|
226
|
+
renderMessages && receivesMessages.length > 0
|
|
227
|
+
? {
|
|
228
|
+
type: 'group',
|
|
229
|
+
title: 'External Events',
|
|
230
|
+
icon: 'Mail',
|
|
231
|
+
pages: sortedReceivesMessages.map(
|
|
232
|
+
(receive) => `${pluralizeMessageType(receive as any)}:${(receive as any).data.id}:${(receive as any).data.version}`
|
|
233
|
+
),
|
|
234
|
+
}
|
|
235
|
+
: null;
|
|
236
|
+
|
|
237
|
+
const resourceSubsections = [servicesSection, flowsSection, entitiesSection, domainEventsSection, externalEventsSection].filter(
|
|
238
|
+
Boolean
|
|
239
|
+
) as NavNode[];
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
'quick-reference': buildQuickReferenceSection(
|
|
243
|
+
[
|
|
244
|
+
{ title: 'Overview', href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}`) },
|
|
245
|
+
hasResources && {
|
|
246
|
+
title: 'Domain Resources',
|
|
247
|
+
href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}/resources`),
|
|
248
|
+
},
|
|
249
|
+
renderUbiquitousLanguage && {
|
|
250
|
+
title: 'Ubiquitous Language',
|
|
251
|
+
href: buildUrl(`/docs/domains/${domain.data.id}/language`),
|
|
252
|
+
},
|
|
253
|
+
isChangelogEnabled() &&
|
|
254
|
+
shouldRenderSideBarSection(domain, 'changelog') && {
|
|
255
|
+
title: 'Changelog',
|
|
256
|
+
href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}/changelog`),
|
|
257
|
+
},
|
|
258
|
+
].filter(Boolean) as { title: string; href: string }[]
|
|
259
|
+
),
|
|
260
|
+
documentation: docsSection,
|
|
261
|
+
architecture: {
|
|
262
|
+
type: 'group',
|
|
263
|
+
title: 'Architecture',
|
|
264
|
+
icon: 'Workflow',
|
|
265
|
+
pages: [
|
|
266
|
+
{
|
|
267
|
+
type: 'item',
|
|
268
|
+
title: 'Overview',
|
|
269
|
+
href: buildUrl(`/architecture/domains/${domain.data.id}/${domain.data.version}`),
|
|
270
|
+
},
|
|
271
|
+
renderSystems &&
|
|
272
|
+
renderVisualiser &&
|
|
273
|
+
hasSystemContext && {
|
|
274
|
+
type: 'item',
|
|
275
|
+
title: 'System Diagram',
|
|
276
|
+
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/systems-context`),
|
|
277
|
+
},
|
|
278
|
+
renderVisualiser &&
|
|
279
|
+
hasResourceDiagram && {
|
|
280
|
+
type: 'item',
|
|
281
|
+
title: 'Resource Diagram',
|
|
282
|
+
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
|
|
283
|
+
},
|
|
284
|
+
renderEntities &&
|
|
285
|
+
renderVisualiser && {
|
|
286
|
+
type: 'item',
|
|
287
|
+
title: 'Entity Diagram',
|
|
288
|
+
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/entity-map`),
|
|
289
|
+
},
|
|
290
|
+
].filter(Boolean) as ChildRef[],
|
|
291
|
+
},
|
|
292
|
+
diagrams: hasDiagrams
|
|
293
|
+
? {
|
|
294
|
+
type: 'group',
|
|
295
|
+
title: 'Diagrams',
|
|
296
|
+
icon: 'FileImage',
|
|
297
|
+
pages: diagramNavItems,
|
|
298
|
+
}
|
|
299
|
+
: null,
|
|
300
|
+
'api-and-contracts': renderSpecifications
|
|
301
|
+
? {
|
|
302
|
+
type: 'group',
|
|
303
|
+
title: 'API & Contracts',
|
|
304
|
+
icon: 'FileCode',
|
|
305
|
+
pages: [
|
|
306
|
+
...openAPISpecifications.map((specification) => ({
|
|
307
|
+
type: 'item',
|
|
308
|
+
title: specification.name,
|
|
309
|
+
leftIcon: '/icons/openapi-black.svg',
|
|
310
|
+
href: buildUrl(
|
|
311
|
+
`/docs/domains/${domain.data.id}/${domain.data.version}/spec/${specification.filenameWithoutExtension}`
|
|
312
|
+
),
|
|
313
|
+
})),
|
|
314
|
+
...asyncAPISpecifications.map((specification) => ({
|
|
315
|
+
type: 'item',
|
|
316
|
+
title: specification.name,
|
|
317
|
+
leftIcon: '/icons/asyncapi-black.svg',
|
|
318
|
+
href: buildUrl(
|
|
319
|
+
`/docs/domains/${domain.data.id}/${domain.data.version}/asyncapi/${specification.filenameWithoutExtension}`
|
|
320
|
+
),
|
|
321
|
+
})),
|
|
322
|
+
...graphQLSpecifications.map((specification) => ({
|
|
323
|
+
type: 'item',
|
|
324
|
+
title: specification.name,
|
|
325
|
+
leftIcon: '/icons/graphql-black.svg',
|
|
326
|
+
href: buildUrl(
|
|
327
|
+
`/docs/domains/${domain.data.id}/${domain.data.version}/graphql/${specification.filenameWithoutExtension}`
|
|
328
|
+
),
|
|
329
|
+
})),
|
|
330
|
+
],
|
|
331
|
+
}
|
|
332
|
+
: null,
|
|
333
|
+
systems: renderSystems
|
|
334
|
+
? {
|
|
335
|
+
type: 'group',
|
|
336
|
+
title: 'Systems',
|
|
337
|
+
icon: 'Group',
|
|
338
|
+
pages: systemsInDomain.map((system) => `system:${(system as any).data.id}:${(system as any).data.version}`),
|
|
339
|
+
}
|
|
340
|
+
: null,
|
|
341
|
+
subdomains: renderSubDomains
|
|
342
|
+
? {
|
|
343
|
+
type: 'group',
|
|
344
|
+
title: 'Subdomains',
|
|
345
|
+
icon: 'Boxes',
|
|
346
|
+
pages: subDomains.map((domain) => `domain:${(domain as any).data.id}:${(domain as any).data.version}`),
|
|
347
|
+
}
|
|
348
|
+
: null,
|
|
349
|
+
resources:
|
|
350
|
+
resourceSubsections.length > 0
|
|
351
|
+
? {
|
|
352
|
+
type: 'group',
|
|
353
|
+
title: 'Resources',
|
|
354
|
+
icon: 'Boxes',
|
|
355
|
+
// Resource type subsections are ordered A-Z by their title, and the
|
|
356
|
+
// resources within each subsection are ordered A-Z by name (sorted above).
|
|
357
|
+
pages: resourceSubsections
|
|
358
|
+
.map((section) => ({ ...section, subtle: true }))
|
|
359
|
+
.sort((a, b) => a.title.localeCompare(b.title)) as ChildRef[],
|
|
360
|
+
}
|
|
361
|
+
: null,
|
|
362
|
+
services: servicesSection,
|
|
363
|
+
flows: flowsSection,
|
|
364
|
+
entities: entitiesSection,
|
|
365
|
+
'domain-events': domainEventsSection,
|
|
366
|
+
'external-events': externalEventsSection,
|
|
367
|
+
'resource-groups': hasResourceGroups
|
|
368
|
+
? (buildResourceGroupSections(resourceGroups, context).filter(Boolean) as NavNode[])
|
|
369
|
+
: null,
|
|
370
|
+
agents: renderAgents
|
|
371
|
+
? {
|
|
372
|
+
type: 'group',
|
|
373
|
+
title: 'Agents In Domain',
|
|
374
|
+
icon: 'Bot',
|
|
375
|
+
pages: agentsInDomain.map((agent) => `agent:${(agent as any).data.id}:${(agent as any).data.version}`),
|
|
376
|
+
}
|
|
377
|
+
: null,
|
|
378
|
+
'external-integrations': renderExternalSystems
|
|
379
|
+
? {
|
|
380
|
+
type: 'group',
|
|
381
|
+
title: 'External Integrations',
|
|
382
|
+
icon: 'Globe',
|
|
383
|
+
pages: externalSystemsInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
384
|
+
}
|
|
385
|
+
: null,
|
|
386
|
+
'data-products': renderDataProducts
|
|
387
|
+
? {
|
|
388
|
+
type: 'group',
|
|
389
|
+
title: 'Data Products',
|
|
390
|
+
icon: 'Package',
|
|
391
|
+
pages: dataProductsInDomain.map(
|
|
392
|
+
(dataProduct) => `data-product:${(dataProduct as any).data.id}:${(dataProduct as any).data.version}`
|
|
393
|
+
),
|
|
394
|
+
}
|
|
395
|
+
: null,
|
|
396
|
+
'decision-records': shouldRenderSideBarSection(domain, 'architectureDecisions')
|
|
397
|
+
? buildArchitectureDecisionsSection(domain, context.adrs || [])
|
|
398
|
+
: null,
|
|
399
|
+
owners: renderOwners ? buildOwnersSection(owners) : null,
|
|
400
|
+
code: renderRepository ? buildRepositorySection(domain.data.repository as { url: string; language: string }) : null,
|
|
401
|
+
attachments: hasAttachments ? buildAttachmentsSection(domain.data.attachments as any[]) : null,
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
export type BuildDomainNodeOptions = {
|
|
406
|
+
/** A parsed `sidebar.json` for this domain. When present it replaces the generated sidebar. */
|
|
407
|
+
sidebar?: SidebarSpec;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
export const buildDomainNode = (
|
|
411
|
+
domain: CollectionEntry<'domains'>,
|
|
412
|
+
owners: any[],
|
|
413
|
+
context: ResourceGroupContext,
|
|
414
|
+
options: BuildDomainNodeOptions = {}
|
|
415
|
+
): NavNode => {
|
|
416
|
+
const sections = buildDomainSections(domain, owners, context);
|
|
417
|
+
|
|
418
|
+
const pages = resolveSidebarPages(sections, DEFAULT_DOMAIN_SECTION_ORDER, {
|
|
419
|
+
sidebar: options.sidebar,
|
|
420
|
+
resource: { collection: 'domains', id: domain.data.id, version: domain.data.version, entry: domain },
|
|
421
|
+
context: toCustomSidebarContext(context),
|
|
422
|
+
});
|
|
423
|
+
|
|
120
424
|
return {
|
|
121
425
|
type: 'item',
|
|
122
426
|
title: domain.data.name,
|
|
@@ -126,192 +430,6 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
126
430
|
// 'Domains' section header (and Domain badge) already convey the type, so the
|
|
127
431
|
// default Boxes glyph on every item is redundant.
|
|
128
432
|
...customIconFieldsForResource(domain.data),
|
|
129
|
-
pages
|
|
130
|
-
buildQuickReferenceSection(
|
|
131
|
-
[
|
|
132
|
-
{ title: 'Overview', href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}`) },
|
|
133
|
-
hasResources && {
|
|
134
|
-
title: 'Domain Resources',
|
|
135
|
-
href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}/resources`),
|
|
136
|
-
},
|
|
137
|
-
renderUbiquitousLanguage && {
|
|
138
|
-
title: 'Ubiquitous Language',
|
|
139
|
-
href: buildUrl(`/docs/domains/${domain.data.id}/language`),
|
|
140
|
-
},
|
|
141
|
-
isChangelogEnabled() &&
|
|
142
|
-
shouldRenderSideBarSection(domain, 'changelog') && {
|
|
143
|
-
title: 'Changelog',
|
|
144
|
-
href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}/changelog`),
|
|
145
|
-
},
|
|
146
|
-
].filter(Boolean) as { title: string; href: string }[]
|
|
147
|
-
),
|
|
148
|
-
docsSection,
|
|
149
|
-
{
|
|
150
|
-
type: 'group',
|
|
151
|
-
title: 'Architecture',
|
|
152
|
-
icon: 'Workflow',
|
|
153
|
-
pages: [
|
|
154
|
-
{
|
|
155
|
-
type: 'item',
|
|
156
|
-
title: 'Overview',
|
|
157
|
-
href: buildUrl(`/architecture/domains/${domain.data.id}/${domain.data.version}`),
|
|
158
|
-
},
|
|
159
|
-
renderSystems &&
|
|
160
|
-
renderVisualiser &&
|
|
161
|
-
hasSystemContext && {
|
|
162
|
-
type: 'item',
|
|
163
|
-
title: 'System Diagram',
|
|
164
|
-
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/systems-context`),
|
|
165
|
-
},
|
|
166
|
-
renderVisualiser &&
|
|
167
|
-
hasResourceDiagram && {
|
|
168
|
-
type: 'item',
|
|
169
|
-
title: 'Resource Diagram',
|
|
170
|
-
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
|
|
171
|
-
},
|
|
172
|
-
renderEntities &&
|
|
173
|
-
renderVisualiser && {
|
|
174
|
-
type: 'item',
|
|
175
|
-
title: 'Entity Diagram',
|
|
176
|
-
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/entity-map`),
|
|
177
|
-
},
|
|
178
|
-
].filter(Boolean) as ChildRef[],
|
|
179
|
-
},
|
|
180
|
-
hasDiagrams && {
|
|
181
|
-
type: 'group',
|
|
182
|
-
title: 'Diagrams',
|
|
183
|
-
icon: 'FileImage',
|
|
184
|
-
pages: diagramNavItems,
|
|
185
|
-
},
|
|
186
|
-
renderSpecifications && {
|
|
187
|
-
type: 'group',
|
|
188
|
-
title: 'API & Contracts',
|
|
189
|
-
icon: 'FileCode',
|
|
190
|
-
pages: [
|
|
191
|
-
...openAPISpecifications.map((specification) => ({
|
|
192
|
-
type: 'item',
|
|
193
|
-
title: specification.name,
|
|
194
|
-
leftIcon: '/icons/openapi-black.svg',
|
|
195
|
-
href: buildUrl(
|
|
196
|
-
`/docs/domains/${domain.data.id}/${domain.data.version}/spec/${specification.filenameWithoutExtension}`
|
|
197
|
-
),
|
|
198
|
-
})),
|
|
199
|
-
...asyncAPISpecifications.map((specification) => ({
|
|
200
|
-
type: 'item',
|
|
201
|
-
title: specification.name,
|
|
202
|
-
leftIcon: '/icons/asyncapi-black.svg',
|
|
203
|
-
href: buildUrl(
|
|
204
|
-
`/docs/domains/${domain.data.id}/${domain.data.version}/asyncapi/${specification.filenameWithoutExtension}`
|
|
205
|
-
),
|
|
206
|
-
})),
|
|
207
|
-
...graphQLSpecifications.map((specification) => ({
|
|
208
|
-
type: 'item',
|
|
209
|
-
title: specification.name,
|
|
210
|
-
leftIcon: '/icons/graphql-black.svg',
|
|
211
|
-
href: buildUrl(
|
|
212
|
-
`/docs/domains/${domain.data.id}/${domain.data.version}/graphql/${specification.filenameWithoutExtension}`
|
|
213
|
-
),
|
|
214
|
-
})),
|
|
215
|
-
],
|
|
216
|
-
},
|
|
217
|
-
renderSystems && {
|
|
218
|
-
type: 'group',
|
|
219
|
-
title: 'Systems',
|
|
220
|
-
icon: 'Group',
|
|
221
|
-
pages: systemsInDomain.map((system) => `system:${(system as any).data.id}:${(system as any).data.version}`),
|
|
222
|
-
},
|
|
223
|
-
renderSubDomains && {
|
|
224
|
-
type: 'group',
|
|
225
|
-
title: 'Subdomains',
|
|
226
|
-
icon: 'Boxes',
|
|
227
|
-
pages: subDomains.map((domain) => `domain:${(domain as any).data.id}:${(domain as any).data.version}`),
|
|
228
|
-
},
|
|
229
|
-
(renderServices ||
|
|
230
|
-
hasFlows ||
|
|
231
|
-
renderEntities ||
|
|
232
|
-
(renderMessages && (sendsMessages.length > 0 || receivesMessages.length > 0))) && {
|
|
233
|
-
type: 'group',
|
|
234
|
-
title: 'Resources',
|
|
235
|
-
icon: 'Boxes',
|
|
236
|
-
// Resource type subsections are ordered A-Z by their title, and the
|
|
237
|
-
// resources within each subsection are ordered A-Z by name (sorted above).
|
|
238
|
-
pages: (
|
|
239
|
-
[
|
|
240
|
-
renderServices && {
|
|
241
|
-
type: 'group',
|
|
242
|
-
title: 'Services',
|
|
243
|
-
subtle: true,
|
|
244
|
-
icon: 'Server',
|
|
245
|
-
pages: servicesInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
246
|
-
},
|
|
247
|
-
hasFlows && {
|
|
248
|
-
type: 'group',
|
|
249
|
-
title: 'Flows',
|
|
250
|
-
subtle: true,
|
|
251
|
-
icon: 'Waypoints',
|
|
252
|
-
pages: domainFlows.map((flow) => `flow:${(flow as any).data.id}:${(flow as any).data.version}`),
|
|
253
|
-
},
|
|
254
|
-
renderEntities && {
|
|
255
|
-
type: 'group',
|
|
256
|
-
title: 'Entities',
|
|
257
|
-
subtle: true,
|
|
258
|
-
icon: 'Box',
|
|
259
|
-
pages: entitiesInDomain.map((entity) => ({
|
|
260
|
-
type: 'item',
|
|
261
|
-
title: (entity as any).data?.name || (entity as any).data.id,
|
|
262
|
-
href: buildUrl(`/docs/entities/${(entity as any).data.id}/${(entity as any).data.version}`),
|
|
263
|
-
})),
|
|
264
|
-
},
|
|
265
|
-
renderMessages &&
|
|
266
|
-
sendsMessages.length > 0 && {
|
|
267
|
-
type: 'group',
|
|
268
|
-
title: 'Domain Events',
|
|
269
|
-
subtle: true,
|
|
270
|
-
icon: 'Mail',
|
|
271
|
-
pages: sortedSendsMessages.map(
|
|
272
|
-
(message) =>
|
|
273
|
-
`${pluralizeMessageType(message as any)}:${(message as any).data.id}:${(message as any).data.version}`
|
|
274
|
-
),
|
|
275
|
-
},
|
|
276
|
-
renderMessages &&
|
|
277
|
-
receivesMessages.length > 0 && {
|
|
278
|
-
type: 'group',
|
|
279
|
-
title: 'External Events',
|
|
280
|
-
subtle: true,
|
|
281
|
-
icon: 'Mail',
|
|
282
|
-
pages: sortedReceivesMessages.map(
|
|
283
|
-
(receive) =>
|
|
284
|
-
`${pluralizeMessageType(receive as any)}:${(receive as any).data.id}:${(receive as any).data.version}`
|
|
285
|
-
),
|
|
286
|
-
},
|
|
287
|
-
].filter(Boolean) as NavNode[]
|
|
288
|
-
).sort((a, b) => a.title.localeCompare(b.title)) as ChildRef[],
|
|
289
|
-
},
|
|
290
|
-
|
|
291
|
-
...(hasResourceGroups ? buildResourceGroupSections(resourceGroups, context) : []),
|
|
292
|
-
renderAgents && {
|
|
293
|
-
type: 'group',
|
|
294
|
-
title: 'Agents In Domain',
|
|
295
|
-
icon: 'Bot',
|
|
296
|
-
pages: agentsInDomain.map((agent) => `agent:${(agent as any).data.id}:${(agent as any).data.version}`),
|
|
297
|
-
},
|
|
298
|
-
renderExternalSystems && {
|
|
299
|
-
type: 'group',
|
|
300
|
-
title: 'External Integrations',
|
|
301
|
-
icon: 'Globe',
|
|
302
|
-
pages: externalSystemsInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
303
|
-
},
|
|
304
|
-
renderDataProducts && {
|
|
305
|
-
type: 'group',
|
|
306
|
-
title: 'Data Products',
|
|
307
|
-
icon: 'Package',
|
|
308
|
-
pages: dataProductsInDomain.map(
|
|
309
|
-
(dataProduct) => `data-product:${(dataProduct as any).data.id}:${(dataProduct as any).data.version}`
|
|
310
|
-
),
|
|
311
|
-
},
|
|
312
|
-
renderOwners && buildOwnersSection(owners),
|
|
313
|
-
renderRepository && buildRepositorySection(domain.data.repository as { url: string; language: string }),
|
|
314
|
-
hasAttachments && buildAttachmentsSection(domain.data.attachments as any[]),
|
|
315
|
-
].filter(Boolean) as ChildRef[],
|
|
433
|
+
pages,
|
|
316
434
|
};
|
|
317
435
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { CollectionEntry } from 'astro:content';
|
|
2
2
|
import { buildUrl } from '@utils/url-builder';
|
|
3
|
-
import type { NavNode,
|
|
3
|
+
import type { NavNode, ResourceGroupContext } from './shared';
|
|
4
4
|
import {
|
|
5
|
+
buildArchitectureDecisionsSection,
|
|
5
6
|
buildAttachmentsSection,
|
|
6
7
|
buildOwnersSection,
|
|
7
8
|
buildQuickReferenceSection,
|
|
@@ -10,8 +11,45 @@ import {
|
|
|
10
11
|
} from './shared';
|
|
11
12
|
import { isChangelogEnabled, isVisualiserEnabled } from '@utils/feature';
|
|
12
13
|
import { iconFieldsForResource } from '@utils/icon';
|
|
14
|
+
import { resolveSidebarPages, toCustomSidebarContext, type SidebarSpec } from '../custom-sidebar';
|
|
13
15
|
|
|
14
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Predefined sidebar sections for an entity, keyed by the token users reference from
|
|
18
|
+
* `sidebar.json` (e.g. `$quick-reference`). Each token is the kebab-cased title of the
|
|
19
|
+
* section as it appears in the default sidebar.
|
|
20
|
+
*/
|
|
21
|
+
export type EntitySectionKey =
|
|
22
|
+
| 'quick-reference'
|
|
23
|
+
| 'documentation'
|
|
24
|
+
| 'architecture'
|
|
25
|
+
| 'domains'
|
|
26
|
+
| 'services'
|
|
27
|
+
| 'decision-records'
|
|
28
|
+
| 'owners'
|
|
29
|
+
| 'attachments';
|
|
30
|
+
|
|
31
|
+
export type EntitySections = Record<EntitySectionKey, NavNode | NavNode[] | null>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Order of sections in the default (generated) sidebar. `decision-records` is deliberately
|
|
35
|
+
* absent — in default mode it is inserted before Owners by `withArchitectureDecisionsSection`
|
|
36
|
+
* in state.ts, and only becomes a first-class token for custom sidebars.
|
|
37
|
+
*/
|
|
38
|
+
export const DEFAULT_ENTITY_SECTION_ORDER: EntitySectionKey[] = [
|
|
39
|
+
'quick-reference',
|
|
40
|
+
'documentation',
|
|
41
|
+
'architecture',
|
|
42
|
+
'domains',
|
|
43
|
+
'services',
|
|
44
|
+
'owners',
|
|
45
|
+
'attachments',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
export const buildEntitySections = (
|
|
49
|
+
entity: CollectionEntry<'entities'>,
|
|
50
|
+
owners: any[],
|
|
51
|
+
context: ResourceGroupContext
|
|
52
|
+
): EntitySections => {
|
|
15
53
|
const domains = entity.data.domains || [];
|
|
16
54
|
const services = entity.data.services || [];
|
|
17
55
|
|
|
@@ -40,48 +78,79 @@ export const buildEntityNode = (entity: CollectionEntry<'entities'>, owners: any
|
|
|
40
78
|
context.resourceDocCategories
|
|
41
79
|
);
|
|
42
80
|
|
|
81
|
+
return {
|
|
82
|
+
'quick-reference': buildQuickReferenceSection(
|
|
83
|
+
[
|
|
84
|
+
{ title: 'Overview', href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}`) },
|
|
85
|
+
isChangelogEnabled() &&
|
|
86
|
+
shouldRenderSideBarSection(entity, 'changelog') && {
|
|
87
|
+
title: 'Changelog',
|
|
88
|
+
href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}/changelog`),
|
|
89
|
+
},
|
|
90
|
+
].filter(Boolean) as { title: string; href: string }[]
|
|
91
|
+
),
|
|
92
|
+
documentation: docsSection,
|
|
93
|
+
architecture: renderArchitecture
|
|
94
|
+
? {
|
|
95
|
+
type: 'group',
|
|
96
|
+
title: 'Architecture',
|
|
97
|
+
icon: 'Workflow',
|
|
98
|
+
pages: entityMapTargets.map((target) => ({
|
|
99
|
+
type: 'item',
|
|
100
|
+
title: entityMapTargets.length === 1 ? 'Entity Map' : `${target.label} Entity Map`,
|
|
101
|
+
href: target.href,
|
|
102
|
+
})),
|
|
103
|
+
}
|
|
104
|
+
: null,
|
|
105
|
+
domains: renderDomains
|
|
106
|
+
? {
|
|
107
|
+
type: 'group',
|
|
108
|
+
title: 'Domains',
|
|
109
|
+
icon: 'Boxes',
|
|
110
|
+
pages: domains.map((domain: any) => `domain:${domain.data.id}:${domain.data.version}`),
|
|
111
|
+
}
|
|
112
|
+
: null,
|
|
113
|
+
services: renderServices
|
|
114
|
+
? {
|
|
115
|
+
type: 'group',
|
|
116
|
+
title: 'Services',
|
|
117
|
+
icon: 'Server',
|
|
118
|
+
pages: services.map((service: any) => `service:${service.data.id}:${service.data.version}`),
|
|
119
|
+
}
|
|
120
|
+
: null,
|
|
121
|
+
'decision-records': shouldRenderSideBarSection(entity, 'architectureDecisions')
|
|
122
|
+
? buildArchitectureDecisionsSection(entity, context.adrs || [])
|
|
123
|
+
: null,
|
|
124
|
+
owners: renderOwners ? buildOwnersSection(owners) : null,
|
|
125
|
+
attachments: hasAttachments ? buildAttachmentsSection(entity.data.attachments as any[]) : null,
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
export type BuildEntityNodeOptions = {
|
|
130
|
+
/** A parsed `sidebar.json` for this entity. When present it replaces the generated sidebar. */
|
|
131
|
+
sidebar?: SidebarSpec;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const buildEntityNode = (
|
|
135
|
+
entity: CollectionEntry<'entities'>,
|
|
136
|
+
owners: any[],
|
|
137
|
+
context: ResourceGroupContext,
|
|
138
|
+
options: BuildEntityNodeOptions = {}
|
|
139
|
+
): NavNode => {
|
|
140
|
+
const sections = buildEntitySections(entity, owners, context);
|
|
141
|
+
|
|
142
|
+
const pages = resolveSidebarPages(sections, DEFAULT_ENTITY_SECTION_ORDER, {
|
|
143
|
+
sidebar: options.sidebar,
|
|
144
|
+
resource: { collection: 'entities', id: entity.data.id, version: entity.data.version, entry: entity },
|
|
145
|
+
context: toCustomSidebarContext(context),
|
|
146
|
+
});
|
|
147
|
+
|
|
43
148
|
return {
|
|
44
149
|
type: 'item',
|
|
45
150
|
title: entity.data.name,
|
|
46
151
|
badge: 'Entity',
|
|
47
152
|
summary: entity.data.summary,
|
|
48
153
|
...iconFieldsForResource(entity.data, 'Box'),
|
|
49
|
-
pages
|
|
50
|
-
buildQuickReferenceSection(
|
|
51
|
-
[
|
|
52
|
-
{ title: 'Overview', href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}`) },
|
|
53
|
-
isChangelogEnabled() &&
|
|
54
|
-
shouldRenderSideBarSection(entity, 'changelog') && {
|
|
55
|
-
title: 'Changelog',
|
|
56
|
-
href: buildUrl(`/docs/entities/${entity.data.id}/${entity.data.version}/changelog`),
|
|
57
|
-
},
|
|
58
|
-
].filter(Boolean) as { title: string; href: string }[]
|
|
59
|
-
),
|
|
60
|
-
docsSection,
|
|
61
|
-
renderArchitecture && {
|
|
62
|
-
type: 'group',
|
|
63
|
-
title: 'Architecture',
|
|
64
|
-
icon: 'Workflow',
|
|
65
|
-
pages: entityMapTargets.map((target) => ({
|
|
66
|
-
type: 'item',
|
|
67
|
-
title: entityMapTargets.length === 1 ? 'Entity Map' : `${target.label} Entity Map`,
|
|
68
|
-
href: target.href,
|
|
69
|
-
})),
|
|
70
|
-
},
|
|
71
|
-
renderDomains && {
|
|
72
|
-
type: 'group',
|
|
73
|
-
title: 'Domains',
|
|
74
|
-
icon: 'Boxes',
|
|
75
|
-
pages: domains.map((domain: any) => `domain:${domain.data.id}:${domain.data.version}`),
|
|
76
|
-
},
|
|
77
|
-
renderServices && {
|
|
78
|
-
type: 'group',
|
|
79
|
-
title: 'Services',
|
|
80
|
-
icon: 'Server',
|
|
81
|
-
pages: services.map((service: any) => `service:${service.data.id}:${service.data.version}`),
|
|
82
|
-
},
|
|
83
|
-
renderOwners && buildOwnersSection(owners),
|
|
84
|
-
hasAttachments && buildAttachmentsSection(entity.data.attachments as any[]),
|
|
85
|
-
].filter(Boolean) as ChildRef[],
|
|
154
|
+
pages,
|
|
86
155
|
};
|
|
87
156
|
};
|