@eventcatalog/core 4.12.2 → 5.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/LICENSE +226 -95
- package/NOTICE +30 -0
- package/README.md +3 -2
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +43 -16
- package/dist/analytics/log-build.d.cts +6 -5
- package/dist/analytics/log-build.d.ts +6 -5
- package/dist/analytics/log-build.js +4 -3
- package/dist/{chunk-U4YJSTGV.js → chunk-AYNZXUB5.js} +2 -10
- package/dist/{chunk-IVVM67LN.js → chunk-CR6AK5LR.js} +1 -1
- package/dist/{chunk-GTIC4R74.js → chunk-LR7AGRHN.js} +13 -16
- package/dist/chunk-TQLRG35T.js +203 -0
- package/dist/{chunk-WK4J6FP3.js → chunk-TWN43V4T.js} +1 -1
- package/dist/{chunk-ZW3MYAWF.js → chunk-WAIADKQE.js} +1 -1
- package/dist/{chunk-RPVA2SZY.js → chunk-ZHKEARLJ.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +407 -291
- package/dist/eventcatalog.config.d.cts +2 -3
- package/dist/eventcatalog.config.d.ts +2 -3
- package/dist/eventcatalog.js +30 -93
- package/dist/federation/content-cache.d.cts +0 -5
- package/dist/federation/content-cache.d.ts +0 -5
- package/dist/federation/diagnostics.d.cts +0 -5
- package/dist/federation/diagnostics.d.ts +0 -5
- package/dist/federation/federate.cjs +0 -9
- package/dist/federation/federate.d.cts +0 -5
- package/dist/federation/federate.d.ts +0 -5
- package/dist/federation/federate.js +2 -3
- package/dist/federation/filesystem-source-provider.d.cts +0 -5
- package/dist/federation/filesystem-source-provider.d.ts +0 -5
- package/dist/federation/github-source-provider.d.cts +0 -5
- package/dist/federation/github-source-provider.d.ts +0 -5
- package/dist/federation/output-transaction.d.cts +0 -4
- package/dist/federation/output-transaction.d.ts +0 -4
- package/dist/federation/public-assets.d.cts +0 -5
- package/dist/federation/public-assets.d.ts +0 -5
- package/dist/federation/source-provider.d.cts +0 -5
- package/dist/federation/source-provider.d.ts +0 -5
- package/dist/federation/types.d.cts +0 -5
- package/dist/federation/types.d.ts +0 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/license-C1y-56bb.d.cts +23 -0
- package/dist/license-C1y-56bb.d.ts +23 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__layout.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__react.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__server.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__sdk__types.js.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +12 -1
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__graphql.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__json.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__markup.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__protobuf.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__yaml.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-dark.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-light.mjs +3 -0
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/dist/utils/license-status.cjs +240 -0
- package/dist/utils/license-status.d.cts +28 -0
- package/dist/utils/license-status.d.ts +28 -0
- package/dist/utils/license-status.js +12 -0
- package/eventcatalog/astro.config.mjs +1 -1
- package/eventcatalog/integrations/eventcatalog-runtime.mjs +1 -1
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +29 -19
- package/eventcatalog/src/components/ChatPanel/OfflineReply.tsx +74 -0
- package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +24 -28
- package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +16 -11
- package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +4 -218
- package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +27 -36
- package/eventcatalog/src/components/Header.astro +43 -58
- package/eventcatalog/src/components/Lists/PillListFlat.styles.css +17 -17
- package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +1 -1
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +4 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +14 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +49 -18
- package/eventcatalog/src/components/MDX/RemoteFile.astro +2 -24
- package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +59 -93
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -32
- package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +20 -67
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -11
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +11 -60
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -3
- package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +0 -3
- package/eventcatalog/src/components/SchemaExplorer/VersionHistoryModal.tsx +2 -9
- package/eventcatalog/src/components/SchemaExplorer/parse-schema.ts +46 -0
- package/eventcatalog/src/components/SchemaExplorer/utils.ts +11 -0
- package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +2 -9
- package/eventcatalog/src/components/Settings/LicenseSettings.tsx +288 -0
- package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +3 -19
- package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +85 -30
- package/eventcatalog/src/components/Settings/SettingsShared.tsx +7 -75
- package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +2 -2
- package/eventcatalog/src/components/TrialBadge.astro +82 -0
- package/eventcatalog/src/content.config.ts +9 -90
- package/eventcatalog/src/{enterprise → features}/ai/chat-api.ts +22 -34
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/ga4.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/gtm.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/posthog.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsHead.astro +2 -4
- package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsTracker.astro +2 -4
- package/eventcatalog/src/{enterprise → features}/analytics/tracker.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/api/catalog.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/[...auth].ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware-auth.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/custom-pages.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/index.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/resource-docs.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/collection.ts +0 -5
- package/eventcatalog/src/features/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/index.tsx +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/types.ts +0 -5
- package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/index.astro → features/custom-documentation/components/CustomDocumentationPage.astro} +5 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/badge-styles.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/custom-docs.ts +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/docs-search.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-pages/routes.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/directory/user-team-directory.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/field-extractor.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/field-indexer.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/fields-db.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/pages/api/fields.ts +1 -6
- package/eventcatalog/src/{enterprise → features}/fields/pages/fields.astro +1 -2
- package/eventcatalog/src/{enterprise → features}/integrations/eventcatalog-features.ts +17 -75
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/links.ts +59 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +299 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/shared.ts +14 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/view.tsx +454 -0
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +432 -0
- package/eventcatalog/src/features/mcp/apps/mermaid-stub.ts +10 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/schema-code.tsx +65 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/shared.ts +23 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/view.tsx +170 -0
- package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +98 -0
- package/eventcatalog/src/features/mcp/apps/shared/resource-types.ts +15 -0
- package/eventcatalog/src/features/mcp/apps/viewer/shared.ts +24 -0
- package/eventcatalog/src/features/mcp/apps/viewer/styles.css +25 -0
- package/eventcatalog/src/features/mcp/apps/viewer/view.tsx +59 -0
- package/eventcatalog/src/features/mcp/mcp-app-icons.ts +63 -0
- package/eventcatalog/src/features/mcp/mcp-apps.ts +160 -0
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-auth.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-scope.ts +7 -7
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-scoped-tools.ts +47 -40
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-server.ts +347 -34
- package/eventcatalog/src/{enterprise → features}/mcp/oauth-protected-resource.ts +0 -5
- package/eventcatalog/src/features/mcp/schema-viewer.ts +24 -0
- package/eventcatalog/src/{enterprise → features}/tools/catalog-tools.ts +133 -102
- package/eventcatalog/src/features/tools/index.ts +5 -0
- package/eventcatalog/src/{enterprise → features}/visualizer-layout/reset.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/visualizer-layout/save.ts +0 -5
- package/eventcatalog/src/layouts/BaseLayout.astro +2 -2
- package/eventcatalog/src/layouts/Footer.astro +31 -39
- package/eventcatalog/src/layouts/SettingsLayout.astro +6 -6
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -37
- package/eventcatalog/src/{enterprise → pages}/api/schemas/[collection]/[id]/[version]/index.ts +0 -22
- package/eventcatalog/src/{enterprise → pages}/api/schemas/services/[id]/[version]/[specification]/index.ts +0 -19
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].md.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +9 -5
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +12 -0
- package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/root-index.astro → pages/docs/custom/index.astro} +1 -23
- package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +4 -9
- package/eventcatalog/src/pages/docs/llm/llms.txt.ts +4 -4
- package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +0 -11
- package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +2 -2
- package/eventcatalog/src/pages/index.astro +2 -2
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +0 -3
- package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -4
- package/eventcatalog/src/pages/settings/assistant.astro +2 -4
- package/eventcatalog/src/pages/settings/license.astro +18 -0
- package/eventcatalog/src/pages/settings/llm-access.astro +1 -4
- package/eventcatalog/src/pages/settings/mcp.astro +33 -4
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -2
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +2 -45
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +7 -109
- package/eventcatalog/src/pages/visualiser/_mermaid-route.ts +78 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/_index.data.ts +44 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +56 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +3 -40
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version].mermaid.ts +20 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/_index.data.ts +29 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +3 -38
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +56 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version].mermaid.ts +20 -0
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +1 -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 +7 -32
- package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +2 -8
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +2 -12
- package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +0 -10
- package/eventcatalog/src/stores/sidebar-store/state.ts +4 -6
- package/eventcatalog/src/styles/theme.css +22 -18
- package/eventcatalog/src/styles/themes/forest.css +8 -8
- package/eventcatalog/src/styles/themes/ocean.css +8 -8
- package/eventcatalog/src/styles/themes/sapphire.css +8 -8
- package/eventcatalog/src/styles/themes/sunset.css +8 -8
- package/eventcatalog/src/utils/clipboard.ts +4 -4
- package/eventcatalog/src/utils/collections/flow-step-schema.ts +117 -0
- package/eventcatalog/src/utils/collections/pointer-schema.ts +7 -0
- package/eventcatalog/src/utils/collections/resource-docs.ts +677 -14
- package/eventcatalog/src/utils/collections/schema-loader.ts +0 -5
- package/eventcatalog/src/utils/feature.ts +14 -23
- package/eventcatalog/src/utils/license.ts +114 -0
- package/eventcatalog/src/utils/node-graphs/architecture-diagram-types.ts +32 -0
- package/eventcatalog/src/utils/node-graphs/architecture-diagram.ts +84 -0
- package/eventcatalog/src/utils/node-graphs/catalog-force-graph.ts +1 -0
- package/eventcatalog/src/utils/node-graphs/channel-node-graph.ts +4 -25
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -39
- package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +11 -27
- package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +679 -0
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +3 -20
- package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +62 -4
- package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +8 -23
- package/eventcatalog/src/utils/node-graphs/flow-lanes.ts +119 -0
- package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +153 -45
- package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +28 -0
- package/eventcatalog/src/utils/node-graphs/layout-persistence.ts +3 -3
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +16 -34
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +11 -25
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +18 -54
- package/eventcatalog/src/utils/node-graphs/system-levels-node-graph.ts +59 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +20 -80
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +1 -78
- package/eventcatalog/src/utils/trial.ts +36 -0
- package/eventcatalog/tsconfig.json +1 -1
- package/package.json +11 -11
- package/dist/chunk-FV56YFM4.js +0 -7
- package/dist/federation/entitlement.cjs +0 -31
- package/dist/federation/entitlement.d.cts +0 -12
- package/dist/federation/entitlement.d.ts +0 -12
- package/dist/federation/entitlement.js +0 -6
- package/dist/runtime-dependencies/dagre.mjs +0 -3
- package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +0 -265
- package/eventcatalog/src/enterprise/LICENSE +0 -57
- package/eventcatalog/src/enterprise/README.md +0 -5
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +0 -691
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +0 -9
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/[...path]/index.astro +0 -18
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/feature.astro +0 -171
- package/eventcatalog/src/enterprise/feature.ts +0 -75
- package/eventcatalog/src/enterprise/tools/index.ts +0 -10
- package/eventcatalog/src/hooks/eventcatalog-visualizer.ts +0 -126
- package/eventcatalog/src/pages/settings/billing.astro +0 -17
- package/eventcatalog/src/pages/visualiser/domain-integrations/index.astro +0 -26
- package/eventcatalog/src/types/mcp-modules.d.ts +0 -67
- package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +0 -261
- package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +0 -91
- /package/eventcatalog/src/{enterprise → features}/auth/error.astro +0 -0
- /package/eventcatalog/src/{enterprise → features}/auth/login.astro +0 -0
- /package/eventcatalog/src/{enterprise → features}/auth/unauthorized.astro +0 -0
- /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path]/_index.data.ts +0 -0
- /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path].mdx.ts +0 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A small modal shown next to a node clicked in the architecture diagram view, to ask a question
|
|
3
|
+
* about it. Nothing is sent until the user sends their question: it then goes to the conversation
|
|
4
|
+
* in the MCP host with the node it is about, so the model can answer it with the EventCatalog tools.
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect, useRef, useState, type FormEvent, type KeyboardEvent, type RefObject } from 'react';
|
|
7
|
+
import type { Node } from '@xyflow/react';
|
|
8
|
+
import { Check, Network, SendHorizontal, X } from 'lucide-react';
|
|
9
|
+
import type { ArchitectureDiagramCollection } from '@utils/node-graphs/architecture-diagram-types';
|
|
10
|
+
import type { DiagramLink } from './links';
|
|
11
|
+
import { RESOURCE_TYPE_LABELS } from '../shared/resource-types';
|
|
12
|
+
|
|
13
|
+
export type SelectedNode = {
|
|
14
|
+
/** The node's id in the diagram, to find it on screen */
|
|
15
|
+
nodeId: string;
|
|
16
|
+
type: string;
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
version?: string;
|
|
20
|
+
summary?: string;
|
|
21
|
+
/** The resource's own architecture diagram, when it has one */
|
|
22
|
+
diagram?: DiagramLink;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const NODE_TYPE_LABELS: Record<string, string> = {
|
|
26
|
+
...RESOURCE_TYPE_LABELS,
|
|
27
|
+
data: 'Data store',
|
|
28
|
+
'context-domain': 'Domain',
|
|
29
|
+
'domain-group': 'Domain',
|
|
30
|
+
'system-group': 'System',
|
|
31
|
+
'context-actor': 'Actor',
|
|
32
|
+
actor: 'Actor',
|
|
33
|
+
user: 'User',
|
|
34
|
+
step: 'Step',
|
|
35
|
+
custom: 'Step',
|
|
36
|
+
externalSystem: 'External system',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Where each node type keeps the resource it shows
|
|
40
|
+
const RESOURCE_DATA_KEYS = [
|
|
41
|
+
'service',
|
|
42
|
+
'agent',
|
|
43
|
+
'message',
|
|
44
|
+
'channel',
|
|
45
|
+
'data',
|
|
46
|
+
'dataProduct',
|
|
47
|
+
'flow',
|
|
48
|
+
'entity',
|
|
49
|
+
'domain',
|
|
50
|
+
'system',
|
|
51
|
+
'custom',
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
// The collection of each node type the architecture diagram tool can draw a diagram for
|
|
55
|
+
const DIAGRAM_COLLECTIONS: Record<string, ArchitectureDiagramCollection> = {
|
|
56
|
+
services: 'services',
|
|
57
|
+
agents: 'agents',
|
|
58
|
+
events: 'events',
|
|
59
|
+
commands: 'commands',
|
|
60
|
+
queries: 'queries',
|
|
61
|
+
flows: 'flows',
|
|
62
|
+
data: 'containers',
|
|
63
|
+
containers: 'containers',
|
|
64
|
+
'data-products': 'data-products',
|
|
65
|
+
domains: 'domains',
|
|
66
|
+
'context-domain': 'domains',
|
|
67
|
+
'domain-group': 'domains',
|
|
68
|
+
systems: 'systems',
|
|
69
|
+
'system-group': 'systems',
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Domain and system boundaries only have their catalog id in the node id: {kind}-group-{id}-{version}
|
|
73
|
+
const catalogIdOfGroup = (node: Node, version?: string) => {
|
|
74
|
+
const match = node.id.match(/^(?:domain|system)-group-(.+)$/);
|
|
75
|
+
if (!match) return undefined;
|
|
76
|
+
return version && match[1].endsWith(`-${version}`) ? match[1].slice(0, -(version.length + 1)) : match[1];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function describeNode(node: Node): SelectedNode {
|
|
80
|
+
const data = (node.data ?? {}) as Record<string, any>;
|
|
81
|
+
const resource = RESOURCE_DATA_KEYS.map((key) => data[key]).find(Boolean) ?? data;
|
|
82
|
+
const details = resource?.data ?? resource;
|
|
83
|
+
const version: string | undefined = details?.version;
|
|
84
|
+
const id: string = details?.id ?? catalogIdOfGroup(node, version) ?? node.id;
|
|
85
|
+
const collection = DIAGRAM_COLLECTIONS[node.type ?? ''];
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
nodeId: node.id,
|
|
89
|
+
type: NODE_TYPE_LABELS[node.type ?? ''] ?? node.type ?? 'Resource',
|
|
90
|
+
id,
|
|
91
|
+
name: details?.name ?? details?.title ?? details?.id ?? data.name ?? data.step?.title ?? node.id,
|
|
92
|
+
version,
|
|
93
|
+
summary: typeof details?.summary === 'string' ? details.summary.trim() : undefined,
|
|
94
|
+
diagram: collection && version ? { collection, id, version } : undefined,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** How the node is described to the model, so it can look it up in EventCatalog */
|
|
99
|
+
export const describeNodeForModel = (node: Pick<SelectedNode, 'type' | 'id' | 'name' | 'version'>) =>
|
|
100
|
+
`the ${node.type.toLowerCase()} "${node.name}" (id: ${node.id}${node.version ? `, version: ${node.version}` : ''})`;
|
|
101
|
+
|
|
102
|
+
const MODAL_WIDTH = 300;
|
|
103
|
+
const GAP = 12;
|
|
104
|
+
const EDGE = 8;
|
|
105
|
+
|
|
106
|
+
type Anchor = { top: number; left: number; side: 'right' | 'left' };
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Where to show the modal: next to the node (on its right, or its left when there is no room),
|
|
110
|
+
* kept inside the diagram and following the node as the diagram is panned or zoomed.
|
|
111
|
+
*/
|
|
112
|
+
function useNodeAnchor(nodeId: string, containerRef: RefObject<HTMLElement | null>, modalRef: RefObject<HTMLElement | null>) {
|
|
113
|
+
const [anchor, setAnchor] = useState<Anchor | null>(null);
|
|
114
|
+
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
let frame = 0;
|
|
117
|
+
const update = () => {
|
|
118
|
+
const container = containerRef.current;
|
|
119
|
+
const element = container?.querySelector<HTMLElement>(`.react-flow__node[data-id="${CSS.escape(nodeId)}"]`);
|
|
120
|
+
if (container && element) {
|
|
121
|
+
const bounds = container.getBoundingClientRect();
|
|
122
|
+
const rect = element.getBoundingClientRect();
|
|
123
|
+
const height = modalRef.current?.offsetHeight ?? 200;
|
|
124
|
+
const side = rect.right + GAP + MODAL_WIDTH <= bounds.right - EDGE ? 'right' : 'left';
|
|
125
|
+
const left = side === 'right' ? rect.right - bounds.left + GAP : rect.left - bounds.left - GAP - MODAL_WIDTH;
|
|
126
|
+
const clamp = (value: number, max: number) => Math.min(Math.max(value, EDGE), Math.max(max, EDGE));
|
|
127
|
+
const next: Anchor = {
|
|
128
|
+
side,
|
|
129
|
+
left: clamp(left, bounds.width - MODAL_WIDTH - EDGE),
|
|
130
|
+
top: clamp(rect.top - bounds.top, bounds.height - height - EDGE),
|
|
131
|
+
};
|
|
132
|
+
setAnchor((previous) =>
|
|
133
|
+
previous?.left === next.left && previous?.top === next.top && previous?.side === next.side ? previous : next
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
frame = requestAnimationFrame(update);
|
|
137
|
+
};
|
|
138
|
+
update();
|
|
139
|
+
return () => cancelAnimationFrame(frame);
|
|
140
|
+
}, [nodeId, containerRef, modalRef]);
|
|
141
|
+
|
|
142
|
+
return anchor;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
type NodeChatProps = {
|
|
146
|
+
node: SelectedNode;
|
|
147
|
+
/** The diagram the node is in, to position the modal next to it */
|
|
148
|
+
containerRef: RefObject<HTMLElement | null>;
|
|
149
|
+
/** Whether the host lets the view send messages to the conversation */
|
|
150
|
+
canSend: boolean;
|
|
151
|
+
onSend: (question: string) => Promise<void>;
|
|
152
|
+
/** Opens the node's own diagram in the view, when it has one */
|
|
153
|
+
onOpenDiagram?: () => void;
|
|
154
|
+
onClose: () => void;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export function NodeChat({ node, containerRef, canSend, onSend, onOpenDiagram, onClose }: NodeChatProps) {
|
|
158
|
+
const [question, setQuestion] = useState('');
|
|
159
|
+
const [status, setStatus] = useState<'idle' | 'sending' | 'sent' | 'failed'>('idle');
|
|
160
|
+
const modalRef = useRef<HTMLDivElement>(null);
|
|
161
|
+
const inputRef = useRef<HTMLTextAreaElement>(null);
|
|
162
|
+
const anchor = useNodeAnchor(node.nodeId, containerRef, modalRef);
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
setQuestion('');
|
|
166
|
+
setStatus('idle');
|
|
167
|
+
}, [node.nodeId]);
|
|
168
|
+
|
|
169
|
+
// Focus the question once the modal is shown next to the node (it is hidden until then, and
|
|
170
|
+
// can't take focus). Waits a moment so a closing right-click menu doesn't take the focus back.
|
|
171
|
+
const isShown = anchor !== null;
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (!isShown) return;
|
|
174
|
+
const timeout = setTimeout(() => inputRef.current?.focus({ preventScroll: true }), 50);
|
|
175
|
+
return () => clearTimeout(timeout);
|
|
176
|
+
}, [isShown, node.nodeId]);
|
|
177
|
+
|
|
178
|
+
// Close on Escape, or on a click on the empty diagram (but not when it is dragged to pan)
|
|
179
|
+
useEffect(() => {
|
|
180
|
+
let pressedAt: { x: number; y: number } | null = null;
|
|
181
|
+
const onPointerDown = (event: PointerEvent) => {
|
|
182
|
+
pressedAt = (event.target as Element).closest?.('.react-flow__pane') ? { x: event.clientX, y: event.clientY } : null;
|
|
183
|
+
};
|
|
184
|
+
const onPointerUp = (event: PointerEvent) => {
|
|
185
|
+
if (pressedAt && Math.hypot(event.clientX - pressedAt.x, event.clientY - pressedAt.y) < 4) onClose();
|
|
186
|
+
pressedAt = null;
|
|
187
|
+
};
|
|
188
|
+
const onKeyDown = (event: globalThis.KeyboardEvent) => event.key === 'Escape' && onClose();
|
|
189
|
+
document.addEventListener('pointerdown', onPointerDown, true);
|
|
190
|
+
document.addEventListener('pointerup', onPointerUp, true);
|
|
191
|
+
document.addEventListener('keydown', onKeyDown);
|
|
192
|
+
return () => {
|
|
193
|
+
document.removeEventListener('pointerdown', onPointerDown, true);
|
|
194
|
+
document.removeEventListener('pointerup', onPointerUp, true);
|
|
195
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
196
|
+
};
|
|
197
|
+
}, [onClose]);
|
|
198
|
+
|
|
199
|
+
// Close shortly after the question is sent, once the user has seen it went
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (status !== 'sent') return;
|
|
202
|
+
const timeout = setTimeout(onClose, 1500);
|
|
203
|
+
return () => clearTimeout(timeout);
|
|
204
|
+
}, [status, onClose]);
|
|
205
|
+
|
|
206
|
+
const send = async () => {
|
|
207
|
+
if (!question.trim() || status === 'sending' || status === 'sent') return;
|
|
208
|
+
setStatus('sending');
|
|
209
|
+
try {
|
|
210
|
+
await onSend(question.trim());
|
|
211
|
+
setStatus('sent');
|
|
212
|
+
} catch {
|
|
213
|
+
setStatus('failed');
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const handleSubmit = (event: FormEvent) => {
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
send();
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Enter sends, Shift+Enter adds a new line
|
|
223
|
+
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
|
224
|
+
if (event.key === 'Enter' && !event.shiftKey) {
|
|
225
|
+
event.preventDefault();
|
|
226
|
+
send();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return (
|
|
231
|
+
<div
|
|
232
|
+
ref={modalRef}
|
|
233
|
+
className="ec-mcp-modal"
|
|
234
|
+
data-side={anchor?.side ?? 'right'}
|
|
235
|
+
role="dialog"
|
|
236
|
+
aria-label={`Ask a question about ${node.name}`}
|
|
237
|
+
style={{
|
|
238
|
+
width: MODAL_WIDTH,
|
|
239
|
+
top: anchor?.top ?? EDGE,
|
|
240
|
+
left: anchor?.left ?? EDGE,
|
|
241
|
+
visibility: anchor ? 'visible' : 'hidden',
|
|
242
|
+
}}
|
|
243
|
+
>
|
|
244
|
+
<div className="ec-mcp-modal-header">
|
|
245
|
+
<span className="ec-mcp-type">{node.type}</span>
|
|
246
|
+
<span className="ec-mcp-name">{node.name}</span>
|
|
247
|
+
{node.version && <span className="ec-mcp-version">v{node.version}</span>}
|
|
248
|
+
<button type="button" className="ec-mcp-modal-close" aria-label="Close" onClick={onClose}>
|
|
249
|
+
<X aria-hidden />
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
{node.summary && <p className="ec-mcp-modal-summary">{node.summary}</p>}
|
|
253
|
+
{onOpenDiagram && (
|
|
254
|
+
<button type="button" className="ec-mcp-modal-link" onClick={onOpenDiagram}>
|
|
255
|
+
<Network aria-hidden />
|
|
256
|
+
Open the {node.type.toLowerCase()} diagram
|
|
257
|
+
</button>
|
|
258
|
+
)}
|
|
259
|
+
|
|
260
|
+
{status === 'sent' ? (
|
|
261
|
+
<p className="ec-mcp-modal-sent">
|
|
262
|
+
<Check aria-hidden />
|
|
263
|
+
Sent to the chat
|
|
264
|
+
</p>
|
|
265
|
+
) : canSend ? (
|
|
266
|
+
<form className="ec-mcp-modal-form" onSubmit={handleSubmit}>
|
|
267
|
+
<label htmlFor="ec-mcp-question">Ask a question</label>
|
|
268
|
+
<div className="ec-mcp-composer">
|
|
269
|
+
<textarea
|
|
270
|
+
id="ec-mcp-question"
|
|
271
|
+
ref={inputRef}
|
|
272
|
+
rows={2}
|
|
273
|
+
value={question}
|
|
274
|
+
placeholder={`Ask about ${node.name}…`}
|
|
275
|
+
disabled={status === 'sending'}
|
|
276
|
+
onChange={(event) => setQuestion(event.target.value)}
|
|
277
|
+
onKeyDown={handleKeyDown}
|
|
278
|
+
/>
|
|
279
|
+
<div className="ec-mcp-composer-footer">
|
|
280
|
+
<span className="ec-mcp-composer-hint">Enter to send</span>
|
|
281
|
+
<button
|
|
282
|
+
type="submit"
|
|
283
|
+
className="ec-mcp-composer-send"
|
|
284
|
+
aria-label={status === 'sending' ? 'Sending' : 'Send to chat'}
|
|
285
|
+
title="Send to chat"
|
|
286
|
+
disabled={!question.trim() || status === 'sending'}
|
|
287
|
+
>
|
|
288
|
+
<SendHorizontal aria-hidden />
|
|
289
|
+
</button>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
{status === 'failed' && <p className="ec-mcp-modal-error">Couldn't send this to the chat. Try again.</p>}
|
|
293
|
+
</form>
|
|
294
|
+
) : (
|
|
295
|
+
<p className="ec-mcp-modal-hint">This app can't send questions here. Ask about {node.name} in the chat.</p>
|
|
296
|
+
)}
|
|
297
|
+
</div>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared by the MCP server and the architecture diagram MCP App view (view.tsx, shown by the viewer in ../viewer).
|
|
3
|
+
* Kept free of server-only imports so it can be bundled into the view.
|
|
4
|
+
*/
|
|
5
|
+
import type { ArchitectureDiagramView } from '@utils/node-graphs/architecture-diagram-types';
|
|
6
|
+
|
|
7
|
+
export type ArchitectureDiagramPayload = {
|
|
8
|
+
resource: { collection: string; id: string; version: string; name: string };
|
|
9
|
+
/** The EventCatalog the diagram came from, for links back to it */
|
|
10
|
+
catalogUrl: string;
|
|
11
|
+
/** Path of the resource's Diagram page in EventCatalog */
|
|
12
|
+
visualiserPath: string;
|
|
13
|
+
view: ArchitectureDiagramView;
|
|
14
|
+
};
|