@eventcatalog/core 3.0.0-beta.9 → 3.0.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 +41 -98
- package/dist/__mocks__/astro-content.cjs +32 -0
- package/dist/__mocks__/astro-content.d.cts +13 -0
- package/dist/__mocks__/astro-content.d.ts +13 -0
- package/dist/__mocks__/astro-content.js +7 -0
- 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 +2 -19
- package/dist/catalog-to-astro-content-directory.d.cts +1 -2
- package/dist/catalog-to-astro-content-directory.d.ts +1 -2
- package/dist/catalog-to-astro-content-directory.js +3 -5
- package/dist/{chunk-R2BJ7MJG.js → chunk-6Z6ARMQS.js} +1 -17
- package/dist/{chunk-A4MGWK5T.js → chunk-BYP43AAT.js} +1 -1
- package/dist/{chunk-RAJ7TGWN.js → chunk-E5Q7TZYT.js} +1 -1
- package/dist/{chunk-TT4LZO2Q.js → chunk-EKGR533N.js} +1 -1
- package/dist/{chunk-2VPX4WIJ.js → chunk-KF5PARQK.js} +1 -1
- package/dist/{chunk-TC3R47V6.js → chunk-VO5WYA44.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +20 -64
- package/dist/eventcatalog.config.d.cts +4 -0
- package/dist/eventcatalog.config.d.ts +4 -0
- package/dist/eventcatalog.js +26 -52
- 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/astro.config.mjs +4 -1
- package/eventcatalog/integrations/eventcatalog-features.ts +69 -0
- package/eventcatalog/public/icons/asyncapi-black.svg +2 -0
- package/eventcatalog/public/icons/graphql-black.svg +1 -0
- package/eventcatalog/public/icons/openapi-black.svg +1 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +994 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanelButton.tsx +24 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +310 -173
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +299 -180
- package/eventcatalog/src/components/Grids/specification-utils.ts +106 -0
- package/eventcatalog/src/components/Header.astro +25 -5
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +14 -3
- package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +95 -90
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +144 -0
- package/eventcatalog/src/components/SchemaExplorer/Pagination.tsx +34 -8
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -2
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsHeader.tsx +140 -109
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +5 -14
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +247 -59
- package/eventcatalog/src/components/SchemaExplorer/SchemaFilters.tsx +64 -126
- package/eventcatalog/src/components/SchemaExplorer/SchemaListItem.tsx +41 -43
- package/eventcatalog/src/components/Search/Search.astro +2 -2
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +25 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/SearchBar.tsx +6 -3
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +44 -16
- package/eventcatalog/src/components/SideNav/SideNav.astro +0 -15
- package/eventcatalog/src/components/Tables/Table.tsx +96 -77
- package/eventcatalog/src/components/Tables/columns/ContainersTableColumns.tsx +108 -74
- package/eventcatalog/src/components/Tables/columns/DomainTableColumns.tsx +74 -55
- package/eventcatalog/src/components/Tables/columns/FlowTableColumns.tsx +36 -36
- package/eventcatalog/src/components/Tables/columns/MessageTableColumns.tsx +110 -77
- package/eventcatalog/src/components/Tables/columns/ServiceTableColumns.tsx +105 -94
- package/eventcatalog/src/components/Tables/columns/SharedColumns.tsx +31 -26
- package/eventcatalog/src/components/Tables/columns/TeamsTableColumns.tsx +115 -215
- package/eventcatalog/src/components/Tables/columns/UserTableColumns.tsx +145 -243
- package/eventcatalog/src/content.config.ts +1 -13
- package/eventcatalog/src/enterprise/ai/chat-api.ts +360 -0
- package/eventcatalog/src/enterprise/auth/[...auth].ts +3 -0
- package/eventcatalog/src/enterprise/auth/login.astro +420 -0
- package/eventcatalog/src/enterprise/collections/index.ts +0 -1
- package/eventcatalog/src/layouts/Footer.astro +8 -5
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +133 -117
- package/eventcatalog/src/pages/_index.astro +243 -559
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +8 -2
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +9 -5
- package/eventcatalog/src/pages/directory/[type]/index.astro +6 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +19 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +7 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +10 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +194 -121
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +94 -70
- package/eventcatalog/src/pages/docs/teams/[id].mdx.ts +36 -0
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +56 -45
- package/eventcatalog/src/pages/docs/users/[id].mdx.ts +36 -0
- package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +178 -0
- package/eventcatalog/src/pages/schemas/explorer/index.astro +7 -157
- package/eventcatalog/src/pages/studio.astro +124 -72
- package/eventcatalog/src/remark-plugins/directives.ts +30 -9
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/container.ts +10 -1
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/domain.ts +17 -7
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/message.ts +10 -1
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/service.ts +11 -4
- package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/shared.ts +14 -0
- package/eventcatalog/src/stores/{sidebar-store.ts → sidebar-store/index.ts} +1 -1
- package/eventcatalog/src/utils/collections/channels.ts +0 -2
- package/eventcatalog/src/utils/collections/commands.ts +0 -2
- package/eventcatalog/src/utils/collections/containers.ts +0 -2
- package/eventcatalog/src/utils/collections/domains.ts +0 -2
- package/eventcatalog/src/utils/collections/entities.ts +0 -2
- package/eventcatalog/src/utils/collections/events.ts +0 -2
- package/eventcatalog/src/utils/collections/flows.ts +0 -2
- package/eventcatalog/src/utils/collections/queries.ts +0 -2
- package/eventcatalog/src/utils/collections/schemas.ts +45 -7
- package/eventcatalog/src/utils/collections/services.ts +0 -2
- package/eventcatalog/src/utils/feature.ts +9 -5
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +1 -1
- package/eventcatalog/src/utils/resource-files.ts +86 -0
- package/package.json +12 -15
- package/default-files-for-collections/changelogs.md +0 -5
- package/default-files-for-collections/channels.md +0 -8
- package/default-files-for-collections/commands.md +0 -8
- package/default-files-for-collections/domains.md +0 -8
- package/default-files-for-collections/events.md +0 -8
- package/default-files-for-collections/flows.md +0 -11
- package/default-files-for-collections/queries.md +0 -8
- package/default-files-for-collections/services.md +0 -8
- package/default-files-for-collections/ubiquitousLanguages.md +0 -7
- package/eventcatalog/src/enterprise/collections/chat-prompts.ts +0 -32
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/Chat.tsx +0 -60
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/ChatMessage.tsx +0 -414
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/ChatSidebar.tsx +0 -169
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/InputModal.tsx +0 -244
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/MentionInput.tsx +0 -211
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/WelcomePromptArea.tsx +0 -176
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/default-prompts.ts +0 -93
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/hooks/ChatProvider.tsx +0 -143
- package/eventcatalog/src/enterprise/eventcatalog-chat/components/windows/ChatWindow.server.tsx +0 -387
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/api/chat.ts +0 -59
- package/eventcatalog/src/enterprise/eventcatalog-chat/pages/chat/index.astro +0 -104
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/ai-provider.ts +0 -140
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/anthropic.ts +0 -28
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/google.ts +0 -41
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/index.ts +0 -26
- package/eventcatalog/src/enterprise/eventcatalog-chat/providers/openai.ts +0 -61
- package/eventcatalog/src/enterprise/eventcatalog-chat/utils/chat-prompts.ts +0 -50
- package/eventcatalog/src/pages/auth/login.astro +0 -280
- package/eventcatalog/src/pages/chat/feature.astro +0 -179
- package/eventcatalog/src/pages/chat/index.astro +0 -10
- package/eventcatalog/src/pages/docs/_default-docs.mdx +0 -25
- package/eventcatalog/src/pages/docs/index.astro +0 -33
- package/eventcatalog/src/pages/nav-index.json.ts +0 -30
- /package/eventcatalog/src/{pages → enterprise}/auth/error.astro +0 -0
- /package/eventcatalog/src/{middleware-auth.ts → enterprise/auth/middleware/middleware-auth.ts} +0 -0
- /package/eventcatalog/src/{middleware.ts → enterprise/auth/middleware/middleware.ts} +0 -0
- /package/eventcatalog/src/{pages/unauthorized/index.astro → enterprise/auth/unauthorized.astro} +0 -0
- /package/eventcatalog/src/{pages → enterprise}/plans/index.astro +0 -0
- /package/eventcatalog/src/{components/SideNav/NestedSideBar → stores/sidebar-store}/builders/flow.ts +0 -0
- /package/eventcatalog/src/{components/SideNav/NestedSideBar/sidebar-builder.ts → stores/sidebar-store/state.ts} +0 -0
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { useState, useMemo, useEffect, useRef } from 'react';
|
|
2
|
-
import { DocumentTextIcon,
|
|
2
|
+
import { DocumentTextIcon, MagnifyingGlassIcon, XMarkIcon } from '@heroicons/react/24/outline';
|
|
3
|
+
import {
|
|
4
|
+
BoltIcon,
|
|
5
|
+
ChatBubbleLeftIcon,
|
|
6
|
+
MagnifyingGlassIcon as MagnifyingGlassSolidIcon,
|
|
7
|
+
CodeBracketIcon,
|
|
8
|
+
} from '@heroicons/react/24/solid';
|
|
3
9
|
import type { CollectionMessageTypes } from '@types';
|
|
10
|
+
|
|
11
|
+
// Specification file types (OpenAPI, AsyncAPI, GraphQL)
|
|
12
|
+
const SPEC_TYPES = ['openapi', 'asyncapi', 'graphql'];
|
|
4
13
|
import semver from 'semver';
|
|
5
|
-
import SchemaFilters from './SchemaFilters';
|
|
6
14
|
import SchemaListItem from './SchemaListItem';
|
|
7
15
|
import SchemaDetailsPanel from './SchemaDetailsPanel';
|
|
8
16
|
import Pagination from './Pagination';
|
|
@@ -22,13 +30,20 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
22
30
|
}
|
|
23
31
|
return '';
|
|
24
32
|
});
|
|
25
|
-
const [
|
|
33
|
+
const [selectedTypes, setSelectedTypes] = useState<Set<CollectionMessageTypes | 'specifications'>>(() => {
|
|
26
34
|
// Load from localStorage
|
|
27
35
|
if (typeof window !== 'undefined') {
|
|
28
|
-
const stored = localStorage.getItem('
|
|
29
|
-
|
|
36
|
+
const stored = localStorage.getItem('schemaRegistrySelectedTypes');
|
|
37
|
+
if (stored) {
|
|
38
|
+
try {
|
|
39
|
+
const parsed = JSON.parse(stored);
|
|
40
|
+
return new Set(parsed);
|
|
41
|
+
} catch {
|
|
42
|
+
return new Set();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
30
45
|
}
|
|
31
|
-
return
|
|
46
|
+
return new Set();
|
|
32
47
|
});
|
|
33
48
|
const [selectedSchemaType, setSelectedSchemaType] = useState<'all' | string>(() => {
|
|
34
49
|
// Load from localStorage
|
|
@@ -41,23 +56,10 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
41
56
|
const [selectedMessage, setSelectedMessage] = useState<SchemaItem | null>(null);
|
|
42
57
|
const [selectedVersion, setSelectedVersion] = useState<string | null>(null);
|
|
43
58
|
const [currentPage, setCurrentPage] = useState(1);
|
|
44
|
-
const [filtersExpanded, setFiltersExpanded] = useState(() => {
|
|
45
|
-
if (typeof window !== 'undefined') {
|
|
46
|
-
const stored = localStorage.getItem('schemaRegistryFiltersExpanded');
|
|
47
|
-
return stored !== null ? stored === 'true' : true;
|
|
48
|
-
}
|
|
49
|
-
return true;
|
|
50
|
-
});
|
|
51
|
-
const [isMounted, setIsMounted] = useState(false);
|
|
52
59
|
const searchInputRef = useRef<HTMLInputElement>(null);
|
|
53
60
|
const selectedItemRef = useRef<HTMLButtonElement>(null);
|
|
54
61
|
const ITEMS_PER_PAGE = 50;
|
|
55
62
|
|
|
56
|
-
// Set mounted state after hydration to prevent FOUC
|
|
57
|
-
useEffect(() => {
|
|
58
|
-
setIsMounted(true);
|
|
59
|
-
}, []);
|
|
60
|
-
|
|
61
63
|
// Function to update URL with query params
|
|
62
64
|
const updateUrlParams = (message: SchemaItem) => {
|
|
63
65
|
if (typeof window === 'undefined') return;
|
|
@@ -138,9 +140,19 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
138
140
|
const filteredMessages = useMemo(() => {
|
|
139
141
|
let result = [...latestMessages];
|
|
140
142
|
|
|
141
|
-
// Filter by message
|
|
142
|
-
if (
|
|
143
|
-
result = result.filter((msg) =>
|
|
143
|
+
// Filter by message types (multi-select)
|
|
144
|
+
if (selectedTypes.size > 0) {
|
|
145
|
+
result = result.filter((msg) => {
|
|
146
|
+
// Check if message matches any selected collection type
|
|
147
|
+
if (selectedTypes.has(msg.collection as CollectionMessageTypes)) {
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
// Check if 'specifications' is selected and this is a spec file
|
|
151
|
+
if (selectedTypes.has('specifications') && SPEC_TYPES.includes(msg.schemaExtension?.toLowerCase() || '')) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
});
|
|
144
156
|
}
|
|
145
157
|
|
|
146
158
|
// Filter by schema type
|
|
@@ -167,7 +179,7 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
167
179
|
});
|
|
168
180
|
|
|
169
181
|
return result;
|
|
170
|
-
}, [latestMessages, searchQuery,
|
|
182
|
+
}, [latestMessages, searchQuery, selectedTypes, selectedSchemaType]);
|
|
171
183
|
|
|
172
184
|
// Pagination
|
|
173
185
|
const totalPages = Math.ceil(filteredMessages.length / ITEMS_PER_PAGE);
|
|
@@ -178,7 +190,7 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
178
190
|
|
|
179
191
|
useEffect(() => {
|
|
180
192
|
setCurrentPage(1);
|
|
181
|
-
}, [searchQuery,
|
|
193
|
+
}, [searchQuery, selectedTypes, selectedSchemaType]);
|
|
182
194
|
|
|
183
195
|
// Load from query string on mount
|
|
184
196
|
useEffect(() => {
|
|
@@ -255,13 +267,6 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
255
267
|
return versionedMessage || versions[0];
|
|
256
268
|
}, [selectedMessage, selectedVersion, messagesByIdAndVersions]);
|
|
257
269
|
|
|
258
|
-
// Save filter expanded state to localStorage
|
|
259
|
-
useEffect(() => {
|
|
260
|
-
if (typeof window !== 'undefined') {
|
|
261
|
-
localStorage.setItem('schemaRegistryFiltersExpanded', filtersExpanded.toString());
|
|
262
|
-
}
|
|
263
|
-
}, [filtersExpanded]);
|
|
264
|
-
|
|
265
270
|
// Save filter states to localStorage
|
|
266
271
|
useEffect(() => {
|
|
267
272
|
if (typeof window !== 'undefined') {
|
|
@@ -271,9 +276,9 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
271
276
|
|
|
272
277
|
useEffect(() => {
|
|
273
278
|
if (typeof window !== 'undefined') {
|
|
274
|
-
localStorage.setItem('
|
|
279
|
+
localStorage.setItem('schemaRegistrySelectedTypes', JSON.stringify(Array.from(selectedTypes)));
|
|
275
280
|
}
|
|
276
|
-
}, [
|
|
281
|
+
}, [selectedTypes]);
|
|
277
282
|
|
|
278
283
|
useEffect(() => {
|
|
279
284
|
if (typeof window !== 'undefined') {
|
|
@@ -312,32 +317,194 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
312
317
|
}
|
|
313
318
|
};
|
|
314
319
|
|
|
320
|
+
// Calculate stats
|
|
321
|
+
const stats = useMemo(() => {
|
|
322
|
+
return {
|
|
323
|
+
total: latestMessages.length,
|
|
324
|
+
events: latestMessages.filter((m) => m.collection === 'events').length,
|
|
325
|
+
commands: latestMessages.filter((m) => m.collection === 'commands').length,
|
|
326
|
+
queries: latestMessages.filter((m) => m.collection === 'queries').length,
|
|
327
|
+
specifications: latestMessages.filter((m) => SPEC_TYPES.includes(m.schemaExtension?.toLowerCase() || '')).length,
|
|
328
|
+
};
|
|
329
|
+
}, [latestMessages]);
|
|
330
|
+
|
|
331
|
+
// Toggle type selection (multi-select)
|
|
332
|
+
const toggleType = (type: CollectionMessageTypes | 'specifications') => {
|
|
333
|
+
setSelectedTypes((prev) => {
|
|
334
|
+
const next = new Set(prev);
|
|
335
|
+
if (next.has(type)) {
|
|
336
|
+
next.delete(type);
|
|
337
|
+
} else {
|
|
338
|
+
next.add(type);
|
|
339
|
+
}
|
|
340
|
+
return next;
|
|
341
|
+
});
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// Clear all type filters
|
|
345
|
+
const clearTypeFilters = () => {
|
|
346
|
+
setSelectedTypes(new Set());
|
|
347
|
+
};
|
|
348
|
+
|
|
315
349
|
return (
|
|
316
350
|
<div className="h-full flex flex-col overflow-hidden">
|
|
317
|
-
{/* Split View */}
|
|
351
|
+
{/* Split View - Full Height */}
|
|
318
352
|
<div className="flex-1 flex gap-4 overflow-hidden">
|
|
319
|
-
{/* Left:
|
|
320
|
-
<div className="w-
|
|
321
|
-
{/*
|
|
322
|
-
<
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
353
|
+
{/* Left: Schema List */}
|
|
354
|
+
<div className="w-[320px] flex-shrink-0 flex flex-col bg-white border border-gray-200 rounded-lg overflow-hidden shadow-sm">
|
|
355
|
+
{/* Search Header */}
|
|
356
|
+
<div className="flex-shrink-0 p-3 border-b border-gray-200">
|
|
357
|
+
{/* Search + Format Filter Row */}
|
|
358
|
+
<div className="flex items-center gap-2">
|
|
359
|
+
<div className="relative flex-1">
|
|
360
|
+
<div className="pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3">
|
|
361
|
+
<MagnifyingGlassIcon className="h-4 w-4 text-gray-400" />
|
|
362
|
+
</div>
|
|
363
|
+
<input
|
|
364
|
+
ref={searchInputRef}
|
|
365
|
+
type="text"
|
|
366
|
+
placeholder="Search schemas..."
|
|
367
|
+
value={searchQuery}
|
|
368
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
369
|
+
className="w-full rounded-md border border-gray-200 bg-white py-2 pl-9 pr-8 text-sm placeholder:text-gray-400 focus:border-gray-300 focus:outline-none focus:ring-1 focus:ring-gray-300 transition-all"
|
|
370
|
+
/>
|
|
371
|
+
{searchQuery && (
|
|
372
|
+
<button onClick={() => setSearchQuery('')} className="absolute inset-y-0 right-0 flex items-center pr-2.5">
|
|
373
|
+
<XMarkIcon className="h-4 w-4 text-gray-400 hover:text-gray-600" />
|
|
374
|
+
</button>
|
|
375
|
+
)}
|
|
376
|
+
</div>
|
|
377
|
+
{/* Format Dropdown */}
|
|
378
|
+
{schemaTypes.length > 1 && (
|
|
379
|
+
<select
|
|
380
|
+
value={selectedSchemaType}
|
|
381
|
+
onChange={(e) => setSelectedSchemaType(e.target.value)}
|
|
382
|
+
className="flex-shrink-0 text-xs font-medium text-gray-600 bg-white border border-gray-200 rounded-md px-2 py-2 focus:outline-none focus:ring-1 focus:ring-gray-300 focus:border-gray-300 cursor-pointer hover:bg-gray-50 transition-colors"
|
|
383
|
+
>
|
|
384
|
+
<option value="all">All formats</option>
|
|
385
|
+
{schemaTypes.map((type) => {
|
|
386
|
+
const labels: Record<string, string> = {
|
|
387
|
+
json: 'JSON',
|
|
388
|
+
asyncapi: 'AsyncAPI',
|
|
389
|
+
openapi: 'OpenAPI',
|
|
390
|
+
graphql: 'GraphQL',
|
|
391
|
+
avro: 'Avro',
|
|
392
|
+
proto: 'Protobuf',
|
|
393
|
+
};
|
|
394
|
+
return (
|
|
395
|
+
<option key={type} value={type}>
|
|
396
|
+
{labels[type] || type.charAt(0).toUpperCase() + type.slice(1)}
|
|
397
|
+
</option>
|
|
398
|
+
);
|
|
399
|
+
})}
|
|
400
|
+
</select>
|
|
401
|
+
)}
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
{/* Type Filter - Multi-select chips */}
|
|
405
|
+
<div className="flex items-center gap-1 mt-2 flex-wrap">
|
|
406
|
+
{stats.events > 0 && (
|
|
407
|
+
<button
|
|
408
|
+
onClick={() => toggleType('events')}
|
|
409
|
+
className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium transition-all border ${
|
|
410
|
+
selectedTypes.has('events')
|
|
411
|
+
? 'bg-orange-50 text-orange-700 border-orange-200'
|
|
412
|
+
: 'text-gray-600 border-gray-200 hover:bg-gray-50'
|
|
413
|
+
}`}
|
|
414
|
+
title="Events"
|
|
415
|
+
>
|
|
416
|
+
<BoltIcon className={`h-3.5 w-3.5 ${selectedTypes.has('events') ? 'text-orange-500' : 'text-orange-400'}`} />
|
|
417
|
+
<span>Events</span>
|
|
418
|
+
<span className={`tabular-nums ${selectedTypes.has('events') ? 'text-orange-500' : 'text-gray-400'}`}>
|
|
419
|
+
{stats.events}
|
|
420
|
+
</span>
|
|
421
|
+
</button>
|
|
422
|
+
)}
|
|
423
|
+
{stats.commands > 0 && (
|
|
424
|
+
<button
|
|
425
|
+
onClick={() => toggleType('commands')}
|
|
426
|
+
className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium transition-all border ${
|
|
427
|
+
selectedTypes.has('commands')
|
|
428
|
+
? 'bg-blue-50 text-blue-700 border-blue-200'
|
|
429
|
+
: 'text-gray-600 border-gray-200 hover:bg-gray-50'
|
|
430
|
+
}`}
|
|
431
|
+
title="Commands"
|
|
432
|
+
>
|
|
433
|
+
<ChatBubbleLeftIcon
|
|
434
|
+
className={`h-3.5 w-3.5 ${selectedTypes.has('commands') ? 'text-blue-500' : 'text-blue-400'}`}
|
|
435
|
+
/>
|
|
436
|
+
<span>Commands</span>
|
|
437
|
+
<span className={`tabular-nums ${selectedTypes.has('commands') ? 'text-blue-500' : 'text-gray-400'}`}>
|
|
438
|
+
{stats.commands}
|
|
439
|
+
</span>
|
|
440
|
+
</button>
|
|
441
|
+
)}
|
|
442
|
+
{stats.queries > 0 && (
|
|
443
|
+
<button
|
|
444
|
+
onClick={() => toggleType('queries')}
|
|
445
|
+
className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium transition-all border ${
|
|
446
|
+
selectedTypes.has('queries')
|
|
447
|
+
? 'bg-green-50 text-green-700 border-green-200'
|
|
448
|
+
: 'text-gray-600 border-gray-200 hover:bg-gray-50'
|
|
449
|
+
}`}
|
|
450
|
+
title="Queries"
|
|
451
|
+
>
|
|
452
|
+
<MagnifyingGlassSolidIcon
|
|
453
|
+
className={`h-3.5 w-3.5 ${selectedTypes.has('queries') ? 'text-green-500' : 'text-green-400'}`}
|
|
454
|
+
/>
|
|
455
|
+
<span>Queries</span>
|
|
456
|
+
<span className={`tabular-nums ${selectedTypes.has('queries') ? 'text-green-500' : 'text-gray-400'}`}>
|
|
457
|
+
{stats.queries}
|
|
458
|
+
</span>
|
|
459
|
+
</button>
|
|
460
|
+
)}
|
|
461
|
+
{stats.specifications > 0 && (
|
|
462
|
+
<button
|
|
463
|
+
onClick={() => toggleType('specifications')}
|
|
464
|
+
className={`inline-flex items-center gap-1.5 px-2 py-1 rounded-md text-xs font-medium transition-all border ${
|
|
465
|
+
selectedTypes.has('specifications')
|
|
466
|
+
? 'bg-purple-50 text-purple-700 border-purple-200'
|
|
467
|
+
: 'text-gray-600 border-gray-200 hover:bg-gray-50'
|
|
468
|
+
}`}
|
|
469
|
+
title="Specifications (OpenAPI, AsyncAPI, etc.)"
|
|
470
|
+
>
|
|
471
|
+
<CodeBracketIcon
|
|
472
|
+
className={`h-3.5 w-3.5 ${selectedTypes.has('specifications') ? 'text-purple-500' : 'text-purple-400'}`}
|
|
473
|
+
/>
|
|
474
|
+
<span>Specs</span>
|
|
475
|
+
<span className={`tabular-nums ${selectedTypes.has('specifications') ? 'text-purple-500' : 'text-gray-400'}`}>
|
|
476
|
+
{stats.specifications}
|
|
477
|
+
</span>
|
|
478
|
+
</button>
|
|
479
|
+
)}
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
{/* Results Count Bar */}
|
|
484
|
+
<div className="flex-shrink-0 px-3 py-1.5 bg-gray-50 border-b border-gray-100 flex items-center justify-between">
|
|
485
|
+
<span className="text-xs text-gray-500">
|
|
486
|
+
{filteredMessages.length === stats.total
|
|
487
|
+
? `${stats.total} schemas`
|
|
488
|
+
: `${filteredMessages.length} of ${stats.total} schemas`}
|
|
489
|
+
</span>
|
|
490
|
+
{(searchQuery || selectedTypes.size > 0 || selectedSchemaType !== 'all') && (
|
|
491
|
+
<button
|
|
492
|
+
onClick={() => {
|
|
493
|
+
setSearchQuery('');
|
|
494
|
+
clearTypeFilters();
|
|
495
|
+
setSelectedSchemaType('all');
|
|
496
|
+
}}
|
|
497
|
+
className="text-xs text-gray-500 hover:text-gray-700"
|
|
498
|
+
>
|
|
499
|
+
Clear filters
|
|
500
|
+
</button>
|
|
501
|
+
)}
|
|
502
|
+
</div>
|
|
336
503
|
|
|
337
504
|
{/* Schema List - Independently Scrollable */}
|
|
338
505
|
<div className="flex-1 overflow-y-auto">
|
|
339
506
|
{paginatedMessages.length > 0 ? (
|
|
340
|
-
<div className="divide-y divide-gray-
|
|
507
|
+
<div className="divide-y divide-gray-100">
|
|
341
508
|
{paginatedMessages.map((message) => {
|
|
342
509
|
// For services, also check spec type to determine if selected
|
|
343
510
|
const isSelected =
|
|
@@ -368,10 +535,26 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
368
535
|
})}
|
|
369
536
|
</div>
|
|
370
537
|
) : (
|
|
371
|
-
<div className="flex flex-col items-center justify-center h-full p-
|
|
372
|
-
<
|
|
538
|
+
<div className="flex flex-col items-center justify-center h-full p-6 text-center">
|
|
539
|
+
<div className="flex items-center justify-center w-12 h-12 rounded-full bg-gray-100 mb-3">
|
|
540
|
+
<MagnifyingGlassIcon className="h-6 w-6 text-gray-400" />
|
|
541
|
+
</div>
|
|
373
542
|
<h3 className="text-sm font-semibold text-gray-900 mb-1">No schemas found</h3>
|
|
374
|
-
<p className="text-xs text-gray-500
|
|
543
|
+
<p className="text-xs text-gray-500 mb-3 max-w-[200px]">
|
|
544
|
+
{searchQuery ? `No results for "${searchQuery}"` : 'Try adjusting your filters'}
|
|
545
|
+
</p>
|
|
546
|
+
{(searchQuery || selectedTypes.size > 0 || selectedSchemaType !== 'all') && (
|
|
547
|
+
<button
|
|
548
|
+
onClick={() => {
|
|
549
|
+
setSearchQuery('');
|
|
550
|
+
clearTypeFilters();
|
|
551
|
+
setSelectedSchemaType('all');
|
|
552
|
+
}}
|
|
553
|
+
className="text-xs font-medium text-gray-600 hover:text-gray-900"
|
|
554
|
+
>
|
|
555
|
+
Clear filters
|
|
556
|
+
</button>
|
|
557
|
+
)}
|
|
375
558
|
</div>
|
|
376
559
|
)}
|
|
377
560
|
</div>
|
|
@@ -391,10 +574,15 @@ export default function SchemaExplorer({ schemas, apiAccessEnabled = false }: Sc
|
|
|
391
574
|
apiAccessEnabled={apiAccessEnabled}
|
|
392
575
|
/>
|
|
393
576
|
) : (
|
|
394
|
-
<div className="h-full flex items-center justify-center
|
|
395
|
-
<div className="text-center">
|
|
396
|
-
<
|
|
397
|
-
|
|
577
|
+
<div className="h-full flex items-center justify-center">
|
|
578
|
+
<div className="text-center max-w-xs">
|
|
579
|
+
<div className="flex items-center justify-center w-14 h-14 mx-auto mb-4 rounded-xl bg-gray-50 border border-gray-100">
|
|
580
|
+
<DocumentTextIcon className="h-7 w-7 text-gray-400" />
|
|
581
|
+
</div>
|
|
582
|
+
<h3 className="text-sm font-semibold text-gray-900 mb-1">Select a schema</h3>
|
|
583
|
+
<p className="text-sm text-gray-500 leading-relaxed">
|
|
584
|
+
Choose a schema from the list to view details, compare versions, and access raw code
|
|
585
|
+
</p>
|
|
398
586
|
</div>
|
|
399
587
|
</div>
|
|
400
588
|
)}
|
|
@@ -1,171 +1,109 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { AdjustmentsHorizontalIcon, ChevronUpIcon, ChevronDownIcon } from '@heroicons/react/24/outline';
|
|
2
|
+
import { buildUrl } from '@utils/url-builder';
|
|
3
3
|
import { getSchemaTypeLabel } from './utils';
|
|
4
4
|
import type { SchemaItem } from './types';
|
|
5
5
|
|
|
6
6
|
interface SchemaFiltersProps {
|
|
7
|
-
searchQuery: string;
|
|
8
|
-
onSearchChange: (query: string) => void;
|
|
9
|
-
selectedType: 'all' | CollectionMessageTypes | 'services';
|
|
10
|
-
onTypeChange: (type: 'all' | CollectionMessageTypes | 'services') => void;
|
|
11
7
|
selectedSchemaType: string;
|
|
12
8
|
onSchemaTypeChange: (type: string) => void;
|
|
13
9
|
schemaTypes: string[];
|
|
14
10
|
latestMessages: SchemaItem[];
|
|
15
11
|
filtersExpanded: boolean;
|
|
16
12
|
onToggleExpanded: () => void;
|
|
17
|
-
searchInputRef: React.RefObject<HTMLInputElement>;
|
|
18
13
|
isMounted: boolean;
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
export default function SchemaFilters({
|
|
22
|
-
searchQuery,
|
|
23
|
-
onSearchChange,
|
|
24
|
-
selectedType,
|
|
25
|
-
onTypeChange,
|
|
26
17
|
selectedSchemaType,
|
|
27
18
|
onSchemaTypeChange,
|
|
28
19
|
schemaTypes,
|
|
29
20
|
latestMessages,
|
|
30
21
|
filtersExpanded,
|
|
31
22
|
onToggleExpanded,
|
|
32
|
-
searchInputRef,
|
|
33
23
|
isMounted,
|
|
34
24
|
}: SchemaFiltersProps) {
|
|
35
|
-
const
|
|
25
|
+
const hasActiveFilters = selectedSchemaType !== 'all';
|
|
26
|
+
|
|
27
|
+
// Only show this component if there are schema types to filter
|
|
28
|
+
if (schemaTypes.length <= 1) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
36
31
|
|
|
37
32
|
return (
|
|
38
|
-
<div className="flex-shrink-0 border-b border-gray-
|
|
33
|
+
<div className="flex-shrink-0 border-b border-gray-100 bg-white">
|
|
39
34
|
{/* Filter Header */}
|
|
40
35
|
<button
|
|
41
36
|
onClick={onToggleExpanded}
|
|
42
|
-
className="w-full flex items-center justify-between
|
|
37
|
+
className="w-full flex items-center justify-between px-3 py-1.5 hover:bg-gray-50 transition-colors"
|
|
43
38
|
>
|
|
44
|
-
<div className="flex items-center gap-
|
|
45
|
-
<
|
|
46
|
-
<span className="text-
|
|
47
|
-
{
|
|
48
|
-
<span className="inline-flex items-center rounded-full bg-
|
|
49
|
-
|
|
39
|
+
<div className="flex items-center gap-1.5">
|
|
40
|
+
<AdjustmentsHorizontalIcon className="h-3.5 w-3.5 text-gray-400" />
|
|
41
|
+
<span className="text-[11px] font-medium text-gray-600">Format</span>
|
|
42
|
+
{hasActiveFilters && (
|
|
43
|
+
<span className="inline-flex items-center justify-center w-4 h-4 rounded-full bg-gray-900 text-[10px] font-medium text-white">
|
|
44
|
+
1
|
|
50
45
|
</span>
|
|
51
46
|
)}
|
|
52
47
|
</div>
|
|
53
48
|
{filtersExpanded ? (
|
|
54
|
-
<ChevronUpIcon className="h-
|
|
49
|
+
<ChevronUpIcon className="h-3.5 w-3.5 text-gray-400" />
|
|
55
50
|
) : (
|
|
56
|
-
<ChevronDownIcon className="h-
|
|
51
|
+
<ChevronDownIcon className="h-3.5 w-3.5 text-gray-400" />
|
|
57
52
|
)}
|
|
58
53
|
</button>
|
|
59
54
|
|
|
60
|
-
{/* Collapsible Filter Content
|
|
55
|
+
{/* Collapsible Filter Content */}
|
|
61
56
|
{isMounted && filtersExpanded && (
|
|
62
|
-
<div className="
|
|
63
|
-
{/*
|
|
64
|
-
<div className="
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
<input
|
|
73
|
-
ref={searchInputRef}
|
|
74
|
-
type="text"
|
|
75
|
-
id="search"
|
|
76
|
-
placeholder="Search schemas..."
|
|
77
|
-
value={searchQuery}
|
|
78
|
-
onChange={(e) => onSearchChange(e.target.value)}
|
|
79
|
-
className="w-full rounded-md border-gray-300 shadow-sm focus:border-primary focus:ring-primary text-xs pl-8 pr-8 py-1.5 border"
|
|
80
|
-
/>
|
|
81
|
-
{searchQuery && (
|
|
82
|
-
<button onClick={() => onSearchChange('')} className="absolute inset-y-0 right-0 flex items-center pr-2.5">
|
|
83
|
-
<XMarkIcon className="h-4 w-4 text-gray-400 hover:text-gray-600" />
|
|
84
|
-
</button>
|
|
85
|
-
)}
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
{/* Message Type Filter */}
|
|
90
|
-
<div className="mb-3">
|
|
91
|
-
<label htmlFor="messageType" className="block text-xs font-medium text-gray-700 mb-1.5">
|
|
92
|
-
Message Type
|
|
93
|
-
</label>
|
|
94
|
-
<select
|
|
95
|
-
id="messageType"
|
|
96
|
-
value={selectedType}
|
|
97
|
-
onChange={(e) => onTypeChange(e.target.value as typeof selectedType)}
|
|
98
|
-
className="w-full rounded-md border-gray-300 shadow-sm focus:border-primary focus:ring-primary text-xs px-2.5 py-1.5 border"
|
|
99
|
-
>
|
|
100
|
-
<option value="all">All ({latestMessages.length})</option>
|
|
101
|
-
<option value="events">Events ({latestMessages.filter((m) => m.collection === 'events').length})</option>
|
|
102
|
-
<option value="commands">Commands ({latestMessages.filter((m) => m.collection === 'commands').length})</option>
|
|
103
|
-
<option value="queries">Queries ({latestMessages.filter((m) => m.collection === 'queries').length})</option>
|
|
104
|
-
<option value="services">Services ({latestMessages.filter((m) => m.collection === 'services').length})</option>
|
|
105
|
-
</select>
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
{/* Schema Type Filter */}
|
|
109
|
-
<div className="mb-3">
|
|
110
|
-
<label htmlFor="schemaType" className="block text-xs font-medium text-gray-700 mb-1.5">
|
|
111
|
-
Schema Format
|
|
112
|
-
</label>
|
|
113
|
-
<select
|
|
114
|
-
id="schemaType"
|
|
115
|
-
value={selectedSchemaType}
|
|
116
|
-
onChange={(e) => onSchemaTypeChange(e.target.value)}
|
|
117
|
-
className="w-full rounded-md border-gray-300 shadow-sm focus:border-primary focus:ring-primary text-xs px-2.5 py-1.5 border"
|
|
57
|
+
<div className="px-3 pb-2">
|
|
58
|
+
{/* Schema Format Filter as chips */}
|
|
59
|
+
<div className="flex flex-wrap gap-1">
|
|
60
|
+
<button
|
|
61
|
+
onClick={() => onSchemaTypeChange('all')}
|
|
62
|
+
className={`inline-flex items-center px-2 py-0.5 rounded text-[11px] font-medium transition-all ${
|
|
63
|
+
selectedSchemaType === 'all'
|
|
64
|
+
? 'bg-gray-900 text-white'
|
|
65
|
+
: 'bg-gray-50 text-gray-600 border border-gray-200 hover:bg-gray-100'
|
|
66
|
+
}`}
|
|
118
67
|
>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
</div>
|
|
68
|
+
All
|
|
69
|
+
</button>
|
|
70
|
+
{schemaTypes.map((type) => {
|
|
71
|
+
const count = latestMessages.filter((m) => m.schemaExtension?.toLowerCase() === type).length;
|
|
72
|
+
const ext = type.toLowerCase();
|
|
73
|
+
const hasIcon = ['openapi', 'asyncapi', 'graphql', 'avro', 'json', 'proto'].includes(ext);
|
|
74
|
+
const iconName = ext === 'json' ? 'json-schema' : ext;
|
|
127
75
|
|
|
128
|
-
|
|
129
|
-
{activeFilterCount > 0 && (
|
|
130
|
-
<div className="pt-2 border-t border-gray-200">
|
|
131
|
-
<div className="flex flex-wrap items-center gap-1.5">
|
|
132
|
-
{searchQuery && (
|
|
133
|
-
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-blue-100 text-blue-800 rounded">
|
|
134
|
-
{searchQuery.substring(0, 15)}
|
|
135
|
-
{searchQuery.length > 15 ? '...' : ''}
|
|
136
|
-
<button onClick={() => onSearchChange('')}>
|
|
137
|
-
<XMarkIcon className="h-3 w-3" />
|
|
138
|
-
</button>
|
|
139
|
-
</span>
|
|
140
|
-
)}
|
|
141
|
-
{selectedType !== 'all' && (
|
|
142
|
-
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-blue-100 text-blue-800 rounded">
|
|
143
|
-
{selectedType}
|
|
144
|
-
<button onClick={() => onTypeChange('all')}>
|
|
145
|
-
<XMarkIcon className="h-3 w-3" />
|
|
146
|
-
</button>
|
|
147
|
-
</span>
|
|
148
|
-
)}
|
|
149
|
-
{selectedSchemaType !== 'all' && (
|
|
150
|
-
<span className="inline-flex items-center gap-1 px-1.5 py-0.5 text-xs bg-blue-100 text-blue-800 rounded">
|
|
151
|
-
{getSchemaTypeLabel(selectedSchemaType)}
|
|
152
|
-
<button onClick={() => onSchemaTypeChange('all')}>
|
|
153
|
-
<XMarkIcon className="h-3 w-3" />
|
|
154
|
-
</button>
|
|
155
|
-
</span>
|
|
156
|
-
)}
|
|
76
|
+
return (
|
|
157
77
|
<button
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
78
|
+
key={type}
|
|
79
|
+
onClick={() => onSchemaTypeChange(type)}
|
|
80
|
+
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded text-[11px] font-medium transition-all ${
|
|
81
|
+
selectedSchemaType === type
|
|
82
|
+
? 'bg-gray-900 text-white'
|
|
83
|
+
: 'bg-gray-50 text-gray-600 border border-gray-200 hover:bg-gray-100'
|
|
84
|
+
}`}
|
|
164
85
|
>
|
|
165
|
-
|
|
86
|
+
{hasIcon && (
|
|
87
|
+
<img
|
|
88
|
+
src={buildUrl(`/icons/${iconName}.svg`, true)}
|
|
89
|
+
alt={`${type} icon`}
|
|
90
|
+
className={`h-3 w-3 ${selectedSchemaType === type ? 'brightness-0 invert' : 'opacity-60'}`}
|
|
91
|
+
/>
|
|
92
|
+
)}
|
|
93
|
+
{getSchemaTypeLabel(type)}
|
|
94
|
+
<span className={`text-[10px] tabular-nums ${selectedSchemaType === type ? 'text-white/60' : 'text-gray-400'}`}>
|
|
95
|
+
{count}
|
|
96
|
+
</span>
|
|
166
97
|
</button>
|
|
167
|
-
|
|
168
|
-
|
|
98
|
+
);
|
|
99
|
+
})}
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
{/* Clear filter */}
|
|
103
|
+
{hasActiveFilters && (
|
|
104
|
+
<button onClick={() => onSchemaTypeChange('all')} className="mt-1.5 text-[11px] text-gray-500 hover:text-gray-700">
|
|
105
|
+
Clear
|
|
106
|
+
</button>
|
|
169
107
|
)}
|
|
170
108
|
</div>
|
|
171
109
|
)}
|