@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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-2VGR4HMJ.js → chunk-2TWZFRC5.js} +1 -1
- package/dist/{chunk-LMNJPHFP.js → chunk-32CT66GO.js} +1 -1
- package/dist/{chunk-CTL6CH3C.js → chunk-3AWWP5JR.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.config.d.cts +1 -4
- package/dist/eventcatalog.config.d.ts +1 -4
- package/dist/eventcatalog.js +3 -3
- package/eventcatalog/public/logo.svg +14 -0
- package/eventcatalog/src/components/Grids/ServiceGrid.tsx +2 -4
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +46 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +30 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +389 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +48 -0
- package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +103 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +8 -7
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -7
- package/eventcatalog/src/pages/architecture/[type]/index.astro +3 -77
- package/eventcatalog/src/pages/architecture/architecture.astro +81 -0
- package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +14 -0
- package/eventcatalog/src/pages/index.astro +1 -1
- package/package.json +1 -1
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/getCatalogResources.ts +0 -65
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/index.tsx +0 -138
- package/eventcatalog/src/components/SideNav/CatalogResourcesSideBar/styles.css +0 -8
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
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
|
package/dist/constants.cjs
CHANGED
package/dist/constants.js
CHANGED
package/dist/eventcatalog.cjs
CHANGED
|
@@ -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;
|
package/dist/eventcatalog.js
CHANGED
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
} from "./chunk-WUCY3QHK.js";
|
|
7
7
|
import {
|
|
8
8
|
log_build_default
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
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-
|
|
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);
|