@eventcatalog/core 2.65.0 → 3.0.0-beta.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 (130) hide show
  1. package/README.md +1 -26
  2. package/dist/analytics/analytics.cjs +1 -1
  3. package/dist/analytics/analytics.js +2 -2
  4. package/dist/analytics/log-build.cjs +1 -1
  5. package/dist/analytics/log-build.js +3 -3
  6. package/dist/{chunk-NK6OYMRD.js → chunk-JB4YT5JY.js} +1 -1
  7. package/dist/{chunk-BMDTX5IN.js → chunk-TQ4HZREX.js} +1 -1
  8. package/dist/{chunk-IJRFYF4B.js → chunk-X4W4YC3U.js} +1 -1
  9. package/dist/constants.cjs +1 -1
  10. package/dist/constants.js +1 -1
  11. package/dist/eventcatalog.cjs +1 -21
  12. package/dist/eventcatalog.config.d.cts +10 -0
  13. package/dist/eventcatalog.config.d.ts +10 -0
  14. package/dist/eventcatalog.js +3 -20
  15. package/eventcatalog/src/components/CopyAsMarkdown.tsx +19 -1
  16. package/eventcatalog/src/components/FavoriteButton.tsx +54 -0
  17. package/eventcatalog/src/components/Grids/DomainGrid.tsx +386 -362
  18. package/eventcatalog/src/components/Grids/MessageGrid.tsx +166 -518
  19. package/eventcatalog/src/components/Header.astro +48 -23
  20. package/eventcatalog/src/components/Lists/VersionList.astro +2 -2
  21. package/eventcatalog/src/components/MDX/Design/Design.astro +4 -1
  22. package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -1
  23. package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +3 -3
  24. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +8 -2
  25. package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +37 -0
  26. package/eventcatalog/src/components/Search/Search.astro +48 -28
  27. package/eventcatalog/src/components/Search/SearchModal.tsx +393 -702
  28. package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +298 -0
  29. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/container.ts +66 -0
  30. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/domain.ts +101 -0
  31. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/flow.ts +29 -0
  32. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/message.ts +84 -0
  33. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/service.ts +147 -0
  34. package/eventcatalog/src/components/SideNav/NestedSideBar/builders/shared.ts +146 -0
  35. package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +1073 -0
  36. package/eventcatalog/src/components/SideNav/NestedSideBar/sidebar-builder.ts +365 -0
  37. package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +90 -0
  38. package/eventcatalog/src/components/SideNav/SideNav.astro +18 -28
  39. package/eventcatalog/src/content.config.ts +2 -0
  40. package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +10 -4
  41. package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +3 -3
  42. package/eventcatalog/src/layouts/DirectoryLayout.astro +2 -2
  43. package/eventcatalog/src/layouts/DiscoverLayout.astro +3 -3
  44. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +85 -63
  45. package/eventcatalog/src/layouts/VisualiserLayout.astro +3 -3
  46. package/eventcatalog/src/pages/_index.astro +530 -110
  47. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +64 -0
  48. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +29 -0
  49. package/eventcatalog/src/pages/directory/[type]/_index.data.ts +4 -4
  50. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -4
  51. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +3 -3
  52. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -5
  53. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +362 -190
  54. package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +1 -1
  55. package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +4 -4
  56. package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +1 -4
  57. package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +3 -27
  58. package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +2 -2
  59. package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +2 -2
  60. package/eventcatalog/src/pages/index.astro +14 -5
  61. package/eventcatalog/src/pages/nav-index.json.ts +30 -0
  62. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +77 -0
  63. package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +90 -0
  64. package/eventcatalog/src/pages/schemas/{index.astro → explorer/index.astro} +3 -3
  65. package/eventcatalog/src/pages/studio.astro +3 -3
  66. package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +4 -3
  67. package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +2 -2
  68. package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +4 -3
  69. package/eventcatalog/src/stores/favorites-store.ts +83 -0
  70. package/eventcatalog/src/stores/sidebar-store.ts +8 -0
  71. package/eventcatalog/src/utils/collections/changelogs.ts +7 -4
  72. package/eventcatalog/src/utils/{channels.ts → collections/channels.ts} +81 -31
  73. package/eventcatalog/src/utils/collections/commands.ts +134 -0
  74. package/eventcatalog/src/utils/collections/containers.ts +44 -33
  75. package/eventcatalog/src/utils/collections/domains.ts +204 -62
  76. package/eventcatalog/src/utils/{entities.ts → collections/entities.ts} +44 -24
  77. package/eventcatalog/src/utils/collections/events.ts +136 -0
  78. package/eventcatalog/src/utils/collections/flows.ts +59 -25
  79. package/eventcatalog/src/utils/{messages.ts → collections/messages.ts} +13 -4
  80. package/eventcatalog/src/utils/{queries.ts → collections/queries.ts} +49 -28
  81. package/eventcatalog/src/utils/collections/services.ts +100 -68
  82. package/eventcatalog/src/utils/collections/teams.ts +94 -0
  83. package/eventcatalog/src/utils/collections/users.ts +122 -0
  84. package/eventcatalog/src/utils/collections/util.ts +57 -1
  85. package/eventcatalog/src/utils/feature.ts +3 -1
  86. package/eventcatalog/src/utils/{collections/file-diffs.ts → file-diffs.ts} +1 -1
  87. package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -0
  88. package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +16 -6
  89. package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +14 -10
  90. package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +36 -64
  91. package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +23 -19
  92. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +36 -49
  93. package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +22 -18
  94. package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +4 -4
  95. package/eventcatalog/tailwind.config.mjs +14 -0
  96. package/eventcatalog/tsconfig.json +2 -1
  97. package/package.json +7 -4
  98. package/eventcatalog/public/logo_old.png +0 -0
  99. package/eventcatalog/src/components/DiscoverInsight.astro +0 -61
  100. package/eventcatalog/src/components/Grids/ServiceGrid.tsx +0 -534
  101. package/eventcatalog/src/components/Lists/CustomSideBarSectionList.astro +0 -55
  102. package/eventcatalog/src/components/Lists/ProtocolList.tsx +0 -74
  103. package/eventcatalog/src/components/Lists/RepositoryList.astro +0 -37
  104. package/eventcatalog/src/components/Lists/SpecificationsList.astro +0 -67
  105. package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +0 -204
  106. package/eventcatalog/src/components/SideBars/ContainerSideBar.astro +0 -180
  107. package/eventcatalog/src/components/SideBars/DomainSideBar.astro +0 -273
  108. package/eventcatalog/src/components/SideBars/EntitySideBar.astro +0 -139
  109. package/eventcatalog/src/components/SideBars/FlowSideBar.astro +0 -128
  110. package/eventcatalog/src/components/SideBars/MessageSideBar.astro +0 -248
  111. package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +0 -294
  112. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +0 -46
  113. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +0 -78
  114. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/SpecificationList.tsx +0 -83
  115. package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +0 -1250
  116. package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +0 -91
  117. package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +0 -201
  118. package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +0 -190
  119. package/eventcatalog/src/components/SideNav/TreeView/index.tsx +0 -94
  120. package/eventcatalog/src/components/TreeView/index.tsx +0 -328
  121. package/eventcatalog/src/components/TreeView/styles.module.css +0 -264
  122. package/eventcatalog/src/components/TreeView/useSlots.ts +0 -95
  123. package/eventcatalog/src/pages/architecture/[type]/index.astro +0 -14
  124. package/eventcatalog/src/pages/architecture/architecture.astro +0 -101
  125. package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +0 -14
  126. package/eventcatalog/src/utils/commands.ts +0 -112
  127. package/eventcatalog/src/utils/events.ts +0 -108
  128. package/eventcatalog/src/utils/generators/index.ts +0 -10
  129. package/eventcatalog/src/utils/teams.ts +0 -72
  130. package/eventcatalog/src/utils/users.ts +0 -72
@@ -0,0 +1,298 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback, useMemo } from 'react';
4
+ import {
5
+ Search,
6
+ X,
7
+ SlidersHorizontal,
8
+ ChevronRight,
9
+ Boxes,
10
+ Server,
11
+ Zap,
12
+ MessageSquare,
13
+ Search as SearchIcon,
14
+ Database,
15
+ Waypoints,
16
+ SquareMousePointer,
17
+ } from 'lucide-react';
18
+ import type { NavNode } from './sidebar-builder';
19
+
20
+ const cn = (...classes: (string | false | undefined)[]) => classes.filter(Boolean).join(' ');
21
+
22
+ const getBadgeClasses = (badge: string): string => {
23
+ const badgeColors: Record<string, string> = {
24
+ domain: 'bg-blue-100 text-blue-700',
25
+ service: 'bg-green-100 text-green-700',
26
+ event: 'bg-amber-100 text-amber-700',
27
+ command: 'bg-pink-100 text-pink-700',
28
+ query: 'bg-purple-100 text-purple-700',
29
+ message: 'bg-indigo-100 text-indigo-700',
30
+ design: 'bg-teal-100 text-teal-700',
31
+ };
32
+ return badgeColors[badge.toLowerCase()] || 'bg-gray-100 text-gray-600';
33
+ };
34
+
35
+ type SearchResult = {
36
+ nodeKey: string;
37
+ node: NavNode;
38
+ matchType: 'name' | 'id';
39
+ };
40
+
41
+ type Props = {
42
+ nodes: Record<string, NavNode>;
43
+ onSelectResult: (nodeKey: string, node: NavNode) => void;
44
+ onSearchChange?: (isSearching: boolean) => void;
45
+ };
46
+
47
+ export default function SearchBar({ nodes, onSelectResult, onSearchChange }: Props) {
48
+ const [searchQuery, setSearchQuery] = useState('');
49
+ const [searchFilters, setSearchFilters] = useState<Set<string>>(new Set());
50
+ const [showFilterDropdown, setShowFilterDropdown] = useState(false);
51
+
52
+ // Pre-process searchable nodes to avoid iterating object on every render
53
+ const searchableNodes = useMemo(() => {
54
+ return Object.entries(nodes).filter(([_, node]) => node.type !== 'group');
55
+ }, [nodes]);
56
+
57
+ // Get available badges from nodes
58
+ const availableBadges = useMemo(() => {
59
+ const badges = new Set<string>();
60
+
61
+ for (const [_, node] of searchableNodes) {
62
+ if (node.badge) {
63
+ badges.add(node.badge);
64
+ }
65
+ }
66
+ return badges;
67
+ }, [searchableNodes]);
68
+
69
+ const handleSearchChange = (value: string) => {
70
+ setSearchQuery(value);
71
+ onSearchChange?.(value.trim().length > 0);
72
+ };
73
+
74
+ const clearSearch = () => {
75
+ setSearchQuery('');
76
+ onSearchChange?.(false);
77
+ };
78
+
79
+ const filterTypes = [
80
+ { key: 'command', label: 'Commands', badge: 'Command', icon: MessageSquare },
81
+ { key: 'container', label: 'Data Stores', badge: 'Container', icon: Database },
82
+ { key: 'design', label: 'Designs', badge: 'Design', icon: SquareMousePointer },
83
+ { key: 'domain', label: 'Domains', badge: 'Domain', icon: Boxes },
84
+ { key: 'event', label: 'Events', badge: 'Event', icon: Zap },
85
+ { key: 'flow', label: 'Flows', badge: 'Flow', icon: Waypoints },
86
+ { key: 'query', label: 'Queries', badge: 'Query', icon: SearchIcon },
87
+ { key: 'service', label: 'Services', badge: 'Service', icon: Server },
88
+ ].filter((filter) => availableBadges.has(filter.badge));
89
+
90
+ const toggleSearchFilter = (filterKey: string) => {
91
+ setSearchFilters((prev) => {
92
+ const next = new Set(prev);
93
+ if (next.has(filterKey)) {
94
+ next.delete(filterKey);
95
+ } else {
96
+ next.add(filterKey);
97
+ }
98
+ return next;
99
+ });
100
+ };
101
+
102
+ const searchResults = useCallback((): SearchResult[] => {
103
+ if (!searchQuery.trim()) return [];
104
+
105
+ const query = searchQuery.toLowerCase();
106
+ const results: SearchResult[] = [];
107
+
108
+ const badgeToFilterKey: Record<string, string> = {
109
+ Domain: 'domain',
110
+ Service: 'service',
111
+ Event: 'event',
112
+ Command: 'command',
113
+ Query: 'query',
114
+ Container: 'container',
115
+ Flow: 'flow',
116
+ Design: 'design',
117
+ };
118
+
119
+ // Use the memoized array instead of Object.entries(nodes)
120
+ for (const [key, node] of searchableNodes) {
121
+ if (searchFilters.size > 0) {
122
+ const filterKey = node.badge ? badgeToFilterKey[node.badge] : null;
123
+ if (!filterKey || !searchFilters.has(filterKey)) continue;
124
+ }
125
+
126
+ if (node.title.toLowerCase().includes(query)) {
127
+ results.push({ nodeKey: key, node, matchType: 'name' });
128
+ continue;
129
+ }
130
+
131
+ const keyParts = key.split(':');
132
+ if (keyParts.length >= 3) {
133
+ const id = keyParts[2].toLowerCase();
134
+ if (id.includes(query)) {
135
+ results.push({ nodeKey: key, node, matchType: 'id' });
136
+ }
137
+ }
138
+ }
139
+
140
+ return results
141
+ .sort((a, b) => {
142
+ const aExact = a.node.title.toLowerCase() === query;
143
+ const bExact = b.node.title.toLowerCase() === query;
144
+ if (aExact && !bExact) return -1;
145
+ if (!aExact && bExact) return 1;
146
+ return a.node.title.localeCompare(b.node.title);
147
+ })
148
+ .slice(0, 20);
149
+ }, [searchQuery, searchableNodes, searchFilters]);
150
+
151
+ const handleSelectResult = (nodeKey: string, node: NavNode) => {
152
+ onSelectResult(nodeKey, node);
153
+ clearSearch();
154
+ };
155
+
156
+ const results = searchResults();
157
+ const showSearchResults = searchQuery.trim().length > 0;
158
+
159
+ return (
160
+ <>
161
+ {/* Search Input */}
162
+ <div className="px-3 py-2 bg-white border-b border-gray-200">
163
+ <div className="flex gap-2">
164
+ <div className="relative flex-1">
165
+ <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
166
+ <input
167
+ type="text"
168
+ placeholder="Search resources..."
169
+ value={searchQuery}
170
+ onChange={(e) => handleSearchChange(e.target.value)}
171
+ className="w-full pl-9 pr-8 py-2 text-sm bg-gray-50 border border-gray-200 rounded-lg focus:outline-none focus:ring-2 focus:ring-purple-500 focus:border-transparent placeholder:text-gray-400"
172
+ />
173
+ {searchQuery && (
174
+ <button
175
+ onClick={clearSearch}
176
+ className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
177
+ >
178
+ <X className="w-4 h-4" />
179
+ </button>
180
+ )}
181
+ </div>
182
+ {/* Filter Button */}
183
+ <div className="relative">
184
+ <button
185
+ onClick={() => setShowFilterDropdown(!showFilterDropdown)}
186
+ className={cn(
187
+ 'flex items-center justify-center w-10 h-10 rounded-lg border transition-colors',
188
+ searchFilters.size > 0
189
+ ? 'bg-purple-50 border-purple-200 text-purple-600'
190
+ : 'bg-gray-50 border-gray-200 text-gray-400 hover:text-gray-600 hover:bg-gray-100'
191
+ )}
192
+ >
193
+ <SlidersHorizontal className="w-4 h-4" />
194
+ {searchFilters.size > 0 && (
195
+ <span className="absolute -top-1 -right-1 w-4 h-4 bg-purple-600 text-white text-[10px] font-bold rounded-full flex items-center justify-center">
196
+ {searchFilters.size}
197
+ </span>
198
+ )}
199
+ </button>
200
+
201
+ {/* Filter Dropdown */}
202
+ {showFilterDropdown && (
203
+ <>
204
+ <div className="fixed inset-0 z-20" onClick={() => setShowFilterDropdown(false)} />
205
+ <div className="absolute right-0 top-full mt-1 w-48 bg-white rounded-lg shadow-lg border border-gray-200 z-30">
206
+ <div className="p-2">
207
+ <div className="text-[10px] font-medium text-gray-400 uppercase tracking-wide px-2 py-1">Filter by type</div>
208
+ <div className="flex flex-col gap-0.5 mt-1">
209
+ {filterTypes.map((filter) => {
210
+ const isActive = searchFilters.has(filter.key);
211
+ const Icon = filter.icon;
212
+ return (
213
+ <button
214
+ key={filter.key}
215
+ onClick={() => toggleSearchFilter(filter.key)}
216
+ className={cn(
217
+ 'flex items-center justify-between px-2 py-1.5 rounded text-sm transition-colors',
218
+ isActive ? 'bg-purple-50 text-purple-700' : 'text-gray-600 hover:bg-gray-100'
219
+ )}
220
+ >
221
+ <span className="flex items-center gap-2">
222
+ <Icon className="w-3 h-3" />
223
+ {filter.label}
224
+ </span>
225
+ {isActive && <span className="text-purple-600">✓</span>}
226
+ </button>
227
+ );
228
+ })}
229
+ </div>
230
+ {searchFilters.size > 0 && (
231
+ <>
232
+ <div className="border-t border-gray-100 my-2" />
233
+ <button
234
+ onClick={() => {
235
+ setSearchFilters(new Set());
236
+ setShowFilterDropdown(false);
237
+ }}
238
+ className="w-full px-2 py-1.5 text-sm text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded text-left"
239
+ >
240
+ Reset filters
241
+ </button>
242
+ </>
243
+ )}
244
+ </div>
245
+ </div>
246
+ </>
247
+ )}
248
+ </div>
249
+ </div>
250
+ </div>
251
+
252
+ {/* Search Results */}
253
+ {showSearchResults && (
254
+ <div className="flex-1 overflow-y-auto bg-white border-b border-gray-200">
255
+ <div className="px-3 py-2">
256
+ <div className="text-[10px] font-medium text-gray-400 uppercase tracking-wide mb-2">
257
+ {results.length > 0 ? `${results.length} result${results.length > 1 ? 's' : ''}` : 'No results'}
258
+ </div>
259
+ {results.length > 0 && (
260
+ <div className="flex flex-col gap-0.5">
261
+ {results.map(({ nodeKey, node, matchType }) => (
262
+ <button
263
+ key={nodeKey}
264
+ onClick={() => handleSelectResult(nodeKey, node)}
265
+ className="group flex items-center justify-between w-full px-3 py-2 rounded-lg cursor-pointer text-left transition-colors hover:bg-gray-100"
266
+ >
267
+ <div className="flex flex-col min-w-0 flex-1">
268
+ <span className="text-sm text-gray-900 truncate">{node.title}</span>
269
+ {matchType === 'id' && <span className="text-xs text-gray-400 truncate">ID: {nodeKey.split(':')[2]}</span>}
270
+ </div>
271
+ <div className="flex items-center gap-2 flex-shrink-0">
272
+ {node.badge && (
273
+ <span
274
+ className={cn(
275
+ 'px-1.5 py-0.5 text-[8px] font-semibold uppercase tracking-wide rounded',
276
+ getBadgeClasses(node.badge)
277
+ )}
278
+ >
279
+ {node.badge}
280
+ </span>
281
+ )}
282
+ {node.pages && node.pages.length > 0 && (
283
+ <ChevronRight className="w-4 h-4 text-gray-400 group-hover:text-purple-500" />
284
+ )}
285
+ </div>
286
+ </button>
287
+ ))}
288
+ </div>
289
+ )}
290
+ {results.length === 0 && searchQuery.trim() && (
291
+ <div className="text-sm text-gray-500 py-4 text-center">No resources found for "{searchQuery}"</div>
292
+ )}
293
+ </div>
294
+ </div>
295
+ )}
296
+ </>
297
+ );
298
+ }
@@ -0,0 +1,66 @@
1
+ import type { CollectionEntry } from 'astro:content';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import type { NavNode, ChildRef } from './shared';
4
+ import { buildQuickReferenceSection, buildOwnersSection, shouldRenderSideBarSection, buildRepositorySection } from './shared';
5
+ import { isVisualiserEnabled } from '@utils/feature';
6
+
7
+ export const buildContainerNode = (container: CollectionEntry<'containers'>, owners: any[]): NavNode => {
8
+ const servicesWritingToContainer = container.data.servicesThatWriteToContainer || [];
9
+ const servicesReadingFromContainer = container.data.servicesThatReadFromContainer || [];
10
+
11
+ const renderServicesWritingToContainer =
12
+ servicesWritingToContainer.length > 0 && shouldRenderSideBarSection(container, 'services');
13
+ const renderServicesReadingFromContainer =
14
+ servicesReadingFromContainer.length > 0 && shouldRenderSideBarSection(container, 'services');
15
+
16
+ const renderVisualiser = isVisualiserEnabled();
17
+
18
+ const renderOwners = owners.length > 0 && shouldRenderSideBarSection(container, 'owners');
19
+
20
+ const renderRepository = container.data.repository && shouldRenderSideBarSection(container, 'repository');
21
+
22
+ return {
23
+ type: 'item',
24
+ title: container.data.name,
25
+ badge: 'Container',
26
+ summary: container.data.summary,
27
+ pages: [
28
+ buildQuickReferenceSection([
29
+ {
30
+ title: 'Overview',
31
+ href: buildUrl(`/docs/containers/${container.data.id}/${container.data.version}`),
32
+ },
33
+ ]),
34
+ renderVisualiser && {
35
+ type: 'group',
36
+ title: 'Architecture & Design',
37
+ icon: 'Workflow',
38
+ pages: [
39
+ {
40
+ type: 'item',
41
+ title: 'Interaction Map',
42
+ href: buildUrl(`/visualiser/containers/${container.data.id}/${container.data.version}`),
43
+ },
44
+ ],
45
+ },
46
+ renderServicesWritingToContainer && {
47
+ type: 'group',
48
+ title: 'Services (Writes)',
49
+ icon: 'Server',
50
+ pages: servicesWritingToContainer.map(
51
+ (service) => `service:${(service as any).data.id}:${(service as any).data.version}`
52
+ ),
53
+ },
54
+ renderServicesReadingFromContainer && {
55
+ type: 'group',
56
+ title: 'Services (Reads)',
57
+ icon: 'Server',
58
+ pages: servicesReadingFromContainer.map(
59
+ (service) => `service:${(service as any).data.id}:${(service as any).data.version}`
60
+ ),
61
+ },
62
+ renderOwners && buildOwnersSection(owners),
63
+ renderRepository && buildRepositorySection(container.data.repository as { url: string; language: string }),
64
+ ].filter(Boolean) as ChildRef[],
65
+ };
66
+ };
@@ -0,0 +1,101 @@
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
+ buildResourceGroupSections,
6
+ buildQuickReferenceSection,
7
+ buildOwnersSection,
8
+ shouldRenderSideBarSection,
9
+ buildRepositorySection,
10
+ } from './shared';
11
+ import { isVisualiserEnabled } from '@utils/feature';
12
+
13
+ export const buildDomainNode = (domain: CollectionEntry<'domains'>, owners: any[], context: ResourceGroupContext): NavNode => {
14
+ const servicesInDomain = domain.data.services || [];
15
+ const renderServices = servicesInDomain.length > 0 && shouldRenderSideBarSection(domain, 'services');
16
+
17
+ const subDomains = domain.data.domains || [];
18
+ const renderSubDomains = subDomains.length > 0 && shouldRenderSideBarSection(domain, 'subdomains');
19
+
20
+ const entitiesInDomain = domain.data.entities || [];
21
+ const renderEntities = entitiesInDomain.length > 0 && shouldRenderSideBarSection(domain, 'entities');
22
+
23
+ const domainFlows = domain.data.flows || [];
24
+ const hasFlows = domainFlows.length > 0;
25
+
26
+ const resourceGroups = domain.data.resourceGroups || [];
27
+ const hasResourceGroups = resourceGroups.length > 0;
28
+
29
+ const renderUbiquitousLanguage = shouldRenderSideBarSection(domain, 'ubiquitousLanguage');
30
+ const renderOwners = owners.length > 0 && shouldRenderSideBarSection(domain, 'owners');
31
+
32
+ const renderVisualiser = isVisualiserEnabled();
33
+
34
+ const renderRepository = domain.data.repository && shouldRenderSideBarSection(domain, 'repository');
35
+ return {
36
+ type: 'item',
37
+ title: domain.data.name,
38
+ badge: 'Domain',
39
+ summary: domain.data.summary,
40
+ pages: [
41
+ buildQuickReferenceSection([
42
+ { title: 'Overview', href: buildUrl(`/docs/domains/${domain.data.id}/${domain.data.version}`) },
43
+ renderUbiquitousLanguage && { title: 'Ubiquitous Language', href: buildUrl(`/docs/domains/${domain.data.id}/language`) },
44
+ ]),
45
+ {
46
+ type: 'group',
47
+ title: 'Architecture & Design',
48
+ icon: 'Workflow',
49
+ pages: [
50
+ {
51
+ type: 'item',
52
+ title: 'Architecture Diagram',
53
+ href: buildUrl(`/architecture/domains/${domain.data.id}/${domain.data.version}`),
54
+ },
55
+ renderEntities &&
56
+ renderVisualiser && {
57
+ type: 'item',
58
+ title: 'Entity Map',
59
+ href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}/entity-map`),
60
+ },
61
+ renderVisualiser && {
62
+ type: 'item',
63
+ title: 'Interaction Map',
64
+ href: buildUrl(`/visualiser/domains/${domain.data.id}/${domain.data.version}`),
65
+ },
66
+ ].filter(Boolean) as ChildRef[],
67
+ },
68
+ hasFlows && {
69
+ type: 'group',
70
+ title: 'Flows',
71
+ icon: 'Waypoints',
72
+ pages: domainFlows.map((flow) => `flow:${(flow as any).data.id}:${(flow as any).data.version}`),
73
+ },
74
+ renderEntities && {
75
+ type: 'group',
76
+ title: 'Entities',
77
+ icon: 'Box',
78
+ pages: entitiesInDomain.map((entity) => ({
79
+ type: 'item',
80
+ title: (entity as any).data?.name || (entity as any).data.id,
81
+ href: buildUrl(`/docs/entities/${(entity as any).data.id}/${(entity as any).data.version}`),
82
+ })),
83
+ },
84
+ renderSubDomains && {
85
+ type: 'group',
86
+ title: 'Subdomains',
87
+ icon: 'Boxes',
88
+ pages: subDomains.map((domain) => `domain:${(domain as any).data.id}:${(domain as any).data.version}`),
89
+ },
90
+ ...(hasResourceGroups ? buildResourceGroupSections(resourceGroups, context) : []),
91
+ renderServices && {
92
+ type: 'group',
93
+ title: 'Services In Domain',
94
+ icon: 'Server',
95
+ pages: servicesInDomain.map((service) => `service:${(service as any).data.id}:${(service as any).data.version}`),
96
+ },
97
+ renderOwners && buildOwnersSection(owners),
98
+ renderRepository && buildRepositorySection(domain.data.repository as { url: string; language: string }),
99
+ ].filter(Boolean) as ChildRef[],
100
+ };
101
+ };
@@ -0,0 +1,29 @@
1
+ import type { CollectionEntry } from 'astro:content';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import type { NavNode, ChildRef } from './shared';
4
+ import { buildQuickReferenceSection } from './shared';
5
+
6
+ export const buildFlowNode = (flow: CollectionEntry<'flows'>): NavNode => {
7
+ return {
8
+ type: 'item',
9
+ title: flow.data.name,
10
+ icon: 'Waypoint',
11
+ badge: 'Flow',
12
+ summary: flow.data.summary,
13
+ pages: [
14
+ buildQuickReferenceSection([{ title: 'Overview', href: buildUrl(`/docs/flows/${flow.data.id}/${flow.data.version}`) }]),
15
+ {
16
+ type: 'group',
17
+ title: 'Architecture & Design',
18
+ icon: 'Workflow',
19
+ pages: [
20
+ {
21
+ type: 'item',
22
+ title: 'Flow Diagram',
23
+ href: buildUrl(`/visualiser/flows/${flow.data.id}/${flow.data.version}`),
24
+ },
25
+ ].filter(Boolean) as ChildRef[],
26
+ },
27
+ ],
28
+ };
29
+ };
@@ -0,0 +1,84 @@
1
+ import type { CollectionEntry } from 'astro:content';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import { getSchemaFormatFromURL } from '@utils/collections/schemas';
4
+ import type { NavNode, ChildRef } from './shared';
5
+ import { buildQuickReferenceSection, buildOwnersSection, shouldRenderSideBarSection, buildRepositorySection } from './shared';
6
+ import { isVisualiserEnabled } from '@utils/feature';
7
+
8
+ export const buildMessageNode = (message: CollectionEntry<'events' | 'commands' | 'queries'>, owners: any[]): NavNode => {
9
+ const producers = message.data.producers || [];
10
+ const consumers = message.data.consumers || [];
11
+ const collection = message.collection;
12
+
13
+ const renderProducers = producers.length > 0 && shouldRenderSideBarSection(message, 'producers');
14
+ const renderConsumers = consumers.length > 0 && shouldRenderSideBarSection(message, 'consumers');
15
+ const renderRepository = message.data.repository && shouldRenderSideBarSection(message, 'repository');
16
+
17
+ // Determine badge based on collection type
18
+ const badgeMap: Record<string, string> = {
19
+ events: 'Event',
20
+ commands: 'Command',
21
+ queries: 'Query',
22
+ };
23
+ const badge = badgeMap[collection] || 'Message';
24
+
25
+ const hasSchema = message.data.schemaPath !== undefined;
26
+ const renderVisualiser = isVisualiserEnabled();
27
+
28
+ const renderOwners = owners.length > 0 && shouldRenderSideBarSection(message, 'owners');
29
+
30
+ return {
31
+ type: 'item',
32
+ title: message.data.name,
33
+ badge,
34
+ summary: message.data.summary,
35
+ pages: [
36
+ buildQuickReferenceSection([
37
+ {
38
+ title: 'Overview',
39
+ href: buildUrl(`/docs/${collection}/${message.data.id}/${message.data.version}`),
40
+ },
41
+ ]),
42
+ renderVisualiser && {
43
+ type: 'group',
44
+ title: 'Architecture & Design',
45
+ icon: 'Workflow',
46
+ pages: [
47
+ {
48
+ type: 'item',
49
+ title: 'Interaction Map',
50
+ href: buildUrl(`/visualiser/${collection}/${message.data.id}/${message.data.version}`),
51
+ },
52
+ ],
53
+ },
54
+ hasSchema && {
55
+ type: 'group',
56
+ title: `API & Contracts`,
57
+ icon: 'FileJson',
58
+ pages: [
59
+ {
60
+ type: 'item',
61
+ title: `Schema (${getSchemaFormatFromURL(message.data.schemaPath!).toUpperCase()})`,
62
+ href: buildUrl(`/schemas/${collection}/${message.data.id}/${message.data.version}`),
63
+ },
64
+ ],
65
+ },
66
+ renderProducers && {
67
+ type: 'group',
68
+ title: 'Producers',
69
+ icon: 'Server',
70
+ pages: producers.map((producer) => `service:${(producer as any).data.id}:${(producer as any).data.version}`),
71
+ visible: producers.length > 0,
72
+ },
73
+ renderConsumers && {
74
+ type: 'group',
75
+ title: 'Consumers',
76
+ icon: 'Server',
77
+ pages: consumers.map((consumer) => `service:${(consumer as any).data.id}:${(consumer as any).data.version}`),
78
+ visible: consumers.length > 0,
79
+ },
80
+ renderOwners && buildOwnersSection(owners),
81
+ renderRepository && buildRepositorySection(message.data.repository as { url: string; language: string }),
82
+ ].filter(Boolean) as ChildRef[],
83
+ };
84
+ };