@eventcatalog/core 2.26.1 → 2.28.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 (37) 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-TOTPAQ4C.js → chunk-KGWJTMWU.js} +1 -1
  6. package/dist/{chunk-M7ERKXSB.js → chunk-KYGD25IE.js} +1 -1
  7. package/dist/{chunk-JCGLXXSE.js → chunk-RCPEAVRY.js} +1 -1
  8. package/dist/constants.cjs +1 -1
  9. package/dist/constants.js +1 -1
  10. package/dist/eventcatalog.cjs +1 -1
  11. package/dist/eventcatalog.config.d.cts +1 -4
  12. package/dist/eventcatalog.config.d.ts +1 -4
  13. package/dist/eventcatalog.js +3 -3
  14. package/eventcatalog/astro.config.mjs +0 -3
  15. package/eventcatalog/public/logo.svg +14 -0
  16. package/eventcatalog/src/components/Grids/DomainGrid.tsx +233 -0
  17. package/eventcatalog/src/components/Grids/MessageGrid.tsx +457 -0
  18. package/eventcatalog/src/components/Grids/ServiceGrid.tsx +362 -0
  19. package/eventcatalog/src/components/Grids/components.tsx +170 -0
  20. package/eventcatalog/src/components/Grids/utils.tsx +38 -0
  21. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +46 -0
  22. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +31 -0
  23. package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +390 -0
  24. package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +48 -0
  25. package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +103 -0
  26. package/eventcatalog/src/components/SideNav/SideNav.astro +8 -7
  27. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +34 -22
  28. package/eventcatalog/src/pages/architecture/[type]/index.astro +14 -0
  29. package/eventcatalog/src/pages/architecture/architecture.astro +81 -0
  30. package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +14 -0
  31. package/eventcatalog/src/pages/index.astro +237 -72
  32. package/eventcatalog/src/utils/url-builder.ts +20 -0
  33. package/eventcatalog/tailwind.config.mjs +11 -0
  34. package/package.json +2 -1
  35. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/getCatalogResources.ts +0 -65
  36. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/index.tsx +0 -138
  37. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/styles.css +0 -8
@@ -0,0 +1,390 @@
1
+ import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
2
+ import { ChevronDownIcon } from '@heroicons/react/24/outline';
3
+ import { buildUrl, buildUrlWithParams } from '@utils/url-builder';
4
+ import CollapsibleGroup from './components/CollapsibleGroup';
5
+ import MessageList from './components/MessageList';
6
+ import type { MessageItem, ServiceItem, ListViewSideBarProps } from './types';
7
+ const STORAGE_KEY = 'EventCatalog:catalogSidebarCollapsedGroups';
8
+ const DEBOUNCE_DELAY = 300; // 300ms debounce delay
9
+
10
+ export const getMessageColorByCollection = (collection: string) => {
11
+ if (collection === 'commands') return 'bg-blue-50 text-blue-600';
12
+ if (collection === 'queries') return 'bg-green-50 text-green-600';
13
+ if (collection === 'events') return 'bg-orange-50 text-orange-600';
14
+ return 'text-gray-600';
15
+ };
16
+
17
+ export const getMessageCollectionName = (collection: string) => {
18
+ if (collection === 'commands') return 'Command';
19
+ if (collection === 'queries') return 'Query';
20
+ if (collection === 'events') return 'Event';
21
+ return collection.slice(0, collection.length - 1).toUpperCase();
22
+ };
23
+
24
+ const NoResultsFound = React.memo(({ searchTerm }: { searchTerm: string }) => (
25
+ <div className="px-4 py-6 text-center">
26
+ <div className="text-gray-400 text-sm mb-2">No results found for "{searchTerm}"</div>
27
+ <div className="text-gray-400 text-xs">
28
+ Try:
29
+ <ul className="mt-2 space-y-1 text-left list-disc pl-4">
30
+ <li>Checking for typos</li>
31
+ <li>Using fewer keywords</li>
32
+ <li>Using more general terms</li>
33
+ </ul>
34
+ </div>
35
+ </div>
36
+ ));
37
+
38
+ const ServiceItem = React.memo(
39
+ ({
40
+ item,
41
+ decodedCurrentPath,
42
+ collapsedGroups,
43
+ toggleGroupCollapse,
44
+ }: {
45
+ item: ServiceItem;
46
+ decodedCurrentPath: string;
47
+ collapsedGroups: { [key: string]: boolean };
48
+ toggleGroupCollapse: (group: string) => void;
49
+ }) => (
50
+ <CollapsibleGroup
51
+ isCollapsed={collapsedGroups[item.href]}
52
+ onToggle={() => toggleGroupCollapse(item.href)}
53
+ title={
54
+ <button
55
+ onClick={(e) => {
56
+ e.stopPropagation();
57
+ toggleGroupCollapse(item.href);
58
+ }}
59
+ className="flex justify-between items-center pl-2 w-full text-xs"
60
+ >
61
+ <span className="truncate text-xs font-bold">{item.label}</span>
62
+ <span className="text-purple-600 ml-2 text-[10px] font-medium bg-purple-50 px-2 py-0.5 rounded">SERVICE</span>
63
+ </button>
64
+ }
65
+ >
66
+ <div className="space-y-0 border-gray-200/80 border-l pl-3 ml-[9px] mt-1">
67
+ <a
68
+ href={`${item.href}`}
69
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
70
+ decodedCurrentPath === item.href ? 'bg-purple-100' : 'hover:bg-purple-100'
71
+ }`}
72
+ >
73
+ <span className="truncate">Overview</span>
74
+ </a>
75
+ <a
76
+ href={buildUrlWithParams('/architecture/docs/messages', {
77
+ serviceName: item.name,
78
+ serviceId: item.id,
79
+ })}
80
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
81
+ window.location.href.includes(`serviceId=${item.id}`) ? 'bg-purple-100' : 'hover:bg-purple-100'
82
+ }`}
83
+ >
84
+ <span className="truncate">Architecture</span>
85
+ </a>
86
+
87
+ <CollapsibleGroup
88
+ isCollapsed={collapsedGroups[`${item.href}-receives`]}
89
+ onToggle={() => toggleGroupCollapse(`${item.href}-receives`)}
90
+ title={
91
+ <button
92
+ onClick={(e) => {
93
+ e.stopPropagation();
94
+ toggleGroupCollapse(`${item.href}-receives`);
95
+ }}
96
+ className="truncate underline ml-2 text-xs mb-1 py-1"
97
+ >
98
+ Receives messages ({item.receives.length})
99
+ </button>
100
+ }
101
+ >
102
+ <MessageList messages={item.receives} decodedCurrentPath={decodedCurrentPath} />
103
+ </CollapsibleGroup>
104
+
105
+ <CollapsibleGroup
106
+ isCollapsed={collapsedGroups[`${item.href}-sends`]}
107
+ onToggle={() => toggleGroupCollapse(`${item.href}-sends`)}
108
+ title={
109
+ <button
110
+ onClick={(e) => {
111
+ e.stopPropagation();
112
+ toggleGroupCollapse(`${item.href}-sends`);
113
+ }}
114
+ className="truncate underline ml-2 text-xs mb-1 py-1"
115
+ >
116
+ Sends messages ({item.sends.length})
117
+ </button>
118
+ }
119
+ >
120
+ <MessageList messages={item.sends} decodedCurrentPath={decodedCurrentPath} />
121
+ </CollapsibleGroup>
122
+ </div>
123
+ </CollapsibleGroup>
124
+ )
125
+ );
126
+
127
+ const ListViewSideBar: React.FC<ListViewSideBarProps> = ({ resources, currentPath }) => {
128
+ const navRef = useRef<HTMLElement>(null);
129
+ const [data] = useState(resources);
130
+ const [searchTerm, setSearchTerm] = useState('');
131
+ const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('');
132
+ const [isInitialized, setIsInitialized] = useState(false);
133
+ const [collapsedGroups, setCollapsedGroups] = useState<{ [key: string]: boolean }>(() => {
134
+ if (typeof window !== 'undefined') {
135
+ const saved = window.localStorage.getItem(STORAGE_KEY);
136
+ setIsInitialized(true);
137
+ return saved ? JSON.parse(saved) : {};
138
+ }
139
+ return {};
140
+ });
141
+
142
+ const decodedCurrentPath = decodeURIComponent(currentPath);
143
+
144
+ // Debounce search term updates
145
+ useEffect(() => {
146
+ const timer = setTimeout(() => {
147
+ setDebouncedSearchTerm(searchTerm.toLowerCase());
148
+ }, DEBOUNCE_DELAY);
149
+
150
+ return () => clearTimeout(timer);
151
+ }, [searchTerm]);
152
+
153
+ // Filter data based on search term
154
+ const filteredData = useMemo(() => {
155
+ if (!debouncedSearchTerm) return data;
156
+
157
+ const filterItem = (item: { label: string }) => {
158
+ return item.label.toLowerCase().includes(debouncedSearchTerm);
159
+ };
160
+
161
+ const filterMessages = (messages: MessageItem[]) => {
162
+ return messages.filter((message) => message.data.name.toLowerCase().includes(debouncedSearchTerm));
163
+ };
164
+
165
+ return {
166
+ domains: data.domains?.filter(filterItem) || [],
167
+ services:
168
+ data.services
169
+ ?.map((service: ServiceItem) => ({
170
+ ...service,
171
+ sends: filterMessages(service.sends),
172
+ receives: filterMessages(service.receives),
173
+ isVisible:
174
+ filterItem(service) ||
175
+ service.sends.some((msg: MessageItem) => msg.data.name.toLowerCase().includes(debouncedSearchTerm)) ||
176
+ service.receives.some((msg: MessageItem) => msg.data.name.toLowerCase().includes(debouncedSearchTerm)),
177
+ }))
178
+ .filter((service: ServiceItem & { isVisible: boolean }) => service.isVisible) || [],
179
+ flows: data.flows?.filter(filterItem) || [],
180
+ messagesNotInService:
181
+ data.messagesNotInService?.filter((msg: MessageItem) => msg.label.toLowerCase().includes(debouncedSearchTerm)) || [],
182
+ };
183
+ }, [data, debouncedSearchTerm]);
184
+
185
+ // Auto-expand groups when searching
186
+ useEffect(() => {
187
+ if (debouncedSearchTerm) {
188
+ // Expand all groups when searching
189
+ const newCollapsedState = { ...collapsedGroups };
190
+ Object.keys(newCollapsedState).forEach((key) => {
191
+ newCollapsedState[key] = false;
192
+ });
193
+ setCollapsedGroups(newCollapsedState);
194
+ }
195
+ }, [debouncedSearchTerm]);
196
+
197
+ // Store collapsed groups in local storage
198
+ useEffect(() => {
199
+ if (typeof window !== 'undefined') {
200
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(collapsedGroups));
201
+ }
202
+ }, [collapsedGroups]);
203
+
204
+ // If we find a data-active element, scroll to it on mount
205
+ useEffect(() => {
206
+ const activeElement = document.querySelector('[data-active="true"]');
207
+ if (activeElement) {
208
+ // Add y offset to the scroll position
209
+ activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
210
+ }
211
+ }, []);
212
+
213
+ const toggleGroupCollapse = useCallback((group: string) => {
214
+ setCollapsedGroups((prev) => ({
215
+ ...prev,
216
+ [group]: !prev[group],
217
+ }));
218
+ }, []);
219
+
220
+ const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
221
+ setSearchTerm(e.target.value);
222
+ }, []);
223
+
224
+ if (!isInitialized) return null;
225
+
226
+ const hasNoResults =
227
+ debouncedSearchTerm &&
228
+ !filteredData.domains?.length &&
229
+ !filteredData.services?.length &&
230
+ !filteredData.flows?.length &&
231
+ !filteredData.messagesNotInService?.length;
232
+
233
+ return (
234
+ <nav ref={navRef} className="space-y-4 text-gray-800 px-3 py-4">
235
+ <input
236
+ type="text"
237
+ value={searchTerm}
238
+ onChange={handleSearchChange}
239
+ placeholder="Quick search..."
240
+ className="w-full p-2 text-sm rounded-md border border-gray-200 h-[30px]"
241
+ />
242
+ <div className="space-y-2 divide-y divide-gray-200/80">
243
+ {hasNoResults ? (
244
+ <NoResultsFound searchTerm={debouncedSearchTerm} />
245
+ ) : (
246
+ <>
247
+ {/* Domains */}
248
+ {filteredData['domains'] && (
249
+ <div>
250
+ <ul className="space-y-2">
251
+ {filteredData['domains'].map((item: any) => (
252
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
253
+ <div className="flex items-center">
254
+ <button
255
+ onClick={(e) => {
256
+ e.stopPropagation();
257
+ toggleGroupCollapse(item.href);
258
+ }}
259
+ className="p-1 hover:bg-gray-100 rounded-md"
260
+ >
261
+ <div className={`transition-transform duration-150 ${collapsedGroups[item.href] ? '' : 'rotate-180'}`}>
262
+ <ChevronDownIcon className="h-3 w-3 text-gray-500" />
263
+ </div>
264
+ </button>
265
+ <button
266
+ onClick={(e) => {
267
+ e.stopPropagation();
268
+ toggleGroupCollapse(item.href);
269
+ }}
270
+ className={`flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
271
+ decodedCurrentPath === item.href
272
+ }`}
273
+ >
274
+ <span className="truncate">{item.label}</span>
275
+ <span className="text-yellow-600 ml-2 text-[10px] font-medium bg-yellow-50 px-2 py-0.5 rounded">
276
+ DOMAIN
277
+ </span>
278
+ </button>
279
+ </div>
280
+ <div
281
+ className={`overflow-hidden transition-[height] duration-150 ease-out ${
282
+ collapsedGroups[item.href] ? 'h-0' : 'h-auto'
283
+ }`}
284
+ >
285
+ <div className="space-y-0 border-gray-200/80 border-l pl-4 ml-[9px] mt-1">
286
+ <a
287
+ href={`${item.href}`}
288
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
289
+ decodedCurrentPath === item.href ? 'bg-purple-100 ' : 'hover:bg-purple-100'
290
+ }`}
291
+ >
292
+ <span className="truncate">Overview</span>
293
+ </a>
294
+ <a
295
+ href={buildUrlWithParams('/architecture/docs/services', {
296
+ serviceIds: item.services.map((service: any) => service.data.id).join(','),
297
+ domainId: item.id,
298
+ domainName: item.name,
299
+ })}
300
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
301
+ window.location.href.includes(`domainId=${item.id}`) ? 'bg-purple-100 ' : 'hover:bg-purple-100'
302
+ }`}
303
+ >
304
+ <span className="truncate">Architecture</span>
305
+ </a>
306
+ <a
307
+ href={buildUrl(`/docs/domains/${item.id}/language`)}
308
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
309
+ decodedCurrentPath.includes(`/docs/domains/${item.id}/language`)
310
+ ? 'bg-purple-100 '
311
+ : 'hover:bg-purple-100'
312
+ }`}
313
+ >
314
+ <span className="truncate">Ubiquitous Language</span>
315
+ </a>
316
+ </div>
317
+ </div>
318
+ </li>
319
+ ))}
320
+ </ul>
321
+ </div>
322
+ )}
323
+
324
+ {filteredData['services'] && (
325
+ <div className="pt-4 pb-2">
326
+ <ul className="space-y-4">
327
+ {filteredData['services'].map((item: any) => (
328
+ <ServiceItem
329
+ key={item.href}
330
+ item={item}
331
+ decodedCurrentPath={decodedCurrentPath}
332
+ collapsedGroups={collapsedGroups}
333
+ toggleGroupCollapse={toggleGroupCollapse}
334
+ />
335
+ ))}
336
+ </ul>
337
+ </div>
338
+ )}
339
+
340
+ {filteredData['messagesNotInService'] && (
341
+ <div className="pt-4 pb-2">
342
+ <ul className="space-y-4">
343
+ {filteredData['messagesNotInService'].map((item: any) => (
344
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
345
+ <a
346
+ href={item.href}
347
+ className={`flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
348
+ decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
349
+ }`}
350
+ >
351
+ <span className="truncate">{item.label}</span>
352
+ <span
353
+ className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded ${getMessageColorByCollection(item.collection)}`}
354
+ >
355
+ {getMessageCollectionName(item.collection)}
356
+ </span>
357
+ </a>
358
+ </li>
359
+ ))}
360
+ </ul>
361
+ </div>
362
+ )}
363
+
364
+ {filteredData['flows'] && (
365
+ <div className="pt-4 pb-2">
366
+ <ul className="space-y-4">
367
+ {filteredData['flows'].map((item: any) => (
368
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
369
+ <a
370
+ href={item.href}
371
+ className={`flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
372
+ decodedCurrentPath === item.href ? 'bg-cyan-100 text-cyan-900' : 'hover:bg-purple-100'
373
+ }`}
374
+ >
375
+ <span className="truncate">{item.label}</span>
376
+ <span className="text-cyan-600 ml-2 text-[10px] font-medium bg-cyan-50 px-2 py-0.5 rounded">FLOW</span>
377
+ </a>
378
+ </li>
379
+ ))}
380
+ </ul>
381
+ </div>
382
+ )}
383
+ </>
384
+ )}
385
+ </div>
386
+ </nav>
387
+ );
388
+ };
389
+
390
+ export default React.memo(ListViewSideBar);
@@ -0,0 +1,48 @@
1
+ export interface MessageItem {
2
+ href: string;
3
+ label: string;
4
+ service: string;
5
+ id: string;
6
+ direction: 'sends' | 'receives';
7
+ type: 'command' | 'query' | 'event';
8
+ data: {
9
+ name: string;
10
+ };
11
+ }
12
+
13
+ export interface ServiceItem {
14
+ href: string;
15
+ label: string;
16
+ name: string;
17
+ id: string;
18
+ sends: MessageItem[];
19
+ receives: MessageItem[];
20
+ }
21
+
22
+ interface DomainItem {
23
+ href: string;
24
+ label: string;
25
+ id: string;
26
+ name: string;
27
+ services: any[];
28
+ }
29
+
30
+ interface FlowItem {
31
+ href: string;
32
+ label: string;
33
+ }
34
+
35
+ interface Resources {
36
+ domains?: DomainItem[];
37
+ services?: ServiceItem[];
38
+ flows?: FlowItem[];
39
+ messagesNotInService?: MessageItem[];
40
+ commands?: MessageItem[];
41
+ queries?: MessageItem[];
42
+ events?: MessageItem[];
43
+ }
44
+
45
+ export interface ListViewSideBarProps {
46
+ resources: Resources;
47
+ currentPath: string;
48
+ }
@@ -0,0 +1,103 @@
1
+ import { isCollectionVisibleInCatalog } from '@eventcatalog';
2
+ import { buildUrl } from '@utils/url-builder';
3
+ import { getChannels } from '@utils/channels';
4
+ import { getDomains } from '@utils/collections/domains';
5
+ import { getFlows } from '@utils/collections/flows';
6
+ import { getServices } from '@utils/collections/services';
7
+ import { getCommands } from '@utils/commands';
8
+ import { getEvents } from '@utils/events';
9
+ import { getQueries } from '@utils/queries';
10
+
11
+ export async function getResourcesForNavigation({ currentPath }: { currentPath: string }) {
12
+ const events = await getEvents({ getAllVersions: false });
13
+ const commands = await getCommands({ getAllVersions: false });
14
+ const queries = await getQueries({ getAllVersions: false });
15
+ const services = await getServices({ getAllVersions: false });
16
+ const domains = await getDomains({ getAllVersions: false });
17
+ const channels = await getChannels({ getAllVersions: false });
18
+ const flows = await getFlows({ getAllVersions: false });
19
+
20
+ const messages = [...events, ...commands, ...queries];
21
+
22
+ // messages that are not in a service (sends or receives)
23
+ const messagesNotInService = messages.filter(
24
+ (message) =>
25
+ !services.some(
26
+ (service) =>
27
+ service.data?.sends?.some((send: any) => send.data.id === message.data.id) ||
28
+ service.data?.receives?.some((receive: any) => receive.data.id === message.data.id)
29
+ )
30
+ );
31
+
32
+ const route = currentPath.includes('visualiser') ? 'visualiser' : 'docs';
33
+
34
+ // Just the domains for now.
35
+ const allDataAsSideNav = [...domains, ...services, ...flows, ...channels].reduce((acc, item) => {
36
+ const title = item.collection;
37
+ const group = acc[title] || [];
38
+
39
+ const servicesCount = item.collection === 'domains' ? item.data.services?.length || 0 : 0;
40
+ const sends = item.collection === 'services' ? item.data.sends || null : null;
41
+ const receives = item.collection === 'services' ? item.data.receives || null : null;
42
+
43
+ // Add href to the sends and receives
44
+ const sendsWithHref = sends?.map((send: any) => ({
45
+ ...send,
46
+ href: buildUrl(`/${route}/${send.collection}/${send.data.id}/${send.data.version}`),
47
+ }));
48
+ const receivesWithHref = receives?.map((receive: any) => ({
49
+ ...receive,
50
+ href: buildUrl(`/${route}/${receive.collection}/${receive.data.id}/${receive.data.version}`),
51
+ }));
52
+
53
+ const navigationItem = {
54
+ label: item.data.name,
55
+ version: item.data.version,
56
+ // items: item.collection === 'users' ? [] : item.headings,
57
+ visible: isCollectionVisibleInCatalog(item.collection),
58
+ // @ts-ignore
59
+ href: item.data.version
60
+ ? // @ts-ignore
61
+ buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`)
62
+ : buildUrl(`/${route}/${item.collection}/${item.data.id}`),
63
+ collection: item.collection,
64
+ servicesCount,
65
+ id: item.data.id,
66
+ name: item.data.name,
67
+ services: item.collection === 'domains' ? item.data.services : null,
68
+ sends: sendsWithHref,
69
+ receives: receivesWithHref,
70
+ };
71
+
72
+ group.push(navigationItem);
73
+
74
+ return {
75
+ ...acc,
76
+ [title]: group,
77
+ };
78
+ }, {} as any);
79
+
80
+ // Add messagesNotInService
81
+ const messagesNotInServiceAsSideNav = messagesNotInService.map((item) => ({
82
+ label: item.data.name,
83
+ version: item.data.version,
84
+ id: item.data.id,
85
+ name: item.data.name,
86
+ href: buildUrl(`/${route}/${item.collection}/${item.data.id}/${item.data.version}`),
87
+ collection: item.collection,
88
+ }));
89
+
90
+ const sideNav = {
91
+ ...(currentPath.includes('visualiser')
92
+ ? {
93
+ 'bounded context map': [
94
+ { label: 'Domain map', href: buildUrl('/visualiser/context-map'), collection: 'bounded-context-map' },
95
+ ],
96
+ }
97
+ : {}),
98
+ ...allDataAsSideNav,
99
+ messagesNotInService: messagesNotInServiceAsSideNav,
100
+ };
101
+
102
+ return sideNav;
103
+ }
@@ -3,29 +3,30 @@ import type { HTMLAttributes } from 'astro/types';
3
3
  import config from '@config';
4
4
 
5
5
  // FlatView
6
- import CatalogResourcesSideBar from './CatalogResourcesSideBar';
7
- import { getCatalogResources } from './CatalogResourcesSideBar/getCatalogResources';
6
+ import { getResourcesForNavigation as getListViewResources } from './ListViewSideBar/utils';
8
7
 
9
8
  // TreeView
10
9
  import { SideNavTreeView } from './TreeView';
11
10
  import { getTreeView } from './TreeView/getTreeView';
12
11
 
12
+ import ListViewSideBar from './ListViewSideBar';
13
+
13
14
  interface Props extends Omit<HTMLAttributes<'div'>, 'children'> {}
14
15
 
15
16
  const currentPath = Astro.url.pathname;
16
17
 
17
18
  let props;
18
19
 
19
- const SIDENAV_TYPE = config?.docs?.sidebar?.type ?? 'FLAT_VIEW';
20
+ const SIDENAV_TYPE = config?.docs?.sidebar?.type ?? 'LIST_VIEW';
20
21
 
21
- if (SIDENAV_TYPE === 'FLAT_VIEW') {
22
- props = await getCatalogResources({ currentPath });
23
- } else if (SIDENAV_TYPE === 'TREE_VIEW') {
22
+ if (SIDENAV_TYPE === 'TREE_VIEW') {
24
23
  props = getTreeView({ projectDir: process.env.PROJECT_DIR!, currentPath });
24
+ } else if (SIDENAV_TYPE === 'LIST_VIEW') {
25
+ props = await getListViewResources({ currentPath });
25
26
  }
26
27
  ---
27
28
 
28
29
  <div {...Astro.props}>
29
- {SIDENAV_TYPE === 'FLAT_VIEW' && <CatalogResourcesSideBar resources={props} currentPath={currentPath} client:load />}
30
+ {SIDENAV_TYPE === 'LIST_VIEW' && <ListViewSideBar resources={props} currentPath={currentPath} client:only />}
30
31
  {SIDENAV_TYPE === 'TREE_VIEW' && <SideNavTreeView client:only transition:persist tree={props} />}
31
32
  </div>
@@ -5,10 +5,11 @@ interface Props {
5
5
  description?: string;
6
6
  }
7
7
 
8
- import { BookOpenText, Workflow, TableProperties, House, BookUser, MessageSquare, BotMessageSquare } from 'lucide-react';
8
+ import { BookOpenText, Workflow, TableProperties, House, BookUser, MessageSquare, BotMessageSquare, Users } from 'lucide-react';
9
9
  import Header from '../components/Header.astro';
10
10
  import SEO from '../components/Seo.astro';
11
11
  import SideNav from '../components/SideNav/SideNav.astro';
12
+ // import '@fontsource/inter';
12
13
 
13
14
  import { getCommands } from '@utils/commands';
14
15
  import { getDomains } from '@utils/collections/domains';
@@ -65,7 +66,7 @@ const navigationItems = [
65
66
  label: 'Documentation',
66
67
  icon: BookOpenText,
67
68
  href: catalogHasDefaultLandingPageForDocs ? buildUrl('/docs') : getDefaultUrl('docs', '/docs'),
68
- current: currentPath.includes('/docs'),
69
+ current: currentPath.includes('/docs') || currentPath.includes('/architecture/docs/'),
69
70
  sidebar: true,
70
71
  },
71
72
  {
@@ -86,12 +87,21 @@ const navigationItems = [
86
87
  },
87
88
  {
88
89
  id: '/directory',
89
- label: 'Directory',
90
- icon: BookUser,
90
+ label: 'Users & Teams',
91
+ icon: Users,
91
92
  href: buildUrl('/directory/users'),
92
93
  current: currentPath.includes('/directory'),
93
94
  sidebar: false,
94
95
  },
96
+ {
97
+ id: '/architecture',
98
+ label: 'Architecture',
99
+ icon: BookUser,
100
+ href: buildUrl('/architecture/domains'),
101
+ current: currentPath.includes('/architecture/'),
102
+ sidebar: false,
103
+ hidden: true,
104
+ },
95
105
  {
96
106
  id: '/chat',
97
107
  label: 'AI Assistant',
@@ -139,23 +149,25 @@ const canPageBeEmbedded = process.env.ENABLE_EMBED === 'true';
139
149
  <nav class="flex flex-col h-[84vh] justify-between">
140
150
  <div class="flex flex-col items-center flex-1 space-y-8">
141
151
  {
142
- navigationItems.map((item) => {
143
- return (
144
- <a
145
- id={item.id}
146
- data-role="nav-item"
147
- href={item.href}
148
- class={`p-1.5 inline-block transition-colors duration-200 rounded-lg ${item.current ? 'text-white bg-gradient-to-b from-purple-500 to-purple-700' : 'hover:bg-gradient-to-r hover:from-purple-500 hover:to-purple-700 hover:text-white text-gray-700'}`}
149
- >
150
- <div class="has-tooltip">
151
- <span class="tooltip rounded shadow-lg p-1 text-xs bg-gradient-to-l from-purple-500 to-purple-700 text-white ml-10">
152
- {item.label}
153
- </span>
154
- <item.icon className="h-6 w-6 " />
155
- </div>
156
- </a>
157
- );
158
- })
152
+ navigationItems
153
+ .filter((item) => !item.hidden)
154
+ .map((item) => {
155
+ return (
156
+ <a
157
+ id={item.id}
158
+ data-role="nav-item"
159
+ href={item.href}
160
+ class={`p-1.5 inline-block transition-colors duration-200 rounded-lg ${item.current ? 'text-white bg-gradient-to-b from-purple-500 to-purple-700' : 'hover:bg-gradient-to-r hover:from-purple-500 hover:to-purple-700 hover:text-white text-gray-700'}`}
161
+ >
162
+ <div class="has-tooltip">
163
+ <span class="tooltip rounded shadow-lg p-1 text-xs bg-gradient-to-l from-purple-500 to-purple-700 text-white ml-10">
164
+ {item.label}
165
+ </span>
166
+ <item.icon className="h-6 w-6 " />
167
+ </div>
168
+ </a>
169
+ );
170
+ })
159
171
  }
160
172
  </div>
161
173
  </nav>
@@ -163,7 +175,7 @@ const canPageBeEmbedded = process.env.ENABLE_EMBED === 'true';
163
175
 
164
176
  <SideNav
165
177
  id="sidebar"
166
- class={`sidebar-transition h-content overflow-y-auto bg-white border-r border-gray-100 w-60 ml-16 ${showSideBarOnLoad ? 'block' : 'hidden'}`}
178
+ class={`sidebar-transition h-content overflow-y-auto bg-white border-r border-gray-100 w-80 ml-16 ${showSideBarOnLoad ? 'block' : 'hidden'}`}
167
179
  />
168
180
  </aside>
169
181
  <main