@eventcatalog/core 5.0.0-beta.1 → 5.0.0-beta.3

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.
Files changed (64) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-AYNZXUB5.js → chunk-3PKS2IIP.js} +4 -4
  6. package/dist/{chunk-Q6SD5SNQ.js → chunk-423S2KHN.js} +1 -1
  7. package/dist/{chunk-UDS3SYLZ.js → chunk-6OC46WQJ.js} +1 -1
  8. package/dist/{chunk-K2ACDO7Y.js → chunk-BH2F5WPN.js} +1 -1
  9. package/dist/{chunk-S2QGT7ZF.js → chunk-GYIVJXOJ.js} +1 -1
  10. package/dist/{chunk-KYJZJLBD.js → chunk-NDJOAITI.js} +1 -1
  11. package/dist/constants.cjs +1 -1
  12. package/dist/constants.js +1 -1
  13. package/dist/eventcatalog.cjs +1 -1
  14. package/dist/eventcatalog.js +13 -13
  15. package/dist/federation/federate.js +4 -4
  16. package/dist/federation/source-provider.js +2 -2
  17. package/dist/generate.cjs +1 -1
  18. package/dist/generate.js +3 -3
  19. package/dist/utils/cli-logger.cjs +1 -1
  20. package/dist/utils/cli-logger.js +2 -2
  21. package/eventcatalog/src/components/Grids/utils.tsx +0 -23
  22. package/eventcatalog/src/components/MDX/CodeGroup/CodeGroup.tsx +6 -1
  23. package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +12 -4
  24. package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +4 -62
  25. package/eventcatalog/src/components/Tables/Discover/columns.tsx +17 -150
  26. package/eventcatalog/src/components/Tables/Resources/ResourcesTable.tsx +425 -0
  27. package/eventcatalog/src/components/Tables/RowActionsMenu.tsx +157 -0
  28. package/eventcatalog/src/components/Tables/TablePagination.tsx +82 -0
  29. package/eventcatalog/src/features/ai/chat-api.ts +3 -3
  30. package/eventcatalog/src/features/mcp/apps/generated/viewer.html +75 -74
  31. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +0 -2
  32. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +52 -63
  33. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +34 -46
  34. package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +11 -29
  35. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_ResourcesPage.astro +79 -0
  36. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +32 -14
  37. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +63 -58
  38. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +2 -62
  39. package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +13 -0
  40. package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +24 -42
  41. package/eventcatalog/src/stores/sidebar-store/builders/flow.ts +2 -0
  42. package/eventcatalog/src/stores/sidebar-store/builders/message.ts +2 -0
  43. package/eventcatalog/src/stores/sidebar-store/builders/service.ts +23 -23
  44. package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +13 -0
  45. package/eventcatalog/src/stores/sidebar-store/builders/system.ts +18 -27
  46. package/eventcatalog/src/stores/sidebar-store/state.ts +5 -0
  47. package/eventcatalog/src/styles/tailwind.css +2 -2
  48. package/eventcatalog/src/utils/collections/channels.ts +56 -1
  49. package/eventcatalog/src/utils/collections/flows.ts +50 -1
  50. package/eventcatalog/src/utils/collections/message-connections.ts +60 -0
  51. package/eventcatalog/src/utils/collections/message-triggers.ts +2 -1
  52. package/eventcatalog/src/utils/collections/resource-owners.ts +193 -0
  53. package/eventcatalog/src/utils/collections/resources.ts +310 -0
  54. package/eventcatalog/src/utils/collections/util.ts +31 -0
  55. package/package.json +7 -7
  56. package/eventcatalog/src/components/Grids/DomainGrid.tsx +0 -838
  57. package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -344
  58. package/eventcatalog/src/components/Grids/SystemGrid.tsx +0 -185
  59. package/eventcatalog/src/components/Grids/components.tsx +0 -170
  60. package/eventcatalog/src/components/Grids/message-link.ts +0 -38
  61. package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +0 -294
  62. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.spec.ts +0 -65
  63. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_resources.ts +0 -46
  64. package/dist/{chunk-A2RZR3U4.js → chunk-6K7XZAYI.js} +3 -3
@@ -1,344 +0,0 @@
1
- import { memo, useState } from 'react';
2
- import {
3
- ServerIcon,
4
- CircleStackIcon,
5
- ArrowLongRightIcon,
6
- BoltIcon,
7
- ChatBubbleLeftIcon,
8
- MagnifyingGlassIcon,
9
- ChevronDownIcon,
10
- ChevronUpIcon,
11
- } from '@heroicons/react/24/outline';
12
- import { buildUrl } from '@utils/url-builder';
13
- import type { CollectionEntry } from 'astro:content';
14
- import { getSpecUrl, getSpecIcon, getSpecLabel, getSpecColor, type Specification } from './specification-utils';
15
-
16
- interface MessageGridV2Props {
17
- service: CollectionEntry<'agents'> | CollectionEntry<'services'>;
18
- embeded?: boolean;
19
- specifications?: Specification[];
20
- }
21
-
22
- // Helper to get message icon and color
23
- const getMessageStyle = (collection: string) => {
24
- switch (collection) {
25
- case 'events':
26
- return { Icon: BoltIcon, color: 'orange', bg: 'bg-orange-50', border: 'border-orange-200', text: 'text-orange-600' };
27
- case 'commands':
28
- return { Icon: ChatBubbleLeftIcon, color: 'blue', bg: 'bg-blue-50', border: 'border-blue-200', text: 'text-blue-600' };
29
- case 'queries':
30
- return {
31
- Icon: MagnifyingGlassIcon,
32
- color: 'emerald',
33
- bg: 'bg-emerald-50',
34
- border: 'border-emerald-200',
35
- text: 'text-emerald-600',
36
- };
37
- default:
38
- return { Icon: BoltIcon, color: 'gray', bg: 'bg-gray-50', border: 'border-gray-200', text: 'text-gray-600' };
39
- }
40
- };
41
-
42
- // Message Card Component
43
- const MessageCard = memo(({ message, compact = false }: { message: any; compact?: boolean }) => {
44
- const { Icon, color } = getMessageStyle(message.collection);
45
-
46
- return (
47
- <a
48
- href={buildUrl(`/docs/${message.collection}/${message.data.id}/${message.data.version}`)}
49
- className={`group block bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-${color}-200 dark:border-${color}-500/30 rounded-lg shadow-xs hover:shadow-md hover:border-${color}-300 dark:hover:border-${color}-500/50 transition-all`}
50
- >
51
- <div className={compact ? 'p-3' : 'p-4'}>
52
- <div className="flex items-center gap-2 mb-1">
53
- <div className={`flex items-center justify-center w-7 h-7 bg-${color}-100 dark:bg-${color}-500/20 rounded-md`}>
54
- <Icon className={`h-4 w-4 text-${color}-600 dark:text-${color}-400`} />
55
- </div>
56
- <h3
57
- className={`font-semibold text-[rgb(var(--ec-page-text))] group-hover:text-${color}-600 dark:group-hover:text-${color}-400 transition-colors truncate ${compact ? 'text-sm' : 'text-base'}`}
58
- >
59
- {message.data.name}
60
- </h3>
61
- <span
62
- className={`text-[10px] text-${color}-600 dark:text-${color}-400 font-medium bg-${color}-50 dark:bg-${color}-500/20 px-1.5 py-0.5 rounded flex-shrink-0`}
63
- >
64
- v{message.data.version}
65
- </span>
66
- </div>
67
- {message.data.summary && (
68
- <p className={`text-[rgb(var(--ec-page-text-muted))] line-clamp-2 ${compact ? 'text-xs mt-1' : 'text-sm mt-2'}`}>
69
- {message.data.summary}
70
- </p>
71
- )}
72
- </div>
73
- </a>
74
- );
75
- });
76
-
77
- // Container Card Component
78
- const ContainerCard = memo(({ container, type }: { container: any; type: 'reads' | 'writes' }) => {
79
- const colorClass = type === 'reads' ? 'amber' : 'violet';
80
-
81
- return (
82
- <a
83
- href={buildUrl(`/docs/containers/${container.data.id}/${container.data.version}`)}
84
- className={`group block bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border rounded-lg shadow-xs hover:shadow-md transition-all ${
85
- type === 'reads'
86
- ? 'border-amber-200 dark:border-amber-500/30 hover:border-amber-300 dark:hover:border-amber-500/50'
87
- : 'border-violet-200 dark:border-violet-500/30 hover:border-violet-300 dark:hover:border-violet-500/50'
88
- }`}
89
- >
90
- <div className="p-3">
91
- <div className="flex items-center gap-2">
92
- <div
93
- className={`flex items-center justify-center w-7 h-7 bg-${colorClass}-100 dark:bg-${colorClass}-500/20 rounded-md`}
94
- >
95
- <CircleStackIcon className={`h-4 w-4 text-${colorClass}-600 dark:text-${colorClass}-400`} />
96
- </div>
97
- <h3
98
- className={`font-semibold text-[rgb(var(--ec-page-text))] text-sm group-hover:text-${colorClass}-600 dark:group-hover:text-${colorClass}-400 transition-colors truncate`}
99
- >
100
- {container.data.name}
101
- </h3>
102
- </div>
103
- {container.data.summary && (
104
- <p className="text-xs text-[rgb(var(--ec-page-text-muted))] mt-1.5 line-clamp-2">{container.data.summary}</p>
105
- )}
106
- </div>
107
- </a>
108
- );
109
- });
110
-
111
- // Specification Card Component
112
- const SpecificationCard = memo(
113
- ({ spec, serviceId, serviceVersion }: { spec: any; serviceId: string; serviceVersion: string }) => {
114
- const color = getSpecColor(spec.type);
115
-
116
- return (
117
- <a
118
- href={getSpecUrl(spec, serviceId, serviceVersion)}
119
- className={`group flex items-center gap-3 p-3 bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-${color}-200 dark:border-${color}-500/30 rounded-lg shadow-xs hover:shadow-md hover:border-${color}-300 dark:hover:border-${color}-500/50 transition-all`}
120
- >
121
- <img src={buildUrl(`/icons/${getSpecIcon(spec.type)}.svg`, true)} alt={`${spec.type} icon`} className="h-6 w-6" />
122
- <div className="flex-1 min-w-0">
123
- <h3
124
- className={`font-semibold text-[rgb(var(--ec-page-text))] text-sm group-hover:text-${color}-600 dark:group-hover:text-${color}-400 transition-colors truncate`}
125
- >
126
- {spec.name || spec.filename}
127
- </h3>
128
- <p className="text-xs text-[rgb(var(--ec-page-text-muted))]">{getSpecLabel(spec.type)}</p>
129
- </div>
130
- </a>
131
- );
132
- }
133
- );
134
-
135
- // Collapsible Message Section Component
136
- const CollapsibleMessageSection = memo(
137
- ({
138
- icon: Icon,
139
- title,
140
- messages,
141
- color,
142
- emptyText,
143
- embeded = false,
144
- }: {
145
- icon: any;
146
- title: string;
147
- messages: any[];
148
- color: string;
149
- emptyText: string;
150
- embeded?: boolean;
151
- }) => {
152
- const [isCollapsed, setIsCollapsed] = useState(false);
153
- const hasContent = messages.length > 0;
154
-
155
- return (
156
- <div className="bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-xl shadow-xs overflow-hidden">
157
- <div
158
- onClick={() => setIsCollapsed(!isCollapsed)}
159
- className={`flex items-center justify-between px-5 py-4 cursor-pointer hover:bg-[rgb(var(--ec-content-hover))] transition-colors ${!isCollapsed && hasContent ? 'border-b border-[rgb(var(--ec-page-border))]' : ''}`}
160
- >
161
- <div className="flex items-center gap-3">
162
- <div className={`flex items-center justify-center w-8 h-8 bg-${color}-100 dark:bg-${color}-500/20 rounded-lg`}>
163
- <Icon className={`h-4 w-4 text-${color}-600 dark:text-${color}-400`} />
164
- </div>
165
- <h2 className="text-base font-bold text-[rgb(var(--ec-page-text))]">{title}</h2>
166
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2 py-0.5 rounded-full font-medium">
167
- {messages.length}
168
- </span>
169
- </div>
170
- <div className="text-[rgb(var(--ec-icon-color))]">
171
- {isCollapsed ? <ChevronDownIcon className="h-5 w-5" /> : <ChevronUpIcon className="h-5 w-5" />}
172
- </div>
173
- </div>
174
- {!isCollapsed && (
175
- <div className="p-5">
176
- {hasContent ? (
177
- <div className="space-y-3">
178
- {messages.map((message: any) => (
179
- <MessageCard key={`${message.data.id}-${message.data.version}`} message={message} compact={embeded} />
180
- ))}
181
- </div>
182
- ) : (
183
- <div className="text-center py-4">
184
- <p className="text-sm text-[rgb(var(--ec-icon-color))]">{emptyText}</p>
185
- </div>
186
- )}
187
- </div>
188
- )}
189
- </div>
190
- );
191
- }
192
- );
193
-
194
- // Collapsible Container Section Component
195
- const CollapsibleContainerSection = memo(
196
- ({ title, containers, color, type }: { title: string; containers: any[]; color: string; type: 'reads' | 'writes' }) => {
197
- const [isCollapsed, setIsCollapsed] = useState(false);
198
-
199
- return (
200
- <div className="bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-xl shadow-xs overflow-hidden">
201
- <div
202
- onClick={() => setIsCollapsed(!isCollapsed)}
203
- className={`flex items-center justify-between px-5 py-4 cursor-pointer hover:bg-[rgb(var(--ec-content-hover))] transition-colors ${!isCollapsed ? 'border-b border-[rgb(var(--ec-page-border))]' : ''}`}
204
- >
205
- <div className="flex items-center gap-3">
206
- <div className={`flex items-center justify-center w-8 h-8 bg-${color}-100 dark:bg-${color}-500/20 rounded-lg`}>
207
- <CircleStackIcon className={`h-4 w-4 text-${color}-600 dark:text-${color}-400`} />
208
- </div>
209
- <h2 className="text-base font-bold text-[rgb(var(--ec-page-text))]">{title}</h2>
210
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2 py-0.5 rounded-full font-medium">
211
- {containers.length}
212
- </span>
213
- </div>
214
- <div className="text-[rgb(var(--ec-icon-color))]">
215
- {isCollapsed ? <ChevronDownIcon className="h-5 w-5" /> : <ChevronUpIcon className="h-5 w-5" />}
216
- </div>
217
- </div>
218
- {!isCollapsed && (
219
- <div className="p-5">
220
- <div className="space-y-3">
221
- {containers.map((container: any) => (
222
- <ContainerCard key={container.data.id} container={container} type={type} />
223
- ))}
224
- </div>
225
- </div>
226
- )}
227
- </div>
228
- );
229
- }
230
- );
231
-
232
- export default function MessageGridV2({ service, embeded = false, specifications = [] }: MessageGridV2Props) {
233
- const { sends = [], receives = [], writesTo = [], readsFrom = [] } = service.data;
234
- const collection = service.collection || 'services';
235
- const resourceLabel = collection === 'agents' ? 'agent' : 'service';
236
- const hasContainers = readsFrom.length > 0 || writesTo.length > 0;
237
- const hasMessages = receives.length > 0 || sends.length > 0;
238
- const hasSpecs = specifications.length > 0;
239
-
240
- return (
241
- <div className="w-full">
242
- {/* Resource Header - Doc style */}
243
- <div className="border-b border-[rgb(var(--ec-page-border))] md:pb-4">
244
- <div className="flex items-start justify-between">
245
- <div>
246
- <h2 className="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">{service.data.name}</h2>
247
- {service.data.summary && (
248
- <p className="text-lg pt-2 text-[rgb(var(--ec-page-text-muted))] font-light">{service.data.summary}</p>
249
- )}
250
- </div>
251
- </div>
252
- </div>
253
-
254
- {/* Service Content */}
255
- <div className="py-4 space-y-8">
256
- {/* Specifications */}
257
- {hasSpecs && (
258
- <div>
259
- <div className="flex items-center gap-2 mb-4">
260
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Specifications</h3>
261
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
262
- {specifications.length}
263
- </span>
264
- </div>
265
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
266
- {specifications.map((spec: any) => (
267
- <SpecificationCard
268
- key={`${spec.type}-${spec.filename}`}
269
- spec={spec}
270
- serviceId={service.data.id}
271
- serviceVersion={service.data.version}
272
- />
273
- ))}
274
- </div>
275
- </div>
276
- )}
277
-
278
- {/* Message Flow - Two columns side by side */}
279
- {hasMessages && (
280
- <div>
281
- <div className="flex items-center gap-2 mb-4">
282
- <BoltIcon className="h-5 w-5 text-orange-500 dark:text-orange-400" />
283
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Messages</h3>
284
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
285
- {receives.length + sends.length}
286
- </span>
287
- </div>
288
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
289
- <CollapsibleMessageSection
290
- icon={ArrowLongRightIcon}
291
- title="Receives"
292
- messages={receives}
293
- color="blue"
294
- emptyText="No messages received"
295
- embeded={embeded}
296
- />
297
- <CollapsibleMessageSection
298
- icon={ArrowLongRightIcon}
299
- title="Sends"
300
- messages={sends}
301
- color="emerald"
302
- emptyText="No messages sent"
303
- embeded={embeded}
304
- />
305
- </div>
306
- </div>
307
- )}
308
-
309
- {/* Container Relationships */}
310
- {hasContainers && (
311
- <div>
312
- <div className="flex items-center gap-2 mb-4">
313
- <CircleStackIcon className="h-5 w-5 text-amber-500 dark:text-amber-400" />
314
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Data Sources</h3>
315
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
316
- {readsFrom.length + writesTo.length}
317
- </span>
318
- </div>
319
- <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
320
- {readsFrom.length > 0 && (
321
- <CollapsibleContainerSection title="Reads from" containers={readsFrom} color="amber" type="reads" />
322
- )}
323
- {writesTo.length > 0 && (
324
- <CollapsibleContainerSection title="Writes to" containers={writesTo} color="violet" type="writes" />
325
- )}
326
- </div>
327
- </div>
328
- )}
329
-
330
- {/* Empty State */}
331
- {!hasMessages && !hasContainers && !hasSpecs && (
332
- <div className="text-center py-12">
333
- <div className="flex items-center justify-center w-16 h-16 mx-auto mb-4 bg-[rgb(var(--ec-content-hover))] rounded-2xl">
334
- <ServerIcon className="h-8 w-8 text-[rgb(var(--ec-icon-color))]" />
335
- </div>
336
- <p className="text-[rgb(var(--ec-page-text-muted))]">
337
- This {resourceLabel} has no message flows or container relationships defined.
338
- </p>
339
- </div>
340
- )}
341
- </div>
342
- </div>
343
- );
344
- }
@@ -1,185 +0,0 @@
1
- import { useMemo } from 'react';
2
- import { ServerIcon, GlobeAltIcon, CircleStackIcon } from '@heroicons/react/24/outline';
3
- import { buildUrl } from '@utils/url-builder';
4
- import { BoxIcon, Group as GroupIcon, Waypoints, Database as DatabaseIcon } from 'lucide-react';
5
- import { ServiceCard, EntityBadge } from './DomainGrid';
6
-
7
- interface SystemGridProps {
8
- system: any;
9
- }
10
-
11
- const FlowLink = ({ flow }: { flow: any }) => {
12
- const data = flow?.data || flow;
13
- const id = data?.id || flow?.id;
14
- const name = data?.name || id;
15
- const version = data?.version || 'latest';
16
-
17
- return (
18
- <a
19
- href={buildUrl(`/docs/flows/${id}/${version}`)}
20
- className="inline-flex items-center gap-2 px-3 py-2 bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-lg text-sm font-medium text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-content-hover))] hover:border-[rgb(var(--ec-accent)/0.5)] transition-all shadow-xs"
21
- >
22
- <Waypoints className="h-4 w-4 text-[rgb(var(--ec-accent))]" />
23
- <span>{name}</span>
24
- <span className="text-xs text-[rgb(var(--ec-icon-color))]">v{version}</span>
25
- </a>
26
- );
27
- };
28
-
29
- const DataStoreLink = ({ container }: { container: any }) => {
30
- const data = container?.data || container;
31
- const id = data?.id || container?.id;
32
- const name = data?.name || id;
33
- const version = data?.version || 'latest';
34
- const technology = data?.technology;
35
-
36
- return (
37
- <a
38
- href={buildUrl(`/docs/containers/${id}/${version}`)}
39
- className="inline-flex items-center gap-2 px-3 py-2 bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-lg text-sm font-medium text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-content-hover))] hover:border-[rgb(var(--ec-accent)/0.5)] transition-all shadow-xs"
40
- >
41
- <CircleStackIcon className="h-4 w-4 text-amber-500" />
42
- <span>{name}</span>
43
- {technology && <span className="text-xs text-[rgb(var(--ec-icon-color))]">{technology}</span>}
44
- </a>
45
- );
46
- };
47
-
48
- export default function SystemGrid({ system }: SystemGridProps) {
49
- const data = system?.data;
50
- if (!data) return <div className="text-[rgb(var(--ec-page-text-muted))]">No system data</div>;
51
-
52
- const entities = data.entities || [];
53
- const services = data.services || [];
54
- const flows = data.flows || [];
55
- const containers = data.containers || [];
56
-
57
- // Split services into internal services and external integrations
58
- // (mirrors the sidebar, where externalSystem services live under "External Integrations")
59
- const internalServices = useMemo(() => services.filter((s: any) => !(s?.data || s)?.externalSystem), [services]);
60
- const externalServices = useMemo(() => services.filter((s: any) => (s?.data || s)?.externalSystem), [services]);
61
-
62
- return (
63
- <div className="w-full">
64
- {/* System Header - Doc style */}
65
- <div className="border-b border-[rgb(var(--ec-page-border))] md:pb-4">
66
- <div className="flex items-start justify-between">
67
- <div>
68
- <h2 className="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">{data.name || data.id}</h2>
69
- {data.summary && <p className="text-lg pt-2 text-[rgb(var(--ec-page-text-muted))] font-light">{data.summary}</p>}
70
- </div>
71
- </div>
72
- </div>
73
-
74
- {/* System Content */}
75
- <div className="py-4 space-y-8">
76
- {/* System Entities */}
77
- {entities.length > 0 && (
78
- <div>
79
- <div className="flex items-center gap-2 mb-4">
80
- <BoxIcon className="h-5 w-5 text-[rgb(var(--ec-accent))]" />
81
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Entities</h3>
82
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
83
- {entities.length}
84
- </span>
85
- </div>
86
- <div className="flex flex-wrap gap-2">
87
- {entities.map((entity: any) => {
88
- const entityId = entity?.data?.id || entity?.id;
89
- return entityId ? <EntityBadge key={entityId} entity={entity} /> : null;
90
- })}
91
- </div>
92
- </div>
93
- )}
94
-
95
- {/* Services */}
96
- {internalServices.length > 0 && (
97
- <div>
98
- <div className="flex items-center gap-2 mb-4">
99
- <ServerIcon className="h-5 w-5 text-pink-600 dark:text-pink-400" />
100
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Services</h3>
101
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
102
- {internalServices.length}
103
- </span>
104
- </div>
105
- <div className="space-y-3">
106
- {internalServices.map((service: any) => {
107
- const serviceId = service?.data?.id || service?.id;
108
- return serviceId ? <ServiceCard key={serviceId} service={service} /> : null;
109
- })}
110
- </div>
111
- </div>
112
- )}
113
-
114
- {/* External Integrations (external systems) */}
115
- {externalServices.length > 0 && (
116
- <div>
117
- <div className="flex items-center gap-2 mb-4">
118
- <GlobeAltIcon className="h-5 w-5 text-sky-600 dark:text-sky-400" />
119
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">External Integrations</h3>
120
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
121
- {externalServices.length}
122
- </span>
123
- </div>
124
- <div className="space-y-3">
125
- {externalServices.map((service: any) => {
126
- const serviceId = service?.data?.id || service?.id;
127
- return serviceId ? <ServiceCard key={serviceId} service={service} /> : null;
128
- })}
129
- </div>
130
- </div>
131
- )}
132
-
133
- {/* Data Stores (containers) */}
134
- {containers.length > 0 && (
135
- <div>
136
- <div className="flex items-center gap-2 mb-4">
137
- <DatabaseIcon className="h-5 w-5 text-amber-500" />
138
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Data Stores</h3>
139
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
140
- {containers.length}
141
- </span>
142
- </div>
143
- <div className="flex flex-wrap gap-2">
144
- {containers.map((container: any) => {
145
- const containerId = container?.data?.id || container?.id;
146
- return containerId ? <DataStoreLink key={containerId} container={container} /> : null;
147
- })}
148
- </div>
149
- </div>
150
- )}
151
-
152
- {/* Flows */}
153
- {flows.length > 0 && (
154
- <div>
155
- <div className="flex items-center gap-2 mb-4">
156
- <Waypoints className="h-5 w-5 text-[rgb(var(--ec-accent))]" />
157
- <h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Flows</h3>
158
- <span className="text-sm text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2.5 py-0.5 rounded-full font-medium">
159
- {flows.length}
160
- </span>
161
- </div>
162
- <div className="flex flex-wrap gap-2">
163
- {flows.map((flow: any) => {
164
- const flowId = flow?.data?.id || flow?.id;
165
- return flowId ? <FlowLink key={flowId} flow={flow} /> : null;
166
- })}
167
- </div>
168
- </div>
169
- )}
170
-
171
- {/* Empty state */}
172
- {entities.length === 0 && services.length === 0 && flows.length === 0 && containers.length === 0 && (
173
- <div className="text-center py-12">
174
- <div className="flex items-center justify-center w-16 h-16 mx-auto mb-4 bg-[rgb(var(--ec-content-hover))] rounded-2xl">
175
- <GroupIcon className="h-8 w-8 text-[rgb(var(--ec-icon-color))]" />
176
- </div>
177
- <p className="text-[rgb(var(--ec-page-text-muted))]">
178
- This system has no entities, services, data stores, or flows defined.
179
- </p>
180
- </div>
181
- )}
182
- </div>
183
- </div>
184
- );
185
- }