@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
|
@@ -25,90 +25,73 @@ const editUrl = resolveUbiquitousLanguageTermEditUrl({
|
|
|
25
25
|
configEditUrl: config.editUrl,
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
marked.setOptions
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// Pass options per call rather than via `marked.setOptions`, which mutates module-global
|
|
29
|
+
// state and leaks between pages (and between HMR reloads) in the same process.
|
|
30
|
+
const renderMarkdown = (markdown: string) => marked.parse(markdown, { gfm: true, breaks: false }) as string;
|
|
31
|
+
|
|
32
|
+
const TermIcon = ubiquitousLanguage.icon
|
|
33
|
+
? ((LucideIcons as unknown as Record<string, LucideIcons.LucideIcon>)[ubiquitousLanguage.icon] ?? null)
|
|
34
|
+
: null;
|
|
32
35
|
|
|
36
|
+
// Badges double as navigation back up the hierarchy: the owning domain and its glossary.
|
|
33
37
|
const badges = [
|
|
34
38
|
{
|
|
35
39
|
content: props.domain.name,
|
|
36
40
|
icon: RectangleGroupIcon,
|
|
41
|
+
url: buildUrl(`/docs/${props.type}/${props.domainId}/${props.domain.latestVersion}`),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
content: 'Ubiquitous Language',
|
|
45
|
+
icon: LucideIcons.BookOpen,
|
|
46
|
+
url: buildUrl(`/docs/${props.type}/${props.domainId}/language`),
|
|
37
47
|
},
|
|
38
48
|
];
|
|
39
49
|
---
|
|
40
50
|
|
|
41
51
|
<VerticalSideBarLayout title={pageTitle} description={ubiquitousLanguage.summary}>
|
|
42
52
|
<main
|
|
43
|
-
class="flex
|
|
53
|
+
class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]"
|
|
44
54
|
data-pagefind-body
|
|
45
55
|
data-pagefind-meta={`title:${pageTitle}`}
|
|
46
56
|
>
|
|
47
57
|
<div class="flex docs-layout w-full">
|
|
48
|
-
<div class="w-full lg:mr-2 pr-
|
|
49
|
-
{/*
|
|
50
|
-
<
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
class="
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
</a>
|
|
74
|
-
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
75
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"></path>
|
|
76
|
-
</svg>
|
|
77
|
-
<span class="text-[rgb(var(--ec-page-text))]">{ubiquitousLanguage.name}</span>
|
|
78
|
-
</nav>
|
|
79
|
-
|
|
80
|
-
<div class="border-b border-[rgb(var(--ec-page-border))] flex justify-between items-start md:pb-2">
|
|
81
|
-
<div>
|
|
82
|
-
<h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">
|
|
83
|
-
{ubiquitousLanguage.name}
|
|
84
|
-
</h2>
|
|
85
|
-
<p class="text-lg pt-2 text-[rgb(var(--ec-page-text-muted))] font-light">{ubiquitousLanguage.summary}</p>
|
|
86
|
-
<!-- Add badge -->
|
|
87
|
-
{
|
|
88
|
-
badges && badges.length > 0 && (
|
|
89
|
-
<div class="flex flex-wrap gap-3 py-4">
|
|
90
|
-
{badges.map((badge: any) => {
|
|
91
|
-
return <Badge badge={badge} />;
|
|
92
|
-
})}
|
|
93
|
-
</div>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
58
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 min-h-[50em]">
|
|
59
|
+
{/* Header mirrors the resource page (docs/[type]/[id]/[version]/index.astro). */}
|
|
60
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
61
|
+
<div class="flex flex-col gap-4">
|
|
62
|
+
<span class="text-xs md:text-sm font-semibold text-[rgb(var(--ec-accent))] capitalize">Term</span>
|
|
63
|
+
<div class="flex items-center gap-3">
|
|
64
|
+
{
|
|
65
|
+
TermIcon && (
|
|
66
|
+
<div class="flex items-center justify-center w-8 h-8 md:w-10 md:h-10 rounded-md bg-[rgb(var(--ec-accent-subtle))] shrink-0">
|
|
67
|
+
<TermIcon className="w-5 h-5 md:w-6 md:h-6 text-[rgb(var(--ec-accent))]" />
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
<h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">
|
|
72
|
+
{ubiquitousLanguage.name}
|
|
73
|
+
</h2>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{
|
|
77
|
+
ubiquitousLanguage.summary && (
|
|
78
|
+
<p class="text-base pt-4 text-[rgb(var(--ec-page-text-muted))] font-light">{ubiquitousLanguage.summary}</p>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
<div class="flex flex-wrap gap-1.5 pt-4 pb-1">
|
|
82
|
+
{badges.map((badge: any) => <Badge badge={badge} />)}
|
|
96
83
|
</div>
|
|
97
84
|
</div>
|
|
98
85
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
{
|
|
106
|
-
!ubiquitousLanguage.description && (
|
|
107
|
-
<div class="prose prose-md py-4 max-w-none">
|
|
86
|
+
<div class="prose prose-md pt-8 pb-4 w-full text-[15px]">
|
|
87
|
+
{
|
|
88
|
+
ubiquitousLanguage.description ? (
|
|
89
|
+
<Fragment set:html={renderMarkdown(ubiquitousLanguage.description)} />
|
|
90
|
+
) : (
|
|
108
91
|
<p>No description for {ubiquitousLanguage.name} available.</p>
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
</div>
|
|
112
95
|
|
|
113
96
|
<Footer />
|
|
114
97
|
<div class="flex justify-end">
|
|
@@ -19,6 +19,11 @@ const pageTitle = `${props.collection} | ${props.data.name}`.replace(/^\w/, (c)
|
|
|
19
19
|
const ubiquitousLanguageData = await getUbiquitousLanguageWithSubdomains(props);
|
|
20
20
|
const ubiquitousLanguage = ubiquitousLanguageData.domain;
|
|
21
21
|
const { subdomains, duplicateTerms } = ubiquitousLanguageData;
|
|
22
|
+
|
|
23
|
+
const termCount =
|
|
24
|
+
(ubiquitousLanguage?.data.dictionary?.length ?? 0) +
|
|
25
|
+
subdomains.reduce((total, subdomain: any) => total + (subdomain.ubiquitousLanguage?.data.dictionary?.length ?? 0), 0);
|
|
26
|
+
const ownerTypeLabel = props.collection === 'domains' ? 'Domain' : 'System';
|
|
22
27
|
---
|
|
23
28
|
|
|
24
29
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
@@ -28,26 +33,31 @@ const { subdomains, duplicateTerms } = ubiquitousLanguageData;
|
|
|
28
33
|
data-pagefind-meta={`title:${pageTitle}`}
|
|
29
34
|
>
|
|
30
35
|
<div class="flex docs-layout w-full">
|
|
31
|
-
<div class="w-full lg:mr-2 pr-24 py-8 min-h-[50em]">
|
|
32
|
-
{/*
|
|
33
|
-
<div class="
|
|
34
|
-
<div class="
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 min-h-[50em]">
|
|
37
|
+
{/* Header mirrors the resource page (docs/[type]/[id]/[version]/index.astro). */}
|
|
38
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
39
|
+
<div class="flex flex-col gap-4">
|
|
40
|
+
<span class="text-xs md:text-sm font-semibold text-[rgb(var(--ec-accent))] capitalize">{ownerTypeLabel}</span>
|
|
41
|
+
<h1 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">
|
|
42
|
+
Ubiquitous Language
|
|
43
|
+
</h1>
|
|
44
|
+
</div>
|
|
45
|
+
<p class="text-base pt-4 pb-1 text-[rgb(var(--ec-page-text-muted))] font-light">
|
|
46
|
+
{termCount} {termCount === 1 ? 'term' : 'terms'} used in the {props.data.name} {ownerTypeLabel.toLowerCase()}{
|
|
47
|
+
subdomains.length > 0 ? ' and its subdomains' : ''
|
|
48
|
+
}.
|
|
49
|
+
</p>
|
|
50
|
+
</div>
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
{
|
|
53
|
+
!ubiquitousLanguage && termCount > 0 && (
|
|
54
|
+
<div class="pt-8">
|
|
55
|
+
<div class="relative w-full max-w-md">
|
|
46
56
|
<input
|
|
47
57
|
type="text"
|
|
48
58
|
id="searchInput"
|
|
49
59
|
placeholder="Search terms..."
|
|
50
|
-
class="block w-full rounded-md border-0 py-
|
|
60
|
+
class="block w-full rounded-md border-0 py-2 pr-4 pl-10 text-sm font-light text-[rgb(var(--ec-header-text))] bg-[rgb(var(--ec-header-bg))] shadow-xs ring-1 ring-inset ring-[rgb(var(--ec-dropdown-border))] placeholder:text-[rgb(var(--ec-icon-color))] focus:ring-2 focus:ring-[rgb(var(--ec-accent))] focus:outline-none"
|
|
51
61
|
/>
|
|
52
62
|
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
53
63
|
<svg class="h-4 w-4 text-[rgb(var(--ec-icon-color))]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -60,8 +70,8 @@ const { subdomains, duplicateTerms } = ubiquitousLanguageData;
|
|
|
60
70
|
</div>
|
|
61
71
|
</div>
|
|
62
72
|
</div>
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
)
|
|
74
|
+
}
|
|
65
75
|
|
|
66
76
|
{
|
|
67
77
|
!ubiquitousLanguage && subdomains.length === 0 && (
|
|
@@ -82,7 +92,7 @@ const { subdomains, duplicateTerms } = ubiquitousLanguageData;
|
|
|
82
92
|
)
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
<div class="
|
|
95
|
+
<div class="pt-8 pb-4 w-full min-h-[calc(100vh-10em)]">
|
|
86
96
|
{
|
|
87
97
|
(ubiquitousLanguage || subdomains.some((s) => s.ubiquitousLanguage)) && (
|
|
88
98
|
<div>
|
|
@@ -101,6 +111,23 @@ const { subdomains, duplicateTerms } = ubiquitousLanguageData;
|
|
|
101
111
|
</span>
|
|
102
112
|
</h3>
|
|
103
113
|
</div>
|
|
114
|
+
<div class="relative w-64 flex-shrink-0">
|
|
115
|
+
<input
|
|
116
|
+
type="text"
|
|
117
|
+
id="searchInput"
|
|
118
|
+
placeholder="Search terms..."
|
|
119
|
+
class="block w-full rounded-md border-0 py-1.5 pr-4 pl-9 text-sm font-light text-[rgb(var(--ec-header-text))] bg-[rgb(var(--ec-header-bg))] shadow-xs ring-1 ring-inset ring-[rgb(var(--ec-dropdown-border))] placeholder:text-[rgb(var(--ec-icon-color))] focus:ring-2 focus:ring-[rgb(var(--ec-accent))] focus:outline-none"
|
|
120
|
+
/>
|
|
121
|
+
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
122
|
+
<svg class="h-4 w-4 text-[rgb(var(--ec-icon-color))]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
123
|
+
<path
|
|
124
|
+
stroke-linecap="round"
|
|
125
|
+
stroke-linejoin="round"
|
|
126
|
+
stroke-width="2"
|
|
127
|
+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
|
128
|
+
</svg>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
104
131
|
</div>
|
|
105
132
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" data-terms-grid="main">
|
|
106
133
|
{ubiquitousLanguage?.data?.dictionary?.map((term) => (
|
|
@@ -103,7 +103,7 @@ const sourceTitle = sourceLabel ? `Synced from ${sourceLabel}` : undefined;
|
|
|
103
103
|
data-pagefind-meta={`title:${pageTitle}`}
|
|
104
104
|
>
|
|
105
105
|
<div class="flex docs-layout w-full">
|
|
106
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
106
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
107
107
|
<div class="border-b border-[rgb(var(--ec-page-border))] pb-6">
|
|
108
108
|
<div class="flex justify-start">
|
|
109
109
|
<div class="flex flex-col justify-between space-y-3">
|
|
@@ -100,7 +100,7 @@ const sourceTitle = sourceLabel ? `Synced from ${sourceLabel}` : undefined;
|
|
|
100
100
|
data-pagefind-meta={`title:${pageTitle}`}
|
|
101
101
|
>
|
|
102
102
|
<div class="flex docs-layout w-full">
|
|
103
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
103
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
104
104
|
<div class="border-b border-[rgb(var(--ec-page-border))] pb-6">
|
|
105
105
|
<div class="flex justify-start gap-6">
|
|
106
106
|
{
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
3
|
-
import { getMDXComponentsByName } from '@utils/markdown';
|
|
3
|
+
import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
|
|
4
|
+
import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
|
|
4
5
|
import { resourceToCollectionMap } from '@utils/collections/util';
|
|
5
6
|
import { buildUrl } from '@utils/url-builder';
|
|
6
|
-
import { isCustomLandingPageEnabled, isVisualiserEnabled } from '@utils/feature';
|
|
7
|
+
import { isCustomLandingPageEnabled, isVisualiserEnabled, isArchitectureGraphEnabled } from '@utils/feature';
|
|
7
8
|
import DefaultAstroLandingPage from './_index.astro';
|
|
8
9
|
import config from '@config';
|
|
9
10
|
|
|
10
11
|
let nodeGraphs: any[] = [];
|
|
11
12
|
let systemContextMaps: any[] = [];
|
|
13
|
+
let architectureGraphs: any[] = [];
|
|
12
14
|
let CustomContent = null;
|
|
13
15
|
let NodeGraph = null;
|
|
16
|
+
let ArchitectureGraph = null;
|
|
14
17
|
let customHomepageComponents: Record<string, any> = {};
|
|
15
18
|
|
|
16
19
|
import path from 'path';
|
|
@@ -37,11 +40,19 @@ if (existsSync(pathToUserDefinedLandingPage) && isCustomLandingPageEnabled()) {
|
|
|
37
40
|
// The homepage can also embed the global System Context Map via <SystemContextMap />.
|
|
38
41
|
systemContextMaps = getMDXComponentsByName(rawContent, 'SystemContextMap') || [];
|
|
39
42
|
|
|
43
|
+
// …and the catalog-wide Architecture Graph via <ArchitectureGraph />. With no
|
|
44
|
+
// `id` + `type` the whole catalog is rendered.
|
|
45
|
+
architectureGraphs = getMDXComponentsByName(rawContent, 'ArchitectureGraph') || [];
|
|
46
|
+
|
|
40
47
|
// Avoid pulling visualizer CSS into the default homepage bundle.
|
|
41
48
|
// Only load the NodeGraph component when the custom homepage actually uses a graph.
|
|
42
49
|
if (nodeGraphs.length > 0 || systemContextMaps.length > 0) {
|
|
43
50
|
NodeGraph = (await import('@components/MDX/NodeGraph/NodeGraph.astro')).default;
|
|
44
51
|
}
|
|
52
|
+
// Only build the catalog-wide graph data when the homepage actually embeds it.
|
|
53
|
+
if (architectureGraphs.length > 0) {
|
|
54
|
+
ArchitectureGraph = (await import('@components/MDX/ArchitectureGraph/ArchitectureGraph.astro')).default;
|
|
55
|
+
}
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
if (config.landingPage) {
|
|
@@ -104,6 +115,27 @@ if (config.landingPage) {
|
|
|
104
115
|
}
|
|
105
116
|
/>
|
|
106
117
|
))}
|
|
118
|
+
{ArchitectureGraph &&
|
|
119
|
+
architectureGraphs.map((graph: any, occurrenceIndex: number) => (
|
|
120
|
+
<ArchitectureGraph
|
|
121
|
+
id={graph.id}
|
|
122
|
+
collection={graph.type ? resourceToCollectionMap[graph.type as keyof typeof resourceToCollectionMap] : undefined}
|
|
123
|
+
depth={graph.depth ? Number(graph.depth) : undefined}
|
|
124
|
+
lens={graph.lens}
|
|
125
|
+
showSearch={parseMdxBooleanProp(graph.search, true)}
|
|
126
|
+
showLegend={parseMdxBooleanProp(graph.legend, true)}
|
|
127
|
+
showLensPicker={parseMdxBooleanProp(graph.lensPicker, false)}
|
|
128
|
+
portalId={architectureGraphPortalId(graph.id, occurrenceIndex)}
|
|
129
|
+
href={
|
|
130
|
+
isArchitectureGraphEnabled()
|
|
131
|
+
? {
|
|
132
|
+
label: 'Open full screen',
|
|
133
|
+
url: buildUrl('/visualiser/graph'),
|
|
134
|
+
}
|
|
135
|
+
: undefined
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
))}
|
|
107
139
|
</main>
|
|
108
140
|
</VerticalSideBarLayout>
|
|
109
141
|
) : (
|
|
@@ -130,7 +130,11 @@ const apiAccessEnabled = isEventCatalogScaleEnabled();
|
|
|
130
130
|
---
|
|
131
131
|
|
|
132
132
|
<VerticalSideBarLayout title={pageTitle}>
|
|
133
|
-
|
|
133
|
+
{/* The schema viewer is an app-style surface: pull it out of the content gutter so it sits flush against the sidebar. */}
|
|
134
|
+
<div
|
|
135
|
+
class="h-[calc(100vh-4rem)] overflow-hidden flex flex-col"
|
|
136
|
+
style="margin-left: calc(var(--ec-app-content-padding-left, 5rem) * -1); margin-right: calc(var(--ec-app-content-padding-right, 5rem) * -1);"
|
|
137
|
+
>
|
|
134
138
|
{
|
|
135
139
|
currentMessage ? (
|
|
136
140
|
<SchemaPageViewer
|
|
@@ -3,6 +3,8 @@ import { getCollection, type CollectionEntry } from 'astro:content';
|
|
|
3
3
|
|
|
4
4
|
import LineageScenarioSwitcher from '@components/Lineage/LineageScenarioSwitcher';
|
|
5
5
|
import AstroNodeGraph from '@components/MDX/NodeGraph/AstroNodeGraph';
|
|
6
|
+
// Visualiser styles ship in the page head so ClientRouter navigations keep them (see NodeGraph.astro).
|
|
7
|
+
import '@eventcatalog/visualiser/styles-core.css';
|
|
6
8
|
import ResourceRef from '@components/MDX/ResourceRef/ResourceRef.astro';
|
|
7
9
|
import Footer from '@layouts/Footer.astro';
|
|
8
10
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import AstroNodeGraph from '@components/MDX/NodeGraph/AstroNodeGraph';
|
|
3
|
+
// Visualiser styles ship in the page head so ClientRouter navigations keep them (see NodeGraph.astro).
|
|
4
|
+
import '@eventcatalog/visualiser/styles-core.css';
|
|
3
5
|
import { ClientRouter } from 'astro:transitions';
|
|
4
6
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
5
7
|
import { isEventCatalogChatEnabled } from '@utils/feature';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import VisualiserLayout from '@layouts/VisualiserLayout.astro';
|
|
3
3
|
import CatalogForceGraph from '@components/CatalogGraph/CatalogForceGraph';
|
|
4
|
-
import
|
|
5
|
-
import { getCatalogForceGraph } from '@utils/node-graphs/catalog-force-graph';
|
|
4
|
+
import { getCatalogForceGraph, toCatalogForceGraphWire } from '@utils/node-graphs/catalog-force-graph';
|
|
6
5
|
import { isArchitectureGraphEnabled } from '@utils/feature';
|
|
7
6
|
|
|
8
7
|
// Bail before building the graph — on very large catalogs the whole point of
|
|
@@ -11,29 +10,9 @@ if (!isArchitectureGraphEnabled()) {
|
|
|
11
10
|
return new Response(null, { status: 404 });
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
const { nodes, links } = await getCatalogForceGraph();
|
|
15
|
-
|
|
16
13
|
// Compact wire format: index-based links and client-derived URLs keep the
|
|
17
14
|
// island props Astro serialises into the page small for large catalogs.
|
|
18
|
-
const
|
|
19
|
-
const linkLabels = [...new Set(links.map((link) => link.label))];
|
|
20
|
-
const labelIndexByLabel = new Map(linkLabels.map((label, index) => [label, index]));
|
|
21
|
-
|
|
22
|
-
const wireNodes = nodes.map(({ id, label, collection, version }) => ({
|
|
23
|
-
// Node ids are `${collection}/${resourceId}` — send only the resource id, the client rebuilds the key
|
|
24
|
-
id: id.slice(collection.length + 1),
|
|
25
|
-
label,
|
|
26
|
-
collection,
|
|
27
|
-
version,
|
|
28
|
-
}));
|
|
29
|
-
|
|
30
|
-
const wireLinks = links.map(
|
|
31
|
-
(link): CatalogGraphWireLink => [
|
|
32
|
-
nodeIndexById.get(link.source)!,
|
|
33
|
-
nodeIndexById.get(link.target)!,
|
|
34
|
-
labelIndexByLabel.get(link.label)!,
|
|
35
|
-
]
|
|
36
|
-
);
|
|
15
|
+
const { nodes: wireNodes, links: wireLinks, linkLabels } = toCatalogForceGraphWire(await getCatalogForceGraph());
|
|
37
16
|
---
|
|
38
17
|
|
|
39
18
|
<VisualiserLayout title="Visualiser | Architecture Graph" description="Force-directed graph of every resource in the catalog">
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
type AdrResource,
|
|
9
9
|
} from '@utils/collections/adrs';
|
|
10
10
|
import { collectionToResourceMap, createVersionedMap, findInMap } from '@utils/collections/util';
|
|
11
|
-
import type {
|
|
11
|
+
import type { NavNode, ResourceGroupContext } from './shared';
|
|
12
12
|
import {
|
|
13
13
|
buildAttachmentsSection,
|
|
14
14
|
buildOwnersSection,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
shouldRenderSideBarSection,
|
|
18
18
|
} from './shared';
|
|
19
19
|
import { isChangelogEnabled } from '@utils/feature';
|
|
20
|
+
import { resolveSidebarPages, toCustomSidebarContext, type SidebarSpec } from '../custom-sidebar';
|
|
20
21
|
|
|
21
22
|
const firstClassResourceCollections = [
|
|
22
23
|
'agents',
|
|
@@ -102,13 +103,105 @@ const buildDecisionMakersSection = (decisionMakers: any[]): NavNode | null => {
|
|
|
102
103
|
};
|
|
103
104
|
};
|
|
104
105
|
|
|
105
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Predefined sidebar sections for a decision record, keyed by the token users reference from
|
|
108
|
+
* `sidebar.json` (e.g. `$quick-reference`). Each token is the kebab-cased title of the
|
|
109
|
+
* section as it appears in the default sidebar.
|
|
110
|
+
*/
|
|
111
|
+
export type AdrSectionKey =
|
|
112
|
+
| 'quick-reference'
|
|
113
|
+
| 'applies-to'
|
|
114
|
+
| 'supersedes'
|
|
115
|
+
| 'superseded-by'
|
|
116
|
+
| 'amends'
|
|
117
|
+
| 'amended-by'
|
|
118
|
+
| 'related-decisions'
|
|
119
|
+
| 'decision-makers'
|
|
120
|
+
| 'owners'
|
|
121
|
+
| 'code'
|
|
122
|
+
| 'attachments';
|
|
123
|
+
|
|
124
|
+
export type AdrSections = Record<AdrSectionKey, NavNode | NavNode[] | null>;
|
|
125
|
+
|
|
126
|
+
/** Order of sections in the default (generated) sidebar. */
|
|
127
|
+
export const DEFAULT_ADR_SECTION_ORDER: AdrSectionKey[] = [
|
|
128
|
+
'quick-reference',
|
|
129
|
+
'applies-to',
|
|
130
|
+
'supersedes',
|
|
131
|
+
'superseded-by',
|
|
132
|
+
'amends',
|
|
133
|
+
'amended-by',
|
|
134
|
+
'related-decisions',
|
|
135
|
+
'decision-makers',
|
|
136
|
+
'owners',
|
|
137
|
+
'code',
|
|
138
|
+
'attachments',
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
export const buildAdrSections = (adr: Adr, owners: any[], decisionMakers: any[], context: ResourceGroupContext): AdrSections => {
|
|
106
142
|
const relationships = getAdrRelationships(adr, context.adrs);
|
|
107
143
|
const appliesToRefs = resolveAppliedResourceRefs(adr, context);
|
|
108
144
|
const hasAttachments = adr.data.attachments && adr.data.attachments.length > 0;
|
|
109
145
|
const renderOwners = owners.length > 0 && shouldRenderSideBarSection(adr, 'owners');
|
|
110
146
|
const renderDecisionMakers = decisionMakers.length > 0 && shouldRenderSideBarSection(adr, 'decisionMakers');
|
|
111
147
|
const renderRepository = adr.data.repository && shouldRenderSideBarSection(adr, 'repository');
|
|
148
|
+
const renderRelationships = shouldRenderSideBarSection(adr, 'relationships');
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
'quick-reference': buildQuickReferenceSection(
|
|
152
|
+
[
|
|
153
|
+
{ title: 'Overview', href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}`) },
|
|
154
|
+
isChangelogEnabled() &&
|
|
155
|
+
shouldRenderSideBarSection(adr, 'changelog') && {
|
|
156
|
+
title: 'Changelog',
|
|
157
|
+
href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}/changelog`),
|
|
158
|
+
},
|
|
159
|
+
].filter(Boolean) as { title: string; href: string }[]
|
|
160
|
+
),
|
|
161
|
+
'applies-to':
|
|
162
|
+
appliesToRefs.length > 0 && shouldRenderSideBarSection(adr, 'appliesTo')
|
|
163
|
+
? {
|
|
164
|
+
type: 'group',
|
|
165
|
+
title: 'Applies to',
|
|
166
|
+
icon: 'GitBranch',
|
|
167
|
+
pages: appliesToRefs,
|
|
168
|
+
}
|
|
169
|
+
: null,
|
|
170
|
+
supersedes: renderRelationships ? buildAdrRelationshipSection('Supersedes', 'History', relationships.supersedes) : null,
|
|
171
|
+
'superseded-by': renderRelationships
|
|
172
|
+
? buildAdrRelationshipSection('Superseded by', 'History', relationships.supersededBy)
|
|
173
|
+
: null,
|
|
174
|
+
amends: renderRelationships ? buildAdrRelationshipSection('Amends', 'Pencil', relationships.amends) : null,
|
|
175
|
+
'amended-by': renderRelationships ? buildAdrRelationshipSection('Amended by', 'Pencil', relationships.amendedBy) : null,
|
|
176
|
+
'related-decisions': renderRelationships
|
|
177
|
+
? buildAdrRelationshipSection('Related decisions', 'Link', resolveAdrPointers(adr.data.related, context.adrs))
|
|
178
|
+
: null,
|
|
179
|
+
'decision-makers': renderDecisionMakers ? buildDecisionMakersSection(decisionMakers) : null,
|
|
180
|
+
owners: renderOwners ? buildOwnersSection(owners) : null,
|
|
181
|
+
code: renderRepository ? buildRepositorySection(adr.data.repository as { url: string; language: string }) : null,
|
|
182
|
+
attachments: hasAttachments ? buildAttachmentsSection(adr.data.attachments as any[]) : null,
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export type BuildAdrNodeOptions = {
|
|
187
|
+
/** A parsed `sidebar.json` for this decision record. When present it replaces the generated sidebar. */
|
|
188
|
+
sidebar?: SidebarSpec;
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export const buildAdrNode = (
|
|
192
|
+
adr: Adr,
|
|
193
|
+
owners: any[],
|
|
194
|
+
decisionMakers: any[],
|
|
195
|
+
context: ResourceGroupContext,
|
|
196
|
+
options: BuildAdrNodeOptions = {}
|
|
197
|
+
): NavNode => {
|
|
198
|
+
const sections = buildAdrSections(adr, owners, decisionMakers, context);
|
|
199
|
+
|
|
200
|
+
const pages = resolveSidebarPages(sections, DEFAULT_ADR_SECTION_ORDER, {
|
|
201
|
+
sidebar: options.sidebar,
|
|
202
|
+
resource: { collection: 'adrs', id: adr.data.id, version: adr.data.version, entry: adr },
|
|
203
|
+
context: toCustomSidebarContext(context),
|
|
204
|
+
});
|
|
112
205
|
|
|
113
206
|
return {
|
|
114
207
|
type: 'item',
|
|
@@ -116,37 +209,6 @@ export const buildAdrNode = (adr: Adr, owners: any[], decisionMakers: any[], con
|
|
|
116
209
|
badge: 'Decision record',
|
|
117
210
|
summary: adr.data.summary,
|
|
118
211
|
icon: 'ClipboardList',
|
|
119
|
-
pages
|
|
120
|
-
buildQuickReferenceSection(
|
|
121
|
-
[
|
|
122
|
-
{ title: 'Overview', href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}`) },
|
|
123
|
-
isChangelogEnabled() &&
|
|
124
|
-
shouldRenderSideBarSection(adr, 'changelog') && {
|
|
125
|
-
title: 'Changelog',
|
|
126
|
-
href: buildUrl(`/docs/adrs/${adr.data.id}/${adr.data.version}/changelog`),
|
|
127
|
-
},
|
|
128
|
-
].filter(Boolean) as { title: string; href: string }[]
|
|
129
|
-
),
|
|
130
|
-
appliesToRefs.length > 0 &&
|
|
131
|
-
shouldRenderSideBarSection(adr, 'appliesTo') && {
|
|
132
|
-
type: 'group',
|
|
133
|
-
title: 'Applies to',
|
|
134
|
-
icon: 'GitBranch',
|
|
135
|
-
pages: appliesToRefs,
|
|
136
|
-
},
|
|
137
|
-
shouldRenderSideBarSection(adr, 'relationships') &&
|
|
138
|
-
buildAdrRelationshipSection('Supersedes', 'History', relationships.supersedes),
|
|
139
|
-
shouldRenderSideBarSection(adr, 'relationships') &&
|
|
140
|
-
buildAdrRelationshipSection('Superseded by', 'History', relationships.supersededBy),
|
|
141
|
-
shouldRenderSideBarSection(adr, 'relationships') && buildAdrRelationshipSection('Amends', 'Pencil', relationships.amends),
|
|
142
|
-
shouldRenderSideBarSection(adr, 'relationships') &&
|
|
143
|
-
buildAdrRelationshipSection('Amended by', 'Pencil', relationships.amendedBy),
|
|
144
|
-
shouldRenderSideBarSection(adr, 'relationships') &&
|
|
145
|
-
buildAdrRelationshipSection('Related decisions', 'Link', resolveAdrPointers(adr.data.related, context.adrs)),
|
|
146
|
-
renderDecisionMakers && buildDecisionMakersSection(decisionMakers),
|
|
147
|
-
renderOwners && buildOwnersSection(owners),
|
|
148
|
-
renderRepository && buildRepositorySection(adr.data.repository as { url: string; language: string }),
|
|
149
|
-
hasAttachments && buildAttachmentsSection(adr.data.attachments as any[]),
|
|
150
|
-
].filter(Boolean) as ChildRef[],
|
|
212
|
+
pages,
|
|
151
213
|
};
|
|
152
214
|
};
|