@eventcatalog/core 3.5.2 → 3.6.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/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-OKWCSRLE.js → chunk-2DSMO5BZ.js} +1 -1
- package/dist/{chunk-YTZSPYJN.js → chunk-O3LNFOFS.js} +1 -1
- package/dist/{chunk-YVX5C6L3.js → chunk-O7ZZX4CS.js} +1 -1
- package/dist/{chunk-WO3AKJVB.js → chunk-XTN3M6CM.js} +1 -1
- package/dist/{chunk-YOFNY2RC.js → chunk-YQ2LO4G6.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/src/components/EnvironmentDropdown.tsx +1 -1
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +23 -11
- package/eventcatalog/src/components/Search/SearchModal.tsx +17 -2
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +12 -6
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +25 -14
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +816 -0
- package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +161 -0
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +565 -0
- package/eventcatalog/src/components/Tables/Discover/index.ts +4 -0
- package/eventcatalog/src/components/Tables/columns/ContainersTableColumns.tsx +1 -1
- package/eventcatalog/src/components/Tables/columns/DomainTableColumns.tsx +1 -1
- package/eventcatalog/src/components/Tables/columns/FlowTableColumns.tsx +1 -1
- package/eventcatalog/src/components/Tables/columns/MessageTableColumns.tsx +1 -1
- package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +54 -64
- package/eventcatalog/src/components/Tables/columns/SharedColumns.tsx +15 -30
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +1 -1
- package/eventcatalog/src/pages/api/sidebar-data.json.ts +22 -0
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -1
- package/eventcatalog/src/pages/discover/[type]/index.astro +360 -41
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/state.ts +25 -22
- package/package.json +1 -1
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
2
|
+
import { QueueListIcon, RectangleGroupIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/outline';
|
|
3
|
+
import ServerIcon from '@heroicons/react/24/outline/ServerIcon';
|
|
4
|
+
import { MagnifyingGlassIcon } from '@heroicons/react/20/solid';
|
|
5
|
+
import { DatabaseIcon } from 'lucide-react';
|
|
6
|
+
import { getCommands } from '@utils/collections/commands';
|
|
7
|
+
import { getDomains, getDomainsForService } from '@utils/collections/domains';
|
|
8
|
+
import { getFlows } from '@utils/collections/flows';
|
|
9
|
+
import { getEvents } from '@utils/collections/events';
|
|
10
|
+
import { getServices } from '@utils/collections/services';
|
|
11
|
+
import { getQueries } from '@utils/collections/queries';
|
|
12
|
+
import { getContainers } from '@utils/collections/containers';
|
|
13
|
+
import { getUsers } from '@utils/collections/users';
|
|
14
|
+
import { getTeams } from '@utils/collections/teams';
|
|
15
|
+
import { buildUrl } from '@utils/url-builder';
|
|
16
|
+
import VerticalSideBarLayout from '@layouts/VerticalSideBarLayout.astro';
|
|
17
|
+
import { DiscoverTable, type DiscoverTableData, type CollectionType } from '@components/Tables/Discover';
|
|
18
|
+
import config from '@config';
|
|
5
19
|
import { Page } from './_index.data';
|
|
6
20
|
|
|
7
21
|
export const prerender = Page.prerender;
|
|
@@ -9,12 +23,165 @@ export const getStaticPaths = Page.getStaticPaths;
|
|
|
9
23
|
|
|
10
24
|
const { type, data } = await Page.getData(Astro);
|
|
11
25
|
|
|
12
|
-
|
|
26
|
+
// Fetch all collections for tabs
|
|
27
|
+
const events = await getEvents();
|
|
28
|
+
const queries = await getQueries();
|
|
29
|
+
const commands = await getCommands();
|
|
30
|
+
const services = await getServices();
|
|
31
|
+
const domains = await getDomains({ getAllVersions: false });
|
|
32
|
+
const flows = await getFlows();
|
|
33
|
+
const containers = await getContainers();
|
|
34
|
+
const users = await getUsers();
|
|
35
|
+
const teams = await getTeams();
|
|
13
36
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
37
|
+
// Create lookup maps for users and teams
|
|
38
|
+
const userMap = new Map(users.map((u) => [u.data.id, u]));
|
|
39
|
+
const teamMap = new Map(teams.map((t) => [t.data.id, t]));
|
|
40
|
+
|
|
41
|
+
// Type configuration for property options
|
|
42
|
+
const typeConfig: Record<
|
|
43
|
+
string,
|
|
44
|
+
{
|
|
45
|
+
label: string;
|
|
46
|
+
propertyOptions: Array<{ id: string; label: string }>;
|
|
47
|
+
}
|
|
48
|
+
> = {
|
|
49
|
+
events: {
|
|
50
|
+
label: 'Events',
|
|
51
|
+
propertyOptions: [
|
|
52
|
+
{ id: 'hasProducers', label: 'Has Producers' },
|
|
53
|
+
{ id: 'hasConsumers', label: 'Has Consumers' },
|
|
54
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
55
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
commands: {
|
|
59
|
+
label: 'Commands',
|
|
60
|
+
propertyOptions: [
|
|
61
|
+
{ id: 'hasProducers', label: 'Has Producers' },
|
|
62
|
+
{ id: 'hasConsumers', label: 'Has Consumers' },
|
|
63
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
64
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
queries: {
|
|
68
|
+
label: 'Queries',
|
|
69
|
+
propertyOptions: [
|
|
70
|
+
{ id: 'hasProducers', label: 'Has Producers' },
|
|
71
|
+
{ id: 'hasConsumers', label: 'Has Consumers' },
|
|
72
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
73
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
domains: {
|
|
77
|
+
label: 'Domains',
|
|
78
|
+
propertyOptions: [
|
|
79
|
+
{ id: 'hasServices', label: 'Has Services' },
|
|
80
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
81
|
+
{ id: 'isSubdomain', label: 'Is Subdomain' },
|
|
82
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
services: {
|
|
86
|
+
label: 'Services',
|
|
87
|
+
propertyOptions: [
|
|
88
|
+
{ id: 'hasSpecifications', label: 'Has Specifications' },
|
|
89
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
90
|
+
{ id: 'hasRepository', label: 'Has Repository' },
|
|
91
|
+
{ id: 'hasDataDependencies', label: 'Has Data Dependencies' },
|
|
92
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
flows: {
|
|
96
|
+
label: 'Flows',
|
|
97
|
+
propertyOptions: [
|
|
98
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
99
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
100
|
+
],
|
|
101
|
+
},
|
|
102
|
+
containers: {
|
|
103
|
+
label: 'Data',
|
|
104
|
+
propertyOptions: [
|
|
105
|
+
{ id: 'hasOwners', label: 'Has Owners' },
|
|
106
|
+
{ id: 'hasWriters', label: 'Has Writers' },
|
|
107
|
+
{ id: 'hasReaders', label: 'Has Readers' },
|
|
108
|
+
{ id: 'isDeprecated', label: 'Is Deprecated' },
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const currentTypeConfig = typeConfig[type] || typeConfig.events;
|
|
114
|
+
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
const tableConfiguration = config[type as keyof typeof config]?.tableConfiguration ?? { columns: {} };
|
|
17
117
|
|
|
118
|
+
const tabs = [
|
|
119
|
+
{
|
|
120
|
+
label: `Domains (${domains.length})`,
|
|
121
|
+
href: buildUrl('/discover/domains'),
|
|
122
|
+
isActive: type === 'domains',
|
|
123
|
+
icon: RectangleGroupIcon,
|
|
124
|
+
activeColor: 'yellow',
|
|
125
|
+
enabled: domains.length > 0,
|
|
126
|
+
visible: domains.length > 0,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
label: `Services (${services.length})`,
|
|
130
|
+
href: buildUrl('/discover/services'),
|
|
131
|
+
isActive: type === 'services',
|
|
132
|
+
icon: ServerIcon,
|
|
133
|
+
activeColor: 'pink',
|
|
134
|
+
enabled: services.length > 0,
|
|
135
|
+
visible: services.length > 0,
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
label: `Data (${containers.length})`,
|
|
139
|
+
href: buildUrl('/discover/containers'),
|
|
140
|
+
isActive: type === 'containers',
|
|
141
|
+
icon: DatabaseIcon,
|
|
142
|
+
activeColor: 'blue',
|
|
143
|
+
enabled: containers.length > 0,
|
|
144
|
+
visible: containers.length > 0,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
label: `Events (${events.length})`,
|
|
148
|
+
href: buildUrl('/discover/events'),
|
|
149
|
+
isActive: type === 'events',
|
|
150
|
+
icon: BoltIcon,
|
|
151
|
+
activeColor: 'orange',
|
|
152
|
+
enabled: events.length > 0,
|
|
153
|
+
visible: events.length > 0,
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: `Queries (${queries.length})`,
|
|
157
|
+
href: buildUrl('/discover/queries'),
|
|
158
|
+
isActive: type === 'queries',
|
|
159
|
+
icon: MagnifyingGlassIcon,
|
|
160
|
+
activeColor: 'green',
|
|
161
|
+
enabled: queries.length > 0,
|
|
162
|
+
visible: queries.length > 0,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
label: `Commands (${commands.length})`,
|
|
166
|
+
href: buildUrl('/discover/commands'),
|
|
167
|
+
isActive: type === 'commands',
|
|
168
|
+
icon: ChatBubbleLeftIcon,
|
|
169
|
+
activeColor: 'blue',
|
|
170
|
+
enabled: commands.length > 0,
|
|
171
|
+
visible: commands.length > 0,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
label: `Flows (${flows.length})`,
|
|
175
|
+
href: buildUrl('/discover/flows'),
|
|
176
|
+
isActive: type === 'flows',
|
|
177
|
+
icon: QueueListIcon,
|
|
178
|
+
activeColor: 'teal',
|
|
179
|
+
enabled: flows.length > 0,
|
|
180
|
+
visible: flows.length > 0,
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
// Map data to match the expected structure for the table
|
|
18
185
|
function mapToItem(i: any) {
|
|
19
186
|
return {
|
|
20
187
|
collection: i.collection,
|
|
@@ -25,39 +192,191 @@ function mapToItem(i: any) {
|
|
|
25
192
|
},
|
|
26
193
|
};
|
|
27
194
|
}
|
|
195
|
+
|
|
196
|
+
// Helper to map owner references with type detection
|
|
197
|
+
function mapOwner(o: any) {
|
|
198
|
+
if (!o) return null;
|
|
199
|
+
const id = typeof o === 'string' ? o : o.data?.id || o.id || o;
|
|
200
|
+
|
|
201
|
+
// Look up in users first, then teams
|
|
202
|
+
const user = userMap.get(id);
|
|
203
|
+
if (user) {
|
|
204
|
+
return { id, name: user.data.name || id, type: 'user' as const };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const team = teamMap.get(id);
|
|
208
|
+
if (team) {
|
|
209
|
+
return { id, name: team.data.name || id, type: 'team' as const };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Fallback if not found in either
|
|
213
|
+
const name = typeof o === 'string' ? o : o.data?.name || o.name || id;
|
|
214
|
+
return { id, name, type: 'user' as const };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Helper to check if service has specifications
|
|
218
|
+
function hasSpecifications(service: any): boolean {
|
|
219
|
+
const specs = service.data?.specifications;
|
|
220
|
+
if (!specs) return false;
|
|
221
|
+
if (Array.isArray(specs)) return specs.length > 0;
|
|
222
|
+
return !!(specs.openapiPath || specs.asyncapiPath || specs.graphqlPath);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Build a Set of subdomain IDs (domains that are nested within other domains)
|
|
226
|
+
const allSubdomainIds = new Set(
|
|
227
|
+
domains.flatMap((d: any) => (d.data?.domains || []).map((sd: any) => sd.data?.id || sd.id)).filter(Boolean)
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// For services, enrich with domain information
|
|
231
|
+
const enrichedData =
|
|
232
|
+
type === 'services'
|
|
233
|
+
? await Promise.all(
|
|
234
|
+
data.map(async (service: any) => {
|
|
235
|
+
const serviceDomains = await getDomainsForService(service);
|
|
236
|
+
return {
|
|
237
|
+
...service,
|
|
238
|
+
enrichedDomains: serviceDomains.map((d: any) => ({
|
|
239
|
+
id: d.data.id,
|
|
240
|
+
name: d.data.name,
|
|
241
|
+
version: d.data.version,
|
|
242
|
+
})),
|
|
243
|
+
};
|
|
244
|
+
})
|
|
245
|
+
)
|
|
246
|
+
: data;
|
|
247
|
+
|
|
248
|
+
const tableData = enrichedData.map((d: any) => ({
|
|
249
|
+
collection: d.collection,
|
|
250
|
+
owners: (d.data?.owners || []).map(mapOwner).filter(Boolean),
|
|
251
|
+
hasOwners: (d.data?.owners || []).length > 0,
|
|
252
|
+
hasServices: type === 'domains' ? (d.data?.services || []).length > 0 : false,
|
|
253
|
+
isSubdomain: type === 'domains' ? allSubdomainIds.has(d.data.id) : false,
|
|
254
|
+
// Service-specific properties
|
|
255
|
+
domains: type === 'services' ? d.enrichedDomains : undefined,
|
|
256
|
+
hasSpecifications: type === 'services' ? hasSpecifications(d) : false,
|
|
257
|
+
hasRepository: type === 'services' ? !!d.data?.repository?.url : false,
|
|
258
|
+
hasDataDependencies: type === 'services' ? (d.data?.writesTo || []).length > 0 || (d.data?.readsFrom || []).length > 0 : false,
|
|
259
|
+
isDeprecated: d.data?.deprecated === true || (typeof d.data?.deprecated === 'object' && d.data?.deprecated !== null),
|
|
260
|
+
data: {
|
|
261
|
+
id: d.data.id,
|
|
262
|
+
name: d.data.name,
|
|
263
|
+
summary: d.data?.summary,
|
|
264
|
+
version: d.data.version,
|
|
265
|
+
latestVersion: d.data?.latestVersion,
|
|
266
|
+
draft: d.data?.draft,
|
|
267
|
+
badges: d.data?.badges,
|
|
268
|
+
producers: d.data?.producers?.map(mapToItem) ?? [],
|
|
269
|
+
consumers: d.data?.consumers?.map(mapToItem) ?? [],
|
|
270
|
+
receives: d.data?.receives?.map(mapToItem) ?? [],
|
|
271
|
+
sends: d.data?.sends?.map(mapToItem) ?? [],
|
|
272
|
+
services: d.data?.services?.map(mapToItem) ?? [],
|
|
273
|
+
servicesThatWriteToContainer: d.data?.servicesThatWriteToContainer?.map(mapToItem) ?? [],
|
|
274
|
+
servicesThatReadFromContainer: d.data?.servicesThatReadFromContainer?.map(mapToItem) ?? [],
|
|
275
|
+
},
|
|
276
|
+
}));
|
|
277
|
+
|
|
278
|
+
// Get unique owners from all items
|
|
279
|
+
const uniqueOwners = Array.from(new Map(tableData.flatMap((d: any) => d.owners || []).map((o: any) => [o.id, o])).values()).sort(
|
|
280
|
+
(a: any, b: any) => a.name.localeCompare(b.name)
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
// Get unique producers (services) for message types
|
|
284
|
+
// Check for duplicate names and add version if needed
|
|
285
|
+
const servicesByName = new Map<string, typeof services>();
|
|
286
|
+
services.forEach((s) => {
|
|
287
|
+
const name = s.data.name;
|
|
288
|
+
if (!servicesByName.has(name)) servicesByName.set(name, []);
|
|
289
|
+
servicesByName.get(name)!.push(s);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
const uniqueProducers = services
|
|
293
|
+
.map((s) => {
|
|
294
|
+
const hasDuplicateName = (servicesByName.get(s.data.name)?.length ?? 0) > 1;
|
|
295
|
+
const isLatest = s.data.version === s.data.latestVersion;
|
|
296
|
+
const versionLabel = isLatest ? 'latest' : `v${s.data.version}`;
|
|
297
|
+
return {
|
|
298
|
+
id: s.data.id,
|
|
299
|
+
name: hasDuplicateName ? `${s.data.name} (${versionLabel})` : s.data.name,
|
|
300
|
+
};
|
|
301
|
+
})
|
|
302
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
303
|
+
|
|
304
|
+
// Show producers/consumers filter only for events, commands, queries
|
|
305
|
+
const showProducersFilter = ['events', 'commands', 'queries'].includes(type);
|
|
306
|
+
const showConsumersFilter = ['events', 'commands', 'queries'].includes(type);
|
|
307
|
+
|
|
308
|
+
// Consumers are the same services list
|
|
309
|
+
const uniqueConsumers = uniqueProducers;
|
|
310
|
+
|
|
311
|
+
// Get unique domains for the services filter
|
|
312
|
+
const uniqueDomains = domains.map((d) => ({
|
|
313
|
+
id: d.data.id,
|
|
314
|
+
name: d.data.name,
|
|
315
|
+
version: d.data.version,
|
|
316
|
+
}));
|
|
317
|
+
|
|
318
|
+
// Show domains filter only for services
|
|
319
|
+
const showDomainsFilter = type === 'services';
|
|
320
|
+
|
|
321
|
+
const title = `${currentTypeConfig.label} (${data.length})`;
|
|
28
322
|
---
|
|
29
323
|
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
324
|
+
<VerticalSideBarLayout title={`Explore | ${title}`} showNestedSideBar={false}>
|
|
325
|
+
<main class="ml-0 bg-[rgb(var(--ec-page-bg))] min-h-content">
|
|
326
|
+
<div id="discover-collection-tabs">
|
|
327
|
+
<div class="hidden sm:block">
|
|
328
|
+
<div class="border-b border-[rgb(var(--ec-page-border))]">
|
|
329
|
+
<nav class="flex space-x-8 -mb-0.5 pl-6" aria-label="Tabs">
|
|
330
|
+
{
|
|
331
|
+
tabs
|
|
332
|
+
.filter((tab) => tab.visible)
|
|
333
|
+
.map((tab) => (
|
|
334
|
+
<a
|
|
335
|
+
href={tab.href}
|
|
336
|
+
class:list={[
|
|
337
|
+
'group inline-flex items-center py-4 px-1 text-sm font-light text-[rgb(var(--ec-page-text))]',
|
|
338
|
+
tab.isActive && 'border-b-[2px] border-[rgb(var(--ec-accent))] text-[rgb(var(--ec-accent))]',
|
|
339
|
+
!tab.isActive && 'opacity-70 hover:opacity-100',
|
|
340
|
+
!tab.enabled && 'disabled',
|
|
341
|
+
]}
|
|
342
|
+
aria-current="page"
|
|
343
|
+
>
|
|
344
|
+
<tab.icon
|
|
345
|
+
className={`w-6 h-6 -ml-0.5 mr-2 ${tab.isActive ? 'text-[rgb(var(--ec-accent))]' : 'text-[rgb(var(--ec-icon-color))]'}`}
|
|
346
|
+
/>
|
|
347
|
+
<span>{tab.label}</span>
|
|
348
|
+
</a>
|
|
349
|
+
))
|
|
350
|
+
}
|
|
351
|
+
</nav>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<div class="py-4 px-6 md:pr-10">
|
|
357
|
+
<DiscoverTable
|
|
358
|
+
data={tableData as DiscoverTableData[]}
|
|
359
|
+
collectionType={type as CollectionType}
|
|
360
|
+
collectionLabel={currentTypeConfig.label}
|
|
361
|
+
domains={uniqueDomains}
|
|
362
|
+
owners={uniqueOwners as Array<{ id: string; name: string; type?: 'user' | 'team' }>}
|
|
363
|
+
producers={uniqueProducers}
|
|
364
|
+
consumers={uniqueConsumers}
|
|
365
|
+
propertyOptions={currentTypeConfig.propertyOptions}
|
|
366
|
+
tableConfiguration={tableConfiguration}
|
|
367
|
+
showDomainsFilter={showDomainsFilter}
|
|
368
|
+
showProducersFilter={showProducersFilter}
|
|
369
|
+
showConsumersFilter={showConsumersFilter}
|
|
370
|
+
client:only="react"
|
|
371
|
+
/>
|
|
372
|
+
</div>
|
|
373
|
+
</main>
|
|
374
|
+
</VerticalSideBarLayout>
|
|
375
|
+
|
|
376
|
+
<style>
|
|
377
|
+
a.disabled {
|
|
378
|
+
pointer-events: none;
|
|
379
|
+
cursor: default;
|
|
380
|
+
opacity: 0.25;
|
|
381
|
+
}
|
|
382
|
+
</style>
|
|
@@ -31,7 +31,7 @@ export type NavNode = {
|
|
|
31
31
|
*/
|
|
32
32
|
export type NavigationData = {
|
|
33
33
|
roots: ChildRef[]; // What to show at top level
|
|
34
|
-
nodes: Record<string, NavNode>; // Flat map of
|
|
34
|
+
nodes: Record<string, NavNode | string>; // Flat map of nodes by key, strings are references to other keys (e.g., unversioned aliases)
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
export const uniqueBy = <T>(array: T[], key: keyof T): T[] => {
|
|
@@ -115,48 +115,55 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
115
115
|
|
|
116
116
|
const domainNodes = domainsWithOwners.reduce(
|
|
117
117
|
(acc, { domain, owners }) => {
|
|
118
|
-
|
|
118
|
+
const versionedKey = `domain:${domain.data.id}:${domain.data.version}`;
|
|
119
|
+
acc[versionedKey] = buildDomainNode(domain, owners, context);
|
|
119
120
|
if (domain.data.latestVersion === domain.data.version) {
|
|
120
|
-
|
|
121
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
122
|
+
acc[`domain:${domain.data.id}`] = versionedKey;
|
|
121
123
|
}
|
|
122
124
|
return acc;
|
|
123
125
|
},
|
|
124
|
-
{} as Record<string, NavNode>
|
|
126
|
+
{} as Record<string, NavNode | string>
|
|
125
127
|
);
|
|
126
128
|
|
|
127
129
|
const serviceNodes = servicesWithOwners.reduce(
|
|
128
130
|
(acc, { service, owners }) => {
|
|
129
|
-
|
|
131
|
+
const versionedKey = `service:${service.data.id}:${service.data.version}`;
|
|
132
|
+
acc[versionedKey] = buildServiceNode(service, owners, context);
|
|
130
133
|
if (service.data.latestVersion === service.data.version) {
|
|
131
|
-
|
|
134
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
135
|
+
acc[`service:${service.data.id}`] = versionedKey;
|
|
132
136
|
}
|
|
133
137
|
return acc;
|
|
134
138
|
},
|
|
135
|
-
{} as Record<string, NavNode>
|
|
139
|
+
{} as Record<string, NavNode | string>
|
|
136
140
|
);
|
|
137
141
|
|
|
138
142
|
const messageNodes = messagesWithOwners.reduce(
|
|
139
143
|
(acc, { message, owners }) => {
|
|
140
144
|
const type = pluralizeMessageType(message as any);
|
|
141
|
-
|
|
142
|
-
acc[
|
|
145
|
+
const versionedKey = `${type}:${message.data.id}:${message.data.version}`;
|
|
146
|
+
acc[versionedKey] = buildMessageNode(message, owners, context);
|
|
143
147
|
if (message.data.latestVersion === message.data.version) {
|
|
144
|
-
|
|
148
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
149
|
+
acc[`${type}:${message.data.id}`] = versionedKey;
|
|
145
150
|
}
|
|
146
151
|
return acc;
|
|
147
152
|
},
|
|
148
|
-
{} as Record<string, NavNode>
|
|
153
|
+
{} as Record<string, NavNode | string>
|
|
149
154
|
);
|
|
150
155
|
|
|
151
156
|
const containerNodes = containerWithOwners.reduce(
|
|
152
157
|
(acc, { container, owners }) => {
|
|
153
|
-
|
|
158
|
+
const versionedKey = `container:${container.data.id}:${container.data.version}`;
|
|
159
|
+
acc[versionedKey] = buildContainerNode(container, owners, context);
|
|
154
160
|
if (container.data.latestVersion === container.data.version) {
|
|
155
|
-
|
|
161
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
162
|
+
acc[`container:${container.data.id}`] = versionedKey;
|
|
156
163
|
}
|
|
157
164
|
return acc;
|
|
158
165
|
},
|
|
159
|
-
{} as Record<string, NavNode>
|
|
166
|
+
{} as Record<string, NavNode | string>
|
|
160
167
|
);
|
|
161
168
|
|
|
162
169
|
const designNodes = designs.reduce(
|
|
@@ -186,7 +193,8 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
186
193
|
|
|
187
194
|
const channelNodes = channels.reduce(
|
|
188
195
|
(acc, channel) => {
|
|
189
|
-
|
|
196
|
+
const versionedKey = `channel:${channel.data.id}:${channel.data.version}`;
|
|
197
|
+
acc[versionedKey] = {
|
|
190
198
|
type: 'item',
|
|
191
199
|
title: channel.data.name,
|
|
192
200
|
badge: 'Channel',
|
|
@@ -195,17 +203,12 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
195
203
|
};
|
|
196
204
|
|
|
197
205
|
if (channel.data.latestVersion === channel.data.version) {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
title: channel.data.name,
|
|
201
|
-
badge: 'Channel',
|
|
202
|
-
summary: channel.data.summary,
|
|
203
|
-
href: buildUrl(`/docs/${channel.collection}/${channel.data.id}/${channel.data.version}`),
|
|
204
|
-
};
|
|
206
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
207
|
+
acc[`channel:${channel.data.id}`] = versionedKey;
|
|
205
208
|
}
|
|
206
209
|
return acc;
|
|
207
210
|
},
|
|
208
|
-
{} as Record<string, NavNode>
|
|
211
|
+
{} as Record<string, NavNode | string>
|
|
209
212
|
);
|
|
210
213
|
|
|
211
214
|
const teamNodes = teams.reduce(
|