@eventcatalog/core 5.0.0-beta.9 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +13 -12
- package/README.md +5 -5
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +91 -44
- package/dist/analytics/log-build.d.cts +2 -2
- package/dist/analytics/log-build.d.ts +2 -2
- package/dist/analytics/log-build.js +6 -5
- package/dist/analytics/studio-usage.cjs +90 -0
- package/dist/analytics/studio-usage.d.cts +5 -0
- package/dist/analytics/studio-usage.d.ts +5 -0
- package/dist/analytics/studio-usage.js +10 -0
- package/dist/catalog-runtime.cjs +1 -1
- package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
- package/dist/{chunk-AWOO63ME.js → chunk-AD7CL772.js} +11 -4
- package/dist/chunk-CA6WCQ2T.js +54 -0
- package/dist/{chunk-GAHKCOQM.js → chunk-JZN4RSMF.js} +1 -1
- package/dist/{chunk-JQMYHZWI.js → chunk-NEAVAFSJ.js} +16 -8
- package/dist/{chunk-4CFZUHGG.js → chunk-NIVST4WY.js} +1 -1
- package/dist/{chunk-ENAG6UH7.js → chunk-NKNOXQ62.js} +1 -6
- package/dist/{chunk-ZEY2XUJN.js → chunk-OX6TSVHY.js} +6 -6
- package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
- package/dist/{chunk-EUNQJO3J.js → chunk-RE7UTPWH.js} +1 -1
- package/dist/chunk-S5GWAUG5.js +29 -0
- package/dist/{chunk-TZVDMWQX.js → chunk-YQGRMDRB.js} +4 -2
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/docs/api/02-config.md +57 -7
- package/dist/docs/development/00-why-eventcatalog.md +11 -11
- package/dist/docs/development/01-fundamentals.md +20 -13
- package/dist/docs/development/01-getting-started/configuration-overview.md +2 -2
- package/dist/docs/development/01-getting-started/installation.md +9 -1
- package/dist/docs/development/_getting-started.mdx +1 -1
- package/dist/docs/development/ask-your-architecture/01-intro.md +5 -5
- package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/01-what-is-eventcatalog-assistant.md +0 -4
- package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/02-configuration.md +15 -3
- package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/03-bring-your-own-tools.md +0 -3
- package/dist/docs/development/ask-your-architecture/02-eventcatalog-assistant/_category_.json +1 -1
- package/dist/docs/development/ask-your-architecture/02-llms.txt.md +1 -1
- package/dist/docs/development/ask-your-architecture/{05-skills/01-introduction.md → 03-install-skills.md} +57 -7
- package/dist/docs/development/ask-your-architecture/03-mcp-server/_category_.json +1 -1
- package/dist/docs/development/ask-your-architecture/03-mcp-server/getting-started.md +86 -33
- package/dist/docs/development/ask-your-architecture/03-mcp-server/introduction.md +14 -4
- package/dist/docs/development/ask-your-architecture/03-schemas.txt.md +1 -1
- package/dist/docs/development/ask-your-architecture/04-agents/_category_.json +1 -1
- package/dist/docs/development/authentication/01-introduction.md +2 -23
- package/dist/docs/development/authentication/02-enabling-authentication.md +0 -20
- package/dist/docs/development/authentication/07-rbac-middleware.md +0 -2
- package/dist/docs/development/authentication/providers/03-setting-up-github.md +0 -2
- package/dist/docs/development/authentication/providers/03a-setting-up-google.md +0 -2
- package/dist/docs/development/authentication/providers/04-setting-up-azure-ad.md +0 -2
- package/dist/docs/development/authentication/providers/05-setting-up-okta.md +0 -3
- package/dist/docs/development/authentication/providers/06-setting-up-auth0.md +0 -2
- package/dist/docs/development/bring-your-own-documentation/01-introduction.md +0 -4
- package/dist/docs/development/bring-your-own-documentation/custom-pages/01-introduction.md +0 -3
- package/dist/docs/development/bring-your-own-documentation/custom-pages/02-adding-custom-docs.md +0 -17
- package/dist/docs/development/bring-your-own-documentation/custom-pages/03-components.md +0 -4
- package/dist/docs/development/bring-your-own-documentation/custom-pages/04-owners.md +0 -2
- package/dist/docs/development/bring-your-own-documentation/resource-docs/01-introduction.md +1 -3
- package/dist/docs/development/bring-your-own-documentation/resource-docs/02-adding-resource-docs.md +1 -4
- package/dist/docs/development/bring-your-own-documentation/resource-docs/03-categories.md +0 -2
- package/dist/docs/development/bring-your-own-documentation/resource-docs/04-versioning.md +1 -3
- package/dist/docs/development/components/components/11-flow.md +17 -0
- package/dist/docs/development/components/components/15-nodegraph.md +43 -10
- package/dist/docs/development/components/components/18-remote-schema.md +1 -4
- package/dist/docs/development/components/custom-components/07-reference.md +14 -0
- package/dist/docs/development/customization/02-themes.md +0 -5
- package/dist/docs/development/customization/03-search.md +1 -1
- package/dist/docs/development/customization/05-custom-pages-and-api-routes/01-introduction.md +0 -2
- package/dist/docs/development/customization/05-custom-pages-and-api-routes/04-reference.md +7 -1
- package/dist/docs/development/customization/05-resource-sidebar.md +1 -1
- package/dist/docs/development/customization/09-embed-eventcatalog.md +20 -25
- package/dist/docs/development/deployment/hosting-options.md +7 -2
- package/dist/docs/development/developer-tools/eventcatalog-linter/how-to/05-fix-common-problems.md +16 -0
- package/dist/docs/development/developer-tools/eventcatalog-linter/reference/03-rules.md +31 -1
- package/dist/docs/development/developer-tools/eventcatalog-linter/reference/05-supported-resources.md +1 -1
- package/dist/docs/development/governance/architecture-change-detection/01-introduction.md +0 -10
- package/dist/docs/development/governance/architecture-change-detection/06-pipeline-gates.md +0 -4
- package/dist/docs/development/guides/97-architecture-graph.md +1 -1
- package/dist/docs/development/guides/99-adding-analytics.md +0 -7
- package/dist/docs/development/guides/domains/03-model-subdomains.md +2 -2
- package/dist/docs/development/guides/domains/04-add-resources-to-domains/01-add-systems-to-domains.md +3 -1
- package/dist/docs/development/guides/domains/04-add-resources-to-domains/02-add-services-to-domains.md +5 -1
- package/dist/docs/development/guides/domains/04-add-resources-to-domains/03-add-messages-to-domains.md +2 -2
- package/dist/docs/development/guides/domains/04-add-resources-to-domains/05-add-entities-to-domains.md +1 -1
- package/dist/docs/development/guides/domains/04-add-resources-to-domains/06-domain-resources-page.md +40 -0
- package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-diagram.md +89 -0
- package/dist/docs/development/guides/domains/06-visualize-domains/_category_.json +1 -2
- package/dist/docs/development/guides/domains/09-reference.md +4 -4
- package/dist/docs/development/guides/owners/automated-teams-and-users/create-your-own-connector.md +0 -2
- package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-github.md +0 -3
- package/dist/docs/development/guides/owners/automated-teams-and-users/sync-from-microsoft-entra.md +0 -2
- package/dist/docs/development/guides/resources/adrs/03-linking-resources.md +8 -0
- package/dist/docs/development/guides/resources/adrs/06-reference.md +4 -4
- package/dist/docs/development/guides/resources/agents/11-reference.md +1 -1
- package/dist/docs/development/guides/resources/data/04-reference.md +1 -1
- package/dist/docs/development/guides/resources/data-products/07-reference.md +1 -1
- package/dist/docs/development/guides/resources/entities/05-entity-maps.md +1 -1
- package/dist/docs/development/guides/resources/entities/06-reference.md +2 -2
- package/dist/docs/development/guides/resources/flows/01-introduction.md +11 -1
- package/dist/docs/development/guides/resources/flows/03-model-flow-steps.md +65 -6
- package/dist/docs/development/guides/resources/flows/05-explore-flows.md +112 -0
- package/dist/docs/development/guides/resources/flows/06-reference.md +25 -4
- package/dist/docs/development/guides/resources/messages/01-what-are-messages.md +19 -0
- package/dist/docs/development/guides/resources/messages/04-message-channels/01-introduction.md +16 -0
- package/dist/docs/development/guides/resources/messages/04-message-channels/05-reference.md +2 -1
- package/dist/docs/development/guides/resources/messages/10-reference.md +6 -3
- package/dist/docs/development/guides/resources/schemas/04-explore-schemas/01-schema-explorer.md +2 -2
- package/dist/docs/development/guides/resources/schemas/04-explore-schemas/02-fields-explorer.md +0 -9
- package/dist/docs/development/guides/resources/schemas/05-schema-api.md +0 -3
- package/dist/docs/development/guides/resources/schemas/06-schema-mcp.md +11 -3
- package/dist/docs/development/guides/resources/services/04-add-resources-to-services/03-add-entities-to-services.md +1 -1
- package/dist/docs/development/guides/resources/services/05-resources-page.md +50 -0
- package/dist/docs/development/guides/resources/services/08-reference.md +2 -1
- package/dist/docs/development/guides/systems/01-introduction.md +1 -1
- package/dist/docs/development/guides/systems/02-create-system.md +2 -2
- package/dist/docs/development/guides/systems/03-add-resources-to-systems.md +35 -9
- package/dist/docs/development/guides/systems/04-model-relationships-and-actors.md +5 -3
- package/dist/docs/development/guides/systems/05-system-context-maps.md +39 -22
- package/dist/docs/development/guides/systems/06-reference.md +4 -4
- package/dist/docs/development/license/01-license-file.md +151 -0
- package/dist/docs/development/license/_category_.json +12 -0
- package/dist/docs/development/license-keys/_category_.json +3 -3
- package/dist/docs/development/license-keys/integrations.md +7 -37
- package/dist/docs/development/license-keys/license-validation.md +4 -0
- package/dist/docs/development/license-keys/overview.md +5 -1
- package/dist/docs/development/license-keys/plans.md +4 -2
- package/dist/docs/development/studio/01-introduction.md +60 -0
- package/dist/docs/development/studio/02-create-a-canvas.md +103 -0
- package/dist/docs/development/studio/03-set-up-persistent-storage.md +59 -0
- package/dist/docs/development/studio/04-collaborate-on-a-canvas.md +78 -0
- package/dist/docs/development/studio/05-connect-your-agent.md +102 -0
- package/dist/docs/development/studio/06-run-studio-in-production.md +54 -0
- package/dist/docs/development/studio/07-reference.md +294 -0
- package/dist/docs/development/studio/_category_.json +12 -0
- package/dist/docs/development/upgrading/v5.md +345 -0
- package/dist/docs/federation/00-overview.md +2 -8
- package/dist/docs/federation/01-first-federation.md +6 -18
- package/dist/docs/federation/explanation/how-it-works.md +0 -4
- package/dist/docs/federation/explanation/lockfile-and-cache.md +0 -4
- package/dist/docs/federation/explanation/mvp-status-and-feedback.md +0 -4
- package/dist/docs/federation/explanation/ownership-and-references.md +0 -4
- package/dist/docs/federation/how-to/configure-github-sources.md +6 -5
- package/dist/docs/federation/how-to/configure-validation-rules.md +0 -4
- package/dist/docs/federation/how-to/run-in-ci.md +2 -9
- package/dist/docs/federation/how-to/share-assets-and-components.md +0 -4
- package/dist/docs/federation/how-to/use-local-sources.md +0 -4
- package/dist/docs/federation/legacy-federation/00-introduction.md +4 -22
- package/dist/docs/federation/legacy-federation/01-installation.md +7 -58
- package/dist/docs/federation/legacy-federation/02-plugin-configuration.md +3 -21
- package/dist/docs/federation/legacy-federation/03-examples.md +3 -5
- package/dist/docs/federation/legacy-federation/04-configuration.md +3 -8
- package/dist/docs/federation/legacy-federation/05-setup-team-catalog.md +3 -6
- package/dist/docs/federation/reference/cli.md +2 -8
- package/dist/docs/federation/reference/configuration.md +0 -4
- package/dist/docs/federation/reference/diagnostic-rules.md +0 -5
- package/dist/docs/federation/reference/generated-output.md +0 -4
- package/dist/docs/federation/reference/supported-content.md +0 -4
- package/dist/docs/federation/reference/troubleshooting.md +0 -14
- package/dist/docs/plugins/02-generators.md +1 -1
- package/dist/docs/plugins/amazon-apigateway/00-intro.md +3 -28
- package/dist/docs/plugins/amazon-apigateway/01-installation.md +4 -56
- package/dist/docs/plugins/amazon-apigateway/02-plugin-configuration.md +1 -6
- package/dist/docs/plugins/apicurio/00-intro.md +2 -31
- package/dist/docs/plugins/apicurio/01-installation.md +2 -26
- package/dist/docs/plugins/apicurio/02-plugin-configuration.md +5 -13
- package/dist/docs/plugins/apicurio/03-features.md +1 -3
- package/dist/docs/plugins/asyncapi/00-intro.md +2 -28
- package/dist/docs/plugins/asyncapi/01-installation.md +3 -54
- package/dist/docs/plugins/asyncapi/02-plugin-configuration.md +2 -1
- package/dist/docs/plugins/aws-glue-registry/00-intro.md +4 -32
- package/dist/docs/plugins/aws-glue-registry/00a-installation.md +3 -53
- package/dist/docs/plugins/azure-schema-registry/00-intro.md +4 -32
- package/dist/docs/plugins/azure-schema-registry/01-installation.md +6 -33
- package/dist/docs/plugins/azure-schema-registry/02-plugin-configuration.md +1 -14
- package/dist/docs/plugins/azure-schema-registry/04-examples.md +0 -2
- package/dist/docs/plugins/backstage/00-overview.md +1 -7
- package/dist/docs/plugins/backstage/01-get-started.md +6 -15
- package/dist/docs/plugins/backstage/06-configuration.md +2 -8
- package/dist/docs/plugins/confluent-schema-registry/00-intro.md +2 -29
- package/dist/docs/plugins/confluent-schema-registry/01-installation.md +2 -26
- package/dist/docs/plugins/eventbridge/00-intro.md +0 -4
- package/dist/docs/plugins/eventbridge/00a-installation.md +1 -87
- package/dist/docs/plugins/eventbridge/03-api.md +2 -20
- package/dist/docs/plugins/github/00-intro.md +0 -31
- package/dist/docs/plugins/github/01-installation.md +2 -34
- package/dist/docs/plugins/graphql/00-intro.md +0 -30
- package/dist/docs/plugins/graphql/01-installation.md +1 -53
- package/dist/docs/plugins/graphql/02-plugin-configuration.md +0 -1
- package/dist/docs/plugins/hookdeck/01-intro.md +1 -1
- package/dist/docs/plugins/openapi/00-intro.md +0 -30
- package/dist/docs/plugins/openapi/01-installation.md +1 -57
- package/dist/docs/plugins/openapi/02-plugin-configuration.md +0 -5
- package/dist/docs/plugins/openapi/03-features.md +0 -4
- package/dist/eventcatalog-config-file-utils.cjs +34 -41
- package/dist/eventcatalog-config-file-utils.d.cts +56 -58
- package/dist/eventcatalog-config-file-utils.d.ts +56 -58
- package/dist/eventcatalog-config-file-utils.js +1 -1
- package/dist/eventcatalog.cjs +340 -249
- package/dist/eventcatalog.config.d.cts +18 -15
- package/dist/eventcatalog.config.d.ts +18 -15
- package/dist/eventcatalog.js +51 -33
- package/dist/features.cjs +36 -49
- package/dist/features.d.cts +1 -3
- package/dist/features.d.ts +1 -3
- package/dist/features.js +4 -6
- package/dist/federation/federate.cjs +37 -44
- package/dist/federation/federate.js +5 -5
- package/dist/federation/source-provider.js +2 -2
- package/dist/generate.cjs +37 -42
- package/dist/generate.js +4 -4
- package/dist/resolve-catalog-dependencies.cjs +34 -41
- package/dist/resolve-catalog-dependencies.js +2 -2
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio-fonts.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.css.mjs +3 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__studio.mjs +3 -0
- package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +5 -1
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
- package/dist/utils/child-process-signals.cjs +53 -0
- package/dist/utils/child-process-signals.d.cts +19 -0
- package/dist/utils/child-process-signals.d.ts +19 -0
- package/dist/utils/child-process-signals.js +6 -0
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/dist/utils/license-status.cjs +11 -4
- package/dist/utils/license-status.d.cts +3 -2
- package/dist/utils/license-status.d.ts +3 -2
- package/dist/utils/license-status.js +1 -1
- package/eventcatalog/astro.config.mjs +21 -1
- package/eventcatalog/integrations/config-loader.mjs +56 -58
- package/eventcatalog/integrations/skip-startup-reload.mjs +31 -0
- package/eventcatalog/integrations/stable-dependency-order.mjs +29 -0
- package/eventcatalog/integrations/storage.mjs +20 -0
- package/eventcatalog/integrations/studio-server.mjs +4 -1
- package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
- package/eventcatalog/src/components/Homepage/CatalogDashboard.astro +342 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +60 -4
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +5 -1
- package/eventcatalog/src/components/NavigationProgress.astro +7 -0
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/ExamplesViewer.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaCodeModal.tsx +2 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -0
- package/eventcatalog/src/components/Search/SearchDataLoader.astro +16 -28
- package/eventcatalog/src/components/Search/SearchModal.tsx +2 -10
- package/eventcatalog/src/components/Search/search-utils.ts +26 -0
- package/eventcatalog/src/components/Seo.astro +5 -1
- package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +53 -48
- package/eventcatalog/src/components/Settings/GeneralSettingsForm.tsx +183 -178
- package/eventcatalog/src/components/Settings/LicenseSettings.tsx +140 -31
- package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +40 -35
- package/eventcatalog/src/components/Settings/LogoUpload.tsx +1 -1
- package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +9 -8
- package/eventcatalog/src/components/Settings/Row.tsx +7 -4
- package/eventcatalog/src/components/Settings/SettingsShared.tsx +3 -3
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +37 -76
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +122 -1
- package/eventcatalog/src/components/SideNav/SideNav.astro +9 -1
- package/eventcatalog/src/components/TrialBadge.astro +20 -9
- package/eventcatalog/src/content.config.ts +19 -2
- package/eventcatalog/src/features/auth/error.astro +4 -2
- package/eventcatalog/src/features/auth/login.astro +2 -1
- package/eventcatalog/src/features/auth/middleware/middleware-auth.ts +21 -1
- package/eventcatalog/src/features/auth/unauthorized.astro +1 -1
- package/eventcatalog/src/features/fields/pages/fields.astro +1 -1
- package/eventcatalog/src/features/integrations/eventcatalog-features.ts +13 -7
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
- package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +3 -3
- package/eventcatalog/src/features/mcp/apps/canvas/styles.css +3 -1
- package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +7 -5
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +123 -98
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +118 -101
- package/eventcatalog/src/features/mcp/mcp-server.ts +20 -4
- package/eventcatalog/src/features/server/start.ts +25 -0
- package/eventcatalog/src/features/storage/database.ts +88 -0
- package/eventcatalog/src/features/storage/migrations.ts +85 -0
- package/eventcatalog/src/features/storage/sql/database.sql +5 -0
- package/eventcatalog/src/features/storage/sql/migrations/0001-studio-canvases.sql +12 -0
- package/eventcatalog/src/features/storage/sql/migrations.sql +15 -0
- package/eventcatalog/src/features/storage/sql.ts +28 -0
- package/eventcatalog/src/features/studio/agent-choreography.ts +13 -10
- package/eventcatalog/src/features/studio/agents.ts +28 -0
- package/eventcatalog/src/features/studio/api/canvases-api.ts +219 -0
- package/eventcatalog/src/features/studio/api/canvases.ts +25 -0
- package/eventcatalog/src/features/studio/api/client.ts +40 -0
- package/eventcatalog/src/features/studio/canvas-actions.ts +160 -34
- package/eventcatalog/src/features/studio/canvas-preview.ts +1 -2
- package/eventcatalog/src/features/studio/catalog.ts +16 -14
- package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +274 -105
- package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +15 -14
- package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +272 -119
- package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +1 -2
- package/eventcatalog/src/features/studio/components/DeleteCanvasDialog.tsx +65 -0
- package/eventcatalog/src/features/studio/components/Dialog.tsx +60 -0
- package/eventcatalog/src/features/studio/components/JoinForm.tsx +101 -26
- package/eventcatalog/src/features/studio/components/LeftPanel.tsx +122 -230
- package/eventcatalog/src/features/studio/components/NodeDetails.tsx +183 -0
- package/eventcatalog/src/features/studio/components/OpenInStudioDialog.tsx +79 -0
- package/eventcatalog/src/features/studio/components/Presence.tsx +52 -45
- package/eventcatalog/src/features/studio/components/ShareDialog.tsx +277 -141
- package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
- package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +1314 -385
- package/eventcatalog/src/features/studio/components/StudioNotice.astro +24 -0
- package/eventcatalog/src/features/studio/document-name.ts +7 -0
- package/eventcatalog/src/features/studio/from-visualiser.ts +138 -0
- package/eventcatalog/src/features/studio/hooks/presence-sender.ts +19 -2
- package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +9 -3
- package/eventcatalog/src/features/studio/hooks/use-comments.ts +2 -2
- package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +8 -3
- package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +244 -32
- package/eventcatalog/src/features/studio/identity.ts +25 -1
- package/eventcatalog/src/features/studio/limits.ts +2 -0
- package/eventcatalog/src/features/studio/pages/[id].astro +42 -16
- package/eventcatalog/src/features/studio/pages/index.astro +596 -373
- package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +12 -15
- package/eventcatalog/src/features/studio/server/canvas-mcp.ts +8 -23
- package/eventcatalog/src/features/studio/server/runtime.ts +150 -46
- package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
- package/eventcatalog/src/features/studio/server/storage.ts +53 -73
- package/eventcatalog/src/features/studio/webmcp-relay/LICENSE +21 -0
- package/eventcatalog/src/features/studio/webmcp-relay/README.md +5 -0
- package/eventcatalog/src/features/studio/webmcp-relay/embed.js +2 -0
- package/eventcatalog/src/features/studio/webmcp-relay/widget.html +10 -0
- package/eventcatalog/src/features/studio/webmcp-relay/widget.js +1 -0
- package/eventcatalog/src/features/tools/catalog-tools.ts +3 -1
- package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
- package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +3 -2
- package/eventcatalog/src/pages/_index.astro +5 -342
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.spec.ts +2 -3
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +3 -1
- package/eventcatalog/src/pages/diagrams/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/diagrams/[id]/[version]/embed.astro +1 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/directory/[type]/_index.data.ts +5 -7
- package/eventcatalog/src/pages/directory/[type]/index.astro +3 -1
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +5 -7
- package/eventcatalog/src/pages/discover/[type]/index.astro +3 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/[filename].astro +3 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/asyncapi/_[filename].data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/[...filename].astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/examples/_[...filename].data.ts +0 -4
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/field-lineage/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +3 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/_[filename].data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.spec.ts +2 -3
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/[filename].astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/spec/_[filename].data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/index.astro +2 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/language/[dictionaryId]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/language/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/[type]/[id]/language/index.astro +1 -0
- package/eventcatalog/src/pages/docs/custom/[...path]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/[version]/resources/index.astro +1 -0
- package/eventcatalog/src/pages/docs/services/[id]/asyncapi/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/changelog/index.astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/graphql/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/services/[id]/spec/[filename].astro +1 -1
- package/eventcatalog/src/pages/docs/teams/[id]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +1 -0
- package/eventcatalog/src/pages/docs/users/[id]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +1 -0
- package/eventcatalog/src/pages/index.astro +4 -2
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +9 -1
- package/eventcatalog/src/pages/schemas/explorer/_index.data.ts +0 -7
- package/eventcatalog/src/pages/schemas/explorer/index.astro +4 -2
- package/eventcatalog/src/pages/settings/license.astro +9 -1
- package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/triggers/[type]/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/_index.data.ts +38 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/index.astro +18 -41
- package/eventcatalog/src/pages/visualiser/designs/[id]/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -1
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +0 -7
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +1 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +1 -0
- package/eventcatalog/src/types/react-syntax-highlighter.d.ts +10 -0
- package/eventcatalog/src/utils/collections/flows.ts +20 -7
- package/eventcatalog/src/utils/collections/resource-owners.ts +8 -2
- package/eventcatalog/src/utils/collections/resources.ts +2 -0
- package/eventcatalog/src/utils/collections/util.ts +8 -4
- package/eventcatalog/src/utils/git.ts +11 -0
- package/eventcatalog/src/utils/homepage-dashboard.ts +143 -0
- package/eventcatalog/src/utils/license.ts +1 -1
- package/eventcatalog/src/utils/link-validation.ts +25 -19
- package/eventcatalog/src/utils/node-graphs/domain-entity-map.ts +3 -1
- package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +3 -3
- package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +4 -2
- package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +20 -1
- package/eventcatalog/src/utils/node-graphs/node-resource.ts +67 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +1 -1
- package/eventcatalog/src/utils/page-loaders/hybrid-page.ts +4 -15
- package/eventcatalog/src/utils/page-title.ts +15 -0
- package/eventcatalog/src/utils/syntax-highlighter-renderer.ts +64 -0
- package/eventcatalog/src/utils/trial.ts +13 -0
- package/package.json +11 -11
- package/dist/docs/development/ask-your-architecture/05-skills/02-installation.md +0 -60
- package/dist/docs/development/ask-your-architecture/05-skills/_category_.json +0 -11
- package/dist/docs/development/ask-your-architecture/06-slack-integration/01-introduction.md +0 -63
- package/dist/docs/development/ask-your-architecture/06-slack-integration/02-slack-app-setup.md +0 -154
- package/dist/docs/development/ask-your-architecture/06-slack-integration/03-installation.md +0 -169
- package/dist/docs/development/ask-your-architecture/06-slack-integration/04-deployment.md +0 -236
- package/dist/docs/development/ask-your-architecture/06-slack-integration/05-usage.md +0 -140
- package/dist/docs/development/ask-your-architecture/06-slack-integration/06-troubleshooting.md +0 -268
- package/dist/docs/development/ask-your-architecture/06-slack-integration/_category_.json +0 -13
- package/dist/docs/development/guides/domains/06-visualize-domains/01-domain-integration-map.md +0 -40
- package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +0 -3
- package/eventcatalog/src/features/studio/canvas-doc.ts +0 -409
- package/eventcatalog/src/features/studio/clipboard.ts +0 -97
- package/eventcatalog/src/features/studio/components/CanvasControls.tsx +0 -154
- package/eventcatalog/src/features/studio/components/Comments.tsx +0 -770
- package/eventcatalog/src/features/studio/components/ContainerChooser.tsx +0 -145
- package/eventcatalog/src/features/studio/components/DragGhost.tsx +0 -115
- package/eventcatalog/src/features/studio/components/Picture.tsx +0 -21
- package/eventcatalog/src/features/studio/components/PropertiesPanel.tsx +0 -212
- package/eventcatalog/src/features/studio/components/canvas-nodes.tsx +0 -255
- package/eventcatalog/src/features/studio/components/icons.ts +0 -53
- package/eventcatalog/src/features/studio/components/status.ts +0 -51
- package/eventcatalog/src/features/studio/edges.ts +0 -56
- package/eventcatalog/src/features/studio/flow-state.ts +0 -92
- package/eventcatalog/src/features/studio/grouping.ts +0 -226
- package/eventcatalog/src/features/studio/layout.ts +0 -42
- package/eventcatalog/src/features/studio/levels.ts +0 -282
- package/eventcatalog/src/features/studio/node-types.ts +0 -205
- package/eventcatalog/src/features/studio/pages/new.astro +0 -24
- package/eventcatalog/src/features/studio/pages/wake.ts +0 -15
- package/eventcatalog/src/features/studio/placement.ts +0 -197
- package/eventcatalog/src/features/studio/studio.css +0 -273
- package/dist/{chunk-A2RZR3U4.js → chunk-6K7XZAYI.js} +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useState, type ReactNode } from 'react';
|
|
2
|
+
import { Check, ChevronDown, Code2, Copy, Globe, Sparkles, X } from 'lucide-react';
|
|
3
3
|
import type { WebMcpStatus } from '../hooks/use-canvas-webmcp';
|
|
4
|
-
import { STATUS } from '
|
|
4
|
+
import { STATUS, ClaudeCodeLogo, ClaudeLogo, CursorLogo, OpenAILogo } from '@eventcatalog/visualiser/studio';
|
|
5
5
|
|
|
6
6
|
type CanvasLink = { canvasId: string; title?: string; canvasUrl: string; mcpUrl: string };
|
|
7
7
|
|
|
@@ -72,41 +72,56 @@ Connect with the first of these you can use:
|
|
|
72
72
|
|
|
73
73
|
Once connected:
|
|
74
74
|
- Read the canvas first (getCanvas / get_canvas) and tell me here who else is on it.
|
|
75
|
-
- Ask me here, in our conversation, what we are designing, then work on the canvas as we talk: add catalog resources (find them with getResources / search_catalog), add new components for things that don't exist yet, and connect them. Leave out positions so new nodes go next to what they connect to
|
|
75
|
+
- Ask me here, in our conversation, what we are designing, then work on the canvas as we talk: add catalog resources (find them with getResources / search_catalog), add new components for things that don't exist yet, and connect them. Leave out positions so new nodes go next to what they connect to. When you finish a round of changes, tidy the whole canvas once (layoutCanvas / layout_canvas) before you hand back to me, unless I asked you to keep the layout.
|
|
76
76
|
- Talk to me here, not in canvas comments. Only comment on the canvas when I ask you to (e.g. to review it), and reply to comments people leave for you.
|
|
77
77
|
- Pass agentName with your name on MCP tools, so people on the canvas can see who you are.`;
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
{copied ? <Check size={large ? 16 : 14} /> : <Copy size={large ? 16 : 14} />}
|
|
93
|
-
{copied ? 'Copied' : label}
|
|
94
|
-
</button>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
79
|
+
const button =
|
|
80
|
+
'inline-flex h-9 flex-none items-center justify-center gap-2 rounded-lg px-4 text-sm font-medium transition-colors [&_svg]:h-4 [&_svg]:w-4';
|
|
81
|
+
const primary = `${button} bg-[rgb(var(--ec-page-text))] text-[rgb(var(--ec-page-bg))] hover:bg-[rgb(var(--ec-page-text)/0.85)]`;
|
|
82
|
+
const secondary = `${button} border border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-content-hover))]`;
|
|
83
|
+
|
|
84
|
+
const copyText = async (text: string) => {
|
|
85
|
+
try {
|
|
86
|
+
await navigator.clipboard.writeText(text);
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
97
92
|
|
|
98
|
-
/** Something to copy
|
|
99
|
-
function
|
|
93
|
+
/** Something to copy, with a button that copies it (as Studio on the web's) */
|
|
94
|
+
function Snippet({ text, label }: { text: string; label: string }) {
|
|
95
|
+
const [copied, setCopied] = useState(false);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!copied) return;
|
|
98
|
+
const timer = setTimeout(() => setCopied(false), 1500);
|
|
99
|
+
return () => clearTimeout(timer);
|
|
100
|
+
}, [copied]);
|
|
100
101
|
return (
|
|
101
|
-
<div className="
|
|
102
|
-
<
|
|
103
|
-
{
|
|
104
|
-
</
|
|
105
|
-
<
|
|
102
|
+
<div className="relative mt-2 rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-content-hover))]">
|
|
103
|
+
<pre className="overflow-x-auto whitespace-pre p-3 pr-12 font-mono text-xs leading-relaxed text-[rgb(var(--ec-page-text))]">
|
|
104
|
+
{text}
|
|
105
|
+
</pre>
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
aria-label={`Copy ${label}`}
|
|
109
|
+
title="Copy"
|
|
110
|
+
onClick={async () => setCopied(await copyText(text))}
|
|
111
|
+
className="absolute right-2 top-2 rounded-md p-1.5 text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-card-bg))] hover:text-[rgb(var(--ec-page-text))] [&_svg]:h-4 [&_svg]:w-4"
|
|
112
|
+
>
|
|
113
|
+
{copied ? <Check aria-hidden /> : <Copy aria-hidden />}
|
|
114
|
+
</button>
|
|
106
115
|
</div>
|
|
107
116
|
);
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
const Steps = ({ children }: { children: ReactNode }) => (
|
|
120
|
+
<ol className="list-decimal space-y-2 pl-5 text-sm leading-relaxed text-[rgb(var(--ec-page-text))] marker:text-[rgb(var(--ec-page-text-muted))]">
|
|
121
|
+
{children}
|
|
122
|
+
</ol>
|
|
123
|
+
);
|
|
124
|
+
|
|
110
125
|
/** Turns something on for this tab, or says it's on */
|
|
111
126
|
function TabSwitch({ on, onTurnOn, label }: { on: boolean; onTurnOn: () => void; label: string }) {
|
|
112
127
|
return on ? (
|
|
@@ -115,25 +130,36 @@ function TabSwitch({ on, onTurnOn, label }: { on: boolean; onTurnOn: () => void;
|
|
|
115
130
|
On for this tab
|
|
116
131
|
</p>
|
|
117
132
|
) : (
|
|
118
|
-
<button
|
|
119
|
-
onClick={onTurnOn}
|
|
120
|
-
className="shrink-0 whitespace-nowrap rounded-lg border px-2.5 py-1.5 text-xs font-medium border-[rgb(var(--ec-page-border))] hover:bg-[rgb(var(--ec-page-border)/0.4)]"
|
|
121
|
-
>
|
|
133
|
+
<button type="button" onClick={onTurnOn} className={`${secondary} h-8 px-3 text-xs`}>
|
|
122
134
|
{label}
|
|
123
135
|
</button>
|
|
124
136
|
);
|
|
125
137
|
}
|
|
126
138
|
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
|
|
139
|
+
/** Things to ask, for the two ways of pairing with an agent on a canvas: designing something new, and understanding what's there */
|
|
140
|
+
const PAIRING = [
|
|
141
|
+
{
|
|
142
|
+
title: 'Design ideas together',
|
|
143
|
+
prompts: [
|
|
144
|
+
'Add a payments service that listens to OrderPlaced',
|
|
145
|
+
'How could we split the orders service?',
|
|
146
|
+
'Add retries and a dead letter queue to this',
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
title: 'Understand how it works',
|
|
151
|
+
prompts: [
|
|
152
|
+
'Put everything the Orders domain owns on the canvas',
|
|
153
|
+
'Walk me through what happens when a payment fails',
|
|
154
|
+
'Which services consume this event?',
|
|
155
|
+
],
|
|
156
|
+
},
|
|
132
157
|
];
|
|
133
158
|
|
|
134
159
|
/**
|
|
135
|
-
* Bringing an AI agent onto the canvas
|
|
136
|
-
*
|
|
160
|
+
* Bringing an AI agent onto the canvas, as Studio on the web does it: how to add EventCatalog's MCP server to each
|
|
161
|
+
* common client, a step or two each with what to copy, and what to ask it. The quickest way first: a prompt to give
|
|
162
|
+
* the agent, which works out how to connect (and which canvas to join) itself. Agents in this browser use WebMCP.
|
|
137
163
|
*/
|
|
138
164
|
export default function ConnectAgentDialog({
|
|
139
165
|
link,
|
|
@@ -151,15 +177,22 @@ export default function ConnectAgentDialog({
|
|
|
151
177
|
onClose: () => void;
|
|
152
178
|
}) {
|
|
153
179
|
const prompt = buildAgentPrompt(link);
|
|
180
|
+
const { mcpUrl, canvasId } = link;
|
|
154
181
|
const [relayOn, setRelayOn] = useState(isRelayEnabled);
|
|
155
182
|
const [showPrompt, setShowPrompt] = useState(false);
|
|
156
|
-
const [
|
|
183
|
+
const [promptCopied, setPromptCopied] = useState(false);
|
|
184
|
+
const [client, setClient] = useState(0);
|
|
157
185
|
|
|
158
186
|
useEffect(() => {
|
|
159
187
|
const onKeyDown = (event: KeyboardEvent) => event.key === 'Escape' && onClose();
|
|
160
188
|
window.addEventListener('keydown', onKeyDown);
|
|
161
189
|
return () => window.removeEventListener('keydown', onKeyDown);
|
|
162
190
|
}, [onClose]);
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
if (!promptCopied) return;
|
|
193
|
+
const timer = setTimeout(() => setPromptCopied(false), 1500);
|
|
194
|
+
return () => clearTimeout(timer);
|
|
195
|
+
}, [promptCopied]);
|
|
163
196
|
|
|
164
197
|
const turnOnRelay = () => {
|
|
165
198
|
if (!relayScriptPath) return;
|
|
@@ -169,111 +202,231 @@ export default function ConnectAgentDialog({
|
|
|
169
202
|
onEnableWebMcp();
|
|
170
203
|
};
|
|
171
204
|
|
|
205
|
+
const joinThisCanvas = (
|
|
206
|
+
<>
|
|
207
|
+
Ask it to join this canvas (<code className="text-xs">{canvasId}</code>), or paste the prompt above, and start pairing (try
|
|
208
|
+
one of the prompts below).
|
|
209
|
+
</>
|
|
210
|
+
);
|
|
211
|
+
const clients: { name: string; logo: ReactNode; body: ReactNode }[] = [
|
|
212
|
+
{
|
|
213
|
+
name: 'Claude',
|
|
214
|
+
logo: <ClaudeLogo />,
|
|
215
|
+
body: (
|
|
216
|
+
<Steps>
|
|
217
|
+
<li>
|
|
218
|
+
In Claude, open <strong>Settings → Connectors</strong> and choose <strong>Add custom connector</strong>.
|
|
219
|
+
</li>
|
|
220
|
+
<li>
|
|
221
|
+
Name it <strong>EventCatalog</strong> and paste this URL:
|
|
222
|
+
<Snippet text={mcpUrl} label="the URL" />
|
|
223
|
+
</li>
|
|
224
|
+
<li>In a chat, turn the connector on. {joinThisCanvas}</li>
|
|
225
|
+
</Steps>
|
|
226
|
+
),
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
name: 'Claude Code',
|
|
230
|
+
logo: <ClaudeCodeLogo />,
|
|
231
|
+
body: (
|
|
232
|
+
<>
|
|
233
|
+
<Steps>
|
|
234
|
+
<li>
|
|
235
|
+
Run this in your project:
|
|
236
|
+
<Snippet text={`claude mcp add --transport http eventcatalog ${mcpUrl}`} label="the command" />
|
|
237
|
+
</li>
|
|
238
|
+
<li>{joinThisCanvas}</li>
|
|
239
|
+
</Steps>
|
|
240
|
+
{relayScriptPath && (
|
|
241
|
+
<div className="mt-4 flex items-center justify-between gap-3 rounded-lg border border-[rgb(var(--ec-page-border))] p-3">
|
|
242
|
+
<p className="text-xs text-[rgb(var(--ec-page-text-muted))]">
|
|
243
|
+
Can't reach this EventCatalog from your computer? Use this tab through the local relay: add{' '}
|
|
244
|
+
<code>{RELAY_COMMAND}</code> as an MCP server.
|
|
245
|
+
</p>
|
|
246
|
+
<TabSwitch on={relayOn} onTurnOn={turnOnRelay} label="Turn on relay" />
|
|
247
|
+
</div>
|
|
248
|
+
)}
|
|
249
|
+
</>
|
|
250
|
+
),
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: 'ChatGPT',
|
|
254
|
+
logo: <OpenAILogo />,
|
|
255
|
+
body: (
|
|
256
|
+
<Steps>
|
|
257
|
+
<li>
|
|
258
|
+
In ChatGPT, open <strong>Settings → Apps & Connectors</strong>, turn on developer mode and choose{' '}
|
|
259
|
+
<strong>Create</strong>.
|
|
260
|
+
</li>
|
|
261
|
+
<li>
|
|
262
|
+
Name it <strong>EventCatalog</strong> and paste this URL:
|
|
263
|
+
<Snippet text={mcpUrl} label="the URL" />
|
|
264
|
+
</li>
|
|
265
|
+
<li>In a chat, add the connector. Chats that show MCP Apps open the canvas right there. {joinThisCanvas}</li>
|
|
266
|
+
</Steps>
|
|
267
|
+
),
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'Cursor',
|
|
271
|
+
logo: <CursorLogo />,
|
|
272
|
+
body: (
|
|
273
|
+
<Steps>
|
|
274
|
+
<li>
|
|
275
|
+
Add this server to <code className="text-xs">.cursor/mcp.json</code> in your project:
|
|
276
|
+
<Snippet text={JSON.stringify({ mcpServers: { eventcatalog: { url: mcpUrl } } }, null, 2)} label="the settings" />
|
|
277
|
+
</li>
|
|
278
|
+
<li>{joinThisCanvas}</li>
|
|
279
|
+
</Steps>
|
|
280
|
+
),
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'VS Code',
|
|
284
|
+
logo: <Code2 />,
|
|
285
|
+
body: (
|
|
286
|
+
<Steps>
|
|
287
|
+
<li>
|
|
288
|
+
Add this server to <code className="text-xs">.vscode/mcp.json</code> in your project:
|
|
289
|
+
<Snippet
|
|
290
|
+
text={JSON.stringify({ servers: { eventcatalog: { type: 'http', url: mcpUrl } } }, null, 2)}
|
|
291
|
+
label="the settings"
|
|
292
|
+
/>
|
|
293
|
+
</li>
|
|
294
|
+
<li>In Copilot's agent mode: {joinThisCanvas}</li>
|
|
295
|
+
</Steps>
|
|
296
|
+
),
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: 'This browser',
|
|
300
|
+
logo: <Globe />,
|
|
301
|
+
body: (
|
|
302
|
+
<div className="flex items-center justify-between gap-3">
|
|
303
|
+
<p className="text-sm leading-relaxed text-[rgb(var(--ec-page-text))]">
|
|
304
|
+
{webMcp.state === 'on'
|
|
305
|
+
? `This tab offers ${webMcp.tools} canvas tools to agents in your browser (like the MCP-B extension) through WebMCP.`
|
|
306
|
+
: 'Let agents in your browser (like the MCP-B extension) use this canvas through WebMCP.'}
|
|
307
|
+
</p>
|
|
308
|
+
<TabSwitch on={webMcp.state === 'on'} onTurnOn={onEnableWebMcp} label="Turn on" />
|
|
309
|
+
</div>
|
|
310
|
+
),
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
|
|
172
314
|
return (
|
|
173
|
-
<div className="fixed inset-0 z-
|
|
315
|
+
<div className="fixed inset-0 z-[80] flex items-center justify-center bg-black/40 p-4" onClick={onClose}>
|
|
174
316
|
<div
|
|
175
317
|
role="dialog"
|
|
176
|
-
aria-
|
|
318
|
+
aria-modal="true"
|
|
319
|
+
aria-labelledby="connect-agent-title"
|
|
177
320
|
onClick={(event) => event.stopPropagation()}
|
|
178
|
-
className="flex max-h-full w-full max-w-
|
|
321
|
+
className="flex max-h-full w-full max-w-2xl flex-col rounded-xl border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-2xl"
|
|
179
322
|
>
|
|
180
|
-
<
|
|
181
|
-
<div className="
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
</
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
323
|
+
<div className="flex items-start gap-3 px-5 pt-5">
|
|
324
|
+
<div className="min-w-0 flex-1">
|
|
325
|
+
<h2 id="connect-agent-title" className="text-base font-semibold">
|
|
326
|
+
Connect your AI agent
|
|
327
|
+
</h2>
|
|
328
|
+
<p className="mt-1.5 text-sm font-light leading-relaxed text-[rgb(var(--ec-page-text-muted))]">
|
|
329
|
+
Pair with your AI agent on this canvas: sketch ideas together, or have it bring in what your catalog has and walk
|
|
330
|
+
you through it. It joins with its own pointer, and you both change the canvas. Add this EventCatalog as an MCP
|
|
331
|
+
server.
|
|
332
|
+
</p>
|
|
189
333
|
</div>
|
|
190
334
|
<button
|
|
191
|
-
|
|
335
|
+
type="button"
|
|
192
336
|
aria-label="Close"
|
|
193
|
-
|
|
337
|
+
onClick={onClose}
|
|
338
|
+
className="-mr-1 -mt-1 rounded-md p-1.5 text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-content-hover))] hover:text-[rgb(var(--ec-page-text))]"
|
|
194
339
|
>
|
|
195
|
-
<X
|
|
340
|
+
<X aria-hidden className="h-4 w-4" />
|
|
196
341
|
</button>
|
|
197
|
-
</
|
|
342
|
+
</div>
|
|
198
343
|
|
|
199
|
-
<div className="min-h-0
|
|
200
|
-
{/* The
|
|
201
|
-
<section className="
|
|
202
|
-
<
|
|
203
|
-
|
|
204
|
-
|
|
344
|
+
<div className="min-h-0 overflow-y-auto">
|
|
345
|
+
{/* The quickest way: one prompt, which the agent works out how to connect from (and which canvas to join) */}
|
|
346
|
+
<section className="mx-5 mt-4 overflow-hidden rounded-xl border border-[color-mix(in_srgb,rgb(var(--ec-accent))_35%,rgb(var(--ec-page-border)))] bg-[color-mix(in_srgb,rgb(var(--ec-accent))_6%,transparent)]">
|
|
347
|
+
<div className="flex items-center gap-3 p-4">
|
|
348
|
+
<span className="flex h-9 w-9 flex-none items-center justify-center rounded-lg bg-[color-mix(in_srgb,rgb(var(--ec-accent))_14%,transparent)] text-[rgb(var(--ec-accent))]">
|
|
349
|
+
<Sparkles aria-hidden className="h-[18px] w-[18px]" />
|
|
350
|
+
</span>
|
|
351
|
+
<div className="min-w-0 flex-1">
|
|
352
|
+
<h3 className="text-sm font-semibold">Quickest: paste one prompt</h3>
|
|
353
|
+
<p className="mt-0.5 text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]">
|
|
354
|
+
Give it to your agent: it connects to this EventCatalog and joins this canvas on its own.
|
|
355
|
+
</p>
|
|
356
|
+
</div>
|
|
357
|
+
<button type="button" onClick={async () => setPromptCopied(await copyText(prompt))} className={primary}>
|
|
358
|
+
{promptCopied ? <Check aria-hidden /> : <Copy aria-hidden />}
|
|
359
|
+
{promptCopied ? 'Copied' : 'Copy prompt'}
|
|
360
|
+
</button>
|
|
361
|
+
</div>
|
|
362
|
+
{/* What's in it, at a glance (the whole of it on a click) */}
|
|
363
|
+
<div className="relative border-t border-[color-mix(in_srgb,rgb(var(--ec-accent))_20%,rgb(var(--ec-page-border)))] bg-[rgb(var(--ec-card-bg)/0.6)]">
|
|
364
|
+
<pre
|
|
365
|
+
className={`whitespace-pre-wrap px-4 py-3 font-mono text-[11px] leading-relaxed text-[rgb(var(--ec-page-text-muted))] ${
|
|
366
|
+
showPrompt ? 'max-h-56 overflow-y-auto' : 'max-h-[112px] overflow-hidden'
|
|
367
|
+
}`}
|
|
368
|
+
>
|
|
369
|
+
{prompt}
|
|
370
|
+
</pre>
|
|
371
|
+
{!showPrompt && (
|
|
372
|
+
<div className="pointer-events-none absolute inset-x-0 bottom-0 h-20 bg-gradient-to-t from-[rgb(var(--ec-card-bg))] via-[rgb(var(--ec-card-bg)/0.85)] to-transparent" />
|
|
373
|
+
)}
|
|
205
374
|
<button
|
|
375
|
+
type="button"
|
|
206
376
|
onClick={() => setShowPrompt((shown) => !shown)}
|
|
207
377
|
aria-expanded={showPrompt}
|
|
208
|
-
className=
|
|
378
|
+
className={`${
|
|
379
|
+
showPrompt ? 'mx-4 mb-3' : 'absolute bottom-2 left-1/2 -translate-x-1/2'
|
|
380
|
+
} inline-flex items-center gap-1 rounded-full border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg))] px-2.5 py-1 text-[11px] font-medium text-[rgb(var(--ec-page-text-muted))] shadow-sm hover:text-[rgb(var(--ec-page-text))]`}
|
|
209
381
|
>
|
|
210
|
-
{showPrompt ? '
|
|
211
|
-
<ChevronDown size={12} className={`transition-transform ${showPrompt ? 'rotate-180' : ''}`} />
|
|
382
|
+
{showPrompt ? 'Show less' : 'Show the whole prompt'}
|
|
383
|
+
<ChevronDown aria-hidden size={12} className={`transition-transform ${showPrompt ? 'rotate-180' : ''}`} />
|
|
212
384
|
</button>
|
|
213
|
-
</
|
|
214
|
-
{showPrompt && (
|
|
215
|
-
<pre className="max-h-56 overflow-y-auto whitespace-pre-wrap rounded-lg border p-3 font-mono text-[11px] leading-relaxed bg-[rgb(var(--ec-page-bg))] border-[rgb(var(--ec-page-border))]">
|
|
216
|
-
{prompt}
|
|
217
|
-
</pre>
|
|
218
|
-
)}
|
|
385
|
+
</div>
|
|
219
386
|
</section>
|
|
220
387
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
388
|
+
<p className="mx-5 mt-5 text-[11px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text-muted))]">
|
|
389
|
+
Or set it up yourself
|
|
390
|
+
</p>
|
|
391
|
+
{/* Or add the server to the client they use, a step or two each */}
|
|
392
|
+
<div className="px-5 pb-5 pt-2">
|
|
393
|
+
<div role="tablist" className="flex gap-1 rounded-lg bg-[rgb(var(--ec-content-hover))] p-1">
|
|
394
|
+
{clients.map(({ name, logo }, index) => (
|
|
226
395
|
<button
|
|
227
|
-
key={
|
|
396
|
+
key={name}
|
|
397
|
+
type="button"
|
|
228
398
|
role="tab"
|
|
229
|
-
aria-selected={
|
|
230
|
-
onClick={() =>
|
|
231
|
-
className={`rounded-md px-2 py-1.5 text-
|
|
232
|
-
|
|
399
|
+
aria-selected={client === index}
|
|
400
|
+
onClick={() => setClient(index)}
|
|
401
|
+
className={`flex flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md px-2 py-1.5 text-xs font-medium outline-none [&_svg]:h-3.5 [&_svg]:w-3.5 [&_svg]:flex-none ${
|
|
402
|
+
client === index
|
|
403
|
+
? 'bg-[rgb(var(--ec-card-bg))] text-[rgb(var(--ec-page-text))] shadow-sm'
|
|
404
|
+
: 'text-[rgb(var(--ec-page-text-muted))] hover:text-[rgb(var(--ec-page-text))]'
|
|
233
405
|
}`}
|
|
234
406
|
>
|
|
235
|
-
|
|
236
|
-
|
|
407
|
+
{logo}
|
|
408
|
+
{name}
|
|
237
409
|
</button>
|
|
238
410
|
))}
|
|
239
411
|
</div>
|
|
412
|
+
<div role="tabpanel" className="mt-4">
|
|
413
|
+
{clients[client].body}
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
240
416
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
</
|
|
246
|
-
<
|
|
417
|
+
{/* What pairing looks like: the two ways people work with their agent on a canvas */}
|
|
418
|
+
<div className="grid gap-3 border-t border-[rgb(var(--ec-page-border))] px-5 py-4 sm:grid-cols-2">
|
|
419
|
+
{PAIRING.map(({ title, prompts }) => (
|
|
420
|
+
<div key={title}>
|
|
421
|
+
<h3 className="text-xs font-semibold text-[rgb(var(--ec-page-text))]">{title}</h3>
|
|
422
|
+
<ul className="mt-1.5 space-y-1 text-xs leading-relaxed text-[rgb(var(--ec-page-text-muted))]">
|
|
423
|
+
{prompts.map((text) => (
|
|
424
|
+
<li key={text}>“{text}”</li>
|
|
425
|
+
))}
|
|
426
|
+
</ul>
|
|
247
427
|
</div>
|
|
248
|
-
)}
|
|
249
|
-
|
|
250
|
-
<div className="space-y-2">
|
|
251
|
-
<p className="text-xs text-[rgb(var(--ec-page-text-muted))]">
|
|
252
|
-
Add EventCatalog's MCP server, e.g. in Claude Code:
|
|
253
|
-
</p>
|
|
254
|
-
<CopyField value={`claude mcp add --transport http eventcatalog ${link.mcpUrl}`} />
|
|
255
|
-
{relayScriptPath && (
|
|
256
|
-
<div className="flex items-center justify-between gap-3 pt-1">
|
|
257
|
-
<p className="text-[11px] text-[rgb(var(--ec-page-text-muted))]">
|
|
258
|
-
Can't reach this server? Use this tab through the local relay: add <code>{RELAY_COMMAND}</code> as an MCP
|
|
259
|
-
server.
|
|
260
|
-
</p>
|
|
261
|
-
<TabSwitch on={relayOn} onTurnOn={turnOnRelay} label="Turn on relay" />
|
|
262
|
-
</div>
|
|
263
|
-
)}
|
|
264
|
-
</div>
|
|
265
|
-
)}
|
|
266
|
-
{way === 'browser' && (
|
|
267
|
-
<div className="flex items-center justify-between gap-3">
|
|
268
|
-
<p className="text-xs text-[rgb(var(--ec-page-text-muted))]">
|
|
269
|
-
{webMcp.state === 'on'
|
|
270
|
-
? `This tab offers ${webMcp.tools} canvas tools to agents in your browser (like the MCP-B extension).`
|
|
271
|
-
: 'Let agents in your browser (like the MCP-B extension) use this canvas through WebMCP.'}
|
|
272
|
-
</p>
|
|
273
|
-
<TabSwitch on={webMcp.state === 'on'} onTurnOn={onEnableWebMcp} label="Turn on" />
|
|
274
|
-
</div>
|
|
275
|
-
)}
|
|
276
|
-
</section>
|
|
428
|
+
))}
|
|
429
|
+
</div>
|
|
277
430
|
</div>
|
|
278
431
|
</div>
|
|
279
432
|
</div>
|
|
@@ -2,8 +2,7 @@ import { useEffect, useState, type ReactElement } from 'react';
|
|
|
2
2
|
import { X } from 'lucide-react';
|
|
3
3
|
import type { ConnectionGroup, ConnectionGroupId } from '../canvas-actions';
|
|
4
4
|
import type { CatalogResource } from '../catalog-resources';
|
|
5
|
-
import { getNodeLabel } from '
|
|
6
|
-
import { CardPreview } from './ContainerChooser';
|
|
5
|
+
import { getNodeLabel, CardPreview } from '@eventcatalog/visualiser/studio';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Asked when a catalog service or message is dropped on the canvas (and connects to things that aren't on it yet):
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { usePeople, type PresenceStore } from '../hooks/presence-store';
|
|
3
|
+
import Dialog, { SECONDARY_BUTTON } from './Dialog';
|
|
4
|
+
import { STATUS } from '@eventcatalog/visualiser/studio';
|
|
5
|
+
|
|
6
|
+
/** Asks before deleting a canvas: it's deleted for everyone, for good */
|
|
7
|
+
export default function DeleteCanvasDialog({
|
|
8
|
+
title,
|
|
9
|
+
presence,
|
|
10
|
+
clientId,
|
|
11
|
+
onDelete,
|
|
12
|
+
onClose,
|
|
13
|
+
}: {
|
|
14
|
+
title?: string;
|
|
15
|
+
/** Who has it open (to say it closes for them) */
|
|
16
|
+
presence: PresenceStore | null;
|
|
17
|
+
clientId: number | null;
|
|
18
|
+
/** Deletes it (rejects with what went wrong) */
|
|
19
|
+
onDelete: () => Promise<void>;
|
|
20
|
+
onClose: () => void;
|
|
21
|
+
}) {
|
|
22
|
+
const othersHere = usePeople(presence).filter((peer) => peer.clientId !== clientId).length;
|
|
23
|
+
const [deleting, setDeleting] = useState(false);
|
|
24
|
+
const [error, setError] = useState<string>();
|
|
25
|
+
|
|
26
|
+
const confirm = async () => {
|
|
27
|
+
setDeleting(true);
|
|
28
|
+
setError(undefined);
|
|
29
|
+
try {
|
|
30
|
+
await onDelete();
|
|
31
|
+
} catch (failure) {
|
|
32
|
+
setError((failure as Error).message);
|
|
33
|
+
setDeleting(false);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Dialog role="alertdialog" labelledBy="delete-canvas-title" busy={deleting} onClose={onClose}>
|
|
39
|
+
<div className="space-y-2 px-5 py-4">
|
|
40
|
+
<h2 id="delete-canvas-title" className="text-base font-semibold">
|
|
41
|
+
Delete {title ? `"${title}"` : 'this canvas'}?
|
|
42
|
+
</h2>
|
|
43
|
+
<p className="text-sm text-[rgb(var(--ec-page-text-muted))]">
|
|
44
|
+
It's deleted for everyone, with its comments, and can't be brought back.
|
|
45
|
+
{othersHere > 0 &&
|
|
46
|
+
` ${othersHere === 1 ? 'Someone else has' : `${othersHere} others have`} it open: it closes for them too.`}
|
|
47
|
+
</p>
|
|
48
|
+
{error && <p className={`text-sm ${STATUS.danger.text}`}>{error}</p>}
|
|
49
|
+
</div>
|
|
50
|
+
<div className="flex justify-end gap-2 border-t px-5 py-4 border-[rgb(var(--ec-page-border))]">
|
|
51
|
+
<button onClick={onClose} disabled={deleting} className={SECONDARY_BUTTON}>
|
|
52
|
+
Cancel
|
|
53
|
+
</button>
|
|
54
|
+
<button
|
|
55
|
+
autoFocus
|
|
56
|
+
onClick={confirm}
|
|
57
|
+
disabled={deleting}
|
|
58
|
+
className={`rounded-lg px-4 py-2 text-sm font-medium disabled:opacity-60 ${STATUS.danger.button}`}
|
|
59
|
+
>
|
|
60
|
+
{deleting ? 'Deleting…' : 'Delete canvas'}
|
|
61
|
+
</button>
|
|
62
|
+
</div>
|
|
63
|
+
</Dialog>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useEffect, useRef, type ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Studio's dialogs: a card over the page, closed by Escape or clicking outside it (not while it's busy). Focus stays
|
|
5
|
+
* in it: anything that moves focus outside (e.g. the menu it was opened from, closing) sends it back to its first
|
|
6
|
+
* field or button.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const SECONDARY_BUTTON =
|
|
10
|
+
'rounded-lg border px-4 py-2 text-sm font-medium border-[rgb(var(--ec-page-border))] hover:bg-[rgb(var(--ec-page-border)/0.4)] disabled:opacity-50';
|
|
11
|
+
export const PRIMARY_BUTTON =
|
|
12
|
+
'rounded-lg px-4 py-2 text-sm font-medium bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))] hover:bg-[rgb(var(--ec-button-bg-hover))] disabled:opacity-60';
|
|
13
|
+
|
|
14
|
+
export default function Dialog({
|
|
15
|
+
labelledBy,
|
|
16
|
+
role = 'dialog',
|
|
17
|
+
busy = false,
|
|
18
|
+
onClose,
|
|
19
|
+
children,
|
|
20
|
+
}: {
|
|
21
|
+
/** The id of its heading */
|
|
22
|
+
labelledBy: string;
|
|
23
|
+
/** `alertdialog` when it asks to confirm something that can't be undone */
|
|
24
|
+
role?: 'dialog' | 'alertdialog';
|
|
25
|
+
/** Doing what was asked: it can't be closed until it's done */
|
|
26
|
+
busy?: boolean;
|
|
27
|
+
onClose: () => void;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
}) {
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const onKeyDown = (event: KeyboardEvent) => event.key === 'Escape' && !busy && onClose();
|
|
32
|
+
window.addEventListener('keydown', onKeyDown);
|
|
33
|
+
return () => window.removeEventListener('keydown', onKeyDown);
|
|
34
|
+
}, [onClose, busy]);
|
|
35
|
+
|
|
36
|
+
const card = useRef<HTMLDivElement>(null);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const keepFocus = (event: FocusEvent) => {
|
|
39
|
+
if (!card.current || card.current.contains(event.target as globalThis.Node)) return;
|
|
40
|
+
card.current.querySelector<HTMLElement>('input, button')?.focus();
|
|
41
|
+
};
|
|
42
|
+
document.addEventListener('focusin', keepFocus);
|
|
43
|
+
return () => document.removeEventListener('focusin', keepFocus);
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4" onClick={() => !busy && onClose()}>
|
|
48
|
+
<div
|
|
49
|
+
ref={card}
|
|
50
|
+
role={role}
|
|
51
|
+
aria-modal="true"
|
|
52
|
+
aria-labelledby={labelledBy}
|
|
53
|
+
onClick={(event) => event.stopPropagation()}
|
|
54
|
+
className="w-full max-w-md rounded-xl border shadow-2xl bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] text-[rgb(var(--ec-page-text))]"
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
);
|
|
60
|
+
}
|