@eventcatalog/core 2.25.1 → 2.26.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/README.md +7 -3
- 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/catalog-to-astro-content-directory.cjs +1 -7
- package/dist/catalog-to-astro-content-directory.js +2 -2
- package/dist/{chunk-7JDTB3U5.js → chunk-FIY5JLSQ.js} +0 -2
- package/dist/{chunk-OZLFIB46.js → chunk-JCGLXXSE.js} +1 -1
- package/dist/{chunk-O33THQNO.js → chunk-M7ERKXSB.js} +1 -1
- package/dist/{chunk-VCR3LHZR.js → chunk-R2NILSWL.js} +2 -6
- package/dist/{chunk-DZIMF2ES.js → chunk-TOTPAQ4C.js} +1 -1
- package/dist/{chunk-OW2FQPYP.js → chunk-WUCY3QHK.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +2 -8
- package/dist/eventcatalog.js +6 -6
- package/dist/map-catalog-to-astro.cjs +0 -2
- package/dist/map-catalog-to-astro.js +1 -1
- package/dist/watcher.cjs +0 -2
- package/dist/watcher.js +2 -2
- package/eventcatalog/src/components/Lists/OwnersList.tsx +3 -2
- package/eventcatalog/src/components/Lists/PillListFlat.tsx +6 -4
- package/eventcatalog/src/components/Lists/RepositoryList.astro +3 -2
- package/eventcatalog/src/components/Lists/VersionList.astro +3 -22
- package/eventcatalog/src/components/MDX/MessageTable/MessageTable.astro +87 -0
- package/eventcatalog/src/components/MDX/MessageTable/MessageTable.client.tsx +430 -0
- package/eventcatalog/src/components/MDX/components.tsx +2 -0
- package/eventcatalog/src/components/SideBars/DomainSideBar.astro +38 -1
- package/eventcatalog/src/components/SideBars/ServiceSideBar.astro +22 -17
- package/eventcatalog/src/{content/config.ts → content.config.ts} +12 -2
- package/eventcatalog/src/enterprise/ai-assistant/components/ChatSidebar.tsx +0 -1
- package/eventcatalog/src/pages/chat/index.astro +1 -1
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +6 -13
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +7 -13
- package/eventcatalog/src/utils/collections/domains.ts +27 -0
- package/eventcatalog/src/utils/users.ts +2 -2
- package/package.json +1 -1
- package/default-files-for-collections/teams.md +0 -11
- package/default-files-for-collections/users.md +0 -11
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { getColorAndIconForMessageType } from '@components/Tables/columns/MessageTableColumns';
|
|
2
|
+
import { buildUrl } from '@utils/url-builder';
|
|
3
|
+
import { useState, useMemo, useCallback, memo } from 'react';
|
|
4
|
+
|
|
5
|
+
type MessageTableMessage = {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
collection: string;
|
|
10
|
+
type: string;
|
|
11
|
+
summary: string;
|
|
12
|
+
channels: any[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type MessageTableProps = {
|
|
16
|
+
format: 'receives' | 'sends' | 'all';
|
|
17
|
+
limit?: number;
|
|
18
|
+
showChannels?: boolean;
|
|
19
|
+
collection: string;
|
|
20
|
+
sends: MessageTableMessage[];
|
|
21
|
+
receives: MessageTableMessage[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type MessageType = 'event' | 'query' | 'command' | null;
|
|
25
|
+
|
|
26
|
+
const MessageRow = memo(
|
|
27
|
+
({ message, showChannels, collection }: { message: MessageTableMessage; showChannels?: boolean; collection: string }) => {
|
|
28
|
+
const { color, Icon } = getColorAndIconForMessageType(message.type);
|
|
29
|
+
const url = buildUrl(`/docs/${collection}/${message.id}/${message.version}`);
|
|
30
|
+
let type = collection.slice(0, -1);
|
|
31
|
+
type = type === 'querie' ? 'query' : type;
|
|
32
|
+
|
|
33
|
+
const channels = message.channels || [];
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<tr className="group hover:bg-gray-100">
|
|
37
|
+
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6 relative">
|
|
38
|
+
<a href={url} className="absolute inset-0 z-10" aria-label={`View details for ${message.name}`} />
|
|
39
|
+
<div className="flex items-center gap-2 relative">
|
|
40
|
+
<Icon className={`h-5 w-5 text-${color}-500`} />
|
|
41
|
+
<span className="group-hover:text-blue-600 break-all">{message.name}</span>
|
|
42
|
+
</div>
|
|
43
|
+
</td>
|
|
44
|
+
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500 relative">
|
|
45
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
46
|
+
<span>v{message.version}</span>
|
|
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>{type}</span>
|
|
51
|
+
</td>
|
|
52
|
+
<td className="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 className="line-clamp-2 break-words">{message.summary || '-'}</span>
|
|
55
|
+
</td>
|
|
56
|
+
{showChannels && (
|
|
57
|
+
<td className="px-3 py-4 text-sm text-gray-500 relative">
|
|
58
|
+
<a href={url} className="absolute inset-0 z-10" aria-hidden="true" />
|
|
59
|
+
<div className="flex flex-wrap gap-1">
|
|
60
|
+
{channels.length > 0
|
|
61
|
+
? channels.map((channel, index) => (
|
|
62
|
+
<span
|
|
63
|
+
key={`${channel.id}-${index}`}
|
|
64
|
+
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"
|
|
65
|
+
>
|
|
66
|
+
{channel.id}
|
|
67
|
+
</span>
|
|
68
|
+
))
|
|
69
|
+
: '-'}
|
|
70
|
+
</div>
|
|
71
|
+
</td>
|
|
72
|
+
)}
|
|
73
|
+
</tr>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const FilterButton = memo(
|
|
79
|
+
({
|
|
80
|
+
type,
|
|
81
|
+
label,
|
|
82
|
+
typeFilter,
|
|
83
|
+
setTypeFilter,
|
|
84
|
+
setCurrentPage,
|
|
85
|
+
count,
|
|
86
|
+
}: {
|
|
87
|
+
type: MessageType;
|
|
88
|
+
label: string;
|
|
89
|
+
typeFilter: MessageType;
|
|
90
|
+
setTypeFilter: (type: MessageType) => void;
|
|
91
|
+
setCurrentPage: (page: number) => void;
|
|
92
|
+
count: number;
|
|
93
|
+
}) => (
|
|
94
|
+
<button
|
|
95
|
+
onClick={() => {
|
|
96
|
+
setTypeFilter(typeFilter === type ? null : type);
|
|
97
|
+
setCurrentPage(1);
|
|
98
|
+
}}
|
|
99
|
+
className={`px-3 py-1 rounded-md text-sm font-medium ${
|
|
100
|
+
typeFilter === type
|
|
101
|
+
? 'bg-black text-white border border-gray-200 hover:bg-gray-900'
|
|
102
|
+
: 'bg-white text-black border border-gray-200 hover:bg-gray-100'
|
|
103
|
+
}`}
|
|
104
|
+
>
|
|
105
|
+
{label} ({count})
|
|
106
|
+
</button>
|
|
107
|
+
)
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const MessageTable = (props: MessageTableProps) => {
|
|
111
|
+
const { receives, sends, collection = 'services', limit, showChannels = false, format = 'all' } = props;
|
|
112
|
+
const [receivesSearchTerm, setReceivesSearchTerm] = useState('');
|
|
113
|
+
const [sendsSearchTerm, setSendsSearchTerm] = useState('');
|
|
114
|
+
const [receivesPage, setReceivesPage] = useState(1);
|
|
115
|
+
const [sendsPage, setSendsPage] = useState(1);
|
|
116
|
+
const [receivesTypeFilter, setReceivesTypeFilter] = useState<MessageType>(null);
|
|
117
|
+
const [sendsTypeFilter, setSendsTypeFilter] = useState<MessageType>(null);
|
|
118
|
+
const itemsPerPage = limit || 5;
|
|
119
|
+
|
|
120
|
+
const shouldRenderReceives = format === 'receives' || format === 'all';
|
|
121
|
+
const shouldRenderSends = format === 'sends' || format === 'all';
|
|
122
|
+
|
|
123
|
+
const filterMessages = useCallback((messages: MessageTableMessage[], searchTerm: string, typeFilter: MessageType) => {
|
|
124
|
+
let filtered = messages;
|
|
125
|
+
|
|
126
|
+
if (typeFilter) {
|
|
127
|
+
filtered = filtered.filter((message) => {
|
|
128
|
+
const collectionType = message.collection.slice(0, -1);
|
|
129
|
+
const normalizedType = collectionType === 'querie' ? 'query' : collectionType;
|
|
130
|
+
return normalizedType === typeFilter;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (searchTerm) {
|
|
135
|
+
const lowerSearchTerm = searchTerm.toLowerCase();
|
|
136
|
+
filtered = filtered.filter((message) => {
|
|
137
|
+
const collectionType = message.collection.slice(0, -1);
|
|
138
|
+
const normalizedType = collectionType === 'querie' ? 'query' : collectionType;
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
message.name.toLowerCase().includes(lowerSearchTerm) ||
|
|
142
|
+
message.summary?.toLowerCase().includes(lowerSearchTerm) ||
|
|
143
|
+
normalizedType.toLowerCase().includes(lowerSearchTerm)
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return filtered;
|
|
149
|
+
}, []);
|
|
150
|
+
|
|
151
|
+
const renderTable = (
|
|
152
|
+
title: string,
|
|
153
|
+
messages: any[],
|
|
154
|
+
searchTerm: string,
|
|
155
|
+
setSearchTerm: (value: string) => void,
|
|
156
|
+
currentPage: number,
|
|
157
|
+
setCurrentPage: (page: number) => void,
|
|
158
|
+
typeFilter: MessageType,
|
|
159
|
+
setTypeFilter: (type: MessageType) => void
|
|
160
|
+
) => {
|
|
161
|
+
const filteredMessages = useMemo(
|
|
162
|
+
() => filterMessages(messages, searchTerm, typeFilter),
|
|
163
|
+
[messages, searchTerm, typeFilter, filterMessages]
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
const totalPages = Math.ceil(filteredMessages.length / itemsPerPage);
|
|
167
|
+
const startIndex = (currentPage - 1) * itemsPerPage;
|
|
168
|
+
const paginatedMessages = useMemo(
|
|
169
|
+
() => filteredMessages.slice(startIndex, startIndex + itemsPerPage),
|
|
170
|
+
[filteredMessages, startIndex, itemsPerPage]
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
// Get unique message types and their counts
|
|
174
|
+
const messageTypeCounts = useMemo(() => {
|
|
175
|
+
const counts = new Map<MessageType, number>();
|
|
176
|
+
messages.forEach((message) => {
|
|
177
|
+
const collectionType = message.collection.slice(0, -1);
|
|
178
|
+
const normalizedType = (collectionType === 'querie' ? 'query' : collectionType) as MessageType;
|
|
179
|
+
counts.set(normalizedType, (counts.get(normalizedType) || 0) + 1);
|
|
180
|
+
});
|
|
181
|
+
return counts;
|
|
182
|
+
}, [messages]);
|
|
183
|
+
|
|
184
|
+
const availableTypes = useMemo(
|
|
185
|
+
() =>
|
|
186
|
+
Array.from(
|
|
187
|
+
new Set(
|
|
188
|
+
messages.map((message) => {
|
|
189
|
+
const collectionType = message.collection.slice(0, -1);
|
|
190
|
+
return collectionType === 'querie' ? 'query' : collectionType;
|
|
191
|
+
})
|
|
192
|
+
)
|
|
193
|
+
) as MessageType[],
|
|
194
|
+
[messages]
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
const filterButtons = useMemo(
|
|
198
|
+
() =>
|
|
199
|
+
[
|
|
200
|
+
{ type: 'event' as MessageType, label: 'Events' },
|
|
201
|
+
{ type: 'query' as MessageType, label: 'Queries' },
|
|
202
|
+
{ type: 'command' as MessageType, label: 'Commands' },
|
|
203
|
+
]
|
|
204
|
+
.filter((button) => availableTypes.includes(button.type))
|
|
205
|
+
.map((button) => ({
|
|
206
|
+
...button,
|
|
207
|
+
count: messageTypeCounts.get(button.type) || 0,
|
|
208
|
+
})),
|
|
209
|
+
[availableTypes, messageTypeCounts]
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<div className="flow-root bg-white border-gray-200 border p-4 pb-2 rounded-lg text-gray-900">
|
|
214
|
+
<div className="space-y-4">
|
|
215
|
+
<h2 className="text-xl font-semibold">
|
|
216
|
+
{title} ({searchTerm || typeFilter ? `${filteredMessages.length}/${messages.length}` : messages.length})
|
|
217
|
+
</h2>
|
|
218
|
+
<span className="text-sm text-gray-700">
|
|
219
|
+
Quickly find the message you need by searching for the name, type, or summary.
|
|
220
|
+
</span>
|
|
221
|
+
|
|
222
|
+
{/* Type filter buttons - only shown if there are filter options */}
|
|
223
|
+
{filterButtons.length > 0 && (
|
|
224
|
+
<div className="flex gap-2 pb-2">
|
|
225
|
+
{filterButtons.map((button) => (
|
|
226
|
+
<FilterButton
|
|
227
|
+
key={button.type}
|
|
228
|
+
type={button.type}
|
|
229
|
+
label={button.label}
|
|
230
|
+
count={button.count}
|
|
231
|
+
typeFilter={typeFilter}
|
|
232
|
+
setTypeFilter={setTypeFilter}
|
|
233
|
+
setCurrentPage={setCurrentPage}
|
|
234
|
+
/>
|
|
235
|
+
))}
|
|
236
|
+
</div>
|
|
237
|
+
)}
|
|
238
|
+
|
|
239
|
+
<div className="relative">
|
|
240
|
+
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
241
|
+
<svg className="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
242
|
+
<path
|
|
243
|
+
fillRule="evenodd"
|
|
244
|
+
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"
|
|
245
|
+
clipRule="evenodd"
|
|
246
|
+
/>
|
|
247
|
+
</svg>
|
|
248
|
+
</div>
|
|
249
|
+
<input
|
|
250
|
+
type="text"
|
|
251
|
+
value={searchTerm}
|
|
252
|
+
onChange={(e) => {
|
|
253
|
+
setSearchTerm(e.target.value);
|
|
254
|
+
setCurrentPage(1); // Reset to first page when searching
|
|
255
|
+
}}
|
|
256
|
+
placeholder={`Search by name, type, or summary...`}
|
|
257
|
+
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"
|
|
258
|
+
/>
|
|
259
|
+
{searchTerm && (
|
|
260
|
+
<button
|
|
261
|
+
onClick={() => {
|
|
262
|
+
setSearchTerm('');
|
|
263
|
+
setCurrentPage(1); // Reset to first page when clearing search
|
|
264
|
+
}}
|
|
265
|
+
className="absolute inset-y-0 right-0 flex items-center pr-3"
|
|
266
|
+
aria-label="Clear search"
|
|
267
|
+
>
|
|
268
|
+
<svg className="h-5 w-5 text-gray-400 hover:text-gray-500" viewBox="0 0 20 20" fill="currentColor">
|
|
269
|
+
<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" />
|
|
270
|
+
</svg>
|
|
271
|
+
</button>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
<div className="overflow-x-auto">
|
|
276
|
+
<div className="inline-block min-w-full py-2 align-middle">
|
|
277
|
+
<div className="max-w-full overflow-hidden">
|
|
278
|
+
<table className="min-w-full table-fixed divide-y divide-gray-300 rounded-sm bg-white ">
|
|
279
|
+
<thead>
|
|
280
|
+
<tr>
|
|
281
|
+
<th
|
|
282
|
+
scope="col"
|
|
283
|
+
className={`${showChannels ? 'w-1/4' : 'w-1/3'} py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6`}
|
|
284
|
+
>
|
|
285
|
+
Name
|
|
286
|
+
</th>
|
|
287
|
+
<th scope="col" className="w-[100px] px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
|
288
|
+
Version
|
|
289
|
+
</th>
|
|
290
|
+
<th scope="col" className="w-[100px] py-3.5 pl-3.5 pr-3 text-left text-sm font-semibold text-gray-900">
|
|
291
|
+
Type
|
|
292
|
+
</th>
|
|
293
|
+
<th
|
|
294
|
+
scope="col"
|
|
295
|
+
className={`${showChannels ? 'w-1/3' : 'w-1/2'} px-3 py-3.5 text-left text-sm font-semibold text-gray-900`}
|
|
296
|
+
>
|
|
297
|
+
Summary
|
|
298
|
+
</th>
|
|
299
|
+
{showChannels && (
|
|
300
|
+
<th scope="col" className="w-1/4 px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
|
|
301
|
+
Channels
|
|
302
|
+
</th>
|
|
303
|
+
)}
|
|
304
|
+
</tr>
|
|
305
|
+
</thead>
|
|
306
|
+
<tbody className="divide-y divide-gray-200">
|
|
307
|
+
{paginatedMessages.length > 0 ? (
|
|
308
|
+
paginatedMessages.map((message) => (
|
|
309
|
+
<MessageRow
|
|
310
|
+
key={message.id}
|
|
311
|
+
message={message}
|
|
312
|
+
showChannels={showChannels}
|
|
313
|
+
collection={message.collection}
|
|
314
|
+
/>
|
|
315
|
+
))
|
|
316
|
+
) : (
|
|
317
|
+
<tr>
|
|
318
|
+
<td colSpan={showChannels ? 5 : 4} className="text-center py-4 text-sm text-gray-500">
|
|
319
|
+
No messages found
|
|
320
|
+
</td>
|
|
321
|
+
</tr>
|
|
322
|
+
)}
|
|
323
|
+
</tbody>
|
|
324
|
+
</table>
|
|
325
|
+
</div>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
{totalPages > 1 && (
|
|
329
|
+
<div className="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 -mt-2">
|
|
330
|
+
<div className="flex flex-1 justify-between sm:hidden">
|
|
331
|
+
<button
|
|
332
|
+
onClick={() => setCurrentPage(currentPage - 1)}
|
|
333
|
+
disabled={currentPage === 1}
|
|
334
|
+
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'}`}
|
|
335
|
+
>
|
|
336
|
+
Previous
|
|
337
|
+
</button>
|
|
338
|
+
<button
|
|
339
|
+
onClick={() => setCurrentPage(currentPage + 1)}
|
|
340
|
+
disabled={currentPage === totalPages}
|
|
341
|
+
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'}`}
|
|
342
|
+
>
|
|
343
|
+
Next
|
|
344
|
+
</button>
|
|
345
|
+
</div>
|
|
346
|
+
<div className="hidden sm:flex sm:flex-1 sm:items-center sm:justify-between">
|
|
347
|
+
<div>
|
|
348
|
+
<p className="text-sm text-gray-700">
|
|
349
|
+
Showing <span className="font-medium">{startIndex + 1}</span> to{' '}
|
|
350
|
+
<span className="font-medium">{Math.min(startIndex + itemsPerPage, filteredMessages.length)}</span> of{' '}
|
|
351
|
+
<span className="font-medium">{filteredMessages.length}</span> results
|
|
352
|
+
</p>
|
|
353
|
+
</div>
|
|
354
|
+
<div>
|
|
355
|
+
<nav className="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
|
356
|
+
<button
|
|
357
|
+
onClick={() => setCurrentPage(currentPage - 1)}
|
|
358
|
+
disabled={currentPage === 1}
|
|
359
|
+
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`}
|
|
360
|
+
>
|
|
361
|
+
<span className="sr-only">Previous</span>
|
|
362
|
+
<svg className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
363
|
+
<path
|
|
364
|
+
fillRule="evenodd"
|
|
365
|
+
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"
|
|
366
|
+
clipRule="evenodd"
|
|
367
|
+
/>
|
|
368
|
+
</svg>
|
|
369
|
+
</button>
|
|
370
|
+
<button
|
|
371
|
+
onClick={() => setCurrentPage(currentPage + 1)}
|
|
372
|
+
disabled={currentPage === totalPages}
|
|
373
|
+
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`}
|
|
374
|
+
>
|
|
375
|
+
<span className="sr-only">Next</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="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"
|
|
380
|
+
clipRule="evenodd"
|
|
381
|
+
/>
|
|
382
|
+
</svg>
|
|
383
|
+
</button>
|
|
384
|
+
</nav>
|
|
385
|
+
</div>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
)}
|
|
389
|
+
</div>
|
|
390
|
+
);
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
return (
|
|
394
|
+
<div className={`mx-auto not-prose py-4 space-y-4 my-4`}>
|
|
395
|
+
<h2 className="text-2xl font-semibold">Messages for this {collection.slice(0, -1)}</h2>
|
|
396
|
+
<div>
|
|
397
|
+
{shouldRenderSends && (
|
|
398
|
+
<div>
|
|
399
|
+
{renderTable(
|
|
400
|
+
'Sends messages',
|
|
401
|
+
sends || [],
|
|
402
|
+
sendsSearchTerm,
|
|
403
|
+
setSendsSearchTerm,
|
|
404
|
+
sendsPage,
|
|
405
|
+
setSendsPage,
|
|
406
|
+
sendsTypeFilter,
|
|
407
|
+
setSendsTypeFilter
|
|
408
|
+
)}
|
|
409
|
+
</div>
|
|
410
|
+
)}
|
|
411
|
+
{shouldRenderReceives && (
|
|
412
|
+
<div className={format === 'all' ? 'pt-4' : ''}>
|
|
413
|
+
{renderTable(
|
|
414
|
+
'Receives messages',
|
|
415
|
+
receives || [],
|
|
416
|
+
receivesSearchTerm,
|
|
417
|
+
setReceivesSearchTerm,
|
|
418
|
+
receivesPage,
|
|
419
|
+
setReceivesPage,
|
|
420
|
+
receivesTypeFilter,
|
|
421
|
+
setReceivesTypeFilter
|
|
422
|
+
)}
|
|
423
|
+
</div>
|
|
424
|
+
)}
|
|
425
|
+
</div>
|
|
426
|
+
</div>
|
|
427
|
+
);
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
export default MessageTable;
|
|
@@ -12,6 +12,7 @@ import Admonition from '@components/MDX/Admonition';
|
|
|
12
12
|
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
|
+
import MessageTable from '@components/MDX/MessageTable/MessageTable.astro';
|
|
15
16
|
import Tabs from '@components/MDX/Tabs/Tabs.astro';
|
|
16
17
|
import TabItem from '@components/MDX/Tabs/TabItem.astro';
|
|
17
18
|
|
|
@@ -39,6 +40,7 @@ const components = (props: any) => {
|
|
|
39
40
|
ChannelInformation: (mdxProp: any) => ChannelInformation({ ...props.data, ...mdxProp }),
|
|
40
41
|
SchemaViewer: (mdxProp: any) => SchemaViewerPortal({ ...props.data, ...mdxProp }),
|
|
41
42
|
Schema: (mdxProp: any) => jsx(Schema, { ...props, ...mdxProp }),
|
|
43
|
+
MessageTable: (mdxProp: any) => jsx(MessageTable, { ...props, ...mdxProp }),
|
|
42
44
|
};
|
|
43
45
|
};
|
|
44
46
|
|
|
@@ -3,7 +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 VersionList from '@components/Lists/VersionList.astro';
|
|
6
|
-
import { getUbiquitousLanguage } from '@utils/collections/domains';
|
|
6
|
+
import { getUbiquitousLanguage, getMessagesForDomain } from '@utils/collections/domains';
|
|
7
7
|
import { getOwner } from '@utils/collections/owners';
|
|
8
8
|
import { buildUrl } from '@utils/url-builder';
|
|
9
9
|
import type { CollectionEntry } from 'astro:content';
|
|
@@ -25,6 +25,8 @@ const ownersRaw = domain.data?.owners || [];
|
|
|
25
25
|
const owners = await Promise.all<ReturnType<typeof getOwner>>(ownersRaw.map(getOwner));
|
|
26
26
|
const filteredOwners = owners.filter((o) => o !== undefined);
|
|
27
27
|
|
|
28
|
+
const messagesForDomain = await getMessagesForDomain(domain);
|
|
29
|
+
|
|
28
30
|
const serviceList = services.map((p) => ({
|
|
29
31
|
label: p.data.name,
|
|
30
32
|
badge: p.collection,
|
|
@@ -33,6 +35,26 @@ const serviceList = services.map((p) => ({
|
|
|
33
35
|
href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
|
|
34
36
|
}));
|
|
35
37
|
|
|
38
|
+
const sendsList = messagesForDomain.sends
|
|
39
|
+
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
40
|
+
.map((p) => ({
|
|
41
|
+
label: p.data.name,
|
|
42
|
+
badge: p.collection,
|
|
43
|
+
tag: `v${p.data.version}`,
|
|
44
|
+
collection: p.collection,
|
|
45
|
+
href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
const receivesList = messagesForDomain.receives
|
|
49
|
+
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
50
|
+
.map((p) => ({
|
|
51
|
+
label: p.data.name,
|
|
52
|
+
badge: p.collection,
|
|
53
|
+
tag: `v${p.data.version}`,
|
|
54
|
+
collection: p.collection,
|
|
55
|
+
href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
|
|
56
|
+
}));
|
|
57
|
+
|
|
36
58
|
const ubiquitousLanguageList = ubiquitousLanguageDictionary?.map((l) => ({
|
|
37
59
|
label: l.name,
|
|
38
60
|
badge: 'Ubiquitous Language',
|
|
@@ -59,12 +81,27 @@ const ownersList = filteredOwners.map((o) => ({
|
|
|
59
81
|
icon="ServerIcon"
|
|
60
82
|
client:load
|
|
61
83
|
/>
|
|
84
|
+
<PillListFlat
|
|
85
|
+
title={`Sends messages (${sendsList.length})`}
|
|
86
|
+
pills={sendsList}
|
|
87
|
+
emptyMessage={`This domain does not send any messages.`}
|
|
88
|
+
color="orange"
|
|
89
|
+
client:load
|
|
90
|
+
/>
|
|
91
|
+
<PillListFlat
|
|
92
|
+
title={`Receives messages (${receivesList.length})`}
|
|
93
|
+
pills={receivesList}
|
|
94
|
+
emptyMessage={`This domain does not receive any messages.`}
|
|
95
|
+
color="orange"
|
|
96
|
+
client:load
|
|
97
|
+
/>
|
|
62
98
|
{
|
|
63
99
|
ubiquitousLanguageList && hasUbiquitousLanguage && (
|
|
64
100
|
<PillListFlat
|
|
65
101
|
title={`Ubiquitous Language Dictionary (${ubiquitousLanguageDictionary?.length})`}
|
|
66
102
|
pills={ubiquitousLanguageList}
|
|
67
103
|
color="pink"
|
|
104
|
+
limit={4}
|
|
68
105
|
emptyMessage={`This domain does not have any documented ubiquitous language.`}
|
|
69
106
|
client:load
|
|
70
107
|
/>
|
|
@@ -26,22 +26,27 @@ 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 sendsList = sends
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
29
|
+
const sendsList = sends
|
|
30
|
+
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
31
|
+
.map((p) => ({
|
|
32
|
+
label: p.data.name,
|
|
33
|
+
badge: p.collection,
|
|
34
|
+
color: p.collection === 'events' ? 'orange' : 'blue',
|
|
35
|
+
collection: p.collection,
|
|
36
|
+
tag: `v${p.data.version}`,
|
|
37
|
+
href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
const receivesList = receives
|
|
41
|
+
.sort((a, b) => a.collection.localeCompare(b.collection))
|
|
42
|
+
.map((p) => ({
|
|
43
|
+
label: p.data.name,
|
|
44
|
+
badge: p.collection,
|
|
45
|
+
color: p.collection === 'events' ? 'orange' : 'blue',
|
|
46
|
+
tag: `v${p.data.version}`,
|
|
47
|
+
collection: p.collection,
|
|
48
|
+
href: buildUrl(`/docs/${p.collection}/${p.data.id}/${p.data.version}`),
|
|
49
|
+
}));
|
|
45
50
|
|
|
46
51
|
const ownersList = filteredOwners.map((o) => ({
|
|
47
52
|
label: o.data.name,
|
|
@@ -94,7 +99,7 @@ const schemaURL = join(publicPath, schemaFilePath || '');
|
|
|
94
99
|
|
|
95
100
|
{
|
|
96
101
|
isRSSEnabled && (
|
|
97
|
-
<div class="mx-auto pb-
|
|
102
|
+
<div class="mx-auto pb-4 w-full max-w-lg divide-y divide-white/5 rounded-xl bg-white/5 border-b border-gray-100 mb-4">
|
|
98
103
|
<span class="text-sm text-black group-data-[hover]:text-black/80 capitalize">Services RSS Feed</span>
|
|
99
104
|
<ul role="list" class="space-y-2 mt-2">
|
|
100
105
|
<li class="has-tooltip rounded-md text-gray-600 group px-1 w-full hover:bg-gradient-to-l hover:from-purple-500 hover:to-purple-700 hover:text-white hover:font-normal ">
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z, defineCollection, reference } from 'astro:content';
|
|
2
|
+
import { glob } from 'astro/loaders';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
|
|
3
5
|
const badge = z.object({
|
|
4
6
|
content: z.string(),
|
|
@@ -252,8 +254,16 @@ const ubiquitousLanguages = defineCollection({
|
|
|
252
254
|
}),
|
|
253
255
|
});
|
|
254
256
|
|
|
257
|
+
const projectDirBase = (() => {
|
|
258
|
+
if (process.platform === 'win32') {
|
|
259
|
+
const projectDirPath = process.env.PROJECT_DIR!.replace(/\\/g, '/');
|
|
260
|
+
return projectDirPath.startsWith('/') ? projectDirPath : `/${projectDirPath}`;
|
|
261
|
+
}
|
|
262
|
+
return process.env.PROJECT_DIR;
|
|
263
|
+
})();
|
|
264
|
+
|
|
255
265
|
const users = defineCollection({
|
|
256
|
-
|
|
266
|
+
loader: glob({ pattern: 'users/*.md', base: projectDirBase, generateId: ({ data }) => data.id as string }),
|
|
257
267
|
schema: z.object({
|
|
258
268
|
id: z.string(),
|
|
259
269
|
name: z.string(),
|
|
@@ -274,7 +284,7 @@ const users = defineCollection({
|
|
|
274
284
|
});
|
|
275
285
|
|
|
276
286
|
const teams = defineCollection({
|
|
277
|
-
|
|
287
|
+
loader: glob({ pattern: 'teams/*.md', base: projectDirBase, generateId: ({ data }) => data.id as string }),
|
|
278
288
|
schema: z.object({
|
|
279
289
|
id: z.string(),
|
|
280
290
|
name: z.string(),
|
|
@@ -11,7 +11,6 @@ const Sidebar: React.FC<{}> = () => {
|
|
|
11
11
|
// Check if this is the first visit after component mounts
|
|
12
12
|
const hasVisited = localStorage.getItem('eventCatalogAIVisited');
|
|
13
13
|
if (!hasVisited || hasVisited === 'false') {
|
|
14
|
-
console.log('setting showHelp to true');
|
|
15
14
|
localStorage.setItem('eventCatalogAIVisited', 'true');
|
|
16
15
|
setShowHelp(true);
|
|
17
16
|
}
|
|
@@ -108,7 +108,7 @@ const generatorConfig = `
|
|
|
108
108
|
<h3 class="text-lg text-white font-semibold mb-3">Quick Setup</h3>
|
|
109
109
|
<Code code={`npm install @eventcatalog/generator-ai`} lang="bash" frame="none" />
|
|
110
110
|
<a
|
|
111
|
-
href="https://www.eventcatalog.dev/
|
|
111
|
+
href="https://www.eventcatalog.dev/features/ai-assistant"
|
|
112
112
|
class="inline-flex items-center text-sm text-white mt-4"
|
|
113
113
|
>
|
|
114
114
|
Learn more about setup →
|
|
@@ -3,7 +3,7 @@ import components from '@components/MDX/components';
|
|
|
3
3
|
|
|
4
4
|
// SideBars
|
|
5
5
|
import { getTeams } from '@utils/teams';
|
|
6
|
-
import { getEntry } from 'astro:content';
|
|
6
|
+
import { getEntry, render } from 'astro:content';
|
|
7
7
|
import type { CollectionEntry } from 'astro:content';
|
|
8
8
|
import OwnersList from '@components/Lists/OwnersList';
|
|
9
9
|
import PillListFlat from '@components/Lists/PillListFlat';
|
|
@@ -15,23 +15,16 @@ export async function getStaticPaths() {
|
|
|
15
15
|
const teams = await getTeams();
|
|
16
16
|
|
|
17
17
|
return teams.map((team) => ({
|
|
18
|
-
params: {
|
|
19
|
-
|
|
20
|
-
id: team.data.id,
|
|
21
|
-
},
|
|
22
|
-
props: {
|
|
23
|
-
type: 'team',
|
|
24
|
-
...team,
|
|
25
|
-
},
|
|
18
|
+
params: { id: team.data.id },
|
|
19
|
+
props: team,
|
|
26
20
|
}));
|
|
27
21
|
}
|
|
28
22
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
const { Content } = await render();
|
|
23
|
+
const props = Astro.props;
|
|
24
|
+
const { Content } = await render(props);
|
|
32
25
|
|
|
33
26
|
const membersRaw = props.data.members || [];
|
|
34
|
-
const members = await Promise.all(membersRaw.map((m) => getEntry(m)));
|
|
27
|
+
const members = (await Promise.all(membersRaw.map((m) => getEntry(m)))).filter(Boolean);
|
|
35
28
|
|
|
36
29
|
const domains = props.data.ownedDomains as CollectionEntry<'domains'>[];
|
|
37
30
|
const services = props.data.ownedServices as CollectionEntry<'services'>[];
|