@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
|
@@ -1,20 +1,66 @@
|
|
|
1
1
|
// Shared utilities for NestedSideBar components
|
|
2
2
|
|
|
3
3
|
export const SIDEBAR_GROUP_COLLAPSE_THRESHOLD = 5;
|
|
4
|
-
const GROUP_TITLES_WITHOUT_COUNT = new Set(['Quick Reference', 'Architecture', 'Resources']);
|
|
5
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The user's overrides of each group's default collapse state, keyed by group id.
|
|
7
|
+
* A group is in at most one set; absence means "use the group's default".
|
|
8
|
+
*/
|
|
6
9
|
export type SectionCollapsePreferences = {
|
|
7
10
|
expanded: Set<string>;
|
|
11
|
+
collapsed: Set<string>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const createSectionCollapsePreferences = (
|
|
15
|
+
expanded: Iterable<string> = [],
|
|
16
|
+
collapsed: Iterable<string> = []
|
|
17
|
+
): SectionCollapsePreferences => ({
|
|
18
|
+
expanded: new Set(expanded),
|
|
19
|
+
collapsed: new Set(collapsed),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether a group shows a caret and can be toggled. Every group inside a resource's sidebar
|
|
24
|
+
* can collapse (docs-sidebar behaviour); the root catalog level stays open. An explicit
|
|
25
|
+
* `collapsed` (set via sidebar.json) overrides every other rule, including `collapsible: false`.
|
|
26
|
+
*/
|
|
27
|
+
export const canCollapseGroup = (isTopLevel: boolean, collapsible = true, collapsed?: boolean): boolean => {
|
|
28
|
+
if (collapsed !== undefined) return true;
|
|
29
|
+
return collapsible && !isTopLevel;
|
|
8
30
|
};
|
|
9
31
|
|
|
10
|
-
|
|
11
|
-
|
|
32
|
+
/**
|
|
33
|
+
* The state a group starts in before the user touches it: an explicit `collapsed` wins,
|
|
34
|
+
* otherwise long lists start collapsed and short ones start open.
|
|
35
|
+
*/
|
|
36
|
+
export const getDefaultCollapsedState = (childCount: number, collapsed?: boolean): boolean =>
|
|
37
|
+
collapsed ?? childCount > SIDEBAR_GROUP_COLLAPSE_THRESHOLD;
|
|
12
38
|
|
|
13
|
-
export const
|
|
14
|
-
|
|
39
|
+
export const isGroupCollapsed = (
|
|
40
|
+
canCollapse: boolean,
|
|
41
|
+
groupId: string,
|
|
42
|
+
preferences: SectionCollapsePreferences,
|
|
43
|
+
defaultCollapsed = true
|
|
44
|
+
): boolean => {
|
|
45
|
+
if (!canCollapse) return false;
|
|
46
|
+
if (preferences.expanded.has(groupId)) return false;
|
|
47
|
+
if (preferences.collapsed.has(groupId)) return true;
|
|
48
|
+
return defaultCollapsed;
|
|
49
|
+
};
|
|
15
50
|
|
|
16
|
-
|
|
17
|
-
|
|
51
|
+
/** Flip a group's state, recording it as an override of its default. */
|
|
52
|
+
export const toggleGroupCollapsed = (
|
|
53
|
+
groupId: string,
|
|
54
|
+
preferences: SectionCollapsePreferences,
|
|
55
|
+
defaultCollapsed = true
|
|
56
|
+
): SectionCollapsePreferences => {
|
|
57
|
+
const next = createSectionCollapsePreferences(preferences.expanded, preferences.collapsed);
|
|
58
|
+
const isCurrentlyCollapsed = isGroupCollapsed(true, groupId, preferences, defaultCollapsed);
|
|
59
|
+
next.expanded.delete(groupId);
|
|
60
|
+
next.collapsed.delete(groupId);
|
|
61
|
+
if (isCurrentlyCollapsed) next.expanded.add(groupId);
|
|
62
|
+
else next.collapsed.add(groupId);
|
|
63
|
+
return next;
|
|
18
64
|
};
|
|
19
65
|
|
|
20
66
|
/**
|
|
@@ -1199,6 +1199,73 @@ const schemas = defineCollection({
|
|
|
1199
1199
|
.extend(baseSchema.shape),
|
|
1200
1200
|
});
|
|
1201
1201
|
|
|
1202
|
+
// Optional `sidebar.json` next to a resource's index.mdx. When present it fully
|
|
1203
|
+
// replaces the generated sidebar for that resource (see stores/sidebar-store/custom-sidebar.ts).
|
|
1204
|
+
const sidebarLinkSchema = z
|
|
1205
|
+
.object({
|
|
1206
|
+
title: z.string(),
|
|
1207
|
+
href: z.string(),
|
|
1208
|
+
icon: z.string().optional(),
|
|
1209
|
+
})
|
|
1210
|
+
.strict();
|
|
1211
|
+
|
|
1212
|
+
// { "title": "Runbooks", "icon": "Siren", "collapsed": true, "pages": [...] } (custom group).
|
|
1213
|
+
// Groups nest: a page can itself be a group, rendered as a subsection.
|
|
1214
|
+
type SidebarGroupInput = {
|
|
1215
|
+
title: string;
|
|
1216
|
+
icon?: string;
|
|
1217
|
+
collapsed?: boolean;
|
|
1218
|
+
pages: Array<string | z.input<typeof sidebarLinkSchema> | SidebarGroupInput>;
|
|
1219
|
+
};
|
|
1220
|
+
const sidebarGroupSchema: z.ZodType<SidebarGroupInput> = z.lazy(() =>
|
|
1221
|
+
z
|
|
1222
|
+
.object({
|
|
1223
|
+
title: z.string(),
|
|
1224
|
+
icon: z.string().optional(),
|
|
1225
|
+
collapsed: z.boolean().optional(),
|
|
1226
|
+
// "$quick-reference", "[[service|OrderService@1.0.0]]", "[[doc|guides/sla]]", { title, href } or a nested group
|
|
1227
|
+
pages: z.array(z.union([z.string(), sidebarLinkSchema, sidebarGroupSchema])),
|
|
1228
|
+
})
|
|
1229
|
+
.strict()
|
|
1230
|
+
);
|
|
1231
|
+
|
|
1232
|
+
const sidebarSchema = z
|
|
1233
|
+
.object({
|
|
1234
|
+
$schema: z.string().optional(),
|
|
1235
|
+
sections: z.array(
|
|
1236
|
+
z.union([
|
|
1237
|
+
// "$quick-reference" (predefined section)
|
|
1238
|
+
z.string(),
|
|
1239
|
+
// { "section": "$owners", "title": "Team", "collapsed": false } (predefined section, adjusted)
|
|
1240
|
+
z
|
|
1241
|
+
.object({
|
|
1242
|
+
section: z.string(),
|
|
1243
|
+
title: z.string().optional(),
|
|
1244
|
+
icon: z.string().optional(),
|
|
1245
|
+
collapsed: z.boolean().optional(),
|
|
1246
|
+
})
|
|
1247
|
+
.strict(),
|
|
1248
|
+
sidebarGroupSchema,
|
|
1249
|
+
])
|
|
1250
|
+
),
|
|
1251
|
+
})
|
|
1252
|
+
.strict();
|
|
1253
|
+
|
|
1254
|
+
const sidebars = defineCollection({
|
|
1255
|
+
loader: globWithSafeWatcher({
|
|
1256
|
+
// Anchored to the resource roots (like resourceDocCategories) so an unrelated
|
|
1257
|
+
// sidebar.json elsewhere in the project — or the public/generated mirror — is ignored.
|
|
1258
|
+
pattern: withIgnoredBuildArtifacts(
|
|
1259
|
+
withFederatedContent([
|
|
1260
|
+
'{services,events,commands,queries,flows,containers,channels,entities,data-products,systems,agents,adrs}/**/sidebar.json',
|
|
1261
|
+
'domains/**/sidebar.json',
|
|
1262
|
+
])
|
|
1263
|
+
),
|
|
1264
|
+
base: projectDirBase,
|
|
1265
|
+
}),
|
|
1266
|
+
schema: sidebarSchema,
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1202
1269
|
export const collections = {
|
|
1203
1270
|
events,
|
|
1204
1271
|
commands,
|
|
@@ -1236,4 +1303,7 @@ export const collections = {
|
|
|
1236
1303
|
|
|
1237
1304
|
// Generated from message schema references
|
|
1238
1305
|
schemas,
|
|
1306
|
+
|
|
1307
|
+
// Optional per-resource sidebar overrides (sidebar.json)
|
|
1308
|
+
sidebars,
|
|
1239
1309
|
};
|
|
@@ -71,6 +71,25 @@ type InferredResource = {
|
|
|
71
71
|
resourceVersion: string;
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
const DOC_TYPE_LABELS: Record<string, string> = {
|
|
75
|
+
adrs: 'ADR',
|
|
76
|
+
runbooks: 'Runbook',
|
|
77
|
+
contracts: 'Contract',
|
|
78
|
+
troubleshooting: 'Troubleshooting',
|
|
79
|
+
guides: 'Guide',
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** Human label for a doc type folder, e.g. `guides` → "Guide", `release-notes` → "Release Notes". */
|
|
83
|
+
export const getResourceDocTypeLabel = (type: string): string => {
|
|
84
|
+
if (DOC_TYPE_LABELS[type]) return DOC_TYPE_LABELS[type];
|
|
85
|
+
const normalized = type
|
|
86
|
+
.split(/[-_\s]+/)
|
|
87
|
+
.filter(Boolean)
|
|
88
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
89
|
+
.join(' ');
|
|
90
|
+
return normalized || 'Doc';
|
|
91
|
+
};
|
|
92
|
+
|
|
74
93
|
let memoryCache: ResourceDocEntry[] | null = null;
|
|
75
94
|
let memoryCategoryCache: ResourceDocCategoryEntry[] | null = null;
|
|
76
95
|
let memoryResourceLookupCache: Record<ResourceCollection, ResourceLookup> | null = null;
|
|
@@ -14,9 +14,17 @@ import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
|
|
|
14
14
|
import { getAdjacentPages, getNavigationItems } from '@enterprise/custom-documentation/utils/custom-docs';
|
|
15
15
|
import CustomDocsNav from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro';
|
|
16
16
|
import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
|
|
17
|
+
import ArchitectureGraph from '@components/MDX/ArchitectureGraph/ArchitectureGraph.astro';
|
|
18
|
+
import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
|
|
17
19
|
import CopyAsMarkdown from '@components/CopyAsMarkdown';
|
|
18
20
|
|
|
19
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
isVisualiserEnabled,
|
|
23
|
+
isMarkdownDownloadEnabled,
|
|
24
|
+
isRSSEnabled,
|
|
25
|
+
isEventCatalogChatEnabled,
|
|
26
|
+
isArchitectureGraphEnabled,
|
|
27
|
+
} from '@utils/feature';
|
|
20
28
|
|
|
21
29
|
const props = Astro.props;
|
|
22
30
|
const doc = props.data;
|
|
@@ -48,6 +56,18 @@ const resolvedNodeGraphs = await Promise.all(
|
|
|
48
56
|
})
|
|
49
57
|
);
|
|
50
58
|
|
|
59
|
+
// Architecture graphs embedded via <ArchitectureGraph />. Custom docs have no
|
|
60
|
+
// resource of their own, so with no `id` + `type` the whole catalog is rendered.
|
|
61
|
+
const architectureGraphs = (getMDXComponentsByName(props.body, 'ArchitectureGraph') || []).map((graph: any) => ({
|
|
62
|
+
id: graph.id,
|
|
63
|
+
collection: graph.type ? resourceToCollectionMap[graph.type as keyof typeof resourceToCollectionMap] : undefined,
|
|
64
|
+
depth: graph.depth ? Number(graph.depth) : undefined,
|
|
65
|
+
lens: graph.lens,
|
|
66
|
+
search: parseMdxBooleanProp(graph.search, true),
|
|
67
|
+
legend: parseMdxBooleanProp(graph.legend, true),
|
|
68
|
+
lensPicker: parseMdxBooleanProp(graph.lensPicker, false),
|
|
69
|
+
}));
|
|
70
|
+
|
|
51
71
|
const { prev, next } = await getAdjacentPages(currentSlug);
|
|
52
72
|
|
|
53
73
|
const ownersRaw = doc?.owners || [];
|
|
@@ -171,6 +191,31 @@ const editUrl =
|
|
|
171
191
|
})
|
|
172
192
|
}
|
|
173
193
|
|
|
194
|
+
{
|
|
195
|
+
architectureGraphs.length > 0 &&
|
|
196
|
+
architectureGraphs.map((graph: any, occurrenceIndex: number) => (
|
|
197
|
+
<ArchitectureGraph
|
|
198
|
+
id={graph.id}
|
|
199
|
+
collection={graph.collection}
|
|
200
|
+
depth={graph.depth}
|
|
201
|
+
lens={graph.lens}
|
|
202
|
+
showSearch={graph.search}
|
|
203
|
+
showLegend={graph.legend}
|
|
204
|
+
showLensPicker={graph.lensPicker}
|
|
205
|
+
portalId={architectureGraphPortalId(graph.id ?? (doc as any).id, occurrenceIndex)}
|
|
206
|
+
href={
|
|
207
|
+
isArchitectureGraphEnabled()
|
|
208
|
+
? {
|
|
209
|
+
label: 'Open full screen',
|
|
210
|
+
// Base URL only — the graph appends its live view state (focus, depth, lens)
|
|
211
|
+
url: buildUrl('/visualiser/graph'),
|
|
212
|
+
}
|
|
213
|
+
: undefined
|
|
214
|
+
}
|
|
215
|
+
/>
|
|
216
|
+
))
|
|
217
|
+
}
|
|
218
|
+
|
|
174
219
|
<!-- Previous / Next Navigation -->
|
|
175
220
|
<div class="py-8 border-t border-[rgb(var(--ec-page-border))] mt-8">
|
|
176
221
|
<div class="flex flex-col sm:flex-row justify-between w-full gap-4">
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
// Visualiser styles ship in the page head so ClientRouter navigations keep them (see NodeGraph.astro).
|
|
3
|
+
import '@eventcatalog/visualiser/styles-core.css';
|
|
2
4
|
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
3
5
|
import FieldsExplorer from '@components/FieldsExplorer/FieldsExplorer';
|
|
4
6
|
import { isEventCatalogScaleEnabled } from '@utils/feature';
|
|
@@ -24,7 +24,7 @@ const specifications = type === 'services' ? getSpecificationsForService(props)
|
|
|
24
24
|
<VerticalSideBarLayout title={pageTitle}>
|
|
25
25
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]">
|
|
26
26
|
<div class="flex docs-layout w-full">
|
|
27
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
27
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
28
28
|
{type === 'domains' && <DomainGrid domain={domain} client:load />}
|
|
29
29
|
{type === 'systems' && <SystemGrid system={props} client:load />}
|
|
30
30
|
{
|
package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro
CHANGED
|
@@ -8,7 +8,8 @@ import CopyAsMarkdown from '@components/CopyAsMarkdown';
|
|
|
8
8
|
import Badge from '@components/Badge.astro';
|
|
9
9
|
import { buildUrl } from '@utils/url-builder';
|
|
10
10
|
import { AlignLeftIcon, HistoryIcon } from 'lucide-react';
|
|
11
|
-
import { isEventCatalogChatEnabled, isResourceDocsEnabled } from '@utils/feature';
|
|
11
|
+
import { isEventCatalogChatEnabled, isMarkdownDownloadEnabled, isResourceDocsEnabled } from '@utils/feature';
|
|
12
|
+
import { getResourceDocTypeLabel } from '@utils/collections/resource-docs';
|
|
12
13
|
import { getIcon } from '@utils/badges';
|
|
13
14
|
import { collectionToResourceMap } from '@utils/collections/util';
|
|
14
15
|
|
|
@@ -51,28 +52,28 @@ const pagefindAttributes =
|
|
|
51
52
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
52
53
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]" {...pagefindAttributes}>
|
|
53
54
|
<div class="flex docs-layout w-full">
|
|
54
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</
|
|
55
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
56
|
+
{/* Header mirrors the latest-doc page ([docId]/index.astro) and the resource page. */}
|
|
57
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
58
|
+
<div class="flex flex-col gap-4">
|
|
59
|
+
<span class="text-xs md:text-sm font-semibold text-[rgb(var(--ec-accent))] capitalize">
|
|
60
|
+
{getResourceDocTypeLabel(props.data.type)}
|
|
61
|
+
</span>
|
|
62
|
+
<h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">{title}</h2>
|
|
62
63
|
</div>
|
|
63
64
|
{
|
|
64
65
|
props.data.summary && (
|
|
65
|
-
<p class="text-base pt-
|
|
66
|
+
<p class="text-base pt-4 text-[rgb(var(--ec-page-text-muted))] font-light">{props.data.summary}</p>
|
|
66
67
|
)
|
|
67
68
|
}
|
|
68
69
|
{
|
|
69
70
|
badges.length > 0 && (
|
|
70
|
-
<div class="flex flex-wrap gap-1.5
|
|
71
|
+
<div class="flex flex-wrap gap-1.5 pt-4">
|
|
71
72
|
{badges.map((badge: any) => <Badge badge={badge} />)}
|
|
72
73
|
</div>
|
|
73
74
|
)
|
|
74
75
|
}
|
|
75
|
-
<div class="pt-
|
|
76
|
+
<div class="pt-5">
|
|
76
77
|
<CopyAsMarkdown
|
|
77
78
|
client:only="react"
|
|
78
79
|
variant="toolbar"
|
|
@@ -80,9 +81,9 @@ const pagefindAttributes =
|
|
|
80
81
|
chatQuery={chatQuery}
|
|
81
82
|
chatEnabled={chatEnabled}
|
|
82
83
|
editUrl=""
|
|
83
|
-
markdownDownloadEnabled={
|
|
84
|
+
markdownDownloadEnabled={isMarkdownDownloadEnabled()}
|
|
84
85
|
rssFeedEnabled={false}
|
|
85
|
-
preferChatAsDefault={
|
|
86
|
+
preferChatAsDefault={chatEnabled}
|
|
86
87
|
/>
|
|
87
88
|
</div>
|
|
88
89
|
</div>
|
|
@@ -100,7 +101,7 @@ const pagefindAttributes =
|
|
|
100
101
|
)
|
|
101
102
|
}
|
|
102
103
|
</div>
|
|
103
|
-
<div class="prose
|
|
104
|
+
<div class="prose prose-md pt-8 pb-4 w-full text-[15px]">
|
|
104
105
|
<Content components={components(props)} />
|
|
105
106
|
</div>
|
|
106
107
|
</div>
|
|
@@ -8,9 +8,10 @@ import CopyAsMarkdown from '@components/CopyAsMarkdown';
|
|
|
8
8
|
import Badge from '@components/Badge.astro';
|
|
9
9
|
import { buildUrl } from '@utils/url-builder';
|
|
10
10
|
import { AlignLeftIcon, HistoryIcon } from 'lucide-react';
|
|
11
|
-
import { isEventCatalogChatEnabled, isResourceDocsEnabled } from '@utils/feature';
|
|
11
|
+
import { isEventCatalogChatEnabled, isMarkdownDownloadEnabled, isResourceDocsEnabled } from '@utils/feature';
|
|
12
12
|
import { getIcon } from '@utils/badges';
|
|
13
13
|
import { collectionToResourceMap } from '@utils/collections/util';
|
|
14
|
+
import { getResourceDocTypeLabel } from '@utils/collections/resource-docs';
|
|
14
15
|
|
|
15
16
|
import { Page } from './_index.data';
|
|
16
17
|
|
|
@@ -36,6 +37,7 @@ const docsBasePath = `/docs/${props.data.resourceCollection}/${props.data.resour
|
|
|
36
37
|
const singularResourceName =
|
|
37
38
|
collectionToResourceMap[props.data.resourceCollection as keyof typeof collectionToResourceMap] ??
|
|
38
39
|
props.data.resourceCollection.slice(0, props.data.resourceCollection.length - 1);
|
|
40
|
+
const typeLabel = getResourceDocTypeLabel(props.data.type);
|
|
39
41
|
const chatEnabled = isEventCatalogChatEnabled();
|
|
40
42
|
const chatQuery = `Tell me about the ${props.data.type} doc "${title}" for ${props.data.resourceId} (version ${props.data.version})`;
|
|
41
43
|
|
|
@@ -51,20 +53,22 @@ const pagefindAttributes =
|
|
|
51
53
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
52
54
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]" {...pagefindAttributes}>
|
|
53
55
|
<div class="flex docs-layout w-full">
|
|
54
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
55
|
-
|
|
56
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
57
|
+
{/* Header mirrors the resource page (docs/[type]/[id]/[version]/index.astro) so docs feel like part of the resource. */}
|
|
58
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
56
59
|
<div class="flex flex-col gap-4">
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
<span class="text-xs md:text-sm font-semibold text-[rgb(var(--ec-accent))] capitalize">{typeLabel}</span>
|
|
61
|
+
<h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">{title}</h2>
|
|
62
|
+
</div>
|
|
63
|
+
{props.data.summary && <p class="text-base pt-4 text-[rgb(var(--ec-page-text-muted))] font-light">{props.data.summary}</p>}
|
|
64
|
+
{
|
|
65
|
+
badges.length > 0 && (
|
|
66
|
+
<div class="flex flex-wrap gap-1.5 pt-4">
|
|
67
|
+
{badges.map((badge: any) => <Badge badge={badge} />)}
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
<div class="pt-5">
|
|
68
72
|
<CopyAsMarkdown
|
|
69
73
|
client:only="react"
|
|
70
74
|
variant="toolbar"
|
|
@@ -72,9 +76,9 @@ const pagefindAttributes =
|
|
|
72
76
|
chatQuery={chatQuery}
|
|
73
77
|
chatEnabled={chatEnabled}
|
|
74
78
|
editUrl=""
|
|
75
|
-
markdownDownloadEnabled={
|
|
79
|
+
markdownDownloadEnabled={isMarkdownDownloadEnabled()}
|
|
76
80
|
rssFeedEnabled={false}
|
|
77
|
-
preferChatAsDefault={
|
|
81
|
+
preferChatAsDefault={chatEnabled}
|
|
78
82
|
/>
|
|
79
83
|
</div>
|
|
80
84
|
</div>
|
|
@@ -92,7 +96,7 @@ const pagefindAttributes =
|
|
|
92
96
|
)
|
|
93
97
|
}
|
|
94
98
|
</div>
|
|
95
|
-
<div class="prose
|
|
99
|
+
<div class="prose prose-md pt-8 pb-4 w-full text-[15px]">
|
|
96
100
|
<Content components={components(props)} />
|
|
97
101
|
</div>
|
|
98
102
|
</div>
|
|
@@ -66,7 +66,7 @@ const pagefindAttributes =
|
|
|
66
66
|
<VerticalSideBarLayout title={pageTitle} description={`GraphQL schema for ${data.name}`}>
|
|
67
67
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]" {...pagefindAttributes}>
|
|
68
68
|
<div class="flex docs-layout w-full">
|
|
69
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
69
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
70
70
|
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-2">
|
|
71
71
|
<div>
|
|
72
72
|
<div class="flex justify-between items-start">
|
|
@@ -10,6 +10,8 @@ import Footer from '@layouts/Footer.astro';
|
|
|
10
10
|
|
|
11
11
|
import components from '@components/MDX/components';
|
|
12
12
|
import NodeGraph from '@components/MDX/NodeGraph/NodeGraph.astro';
|
|
13
|
+
import ArchitectureGraph from '@components/MDX/ArchitectureGraph/ArchitectureGraph.astro';
|
|
14
|
+
import { architectureGraphPortalId } from '@components/MDX/ArchitectureGraph/ArchitectureGraphPortal';
|
|
13
15
|
import SchemaViewer from '@components/MDX/SchemaViewer/SchemaViewerRoot.astro';
|
|
14
16
|
import Admonition from '@components/MDX/Admonition';
|
|
15
17
|
import VersionList from '@components/Lists/VersionList.astro';
|
|
@@ -65,6 +67,7 @@ import {
|
|
|
65
67
|
isVisualiserEnabled,
|
|
66
68
|
isRSSEnabled,
|
|
67
69
|
isEventCatalogMCPEnabled,
|
|
70
|
+
isArchitectureGraphEnabled,
|
|
68
71
|
} from '@utils/feature';
|
|
69
72
|
import { getMDXComponentsByName, parseMdxBooleanProp } from '@utils/markdown';
|
|
70
73
|
|
|
@@ -361,6 +364,20 @@ const contextDiagrams = contextDiagramSupported
|
|
|
361
364
|
})
|
|
362
365
|
: [];
|
|
363
366
|
|
|
367
|
+
// Architecture graphs embedded via <ArchitectureGraph />. Renders the D3
|
|
368
|
+
// catalog-wide force graph focused on the current resource's neighbourhood;
|
|
369
|
+
// `id` + `type` focus another resource instead. Each renders into its own
|
|
370
|
+
// portal, so it never collides with the page's NodeGraph.
|
|
371
|
+
const architectureGraphs = (getMDXComponentsByName(props.body || '', 'ArchitectureGraph') || []).map((graph: any) => ({
|
|
372
|
+
id: graph.id ?? props.data.id,
|
|
373
|
+
collection: graph.type ? resourceToCollectionMap[graph.type as keyof typeof resourceToCollectionMap] : props.collection,
|
|
374
|
+
depth: graph.depth ? Number(graph.depth) : undefined,
|
|
375
|
+
lens: graph.lens,
|
|
376
|
+
search: parseMdxBooleanProp(graph.search, true),
|
|
377
|
+
legend: parseMdxBooleanProp(graph.legend, true),
|
|
378
|
+
lensPicker: parseMdxBooleanProp(graph.lensPicker, false),
|
|
379
|
+
}));
|
|
380
|
+
|
|
364
381
|
// Get props for the node graph (when no id is passed, we assume its the current page)
|
|
365
382
|
const hasCurrentFlowEmbed =
|
|
366
383
|
props.collection === 'flows' &&
|
|
@@ -408,8 +425,8 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
|
|
|
408
425
|
<VerticalSideBarLayout title={pageTitle} description={props.data.summary}>
|
|
409
426
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]" {...pagefindAttributes}>
|
|
410
427
|
<div class="flex docs-layout w-full">
|
|
411
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
412
|
-
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-
|
|
428
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
429
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
413
430
|
<div>
|
|
414
431
|
<div>
|
|
415
432
|
<div class="flex flex-col gap-4">
|
|
@@ -447,7 +464,7 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
|
|
|
447
464
|
</div>
|
|
448
465
|
</div>
|
|
449
466
|
|
|
450
|
-
<
|
|
467
|
+
<p class="text-base pt-4 text-[rgb(var(--ec-page-text-muted))] font-light">{props.data.summary}</p>
|
|
451
468
|
{
|
|
452
469
|
badges && (
|
|
453
470
|
<div class="flex flex-wrap gap-1.5 pt-4">
|
|
@@ -596,7 +613,7 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
|
|
|
596
613
|
}
|
|
597
614
|
</div>
|
|
598
615
|
|
|
599
|
-
<div class="prose prose-md
|
|
616
|
+
<div class="prose prose-md pt-8 pb-4 w-full text-[15px]">
|
|
600
617
|
<Content components={components(props)} />
|
|
601
618
|
</div>
|
|
602
619
|
<div data-pagefind-ignore>
|
|
@@ -653,6 +670,30 @@ if (!isAdrPage && !hasCurrentFlowEmbed && !hasCurrentPageNodeGraph) {
|
|
|
653
670
|
/>
|
|
654
671
|
))
|
|
655
672
|
}
|
|
673
|
+
{
|
|
674
|
+
architectureGraphs.length > 0 &&
|
|
675
|
+
architectureGraphs.map((graph: any, occurrenceIndex: number) => (
|
|
676
|
+
<ArchitectureGraph
|
|
677
|
+
id={graph.id}
|
|
678
|
+
collection={graph.collection}
|
|
679
|
+
depth={graph.depth}
|
|
680
|
+
lens={graph.lens}
|
|
681
|
+
showSearch={graph.search}
|
|
682
|
+
showLegend={graph.legend}
|
|
683
|
+
showLensPicker={graph.lensPicker}
|
|
684
|
+
portalId={architectureGraphPortalId(graph.id, occurrenceIndex)}
|
|
685
|
+
href={
|
|
686
|
+
isArchitectureGraphEnabled()
|
|
687
|
+
? {
|
|
688
|
+
label: 'Open full screen',
|
|
689
|
+
// Base URL only — the graph appends its live view state (focus, depth, lens)
|
|
690
|
+
url: buildUrl('/visualiser/graph'),
|
|
691
|
+
}
|
|
692
|
+
: undefined
|
|
693
|
+
}
|
|
694
|
+
/>
|
|
695
|
+
))
|
|
696
|
+
}
|
|
656
697
|
</div>
|
|
657
698
|
<Footer />
|
|
658
699
|
<!-- Add edit this page button with icon and text-->
|
|
@@ -29,6 +29,8 @@ const hrefForResource = (collection: SystemResourceCollection, id: string, versi
|
|
|
29
29
|
return buildUrl(`/docs/${collection}/${id}/${version}`);
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
const ownerTypeLabel = ownerCollection === 'domains' ? 'Domain' : 'System';
|
|
33
|
+
|
|
32
34
|
const resources: SystemResourceItem[] = resourceGroups.flatMap(({ collection, items }) =>
|
|
33
35
|
items.map((item: any) => ({
|
|
34
36
|
collection,
|
|
@@ -45,16 +47,22 @@ const resources: SystemResourceItem[] = resourceGroups.flatMap(({ collection, it
|
|
|
45
47
|
<VerticalSideBarLayout title={`${data.name} | Resources`}>
|
|
46
48
|
<main class="flex docs-layout min-h-full bg-[rgb(var(--ec-page-bg))]">
|
|
47
49
|
<div class="flex docs-layout w-full">
|
|
48
|
-
<div class="w-full lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
<
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
<div class="w-full min-w-0 lg:mr-2 pr-24 py-8 bg-[rgb(var(--ec-page-bg))]">
|
|
51
|
+
{/* Header mirrors the resource page (docs/[type]/[id]/[version]/index.astro). */}
|
|
52
|
+
<div class="border-b border-[rgb(var(--ec-page-border))] md:pb-3 pt-4">
|
|
53
|
+
<div class="flex flex-col gap-4">
|
|
54
|
+
<span class="text-xs md:text-sm font-semibold text-[rgb(var(--ec-accent))] capitalize">{ownerTypeLabel}</span>
|
|
55
|
+
<h2 id="doc-page-header" class="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">
|
|
56
|
+
{data.name} Resources
|
|
57
|
+
</h2>
|
|
58
|
+
</div>
|
|
59
|
+
<p class="text-base pt-4 pb-1 text-[rgb(var(--ec-page-text-muted))] font-light">
|
|
60
|
+
{resources.length} {resources.length === 1 ? 'resource' : 'resources'} mapped to the {data.name}{' '}
|
|
61
|
+
{ownerTypeLabel.toLowerCase()}.
|
|
62
|
+
</p>
|
|
55
63
|
</div>
|
|
56
64
|
|
|
57
|
-
<div class="
|
|
65
|
+
<div class="pt-8 pb-4 w-full">
|
|
58
66
|
<SystemResourcesTable resources={resources} client:only="react" />
|
|
59
67
|
</div>
|
|
60
68
|
</div>
|