@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.
- package/README.md +1 -26
- 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-NK6OYMRD.js → chunk-JB4YT5JY.js} +1 -1
- package/dist/{chunk-BMDTX5IN.js → chunk-TQ4HZREX.js} +1 -1
- package/dist/{chunk-IJRFYF4B.js → chunk-X4W4YC3U.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -21
- package/dist/eventcatalog.config.d.cts +10 -0
- package/dist/eventcatalog.config.d.ts +10 -0
- package/dist/eventcatalog.js +3 -20
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +19 -1
- package/eventcatalog/src/components/FavoriteButton.tsx +54 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +386 -362
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +166 -518
- package/eventcatalog/src/components/Header.astro +48 -23
- package/eventcatalog/src/components/Lists/VersionList.astro +2 -2
- package/eventcatalog/src/components/MDX/Design/Design.astro +4 -1
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -1
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +3 -3
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +8 -2
- package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +37 -0
- package/eventcatalog/src/components/Search/Search.astro +48 -28
- package/eventcatalog/src/components/Search/SearchModal.tsx +393 -702
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +298 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/container.ts +66 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/domain.ts +101 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/flow.ts +29 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/message.ts +84 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/service.ts +147 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/builders/shared.ts +146 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +1073 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/sidebar-builder.ts +365 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +90 -0
- package/eventcatalog/src/components/SideNav/SideNav.astro +18 -28
- package/eventcatalog/src/content.config.ts +2 -0
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +10 -4
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +3 -3
- package/eventcatalog/src/layouts/DirectoryLayout.astro +2 -2
- package/eventcatalog/src/layouts/DiscoverLayout.astro +3 -3
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +85 -63
- package/eventcatalog/src/layouts/VisualiserLayout.astro +3 -3
- package/eventcatalog/src/pages/_index.astro +530 -110
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +64 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +29 -0
- package/eventcatalog/src/pages/directory/[type]/_index.data.ts +4 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +3 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +362 -190
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +4 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +1 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +3 -27
- package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +2 -2
- package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +2 -2
- package/eventcatalog/src/pages/index.astro +14 -5
- package/eventcatalog/src/pages/nav-index.json.ts +30 -0
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +77 -0
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +90 -0
- package/eventcatalog/src/pages/schemas/{index.astro → explorer/index.astro} +3 -3
- package/eventcatalog/src/pages/studio.astro +3 -3
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +4 -3
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +2 -2
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +4 -3
- package/eventcatalog/src/stores/favorites-store.ts +83 -0
- package/eventcatalog/src/stores/sidebar-store.ts +8 -0
- package/eventcatalog/src/utils/collections/changelogs.ts +7 -4
- package/eventcatalog/src/utils/{channels.ts → collections/channels.ts} +81 -31
- package/eventcatalog/src/utils/collections/commands.ts +134 -0
- package/eventcatalog/src/utils/collections/containers.ts +44 -33
- package/eventcatalog/src/utils/collections/domains.ts +204 -62
- package/eventcatalog/src/utils/{entities.ts → collections/entities.ts} +44 -24
- package/eventcatalog/src/utils/collections/events.ts +136 -0
- package/eventcatalog/src/utils/collections/flows.ts +59 -25
- package/eventcatalog/src/utils/{messages.ts → collections/messages.ts} +13 -4
- package/eventcatalog/src/utils/{queries.ts → collections/queries.ts} +49 -28
- package/eventcatalog/src/utils/collections/services.ts +100 -68
- package/eventcatalog/src/utils/collections/teams.ts +94 -0
- package/eventcatalog/src/utils/collections/users.ts +122 -0
- package/eventcatalog/src/utils/collections/util.ts +57 -1
- package/eventcatalog/src/utils/feature.ts +3 -1
- package/eventcatalog/src/utils/{collections/file-diffs.ts → file-diffs.ts} +1 -1
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +2 -0
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +16 -6
- package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +14 -10
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +36 -64
- package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +23 -19
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +36 -49
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +22 -18
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +4 -4
- package/eventcatalog/tailwind.config.mjs +14 -0
- package/eventcatalog/tsconfig.json +2 -1
- package/package.json +7 -4
- package/eventcatalog/public/logo_old.png +0 -0
- package/eventcatalog/src/components/DiscoverInsight.astro +0 -61
- package/eventcatalog/src/components/Grids/ServiceGrid.tsx +0 -534
- package/eventcatalog/src/components/Lists/CustomSideBarSectionList.astro +0 -55
- package/eventcatalog/src/components/Lists/ProtocolList.tsx +0 -74
- package/eventcatalog/src/components/Lists/RepositoryList.astro +0 -37
- package/eventcatalog/src/components/Lists/SpecificationsList.astro +0 -67
- package/eventcatalog/src/components/SideBars/ChannelSideBar.astro +0 -204
- package/eventcatalog/src/components/SideBars/ContainerSideBar.astro +0 -180
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +0 -273
- package/eventcatalog/src/components/SideBars/EntitySideBar.astro +0 -139
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +0 -128
- package/eventcatalog/src/components/SideBars/MessageSideBar.astro +0 -248
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +0 -294
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/CollapsibleGroup.tsx +0 -46
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/MessageList.tsx +0 -78
- package/eventcatalog/src/components/SideNav/ListViewSideBar/components/SpecificationList.tsx +0 -83
- package/eventcatalog/src/components/SideNav/ListViewSideBar/index.tsx +0 -1250
- package/eventcatalog/src/components/SideNav/ListViewSideBar/types.ts +0 -91
- package/eventcatalog/src/components/SideNav/ListViewSideBar/utils.ts +0 -201
- package/eventcatalog/src/components/SideNav/TreeView/getTreeView.ts +0 -190
- package/eventcatalog/src/components/SideNav/TreeView/index.tsx +0 -94
- package/eventcatalog/src/components/TreeView/index.tsx +0 -328
- package/eventcatalog/src/components/TreeView/styles.module.css +0 -264
- package/eventcatalog/src/components/TreeView/useSlots.ts +0 -95
- package/eventcatalog/src/pages/architecture/[type]/index.astro +0 -14
- package/eventcatalog/src/pages/architecture/architecture.astro +0 -101
- package/eventcatalog/src/pages/architecture/docs/[type]/index.astro +0 -14
- package/eventcatalog/src/utils/commands.ts +0 -112
- package/eventcatalog/src/utils/events.ts +0 -108
- package/eventcatalog/src/utils/generators/index.ts +0 -10
- package/eventcatalog/src/utils/teams.ts +0 -72
- 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
|
+
};
|