@eventcatalog/core 3.48.3 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/catalog-to-astro-content-directory.cjs +1 -1
- package/dist/{chunk-4BRGEUVO.js → chunk-7PMNFOIL.js} +1 -1
- package/dist/chunk-BWN544LB.js +73 -0
- package/dist/{chunk-X7GMZVB3.js → chunk-D3MI3OFO.js} +1 -1
- package/dist/{chunk-EE5Q6MJZ.js → chunk-HN45LKSL.js} +1 -1
- package/dist/{chunk-PWBFBCJ4.js → chunk-JMADW4J7.js} +1 -1
- package/dist/{chunk-XEUW7PEQ.js → chunk-NAOHQDLC.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/core-node-modules.cjs +108 -0
- package/dist/core-node-modules.d.cts +7 -0
- package/dist/core-node-modules.d.ts +7 -0
- package/dist/core-node-modules.js +8 -0
- package/dist/docs/development/components/components/15-prompt.md +5 -1
- package/dist/eventcatalog.cjs +124 -48
- package/dist/eventcatalog.js +26 -15
- 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 +27 -23
- package/eventcatalog/public/icons/languages/java.svg +1 -0
- package/eventcatalog/public/icons/payments/stripe.svg +1 -0
- package/eventcatalog/src/components/Badge.astro +10 -10
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +154 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +207 -44
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -20
- package/eventcatalog/src/components/Grids/SystemGrid.tsx +185 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.astro +99 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.client.tsx +400 -0
- package/eventcatalog/src/components/MDX/ContextDiagram/ContextDiagramPortal.tsx +21 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +1 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +42 -6
- package/eventcatalog/src/components/MDX/Prompt/Prompt.astro +62 -9
- package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +8 -1
- package/eventcatalog/src/components/MDX/SystemContextMap/SystemContextMapPortal.tsx +22 -0
- package/eventcatalog/src/components/MDX/components.tsx +7 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -1
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +67 -37
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +47 -0
- package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +10 -2
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +115 -27
- package/eventcatalog/src/components/Tables/Discover/index.ts +7 -1
- package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +267 -0
- package/eventcatalog/src/content.config.ts +94 -8
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +4 -1
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +12 -13
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -0
- package/eventcatalog/src/enterprise/feature.ts +3 -1
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +85 -129
- package/eventcatalog/src/layouts/VisualiserLayout.astro +66 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +4 -2
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +2 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +15 -15
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/discover/[type]/index.astro +47 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +15 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +13 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +11 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +81 -26
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +89 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +85 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/index.astro +30 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +3 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +94 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +51 -0
- package/eventcatalog/src/pages/visualiser/system-context-map/index.astro +41 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +91 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +51 -0
- package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +3 -1
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +3 -1
- package/eventcatalog/src/stores/sidebar-store/builders/container.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +127 -49
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +4 -2
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +2 -1
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +166 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +99 -6
- package/eventcatalog/src/types/index.ts +2 -0
- package/eventcatalog/src/utils/collection-colors.ts +6 -1
- package/eventcatalog/src/utils/collections/domains.ts +35 -0
- package/eventcatalog/src/utils/collections/icons.ts +4 -5
- package/eventcatalog/src/utils/collections/systems.ts +110 -0
- package/eventcatalog/src/utils/collections/teams.ts +15 -10
- package/eventcatalog/src/utils/collections/users.ts +7 -4
- package/eventcatalog/src/utils/collections/util.ts +2 -0
- package/eventcatalog/src/utils/icon-map.ts +20 -0
- package/eventcatalog/src/utils/icon.ts +11 -0
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -2
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +0 -170
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +400 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +208 -0
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +12 -0
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +17 -14
- package/eventcatalog/src/pages/visualiser/context-map/index.astro +0 -30
|
@@ -65,6 +65,7 @@ export function CopyPageMenu({
|
|
|
65
65
|
preferChatAsDefault = false,
|
|
66
66
|
chatButtonText = 'Ask',
|
|
67
67
|
printUrl,
|
|
68
|
+
variant = 'menu',
|
|
68
69
|
}: {
|
|
69
70
|
schemas: Schema[];
|
|
70
71
|
chatQuery?: string;
|
|
@@ -75,6 +76,7 @@ export function CopyPageMenu({
|
|
|
75
76
|
preferChatAsDefault?: boolean;
|
|
76
77
|
chatButtonText?: string;
|
|
77
78
|
printUrl?: string;
|
|
79
|
+
variant?: 'menu' | 'toolbar';
|
|
78
80
|
}) {
|
|
79
81
|
// Define available actions
|
|
80
82
|
const availableActions = {
|
|
@@ -164,12 +166,14 @@ export function CopyPageMenu({
|
|
|
164
166
|
const defaultAction = getDefaultAction();
|
|
165
167
|
const [open, setOpen] = useState(false);
|
|
166
168
|
const [buttonText, setButtonText] = useState(defaultAction?.text || 'Action');
|
|
169
|
+
const [copyButtonText, setCopyButtonText] = useState('Copy page as markdown');
|
|
167
170
|
|
|
168
171
|
// Fetch the markdown from the url + .mdx
|
|
169
172
|
const copyMarkdownToClipboard = async () => {
|
|
170
173
|
console.log('Copying markdown to clipboard');
|
|
171
174
|
try {
|
|
172
175
|
setButtonText('Copied');
|
|
176
|
+
setCopyButtonText('Copied');
|
|
173
177
|
const response = await fetch(markdownUrl);
|
|
174
178
|
if (!response.ok) {
|
|
175
179
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
@@ -177,10 +181,13 @@ export function CopyPageMenu({
|
|
|
177
181
|
const markdown = await response.text();
|
|
178
182
|
await navigator.clipboard.writeText(markdown);
|
|
179
183
|
setTimeout(() => setButtonText(defaultAction?.text || 'Action'), 3000); // Revert after 3 seconds
|
|
184
|
+
setTimeout(() => setCopyButtonText('Copy page as markdown'), 3000);
|
|
180
185
|
} catch (error) {
|
|
181
186
|
console.error('Failed to copy markdown:', error);
|
|
182
187
|
setButtonText('Copy failed'); // Provide feedback on failure
|
|
188
|
+
setCopyButtonText('Copy failed');
|
|
183
189
|
setTimeout(() => setButtonText(defaultAction?.text || 'Action'), 3000);
|
|
190
|
+
setTimeout(() => setCopyButtonText('Copy page as markdown'), 3000);
|
|
184
191
|
}
|
|
185
192
|
};
|
|
186
193
|
|
|
@@ -236,6 +243,153 @@ export function CopyPageMenu({
|
|
|
236
243
|
return null;
|
|
237
244
|
}
|
|
238
245
|
|
|
246
|
+
const actionButtonClass =
|
|
247
|
+
'group inline-flex items-center gap-1.5 whitespace-nowrap text-xs font-medium text-[rgb(var(--ec-page-text-muted))] transition-colors duration-150 hover:text-[rgb(var(--ec-page-text))] focus:outline-hidden focus:ring-2 focus:ring-[rgb(var(--ec-accent))] focus:ring-offset-2 focus:ring-offset-[rgb(var(--ec-page-bg))] rounded-md';
|
|
248
|
+
const actionIconClass = 'h-3.5 w-3.5 shrink-0 text-[rgb(var(--ec-icon-color))] group-hover:text-[rgb(var(--ec-page-text))]';
|
|
249
|
+
|
|
250
|
+
const hasToolbarActions =
|
|
251
|
+
availableActions.chat ||
|
|
252
|
+
availableActions.copyMarkdown ||
|
|
253
|
+
availableActions.viewMarkdown ||
|
|
254
|
+
availableActions.copySchemas ||
|
|
255
|
+
availableActions.rssFeed ||
|
|
256
|
+
availableActions.exportPDF ||
|
|
257
|
+
availableActions.editPage;
|
|
258
|
+
|
|
259
|
+
if (variant === 'toolbar') {
|
|
260
|
+
if (!hasToolbarActions) return null;
|
|
261
|
+
|
|
262
|
+
const moreActionsAvailable =
|
|
263
|
+
availableActions.copySchemas || availableActions.rssFeed || availableActions.exportPDF || availableActions.editPage;
|
|
264
|
+
|
|
265
|
+
return (
|
|
266
|
+
<div className="not-prose flex flex-wrap items-center gap-x-3 gap-y-1.5 text-xs text-[rgb(var(--ec-page-text-muted))]">
|
|
267
|
+
{availableActions.chat && (
|
|
268
|
+
<button
|
|
269
|
+
type="button"
|
|
270
|
+
onClick={() => window.dispatchEvent(new CustomEvent('eventcatalog:open-chat'))}
|
|
271
|
+
className={actionButtonClass}
|
|
272
|
+
>
|
|
273
|
+
<MessageCircleQuestion className={actionIconClass} />
|
|
274
|
+
Ask a question
|
|
275
|
+
</button>
|
|
276
|
+
)}
|
|
277
|
+
|
|
278
|
+
{availableActions.chat && (availableActions.copyMarkdown || availableActions.viewMarkdown || moreActionsAvailable) && (
|
|
279
|
+
<span className="h-4 w-px bg-[rgb(var(--ec-page-border))]" aria-hidden="true" />
|
|
280
|
+
)}
|
|
281
|
+
|
|
282
|
+
{availableActions.copyMarkdown && (
|
|
283
|
+
<button type="button" onClick={copyMarkdownToClipboard} className={actionButtonClass}>
|
|
284
|
+
<Copy className={actionIconClass} />
|
|
285
|
+
{copyButtonText}
|
|
286
|
+
</button>
|
|
287
|
+
)}
|
|
288
|
+
|
|
289
|
+
{availableActions.copyMarkdown && (availableActions.viewMarkdown || moreActionsAvailable) && (
|
|
290
|
+
<span className="h-4 w-px bg-[rgb(var(--ec-page-border))]" aria-hidden="true" />
|
|
291
|
+
)}
|
|
292
|
+
|
|
293
|
+
{availableActions.viewMarkdown && (
|
|
294
|
+
<button type="button" onClick={() => window.open(markdownUrl, '_blank')} className={actionButtonClass}>
|
|
295
|
+
<FileText className={actionIconClass} />
|
|
296
|
+
View as Markdown
|
|
297
|
+
</button>
|
|
298
|
+
)}
|
|
299
|
+
|
|
300
|
+
{availableActions.viewMarkdown && moreActionsAvailable && (
|
|
301
|
+
<span className="h-4 w-px bg-[rgb(var(--ec-page-border))]" aria-hidden="true" />
|
|
302
|
+
)}
|
|
303
|
+
|
|
304
|
+
{moreActionsAvailable && (
|
|
305
|
+
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
|
306
|
+
<DropdownMenu.Trigger asChild>
|
|
307
|
+
<button type="button" className={actionButtonClass}>
|
|
308
|
+
More actions
|
|
309
|
+
<ChevronDownIcon className={`h-3.5 w-3.5 transition-transform duration-200 ${open ? 'rotate-180' : ''}`} />
|
|
310
|
+
</button>
|
|
311
|
+
</DropdownMenu.Trigger>
|
|
312
|
+
<DropdownMenu.Content
|
|
313
|
+
className="z-50 w-72 max-w-[calc(100vw-1.5rem)] rounded-2xl border border-[rgb(var(--ec-dropdown-border)/0.8)] bg-[rgb(var(--ec-page-bg))] px-1.5 py-1.5 shadow-[0_24px_64px_rgb(0_0_0/0.35)]"
|
|
314
|
+
sideOffset={10}
|
|
315
|
+
align="start"
|
|
316
|
+
>
|
|
317
|
+
{availableActions.copySchemas &&
|
|
318
|
+
schemas.map((schema) => {
|
|
319
|
+
const title =
|
|
320
|
+
schema.format === 'asyncapi'
|
|
321
|
+
? 'Copy AsyncAPI specification'
|
|
322
|
+
: schema.format === 'openapi'
|
|
323
|
+
? 'Copy OpenAPI specification'
|
|
324
|
+
: 'Copy schema';
|
|
325
|
+
const type =
|
|
326
|
+
schema.format === 'asyncapi' || schema.format === 'openapi'
|
|
327
|
+
? 'specification'
|
|
328
|
+
: `${schema.format.toUpperCase()} schema`;
|
|
329
|
+
|
|
330
|
+
const Icon =
|
|
331
|
+
schema.format === 'asyncapi' ? (
|
|
332
|
+
<img src={buildUrl('/icons/asyncapi.svg', true)} className="w-4 h-4" />
|
|
333
|
+
) : schema.format === 'openapi' ? (
|
|
334
|
+
<img src={buildUrl('/icons/openapi.svg', true)} className="w-4 h-4" />
|
|
335
|
+
) : (
|
|
336
|
+
FileText
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
return (
|
|
340
|
+
<DropdownMenu.Item
|
|
341
|
+
key={schema.url}
|
|
342
|
+
className="cursor-pointer rounded-2xl outline-hidden transition-colors duration-150 hover:bg-[rgb(var(--ec-dropdown-hover))] data-[highlighted]:bg-[rgb(var(--ec-dropdown-hover))]"
|
|
343
|
+
onSelect={() => copySchemaToClipboard(schema)}
|
|
344
|
+
>
|
|
345
|
+
<MenuItemContent icon={Icon} title={title} description={`Copy ${type} to clipboard`} />
|
|
346
|
+
</DropdownMenu.Item>
|
|
347
|
+
);
|
|
348
|
+
})}
|
|
349
|
+
|
|
350
|
+
{availableActions.rssFeed && (
|
|
351
|
+
<DropdownMenu.Item
|
|
352
|
+
className="cursor-pointer rounded-2xl outline-hidden transition-colors duration-150 hover:bg-[rgb(var(--ec-dropdown-hover))] data-[highlighted]:bg-[rgb(var(--ec-dropdown-hover))]"
|
|
353
|
+
onSelect={() => window.open(buildUrl(`/rss/all/rss.xml`), '_blank')}
|
|
354
|
+
>
|
|
355
|
+
<MenuItemContent icon={RssIcon} title="RSS Feed" description="View this page as RSS feed" external={true} />
|
|
356
|
+
</DropdownMenu.Item>
|
|
357
|
+
)}
|
|
358
|
+
|
|
359
|
+
{availableActions.exportPDF && (
|
|
360
|
+
<DropdownMenu.Item
|
|
361
|
+
className="cursor-pointer rounded-2xl outline-hidden transition-colors duration-150 hover:bg-[rgb(var(--ec-dropdown-hover))] data-[highlighted]:bg-[rgb(var(--ec-dropdown-hover))]"
|
|
362
|
+
onSelect={() => window.open(printUrl, '_blank')}
|
|
363
|
+
>
|
|
364
|
+
<MenuItemContent
|
|
365
|
+
icon={PrinterIcon}
|
|
366
|
+
title="Export to PDF"
|
|
367
|
+
description="Open print-friendly version"
|
|
368
|
+
external={true}
|
|
369
|
+
/>
|
|
370
|
+
</DropdownMenu.Item>
|
|
371
|
+
)}
|
|
372
|
+
|
|
373
|
+
{availableActions.editPage && (
|
|
374
|
+
<DropdownMenu.Item
|
|
375
|
+
className="cursor-pointer rounded-2xl outline-hidden transition-colors duration-150 hover:bg-[rgb(var(--ec-dropdown-hover))] data-[highlighted]:bg-[rgb(var(--ec-dropdown-hover))]"
|
|
376
|
+
onSelect={() => window.open(editUrl, '_blank')}
|
|
377
|
+
>
|
|
378
|
+
<MenuItemContent
|
|
379
|
+
icon={PenSquareIcon}
|
|
380
|
+
title="Edit page"
|
|
381
|
+
description="Edit the contents of this page"
|
|
382
|
+
external={true}
|
|
383
|
+
/>
|
|
384
|
+
</DropdownMenu.Item>
|
|
385
|
+
)}
|
|
386
|
+
</DropdownMenu.Content>
|
|
387
|
+
</DropdownMenu.Root>
|
|
388
|
+
)}
|
|
389
|
+
</div>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
239
393
|
return (
|
|
240
394
|
<DropdownMenu.Root open={open} onOpenChange={setOpen}>
|
|
241
395
|
{/* Container for the split button */}
|
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
ArrowLongRightIcon,
|
|
13
13
|
ArrowLongLeftIcon,
|
|
14
14
|
CubeIcon,
|
|
15
|
+
GlobeAltIcon,
|
|
15
16
|
} from '@heroicons/react/24/outline';
|
|
16
17
|
import { buildUrl } from '@utils/url-builder';
|
|
17
|
-
import { BoxIcon } from 'lucide-react';
|
|
18
|
+
import { BoxIcon, Group as GroupIcon } from 'lucide-react';
|
|
18
19
|
import { getSpecUrl, getSpecIcon, getSpecLabel, getServiceSpecifications } from './specification-utils';
|
|
19
20
|
|
|
20
21
|
// ============================================
|
|
@@ -46,7 +47,7 @@ const getMessageIcon = (collection: string) => {
|
|
|
46
47
|
// Sub-components
|
|
47
48
|
// ============================================
|
|
48
49
|
|
|
49
|
-
const EntityBadge = memo(({ entity }: { entity: any }) => {
|
|
50
|
+
export const EntityBadge = memo(({ entity }: { entity: any }) => {
|
|
50
51
|
const id = entity?.data?.id || entity?.id;
|
|
51
52
|
const name = entity?.data?.name || entity?.name || id;
|
|
52
53
|
const version = entity?.data?.version || entity?.version || 'latest';
|
|
@@ -120,6 +121,26 @@ const ContainerLink = memo(({ container, type }: { container: any; type: 'reads'
|
|
|
120
121
|
);
|
|
121
122
|
});
|
|
122
123
|
|
|
124
|
+
// Standalone data store (container) link, used to list a system's data stores
|
|
125
|
+
const DataStoreLink = memo(({ container }: { container: any }) => {
|
|
126
|
+
const data = container?.data || container;
|
|
127
|
+
const id = data?.id || container?.id;
|
|
128
|
+
const name = data?.name || id;
|
|
129
|
+
const version = data?.version || 'latest';
|
|
130
|
+
const technology = data?.technology;
|
|
131
|
+
|
|
132
|
+
return (
|
|
133
|
+
<a
|
|
134
|
+
href={buildUrl(`/docs/containers/${id}/${version}`)}
|
|
135
|
+
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"
|
|
136
|
+
>
|
|
137
|
+
<CircleStackIcon className="h-4 w-4 text-amber-500" />
|
|
138
|
+
<span>{name}</span>
|
|
139
|
+
{technology && <span className="text-xs text-[rgb(var(--ec-icon-color))]">{technology}</span>}
|
|
140
|
+
</a>
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
123
144
|
// Searchable scrollable box component
|
|
124
145
|
const SearchableBox = memo(
|
|
125
146
|
({
|
|
@@ -245,9 +266,9 @@ const ServiceExpandedContent = memo(
|
|
|
245
266
|
}
|
|
246
267
|
);
|
|
247
268
|
|
|
248
|
-
const ServiceCard = memo(({ service }: { service: any }) => {
|
|
269
|
+
export const ServiceCard = memo(({ service, defaultOpen = false }: { service: any; defaultOpen?: boolean }) => {
|
|
249
270
|
const data = service?.data || service;
|
|
250
|
-
const [isCollapsed, setIsCollapsed] = useState(
|
|
271
|
+
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
251
272
|
|
|
252
273
|
if (!data?.id) return null;
|
|
253
274
|
|
|
@@ -363,9 +384,9 @@ const DataProductCard = memo(({ dataProduct }: { dataProduct: any }) => {
|
|
|
363
384
|
);
|
|
364
385
|
});
|
|
365
386
|
|
|
366
|
-
const SubdomainSection = memo(({ subdomain }: { subdomain: any }) => {
|
|
387
|
+
const SubdomainSection = memo(({ subdomain, defaultOpen = false }: { subdomain: any; defaultOpen?: boolean }) => {
|
|
367
388
|
const data = subdomain?.data || subdomain;
|
|
368
|
-
const [isCollapsed, setIsCollapsed] = useState(
|
|
389
|
+
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
369
390
|
|
|
370
391
|
if (!data?.id) return null;
|
|
371
392
|
|
|
@@ -489,6 +510,109 @@ const SubdomainSection = memo(({ subdomain }: { subdomain: any }) => {
|
|
|
489
510
|
);
|
|
490
511
|
});
|
|
491
512
|
|
|
513
|
+
const SystemSection = memo(({ system, defaultOpen = false }: { system: any; defaultOpen?: boolean }) => {
|
|
514
|
+
const data = system?.data || system;
|
|
515
|
+
const [isCollapsed, setIsCollapsed] = useState(!defaultOpen);
|
|
516
|
+
|
|
517
|
+
if (!data?.id) return null;
|
|
518
|
+
|
|
519
|
+
const services = data.services || [];
|
|
520
|
+
const containers = data.containers || [];
|
|
521
|
+
|
|
522
|
+
return (
|
|
523
|
+
<div className="bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-xl overflow-hidden shadow-xs">
|
|
524
|
+
{/* System Header - Clickable */}
|
|
525
|
+
<div
|
|
526
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
527
|
+
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))]' : ''}`}
|
|
528
|
+
>
|
|
529
|
+
<div className="flex items-center gap-3">
|
|
530
|
+
<div className="flex items-center justify-center w-9 h-9 bg-violet-100 dark:bg-violet-500/20 rounded-lg">
|
|
531
|
+
<GroupIcon className="h-5 w-5 text-violet-600 dark:text-violet-400" />
|
|
532
|
+
</div>
|
|
533
|
+
<div>
|
|
534
|
+
<div className="flex items-center gap-2">
|
|
535
|
+
<h3 className="text-base font-semibold text-[rgb(var(--ec-page-text))]">{data.name || data.id}</h3>
|
|
536
|
+
<span className="text-[11px] text-[rgb(var(--ec-page-text-muted))] font-medium bg-[rgb(var(--ec-content-hover))] px-1.5 py-0.5 rounded border border-[rgb(var(--ec-page-border))]">
|
|
537
|
+
v{data.version}
|
|
538
|
+
</span>
|
|
539
|
+
{/* Show counts when collapsed */}
|
|
540
|
+
{isCollapsed && (services.length > 0 || containers.length > 0) && (
|
|
541
|
+
<span className="text-[11px] text-[rgb(var(--ec-icon-color))] ml-1">
|
|
542
|
+
{[
|
|
543
|
+
services.length > 0 && `${services.length} service${services.length > 1 ? 's' : ''}`,
|
|
544
|
+
containers.length > 0 && `${containers.length} data store${containers.length > 1 ? 's' : ''}`,
|
|
545
|
+
]
|
|
546
|
+
.filter(Boolean)
|
|
547
|
+
.join(' · ')}
|
|
548
|
+
</span>
|
|
549
|
+
)}
|
|
550
|
+
</div>
|
|
551
|
+
<span className="text-[11px] text-[rgb(var(--ec-page-text-muted))] font-medium">System</span>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
<div className="flex items-center gap-1">
|
|
555
|
+
<div className="p-2 text-[rgb(var(--ec-icon-color))]">
|
|
556
|
+
{isCollapsed ? <ChevronDownIcon className="h-5 w-5" /> : <ChevronUpIcon className="h-5 w-5" />}
|
|
557
|
+
</div>
|
|
558
|
+
<a
|
|
559
|
+
href={buildUrl(`/visualiser/systems/${data.id}/${data.version}`)}
|
|
560
|
+
onClick={(e) => e.stopPropagation()}
|
|
561
|
+
className="p-2 text-[rgb(var(--ec-icon-color))] hover:text-violet-500 hover:bg-violet-500/10 rounded-lg transition-colors"
|
|
562
|
+
title="View system map"
|
|
563
|
+
>
|
|
564
|
+
<ArrowTopRightOnSquareIcon className="h-5 w-5" />
|
|
565
|
+
</a>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
|
|
569
|
+
{!isCollapsed && (
|
|
570
|
+
<div className="p-5 space-y-5">
|
|
571
|
+
{services.length > 0 && (
|
|
572
|
+
<div>
|
|
573
|
+
<div className="flex items-center gap-2 mb-3">
|
|
574
|
+
<ServerIcon className="h-4 w-4 text-pink-600 dark:text-pink-400" />
|
|
575
|
+
<h4 className="text-sm font-semibold text-[rgb(var(--ec-page-text))]">Services</h4>
|
|
576
|
+
<span className="text-xs text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2 py-0.5 rounded-full font-medium">
|
|
577
|
+
{services.length}
|
|
578
|
+
</span>
|
|
579
|
+
</div>
|
|
580
|
+
<div className="space-y-3">
|
|
581
|
+
{services.map((service: any) => {
|
|
582
|
+
const serviceId = service?.data?.id || service?.id;
|
|
583
|
+
return serviceId ? <ServiceCard key={serviceId} service={service} /> : null;
|
|
584
|
+
})}
|
|
585
|
+
</div>
|
|
586
|
+
</div>
|
|
587
|
+
)}
|
|
588
|
+
|
|
589
|
+
{containers.length > 0 && (
|
|
590
|
+
<div>
|
|
591
|
+
<div className="flex items-center gap-2 mb-3">
|
|
592
|
+
<CircleStackIcon className="h-4 w-4 text-amber-500" />
|
|
593
|
+
<h4 className="text-sm font-semibold text-[rgb(var(--ec-page-text))]">Data Stores</h4>
|
|
594
|
+
<span className="text-xs text-[rgb(var(--ec-page-text-muted))] bg-[rgb(var(--ec-content-hover))] px-2 py-0.5 rounded-full font-medium">
|
|
595
|
+
{containers.length}
|
|
596
|
+
</span>
|
|
597
|
+
</div>
|
|
598
|
+
<div className="flex flex-wrap gap-2">
|
|
599
|
+
{containers.map((container: any) => {
|
|
600
|
+
const containerId = container?.data?.id || container?.id;
|
|
601
|
+
return containerId ? <DataStoreLink key={containerId} container={container} /> : null;
|
|
602
|
+
})}
|
|
603
|
+
</div>
|
|
604
|
+
</div>
|
|
605
|
+
)}
|
|
606
|
+
|
|
607
|
+
{services.length === 0 && containers.length === 0 && (
|
|
608
|
+
<p className="text-sm text-[rgb(var(--ec-icon-color))] italic text-center py-4">Nothing in this system yet</p>
|
|
609
|
+
)}
|
|
610
|
+
</div>
|
|
611
|
+
)}
|
|
612
|
+
</div>
|
|
613
|
+
);
|
|
614
|
+
});
|
|
615
|
+
|
|
492
616
|
// ============================================
|
|
493
617
|
// Main Component
|
|
494
618
|
// ============================================
|
|
@@ -498,6 +622,7 @@ export default function DomainGrid({ domain }: DomainGridProps) {
|
|
|
498
622
|
if (!data) return <div className="text-[rgb(var(--ec-page-text-muted))]">No domain data</div>;
|
|
499
623
|
|
|
500
624
|
const subdomains = data.domains || [];
|
|
625
|
+
const systems = data.systems || [];
|
|
501
626
|
const entities = data.entities || [];
|
|
502
627
|
const services = data.services || [];
|
|
503
628
|
const dataProducts = data['data-products'] || [];
|
|
@@ -535,6 +660,18 @@ export default function DomainGrid({ domain }: DomainGridProps) {
|
|
|
535
660
|
[services, subdomainServiceIds]
|
|
536
661
|
);
|
|
537
662
|
|
|
663
|
+
// Split top-level services into internal services and external integrations
|
|
664
|
+
// (mirrors the sidebar, where externalSystem services live under "External Integrations")
|
|
665
|
+
const topLevelInternalServices = useMemo(
|
|
666
|
+
() => topLevelServices.filter((s: any) => !(s?.data || s)?.externalSystem),
|
|
667
|
+
[topLevelServices]
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
const topLevelExternalServices = useMemo(
|
|
671
|
+
() => topLevelServices.filter((s: any) => (s?.data || s)?.externalSystem),
|
|
672
|
+
[topLevelServices]
|
|
673
|
+
);
|
|
674
|
+
|
|
538
675
|
const topLevelDataProducts = useMemo(
|
|
539
676
|
() =>
|
|
540
677
|
dataProducts.filter((dp: any) => {
|
|
@@ -553,22 +690,6 @@ export default function DomainGrid({ domain }: DomainGridProps) {
|
|
|
553
690
|
<h2 className="text-2xl md:text-4xl font-bold text-[rgb(var(--ec-page-text))]">{data.name || data.id}</h2>
|
|
554
691
|
{data.summary && <p className="text-lg pt-2 text-[rgb(var(--ec-page-text-muted))] font-light">{data.summary}</p>}
|
|
555
692
|
</div>
|
|
556
|
-
<div className="flex items-center gap-2 flex-shrink-0">
|
|
557
|
-
<a
|
|
558
|
-
href={buildUrl(`/docs/domains/${data.id}/${data.version}`)}
|
|
559
|
-
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-[rgb(var(--ec-page-text))] bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-lg hover:bg-[rgb(var(--ec-content-hover))] hover:border-[rgb(var(--ec-page-text-muted))] transition-all"
|
|
560
|
-
>
|
|
561
|
-
View docs
|
|
562
|
-
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-[rgb(var(--ec-icon-color))]" />
|
|
563
|
-
</a>
|
|
564
|
-
<a
|
|
565
|
-
href={buildUrl(`/visualiser/domains/${data.id}/${data.version}`)}
|
|
566
|
-
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-white bg-zinc-800 dark:bg-zinc-700 rounded-lg hover:bg-zinc-900 dark:hover:bg-zinc-600 transition-all"
|
|
567
|
-
>
|
|
568
|
-
Visualizer
|
|
569
|
-
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-zinc-400" />
|
|
570
|
-
</a>
|
|
571
|
-
</div>
|
|
572
693
|
</div>
|
|
573
694
|
</div>
|
|
574
695
|
|
|
@@ -593,39 +714,77 @@ export default function DomainGrid({ domain }: DomainGridProps) {
|
|
|
593
714
|
</div>
|
|
594
715
|
)}
|
|
595
716
|
|
|
717
|
+
{/* Subdomains */}
|
|
718
|
+
{subdomains.length > 0 && (
|
|
719
|
+
<div>
|
|
720
|
+
<div className="flex items-center gap-2 mb-4">
|
|
721
|
+
<RectangleGroupIcon className="h-5 w-5 text-orange-600 dark:text-orange-400" />
|
|
722
|
+
<h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Subdomains</h3>
|
|
723
|
+
<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">
|
|
724
|
+
{subdomains.length}
|
|
725
|
+
</span>
|
|
726
|
+
</div>
|
|
727
|
+
<div className="space-y-4">
|
|
728
|
+
{subdomains.map((subdomain: any) => {
|
|
729
|
+
const subdomainId = subdomain?.data?.id || subdomain?.id;
|
|
730
|
+
return subdomainId ? <SubdomainSection key={subdomainId} subdomain={subdomain} defaultOpen /> : null;
|
|
731
|
+
})}
|
|
732
|
+
</div>
|
|
733
|
+
</div>
|
|
734
|
+
)}
|
|
735
|
+
|
|
736
|
+
{/* Systems */}
|
|
737
|
+
{systems.length > 0 && (
|
|
738
|
+
<div>
|
|
739
|
+
<div className="flex items-center gap-2 mb-4">
|
|
740
|
+
<GroupIcon className="h-5 w-5 text-violet-600 dark:text-violet-400" />
|
|
741
|
+
<h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Systems</h3>
|
|
742
|
+
<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">
|
|
743
|
+
{systems.length}
|
|
744
|
+
</span>
|
|
745
|
+
</div>
|
|
746
|
+
<div className="space-y-4">
|
|
747
|
+
{systems.map((system: any) => {
|
|
748
|
+
const systemId = system?.data?.id || system?.id;
|
|
749
|
+
return systemId ? <SystemSection key={systemId} system={system} defaultOpen /> : null;
|
|
750
|
+
})}
|
|
751
|
+
</div>
|
|
752
|
+
</div>
|
|
753
|
+
)}
|
|
754
|
+
|
|
596
755
|
{/* Top-level Services */}
|
|
597
|
-
{
|
|
756
|
+
{topLevelInternalServices.length > 0 && (
|
|
598
757
|
<div>
|
|
599
758
|
<div className="flex items-center gap-2 mb-4">
|
|
600
759
|
<ServerIcon className="h-5 w-5 text-pink-600 dark:text-pink-400" />
|
|
601
760
|
<h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">Services</h3>
|
|
602
761
|
<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">
|
|
603
|
-
{
|
|
762
|
+
{topLevelInternalServices.length}
|
|
604
763
|
</span>
|
|
605
764
|
</div>
|
|
606
765
|
<div className="space-y-3">
|
|
607
|
-
{
|
|
766
|
+
{topLevelInternalServices.map((service: any) => {
|
|
608
767
|
const serviceId = service?.data?.id || service?.id;
|
|
609
|
-
return serviceId ? <ServiceCard key={serviceId} service={service} /> : null;
|
|
768
|
+
return serviceId ? <ServiceCard key={serviceId} service={service} defaultOpen /> : null;
|
|
610
769
|
})}
|
|
611
770
|
</div>
|
|
612
771
|
</div>
|
|
613
772
|
)}
|
|
614
773
|
|
|
615
|
-
{/*
|
|
616
|
-
{
|
|
774
|
+
{/* External Integrations (external systems) */}
|
|
775
|
+
{topLevelExternalServices.length > 0 && (
|
|
617
776
|
<div>
|
|
618
777
|
<div className="flex items-center gap-2 mb-4">
|
|
619
|
-
<
|
|
620
|
-
<h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">
|
|
778
|
+
<GlobeAltIcon className="h-5 w-5 text-sky-600 dark:text-sky-400" />
|
|
779
|
+
<h3 className="text-lg font-semibold text-[rgb(var(--ec-page-text))]">External Integrations</h3>
|
|
621
780
|
<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">
|
|
622
|
-
{
|
|
781
|
+
{topLevelExternalServices.length}
|
|
623
782
|
</span>
|
|
624
783
|
</div>
|
|
625
|
-
<div className="space-y-
|
|
626
|
-
{
|
|
627
|
-
const
|
|
628
|
-
return
|
|
784
|
+
<div className="space-y-3">
|
|
785
|
+
{topLevelExternalServices.map((service: any) => {
|
|
786
|
+
const serviceId = service?.data?.id || service?.id;
|
|
787
|
+
return serviceId ? <ServiceCard key={serviceId} service={service} defaultOpen /> : null;
|
|
629
788
|
})}
|
|
630
789
|
</div>
|
|
631
790
|
</div>
|
|
@@ -651,16 +810,20 @@ export default function DomainGrid({ domain }: DomainGridProps) {
|
|
|
651
810
|
)}
|
|
652
811
|
|
|
653
812
|
{/* Empty state */}
|
|
654
|
-
{entities.length === 0 &&
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
813
|
+
{entities.length === 0 &&
|
|
814
|
+
services.length === 0 &&
|
|
815
|
+
dataProducts.length === 0 &&
|
|
816
|
+
subdomains.length === 0 &&
|
|
817
|
+
systems.length === 0 && (
|
|
818
|
+
<div className="text-center py-12">
|
|
819
|
+
<div className="flex items-center justify-center w-16 h-16 mx-auto mb-4 bg-[rgb(var(--ec-content-hover))] rounded-2xl">
|
|
820
|
+
<RectangleGroupIcon className="h-8 w-8 text-[rgb(var(--ec-icon-color))]" />
|
|
821
|
+
</div>
|
|
822
|
+
<p className="text-[rgb(var(--ec-page-text-muted))]">
|
|
823
|
+
This domain has no entities, services, data products, subdomains, or systems defined.
|
|
824
|
+
</p>
|
|
658
825
|
</div>
|
|
659
|
-
|
|
660
|
-
This domain has no entities, services, data products, or subdomains defined.
|
|
661
|
-
</p>
|
|
662
|
-
</div>
|
|
663
|
-
)}
|
|
826
|
+
)}
|
|
664
827
|
</div>
|
|
665
828
|
</div>
|
|
666
829
|
);
|
|
@@ -2,7 +2,6 @@ import { memo, useState } from 'react';
|
|
|
2
2
|
import {
|
|
3
3
|
ServerIcon,
|
|
4
4
|
CircleStackIcon,
|
|
5
|
-
ArrowTopRightOnSquareIcon,
|
|
6
5
|
ArrowLongRightIcon,
|
|
7
6
|
BoltIcon,
|
|
8
7
|
ChatBubbleLeftIcon,
|
|
@@ -234,7 +233,6 @@ export default function MessageGridV2({ service, embeded = false, specifications
|
|
|
234
233
|
const { sends = [], receives = [], writesTo = [], readsFrom = [] } = service.data;
|
|
235
234
|
const collection = service.collection || 'services';
|
|
236
235
|
const resourceLabel = collection === 'agents' ? 'agent' : 'service';
|
|
237
|
-
const hasVisualizer = true;
|
|
238
236
|
const hasContainers = readsFrom.length > 0 || writesTo.length > 0;
|
|
239
237
|
const hasMessages = receives.length > 0 || sends.length > 0;
|
|
240
238
|
const hasSpecs = specifications.length > 0;
|
|
@@ -250,24 +248,6 @@ export default function MessageGridV2({ service, embeded = false, specifications
|
|
|
250
248
|
<p className="text-lg pt-2 text-[rgb(var(--ec-page-text-muted))] font-light">{service.data.summary}</p>
|
|
251
249
|
)}
|
|
252
250
|
</div>
|
|
253
|
-
<div className="flex items-center gap-2 flex-shrink-0">
|
|
254
|
-
<a
|
|
255
|
-
href={buildUrl(`/docs/${collection}/${service.data.id}/${service.data.version}`)}
|
|
256
|
-
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-[rgb(var(--ec-page-text))] bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))] border border-[rgb(var(--ec-page-border))] rounded-lg hover:bg-[rgb(var(--ec-content-hover))] hover:border-[rgb(var(--ec-page-text-muted))] transition-all"
|
|
257
|
-
>
|
|
258
|
-
View docs
|
|
259
|
-
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-[rgb(var(--ec-icon-color))]" />
|
|
260
|
-
</a>
|
|
261
|
-
{hasVisualizer && (
|
|
262
|
-
<a
|
|
263
|
-
href={buildUrl(`/visualiser/${collection}/${service.data.id}/${service.data.version}`)}
|
|
264
|
-
className="inline-flex items-center gap-1.5 px-3 py-2 text-sm font-medium text-white bg-zinc-800 dark:bg-zinc-700 rounded-lg hover:bg-zinc-900 dark:hover:bg-zinc-600 transition-all"
|
|
265
|
-
>
|
|
266
|
-
Visualizer
|
|
267
|
-
<ArrowTopRightOnSquareIcon className="h-4 w-4 text-zinc-400" />
|
|
268
|
-
</a>
|
|
269
|
-
)}
|
|
270
|
-
</div>
|
|
271
251
|
</div>
|
|
272
252
|
</div>
|
|
273
253
|
|