@eventcatalog/core 2.31.4 → 2.32.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-C3M26NRD.js → chunk-EIEK445B.js} +1 -1
- package/dist/{chunk-W5HUNIMM.js → chunk-NPZQE3LM.js} +1 -1
- package/dist/{chunk-H5QIDJHP.js → chunk-YXHR3YSA.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 +3 -3
- package/eventcatalog/src/components/Lists/CustomSideBarSectionList.astro +67 -0
- package/eventcatalog/src/components/MDX/MessageTable/MessageTable.client.tsx +2 -2
- package/eventcatalog/src/components/MDX/ResourceGroupTable/ResourceGroupTable.astro +126 -0
- package/eventcatalog/src/components/MDX/ResourceGroupTable/ResourceGroupTable.client.tsx +408 -0
- package/eventcatalog/src/components/MDX/components.tsx +2 -0
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +8 -0
- package/eventcatalog/src/components/SideBars/FlowSideBar.astro +8 -1
- package/eventcatalog/src/components/SideBars/MessageSideBar.astro +8 -0
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +8 -1
- package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +1 -1
- package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +4 -6
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +0 -15
- package/eventcatalog/src/content.config.ts +17 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +26 -96
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/index.tsx +19 -16
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/types.ts +1 -0
- package/eventcatalog/src/enterprise/custom-documentation/pages/{index.astro → docs/custom/index.astro} +10 -5
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -3
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +4 -4
- package/eventcatalog/src/utils/collections/icons.ts +29 -0
- package/eventcatalog/src/utils/collections/services.ts +4 -4
- package/package.json +1 -1
- package/eventcatalog/src/components/SideNav/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -11
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NestedItem.tsx +0 -183
- package/eventcatalog/src/components/SideNav/CustomDocsNav/components/NoResultsFound.tsx +0 -21
- package/eventcatalog/src/components/SideNav/CustomDocsNav/index.tsx +0 -250
- package/eventcatalog/src/components/SideNav/CustomDocsNav/types.ts +0 -29
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { getColorAndIconForCollection } from '@utils/collections/icons';
|
|
2
|
+
import { buildUrl } from '@utils/url-builder';
|
|
3
|
+
import { useState, useMemo, useCallback, memo } from 'react';
|
|
4
|
+
|
|
5
|
+
type Resource = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
collection: string;
|
|
10
|
+
type: string;
|
|
11
|
+
summary?: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
owners?: any[];
|
|
14
|
+
tags?: string[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type ResourceGroupTableProps = {
|
|
18
|
+
resources: Resource[];
|
|
19
|
+
limit?: number;
|
|
20
|
+
showTags?: boolean;
|
|
21
|
+
showOwners?: boolean;
|
|
22
|
+
title: string;
|
|
23
|
+
subtitle: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type ResourceType = 'service' | 'event' | 'query' | 'command' | 'domain' | 'flow' | 'channel' | 'user' | 'team' | null;
|
|
28
|
+
|
|
29
|
+
const ResourceRow = memo(
|
|
30
|
+
({ resource, showTags, showOwners }: { resource: Resource; showTags?: boolean; showOwners?: boolean }) => {
|
|
31
|
+
const { color, Icon } = getColorAndIconForCollection(resource.collection);
|
|
32
|
+
const url = buildUrl(`/docs/${resource.collection}/${resource.id}/${resource.version}`);
|
|
33
|
+
let type = resource.collection.slice(0, -1);
|
|
34
|
+
type = type === 'querie' ? 'query' : type;
|
|
35
|
+
|
|
36
|
+
const tags = resource.tags || [];
|
|
37
|
+
const owners = resource.owners || [];
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<tr className="group hover:bg-gray-100">
|
|
41
|
+
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 relative">
|
|
42
|
+
<a href={url} className="absolute inset-0 z-10" aria-label={`View details for ${resource.name}`} />
|
|
43
|
+
<div className="flex items-center gap-2 relative">
|
|
44
|
+
<Icon className={`h-5 w-5 text-${color}-500`} />
|
|
45
|
+
<span className="group-hover:text-blue-600 break-all">{resource.name}</span>
|
|
46
|
+
</div>
|
|
47
|
+
</td>
|
|
48
|
+
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500 relative">
|
|
49
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
50
|
+
<span>v{resource.version}</span>
|
|
51
|
+
</td>
|
|
52
|
+
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500 relative">
|
|
53
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
54
|
+
<span>{type}</span>
|
|
55
|
+
</td>
|
|
56
|
+
<td className="px-3 py-4 text-sm text-gray-500 relative">
|
|
57
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
58
|
+
<span className="line-clamp-2 break-words">{resource.summary || resource.description || '-'}</span>
|
|
59
|
+
</td>
|
|
60
|
+
{showTags && (
|
|
61
|
+
<td className="px-3 py-4 text-sm text-gray-500 relative">
|
|
62
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
63
|
+
<div className="flex flex-wrap gap-1">
|
|
64
|
+
{tags.length > 0
|
|
65
|
+
? tags.map((tag, index) => (
|
|
66
|
+
<span
|
|
67
|
+
key={`${tag}-${index}`}
|
|
68
|
+
className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
|
|
69
|
+
>
|
|
70
|
+
{tag}
|
|
71
|
+
</span>
|
|
72
|
+
))
|
|
73
|
+
: '-'}
|
|
74
|
+
</div>
|
|
75
|
+
</td>
|
|
76
|
+
)}
|
|
77
|
+
{showOwners && (
|
|
78
|
+
<td className="px-3 py-4 text-sm text-gray-500 relative">
|
|
79
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
80
|
+
<div className="flex flex-wrap gap-1">
|
|
81
|
+
{owners.length > 0
|
|
82
|
+
? owners.map((owner, index) => (
|
|
83
|
+
<span
|
|
84
|
+
key={`${owner.id || owner.name}-${index}`}
|
|
85
|
+
className="inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10"
|
|
86
|
+
>
|
|
87
|
+
{owner.name || owner.id}
|
|
88
|
+
</span>
|
|
89
|
+
))
|
|
90
|
+
: '-'}
|
|
91
|
+
</div>
|
|
92
|
+
</td>
|
|
93
|
+
)}
|
|
94
|
+
</tr>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const FilterButton = memo(
|
|
100
|
+
({
|
|
101
|
+
type,
|
|
102
|
+
label,
|
|
103
|
+
typeFilter,
|
|
104
|
+
setTypeFilter,
|
|
105
|
+
setCurrentPage,
|
|
106
|
+
count,
|
|
107
|
+
}: {
|
|
108
|
+
type: ResourceType;
|
|
109
|
+
label: string;
|
|
110
|
+
typeFilter: ResourceType;
|
|
111
|
+
setTypeFilter: (type: ResourceType) => void;
|
|
112
|
+
setCurrentPage: (page: number) => void;
|
|
113
|
+
count: number;
|
|
114
|
+
}) => (
|
|
115
|
+
<button
|
|
116
|
+
onClick={() => {
|
|
117
|
+
setTypeFilter(typeFilter === type ? null : type);
|
|
118
|
+
setCurrentPage(1);
|
|
119
|
+
}}
|
|
120
|
+
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
|
121
|
+
typeFilter === type
|
|
122
|
+
? 'bg-black text-white border border-gray-200 hover:bg-gray-900'
|
|
123
|
+
: 'bg-white text-black border border-gray-200 hover:bg-gray-100'
|
|
124
|
+
}`}
|
|
125
|
+
>
|
|
126
|
+
{label} ({count})
|
|
127
|
+
</button>
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const ResourceGroupTable = (props: ResourceGroupTableProps) => {
|
|
132
|
+
const { resources = [], limit, showTags = false, showOwners = false, title, subtitle = 'Resources', description } = props;
|
|
133
|
+
const [searchTerm, setSearchTerm] = useState('');
|
|
134
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
135
|
+
const [typeFilter, setTypeFilter] = useState<ResourceType>(null);
|
|
136
|
+
const itemsPerPage = limit || 10;
|
|
137
|
+
|
|
138
|
+
const filterResources = useCallback((resources: Resource[], searchTerm: string, typeFilter: ResourceType) => {
|
|
139
|
+
let filtered = resources;
|
|
140
|
+
|
|
141
|
+
if (typeFilter) {
|
|
142
|
+
filtered = filtered.filter((resource) => {
|
|
143
|
+
const collectionType = resource.collection.slice(0, -1);
|
|
144
|
+
const normalizedType = collectionType === 'querie' ? 'query' : collectionType;
|
|
145
|
+
return normalizedType === typeFilter;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (searchTerm) {
|
|
150
|
+
const lowerSearchTerm = searchTerm.toLowerCase();
|
|
151
|
+
filtered = filtered.filter((resource) => {
|
|
152
|
+
const collectionType = resource.collection.slice(0, -1);
|
|
153
|
+
const normalizedType = collectionType === 'querie' ? 'query' : collectionType;
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
resource.name.toLowerCase().includes(lowerSearchTerm) ||
|
|
157
|
+
resource.summary?.toLowerCase().includes(lowerSearchTerm) ||
|
|
158
|
+
resource.description?.toLowerCase().includes(lowerSearchTerm) ||
|
|
159
|
+
normalizedType.toLowerCase().includes(lowerSearchTerm) ||
|
|
160
|
+
resource.tags?.some((tag) => tag.toLowerCase().includes(lowerSearchTerm)) ||
|
|
161
|
+
false
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return filtered;
|
|
167
|
+
}, []);
|
|
168
|
+
|
|
169
|
+
const filteredResources = useMemo(
|
|
170
|
+
() => filterResources(resources, searchTerm, typeFilter),
|
|
171
|
+
[resources, searchTerm, typeFilter, filterResources]
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const totalPages = Math.ceil(filteredResources.length / itemsPerPage);
|
|
175
|
+
const startIndex = (currentPage - 1) * itemsPerPage;
|
|
176
|
+
const paginatedResources = useMemo(
|
|
177
|
+
() => filteredResources.slice(startIndex, startIndex + itemsPerPage),
|
|
178
|
+
[filteredResources, startIndex, itemsPerPage]
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// Get unique resource types and their counts
|
|
182
|
+
const resourceTypeCounts = useMemo(() => {
|
|
183
|
+
const counts = new Map<ResourceType, number>();
|
|
184
|
+
resources.forEach((resource) => {
|
|
185
|
+
const collectionType = resource.collection.slice(0, -1);
|
|
186
|
+
const normalizedType = (collectionType === 'querie' ? 'query' : collectionType) as ResourceType;
|
|
187
|
+
counts.set(normalizedType, (counts.get(normalizedType) || 0) + 1);
|
|
188
|
+
});
|
|
189
|
+
return counts;
|
|
190
|
+
}, [resources]);
|
|
191
|
+
|
|
192
|
+
const availableTypes = useMemo(
|
|
193
|
+
() =>
|
|
194
|
+
Array.from(
|
|
195
|
+
new Set(
|
|
196
|
+
resources.map((resource) => {
|
|
197
|
+
const collectionType = resource.collection.slice(0, -1);
|
|
198
|
+
return collectionType === 'querie' ? 'query' : collectionType;
|
|
199
|
+
})
|
|
200
|
+
)
|
|
201
|
+
) as ResourceType[],
|
|
202
|
+
[resources]
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const filterButtons = useMemo(
|
|
206
|
+
() =>
|
|
207
|
+
availableTypes
|
|
208
|
+
.filter((type): type is NonNullable<ResourceType> => type !== null)
|
|
209
|
+
.map((type) => ({
|
|
210
|
+
type,
|
|
211
|
+
// Format the label to be capitalized and pluralized if needed
|
|
212
|
+
label: type.charAt(0).toUpperCase() + type.slice(1) + (type.endsWith('s') ? '' : 's'),
|
|
213
|
+
count: resourceTypeCounts.get(type) || 0,
|
|
214
|
+
})),
|
|
215
|
+
[availableTypes, resourceTypeCounts]
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<div className="mx-auto not-prose py-4 space-y-4 my-4">
|
|
220
|
+
{title && <h2 className="text-2xl font-semibold">{title}</h2>}
|
|
221
|
+
<div className="flow-root bg-white border-gray-200 border p-4 pb-2 rounded-lg text-gray-900">
|
|
222
|
+
<div className="space-y-4">
|
|
223
|
+
<h2 className="text-xl font-semibold">
|
|
224
|
+
{subtitle} ({searchTerm || typeFilter ? `${filteredResources.length}/${resources.length}` : resources.length})
|
|
225
|
+
</h2>
|
|
226
|
+
<span className="text-sm text-gray-700">{description}</span>
|
|
227
|
+
|
|
228
|
+
{/* Type filter buttons - only shown if there are filter options */}
|
|
229
|
+
{filterButtons.length > 0 && (
|
|
230
|
+
<div className="flex gap-2 pb-2 flex-wrap">
|
|
231
|
+
{filterButtons.map((button) => (
|
|
232
|
+
<FilterButton
|
|
233
|
+
key={button.type}
|
|
234
|
+
type={button.type}
|
|
235
|
+
label={button.label}
|
|
236
|
+
count={button.count}
|
|
237
|
+
typeFilter={typeFilter}
|
|
238
|
+
setTypeFilter={setTypeFilter}
|
|
239
|
+
setCurrentPage={setCurrentPage}
|
|
240
|
+
/>
|
|
241
|
+
))}
|
|
242
|
+
</div>
|
|
243
|
+
)}
|
|
244
|
+
|
|
245
|
+
<div className="relative">
|
|
246
|
+
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
247
|
+
<svg className="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
248
|
+
<path
|
|
249
|
+
fillRule="evenodd"
|
|
250
|
+
d="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
|
|
251
|
+
clipRule="evenodd"
|
|
252
|
+
/>
|
|
253
|
+
</svg>
|
|
254
|
+
</div>
|
|
255
|
+
<input
|
|
256
|
+
type="text"
|
|
257
|
+
value={searchTerm}
|
|
258
|
+
onChange={(e) => {
|
|
259
|
+
setSearchTerm(e.target.value);
|
|
260
|
+
setCurrentPage(1); // Reset to first page when searching
|
|
261
|
+
}}
|
|
262
|
+
placeholder="Search by name, type, description, or tags..."
|
|
263
|
+
className="block w-full rounded-md border-0 py-1.5 pl-10 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6"
|
|
264
|
+
/>
|
|
265
|
+
{searchTerm && (
|
|
266
|
+
<button
|
|
267
|
+
onClick={() => {
|
|
268
|
+
setSearchTerm('');
|
|
269
|
+
setCurrentPage(1); // Reset to first page when clearing search
|
|
270
|
+
}}
|
|
271
|
+
className="absolute inset-y-0 right-0 flex items-center pr-3"
|
|
272
|
+
aria-label="Clear search"
|
|
273
|
+
>
|
|
274
|
+
<svg className="h-5 w-5 text-gray-400 hover:text-gray-500" viewBox="0 0 20 20" fill="currentColor">
|
|
275
|
+
<path d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z" />
|
|
276
|
+
</svg>
|
|
277
|
+
</button>
|
|
278
|
+
)}
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
<div className="overflow-x-auto">
|
|
282
|
+
<div className="inline-block min-w-full py-2 align-middle">
|
|
283
|
+
<div className="max-w-full overflow-hidden">
|
|
284
|
+
<table className="min-w-full table-fixed divide-y divide-gray-300 rounded-sm bg-white">
|
|
285
|
+
<thead>
|
|
286
|
+
<tr>
|
|
287
|
+
<th
|
|
288
|
+
scope="col"
|
|
289
|
+
className={`${showTags || showOwners ? 'w-1/5' : 'w-1/4'} py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6`}
|
|
290
|
+
>
|
|
291
|
+
Name
|
|
292
|
+
</th>
|
|
293
|
+
<th scope="col" className="w-[100px] px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
|
294
|
+
Version
|
|
295
|
+
</th>
|
|
296
|
+
<th scope="col" className="w-[100px] py-3.5 pl-3.5 pr-3 text-left text-sm font-semibold text-gray-900">
|
|
297
|
+
Type
|
|
298
|
+
</th>
|
|
299
|
+
<th
|
|
300
|
+
scope="col"
|
|
301
|
+
className={`${showTags && showOwners ? 'w-1/4' : showTags || showOwners ? 'w-1/3' : 'w-1/2'} px-3 py-3.5 text-left text-sm font-semibold text-gray-900`}
|
|
302
|
+
>
|
|
303
|
+
Description
|
|
304
|
+
</th>
|
|
305
|
+
{showTags && (
|
|
306
|
+
<th scope="col" className="w-1/6 px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
|
307
|
+
Tags
|
|
308
|
+
</th>
|
|
309
|
+
)}
|
|
310
|
+
{showOwners && (
|
|
311
|
+
<th scope="col" className="w-1/6 px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
|
312
|
+
Owners
|
|
313
|
+
</th>
|
|
314
|
+
)}
|
|
315
|
+
</tr>
|
|
316
|
+
</thead>
|
|
317
|
+
<tbody className="divide-y divide-gray-200">
|
|
318
|
+
{paginatedResources.length > 0 ? (
|
|
319
|
+
paginatedResources.map((resource) => (
|
|
320
|
+
<ResourceRow
|
|
321
|
+
key={`${resource.collection}-${resource.id}-${resource.version}`}
|
|
322
|
+
resource={resource}
|
|
323
|
+
showTags={showTags}
|
|
324
|
+
showOwners={showOwners}
|
|
325
|
+
/>
|
|
326
|
+
))
|
|
327
|
+
) : (
|
|
328
|
+
<tr>
|
|
329
|
+
<td
|
|
330
|
+
colSpan={showTags && showOwners ? 6 : showTags || showOwners ? 5 : 4}
|
|
331
|
+
className="text-center py-4 text-sm text-gray-500"
|
|
332
|
+
>
|
|
333
|
+
No resources found
|
|
334
|
+
</td>
|
|
335
|
+
</tr>
|
|
336
|
+
)}
|
|
337
|
+
</tbody>
|
|
338
|
+
</table>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
</div>
|
|
342
|
+
{totalPages > 1 && (
|
|
343
|
+
<div className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 -mt-2">
|
|
344
|
+
<div className="flex flex-1 justify-between sm:hidden">
|
|
345
|
+
<button
|
|
346
|
+
onClick={() => setCurrentPage(currentPage - 1)}
|
|
347
|
+
disabled={currentPage === 1}
|
|
348
|
+
className={`relative inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium ${currentPage === 1 ? 'text-gray-300' : 'text-gray-700 hover:bg-gray-50'}`}
|
|
349
|
+
>
|
|
350
|
+
Previous
|
|
351
|
+
</button>
|
|
352
|
+
<button
|
|
353
|
+
onClick={() => setCurrentPage(currentPage + 1)}
|
|
354
|
+
disabled={currentPage === totalPages}
|
|
355
|
+
className={`relative ml-3 inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium ${currentPage === totalPages ? 'text-gray-300' : 'text-gray-700 hover:bg-gray-50'}`}
|
|
356
|
+
>
|
|
357
|
+
Next
|
|
358
|
+
</button>
|
|
359
|
+
</div>
|
|
360
|
+
<div className="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
361
|
+
<div>
|
|
362
|
+
<p className="text-sm text-gray-700">
|
|
363
|
+
Showing <span className="font-medium">{startIndex + 1}</span> to{' '}
|
|
364
|
+
<span className="font-medium">{Math.min(startIndex + itemsPerPage, filteredResources.length)}</span> of{' '}
|
|
365
|
+
<span className="font-medium">{filteredResources.length}</span> results
|
|
366
|
+
</p>
|
|
367
|
+
</div>
|
|
368
|
+
<div>
|
|
369
|
+
<nav className="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
|
370
|
+
<button
|
|
371
|
+
onClick={() => setCurrentPage(currentPage - 1)}
|
|
372
|
+
disabled={currentPage === 1}
|
|
373
|
+
className={`relative inline-flex items-center rounded-l-md px-2 py-2 ${currentPage === 1 ? 'text-gray-300' : 'text-gray-400 hover:bg-gray-50'} ring-1 ring-inset ring-gray-300`}
|
|
374
|
+
>
|
|
375
|
+
<span className="sr-only">Previous</span>
|
|
376
|
+
<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
377
|
+
<path
|
|
378
|
+
fillRule="evenodd"
|
|
379
|
+
d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
|
|
380
|
+
clipRule="evenodd"
|
|
381
|
+
/>
|
|
382
|
+
</svg>
|
|
383
|
+
</button>
|
|
384
|
+
<button
|
|
385
|
+
onClick={() => setCurrentPage(currentPage + 1)}
|
|
386
|
+
disabled={currentPage === totalPages}
|
|
387
|
+
className={`relative inline-flex items-center rounded-r-md px-2 py-2 ${currentPage === totalPages ? 'text-gray-300' : 'text-gray-400 hover:bg-gray-50'} ring-1 ring-inset ring-gray-300`}
|
|
388
|
+
>
|
|
389
|
+
<span className="sr-only">Next</span>
|
|
390
|
+
<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
391
|
+
<path
|
|
392
|
+
fillRule="evenodd"
|
|
393
|
+
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
|
|
394
|
+
clipRule="evenodd"
|
|
395
|
+
/>
|
|
396
|
+
</svg>
|
|
397
|
+
</button>
|
|
398
|
+
</nav>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
)}
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
);
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
export default ResourceGroupTable;
|
|
@@ -13,6 +13,7 @@ import OpenAPI from '@components/MDX/OpenAPI/OpenAPI.astro';
|
|
|
13
13
|
import AsyncAPI from '@components/MDX/AsyncAPI/AsyncAPI.astro';
|
|
14
14
|
import ChannelInformation from '@components/MDX/ChannelInformation/ChannelInformation';
|
|
15
15
|
import MessageTable from '@components/MDX/MessageTable/MessageTable.astro';
|
|
16
|
+
import ResourceGroupTable from '@components/MDX/ResourceGroupTable/ResourceGroupTable.astro';
|
|
16
17
|
import Tabs from '@components/MDX/Tabs/Tabs.astro';
|
|
17
18
|
import TabItem from '@components/MDX/Tabs/TabItem.astro';
|
|
18
19
|
|
|
@@ -41,6 +42,7 @@ const components = (props: any) => {
|
|
|
41
42
|
SchemaViewer: (mdxProp: any) => SchemaViewerPortal({ ...props.data, ...mdxProp }),
|
|
42
43
|
Schema: (mdxProp: any) => jsx(Schema, { ...props, ...mdxProp }),
|
|
43
44
|
MessageTable: (mdxProp: any) => jsx(MessageTable, { ...props, ...mdxProp }),
|
|
45
|
+
ResourceGroupTable: (mdxProp: any) => jsx(ResourceGroupTable, { ...props, ...mdxProp }),
|
|
44
46
|
};
|
|
45
47
|
};
|
|
46
48
|
|
|
@@ -4,6 +4,7 @@ import PillListFlat from '@components/Lists/PillListFlat';
|
|
|
4
4
|
import RepositoryList from '@components/Lists/RepositoryList.astro';
|
|
5
5
|
import VersionList from '@components/Lists/VersionList.astro';
|
|
6
6
|
import { getUbiquitousLanguage, getMessagesForDomain } from '@utils/collections/domains';
|
|
7
|
+
import CustomSideBarSectionList from '@components/Lists/CustomSideBarSectionList.astro';
|
|
7
8
|
import { getOwner } from '@utils/collections/owners';
|
|
8
9
|
import { buildUrl } from '@utils/url-builder';
|
|
9
10
|
import type { CollectionEntry } from 'astro:content';
|
|
@@ -27,6 +28,8 @@ const filteredOwners = owners.filter((o) => o !== undefined);
|
|
|
27
28
|
|
|
28
29
|
const messagesForDomain = await getMessagesForDomain(domain);
|
|
29
30
|
|
|
31
|
+
const resourceGroups = domain.data?.resourceGroups || [];
|
|
32
|
+
|
|
30
33
|
const serviceList = services.map((p) => ({
|
|
31
34
|
label: p.data.name,
|
|
32
35
|
badge: p.collection,
|
|
@@ -73,6 +76,11 @@ const ownersList = filteredOwners.map((o) => ({
|
|
|
73
76
|
|
|
74
77
|
<aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto py-4">
|
|
75
78
|
<div>
|
|
79
|
+
{
|
|
80
|
+
resourceGroups
|
|
81
|
+
.filter((section) => section.items.length > 0 && section.sidebar)
|
|
82
|
+
.map((section) => <CustomSideBarSectionList section={section} />)
|
|
83
|
+
}
|
|
76
84
|
<PillListFlat
|
|
77
85
|
title={`Services (${services.length})`}
|
|
78
86
|
pills={serviceList}
|
|
@@ -6,7 +6,7 @@ import { getOwner } from '@utils/collections/owners';
|
|
|
6
6
|
import type { CollectionEntry } from 'astro:content';
|
|
7
7
|
import { ScrollText, Workflow, RssIcon } from 'lucide-react';
|
|
8
8
|
import config from '@config';
|
|
9
|
-
|
|
9
|
+
import CustomSideBarSectionList from '@components/Lists/CustomSideBarSectionList.astro';
|
|
10
10
|
interface Props {
|
|
11
11
|
flow: CollectionEntry<'flows'>;
|
|
12
12
|
}
|
|
@@ -17,6 +17,8 @@ const ownersRaw = flow.data?.owners || [];
|
|
|
17
17
|
const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
|
|
18
18
|
const filteredOwners = owners.filter((o) => o !== undefined);
|
|
19
19
|
|
|
20
|
+
const resourceGroups = flow.data?.resourceGroups || [];
|
|
21
|
+
|
|
20
22
|
const ownersList = filteredOwners.map((o) => ({
|
|
21
23
|
label: o.data.name,
|
|
22
24
|
type: o.collection,
|
|
@@ -30,6 +32,11 @@ const isRSSEnabled = config.rss?.enabled;
|
|
|
30
32
|
|
|
31
33
|
<aside class="sticky top-28 left-0 h-full overflow-y-auto pr-6 py-4">
|
|
32
34
|
<div id="sidebar-cta-portal" class="">
|
|
35
|
+
{
|
|
36
|
+
resourceGroups
|
|
37
|
+
.filter((section) => section.items.length > 0 && section.sidebar)
|
|
38
|
+
.map((section) => <CustomSideBarSectionList section={section} />)
|
|
39
|
+
}
|
|
33
40
|
{flow.data.versions && <VersionList versions={flow.data.versions} collectionItem={flow} />}
|
|
34
41
|
|
|
35
42
|
<OwnersList
|
|
@@ -9,6 +9,7 @@ import { buildUrl } from '@utils/url-builder';
|
|
|
9
9
|
import { FileDownIcon, ScrollText, Workflow, RssIcon } from 'lucide-react';
|
|
10
10
|
import RepositoryList from '@components/Lists/RepositoryList.astro';
|
|
11
11
|
import { getOwner } from '@utils/collections/owners';
|
|
12
|
+
import CustomSideBarSectionList from '@components/Lists/CustomSideBarSectionList.astro';
|
|
12
13
|
import config from '@config';
|
|
13
14
|
|
|
14
15
|
interface Props {
|
|
@@ -25,6 +26,8 @@ const ownersRaw = message.data?.owners || [];
|
|
|
25
26
|
const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
|
|
26
27
|
const filteredOwners = owners.filter((o) => o !== undefined);
|
|
27
28
|
|
|
29
|
+
const resourceGroups = message.data?.resourceGroups || [];
|
|
30
|
+
|
|
28
31
|
const producerList = producers.map((p) => ({
|
|
29
32
|
label: `${p.data.name}`,
|
|
30
33
|
tag: `v${p.data.version}`,
|
|
@@ -98,6 +101,11 @@ const schemaURL = path.join(publicPath, schemaFilePath || '');
|
|
|
98
101
|
|
|
99
102
|
<aside class="sticky top-28 left-0 space-y-8 h-full overflow-y-auto py-4">
|
|
100
103
|
<div class="">
|
|
104
|
+
{
|
|
105
|
+
resourceGroups
|
|
106
|
+
.filter((section) => section.items.length > 0 && section.sidebar)
|
|
107
|
+
.map((section) => <CustomSideBarSectionList section={section} />)
|
|
108
|
+
}
|
|
101
109
|
{
|
|
102
110
|
producerList.length > 0 && (
|
|
103
111
|
<PillListFlat
|
|
@@ -3,6 +3,7 @@ import OwnersList from '@components/Lists/OwnersList';
|
|
|
3
3
|
import PillListFlat from '@components/Lists/PillListFlat';
|
|
4
4
|
import RepositoryList from '@components/Lists/RepositoryList.astro';
|
|
5
5
|
import SpecificationsList from '@components/Lists/SpecificationsList.astro';
|
|
6
|
+
import CustomSideBarSectionList from '@components/Lists/CustomSideBarSectionList.astro';
|
|
6
7
|
import VersionList from '@components/Lists/VersionList.astro';
|
|
7
8
|
import { buildUrl } from '@utils/url-builder';
|
|
8
9
|
import { getOwner } from '@utils/collections/owners';
|
|
@@ -10,7 +11,6 @@ import type { CollectionEntry } from 'astro:content';
|
|
|
10
11
|
import { ScrollText, Workflow, FileDownIcon, Code, Link, RssIcon } from 'lucide-react';
|
|
11
12
|
import { join } from 'node:path';
|
|
12
13
|
import config from '@config';
|
|
13
|
-
|
|
14
14
|
interface Props {
|
|
15
15
|
service: CollectionEntry<'services'>;
|
|
16
16
|
}
|
|
@@ -26,6 +26,8 @@ const ownersRaw = service.data?.owners || [];
|
|
|
26
26
|
const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
|
|
27
27
|
const filteredOwners = owners.filter((o) => o !== undefined);
|
|
28
28
|
|
|
29
|
+
const resourceGroups = service.data?.resourceGroups || [];
|
|
30
|
+
|
|
29
31
|
const sendsList = sends
|
|
30
32
|
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
31
33
|
.map((p) => ({
|
|
@@ -66,6 +68,11 @@ const schemaURL = join(publicPath, schemaFilePath || '');
|
|
|
66
68
|
|
|
67
69
|
<aside class="sticky top-28 left-0 h-full overflow-y-auto pr-6 py-4">
|
|
68
70
|
<div id="sidebar-cta-portal" class="">
|
|
71
|
+
{
|
|
72
|
+
resourceGroups
|
|
73
|
+
.filter((section) => section.items.length > 0 && section.sidebar)
|
|
74
|
+
.map((section) => <CustomSideBarSectionList section={section} />)
|
|
75
|
+
}
|
|
69
76
|
<PillListFlat
|
|
70
77
|
title={`Receives Messages (${receivesList.length})`}
|
|
71
78
|
pills={receivesList}
|
|
@@ -6,4 +6,4 @@ const currentPath = Astro.url.pathname;
|
|
|
6
6
|
const sidebarItems = await getNavigationItems();
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
<CustomDocsNavWrapper client:
|
|
9
|
+
<CustomDocsNavWrapper client:only sidebarItems={sidebarItems} currentPath={currentPath} />
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ServerIcon
|
|
1
|
+
import { ServerIcon } from '@heroicons/react/24/solid';
|
|
2
2
|
import { createColumnHelper } from '@tanstack/react-table';
|
|
3
3
|
import { useMemo, useState } from 'react';
|
|
4
4
|
import { filterByName, filterCollectionByName } from '../filters/custom-filters';
|
|
5
5
|
import { buildUrl } from '@utils/url-builder';
|
|
6
|
-
import {
|
|
6
|
+
import { getColorAndIconForCollection } from '@utils/collections/icons';
|
|
7
7
|
import { createBadgesColumn } from './SharedColumns';
|
|
8
8
|
import type { TData } from '../Table';
|
|
9
9
|
|
|
@@ -66,10 +66,9 @@ export const columns = () => [
|
|
|
66
66
|
const receiversWithIcons = useMemo(
|
|
67
67
|
() =>
|
|
68
68
|
receives?.map((consumer) => {
|
|
69
|
-
const type = consumer.collection.slice(0, -1);
|
|
70
69
|
return {
|
|
71
70
|
...consumer,
|
|
72
|
-
...
|
|
71
|
+
...getColorAndIconForCollection(consumer.collection),
|
|
73
72
|
};
|
|
74
73
|
}) || [],
|
|
75
74
|
[receives]
|
|
@@ -131,10 +130,9 @@ export const columns = () => [
|
|
|
131
130
|
const sendersWithIcons = useMemo(
|
|
132
131
|
() =>
|
|
133
132
|
sends?.map((sender) => {
|
|
134
|
-
const type = sender.collection.slice(0, -1);
|
|
135
133
|
return {
|
|
136
134
|
...sender,
|
|
137
|
-
...
|
|
135
|
+
...getColorAndIconForCollection(sender.collection),
|
|
138
136
|
};
|
|
139
137
|
}) || [],
|
|
140
138
|
[sends]
|
|
@@ -5,26 +5,11 @@ import { filterByName, filterCollectionByName } from '../filters/custom-filters'
|
|
|
5
5
|
import { buildUrl } from '@utils/url-builder';
|
|
6
6
|
import type { TData } from '../Table';
|
|
7
7
|
import type { CollectionUserTypes } from '@types';
|
|
8
|
-
import { User, Users } from 'lucide-react';
|
|
9
8
|
import type { CollectionEntry } from 'astro:content';
|
|
10
9
|
import { ServerIcon, BoltIcon, ChatBubbleLeftIcon } from '@heroicons/react/24/solid';
|
|
11
10
|
|
|
12
11
|
const columnHelper = createColumnHelper<TData<CollectionUserTypes>>();
|
|
13
12
|
|
|
14
|
-
export const getColorAndIconForMessageType = (type: string) => {
|
|
15
|
-
switch (type) {
|
|
16
|
-
case 'event':
|
|
17
|
-
return { color: 'orange', Icon: BoltIcon };
|
|
18
|
-
case 'command':
|
|
19
|
-
return { color: 'blue', Icon: ChatBubbleLeftIcon };
|
|
20
|
-
case 'querie':
|
|
21
|
-
case 'query':
|
|
22
|
-
return { color: 'green', Icon: MagnifyingGlassIcon };
|
|
23
|
-
default:
|
|
24
|
-
return { color: 'gray', Icon: ChatBubbleLeftIcon };
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
13
|
export const columns = () => [
|
|
29
14
|
columnHelper.accessor('data.name', {
|
|
30
15
|
id: 'name',
|
|
@@ -35,6 +35,12 @@ const channelPointer = z
|
|
|
35
35
|
})
|
|
36
36
|
.merge(pointer);
|
|
37
37
|
|
|
38
|
+
const resourcePointer = z.object({
|
|
39
|
+
id: z.string(),
|
|
40
|
+
version: z.string().optional().default('latest'),
|
|
41
|
+
type: z.enum(['service', 'event', 'command', 'query', 'flow', 'channel', 'domain', 'user', 'team']),
|
|
42
|
+
});
|
|
43
|
+
|
|
38
44
|
const changelogs = defineCollection({
|
|
39
45
|
loader: glob({
|
|
40
46
|
pattern: ['**/changelog.(md|mdx)'],
|
|
@@ -87,6 +93,17 @@ const baseSchema = z.object({
|
|
|
87
93
|
})
|
|
88
94
|
.optional(),
|
|
89
95
|
hidden: z.boolean().optional(),
|
|
96
|
+
resourceGroups: z
|
|
97
|
+
.array(
|
|
98
|
+
z.object({
|
|
99
|
+
id: z.string().optional(),
|
|
100
|
+
title: z.string().optional(),
|
|
101
|
+
items: z.array(resourcePointer),
|
|
102
|
+
limit: z.number().optional().default(10),
|
|
103
|
+
sidebar: z.boolean().optional().default(true),
|
|
104
|
+
})
|
|
105
|
+
)
|
|
106
|
+
.optional(),
|
|
90
107
|
// Used by eventcatalog
|
|
91
108
|
versions: z.array(z.string()).optional(),
|
|
92
109
|
latestVersion: z.string().optional(),
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { getNavigationItems } from '@enterprise/custom-documentation/utils/custom-docs';
|
|
3
|
+
import CustomDocsNavWrapper from '@enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper';
|
|
4
|
+
|
|
5
|
+
const currentPath = Astro.url.pathname;
|
|
6
|
+
const sidebarItems = await getNavigationItems();
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<CustomDocsNavWrapper client:only sidebarItems={sidebarItems} currentPath={currentPath} />
|