@eventcatalog/core 5.0.0-beta.3 → 5.0.0-beta.30
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 +234 -134
- package/README.md +5 -5
- package/dist/analytics/analytics.cjs +18 -3
- package/dist/analytics/analytics.d.cts +1 -1
- package/dist/analytics/analytics.d.ts +1 -1
- package/dist/analytics/analytics.js +3 -2
- package/dist/analytics/log-build.cjs +160 -77
- package/dist/analytics/log-build.d.cts +2 -2
- package/dist/analytics/log-build.d.ts +2 -2
- package/dist/analytics/log-build.js +7 -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/analytics/telemetry.cjs +42 -0
- package/dist/analytics/telemetry.d.cts +20 -0
- package/dist/analytics/telemetry.d.ts +20 -0
- package/dist/analytics/telemetry.js +8 -0
- package/dist/catalog-runtime.cjs +1 -1
- package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
- package/dist/{chunk-6OC46WQJ.js → chunk-55QETQZ3.js} +66 -35
- package/dist/{chunk-TQLRG35T.js → chunk-AD7CL772.js} +78 -45
- package/dist/chunk-CA6WCQ2T.js +54 -0
- package/dist/chunk-CPW6G62V.js +17 -0
- package/dist/{chunk-423S2KHN.js → chunk-FLAZ2JVN.js} +4 -2
- package/dist/{chunk-BH2F5WPN.js → chunk-GQI5UYXZ.js} +1 -1
- package/dist/{chunk-GYIVJXOJ.js → chunk-NA7OTBWW.js} +1 -1
- package/dist/{chunk-MDWB5HLO.js → chunk-NKNOXQ62.js} +1 -1
- package/dist/{chunk-3PKS2IIP.js → chunk-OX6TSVHY.js} +1 -1
- package/dist/{chunk-36RYTYT5.js → chunk-PD7KTSYN.js} +1 -1
- package/dist/chunk-S5GWAUG5.js +29 -0
- package/dist/{chunk-NDJOAITI.js → chunk-T3OROMAU.js} +9 -3
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- 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 +531 -356
- package/dist/eventcatalog.config.d.cts +59 -1
- package/dist/eventcatalog.config.d.ts +59 -1
- package/dist/eventcatalog.js +63 -25
- package/dist/features.cjs +34 -41
- package/dist/features.js +2 -2
- package/dist/federation/federate.cjs +37 -44
- package/dist/federation/federate.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/@hocuspocus__provider.mjs +3 -0
- package/dist/runtime-dependencies/@hocuspocus__server.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-local-relay.mjs +3 -0
- package/dist/runtime-dependencies/@mcp-b__webmcp-polyfill.mjs +3 -0
- package/dist/runtime-dependencies/htmlparser2.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +13 -1
- package/dist/runtime-dependencies/react-hotkeys-hook.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__cjs__create-element.js.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols.mjs +3 -0
- package/dist/runtime-dependencies/y-protocols__awareness.mjs +3 -0
- package/dist/runtime-dependencies/yjs.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 +78 -45
- package/dist/utils/license-status.d.cts +15 -5
- package/dist/utils/license-status.d.ts +15 -5
- package/dist/utils/license-status.js +1 -1
- package/eventcatalog/astro.config.mjs +23 -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 +32 -0
- package/eventcatalog/src/components/CatalogGraph/CatalogForceGraph.tsx +39 -0
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +2 -0
- package/eventcatalog/src/components/Header.astro +3 -3
- 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 +53 -83
- package/eventcatalog/src/components/SideNav/NestedSideBar/storage.ts +2 -0
- package/eventcatalog/src/components/SideNav/NestedSideBar/utils.ts +131 -0
- 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 +10 -0
- 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 +34 -1
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +6 -45
- package/eventcatalog/src/features/mcp/apps/canvas/shared.ts +47 -0
- package/eventcatalog/src/features/mcp/apps/canvas/styles.css +24 -0
- package/eventcatalog/src/features/mcp/apps/canvas/view.tsx +278 -0
- package/eventcatalog/src/features/mcp/apps/generated/canvas.html +272 -0
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +65 -65
- package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +2 -1
- package/eventcatalog/src/features/mcp/mcp-apps.ts +6 -3
- package/eventcatalog/src/features/mcp/mcp-server.ts +36 -5
- 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 +384 -0
- 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 +540 -0
- package/eventcatalog/src/features/studio/canvas-preview.ts +52 -0
- package/eventcatalog/src/features/studio/catalog-resources.ts +155 -0
- package/eventcatalog/src/features/studio/catalog.ts +173 -0
- package/eventcatalog/src/features/studio/components/CanvasHeader.tsx +518 -0
- package/eventcatalog/src/features/studio/components/CanvasStatusMenu.tsx +118 -0
- package/eventcatalog/src/features/studio/components/ConnectAgentDialog.tsx +434 -0
- package/eventcatalog/src/features/studio/components/ConnectionsChooser.tsx +143 -0
- 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 +109 -0
- package/eventcatalog/src/features/studio/components/LeftPanel.tsx +206 -0
- 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 +293 -0
- package/eventcatalog/src/features/studio/components/ShareDialog.tsx +396 -0
- package/eventcatalog/src/features/studio/components/ShortcutsDialog.tsx +41 -0
- package/eventcatalog/src/features/studio/components/StudioDesigner.tsx +2091 -0
- 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 +63 -0
- package/eventcatalog/src/features/studio/hooks/presence-store.ts +119 -0
- package/eventcatalog/src/features/studio/hooks/use-canvas-webmcp.ts +353 -0
- package/eventcatalog/src/features/studio/hooks/use-comments.ts +54 -0
- package/eventcatalog/src/features/studio/hooks/use-follow-camera.ts +109 -0
- package/eventcatalog/src/features/studio/hooks/use-studio-flow.ts +782 -0
- package/eventcatalog/src/features/studio/identity.ts +59 -0
- package/eventcatalog/src/features/studio/limits.ts +2 -0
- package/eventcatalog/src/features/studio/pages/[id].astro +69 -0
- package/eventcatalog/src/features/studio/pages/index.astro +784 -0
- package/eventcatalog/src/features/studio/pages/webmcp-relay.ts +27 -0
- package/eventcatalog/src/features/studio/server/canvas-mcp.ts +495 -0
- package/eventcatalog/src/features/studio/server/runtime.ts +498 -0
- package/eventcatalog/src/features/studio/server/sign-in.ts +18 -0
- package/eventcatalog/src/features/studio/server/sql/storage.sql +18 -0
- package/eventcatalog/src/features/studio/server/storage.ts +90 -0
- package/eventcatalog/src/features/studio/server/tool-icons.ts +30 -0
- package/eventcatalog/src/features/studio/tool-sync.ts +75 -0
- package/eventcatalog/src/layouts/BaseLayout.astro +4 -4
- package/eventcatalog/src/layouts/SettingsLayout.astro +2 -2
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +13 -5
- 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 +1 -0
- 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/util.ts +8 -4
- package/eventcatalog/src/utils/feature.ts +8 -0
- package/eventcatalog/src/utils/git.ts +22 -5
- 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/export-mermaid.ts +0 -2
- 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 +14 -1
- package/package.json +19 -13
- package/dist/runtime-dependencies/shelljs.mjs +0 -3
- package/eventcatalog/public/studio-bg.png +0 -0
- package/eventcatalog/src/components/Studio/StudioPageModal.tsx +0 -150
- package/eventcatalog/src/pages/studio.astro +0 -316
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isFullCatalogAPIEnabled,
|
|
14
14
|
isDevMode,
|
|
15
15
|
isSSR,
|
|
16
|
+
isCanvasEnabled,
|
|
16
17
|
} from '../../utils/feature';
|
|
17
18
|
import { getCustomPageRoutes, isApiRoute, listCustomPageFiles, resolveCustomPagesPrefix } from '../custom-pages/routes';
|
|
18
19
|
|
|
@@ -111,7 +112,8 @@ export default function eventCatalogIntegration(): AstroIntegration {
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
// Handle routes for MCP Server (requires SSR)
|
|
114
|
-
|
|
115
|
+
// Also for canvases, so agents can join them (the canvas tools are on the MCP server)
|
|
116
|
+
if (isEventCatalogMCPEnabled() || isCanvasEnabled()) {
|
|
115
117
|
params.injectRoute({
|
|
116
118
|
pattern: '/docs/mcp/[...path]',
|
|
117
119
|
entrypoint: path.join(packageDirectory, 'src/features/mcp/mcp-server.ts'),
|
|
@@ -173,6 +175,37 @@ export default function eventCatalogIntegration(): AstroIntegration {
|
|
|
173
175
|
entrypoint: path.join(packageDirectory, 'src/features/visualizer-layout/reset.ts'),
|
|
174
176
|
});
|
|
175
177
|
}
|
|
178
|
+
|
|
179
|
+
// What a server starts before anyone asks for it (the storage configured, migrated; Studio), called by
|
|
180
|
+
// `eventcatalog start` once it listens
|
|
181
|
+
if (isSSR()) {
|
|
182
|
+
params.injectRoute({
|
|
183
|
+
pattern: '/_eventcatalog/start',
|
|
184
|
+
entrypoint: path.join(packageDirectory, 'src/features/server/start.ts'),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Collaborative canvases in EventCatalog Studio (/studio lists them, /studio?new=1 starts one). Their WebSocket
|
|
189
|
+
// server is in integrations/studio-server.mjs.
|
|
190
|
+
if (isCanvasEnabled()) {
|
|
191
|
+
params.injectRoute({
|
|
192
|
+
pattern: '/studio',
|
|
193
|
+
entrypoint: path.join(packageDirectory, 'src/features/studio/pages/index.astro'),
|
|
194
|
+
});
|
|
195
|
+
params.injectRoute({
|
|
196
|
+
pattern: '/studio/[id]',
|
|
197
|
+
entrypoint: path.join(packageDirectory, 'src/features/studio/pages/[id].astro'),
|
|
198
|
+
});
|
|
199
|
+
// The Studio API (canvases as a whole: listing, creating, deleting)
|
|
200
|
+
params.injectRoute({
|
|
201
|
+
pattern: '/api/studio/canvases/[...path]',
|
|
202
|
+
entrypoint: path.join(packageDirectory, 'src/features/studio/api/canvases.ts'),
|
|
203
|
+
});
|
|
204
|
+
params.injectRoute({
|
|
205
|
+
pattern: '/webmcp-relay/[file]',
|
|
206
|
+
entrypoint: path.join(packageDirectory, 'src/features/studio/pages/webmcp-relay.ts'),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
176
209
|
},
|
|
177
210
|
'astro:server:setup': ({ server }) => {
|
|
178
211
|
// When custom page files appear or disappear, refresh the manifest.
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
import { useEffect, useRef, useState, type FormEvent, type KeyboardEvent, type RefObject } from 'react';
|
|
7
7
|
import type { Node } from '@xyflow/react';
|
|
8
8
|
import { Check, Network, SendHorizontal, X } from 'lucide-react';
|
|
9
|
-
import
|
|
9
|
+
import { isArchitectureDiagramCollection } from '@utils/node-graphs/architecture-diagram-types';
|
|
10
|
+
import { getNodeCatalogResource, getNodeResourceDetails } from '@utils/node-graphs/node-resource';
|
|
10
11
|
import type { DiagramLink } from './links';
|
|
11
12
|
import { RESOURCE_TYPE_LABELS } from '../shared/resource-types';
|
|
12
13
|
|
|
@@ -36,53 +37,13 @@ const NODE_TYPE_LABELS: Record<string, string> = {
|
|
|
36
37
|
externalSystem: 'External system',
|
|
37
38
|
};
|
|
38
39
|
|
|
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
40
|
export function describeNode(node: Node): SelectedNode {
|
|
80
41
|
const data = (node.data ?? {}) as Record<string, any>;
|
|
81
|
-
const
|
|
82
|
-
const details = resource?.data ?? resource;
|
|
42
|
+
const details = (getNodeResourceDetails(node) ?? data) as Record<string, any>;
|
|
83
43
|
const version: string | undefined = details?.version;
|
|
84
|
-
const id: string = details?.id ??
|
|
85
|
-
const
|
|
44
|
+
const id: string = details?.id ?? node.id;
|
|
45
|
+
const resource = getNodeCatalogResource(node);
|
|
46
|
+
const collection = resource && isArchitectureDiagramCollection(resource.collection) ? resource.collection : undefined;
|
|
86
47
|
|
|
87
48
|
return {
|
|
88
49
|
nodeId: node.id,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Shared by the canvas MCP App (client) and the MCP server: no server-only imports here
|
|
2
|
+
import type { CatalogRelation, CatalogResource } from '../../../studio/catalog-resources';
|
|
3
|
+
import { type CanvasStatus } from '@eventcatalog/visualiser/studio';
|
|
4
|
+
|
|
5
|
+
export const CANVAS_RESOURCE_URI = 'ui://eventcatalog/canvas.html';
|
|
6
|
+
/** Key of the payload in openCanvas results' `_meta` */
|
|
7
|
+
export const CANVAS_META_KEY = 'eventcatalog/canvas';
|
|
8
|
+
/** App-only tool the view loads the canvas from when the host doesn't pass the result's `_meta` */
|
|
9
|
+
export const CANVAS_VIEW_TOOL = 'getCanvasView';
|
|
10
|
+
/** App-only tool the view loads the catalog (for dragging resources in) from */
|
|
11
|
+
export const CANVAS_CATALOG_TOOL = 'getCanvasCatalog';
|
|
12
|
+
/** App-only tool the view syncs through when the chat's sandbox blocks the collaboration WebSocket */
|
|
13
|
+
export const CANVAS_SYNC_TOOL = 'syncCanvas';
|
|
14
|
+
|
|
15
|
+
/** A canvas listed in the view's picker */
|
|
16
|
+
export type CanvasListItem = {
|
|
17
|
+
canvasId: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
status: CanvasStatus;
|
|
20
|
+
people: string[];
|
|
21
|
+
nodeCount: number;
|
|
22
|
+
openComments: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* What the view shows: a canvas (it connects to it itself, so people and agents edit it live), or, when opened
|
|
27
|
+
* without one (e.g. from ChatGPT's sidebar), a list of canvases to open or start.
|
|
28
|
+
*/
|
|
29
|
+
export type CanvasPayload = CanvasView | CanvasHome;
|
|
30
|
+
|
|
31
|
+
export type CanvasHome = { view: 'home'; canvases: CanvasListItem[] };
|
|
32
|
+
|
|
33
|
+
export type CanvasView = {
|
|
34
|
+
view: 'canvas';
|
|
35
|
+
canvasId: string;
|
|
36
|
+
title?: string;
|
|
37
|
+
/** The collaboration WebSocket, e.g. wss://catalog.example.com/_eventcatalog/studio */
|
|
38
|
+
socketUrl: string;
|
|
39
|
+
/** The canvas in EventCatalog */
|
|
40
|
+
canvasUrl: string;
|
|
41
|
+
/** The EventCatalog MCP server, for "Connect your agent" */
|
|
42
|
+
mcpUrl: string;
|
|
43
|
+
/** The chat's agent: the view joins the canvas as it (its name, colour and logo) */
|
|
44
|
+
agent?: { name: string; color: string };
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type CanvasCatalog = { resources: CatalogResource[]; relations: CatalogRelation[] };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The canvas view's Tailwind stylesheet (with Tailwind's base reset) and EventCatalog's theme variables,
|
|
3
|
+
* built from the classes of the collaborative canvas components it renders.
|
|
4
|
+
*/
|
|
5
|
+
@import 'tailwindcss' source(none);
|
|
6
|
+
@import '../../../../styles/theme.css';
|
|
7
|
+
@import '@eventcatalog/visualiser/studio.css';
|
|
8
|
+
|
|
9
|
+
@source './*.tsx';
|
|
10
|
+
@source '../../../studio/components/*.{ts,tsx}';
|
|
11
|
+
/* Studio's shared canvas (nodes, comments, hotspots), from the visualiser in this repo */
|
|
12
|
+
@source '../../../../../../../visualiser/src/studio';
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
margin: 0;
|
|
16
|
+
background: rgb(var(--ec-page-bg));
|
|
17
|
+
color: rgb(var(--ec-page-text));
|
|
18
|
+
font-family:
|
|
19
|
+
ui-sans-serif,
|
|
20
|
+
system-ui,
|
|
21
|
+
-apple-system,
|
|
22
|
+
'Segoe UI',
|
|
23
|
+
sans-serif;
|
|
24
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The collaborative canvas as an MCP App: openCanvas shows it in the chat (ChatGPT, Claude...), where it
|
|
3
|
+
* joins the canvas (over the collaboration WebSocket, or through tool calls when the chat's sandbox blocks it).
|
|
4
|
+
* The user edits it there with everyone else on it, people in EventCatalog and agents, live.
|
|
5
|
+
*
|
|
6
|
+
* Opened without a canvas (e.g. from ChatGPT's sidebar or a thread tab, its entrypoints), it lists the canvases
|
|
7
|
+
* to open one or start one. Follows the OpenAI MCP extensions for ChatGPT: entrypoints, display modes, deep
|
|
8
|
+
* links (/canvas/<id>) and model context (background context, and the selection as titled attachments).
|
|
9
|
+
*
|
|
10
|
+
* Built into a single HTML file by scripts/build-mcp-apps.mjs and served as a ui:// resource.
|
|
11
|
+
*/
|
|
12
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import { ArrowLeft, ExternalLink, Maximize2, Minimize2, Plus, Users } from 'lucide-react';
|
|
14
|
+
import type { App } from '@modelcontextprotocol/ext-apps';
|
|
15
|
+
import styles from './styles.css?inline';
|
|
16
|
+
import visualiserStyles from '@eventcatalog/visualiser/styles.css?inline';
|
|
17
|
+
import StudioDesigner, { type SelectedNode } from '@features/studio/components/StudioDesigner';
|
|
18
|
+
import { getAgent } from '@features/studio/agents';
|
|
19
|
+
import { CANVAS_STATUS_LOOK, STATUS } from '@eventcatalog/visualiser/studio';
|
|
20
|
+
import { getToolResultPayload, mountView, useMcpAppView } from '../shared/app-view';
|
|
21
|
+
import {
|
|
22
|
+
CANVAS_CATALOG_TOOL,
|
|
23
|
+
CANVAS_META_KEY,
|
|
24
|
+
CANVAS_SYNC_TOOL,
|
|
25
|
+
CANVAS_VIEW_TOOL,
|
|
26
|
+
type CanvasCatalog,
|
|
27
|
+
type CanvasHome,
|
|
28
|
+
type CanvasPayload,
|
|
29
|
+
type CanvasView,
|
|
30
|
+
} from './shared';
|
|
31
|
+
import type { SyncResponse, ToolSync } from '@features/studio/tool-sync';
|
|
32
|
+
|
|
33
|
+
const isCanvasPayload = (payload?: CanvasPayload): payload is CanvasPayload =>
|
|
34
|
+
payload?.view === 'home' ? Array.isArray(payload.canvases) : Boolean(payload?.canvasId && payload.socketUrl);
|
|
35
|
+
|
|
36
|
+
const VIEW_OPTIONS = {
|
|
37
|
+
name: 'EventCatalog canvas',
|
|
38
|
+
metaKey: CANVAS_META_KEY,
|
|
39
|
+
viewTool: CANVAS_VIEW_TOOL,
|
|
40
|
+
isPayload: isCanvasPayload,
|
|
41
|
+
getViewToolArguments: ({ canvasId }: Record<string, any>) => ({ canvasId }),
|
|
42
|
+
loadErrorMessage: 'The canvas could not be opened',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const INLINE_HEIGHT = 640;
|
|
46
|
+
/** Deep links into the app (ChatGPT's `openai/deepLink`), e.g. /canvas/<id> */
|
|
47
|
+
const DEEP_LINK = /^\/canvas(?:es)?\/([0-9a-f-]{36})/i;
|
|
48
|
+
|
|
49
|
+
/** Loads what to show through a tool (the canvas view's own, or openCanvas to start a canvas) */
|
|
50
|
+
const loadPayload = async (app: App, name: string, args: Record<string, unknown>) => {
|
|
51
|
+
const result = await app.callServerTool({ name, arguments: args });
|
|
52
|
+
const payload = getToolResultPayload<CanvasPayload>(result, CANVAS_META_KEY);
|
|
53
|
+
if (result.isError || !isCanvasPayload(payload)) throw new Error('The canvas could not be opened');
|
|
54
|
+
return payload;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
function CanvasPicker({
|
|
58
|
+
home,
|
|
59
|
+
onOpen,
|
|
60
|
+
onCreate,
|
|
61
|
+
}: {
|
|
62
|
+
home: CanvasHome;
|
|
63
|
+
onOpen: (id: string) => void;
|
|
64
|
+
onCreate: (title: string) => void;
|
|
65
|
+
}) {
|
|
66
|
+
const [title, setTitle] = useState('');
|
|
67
|
+
return (
|
|
68
|
+
<div className="mx-auto max-w-2xl space-y-6 p-6">
|
|
69
|
+
<div className="space-y-1">
|
|
70
|
+
<h1 className="text-lg font-semibold">Canvases</h1>
|
|
71
|
+
<p className="text-sm text-[rgb(var(--ec-page-text-muted))]">
|
|
72
|
+
Work together, live: people in EventCatalog, people in chats and agents, on the same canvas.
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
<form
|
|
76
|
+
className="flex gap-2"
|
|
77
|
+
onSubmit={(event) => {
|
|
78
|
+
event.preventDefault();
|
|
79
|
+
if (title.trim()) onCreate(title.trim());
|
|
80
|
+
}}
|
|
81
|
+
>
|
|
82
|
+
<input
|
|
83
|
+
value={title}
|
|
84
|
+
onChange={(event) => setTitle(event.target.value)}
|
|
85
|
+
placeholder="What are you designing?"
|
|
86
|
+
className="min-w-0 flex-1 rounded-lg border px-3 py-2 text-sm bg-[rgb(var(--ec-input-bg))] border-[rgb(var(--ec-input-border))] text-[rgb(var(--ec-input-text))]"
|
|
87
|
+
/>
|
|
88
|
+
<button
|
|
89
|
+
type="submit"
|
|
90
|
+
disabled={!title.trim()}
|
|
91
|
+
className="flex items-center gap-1.5 rounded-lg px-3 py-2 text-sm font-medium disabled:opacity-50 bg-[rgb(var(--ec-button-bg))] text-[rgb(var(--ec-button-text))] hover:bg-[rgb(var(--ec-button-bg-hover))]"
|
|
92
|
+
>
|
|
93
|
+
<Plus size={16} /> New canvas
|
|
94
|
+
</button>
|
|
95
|
+
</form>
|
|
96
|
+
<div className="space-y-2">
|
|
97
|
+
{home.canvases.length === 0 && <p className="text-sm text-[rgb(var(--ec-page-text-muted))]">No canvases yet.</p>}
|
|
98
|
+
{home.canvases.map((canvas) => (
|
|
99
|
+
<button
|
|
100
|
+
key={canvas.canvasId}
|
|
101
|
+
onClick={() => onOpen(canvas.canvasId)}
|
|
102
|
+
className="flex w-full items-center justify-between gap-3 rounded-xl border px-4 py-3 text-left bg-[rgb(var(--ec-card-bg))] border-[rgb(var(--ec-page-border))] hover:border-[rgb(var(--ec-accent))]"
|
|
103
|
+
>
|
|
104
|
+
<span className="min-w-0">
|
|
105
|
+
<span className="flex items-center gap-2">
|
|
106
|
+
<span className="truncate text-sm font-semibold">{canvas.title ?? 'Untitled canvas'}</span>
|
|
107
|
+
<span
|
|
108
|
+
className={`shrink-0 rounded-full border px-1.5 py-px text-[10px] font-semibold ${CANVAS_STATUS_LOOK[canvas.status].pill}`}
|
|
109
|
+
>
|
|
110
|
+
{CANVAS_STATUS_LOOK[canvas.status].label}
|
|
111
|
+
</span>
|
|
112
|
+
</span>
|
|
113
|
+
<span className="text-xs text-[rgb(var(--ec-page-text-muted))]">
|
|
114
|
+
{canvas.nodeCount} {canvas.nodeCount === 1 ? 'node' : 'nodes'}
|
|
115
|
+
{canvas.openComments > 0 && ` · ${canvas.openComments} open comments`}
|
|
116
|
+
</span>
|
|
117
|
+
</span>
|
|
118
|
+
{canvas.people.length > 0 && (
|
|
119
|
+
<span
|
|
120
|
+
className={`flex shrink-0 items-center gap-1 text-xs ${STATUS.success.text}`}
|
|
121
|
+
title={canvas.people.join(', ')}
|
|
122
|
+
>
|
|
123
|
+
<Users size={14} /> {canvas.people.length} here now
|
|
124
|
+
</span>
|
|
125
|
+
)}
|
|
126
|
+
</button>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function CanvasApp() {
|
|
134
|
+
const { app, payload, setPayload, error, hostContext } = useMcpAppView(VIEW_OPTIONS);
|
|
135
|
+
const [catalog, setCatalog] = useState<CanvasCatalog>({ resources: [], relations: [] });
|
|
136
|
+
const [selection, setSelection] = useState<SelectedNode[]>([]);
|
|
137
|
+
const [loadError, setLoadError] = useState<string | null>(null);
|
|
138
|
+
const canvas = payload?.view === 'canvas' ? payload : undefined;
|
|
139
|
+
|
|
140
|
+
const show = useCallback(
|
|
141
|
+
(load: Promise<CanvasPayload>) =>
|
|
142
|
+
load.then(setPayload).catch((cause) => setLoadError(String((cause as Error)?.message ?? cause))),
|
|
143
|
+
[setPayload]
|
|
144
|
+
);
|
|
145
|
+
const openCanvas = (canvasId?: string) => app && show(loadPayload(app, CANVAS_VIEW_TOOL, canvasId ? { canvasId } : {}));
|
|
146
|
+
|
|
147
|
+
// Deep links (ChatGPT's `openai/deepLink`): /canvas/<id> opens that canvas
|
|
148
|
+
const deepLink = (hostContext as Record<string, { url?: string } | undefined> | undefined)?.['openai/deepLink']?.url;
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
const canvasId = deepLink?.match(DEEP_LINK)?.[1];
|
|
151
|
+
if (app && canvasId && canvasId !== canvas?.canvasId) void show(loadPayload(app, CANVAS_VIEW_TOOL, { canvasId }));
|
|
152
|
+
}, [app, deepLink]);
|
|
153
|
+
|
|
154
|
+
// Chats may not let the view open the collaboration WebSocket (sandbox CSP, local network rules...):
|
|
155
|
+
// then it syncs through the MCP server, the same way the model's tools reach the canvas
|
|
156
|
+
const syncViaTools = useMemo<ToolSync | undefined>(
|
|
157
|
+
() =>
|
|
158
|
+
app
|
|
159
|
+
? async (request) => {
|
|
160
|
+
const result = await app.callServerTool({ name: CANVAS_SYNC_TOOL, arguments: request });
|
|
161
|
+
if (result.isError || !result.structuredContent) throw new Error('Sync failed');
|
|
162
|
+
return result.structuredContent as SyncResponse;
|
|
163
|
+
}
|
|
164
|
+
: undefined,
|
|
165
|
+
[app]
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// The catalog (to drag resources in) is loaded separately, to keep tool results small
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!app || !canvas) return;
|
|
171
|
+
app
|
|
172
|
+
.callServerTool({ name: CANVAS_CATALOG_TOOL, arguments: {} })
|
|
173
|
+
.then((result) => {
|
|
174
|
+
const loaded = result.structuredContent as CanvasCatalog | undefined;
|
|
175
|
+
if (loaded?.resources) setCatalog(loaded);
|
|
176
|
+
})
|
|
177
|
+
.catch(() => {});
|
|
178
|
+
}, [app, canvas?.canvasId]);
|
|
179
|
+
|
|
180
|
+
// Model context (replaced on each update): which canvas is open as background context the user doesn't see,
|
|
181
|
+
// and what they've selected as an attachment they can see (and remove), titled with the names
|
|
182
|
+
useEffect(() => {
|
|
183
|
+
if (!app || !payload || !app.getHostCapabilities()?.updateModelContext) return;
|
|
184
|
+
const background = {
|
|
185
|
+
type: 'text' as const,
|
|
186
|
+
text: canvas
|
|
187
|
+
? `The user has the canvas "${canvas.title ?? 'Untitled'}" open (canvasId ${canvas.canvasId}). Use getCanvas to see what is on it, and the canvas tools to work on it with them.`
|
|
188
|
+
: 'The user is looking at their canvases, to open one or start one.',
|
|
189
|
+
annotations: { audience: ['assistant' as const] },
|
|
190
|
+
};
|
|
191
|
+
const selected = selection.length
|
|
192
|
+
? [
|
|
193
|
+
{
|
|
194
|
+
type: 'text' as const,
|
|
195
|
+
text: `Selected on the canvas: ${selection
|
|
196
|
+
.map(
|
|
197
|
+
(node) =>
|
|
198
|
+
`${node.name} (${node.type}${node.catalogResource ? `, catalog ${node.catalogResource}` : ''}, nodeId ${node.id})`
|
|
199
|
+
)
|
|
200
|
+
.join('; ')}`,
|
|
201
|
+
_meta: { 'openai/title': selection.map((node) => node.name).join(', ') },
|
|
202
|
+
},
|
|
203
|
+
]
|
|
204
|
+
: [];
|
|
205
|
+
app.updateModelContext({ content: [background, ...selected] }).catch(() => {});
|
|
206
|
+
}, [app, payload, selection]);
|
|
207
|
+
|
|
208
|
+
if (error || loadError) return <p className="p-4 text-sm">{error ?? loadError}</p>;
|
|
209
|
+
if (!payload) return <p className="p-4 text-sm text-[rgb(var(--ec-page-text-muted))]">Opening the canvas…</p>;
|
|
210
|
+
|
|
211
|
+
const fullscreen = hostContext?.displayMode === 'fullscreen';
|
|
212
|
+
const canToggle = hostContext?.availableDisplayModes?.includes(fullscreen ? 'inline' : 'fullscreen');
|
|
213
|
+
const iconButton =
|
|
214
|
+
'flex items-center gap-1 rounded-md px-2 py-1 text-xs text-[rgb(var(--ec-page-text-muted))] hover:bg-[rgb(var(--ec-page-border)/0.5)]';
|
|
215
|
+
|
|
216
|
+
// No join form inside a chat: it joins as the chat's agent (e.g. ChatGPT or Claude, with its logo), as the agent
|
|
217
|
+
// working on the canvas does, else as the chat it's in
|
|
218
|
+
const hostName = app?.getHostVersion()?.name;
|
|
219
|
+
const agentOf = (view: CanvasView) => view.agent ?? getAgent(undefined, hostName);
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<div className="flex flex-col" style={{ height: fullscreen ? '100vh' : INLINE_HEIGHT }}>
|
|
223
|
+
<div className="flex items-center justify-between border-b px-3 py-1.5 border-[rgb(var(--ec-page-border))]">
|
|
224
|
+
<span className="flex min-w-0 items-center gap-1">
|
|
225
|
+
{canvas && (
|
|
226
|
+
<button className={iconButton} title="All canvases" onClick={() => void openCanvas()}>
|
|
227
|
+
<ArrowLeft size={14} />
|
|
228
|
+
</button>
|
|
229
|
+
)}
|
|
230
|
+
<span className="truncate text-sm font-semibold">{canvas ? (canvas.title ?? 'Canvas') : 'Canvases'}</span>
|
|
231
|
+
</span>
|
|
232
|
+
<span className="flex items-center gap-1">
|
|
233
|
+
{canvas && (
|
|
234
|
+
<button className={iconButton} onClick={() => app?.openLink({ url: canvas.canvasUrl })}>
|
|
235
|
+
<ExternalLink size={14} />
|
|
236
|
+
Open in EventCatalog
|
|
237
|
+
</button>
|
|
238
|
+
)}
|
|
239
|
+
{canToggle && (
|
|
240
|
+
<button
|
|
241
|
+
className={iconButton}
|
|
242
|
+
title={fullscreen ? 'Exit full screen' : 'Full screen'}
|
|
243
|
+
onClick={() => app?.requestDisplayMode({ mode: fullscreen ? 'inline' : 'fullscreen' })}
|
|
244
|
+
>
|
|
245
|
+
{fullscreen ? <Minimize2 size={14} /> : <Maximize2 size={14} />}
|
|
246
|
+
</button>
|
|
247
|
+
)}
|
|
248
|
+
</span>
|
|
249
|
+
</div>
|
|
250
|
+
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
251
|
+
{canvas ? (
|
|
252
|
+
<StudioDesigner
|
|
253
|
+
key={canvas.canvasId}
|
|
254
|
+
canvasId={canvas.canvasId}
|
|
255
|
+
socketUrl={canvas.socketUrl}
|
|
256
|
+
shareUrl={canvas.canvasUrl}
|
|
257
|
+
mcpUrl={canvas.mcpUrl}
|
|
258
|
+
syncViaTools={syncViaTools}
|
|
259
|
+
asAgent={agentOf(canvas)}
|
|
260
|
+
resources={catalog.resources}
|
|
261
|
+
relations={catalog.relations}
|
|
262
|
+
onSelectionChange={setSelection}
|
|
263
|
+
followChanges
|
|
264
|
+
paletteCollapsed
|
|
265
|
+
/>
|
|
266
|
+
) : (
|
|
267
|
+
<CanvasPicker
|
|
268
|
+
home={payload as CanvasHome}
|
|
269
|
+
onOpen={(canvasId) => void openCanvas(canvasId)}
|
|
270
|
+
onCreate={(title) => app && void show(loadPayload(app, 'openCanvas', { title }))}
|
|
271
|
+
/>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
mountView(CanvasApp, [visualiserStyles, styles].join('\n'));
|