@eventcatalog/core 2.27.0 → 2.28.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.
Files changed (30) 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-2VGR4HMJ.js → chunk-2TWZFRC5.js} +1 -1
  6. package/dist/{chunk-LMNJPHFP.js → chunk-32CT66GO.js} +1 -1
  7. package/dist/{chunk-CTL6CH3C.js → chunk-3AWWP5JR.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/public/logo.svg +14 -0
  15. package/eventcatalog/src/components/Grids/ServiceGrid.tsx +2 -4
  16. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +46 -0
  17. package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +30 -0
  18. package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +389 -0
  19. package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +48 -0
  20. package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +103 -0
  21. package/eventcatalog/src/components/SideNav/SideNav.astro +8 -7
  22. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -7
  23. package/eventcatalog/src/pages/architecture/[type]/index.astro +3 -77
  24. package/eventcatalog/src/pages/architecture/architecture.astro +81 -0
  25. package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +14 -0
  26. package/eventcatalog/src/pages/index.astro +1 -1
  27. package/package.json +1 -1
  28. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/getCatalogResources.ts +0 -65
  29. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/index.tsx +0 -138
  30. package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/styles.css +0 -8
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "2.27.0";
40
+ var version = "2.28.1";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-2VGR4HMJ.js";
4
- import "../chunk-LMNJPHFP.js";
3
+ } from "../chunk-2TWZFRC5.js";
4
+ import "../chunk-32CT66GO.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -106,7 +106,7 @@ var import_axios = __toESM(require("axios"), 1);
106
106
  var import_os = __toESM(require("os"), 1);
107
107
 
108
108
  // package.json
109
- var version = "2.27.0";
109
+ var version = "2.28.1";
110
110
 
111
111
  // src/constants.ts
112
112
  var VERSION = version;
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-CTL6CH3C.js";
4
- import "../chunk-2VGR4HMJ.js";
5
- import "../chunk-LMNJPHFP.js";
3
+ } from "../chunk-3AWWP5JR.js";
4
+ import "../chunk-2TWZFRC5.js";
5
+ import "../chunk-32CT66GO.js";
6
6
  import "../chunk-E7TXTI7G.js";
7
7
  export {
8
8
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-LMNJPHFP.js";
3
+ } from "./chunk-32CT66GO.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "2.27.0";
2
+ var version = "2.28.1";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-2VGR4HMJ.js";
3
+ } from "./chunk-2TWZFRC5.js";
4
4
  import {
5
5
  getEventCatalogConfigFile,
6
6
  verifyRequiredFieldsAreInCatalogConfigFile
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "2.27.0";
28
+ var version = "2.28.1";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-LMNJPHFP.js";
3
+ } from "./chunk-32CT66GO.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -161,7 +161,7 @@ var import_axios = __toESM(require("axios"), 1);
161
161
  var import_os = __toESM(require("os"), 1);
162
162
 
163
163
  // package.json
164
- var version = "2.27.0";
164
+ var version = "2.28.1";
165
165
 
166
166
  // src/constants.ts
167
167
  var VERSION = version;
@@ -33,10 +33,7 @@ interface Config {
33
33
  mdxOptimize?: boolean;
34
34
  docs: {
35
35
  sidebar: {
36
- /**
37
- * @default 'FLAT_VIEW'
38
- */
39
- type?: 'FLAT_VIEW' | 'TREE_VIEW';
36
+ type?: 'TREE_VIEW' | 'LIST_VIEW';
40
37
  showPageHeadings: true;
41
38
  services?: SideBarConfig;
42
39
  messages?: SideBarConfig;
@@ -33,10 +33,7 @@ interface Config {
33
33
  mdxOptimize?: boolean;
34
34
  docs: {
35
35
  sidebar: {
36
- /**
37
- * @default 'FLAT_VIEW'
38
- */
39
- type?: 'FLAT_VIEW' | 'TREE_VIEW';
36
+ type?: 'TREE_VIEW' | 'LIST_VIEW';
40
37
  showPageHeadings: true;
41
38
  services?: SideBarConfig;
42
39
  messages?: SideBarConfig;
@@ -6,14 +6,14 @@ import {
6
6
  } from "./chunk-WUCY3QHK.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-CTL6CH3C.js";
10
- import "./chunk-2VGR4HMJ.js";
9
+ } from "./chunk-3AWWP5JR.js";
10
+ import "./chunk-2TWZFRC5.js";
11
11
  import {
12
12
  catalogToAstro
13
13
  } from "./chunk-R2NILSWL.js";
14
14
  import {
15
15
  VERSION
16
- } from "./chunk-LMNJPHFP.js";
16
+ } from "./chunk-32CT66GO.js";
17
17
  import {
18
18
  isBackstagePluginEnabled
19
19
  } from "./chunk-XMDPVKIJ.js";
@@ -0,0 +1,14 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">
2
+ <!-- Background shape -->
3
+ <rect x="50" y="50" width="200" height="100" rx="20" fill="#4a86e8" />
4
+
5
+ <!-- Flow waves -->
6
+ <path d="M80 90 Q100 70, 120 90 Q140 110, 160 90 Q180 70, 200 90 Q220 110, 240 90"
7
+ fill="none" stroke="#ffffff" stroke-width="8" stroke-linecap="round" />
8
+
9
+ <!-- Shopping cart icon -->
10
+ <circle cx="220" cy="110" r="10" fill="#ffffff" />
11
+ <circle cx="180" cy="110" r="10" fill="#ffffff" />
12
+ <path d="M160 80 L170 110 L230 110 L240 80 Z" fill="none" stroke="#ffffff" stroke-width="3" />
13
+ <path d="M170 80 L245 80" fill="none" stroke="#ffffff" stroke-width="3" />
14
+ </svg>
@@ -125,14 +125,12 @@ export default function ServiceGrid({ services }: ServiceGridProps) {
125
125
  <div className="min-w-0 flex-1 max-w-lg">
126
126
  <div className="flex items-center gap-2">
127
127
  <h1 className="text-2xl font-bold leading-7 text-gray-900 sm:text-3xl sm:truncate">
128
- {urlParams?.domainId
129
- ? `Services in the ${urlParams.domainName} domain (${filteredAndSortedServices.length})`
130
- : 'All Services'}
128
+ {urlParams?.domainId ? `${urlParams.domainName} Architecture` : 'All Services'}
131
129
  </h1>
132
130
  </div>
133
131
  <p className="mt-2 text-sm text-gray-500">
134
132
  {urlParams?.domainId
135
- ? `Browse services in the ${urlParams.domainId} domain`
133
+ ? `Browse services and messages in the ${urlParams.domainId} domain`
136
134
  : 'Browse and discover services in your event-driven architecture'}
137
135
  </p>
138
136
  </div>
@@ -0,0 +1,46 @@
1
+ import React from 'react';
2
+ import { ChevronDownIcon } from '@heroicons/react/24/outline';
3
+
4
+ interface CollapsibleGroupProps {
5
+ isCollapsed: boolean;
6
+ onToggle: () => void;
7
+ title: React.ReactNode;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ }
11
+
12
+ const CollapsibleGroup: React.FC<CollapsibleGroupProps> = ({ isCollapsed, onToggle, title, children, className = '' }) => (
13
+ <div className={className}>
14
+ <div className="flex items-center">
15
+ <button
16
+ onClick={(e) => {
17
+ e.stopPropagation();
18
+ onToggle();
19
+ }}
20
+ className="p-1 hover:bg-gray-100 rounded-md"
21
+ >
22
+ <div className={`transition-transform duration-150 ${isCollapsed ? '' : 'rotate-180'}`}>
23
+ <ChevronDownIcon className="h-3 w-3 text-gray-500" />
24
+ </div>
25
+ </button>
26
+ {typeof title === 'string' ? (
27
+ <button
28
+ onClick={(e) => {
29
+ e.stopPropagation();
30
+ onToggle();
31
+ }}
32
+ className="flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md"
33
+ >
34
+ {title}
35
+ </button>
36
+ ) : (
37
+ title
38
+ )}
39
+ </div>
40
+ <div className={`overflow-hidden transition-[height] duration-150 ease-out ${isCollapsed ? 'h-0' : 'h-auto'}`}>
41
+ {children}
42
+ </div>
43
+ </div>
44
+ );
45
+
46
+ export default CollapsibleGroup;
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { getMessageColorByCollection, getMessageCollectionName } from '../index';
3
+ interface MessageListProps {
4
+ messages: any[];
5
+ decodedCurrentPath: string;
6
+ }
7
+
8
+ const MessageList: React.FC<MessageListProps> = ({ messages, decodedCurrentPath }) => (
9
+ <ul className="space-y-0.5 border-l border-gray-200/80 ml-[9px] pl-4">
10
+ {messages.map((message: any) => (
11
+ <li key={message.id} data-active={decodedCurrentPath === message.href}>
12
+ <a
13
+ href={message.href}
14
+ className={`flex items-center justify-between px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
15
+ decodedCurrentPath.includes(message.href) ? 'bg-purple-100 ' : 'hover:bg-purple-100'
16
+ }`}
17
+ >
18
+ <span className="truncate">{message.data.name}</span>
19
+ <span
20
+ className={`ml-2 text-[10px] flex items-center gap-1 font-medium px-2 uppercase py-0.5 rounded ${getMessageColorByCollection(message.collection)}`}
21
+ >
22
+ {getMessageCollectionName(message.collection)}
23
+ </span>
24
+ </a>
25
+ </li>
26
+ ))}
27
+ </ul>
28
+ );
29
+
30
+ export default MessageList;
@@ -0,0 +1,389 @@
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.5 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 = window.location.pathname;
143
+
144
+ useEffect(() => {
145
+ const timer = setTimeout(() => {
146
+ setDebouncedSearchTerm(searchTerm.toLowerCase());
147
+ }, DEBOUNCE_DELAY);
148
+
149
+ return () => clearTimeout(timer);
150
+ }, [searchTerm]);
151
+
152
+ // Filter data based on search term
153
+ const filteredData = useMemo(() => {
154
+ if (!debouncedSearchTerm) return data;
155
+
156
+ const filterItem = (item: { label: string }) => {
157
+ return item.label.toLowerCase().includes(debouncedSearchTerm);
158
+ };
159
+
160
+ const filterMessages = (messages: MessageItem[]) => {
161
+ return messages.filter((message) => message.data.name.toLowerCase().includes(debouncedSearchTerm));
162
+ };
163
+
164
+ return {
165
+ domains: data.domains?.filter(filterItem) || [],
166
+ services:
167
+ data.services
168
+ ?.map((service: ServiceItem) => ({
169
+ ...service,
170
+ sends: filterMessages(service.sends),
171
+ receives: filterMessages(service.receives),
172
+ isVisible:
173
+ filterItem(service) ||
174
+ service.sends.some((msg: MessageItem) => msg.data.name.toLowerCase().includes(debouncedSearchTerm)) ||
175
+ service.receives.some((msg: MessageItem) => msg.data.name.toLowerCase().includes(debouncedSearchTerm)),
176
+ }))
177
+ .filter((service: ServiceItem & { isVisible: boolean }) => service.isVisible) || [],
178
+ flows: data.flows?.filter(filterItem) || [],
179
+ messagesNotInService:
180
+ data.messagesNotInService?.filter((msg: MessageItem) => msg.label.toLowerCase().includes(debouncedSearchTerm)) || [],
181
+ };
182
+ }, [data, debouncedSearchTerm]);
183
+
184
+ // Auto-expand groups when searching
185
+ useEffect(() => {
186
+ if (debouncedSearchTerm) {
187
+ // Expand all groups when searching
188
+ const newCollapsedState = { ...collapsedGroups };
189
+ Object.keys(newCollapsedState).forEach((key) => {
190
+ newCollapsedState[key] = false;
191
+ });
192
+ setCollapsedGroups(newCollapsedState);
193
+ }
194
+ }, [debouncedSearchTerm]);
195
+
196
+ // Store collapsed groups in local storage
197
+ useEffect(() => {
198
+ if (typeof window !== 'undefined') {
199
+ window.localStorage.setItem(STORAGE_KEY, JSON.stringify(collapsedGroups));
200
+ }
201
+ }, [collapsedGroups]);
202
+
203
+ // If we find a data-active element, scroll to it on mount
204
+ useEffect(() => {
205
+ const activeElement = document.querySelector('[data-active="true"]');
206
+ if (activeElement) {
207
+ // Add y offset to the scroll position
208
+ activeElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
209
+ }
210
+ }, []);
211
+
212
+ const toggleGroupCollapse = useCallback((group: string) => {
213
+ setCollapsedGroups((prev) => ({
214
+ ...prev,
215
+ [group]: !prev[group],
216
+ }));
217
+ }, []);
218
+
219
+ const handleSearchChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
220
+ setSearchTerm(e.target.value);
221
+ }, []);
222
+
223
+ if (!isInitialized) return null;
224
+
225
+ const hasNoResults =
226
+ debouncedSearchTerm &&
227
+ !filteredData.domains?.length &&
228
+ !filteredData.services?.length &&
229
+ !filteredData.flows?.length &&
230
+ !filteredData.messagesNotInService?.length;
231
+
232
+ return (
233
+ <nav ref={navRef} className="space-y-4 text-gray-800 px-3 py-4">
234
+ <input
235
+ type="text"
236
+ value={searchTerm}
237
+ onChange={handleSearchChange}
238
+ placeholder="Quick search..."
239
+ className="w-full p-2 text-sm rounded-md border border-gray-200 h-[30px]"
240
+ />
241
+ <div className="space-y-2 divide-y divide-gray-200/80">
242
+ {hasNoResults ? (
243
+ <NoResultsFound searchTerm={debouncedSearchTerm} />
244
+ ) : (
245
+ <>
246
+ {/* Domains */}
247
+ {filteredData['domains'] && (
248
+ <div>
249
+ <ul className="space-y-2">
250
+ {filteredData['domains'].map((item: any) => (
251
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
252
+ <div className="flex items-center">
253
+ <button
254
+ onClick={(e) => {
255
+ e.stopPropagation();
256
+ toggleGroupCollapse(item.href);
257
+ }}
258
+ className="p-1 hover:bg-gray-100 rounded-md"
259
+ >
260
+ <div className={`transition-transform duration-150 ${collapsedGroups[item.href] ? '' : 'rotate-180'}`}>
261
+ <ChevronDownIcon className="h-3 w-3 text-gray-500" />
262
+ </div>
263
+ </button>
264
+ <button
265
+ onClick={(e) => {
266
+ e.stopPropagation();
267
+ toggleGroupCollapse(item.href);
268
+ }}
269
+ className={`flex-grow flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
270
+ decodedCurrentPath === item.href
271
+ }`}
272
+ >
273
+ <span className="truncate">{item.label}</span>
274
+ <span className="text-yellow-600 ml-2 text-[10px] font-medium bg-yellow-50 px-2 py-0.5 rounded">
275
+ DOMAIN
276
+ </span>
277
+ </button>
278
+ </div>
279
+ <div
280
+ className={`overflow-hidden transition-[height] duration-150 ease-out ${
281
+ collapsedGroups[item.href] ? 'h-0' : 'h-auto'
282
+ }`}
283
+ >
284
+ <div className="space-y-0.5 border-gray-200/80 border-l pl-4 ml-[9px] mt-1">
285
+ <a
286
+ href={`${item.href}`}
287
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
288
+ decodedCurrentPath === item.href ? 'bg-purple-100 ' : 'hover:bg-purple-100'
289
+ }`}
290
+ >
291
+ <span className="truncate">Overview</span>
292
+ </a>
293
+ <a
294
+ href={buildUrlWithParams('/architecture/docs/services', {
295
+ serviceIds: item.services.map((service: any) => service.data.id).join(','),
296
+ domainId: item.id,
297
+ domainName: item.name,
298
+ })}
299
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
300
+ window.location.href.includes(`domainId=${item.id}`) ? 'bg-purple-100 ' : 'hover:bg-purple-100'
301
+ }`}
302
+ >
303
+ <span className="truncate">Architecture</span>
304
+ </a>
305
+ <a
306
+ href={buildUrl(`/docs/domains/${item.id}/language`)}
307
+ className={`flex items-center px-2 py-1.5 text-xs text-gray-600 hover:bg-purple-100 rounded-md ${
308
+ decodedCurrentPath.includes(`/docs/domains/${item.id}/language`)
309
+ ? 'bg-purple-100 '
310
+ : 'hover:bg-purple-100'
311
+ }`}
312
+ >
313
+ <span className="truncate">Ubiquitous Language</span>
314
+ </a>
315
+ </div>
316
+ </div>
317
+ </li>
318
+ ))}
319
+ </ul>
320
+ </div>
321
+ )}
322
+
323
+ {filteredData['services'] && (
324
+ <div className="pt-4 pb-2">
325
+ <ul className="space-y-4">
326
+ {filteredData['services'].map((item: any) => (
327
+ <ServiceItem
328
+ key={item.href}
329
+ item={item}
330
+ decodedCurrentPath={decodedCurrentPath}
331
+ collapsedGroups={collapsedGroups}
332
+ toggleGroupCollapse={toggleGroupCollapse}
333
+ />
334
+ ))}
335
+ </ul>
336
+ </div>
337
+ )}
338
+
339
+ {filteredData['messagesNotInService'] && (
340
+ <div className="pt-4 pb-2">
341
+ <ul className="space-y-4">
342
+ {filteredData['messagesNotInService'].map((item: any) => (
343
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
344
+ <a
345
+ href={item.href}
346
+ className={`flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
347
+ decodedCurrentPath === item.href ? 'bg-purple-100 text-purple-900' : 'hover:bg-purple-100'
348
+ }`}
349
+ >
350
+ <span className="truncate">{item.label}</span>
351
+ <span
352
+ className={`ml-2 text-[10px] font-medium px-2 uppercase py-0.5 rounded ${getMessageColorByCollection(item.collection)}`}
353
+ >
354
+ {getMessageCollectionName(item.collection)}
355
+ </span>
356
+ </a>
357
+ </li>
358
+ ))}
359
+ </ul>
360
+ </div>
361
+ )}
362
+
363
+ {filteredData['flows'] && (
364
+ <div className="pt-4 pb-2">
365
+ <ul className="space-y-4">
366
+ {filteredData['flows'].map((item: any) => (
367
+ <li key={item.href} className="space-y-0" data-active={decodedCurrentPath === item.href}>
368
+ <a
369
+ href={item.href}
370
+ className={`flex items-center justify-between px-2 py-0.5 text-xs font-bold rounded-md ${
371
+ decodedCurrentPath === item.href ? 'bg-cyan-100 text-cyan-900' : 'hover:bg-purple-100'
372
+ }`}
373
+ >
374
+ <span className="truncate">{item.label}</span>
375
+ <span className="text-cyan-600 ml-2 text-[10px] font-medium bg-cyan-50 px-2 py-0.5 rounded">FLOW</span>
376
+ </a>
377
+ </li>
378
+ ))}
379
+ </ul>
380
+ </div>
381
+ )}
382
+ </>
383
+ )}
384
+ </div>
385
+ </nav>
386
+ );
387
+ };
388
+
389
+ export default React.memo(ListViewSideBar);