@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,219 +1,338 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { memo, useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ServerIcon,
|
|
4
|
+
CircleStackIcon,
|
|
5
|
+
ArrowTopRightOnSquareIcon,
|
|
6
|
+
ArrowLongRightIcon,
|
|
7
|
+
BoltIcon,
|
|
8
|
+
ChatBubbleLeftIcon,
|
|
9
|
+
MagnifyingGlassIcon,
|
|
10
|
+
ChevronDownIcon,
|
|
11
|
+
ChevronUpIcon,
|
|
12
|
+
} from '@heroicons/react/24/outline';
|
|
2
13
|
import { buildUrl } from '@utils/url-builder';
|
|
3
14
|
import type { CollectionEntry } from 'astro:content';
|
|
4
|
-
import {
|
|
15
|
+
import { getSpecUrl, getSpecIcon, getSpecLabel, getSpecColor, type Specification } from './specification-utils';
|
|
5
16
|
|
|
6
17
|
interface MessageGridV2Props {
|
|
7
18
|
service: CollectionEntry<'services'>;
|
|
8
19
|
embeded?: boolean;
|
|
20
|
+
specifications?: Specification[];
|
|
9
21
|
}
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
|
|
23
|
+
// Helper to get message icon and color
|
|
24
|
+
const getMessageStyle = (collection: string) => {
|
|
25
|
+
switch (collection) {
|
|
26
|
+
case 'events':
|
|
27
|
+
return { Icon: BoltIcon, color: 'orange', bg: 'bg-orange-50', border: 'border-orange-200', text: 'text-orange-600' };
|
|
28
|
+
case 'commands':
|
|
29
|
+
return { Icon: ChatBubbleLeftIcon, color: 'blue', bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-600' };
|
|
30
|
+
case 'queries':
|
|
31
|
+
return {
|
|
32
|
+
Icon: MagnifyingGlassIcon,
|
|
33
|
+
color: 'emerald',
|
|
34
|
+
bg: 'bg-emerald-50',
|
|
35
|
+
border: 'border-emerald-200',
|
|
36
|
+
text: 'text-emerald-600',
|
|
37
|
+
};
|
|
38
|
+
default:
|
|
39
|
+
return { Icon: BoltIcon, color: 'gray', bg: 'bg-gray-50', border: 'border-gray-200', text: 'text-gray-600' };
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Message Card Component
|
|
44
|
+
const MessageCard = memo(({ message, compact = false }: { message: any; compact?: boolean }) => {
|
|
45
|
+
const { Icon, color } = getMessageStyle(message.collection);
|
|
13
46
|
|
|
14
|
-
|
|
15
|
-
<
|
|
16
|
-
{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
className={`
|
|
47
|
+
return (
|
|
48
|
+
<a
|
|
49
|
+
href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}`)}
|
|
50
|
+
className={`group block bg-white border border-${color}-200 rounded-lg shadow-sm hover:shadow-md hover:border-${color}-300 transition-all`}
|
|
51
|
+
>
|
|
52
|
+
<div className={compact ? 'p-3' : 'p-4'}>
|
|
53
|
+
<div className="flex items-center gap-2 mb-1">
|
|
54
|
+
<div className={`flex items-center justify-center w-7 h-7 bg-${color}-100 rounded-md`}>
|
|
55
|
+
<Icon className={`h-4 w-4 text-${color}-600`} />
|
|
56
|
+
</div>
|
|
57
|
+
<h3
|
|
58
|
+
className={`font-semibold text-gray-900 group-hover:text-${color}-600 transition-colors truncate ${compact ? 'text-sm' : 'text-base'}`}
|
|
23
59
|
>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{message.data.summary && <p className="text-gray-600 text-xs line-clamp-2 mb-4">{message.data.summary}</p>}
|
|
36
|
-
</div>
|
|
37
|
-
</a>
|
|
38
|
-
);
|
|
39
|
-
})}
|
|
40
|
-
</div>
|
|
60
|
+
{message.data.name}
|
|
61
|
+
</h3>
|
|
62
|
+
<span className={`text-[10px] text-${color}-600 font-medium bg-${color}-50 px-1.5 py-0.5 rounded flex-shrink-0`}>
|
|
63
|
+
v{message.data.version}
|
|
64
|
+
</span>
|
|
65
|
+
</div>
|
|
66
|
+
{message.data.summary && (
|
|
67
|
+
<p className={`text-gray-600 line-clamp-2 ${compact ? 'text-xs mt-1' : 'text-sm mt-2'}`}>{message.data.summary}</p>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
</a>
|
|
41
71
|
);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Container Card Component
|
|
75
|
+
const ContainerCard = memo(({ container, type }: { container: any; type: 'reads' | 'writes' }) => {
|
|
76
|
+
const colorClass = type === 'reads' ? 'amber' : 'violet';
|
|
42
77
|
|
|
43
78
|
return (
|
|
44
|
-
<
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
className="inline-flex items-center px-3 py-2 text-sm font-medium text-black border border-gray-300 bg-white rounded-md transition-colors duration-200 hover:bg-gray-50"
|
|
59
|
-
>
|
|
60
|
-
Read documentation
|
|
61
|
-
</a>
|
|
79
|
+
<a
|
|
80
|
+
href={buildUrl(`/docs/containers/${container.data.id}/${container.data.version}`)}
|
|
81
|
+
className={`group block bg-white border rounded-lg shadow-sm hover:shadow-md transition-all ${
|
|
82
|
+
type === 'reads' ? 'border-amber-200 hover:border-amber-300' : 'border-violet-200 hover:border-violet-300'
|
|
83
|
+
}`}
|
|
84
|
+
>
|
|
85
|
+
<div className="p-3">
|
|
86
|
+
<div className="flex items-center gap-2">
|
|
87
|
+
<div className={`flex items-center justify-center w-7 h-7 bg-${colorClass}-100 rounded-md`}>
|
|
88
|
+
<CircleStackIcon className={`h-4 w-4 text-${colorClass}-600`} />
|
|
89
|
+
</div>
|
|
90
|
+
<h3 className={`font-semibold text-gray-900 text-sm group-hover:text-${colorClass}-600 transition-colors truncate`}>
|
|
91
|
+
{container.data.name}
|
|
92
|
+
</h3>
|
|
62
93
|
</div>
|
|
94
|
+
{container.data.summary && <p className="text-xs text-gray-600 mt-1.5 line-clamp-2">{container.data.summary}</p>}
|
|
63
95
|
</div>
|
|
96
|
+
</a>
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Specification Card Component
|
|
101
|
+
const SpecificationCard = memo(
|
|
102
|
+
({ spec, serviceId, serviceVersion }: { spec: any; serviceId: string; serviceVersion: string }) => {
|
|
103
|
+
const color = getSpecColor(spec.type);
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<a
|
|
107
|
+
href={getSpecUrl(spec, serviceId, serviceVersion)}
|
|
108
|
+
className={`group flex items-center gap-3 p-3 bg-white border border-${color}-200 rounded-lg shadow-sm hover:shadow-md hover:border-${color}-300 transition-all`}
|
|
109
|
+
>
|
|
110
|
+
<img src={buildUrl(`/icons/${getSpecIcon(spec.type)}.svg`, true)} alt={`${spec.type} icon`} className="h-6 w-6" />
|
|
111
|
+
<div className="flex-1 min-w-0">
|
|
112
|
+
<h3 className={`font-semibold text-gray-900 text-sm group-hover:text-${color}-600 transition-colors truncate`}>
|
|
113
|
+
{spec.name || spec.filename}
|
|
114
|
+
</h3>
|
|
115
|
+
<p className="text-xs text-gray-500">{getSpecLabel(spec.type)}</p>
|
|
116
|
+
</div>
|
|
117
|
+
</a>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
);
|
|
64
121
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
122
|
+
// Collapsible Message Section Component
|
|
123
|
+
const CollapsibleMessageSection = memo(
|
|
124
|
+
({
|
|
125
|
+
icon: Icon,
|
|
126
|
+
title,
|
|
127
|
+
messages,
|
|
128
|
+
color,
|
|
129
|
+
emptyText,
|
|
130
|
+
embeded = false,
|
|
131
|
+
}: {
|
|
132
|
+
icon: any;
|
|
133
|
+
title: string;
|
|
134
|
+
messages: any[];
|
|
135
|
+
color: string;
|
|
136
|
+
emptyText: string;
|
|
137
|
+
embeded?: boolean;
|
|
138
|
+
}) => {
|
|
139
|
+
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
140
|
+
const hasContent = messages.length > 0;
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div className="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden">
|
|
144
|
+
<div
|
|
145
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
146
|
+
className={`flex items-center justify-between px-5 py-4 cursor-pointer hover:bg-gray-50 transition-colors ${!isCollapsed && hasContent ? 'border-b border-gray-200' : ''}`}
|
|
147
|
+
>
|
|
148
|
+
<div className="flex items-center gap-3">
|
|
149
|
+
<div className={`flex items-center justify-center w-8 h-8 bg-${color}-100 rounded-lg`}>
|
|
150
|
+
<Icon className={`h-4 w-4 text-${color}-600`} />
|
|
75
151
|
</div>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
) : (
|
|
79
|
-
<div className="text-center py-12">
|
|
80
|
-
<p className="text-gray-500 text-sm">No messages</p>
|
|
81
|
-
</div>
|
|
82
|
-
)}
|
|
152
|
+
<h2 className="text-base font-bold text-gray-900">{title}</h2>
|
|
153
|
+
<span className="text-sm text-gray-500 bg-gray-100 px-2 py-0.5 rounded-full font-medium">{messages.length}</span>
|
|
83
154
|
</div>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Reads from ({readsFrom.length})
|
|
92
|
-
</h2>
|
|
93
|
-
</div>
|
|
155
|
+
<div className="text-gray-400">
|
|
156
|
+
{isCollapsed ? <ChevronDownIcon className="h-5 w-5" /> : <ChevronUpIcon className="h-5 w-5" />}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
{!isCollapsed && (
|
|
160
|
+
<div className="p-5">
|
|
161
|
+
{hasContent ? (
|
|
94
162
|
<div className="space-y-3">
|
|
95
|
-
{
|
|
96
|
-
<
|
|
97
|
-
key={container.data.id}
|
|
98
|
-
href={buildUrl(`/docs/containers/${container.data.id}/${container.data.version}`)}
|
|
99
|
-
className="group bg-white border border-orange-200 hover:bg-orange-100 rounded-lg p-3 block transition-all duration-200"
|
|
100
|
-
>
|
|
101
|
-
<div className="flex items-center gap-2">
|
|
102
|
-
<CircleStackIcon className="h-4 w-4 text-orange-500" />
|
|
103
|
-
<h3 className="font-semibold text-gray-900 text-sm group-hover:text-orange-700">{container.data.name}</h3>
|
|
104
|
-
</div>
|
|
105
|
-
{container.data.summary && (
|
|
106
|
-
<p className="text-xs text-gray-600 mt-1 line-clamp-2">{container.data.summary}</p>
|
|
107
|
-
)}
|
|
108
|
-
</a>
|
|
163
|
+
{messages.map((message: any) => (
|
|
164
|
+
<MessageCard key={`${message.data.id}-${message.data.version}`} message={message} compact={embeded} />
|
|
109
165
|
))}
|
|
110
166
|
</div>
|
|
111
|
-
|
|
112
|
-
<div className="
|
|
113
|
-
<
|
|
114
|
-
<div className="w-full h-[3px] bg-orange-200 shadow-[0_0_0_1px_rgba(0,0,0,0.1)]"></div>
|
|
167
|
+
) : (
|
|
168
|
+
<div className="text-center py-4">
|
|
169
|
+
<p className="text-sm text-gray-400">{emptyText}</p>
|
|
115
170
|
</div>
|
|
171
|
+
)}
|
|
172
|
+
</div>
|
|
173
|
+
)}
|
|
174
|
+
</div>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// Collapsible Container Section Component
|
|
180
|
+
const CollapsibleContainerSection = memo(
|
|
181
|
+
({ title, containers, color, type }: { title: string; containers: any[]; color: string; type: 'reads' | 'writes' }) => {
|
|
182
|
+
const [isCollapsed, setIsCollapsed] = useState(false);
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div className="bg-white border border-gray-200 rounded-xl shadow-sm overflow-hidden">
|
|
186
|
+
<div
|
|
187
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
188
|
+
className={`flex items-center justify-between px-5 py-4 cursor-pointer hover:bg-gray-50 transition-colors ${!isCollapsed ? 'border-b border-gray-200' : ''}`}
|
|
189
|
+
>
|
|
190
|
+
<div className="flex items-center gap-3">
|
|
191
|
+
<div className={`flex items-center justify-center w-8 h-8 bg-${color}-100 rounded-lg`}>
|
|
192
|
+
<CircleStackIcon className={`h-4 w-4 text-${color}-600`} />
|
|
116
193
|
</div>
|
|
117
|
-
|
|
194
|
+
<h2 className="text-base font-bold text-gray-900">{title}</h2>
|
|
195
|
+
<span className="text-sm text-gray-500 bg-gray-100 px-2 py-0.5 rounded-full font-medium">{containers.length}</span>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="text-gray-400">
|
|
198
|
+
{isCollapsed ? <ChevronDownIcon className="h-5 w-5" /> : <ChevronUpIcon className="h-5 w-5" />}
|
|
199
|
+
</div>
|
|
118
200
|
</div>
|
|
201
|
+
{!isCollapsed && (
|
|
202
|
+
<div className="p-5">
|
|
203
|
+
<div className="space-y-3">
|
|
204
|
+
{containers.map((container: any) => (
|
|
205
|
+
<ContainerCard key={container.data.id} container={container} type={type} />
|
|
206
|
+
))}
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
)}
|
|
210
|
+
</div>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
119
214
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
215
|
+
export default function MessageGridV2({ service, embeded = false, specifications = [] }: MessageGridV2Props) {
|
|
216
|
+
const { sends = [], receives = [], writesTo = [], readsFrom = [] } = service.data;
|
|
217
|
+
const hasContainers = readsFrom.length > 0 || writesTo.length > 0;
|
|
218
|
+
const hasMessages = receives.length > 0 || sends.length > 0;
|
|
219
|
+
const hasSpecs = specifications.length > 0;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<div className="w-full">
|
|
223
|
+
{/* Service Header - Doc style */}
|
|
224
|
+
<div className="border-b border-gray-200 md:pb-4">
|
|
225
|
+
<div className="flex items-start justify-between">
|
|
226
|
+
<div>
|
|
227
|
+
<h2 className="text-2xl md:text-4xl font-bold text-black">{service.data.name}</h2>
|
|
228
|
+
{service.data.summary && <p className="text-lg pt-2 text-gray-500 font-light">{service.data.summary}</p>}
|
|
229
|
+
</div>
|
|
230
|
+
<div className="flex items-center gap-2 flex-shrink-0">
|
|
231
|
+
<a
|
|
232
|
+
href={buildUrl(`/docs/services/${service.data.id}/${service.data.version}`)}
|
|
233
|
+
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 hover:border-gray-300 transition-all"
|
|
234
|
+
>
|
|
235
|
+
View docs
|
|
236
|
+
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-gray-400" />
|
|
237
|
+
</a>
|
|
238
|
+
<a
|
|
239
|
+
href={buildUrl(`/visualiser/services/${service.data.id}/${service.data.version}`)}
|
|
240
|
+
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-white bg-gray-800 rounded-lg hover:bg-gray-900 transition-all"
|
|
241
|
+
>
|
|
242
|
+
Visualizer
|
|
243
|
+
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-gray-400" />
|
|
244
|
+
</a>
|
|
245
|
+
</div>
|
|
124
246
|
</div>
|
|
247
|
+
</div>
|
|
125
248
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
249
|
+
{/* Service Content */}
|
|
250
|
+
<div className="py-4 space-y-8">
|
|
251
|
+
{/* Specifications */}
|
|
252
|
+
{hasSpecs && (
|
|
253
|
+
<div>
|
|
254
|
+
<div className="flex items-center gap-2 mb-4">
|
|
255
|
+
<h3 className="text-lg font-semibold text-gray-900">Specifications</h3>
|
|
256
|
+
<span className="text-sm text-gray-500 bg-gray-100 px-2.5 py-0.5 rounded-full font-medium">
|
|
257
|
+
{specifications.length}
|
|
258
|
+
</span>
|
|
259
|
+
</div>
|
|
260
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
|
|
261
|
+
{specifications.map((spec: any) => (
|
|
262
|
+
<SpecificationCard
|
|
263
|
+
key={`${spec.type}-${spec.filename}`}
|
|
264
|
+
spec={spec}
|
|
265
|
+
serviceId={service.data.id}
|
|
266
|
+
serviceVersion={service.data.version}
|
|
267
|
+
/>
|
|
268
|
+
))}
|
|
269
|
+
</div>
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
|
|
273
|
+
{/* Message Flow - Two columns side by side */}
|
|
274
|
+
{hasMessages && (
|
|
275
|
+
<div>
|
|
276
|
+
<div className="flex items-center gap-2 mb-4">
|
|
277
|
+
<BoltIcon className="h-5 w-5 text-orange-500" />
|
|
278
|
+
<h3 className="text-lg font-semibold text-gray-900">Messages</h3>
|
|
279
|
+
<span className="text-sm text-gray-500 bg-gray-100 px-2.5 py-0.5 rounded-full font-medium">
|
|
280
|
+
{receives.length + sends.length}
|
|
281
|
+
</span>
|
|
282
|
+
</div>
|
|
283
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
284
|
+
<CollapsibleMessageSection
|
|
285
|
+
icon={ArrowLongRightIcon}
|
|
286
|
+
title="Receives"
|
|
287
|
+
messages={receives}
|
|
288
|
+
color="blue"
|
|
289
|
+
emptyText="No messages received"
|
|
290
|
+
embeded={embeded}
|
|
291
|
+
/>
|
|
292
|
+
<CollapsibleMessageSection
|
|
293
|
+
icon={ArrowLongRightIcon}
|
|
294
|
+
title="Sends"
|
|
295
|
+
messages={sends}
|
|
296
|
+
color="emerald"
|
|
297
|
+
emptyText="No messages sent"
|
|
298
|
+
embeded={embeded}
|
|
299
|
+
/>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
|
|
304
|
+
{/* Container Relationships */}
|
|
305
|
+
{hasContainers && (
|
|
306
|
+
<div>
|
|
307
|
+
<div className="flex items-center gap-2 mb-4">
|
|
308
|
+
<CircleStackIcon className="h-5 w-5 text-amber-500" />
|
|
309
|
+
<h3 className="text-lg font-semibold text-gray-900">Data Sources</h3>
|
|
310
|
+
<span className="text-sm text-gray-500 bg-gray-100 px-2.5 py-0.5 rounded-full font-medium">
|
|
311
|
+
{readsFrom.length + writesTo.length}
|
|
312
|
+
</span>
|
|
313
|
+
</div>
|
|
314
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
142
315
|
{readsFrom.length > 0 && (
|
|
143
|
-
<
|
|
144
|
-
<div className="text-2xl font-bold text-orange-600">{readsFrom.length}</div>
|
|
145
|
-
<div className="text-xs text-gray-600 mt-1">Reads from</div>
|
|
146
|
-
</div>
|
|
316
|
+
<CollapsibleContainerSection title="Reads from" containers={readsFrom} color="amber" type="reads" />
|
|
147
317
|
)}
|
|
148
318
|
{writesTo.length > 0 && (
|
|
149
|
-
<
|
|
150
|
-
<div className="text-2xl font-bold text-purple-600">{writesTo.length}</div>
|
|
151
|
-
<div className="text-xs text-gray-600 mt-1">Writes to</div>
|
|
152
|
-
</div>
|
|
319
|
+
<CollapsibleContainerSection title="Writes to" containers={writesTo} color="violet" type="writes" />
|
|
153
320
|
)}
|
|
154
321
|
</div>
|
|
155
322
|
</div>
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
{/* Arrow from Service to Sends */}
|
|
159
|
-
<div className="absolute right-[30%] top-[25%] -translate-y-1/2 flex items-center justify-center w-16">
|
|
160
|
-
<div className="w-full h-[3px] bg-green-200 shadow-[0_0_0_1px_rgba(0,0,0,0.1)]"></div>
|
|
161
|
-
<div className="absolute right-0 w-4 h-4 border-t-[3px] border-r-[3px] border-green-200 transform rotate-45 translate-x-1 translate-y-[-1px] shadow-[1px_-1px_0_1px_rgba(0,0,0,0.1)]"></div>
|
|
162
|
-
</div>
|
|
323
|
+
)}
|
|
163
324
|
|
|
164
|
-
{/*
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
<h2 className={`font-semibold text-gray-900 flex items-center gap-2 ${embeded ? 'text-sm' : 'text-xl'}`}>
|
|
170
|
-
<ServerIcon className="h-5 w-5 text-emerald-500" />
|
|
171
|
-
Sends ({sends.length})
|
|
172
|
-
</h2>
|
|
325
|
+
{/* Empty State */}
|
|
326
|
+
{!hasMessages && !hasContainers && !hasSpecs && (
|
|
327
|
+
<div className="text-center py-12">
|
|
328
|
+
<div className="flex items-center justify-center w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-2xl">
|
|
329
|
+
<ServerIcon className="h-8 w-8 text-gray-400" />
|
|
173
330
|
</div>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<div className="text-center py-12">
|
|
178
|
-
<p className="text-gray-500 text-sm">No messages</p>
|
|
179
|
-
</div>
|
|
180
|
-
)}
|
|
331
|
+
<p className="text-gray-500">
|
|
332
|
+
This service has no message flows, container relationships, or specifications defined.
|
|
333
|
+
</p>
|
|
181
334
|
</div>
|
|
182
|
-
|
|
183
|
-
{/* Writes To Containers */}
|
|
184
|
-
{writesTo.length > 0 && (
|
|
185
|
-
<div className="bg-purple-50 border border-purple-300 border-dashed rounded-lg p-4 relative">
|
|
186
|
-
{/* Arrow from Service to Writes To */}
|
|
187
|
-
<div className="absolute -left-8 top-1/2 -translate-y-1/2 flex items-center justify-center w-16 z-10">
|
|
188
|
-
<div className="w-full h-[3px] bg-purple-200 shadow-[0_0_0_1px_rgba(0,0,0,0.1)]"></div>
|
|
189
|
-
<div className="absolute right-0 w-4 h-4 border-t-[3px] border-r-[3px] border-purple-200 transform rotate-45 translate-x-1 translate-y-[-1px] shadow-[1px_-1px_0_1px_rgba(0,0,0,0.1)]"></div>
|
|
190
|
-
</div>
|
|
191
|
-
<div className="mb-6">
|
|
192
|
-
<h2 className={`font-semibold text-gray-900 flex items-center gap-2 ${embeded ? 'text-sm' : 'text-xl'}`}>
|
|
193
|
-
<CircleStackIcon className="h-5 w-5 text-purple-500" />
|
|
194
|
-
Writes to ({writesTo.length})
|
|
195
|
-
</h2>
|
|
196
|
-
</div>
|
|
197
|
-
<div className="space-y-3">
|
|
198
|
-
{writesTo.map((container: any) => (
|
|
199
|
-
<a
|
|
200
|
-
key={container.data.id}
|
|
201
|
-
href={buildUrl(`/docs/containers/${container.data.id}/${container.data.version}`)}
|
|
202
|
-
className="group bg-white border border-purple-200 hover:bg-purple-100 rounded-lg p-3 block transition-all duration-200"
|
|
203
|
-
>
|
|
204
|
-
<div className="flex items-center gap-2">
|
|
205
|
-
<CircleStackIcon className="h-4 w-4 text-purple-500" />
|
|
206
|
-
<h3 className="font-semibold text-gray-900 text-sm group-hover:text-purple-700">{container.data.name}</h3>
|
|
207
|
-
</div>
|
|
208
|
-
{container.data.summary && (
|
|
209
|
-
<p className="text-xs text-gray-600 mt-1 line-clamp-2">{container.data.summary}</p>
|
|
210
|
-
)}
|
|
211
|
-
</a>
|
|
212
|
-
))}
|
|
213
|
-
</div>
|
|
214
|
-
</div>
|
|
215
|
-
)}
|
|
216
|
-
</div>
|
|
335
|
+
)}
|
|
217
336
|
</div>
|
|
218
337
|
</div>
|
|
219
338
|
);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { buildUrl } from '@utils/url-builder';
|
|
2
|
+
|
|
3
|
+
export type SpecificationType = 'openapi' | 'asyncapi' | 'graphql';
|
|
4
|
+
|
|
5
|
+
export interface Specification {
|
|
6
|
+
type: SpecificationType;
|
|
7
|
+
path: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
filename: string;
|
|
10
|
+
filenameWithoutExtension: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const getSpecUrl = (spec: Specification, serviceId: string, serviceVersion: string): string => {
|
|
14
|
+
switch (spec.type) {
|
|
15
|
+
case 'openapi':
|
|
16
|
+
return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/spec/${spec.filenameWithoutExtension}`);
|
|
17
|
+
case 'asyncapi':
|
|
18
|
+
return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/asyncapi/${spec.filenameWithoutExtension}`);
|
|
19
|
+
case 'graphql':
|
|
20
|
+
return buildUrl(`/docs/services/${serviceId}/${serviceVersion}/graphql/${spec.filenameWithoutExtension}`);
|
|
21
|
+
default:
|
|
22
|
+
return '#';
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const getSpecIcon = (type: string): string => {
|
|
27
|
+
switch (type) {
|
|
28
|
+
case 'openapi':
|
|
29
|
+
return 'openapi';
|
|
30
|
+
case 'asyncapi':
|
|
31
|
+
return 'asyncapi';
|
|
32
|
+
case 'graphql':
|
|
33
|
+
return 'graphql';
|
|
34
|
+
default:
|
|
35
|
+
return 'json-schema';
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const getSpecLabel = (type: string): string => {
|
|
40
|
+
switch (type) {
|
|
41
|
+
case 'openapi':
|
|
42
|
+
return 'OpenAPI';
|
|
43
|
+
case 'asyncapi':
|
|
44
|
+
return 'AsyncAPI';
|
|
45
|
+
case 'graphql':
|
|
46
|
+
return 'GraphQL';
|
|
47
|
+
default:
|
|
48
|
+
return type;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getSpecColor = (type: string): string => {
|
|
53
|
+
switch (type) {
|
|
54
|
+
case 'openapi':
|
|
55
|
+
return 'green';
|
|
56
|
+
case 'asyncapi':
|
|
57
|
+
return 'purple';
|
|
58
|
+
case 'graphql':
|
|
59
|
+
return 'pink';
|
|
60
|
+
default:
|
|
61
|
+
return 'gray';
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Helper to normalize specifications from service data
|
|
66
|
+
export const getServiceSpecifications = (data: any): Specification[] => {
|
|
67
|
+
const specs = data?.specifications;
|
|
68
|
+
if (!specs) return [];
|
|
69
|
+
|
|
70
|
+
// Handle array format
|
|
71
|
+
if (Array.isArray(specs)) {
|
|
72
|
+
return specs.map((spec: any) => {
|
|
73
|
+
const filename = spec.path?.split('/').pop() || spec.path;
|
|
74
|
+
const filenameWithoutExtension = filename?.replace(/\.[^/.]+$/, '') || '';
|
|
75
|
+
return {
|
|
76
|
+
type: spec.type,
|
|
77
|
+
path: spec.path,
|
|
78
|
+
name: spec.name,
|
|
79
|
+
filename,
|
|
80
|
+
filenameWithoutExtension,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Handle legacy object format
|
|
86
|
+
const result: Specification[] = [];
|
|
87
|
+
if (specs.asyncapiPath) {
|
|
88
|
+
const filename = specs.asyncapiPath.split('/').pop();
|
|
89
|
+
result.push({
|
|
90
|
+
type: 'asyncapi',
|
|
91
|
+
path: specs.asyncapiPath,
|
|
92
|
+
filename,
|
|
93
|
+
filenameWithoutExtension: filename?.replace(/\.[^/.]+$/, '') || '',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (specs.openapiPath) {
|
|
97
|
+
const filename = specs.openapiPath.split('/').pop();
|
|
98
|
+
result.push({
|
|
99
|
+
type: 'openapi',
|
|
100
|
+
path: specs.openapiPath,
|
|
101
|
+
filename,
|
|
102
|
+
filenameWithoutExtension: filename?.replace(/\.[^/.]+$/, '') || '',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
};
|