@eventcatalog/core 4.9.0 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-XQHS36GO.js → chunk-5XURY2JV.js} +1 -1
  6. package/dist/{chunk-3CGSSMTK.js → chunk-BDFTJVGN.js} +1 -1
  7. package/dist/{chunk-HKVOSQTD.js → chunk-BQXEWQ5J.js} +1 -1
  8. package/dist/{chunk-MPHX5C7M.js → chunk-HFAQXAG3.js} +1 -1
  9. package/dist/{chunk-LVGQ23LR.js → chunk-IC6XSXJO.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +1 -1
  13. package/dist/eventcatalog.js +5 -5
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/src/components/Badge.astro +3 -1
  19. package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +0 -5
  20. package/eventcatalog/src/components/MDX/Design/Design.astro +2 -0
  21. package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +2 -0
  22. package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -0
  23. package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +5 -7
  24. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -0
  25. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +121 -88
  26. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +55 -7
  27. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.spec.ts +59 -15
  28. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +53 -7
  29. package/eventcatalog/src/content.config.ts +70 -0
  30. package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +19 -0
  31. package/eventcatalog/src/enterprise/fields/pages/fields.astro +2 -0
  32. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +1 -1
  33. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +16 -15
  34. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +21 -17
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +4 -4
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +16 -8
  38. package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +48 -65
  39. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +45 -18
  40. package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -1
  41. package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -1
  42. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +5 -1
  43. package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +2 -0
  44. package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -0
  45. package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +96 -34
  46. package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +167 -75
  47. package/eventcatalog/src/stores/sidebar-store/builders/container.ts +135 -59
  48. package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +144 -58
  49. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +306 -188
  50. package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +108 -39
  51. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +147 -63
  52. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +212 -121
  53. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +223 -127
  54. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +3 -23
  55. package/eventcatalog/src/stores/sidebar-store/builders/system.ts +187 -97
  56. package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +678 -0
  57. package/eventcatalog/src/stores/sidebar-store/state.ts +66 -36
  58. package/eventcatalog/src/styles/tailwind.css +82 -0
  59. package/eventcatalog/src/utils/collections/resource-docs.ts +1 -0
  60. package/package.json +3 -3
@@ -1,10 +1,16 @@
1
1
  import type { CollectionEntry } from 'astro:content';
2
2
  import { buildUrl } from '@utils/url-builder';
3
3
  import type { NavNode, ChildRef, ResourceGroupContext } from './shared';
4
- import { buildQuickReferenceSection, buildResourceDocsSection, shouldRenderSideBarSection } from './shared';
4
+ import {
5
+ buildQuickReferenceSection,
6
+ buildResourceDocsSection,
7
+ shouldRenderSideBarSection,
8
+ buildArchitectureDecisionsSection,
9
+ } from './shared';
5
10
  import { isChangelogEnabled } from '@utils/feature';
6
11
  import { createVersionedMap, findInMap } from '@utils/collections/util';
7
12
  import { pluralizeMessageType } from '@utils/collections/messages';
13
+ import { resolveSidebarPages, toCustomSidebarContext, type SidebarSpec } from '../custom-sidebar';
8
14
 
9
15
  type VersionedEntry = { collection?: string; data: { id: string; version: string } };
10
16
  type VersionedEntryMap<T extends VersionedEntry> = Map<string, T[]>;
@@ -42,7 +48,43 @@ const resolveMessageStep = (
42
48
  return message ? `${pluralizeMessageType(message as any)}:${message.data.id}:${message.data.version}` : null;
43
49
  };
44
50
 
45
- export const buildFlowNode = (flow: CollectionEntry<'flows'>, context: ResourceGroupContext): NavNode => {
51
+ /**
52
+ * Predefined sidebar sections for a flow, keyed by the token users reference from
53
+ * `sidebar.json` (e.g. `$quick-reference`). Each token is the kebab-cased title of the
54
+ * section as it appears in the default sidebar.
55
+ */
56
+ export type FlowSectionKey =
57
+ | 'quick-reference'
58
+ | 'documentation'
59
+ | 'architecture'
60
+ | 'messages'
61
+ | 'services'
62
+ | 'agents'
63
+ | 'subflows'
64
+ | 'data-stores'
65
+ | 'data-products'
66
+ | 'decision-records';
67
+
68
+ export type FlowSections = Record<FlowSectionKey, NavNode | NavNode[] | null>;
69
+
70
+ /**
71
+ * Order of sections in the default (generated) sidebar. `decision-records` is deliberately
72
+ * absent — in default mode it is appended by `withArchitectureDecisionsSection` in state.ts,
73
+ * and only becomes a first-class token for custom sidebars.
74
+ */
75
+ export const DEFAULT_FLOW_SECTION_ORDER: FlowSectionKey[] = [
76
+ 'quick-reference',
77
+ 'documentation',
78
+ 'architecture',
79
+ 'messages',
80
+ 'services',
81
+ 'agents',
82
+ 'subflows',
83
+ 'data-stores',
84
+ 'data-products',
85
+ ];
86
+
87
+ export const buildFlowSections = (flow: CollectionEntry<'flows'>, context: ResourceGroupContext): FlowSections => {
46
88
  const docsSection = buildResourceDocsSection(
47
89
  'flows',
48
90
  flow.data.id,
@@ -111,72 +153,114 @@ export const buildFlowNode = (flow: CollectionEntry<'flows'>, context: ResourceG
111
153
  .map((dataProduct) => `data-product:${dataProduct!.data.id}:${dataProduct!.data.version}`)
112
154
  );
113
155
 
156
+ return {
157
+ 'quick-reference': buildQuickReferenceSection(
158
+ [
159
+ { title: 'Overview', href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}`) },
160
+ isChangelogEnabled() &&
161
+ shouldRenderSideBarSection(flow, 'changelog') && {
162
+ title: 'Changelog',
163
+ href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}/changelog`),
164
+ },
165
+ ].filter(Boolean) as { title: string; href: string }[]
166
+ ),
167
+ documentation: docsSection,
168
+ architecture: {
169
+ type: 'group',
170
+ title: 'Architecture',
171
+ icon: 'Workflow',
172
+ pages: [
173
+ {
174
+ type: 'item',
175
+ title: 'Flow Diagram',
176
+ href: buildUrl(`/visualiser/flows/${flow.data.id}/${flow.data.version}`),
177
+ },
178
+ ].filter(Boolean) as ChildRef[],
179
+ },
180
+ messages:
181
+ messageRefs.length > 0
182
+ ? {
183
+ type: 'group',
184
+ title: 'Messages',
185
+ icon: 'Mail',
186
+ pages: messageRefs,
187
+ }
188
+ : null,
189
+ services:
190
+ serviceRefs.length > 0
191
+ ? {
192
+ type: 'group',
193
+ title: 'Services',
194
+ icon: 'Server',
195
+ pages: serviceRefs,
196
+ }
197
+ : null,
198
+ agents:
199
+ agentRefs.length > 0
200
+ ? {
201
+ type: 'group',
202
+ title: 'Agents',
203
+ icon: 'Bot',
204
+ pages: agentRefs,
205
+ }
206
+ : null,
207
+ subflows:
208
+ flowRefs.length > 0
209
+ ? {
210
+ type: 'group',
211
+ title: 'Subflows',
212
+ icon: 'Waypoints',
213
+ pages: flowRefs,
214
+ }
215
+ : null,
216
+ 'data-stores':
217
+ containerRefs.length > 0
218
+ ? {
219
+ type: 'group',
220
+ title: 'Data Stores',
221
+ icon: 'Database',
222
+ pages: containerRefs,
223
+ }
224
+ : null,
225
+ 'data-products':
226
+ dataProductRefs.length > 0
227
+ ? {
228
+ type: 'group',
229
+ title: 'Data Products',
230
+ icon: 'Package',
231
+ pages: dataProductRefs,
232
+ }
233
+ : null,
234
+ 'decision-records': shouldRenderSideBarSection(flow, 'architectureDecisions')
235
+ ? buildArchitectureDecisionsSection(flow, context.adrs || [])
236
+ : null,
237
+ };
238
+ };
239
+
240
+ export type BuildFlowNodeOptions = {
241
+ /** A parsed `sidebar.json` for this flow. When present it replaces the generated sidebar. */
242
+ sidebar?: SidebarSpec;
243
+ };
244
+
245
+ export const buildFlowNode = (
246
+ flow: CollectionEntry<'flows'>,
247
+ context: ResourceGroupContext,
248
+ options: BuildFlowNodeOptions = {}
249
+ ): NavNode => {
250
+ const sections = buildFlowSections(flow, context);
251
+
252
+ const pages = resolveSidebarPages(sections, DEFAULT_FLOW_SECTION_ORDER, {
253
+ sidebar: options.sidebar,
254
+ resource: { collection: 'flows', id: flow.data.id, version: flow.data.version, entry: flow },
255
+ context: toCustomSidebarContext(context),
256
+ });
257
+
114
258
  return {
115
259
  type: 'item',
116
260
  title: flow.data.name,
117
261
  icon: 'Waypoint',
118
262
  badge: 'Flow',
119
263
  summary: flow.data.summary,
120
- pages: [
121
- buildQuickReferenceSection(
122
- [
123
- { title: 'Overview', href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}`) },
124
- isChangelogEnabled() &&
125
- shouldRenderSideBarSection(flow, 'changelog') && {
126
- title: 'Changelog',
127
- href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}/changelog`),
128
- },
129
- ].filter(Boolean) as { title: string; href: string }[]
130
- ),
131
- docsSection,
132
- {
133
- type: 'group',
134
- title: 'Architecture',
135
- icon: 'Workflow',
136
- pages: [
137
- {
138
- type: 'item',
139
- title: 'Flow Diagram',
140
- href: buildUrl(`/visualiser/flows/${flow.data.id}/${flow.data.version}`),
141
- },
142
- ].filter(Boolean) as ChildRef[],
143
- },
144
- messageRefs.length > 0 && {
145
- type: 'group',
146
- title: 'Messages',
147
- icon: 'Mail',
148
- pages: messageRefs,
149
- },
150
- serviceRefs.length > 0 && {
151
- type: 'group',
152
- title: 'Services',
153
- icon: 'Server',
154
- pages: serviceRefs,
155
- },
156
- agentRefs.length > 0 && {
157
- type: 'group',
158
- title: 'Agents',
159
- icon: 'Bot',
160
- pages: agentRefs,
161
- },
162
- flowRefs.length > 0 && {
163
- type: 'group',
164
- title: 'Subflows',
165
- icon: 'Waypoints',
166
- pages: flowRefs,
167
- },
168
- containerRefs.length > 0 && {
169
- type: 'group',
170
- title: 'Data Stores',
171
- icon: 'Database',
172
- pages: containerRefs,
173
- },
174
- dataProductRefs.length > 0 && {
175
- type: 'group',
176
- title: 'Data Products',
177
- icon: 'Package',
178
- pages: dataProductRefs,
179
- },
180
- ].filter(Boolean) as ChildRef[],
264
+ pages,
181
265
  };
182
266
  };
@@ -10,23 +10,24 @@ import {
10
10
  buildAttachmentsSection,
11
11
  buildDiagramNavItems,
12
12
  buildResourceDocsSection,
13
+ buildArchitectureDecisionsSection,
13
14
  } from './shared';
14
15
  import { isVisualiserEnabled, isChangelogEnabled } from '@utils/feature';
15
16
  import { iconFieldsForResource } from '@utils/icon';
16
17
  import { collectionToResourceMap } from '@utils/collections/util';
17
18
  import type { MessageTrigger } from '@utils/collections/message-triggers';
19
+ import { resolveSidebarPages, toCustomSidebarContext, type SidebarSpec } from '../custom-sidebar';
18
20
 
19
21
  type MessageSchemaEntry = CollectionEntry<'schemas'>;
22
+ type MessageEntry = CollectionEntry<'events' | 'commands' | 'queries'>;
23
+ type MessageTriggers = { triggers: MessageTrigger[]; triggeredBy: MessageTrigger[] };
20
24
 
21
25
  const getProducerConsumerPageRef = (resource: any) => {
22
26
  const resourceType = collectionToResourceMap[resource.collection as keyof typeof collectionToResourceMap];
23
27
  return `${resourceType}:${resource.data.id}:${resource.data.version}`;
24
28
  };
25
29
 
26
- const getSchemasForMessage = (
27
- message: CollectionEntry<'events' | 'commands' | 'queries'>,
28
- schemas: MessageSchemaEntry[] = []
29
- ) => {
30
+ const getSchemasForMessage = (message: MessageEntry, schemas: MessageSchemaEntry[] = []) => {
30
31
  return schemas.filter(
31
32
  (schema) =>
32
33
  schema.data.message.collectionName === message.collection &&
@@ -43,14 +44,58 @@ const getSchemaNavTitle = (schemas: MessageSchemaEntry[]) => {
43
44
  return format ? `Schema (${format.toUpperCase()})` : 'Schema';
44
45
  };
45
46
 
46
- export const buildMessageNode = (
47
- message: CollectionEntry<'events' | 'commands' | 'queries'>,
47
+ /**
48
+ * Predefined sidebar sections for a message (event, command or query), keyed by the token
49
+ * users reference from `sidebar.json` (e.g. `$quick-reference`). Each token is the
50
+ * kebab-cased title of the section as it appears in the default sidebar.
51
+ */
52
+ export type MessageSectionKey =
53
+ | 'quick-reference'
54
+ | 'documentation'
55
+ | 'architecture'
56
+ | 'diagrams'
57
+ | 'api-and-contracts'
58
+ | 'producers'
59
+ | 'consumers'
60
+ | 'triggered-by'
61
+ | 'triggers'
62
+ | 'appears-in-flows'
63
+ | 'decision-records'
64
+ | 'owners'
65
+ | 'code'
66
+ | 'attachments';
67
+
68
+ export type MessageSections = Record<MessageSectionKey, NavNode | NavNode[] | null>;
69
+
70
+ /**
71
+ * Order of sections in the default (generated) sidebar. `decision-records` is deliberately
72
+ * absent — in default mode it is inserted before Owners by `withArchitectureDecisionsSection`
73
+ * in state.ts, and only becomes a first-class token for custom sidebars.
74
+ */
75
+ export const DEFAULT_MESSAGE_SECTION_ORDER: MessageSectionKey[] = [
76
+ 'quick-reference',
77
+ 'documentation',
78
+ 'architecture',
79
+ 'diagrams',
80
+ 'api-and-contracts',
81
+ 'producers',
82
+ 'consumers',
83
+ 'triggered-by',
84
+ 'triggers',
85
+ 'appears-in-flows',
86
+ 'owners',
87
+ 'code',
88
+ 'attachments',
89
+ ];
90
+
91
+ export const buildMessageSections = (
92
+ message: MessageEntry,
48
93
  owners: any[],
49
94
  context: ResourceGroupContext,
50
95
  hasFieldUsage: boolean = false,
51
96
  flowRefs: string[] = [],
52
- messageTriggers: { triggers: MessageTrigger[]; triggeredBy: MessageTrigger[] } = { triggers: [], triggeredBy: [] }
53
- ): NavNode => {
97
+ messageTriggers: MessageTriggers = { triggers: [], triggeredBy: [] }
98
+ ): MessageSections => {
54
99
  const producers = message.data.producers || [];
55
100
  const consumers = message.data.consumers || [];
56
101
  const collection = message.collection;
@@ -65,21 +110,6 @@ export const buildMessageNode = (
65
110
  const renderRepository = message.data.repository && shouldRenderSideBarSection(message, 'repository');
66
111
  const hasTriggerPaths = messageTriggers.triggers.length > 0 || messageTriggers.triggeredBy.length > 0;
67
112
 
68
- // Determine badge based on collection type
69
- const badgeMap: Record<string, string> = {
70
- events: 'Event',
71
- commands: 'Command',
72
- queries: 'Query',
73
- };
74
- const badge = badgeMap[collection] || 'Message';
75
-
76
- const iconMap: Record<string, string> = {
77
- events: 'Zap',
78
- commands: 'MessageSquare',
79
- queries: 'Search',
80
- };
81
- const defaultIcon = iconMap[collection] || 'Mail';
82
-
83
113
  const resolvedSchemas = getSchemasForMessage(message, context.schemas);
84
114
  const hasSchema = resolvedSchemas.length > 0;
85
115
  const renderVisualiser = isVisualiserEnabled();
@@ -100,109 +130,170 @@ export const buildMessageNode = (
100
130
  const diagramNavItems = buildDiagramNavItems(messageDiagrams, context.diagrams);
101
131
  const hasDiagrams = diagramNavItems.length > 0;
102
132
 
133
+ return {
134
+ 'quick-reference': buildQuickReferenceSection(
135
+ [
136
+ {
137
+ title: 'Overview',
138
+ href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}`),
139
+ },
140
+ isChangelogEnabled() &&
141
+ shouldRenderSideBarSection(message, 'changelog') && {
142
+ title: 'Changelog',
143
+ href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}/changelog`),
144
+ },
145
+ ].filter(Boolean) as { title: string; href: string }[]
146
+ ),
147
+ documentation: docsSection,
148
+ architecture: renderVisualiser
149
+ ? {
150
+ type: 'group',
151
+ title: 'Architecture',
152
+ icon: 'Workflow',
153
+ pages: [
154
+ {
155
+ type: 'item',
156
+ title: 'Map',
157
+ href: buildUrl(`/visualiser/${collection}/${message.data.id}/${message.data.version}`),
158
+ },
159
+ ...(hasTriggerPaths
160
+ ? [
161
+ {
162
+ type: 'item' as const,
163
+ title: 'Trigger paths',
164
+ href: buildUrl(`/triggers/${collection}/${message.data.id}/${message.data.version}`),
165
+ },
166
+ ]
167
+ : []),
168
+ ],
169
+ }
170
+ : null,
171
+ diagrams: hasDiagrams
172
+ ? {
173
+ type: 'group',
174
+ title: 'Diagrams',
175
+ icon: 'FileImage',
176
+ pages: diagramNavItems,
177
+ }
178
+ : null,
179
+ 'api-and-contracts': hasSchema
180
+ ? {
181
+ type: 'group',
182
+ title: 'API & Contracts',
183
+ icon: 'FileJson',
184
+ pages: [
185
+ {
186
+ type: 'item',
187
+ title: getSchemaNavTitle(resolvedSchemas),
188
+ href: buildUrl(`/schemas/${collection}/${message.data.id}/${message.data.version}`),
189
+ },
190
+ hasFieldUsage && {
191
+ type: 'item',
192
+ title: 'Field Usage',
193
+ href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}/field-lineage`),
194
+ },
195
+ ].filter(Boolean) as ChildRef[],
196
+ }
197
+ : null,
198
+ producers: renderProducers
199
+ ? {
200
+ type: 'group',
201
+ title: 'Producers',
202
+ icon: 'Server',
203
+ pages: producers.map(getProducerConsumerPageRef),
204
+ visible: producers.length > 0,
205
+ }
206
+ : null,
207
+ consumers: renderConsumers
208
+ ? {
209
+ type: 'group',
210
+ title: 'Consumers',
211
+ icon: 'Server',
212
+ pages: consumers.map(getProducerConsumerPageRef),
213
+ visible: consumers.length > 0,
214
+ }
215
+ : null,
216
+ 'triggered-by': renderTriggeredBy
217
+ ? {
218
+ type: 'group',
219
+ title: 'Triggered by',
220
+ icon: 'Mail',
221
+ pages: triggeredByRefs,
222
+ visible: triggeredByRefs.length > 0,
223
+ }
224
+ : null,
225
+ triggers: renderTriggers
226
+ ? {
227
+ type: 'group',
228
+ title: 'Triggers',
229
+ icon: 'Mail',
230
+ pages: triggerRefs,
231
+ visible: triggerRefs.length > 0,
232
+ }
233
+ : null,
234
+ 'appears-in-flows': renderFlows
235
+ ? {
236
+ type: 'group',
237
+ title: 'Appears in flows',
238
+ icon: 'Waypoints',
239
+ pages: flowRefs,
240
+ visible: flowRefs.length > 0,
241
+ }
242
+ : null,
243
+ 'decision-records': shouldRenderSideBarSection(message, 'architectureDecisions')
244
+ ? buildArchitectureDecisionsSection(message, context.adrs || [])
245
+ : null,
246
+ owners: renderOwners ? buildOwnersSection(owners) : null,
247
+ code: renderRepository ? buildRepositorySection(message.data.repository as { url: string; language: string }) : null,
248
+ attachments: hasAttachments ? buildAttachmentsSection(message.data.attachments as any[]) : null,
249
+ };
250
+ };
251
+
252
+ export type BuildMessageNodeOptions = {
253
+ /** A parsed `sidebar.json` for this message. When present it replaces the generated sidebar. */
254
+ sidebar?: SidebarSpec;
255
+ };
256
+
257
+ export const buildMessageNode = (
258
+ message: MessageEntry,
259
+ owners: any[],
260
+ context: ResourceGroupContext,
261
+ hasFieldUsage: boolean = false,
262
+ flowRefs: string[] = [],
263
+ messageTriggers: MessageTriggers = { triggers: [], triggeredBy: [] },
264
+ options: BuildMessageNodeOptions = {}
265
+ ): NavNode => {
266
+ const collection = message.collection;
267
+
268
+ // Determine badge based on collection type
269
+ const badgeMap: Record<string, string> = {
270
+ events: 'Event',
271
+ commands: 'Command',
272
+ queries: 'Query',
273
+ };
274
+ const badge = badgeMap[collection] || 'Message';
275
+
276
+ const iconMap: Record<string, string> = {
277
+ events: 'Zap',
278
+ commands: 'MessageSquare',
279
+ queries: 'Search',
280
+ };
281
+ const defaultIcon = iconMap[collection] || 'Mail';
282
+
283
+ const sections = buildMessageSections(message, owners, context, hasFieldUsage, flowRefs, messageTriggers);
284
+
285
+ const pages = resolveSidebarPages(sections, DEFAULT_MESSAGE_SECTION_ORDER, {
286
+ sidebar: options.sidebar,
287
+ resource: { collection, id: message.data.id, version: message.data.version, entry: message },
288
+ context: toCustomSidebarContext(context),
289
+ });
290
+
103
291
  return {
104
292
  type: 'item',
105
293
  title: message.data.name,
106
294
  badge,
107
295
  summary: message.data.summary,
108
296
  ...iconFieldsForResource(message.data, defaultIcon),
109
- pages: [
110
- buildQuickReferenceSection(
111
- [
112
- {
113
- title: 'Overview',
114
- href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}`),
115
- },
116
- isChangelogEnabled() &&
117
- shouldRenderSideBarSection(message, 'changelog') && {
118
- title: 'Changelog',
119
- href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}/changelog`),
120
- },
121
- ].filter(Boolean) as { title: string; href: string }[]
122
- ),
123
- docsSection,
124
- renderVisualiser && {
125
- type: 'group',
126
- title: 'Architecture',
127
- icon: 'Workflow',
128
- pages: [
129
- {
130
- type: 'item',
131
- title: 'Map',
132
- href: buildUrl(`/visualiser/${collection}/${message.data.id}/${message.data.version}`),
133
- },
134
- ...(hasTriggerPaths
135
- ? [
136
- {
137
- type: 'item' as const,
138
- title: 'Trigger paths',
139
- href: buildUrl(`/triggers/${collection}/${message.data.id}/${message.data.version}`),
140
- },
141
- ]
142
- : []),
143
- ],
144
- },
145
- hasDiagrams && {
146
- type: 'group',
147
- title: 'Diagrams',
148
- icon: 'FileImage',
149
- pages: diagramNavItems,
150
- },
151
- hasSchema && {
152
- type: 'group',
153
- title: 'API & Contracts',
154
- icon: 'FileJson',
155
- pages: [
156
- {
157
- type: 'item',
158
- title: getSchemaNavTitle(resolvedSchemas),
159
- href: buildUrl(`/schemas/${collection}/${message.data.id}/${message.data.version}`),
160
- },
161
- hasFieldUsage && {
162
- type: 'item',
163
- title: 'Field Usage',
164
- href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}/field-lineage`),
165
- },
166
- ].filter(Boolean),
167
- },
168
- renderProducers && {
169
- type: 'group',
170
- title: 'Producers',
171
- icon: 'Server',
172
- pages: producers.map(getProducerConsumerPageRef),
173
- visible: producers.length > 0,
174
- },
175
- renderConsumers && {
176
- type: 'group',
177
- title: 'Consumers',
178
- icon: 'Server',
179
- pages: consumers.map(getProducerConsumerPageRef),
180
- visible: consumers.length > 0,
181
- },
182
- renderTriggeredBy && {
183
- type: 'group',
184
- title: 'Triggered by',
185
- icon: 'Mail',
186
- pages: triggeredByRefs,
187
- visible: triggeredByRefs.length > 0,
188
- },
189
- renderTriggers && {
190
- type: 'group',
191
- title: 'Triggers',
192
- icon: 'Mail',
193
- pages: triggerRefs,
194
- visible: triggerRefs.length > 0,
195
- },
196
- renderFlows && {
197
- type: 'group',
198
- title: 'Appears in flows',
199
- icon: 'Waypoints',
200
- pages: flowRefs,
201
- visible: flowRefs.length > 0,
202
- },
203
- renderOwners && buildOwnersSection(owners),
204
- renderRepository && buildRepositorySection(message.data.repository as { url: string; language: string }),
205
- hasAttachments && buildAttachmentsSection(message.data.attachments as any[]),
206
- ].filter(Boolean) as ChildRef[],
297
+ pages,
207
298
  };
208
299
  };