@eventcatalog/core 3.48.4 → 4.0.0-beta.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/catalog-to-astro-content-directory.cjs +1 -1
- package/dist/chunk-BWN544LB.js +73 -0
- package/dist/{chunk-XNVSSL4W.js → chunk-JTZT2SDF.js} +1 -1
- package/dist/{chunk-JY4H7A4S.js → chunk-M2ZRT7KQ.js} +1 -1
- package/dist/{chunk-SY4XL6OQ.js → chunk-MBVTS76Q.js} +1 -1
- package/dist/{chunk-KDLSBQRP.js → chunk-TZTPGQGL.js} +1 -1
- package/dist/{chunk-FNDSHOV2.js → chunk-U5OTNDVQ.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/core-node-modules.cjs +108 -0
- package/dist/core-node-modules.d.cts +7 -0
- package/dist/core-node-modules.d.ts +7 -0
- package/dist/core-node-modules.js +8 -0
- package/dist/docs/development/components/components/15-prompt.md +5 -1
- package/dist/eventcatalog.cjs +124 -48
- package/dist/eventcatalog.js +26 -15
- 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 +27 -23
- package/eventcatalog/public/icons/languages/java.svg +1 -0
- package/eventcatalog/public/icons/payments/stripe.svg +1 -0
- package/eventcatalog/src/components/Badge.astro +10 -10
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +154 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +207 -44
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -20
- package/eventcatalog/src/components/Grids/SystemGrid.tsx +185 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.astro +99 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.client.tsx +400 -0
- package/eventcatalog/src/components/MDX/ContextDiagram/ContextDiagramPortal.tsx +21 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +1 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +42 -6
- package/eventcatalog/src/components/MDX/Prompt/Prompt.astro +62 -9
- package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +8 -1
- package/eventcatalog/src/components/MDX/SystemContextMap/SystemContextMapPortal.tsx +22 -0
- package/eventcatalog/src/components/MDX/components.tsx +7 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -1
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +67 -37
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +47 -0
- package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +10 -2
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +115 -27
- package/eventcatalog/src/components/Tables/Discover/index.ts +7 -1
- package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +267 -0
- package/eventcatalog/src/content.config.ts +96 -8
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +4 -1
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +12 -13
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -0
- package/eventcatalog/src/enterprise/feature.ts +3 -1
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +96 -140
- package/eventcatalog/src/layouts/VisualiserLayout.astro +66 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +4 -2
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +2 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +15 -15
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/discover/[type]/index.astro +47 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +15 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +13 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +11 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +81 -26
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +89 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +85 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/index.astro +30 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +3 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +94 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +51 -0
- package/eventcatalog/src/pages/visualiser/system-context-map/index.astro +41 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +91 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +51 -0
- package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +3 -1
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +3 -1
- package/eventcatalog/src/stores/sidebar-store/builders/container.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +127 -49
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +4 -2
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +2 -1
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +166 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +99 -6
- package/eventcatalog/src/types/index.ts +2 -0
- package/eventcatalog/src/utils/collection-colors.ts +6 -1
- package/eventcatalog/src/utils/collections/domains.ts +35 -0
- package/eventcatalog/src/utils/collections/icons.ts +4 -5
- package/eventcatalog/src/utils/collections/systems.ts +110 -0
- package/eventcatalog/src/utils/collections/teams.ts +15 -10
- package/eventcatalog/src/utils/collections/users.ts +7 -4
- package/eventcatalog/src/utils/collections/util.ts +2 -0
- package/eventcatalog/src/utils/icon-map.ts +20 -0
- package/eventcatalog/src/utils/icon.ts +11 -0
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -2
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +0 -170
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +400 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +208 -0
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +12 -0
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +17 -14
- package/eventcatalog/src/pages/visualiser/context-map/index.astro +0 -30
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
|
|
3
|
+
import VisualiserLayout from '@layouts/VisualiserLayout.astro';
|
|
4
|
+
import { ClientRouter } from 'astro:transitions';
|
|
5
|
+
|
|
6
|
+
import { Page } from './_index.data';
|
|
7
|
+
|
|
8
|
+
export const prerender = Page.prerender;
|
|
9
|
+
export const getStaticPaths = Page.getStaticPaths;
|
|
10
|
+
|
|
11
|
+
// Get data
|
|
12
|
+
const props = await Page.getData(Astro);
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
data: { id },
|
|
16
|
+
} = props;
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<VisualiserLayout title={`Visualiser | ${props.data.name} - System Context`} description={props.data.summary}>
|
|
20
|
+
<div class="p-2">
|
|
21
|
+
<div
|
|
22
|
+
class="h-[calc(100vh-5rem)] w-full relative border border-[rgb(var(--ec-page-border))]"
|
|
23
|
+
id={`${id}-portal`}
|
|
24
|
+
transition:name="visualiser-graph"
|
|
25
|
+
>
|
|
26
|
+
</div>
|
|
27
|
+
<NodeGraph
|
|
28
|
+
id={id}
|
|
29
|
+
collection="systems-context"
|
|
30
|
+
title={`${props.data.name} (v${props.data.version}) - System Context`}
|
|
31
|
+
mode="full"
|
|
32
|
+
linkTo="visualiser"
|
|
33
|
+
version={props.data.version}
|
|
34
|
+
linksToVisualiser={false}
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
<ClientRouter />
|
|
38
|
+
</VisualiserLayout>
|
|
39
|
+
|
|
40
|
+
<script define:vars={{ id }}>
|
|
41
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
42
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
43
|
+
const params = Object.fromEntries(urlSearchParams.entries());
|
|
44
|
+
const embeded = params.embed === 'true' ? true : false;
|
|
45
|
+
const viewport = document.getElementById(`${id}-portal`);
|
|
46
|
+
|
|
47
|
+
if (embeded) {
|
|
48
|
+
viewport.style.height = 'calc(100vh - 30px)';
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
</script>
|
|
@@ -27,6 +27,7 @@ const firstClassResourceCollections = [
|
|
|
27
27
|
'flows',
|
|
28
28
|
'channels',
|
|
29
29
|
'domains',
|
|
30
|
+
'systems',
|
|
30
31
|
'users',
|
|
31
32
|
'teams',
|
|
32
33
|
'containers',
|
|
@@ -50,6 +51,7 @@ const getResourcesForCollection = (collection: string, context: ResourceGroupCon
|
|
|
50
51
|
flows: context.flows,
|
|
51
52
|
channels: context.channels || [],
|
|
52
53
|
domains: context.domains,
|
|
54
|
+
systems: context.systems || [],
|
|
53
55
|
users: context.users || [],
|
|
54
56
|
teams: context.teams || [],
|
|
55
57
|
containers: context.containers,
|
|
@@ -113,7 +115,7 @@ export const buildAdrNode = (adr: Adr, owners: any[], decisionMakers: any[], con
|
|
|
113
115
|
title: adr.data.name,
|
|
114
116
|
badge: 'Decision record',
|
|
115
117
|
summary: adr.data.summary,
|
|
116
|
-
icon: '
|
|
118
|
+
icon: 'ClipboardList',
|
|
117
119
|
pages: [
|
|
118
120
|
buildQuickReferenceSection(
|
|
119
121
|
[
|
|
@@ -129,7 +129,9 @@ export const buildAgentNode = (
|
|
|
129
129
|
},
|
|
130
130
|
hasFlows && {
|
|
131
131
|
type: 'group',
|
|
132
|
-
|
|
132
|
+
// If the agent declares its own flows it owns them ("Flows"); otherwise it is
|
|
133
|
+
// only referenced as a step in someone else's flow ("Appears in flows").
|
|
134
|
+
title: agentFlows.length > 0 ? 'Flows' : 'Appears in flows',
|
|
133
135
|
icon: 'Waypoints',
|
|
134
136
|
pages: agentFlowRefs,
|
|
135
137
|
},
|
|
@@ -14,14 +14,17 @@ import {
|
|
|
14
14
|
import { isVisualiserEnabled, isChangelogEnabled } from '@utils/feature';
|
|
15
15
|
import { pluralizeMessageType } from '@utils/collections/messages';
|
|
16
16
|
import { getSpecificationsForDomain, hasUbiquitousLanguageTermsWithSubdomainsInCollection } from '@utils/collections/domains';
|
|
17
|
-
import {
|
|
17
|
+
import { customIconFieldsForResource } from '@utils/icon';
|
|
18
|
+
|
|
19
|
+
// Sort resolved collection entries A-Z by their display name (falling back to id).
|
|
20
|
+
const byResourceName = (a: any, b: any) => (a.data?.name || a.data?.id || '').localeCompare(b.data?.name || b.data?.id || '');
|
|
18
21
|
|
|
19
22
|
export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[], context: ResourceGroupContext): NavNode => {
|
|
20
23
|
const agentsInDomain = domain.data.agents || [];
|
|
21
24
|
const renderAgents = agentsInDomain.length > 0 && shouldRenderSideBarSection(domain, 'agents');
|
|
22
25
|
|
|
23
26
|
const allServicesInDomain = domain.data.services || [];
|
|
24
|
-
const servicesInDomain = allServicesInDomain.filter((service) => !(service as any).data?.externalSystem);
|
|
27
|
+
const servicesInDomain = allServicesInDomain.filter((service) => !(service as any).data?.externalSystem).sort(byResourceName);
|
|
25
28
|
const externalSystemsInDomain = allServicesInDomain.filter((service) => (service as any).data?.externalSystem);
|
|
26
29
|
const renderServices = servicesInDomain.length > 0 && shouldRenderSideBarSection(domain, 'services');
|
|
27
30
|
const renderExternalSystems = externalSystemsInDomain.length > 0 && shouldRenderSideBarSection(domain, 'services');
|
|
@@ -29,13 +32,25 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
29
32
|
const dataProductsInDomain = domain.data['data-products'] || [];
|
|
30
33
|
const renderDataProducts = dataProductsInDomain.length > 0 && shouldRenderSideBarSection(domain, 'data-products');
|
|
31
34
|
|
|
35
|
+
const systemsInDomain = domain.data.systems || [];
|
|
36
|
+
const renderSystems = systemsInDomain.length > 0 && shouldRenderSideBarSection(domain, 'systems');
|
|
37
|
+
|
|
38
|
+
// The domain's System Diagram only has something to show when at least one of
|
|
39
|
+
// its systems takes part in a context graph (declares relationships or actors). This
|
|
40
|
+
// mirrors the guard that generates the visualiser page, so we never link to a page
|
|
41
|
+
// that wasn't generated.
|
|
42
|
+
const hasSystemContext = systemsInDomain.some((system: any) => {
|
|
43
|
+
const data = system?.data || system;
|
|
44
|
+
return (data?.relationships || []).length > 0 || (data?.actors || []).length > 0;
|
|
45
|
+
});
|
|
46
|
+
|
|
32
47
|
const subDomains = domain.data.domains || [];
|
|
33
48
|
const renderSubDomains = subDomains.length > 0 && shouldRenderSideBarSection(domain, 'subdomains');
|
|
34
49
|
|
|
35
|
-
const entitiesInDomain = domain.data.entities || [];
|
|
50
|
+
const entitiesInDomain = [...(domain.data.entities || [])].sort(byResourceName);
|
|
36
51
|
const renderEntities = entitiesInDomain.length > 0 && shouldRenderSideBarSection(domain, 'entities');
|
|
37
52
|
|
|
38
|
-
const domainFlows = domain.data.flows || [];
|
|
53
|
+
const domainFlows = [...(domain.data.flows || [])].sort(byResourceName);
|
|
39
54
|
const hasFlows = domainFlows.length > 0;
|
|
40
55
|
|
|
41
56
|
const resourceGroups = domain.data.resourceGroups || [];
|
|
@@ -62,8 +77,29 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
62
77
|
// Domain-level messages (sends/receives)
|
|
63
78
|
const sendsMessages = domain.data.sends || [];
|
|
64
79
|
const receivesMessages = domain.data.receives || [];
|
|
80
|
+
const sortedSendsMessages = [...sendsMessages].sort(byResourceName);
|
|
81
|
+
const sortedReceivesMessages = [...receivesMessages].sort(byResourceName);
|
|
65
82
|
const renderMessages = shouldRenderSideBarSection(domain, 'messages');
|
|
66
83
|
|
|
84
|
+
// The Resources page/link only makes sense when the domain actually has resources
|
|
85
|
+
// attached (services, flows, entities or its own messages). Mirrors what the page renders.
|
|
86
|
+
const hasResources =
|
|
87
|
+
servicesInDomain.length > 0 ||
|
|
88
|
+
domainFlows.length > 0 ||
|
|
89
|
+
entitiesInDomain.length > 0 ||
|
|
90
|
+
sendsMessages.length > 0 ||
|
|
91
|
+
receivesMessages.length > 0;
|
|
92
|
+
|
|
93
|
+
// The Resource Diagram renders the domain's services, agents, data products and
|
|
94
|
+
// subdomains (see domains-node-graph). Only link to it when there's something to
|
|
95
|
+
// draw — otherwise the visualiser page is empty.
|
|
96
|
+
const hasResourceDiagram =
|
|
97
|
+
servicesInDomain.length > 0 ||
|
|
98
|
+
externalSystemsInDomain.length > 0 ||
|
|
99
|
+
agentsInDomain.length > 0 ||
|
|
100
|
+
dataProductsInDomain.length > 0 ||
|
|
101
|
+
subDomains.length > 0;
|
|
102
|
+
|
|
67
103
|
// Diagrams
|
|
68
104
|
const domainDiagrams = domain.data.diagrams || [];
|
|
69
105
|
const diagramNavItems = buildDiagramNavItems(domainDiagrams, context.diagrams);
|
|
@@ -82,11 +118,18 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
82
118
|
title: domain.data.name,
|
|
83
119
|
badge: 'Domain',
|
|
84
120
|
summary: domain.data.summary,
|
|
85
|
-
|
|
121
|
+
// Domains use a custom icon when defined, otherwise none — the surrounding
|
|
122
|
+
// 'Domains' section header (and Domain badge) already convey the type, so the
|
|
123
|
+
// default Boxes glyph on every item is redundant.
|
|
124
|
+
...customIconFieldsForResource(domain.data),
|
|
86
125
|
pages: [
|
|
87
126
|
buildQuickReferenceSection(
|
|
88
127
|
[
|
|
89
128
|
{ title: 'Overview', href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}`) },
|
|
129
|
+
hasResources && {
|
|
130
|
+
title: 'Domain Resources',
|
|
131
|
+
href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}/resources`),
|
|
132
|
+
},
|
|
90
133
|
renderUbiquitousLanguage && {
|
|
91
134
|
title: 'Ubiquitous Language',
|
|
92
135
|
href: buildUrl(`/docs/domains/${domain.data.id}/language`),
|
|
@@ -109,15 +152,23 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
109
152
|
title: 'Overview',
|
|
110
153
|
href: buildUrl(`/architecture/domains/${domain.data.id}/${domain.data.version}`),
|
|
111
154
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
155
|
+
renderSystems &&
|
|
156
|
+
renderVisualiser &&
|
|
157
|
+
hasSystemContext && {
|
|
158
|
+
type: 'item',
|
|
159
|
+
title: 'System Diagram',
|
|
160
|
+
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/systems-context`),
|
|
161
|
+
},
|
|
162
|
+
renderVisualiser &&
|
|
163
|
+
hasResourceDiagram && {
|
|
164
|
+
type: 'item',
|
|
165
|
+
title: 'Resource Diagram',
|
|
166
|
+
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
|
|
167
|
+
},
|
|
117
168
|
renderEntities &&
|
|
118
169
|
renderVisualiser && {
|
|
119
170
|
type: 'item',
|
|
120
|
-
title: 'Entity
|
|
171
|
+
title: 'Entity Diagram',
|
|
121
172
|
href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/entity-map`),
|
|
122
173
|
},
|
|
123
174
|
].filter(Boolean) as ChildRef[],
|
|
@@ -159,36 +210,81 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
159
210
|
})),
|
|
160
211
|
],
|
|
161
212
|
},
|
|
213
|
+
renderSystems && {
|
|
214
|
+
type: 'group',
|
|
215
|
+
title: 'Systems',
|
|
216
|
+
icon: 'Group',
|
|
217
|
+
pages: systemsInDomain.map((system) => `system:${(system as any).data.id}:${(system as any).data.version}`),
|
|
218
|
+
},
|
|
162
219
|
renderSubDomains && {
|
|
163
220
|
type: 'group',
|
|
164
221
|
title: 'Subdomains',
|
|
165
222
|
icon: 'Boxes',
|
|
166
223
|
pages: subDomains.map((domain) => `domain:${(domain as any).data.id}:${(domain as any).data.version}`),
|
|
167
224
|
},
|
|
168
|
-
|
|
225
|
+
(renderServices ||
|
|
226
|
+
hasFlows ||
|
|
227
|
+
renderEntities ||
|
|
228
|
+
(renderMessages && (sendsMessages.length > 0 || receivesMessages.length > 0))) && {
|
|
169
229
|
type: 'group',
|
|
170
|
-
title: '
|
|
171
|
-
icon: '
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
230
|
+
title: 'Resources',
|
|
231
|
+
icon: 'Boxes',
|
|
232
|
+
// Resource type subsections are ordered A-Z by their title, and the
|
|
233
|
+
// resources within each subsection are ordered A-Z by name (sorted above).
|
|
234
|
+
pages: (
|
|
235
|
+
[
|
|
236
|
+
renderServices && {
|
|
237
|
+
type: 'group',
|
|
238
|
+
title: 'Services',
|
|
239
|
+
subtle: true,
|
|
240
|
+
icon: 'Server',
|
|
241
|
+
pages: servicesInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
242
|
+
},
|
|
243
|
+
hasFlows && {
|
|
244
|
+
type: 'group',
|
|
245
|
+
title: 'Flows',
|
|
246
|
+
subtle: true,
|
|
247
|
+
icon: 'Waypoints',
|
|
248
|
+
pages: domainFlows.map((flow) => `flow:${(flow as any).data.id}:${(flow as any).data.version}`),
|
|
249
|
+
},
|
|
250
|
+
renderEntities && {
|
|
251
|
+
type: 'group',
|
|
252
|
+
title: 'Entities',
|
|
253
|
+
subtle: true,
|
|
254
|
+
icon: 'Box',
|
|
255
|
+
pages: entitiesInDomain.map((entity) => ({
|
|
256
|
+
type: 'item',
|
|
257
|
+
title: (entity as any).data?.name || (entity as any).data.id,
|
|
258
|
+
href: buildUrl(`/docs/entities/${(entity as any).data.id}/${(entity as any).data.version}`),
|
|
259
|
+
})),
|
|
260
|
+
},
|
|
261
|
+
renderMessages &&
|
|
262
|
+
sendsMessages.length > 0 && {
|
|
263
|
+
type: 'group',
|
|
264
|
+
title: 'Domain Events',
|
|
265
|
+
subtle: true,
|
|
266
|
+
icon: 'Mail',
|
|
267
|
+
pages: sortedSendsMessages.map(
|
|
268
|
+
(message) =>
|
|
269
|
+
`${pluralizeMessageType(message as any)}:${(message as any).data.id}:${(message as any).data.version}`
|
|
270
|
+
),
|
|
271
|
+
},
|
|
272
|
+
renderMessages &&
|
|
273
|
+
receivesMessages.length > 0 && {
|
|
274
|
+
type: 'group',
|
|
275
|
+
title: 'External Events',
|
|
276
|
+
subtle: true,
|
|
277
|
+
icon: 'Mail',
|
|
278
|
+
pages: sortedReceivesMessages.map(
|
|
279
|
+
(receive) =>
|
|
280
|
+
`${pluralizeMessageType(receive as any)}:${(receive as any).data.id}:${(receive as any).data.version}`
|
|
281
|
+
),
|
|
282
|
+
},
|
|
283
|
+
].filter(Boolean) as NavNode[]
|
|
284
|
+
).sort((a, b) => a.title.localeCompare(b.title)) as ChildRef[],
|
|
183
285
|
},
|
|
184
286
|
|
|
185
287
|
...(hasResourceGroups ? buildResourceGroupSections(resourceGroups, context) : []),
|
|
186
|
-
renderServices && {
|
|
187
|
-
type: 'group',
|
|
188
|
-
title: 'Services In Domain',
|
|
189
|
-
icon: 'Server',
|
|
190
|
-
pages: servicesInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
191
|
-
},
|
|
192
288
|
renderAgents && {
|
|
193
289
|
type: 'group',
|
|
194
290
|
title: 'Agents In Domain',
|
|
@@ -209,24 +305,6 @@ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[
|
|
|
209
305
|
(dataProduct) => `data-product:${(dataProduct as any).data.id}:${(dataProduct as any).data.version}`
|
|
210
306
|
),
|
|
211
307
|
},
|
|
212
|
-
sendsMessages.length > 0 &&
|
|
213
|
-
renderMessages && {
|
|
214
|
-
type: 'group',
|
|
215
|
-
title: 'Domain Events',
|
|
216
|
-
icon: 'Mail',
|
|
217
|
-
pages: sendsMessages.map(
|
|
218
|
-
(message) => `${pluralizeMessageType(message as any)}:${(message as any).data.id}:${(message as any).data.version}`
|
|
219
|
-
),
|
|
220
|
-
},
|
|
221
|
-
receivesMessages.length > 0 &&
|
|
222
|
-
renderMessages && {
|
|
223
|
-
type: 'group',
|
|
224
|
-
title: 'External Events',
|
|
225
|
-
icon: 'Mail',
|
|
226
|
-
pages: receivesMessages.map(
|
|
227
|
-
(receive) => `${pluralizeMessageType(receive as any)}:${(receive as any).data.id}:${(receive as any).data.version}`
|
|
228
|
-
),
|
|
229
|
-
},
|
|
230
308
|
renderOwners && buildOwnersSection(owners),
|
|
231
309
|
renderRepository && buildRepositorySection(domain.data.repository as { url: string; language: string }),
|
|
232
310
|
hasAttachments && buildAttachmentsSection(domain.data.attachments as any[]),
|
|
@@ -115,7 +115,7 @@ export const buildServiceNode = (
|
|
|
115
115
|
renderVisualiser &&
|
|
116
116
|
hasDataStores && {
|
|
117
117
|
type: 'item',
|
|
118
|
-
title: 'Data
|
|
118
|
+
title: 'Data Dependency Graph',
|
|
119
119
|
href: buildUrl(`/visualiser/services/${service.data.id}/${service.data.version}/data`),
|
|
120
120
|
},
|
|
121
121
|
].filter(Boolean) as ChildRef[],
|
|
@@ -202,7 +202,9 @@ export const buildServiceNode = (
|
|
|
202
202
|
},
|
|
203
203
|
hasFlows && {
|
|
204
204
|
type: 'group',
|
|
205
|
-
|
|
205
|
+
// If the service declares its own flows it owns them ("Flows"); otherwise it is
|
|
206
|
+
// only referenced as a step in someone else's flow ("Appears in flows").
|
|
207
|
+
title: serviceFlows.length > 0 ? 'Flows' : 'Appears in flows',
|
|
206
208
|
icon: 'Waypoints',
|
|
207
209
|
pages: serviceFlowRefs,
|
|
208
210
|
},
|
|
@@ -58,6 +58,7 @@ export type ResourceGroupContext = {
|
|
|
58
58
|
agents?: CollectionEntry<'agents'>[];
|
|
59
59
|
services: CollectionEntry<'services'>[];
|
|
60
60
|
domains: CollectionEntry<'domains'>[];
|
|
61
|
+
systems?: CollectionEntry<'systems'>[];
|
|
61
62
|
events: CollectionEntry<'events'>[];
|
|
62
63
|
commands: CollectionEntry<'commands'>[];
|
|
63
64
|
queries: CollectionEntry<'queries'>[];
|
|
@@ -115,7 +116,7 @@ export const buildArchitectureDecisionsSection = (resource: AdrResource, adrs: A
|
|
|
115
116
|
return {
|
|
116
117
|
type: 'group',
|
|
117
118
|
title: 'Decision Records',
|
|
118
|
-
icon: '
|
|
119
|
+
icon: 'ClipboardList',
|
|
119
120
|
pages: [...relatedAdrs].sort(byAdrName).map(getAdrNodeKey),
|
|
120
121
|
};
|
|
121
122
|
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { CollectionEntry } from 'astro:content';
|
|
2
|
+
import { buildUrl } from '@utils/url-builder';
|
|
3
|
+
import type { NavNode, ChildRef, ResourceGroupContext } from './shared';
|
|
4
|
+
import {
|
|
5
|
+
buildQuickReferenceSection,
|
|
6
|
+
buildOwnersSection,
|
|
7
|
+
shouldRenderSideBarSection,
|
|
8
|
+
buildRepositorySection,
|
|
9
|
+
buildAttachmentsSection,
|
|
10
|
+
buildDiagramNavItems,
|
|
11
|
+
buildResourceDocsSection,
|
|
12
|
+
} from './shared';
|
|
13
|
+
import { isChangelogEnabled, isVisualiserEnabled } from '@utils/feature';
|
|
14
|
+
import { customIconFieldsForResource } from '@utils/icon';
|
|
15
|
+
|
|
16
|
+
// Sort resolved collection entries A-Z by their display name (falling back to id).
|
|
17
|
+
const byResourceName = (a: any, b: any) => (a.data?.name || a.data?.id || '').localeCompare(b.data?.name || b.data?.id || '');
|
|
18
|
+
|
|
19
|
+
export const buildSystemNode = (system: CollectionEntry<'systems'>, owners: any[], context: ResourceGroupContext): NavNode => {
|
|
20
|
+
const servicesInSystem = [...(system.data.services || [])].sort(byResourceName);
|
|
21
|
+
const renderServices = servicesInSystem.length > 0 && shouldRenderSideBarSection(system, 'services');
|
|
22
|
+
|
|
23
|
+
const flowsInSystem = [...(system.data.flows || [])].sort(byResourceName);
|
|
24
|
+
const renderFlows = flowsInSystem.length > 0 && shouldRenderSideBarSection(system, 'flows');
|
|
25
|
+
|
|
26
|
+
const entitiesInSystem = [...(system.data.entities || [])].sort(byResourceName);
|
|
27
|
+
const renderEntities = entitiesInSystem.length > 0 && shouldRenderSideBarSection(system, 'entities');
|
|
28
|
+
|
|
29
|
+
const containersInSystem = [...(system.data.containers || [])].sort(byResourceName);
|
|
30
|
+
const renderContainers = containersInSystem.length > 0 && shouldRenderSideBarSection(system, 'containers');
|
|
31
|
+
|
|
32
|
+
// The Resources page/link only makes sense when the system actually has resources
|
|
33
|
+
// attached (services, flows, entities or data stores). Mirrors what the page renders.
|
|
34
|
+
const hasResources =
|
|
35
|
+
servicesInSystem.length > 0 || flowsInSystem.length > 0 || entitiesInSystem.length > 0 || containersInSystem.length > 0;
|
|
36
|
+
|
|
37
|
+
const systemDiagrams = system.data.diagrams || [];
|
|
38
|
+
const diagramNavItems = buildDiagramNavItems(systemDiagrams, context.diagrams);
|
|
39
|
+
const hasDiagrams = diagramNavItems.length > 0 && shouldRenderSideBarSection(system, 'diagrams');
|
|
40
|
+
|
|
41
|
+
// A system that declares relationships to other systems, or actors, can be the starting
|
|
42
|
+
// point of a Context Diagram. (Systems that are only referenced by others still get a
|
|
43
|
+
// context page; here we surface the link from systems that declare something themselves.)
|
|
44
|
+
const hasRelationships = (system.data.relationships || []).length > 0 || (system.data.actors || []).length > 0;
|
|
45
|
+
|
|
46
|
+
const renderOwners = owners.length > 0 && shouldRenderSideBarSection(system, 'owners');
|
|
47
|
+
const renderRepository = system.data.repository && shouldRenderSideBarSection(system, 'repository');
|
|
48
|
+
const hasAttachments = system.data.attachments && system.data.attachments.length > 0;
|
|
49
|
+
|
|
50
|
+
const renderVisualiser = isVisualiserEnabled();
|
|
51
|
+
|
|
52
|
+
const docsSection = buildResourceDocsSection(
|
|
53
|
+
'systems',
|
|
54
|
+
system.data.id,
|
|
55
|
+
system.data.version,
|
|
56
|
+
context.resourceDocs,
|
|
57
|
+
context.resourceDocCategories
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
type: 'item',
|
|
62
|
+
title: system.data.name,
|
|
63
|
+
badge: 'System',
|
|
64
|
+
summary: system.data.summary,
|
|
65
|
+
// Systems use a custom icon when defined, otherwise none — the surrounding
|
|
66
|
+
// 'Systems' section header (and System badge) already convey the type, so the
|
|
67
|
+
// default Group glyph on every item is redundant.
|
|
68
|
+
...customIconFieldsForResource(system.data),
|
|
69
|
+
pages: [
|
|
70
|
+
buildQuickReferenceSection(
|
|
71
|
+
[
|
|
72
|
+
{
|
|
73
|
+
title: 'Overview',
|
|
74
|
+
href: buildUrl(`/docs/systems/${system.data.id}/${system.data.version}`),
|
|
75
|
+
},
|
|
76
|
+
hasResources && {
|
|
77
|
+
title: 'System Resources',
|
|
78
|
+
href: buildUrl(`/docs/systems/${system.data.id}/${system.data.version}/resources`),
|
|
79
|
+
},
|
|
80
|
+
isChangelogEnabled() &&
|
|
81
|
+
shouldRenderSideBarSection(system, 'changelog') && {
|
|
82
|
+
title: 'Changelog',
|
|
83
|
+
href: buildUrl(`/docs/systems/${system.data.id}/${system.data.version}/changelog`),
|
|
84
|
+
},
|
|
85
|
+
].filter(Boolean) as { title: string; href: string }[]
|
|
86
|
+
),
|
|
87
|
+
docsSection,
|
|
88
|
+
{
|
|
89
|
+
type: 'group',
|
|
90
|
+
title: 'Architecture',
|
|
91
|
+
icon: 'Workflow',
|
|
92
|
+
pages: [
|
|
93
|
+
{
|
|
94
|
+
type: 'item',
|
|
95
|
+
title: 'Overview',
|
|
96
|
+
href: buildUrl(`/architecture/systems/${system.data.id}/${system.data.version}`),
|
|
97
|
+
},
|
|
98
|
+
renderVisualiser &&
|
|
99
|
+
hasRelationships && {
|
|
100
|
+
type: 'item',
|
|
101
|
+
title: 'Context Diagram',
|
|
102
|
+
href: buildUrl(`/visualiser/systems/${system.data.id}/${system.data.version}/context`),
|
|
103
|
+
},
|
|
104
|
+
renderVisualiser && {
|
|
105
|
+
type: 'item',
|
|
106
|
+
title: 'Resource Diagram',
|
|
107
|
+
href: buildUrl(`/visualiser/systems/${system.data.id}/${system.data.version}`),
|
|
108
|
+
},
|
|
109
|
+
].filter(Boolean) as ChildRef[],
|
|
110
|
+
},
|
|
111
|
+
hasDiagrams && {
|
|
112
|
+
type: 'group',
|
|
113
|
+
title: 'Diagrams',
|
|
114
|
+
icon: 'FileImage',
|
|
115
|
+
pages: diagramNavItems,
|
|
116
|
+
},
|
|
117
|
+
(renderServices || renderFlows || renderContainers) && {
|
|
118
|
+
type: 'group',
|
|
119
|
+
title: 'Resources',
|
|
120
|
+
icon: 'Boxes',
|
|
121
|
+
// Resource type subsections are ordered A-Z by their title, and the
|
|
122
|
+
// resources within each subsection are ordered A-Z by name (sorted above).
|
|
123
|
+
pages: (
|
|
124
|
+
[
|
|
125
|
+
renderServices && {
|
|
126
|
+
type: 'group',
|
|
127
|
+
title: 'Services',
|
|
128
|
+
subtle: true,
|
|
129
|
+
icon: 'Server',
|
|
130
|
+
pages: servicesInSystem.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
|
|
131
|
+
},
|
|
132
|
+
renderFlows && {
|
|
133
|
+
type: 'group',
|
|
134
|
+
title: 'Flows',
|
|
135
|
+
subtle: true,
|
|
136
|
+
icon: 'Waypoints',
|
|
137
|
+
pages: flowsInSystem.map((flow) => `flow:${(flow as any).data.id}:${(flow as any).data.version}`),
|
|
138
|
+
},
|
|
139
|
+
renderContainers && {
|
|
140
|
+
type: 'group',
|
|
141
|
+
title: 'Data Stores',
|
|
142
|
+
subtle: true,
|
|
143
|
+
icon: 'Database',
|
|
144
|
+
pages: containersInSystem.map(
|
|
145
|
+
(container) => `container:${(container as any).data.id}:${(container as any).data.version}`
|
|
146
|
+
),
|
|
147
|
+
},
|
|
148
|
+
].filter(Boolean) as NavNode[]
|
|
149
|
+
).sort((a, b) => a.title.localeCompare(b.title)) as ChildRef[],
|
|
150
|
+
},
|
|
151
|
+
renderEntities && {
|
|
152
|
+
type: 'group',
|
|
153
|
+
title: 'Entities',
|
|
154
|
+
icon: 'Box',
|
|
155
|
+
pages: entitiesInSystem.map((entity) => ({
|
|
156
|
+
type: 'item',
|
|
157
|
+
title: (entity as any).data?.name || (entity as any).data.id,
|
|
158
|
+
href: buildUrl(`/docs/entities/${(entity as any).data.id}/${(entity as any).data.version}`),
|
|
159
|
+
})),
|
|
160
|
+
},
|
|
161
|
+
renderOwners && buildOwnersSection(owners),
|
|
162
|
+
renderRepository && buildRepositorySection(system.data.repository as { url: string; language: string }),
|
|
163
|
+
hasAttachments && buildAttachmentsSection(system.data.attachments as any[]),
|
|
164
|
+
].filter(Boolean) as ChildRef[],
|
|
165
|
+
};
|
|
166
|
+
};
|