@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
|
@@ -64,44 +64,49 @@ export const LlmAccessSettingsForm = ({ canEdit, initial, apiBase, llmsTxtUrl, l
|
|
|
64
64
|
};
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
|
-
|
|
67
|
+
<>
|
|
68
68
|
<Toaster richColors closeButton position="bottom-right" theme="system" />
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
</div>
|
|
73
|
-
)}
|
|
74
|
-
|
|
75
|
-
<Row
|
|
76
|
-
title="llms.txt"
|
|
77
|
-
description="Generate llms.txt files so tools like Claude, ChatGPT, and Cursor can read your catalog at /llms.txt."
|
|
78
|
-
canEdit={canEdit}
|
|
79
|
-
dirty={dirty}
|
|
80
|
-
saving={saving}
|
|
81
|
-
onSave={save}
|
|
69
|
+
<form
|
|
70
|
+
onSubmit={(e) => e.preventDefault()}
|
|
71
|
+
className="divide-y divide-[rgb(var(--ec-page-border))] border-t border-[rgb(var(--ec-page-border))]"
|
|
82
72
|
>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
checked={llmsTxtEnabled}
|
|
90
|
-
disabled={!canEdit}
|
|
91
|
-
onChange={setLlmsTxtEnabled}
|
|
92
|
-
/>
|
|
93
|
-
{llmsTxtEnabled && <LlmsTxtPreview url={llmsTxtUrl} fullUrl={llmsFullTxtUrl} />}
|
|
94
|
-
</Row>
|
|
73
|
+
{!canEdit && (
|
|
74
|
+
<div className="pb-6">
|
|
75
|
+
<ReadOnlyBanner />
|
|
76
|
+
</div>
|
|
77
|
+
)}
|
|
95
78
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
79
|
+
<Row
|
|
80
|
+
title="llms.txt"
|
|
81
|
+
description="Generate llms.txt files so tools like Claude, ChatGPT, and Cursor can read your catalog at /llms.txt."
|
|
82
|
+
canEdit={canEdit}
|
|
83
|
+
dirty={dirty}
|
|
84
|
+
saving={saving}
|
|
85
|
+
onSave={save}
|
|
86
|
+
>
|
|
87
|
+
<ToggleRow
|
|
88
|
+
icon={<Bot className="h-4 w-4" aria-hidden />}
|
|
89
|
+
label={llmsTxtEnabled ? 'Enabled' : 'Disabled'}
|
|
90
|
+
hint={
|
|
91
|
+
llmsTxtEnabled ? 'AI tools can read your catalog at /llms.txt.' : 'AI tools will not be able to read your catalog.'
|
|
92
|
+
}
|
|
93
|
+
checked={llmsTxtEnabled}
|
|
94
|
+
disabled={!canEdit}
|
|
95
|
+
onChange={setLlmsTxtEnabled}
|
|
96
|
+
/>
|
|
97
|
+
{llmsTxtEnabled && <LlmsTxtPreview url={llmsTxtUrl} fullUrl={llmsFullTxtUrl} />}
|
|
98
|
+
</Row>
|
|
99
|
+
|
|
100
|
+
<Row
|
|
101
|
+
title="schemas.txt"
|
|
102
|
+
description="Give LLMs access to every schema across your organization in one place — events, commands, queries, and services."
|
|
103
|
+
canEdit={false}
|
|
104
|
+
dirty={false}
|
|
105
|
+
>
|
|
106
|
+
<SchemasTxtAvailable url={schemasTxtUrl} />
|
|
107
|
+
</Row>
|
|
108
|
+
</form>
|
|
109
|
+
</>
|
|
105
110
|
);
|
|
106
111
|
};
|
|
107
112
|
|
|
@@ -75,7 +75,7 @@ export const LogoUpload = ({ canEdit, initialSrc, apiUrl, onSrcChange }: LogoUpl
|
|
|
75
75
|
onDrop={onDrop}
|
|
76
76
|
className={`relative flex items-center gap-5 rounded-lg border border-dashed px-4 py-4 transition-colors ${
|
|
77
77
|
dragOver
|
|
78
|
-
? 'border-[rgb(var(--ec-
|
|
78
|
+
? 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.04)]'
|
|
79
79
|
: 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg)/0.4)]'
|
|
80
80
|
}`}
|
|
81
81
|
>
|
|
@@ -26,7 +26,8 @@ interface Props {
|
|
|
26
26
|
|
|
27
27
|
export const McpSettingsForm = ({ inSSR, mcpUrl, domainServers }: Props) => {
|
|
28
28
|
return (
|
|
29
|
-
|
|
29
|
+
// A top border, as on the other settings pages
|
|
30
|
+
<div className="divide-y divide-[rgb(var(--ec-page-border))] border-t border-[rgb(var(--ec-page-border))]">
|
|
30
31
|
<Row
|
|
31
32
|
title="Catalog MCP Server"
|
|
32
33
|
description="Connect AI agents (Claude, Cursor, VS Code and any MCP client) to every resource in your catalog: domains, services, messages, flows, schemas and the teams that own them."
|
|
@@ -63,7 +64,7 @@ const LivePill = () => (
|
|
|
63
64
|
const CatalogServer = ({ url }: { url: string }) => (
|
|
64
65
|
<div className="overflow-hidden rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-card-bg,var(--ec-page-bg)))]">
|
|
65
66
|
<div className="flex items-start gap-3 px-4 py-3.5">
|
|
66
|
-
<span className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg border border-[rgb(var(--ec-
|
|
67
|
+
<span className="flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.05)] text-[rgb(var(--ec-page-text))]">
|
|
67
68
|
<Library className="h-4 w-4" aria-hidden />
|
|
68
69
|
</span>
|
|
69
70
|
<div className="min-w-0 flex-1">
|
|
@@ -83,7 +84,7 @@ const CatalogServer = ({ url }: { url: string }) => (
|
|
|
83
84
|
href={MCP_DOCS_URL}
|
|
84
85
|
target="_blank"
|
|
85
86
|
rel="noreferrer"
|
|
86
|
-
className="mt-3 inline-flex items-center gap-1 text-[12px] font-medium text-[rgb(var(--ec-
|
|
87
|
+
className="mt-3 inline-flex items-center gap-1 text-[12px] font-medium text-[rgb(var(--ec-page-text))] hover:underline"
|
|
87
88
|
>
|
|
88
89
|
How to connect a client
|
|
89
90
|
<ArrowUpRight className="h-3.5 w-3.5" aria-hidden />
|
|
@@ -100,7 +101,7 @@ const DomainServers = ({ servers }: { servers: DomainMcpServer[] }) => (
|
|
|
100
101
|
<a
|
|
101
102
|
href={server.docsUrl}
|
|
102
103
|
title={server.summary}
|
|
103
|
-
className="inline-flex min-w-0 items-center gap-2 text-[13px] font-medium text-[rgb(var(--ec-page-text))] hover:
|
|
104
|
+
className="inline-flex min-w-0 items-center gap-2 text-[13px] font-medium text-[rgb(var(--ec-page-text))] hover:underline"
|
|
104
105
|
>
|
|
105
106
|
<Boxes className="h-3.5 w-3.5 flex-shrink-0 self-center text-[rgb(var(--ec-icon-color))]" aria-hidden />
|
|
106
107
|
<span className="truncate">{server.name}</span>
|
|
@@ -114,15 +115,15 @@ const DomainServers = ({ servers }: { servers: DomainMcpServer[] }) => (
|
|
|
114
115
|
);
|
|
115
116
|
|
|
116
117
|
const McpNeedsSSR = () => (
|
|
117
|
-
<div className="overflow-hidden rounded-lg border border-[rgb(var(--ec-
|
|
118
|
+
<div className="overflow-hidden rounded-lg border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.03)]">
|
|
118
119
|
<div className="flex items-start gap-3 px-4 py-3.5">
|
|
119
|
-
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-[rgb(var(--ec-
|
|
120
|
+
<span className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.05)] text-[rgb(var(--ec-page-text))]">
|
|
120
121
|
<ServerCog className="h-4 w-4" aria-hidden />
|
|
121
122
|
</span>
|
|
122
123
|
<div className="flex-1 min-w-0">
|
|
123
124
|
<div className="flex items-center gap-2">
|
|
124
125
|
<p className="text-[13px] font-semibold text-[rgb(var(--ec-page-text))]">Server output mode required</p>
|
|
125
|
-
<span className="inline-flex items-center gap-1 rounded-full border border-[rgb(var(--ec-
|
|
126
|
+
<span className="inline-flex items-center gap-1 rounded-full border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.05)] px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[rgb(var(--ec-page-text))]">
|
|
126
127
|
SSR
|
|
127
128
|
</span>
|
|
128
129
|
</div>
|
|
@@ -134,7 +135,7 @@ const McpNeedsSSR = () => (
|
|
|
134
135
|
href={MCP_DOCS_URL}
|
|
135
136
|
target="_blank"
|
|
136
137
|
rel="noreferrer"
|
|
137
|
-
className="inline-flex items-center gap-1 rounded-md bg-[rgb(var(--ec-
|
|
138
|
+
className="inline-flex items-center gap-1 rounded-md bg-[rgb(var(--ec-page-text))] px-3 py-1.5 text-[12px] font-semibold text-[rgb(var(--ec-page-bg))] shadow-sm transition-colors hover:opacity-85"
|
|
138
139
|
>
|
|
139
140
|
MCP setup guide
|
|
140
141
|
<ExternalLink className="h-3 w-3" aria-hidden />
|
|
@@ -3,7 +3,7 @@ import { AlertCircle } from 'lucide-react';
|
|
|
3
3
|
export const cn = (...parts: Array<string | false | undefined | null>): string => parts.filter(Boolean).join(' ');
|
|
4
4
|
|
|
5
5
|
export const inputBase =
|
|
6
|
-
'block w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-input-bg,var(--ec-page-bg)))] px-3 py-2 text-[13px] text-[rgb(var(--ec-page-text))] placeholder:text-[rgb(var(--ec-page-text-muted)/0.7)] transition-colors focus:border-[rgb(var(--ec-
|
|
6
|
+
'block w-full rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-input-bg,var(--ec-page-bg)))] px-3 py-2 text-[13px] text-[rgb(var(--ec-page-text))] placeholder:text-[rgb(var(--ec-page-text-muted)/0.7)] transition-colors focus:border-[rgb(var(--ec-page-text)/0.5)] focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ec-page-text)/0.15)] disabled:cursor-not-allowed disabled:opacity-60';
|
|
7
7
|
|
|
8
8
|
export const monoInput = 'font-mono text-[12.5px] tracking-tight';
|
|
9
9
|
|
|
@@ -11,7 +11,9 @@ export const inputError = 'border-red-500/70 focus:border-red-500 focus:ring-red
|
|
|
11
11
|
|
|
12
12
|
interface RowProps {
|
|
13
13
|
title: string;
|
|
14
|
-
description:
|
|
14
|
+
description: React.ReactNode;
|
|
15
|
+
/** Shown under the description, in the left column */
|
|
16
|
+
aside?: React.ReactNode;
|
|
15
17
|
canEdit: boolean;
|
|
16
18
|
dirty: boolean;
|
|
17
19
|
saving?: boolean;
|
|
@@ -20,13 +22,14 @@ interface RowProps {
|
|
|
20
22
|
children: React.ReactNode;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
export const Row = ({ title, description, canEdit, dirty, saving, onSave, error, children }: RowProps) => (
|
|
25
|
+
export const Row = ({ title, description, aside, canEdit, dirty, saving, onSave, error, children }: RowProps) => (
|
|
24
26
|
<section className="grid grid-cols-1 gap-6 py-8 md:grid-cols-[minmax(0,_18rem)_minmax(0,_1fr)] md:gap-12">
|
|
25
27
|
<header className="space-y-1.5">
|
|
26
28
|
<h3 className="text-[14px] font-semibold tracking-tight text-[rgb(var(--ec-page-text))]">{title}</h3>
|
|
27
29
|
<p className="text-[13px] leading-relaxed text-[rgb(var(--ec-content-text-muted,var(--ec-page-text-muted)))]">
|
|
28
30
|
{description}
|
|
29
31
|
</p>
|
|
32
|
+
{aside && <div className="pt-3">{aside}</div>}
|
|
30
33
|
</header>
|
|
31
34
|
<div className="space-y-2.5">
|
|
32
35
|
{children}
|
|
@@ -45,7 +48,7 @@ export const Row = ({ title, description, canEdit, dirty, saving, onSave, error,
|
|
|
45
48
|
className={cn(
|
|
46
49
|
'inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-[12px] font-medium transition-colors',
|
|
47
50
|
dirty && !saving
|
|
48
|
-
? 'border-[rgb(var(--ec-
|
|
51
|
+
? 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-text)/0.05)] text-[rgb(var(--ec-page-text))] hover:bg-[rgb(var(--ec-page-text)/0.08)]'
|
|
49
52
|
: 'border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] text-[rgb(var(--ec-page-text-muted))]',
|
|
50
53
|
'disabled:cursor-not-allowed disabled:opacity-60'
|
|
51
54
|
)}
|
|
@@ -32,7 +32,7 @@ export const UrlPanel = ({ url }: UrlPanelProps) => {
|
|
|
32
32
|
href={url}
|
|
33
33
|
target="_blank"
|
|
34
34
|
rel="noreferrer"
|
|
35
|
-
className="flex-1 truncate rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-1.5 font-mono text-[12px] text-[rgb(var(--ec-page-text))] transition-colors hover:border-[rgb(var(--ec-
|
|
35
|
+
className="flex-1 truncate rounded-md border border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-page-bg))] px-2.5 py-1.5 font-mono text-[12px] text-[rgb(var(--ec-page-text))] transition-colors hover:border-[rgb(var(--ec-page-text)/0.4)]"
|
|
36
36
|
>
|
|
37
37
|
{fullUrl}
|
|
38
38
|
</a>
|
|
@@ -72,13 +72,13 @@ export const Toggle = ({ checked, disabled, onChange }: ToggleProps) => (
|
|
|
72
72
|
onClick={() => onChange(!checked)}
|
|
73
73
|
className={cn(
|
|
74
74
|
'relative inline-flex h-5 w-9 flex-shrink-0 cursor-pointer items-center rounded-full transition-colors',
|
|
75
|
-
checked ? 'bg-[rgb(var(--ec-
|
|
75
|
+
checked ? 'bg-[rgb(var(--ec-page-text))]' : 'bg-[rgb(var(--ec-page-text-muted)/0.35)]',
|
|
76
76
|
disabled && 'cursor-not-allowed opacity-50'
|
|
77
77
|
)}
|
|
78
78
|
>
|
|
79
79
|
<span
|
|
80
80
|
className={cn(
|
|
81
|
-
'inline-block h-3.5 w-3.5 transform rounded-full bg-
|
|
81
|
+
'inline-block h-3.5 w-3.5 transform rounded-full bg-[rgb(var(--ec-page-bg))] shadow-sm transition-transform',
|
|
82
82
|
checked ? 'translate-x-[1.125rem]' : 'translate-x-[0.1875rem]'
|
|
83
83
|
)}
|
|
84
84
|
/>
|
|
@@ -21,57 +21,56 @@ import {
|
|
|
21
21
|
type FavoriteItem,
|
|
22
22
|
} from '@stores/favorites-store';
|
|
23
23
|
import {
|
|
24
|
+
buildNodeLookup,
|
|
24
25
|
canCollapseGroup,
|
|
25
26
|
findNodeKeyByUrl,
|
|
26
27
|
getBadgeClasses,
|
|
27
28
|
getDefaultCollapsedState,
|
|
28
29
|
hidesDefaultItemIcon,
|
|
29
30
|
isGroupCollapsed,
|
|
31
|
+
resolveNavRef,
|
|
32
|
+
rootLevel,
|
|
33
|
+
stripBasePath,
|
|
30
34
|
toggleGroupCollapsed,
|
|
35
|
+
type NavigationLevel,
|
|
36
|
+
type SidebarSnapshot,
|
|
31
37
|
} from './utils';
|
|
32
38
|
import { resolveIconUrl } from '@utils/icon';
|
|
33
39
|
|
|
34
40
|
const cn = (...classes: (string | false | undefined)[]) => classes.filter(Boolean).join(' ');
|
|
35
41
|
|
|
36
|
-
/**
|
|
37
|
-
* Strip the configured base path from a pathname so URL pattern matching works
|
|
38
|
-
* regardless of the base path setting (e.g. `/eventcatalog/docs/...` → `/docs/...`).
|
|
39
|
-
*/
|
|
40
|
-
const stripBasePath = (pathname: string): string => {
|
|
41
|
-
const base = __EC_BASE__.replace(/\/$/, ''); // e.g. '/eventcatalog'
|
|
42
|
-
if (base && pathname.startsWith(base)) {
|
|
43
|
-
return pathname.slice(base.length) || '/';
|
|
44
|
-
}
|
|
45
|
-
return pathname;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
42
|
// ============================================
|
|
49
43
|
// Component
|
|
50
44
|
// ============================================
|
|
51
45
|
|
|
52
|
-
type
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
type NestedSideBarProps = {
|
|
47
|
+
/**
|
|
48
|
+
* This page's level, built on the server. It renders the sidebar into the HTML and keeps
|
|
49
|
+
* the island showing it until the full navigation data (sidebar-data.json) is loaded.
|
|
50
|
+
*/
|
|
51
|
+
snapshot?: SidebarSnapshot;
|
|
57
52
|
};
|
|
58
53
|
|
|
59
|
-
export default function NestedSideBar() {
|
|
60
|
-
const
|
|
54
|
+
export default function NestedSideBar({ snapshot }: NestedSideBarProps) {
|
|
55
|
+
const storeData = useStore(sidebarStore);
|
|
61
56
|
const favorites = useStore(favoritesStore);
|
|
57
|
+
// Drill-down, restoring state and favorites need the whole catalog; until it loads the
|
|
58
|
+
// snapshot only shows this page's level
|
|
59
|
+
const hasFullData = storeData !== null;
|
|
60
|
+
const data = storeData ?? snapshot?.data ?? null;
|
|
62
61
|
|
|
63
62
|
// Guard against undefined data (e.g., during hydration)
|
|
64
63
|
// Use useMemo to ensure stable references for roots and nodes
|
|
65
64
|
const roots = useMemo(() => data?.roots ?? [], [data?.roots]);
|
|
66
65
|
const nodes = useMemo(() => data?.nodes ?? {}, [data?.nodes]);
|
|
67
66
|
|
|
68
|
-
const [navigationStack, setNavigationStack] = useState<NavigationLevel[]>(
|
|
69
|
-
{ key: null, entries: [], title: 'Documentation' }
|
|
70
|
-
|
|
67
|
+
const [navigationStack, setNavigationStack] = useState<NavigationLevel[]>(
|
|
68
|
+
() => snapshot?.stack ?? [{ key: null, entries: [], title: 'Documentation' }]
|
|
69
|
+
);
|
|
71
70
|
const [animationKey, setAnimationKey] = useState(0);
|
|
72
71
|
const [slideDirection, setSlideDirection] = useState<'forward' | 'backward' | null>(null);
|
|
73
72
|
const [isInitialized, setIsInitialized] = useState(false);
|
|
74
|
-
const [currentPath, setCurrentPath] = useState<string>('');
|
|
73
|
+
const [currentPath, setCurrentPath] = useState<string>(snapshot?.url ?? '');
|
|
75
74
|
const [sectionCollapsePreferences, setSectionCollapsePreferences] = useState(loadCollapsedSections);
|
|
76
75
|
const [showPathPreview, setShowPathPreview] = useState(false);
|
|
77
76
|
const [showFullPath, setShowFullPath] = useState(false);
|
|
@@ -79,33 +78,7 @@ export default function NestedSideBar() {
|
|
|
79
78
|
|
|
80
79
|
// Build a lookup map for faster URL navigation
|
|
81
80
|
// Map format: "type:id" -> "nodeKey"
|
|
82
|
-
const nodeLookup = useMemo(() =>
|
|
83
|
-
const lookup = new Map<string, string>();
|
|
84
|
-
|
|
85
|
-
Object.entries(nodes).forEach(([key, value]) => {
|
|
86
|
-
// Skip keys that are references (string values pointing to other keys)
|
|
87
|
-
// These are unversioned aliases like "domain:E-Commerce" -> "domain:E-Commerce:1.0.0"
|
|
88
|
-
if (typeof value === 'string') return;
|
|
89
|
-
|
|
90
|
-
// Key formats:
|
|
91
|
-
// - "type:id:version" (e.g., "service:OrdersService:0.0.3")
|
|
92
|
-
// - "type:id" (e.g., "user:john", "team:backend") - non-versioned resources
|
|
93
|
-
// - "list:name" (e.g., "list:domains") - skip these
|
|
94
|
-
const parts = key.split(':');
|
|
95
|
-
|
|
96
|
-
// Skip list items
|
|
97
|
-
if (parts[0] === 'list') return;
|
|
98
|
-
|
|
99
|
-
if (parts.length >= 2) {
|
|
100
|
-
// Store as "type:id"
|
|
101
|
-
const type = parts[0];
|
|
102
|
-
const id = parts[1];
|
|
103
|
-
lookup.set(`${type}:${id}`, key);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
return lookup;
|
|
108
|
-
}, [nodes]);
|
|
81
|
+
const nodeLookup = useMemo(() => buildNodeLookup(nodes), [nodes]);
|
|
109
82
|
|
|
110
83
|
/**
|
|
111
84
|
* Toggle section collapse state
|
|
@@ -126,7 +99,7 @@ export default function NestedSideBar() {
|
|
|
126
99
|
setNavigationStack((prevStack) => {
|
|
127
100
|
// Only update if the current stack has no entries (initial state)
|
|
128
101
|
if (prevStack.length === 1 && prevStack[0].entries.length === 0) {
|
|
129
|
-
return [
|
|
102
|
+
return [rootLevel(roots)];
|
|
130
103
|
}
|
|
131
104
|
return prevStack;
|
|
132
105
|
});
|
|
@@ -146,21 +119,7 @@ export default function NestedSideBar() {
|
|
|
146
119
|
* Resolve a child reference to a NavNode
|
|
147
120
|
* Handles both direct keys and string references (unversioned aliases pointing to versioned keys)
|
|
148
121
|
*/
|
|
149
|
-
const resolveRef = useCallback(
|
|
150
|
-
(ref: ChildRef): NavNode | null => {
|
|
151
|
-
if (typeof ref === 'string') {
|
|
152
|
-
const node = nodes[ref];
|
|
153
|
-
if (!node) return null;
|
|
154
|
-
// If node is a string, it's a reference to another key (e.g., unversioned alias)
|
|
155
|
-
if (typeof node === 'string') {
|
|
156
|
-
return (nodes[node] as NavNode) ?? null;
|
|
157
|
-
}
|
|
158
|
-
return node;
|
|
159
|
-
}
|
|
160
|
-
return ref;
|
|
161
|
-
},
|
|
162
|
-
[nodes]
|
|
163
|
-
);
|
|
122
|
+
const resolveRef = useCallback((ref: ChildRef): NavNode | null => resolveNavRef(nodes, ref), [nodes]);
|
|
164
123
|
|
|
165
124
|
/**
|
|
166
125
|
* Check if a node is visible (default: true)
|
|
@@ -175,7 +134,7 @@ export default function NestedSideBar() {
|
|
|
175
134
|
*/
|
|
176
135
|
const buildStackFromPath = useCallback(
|
|
177
136
|
(path: string[]): NavigationLevel[] => {
|
|
178
|
-
const stack: NavigationLevel[] = [
|
|
137
|
+
const stack: NavigationLevel[] = [rootLevel(roots)];
|
|
179
138
|
|
|
180
139
|
for (const key of path) {
|
|
181
140
|
const node = resolveRef(key);
|
|
@@ -281,7 +240,7 @@ export default function NestedSideBar() {
|
|
|
281
240
|
if (foundNode && foundNode.pages && foundNode.pages.length > 0) {
|
|
282
241
|
// Fallback: Flattened navigation
|
|
283
242
|
return [
|
|
284
|
-
|
|
243
|
+
rootLevel(roots),
|
|
285
244
|
{ key: foundNodeKey, entries: foundNode.pages, title: foundNode.title, badge: foundNode.badge },
|
|
286
245
|
];
|
|
287
246
|
}
|
|
@@ -296,7 +255,7 @@ export default function NestedSideBar() {
|
|
|
296
255
|
setSlideDirection('backward');
|
|
297
256
|
setAnimationKey((prev) => prev + 1);
|
|
298
257
|
}
|
|
299
|
-
return [
|
|
258
|
+
return [rootLevel(roots)];
|
|
300
259
|
});
|
|
301
260
|
return true;
|
|
302
261
|
}
|
|
@@ -309,14 +268,14 @@ export default function NestedSideBar() {
|
|
|
309
268
|
* Restore state from localStorage on mount, or navigate to URL
|
|
310
269
|
*/
|
|
311
270
|
useEffect(() => {
|
|
312
|
-
if (!
|
|
271
|
+
if (!hasFullData || roots.length === 0 || isInitialized) return;
|
|
313
272
|
|
|
314
273
|
const currentUrl = window.location.pathname;
|
|
315
274
|
const normalizedCurrentUrl = stripBasePath(currentUrl);
|
|
316
275
|
|
|
317
276
|
// Force root navigation on homepage
|
|
318
277
|
if (normalizedCurrentUrl === '/' || normalizedCurrentUrl === '') {
|
|
319
|
-
setNavigationStack([
|
|
278
|
+
setNavigationStack([rootLevel(roots)]);
|
|
320
279
|
setIsInitialized(true);
|
|
321
280
|
return;
|
|
322
281
|
}
|
|
@@ -347,7 +306,7 @@ export default function NestedSideBar() {
|
|
|
347
306
|
const targetNode = resolveRef(targetKey);
|
|
348
307
|
if (targetNode && targetNode.pages && targetNode.pages.length > 0) {
|
|
349
308
|
finalStack = [
|
|
350
|
-
|
|
309
|
+
rootLevel(roots),
|
|
351
310
|
{ key: targetKey, entries: targetNode.pages, title: targetNode.title, badge: targetNode.badge },
|
|
352
311
|
];
|
|
353
312
|
}
|
|
@@ -355,13 +314,13 @@ export default function NestedSideBar() {
|
|
|
355
314
|
|
|
356
315
|
// 3. Fallback to root
|
|
357
316
|
if (!finalStack) {
|
|
358
|
-
setNavigationStack([
|
|
317
|
+
setNavigationStack([rootLevel(roots)]);
|
|
359
318
|
} else {
|
|
360
319
|
setNavigationStack(finalStack);
|
|
361
320
|
}
|
|
362
321
|
|
|
363
322
|
setIsInitialized(true);
|
|
364
|
-
}, [
|
|
323
|
+
}, [hasFullData, roots, isInitialized, buildStackFromPath, findNodeKeyForUrl, tryConnectStack, resolveRef]);
|
|
365
324
|
|
|
366
325
|
/**
|
|
367
326
|
* Save state whenever navigation changes
|
|
@@ -575,6 +534,7 @@ export default function NestedSideBar() {
|
|
|
575
534
|
* Handle drilling down into an item with children
|
|
576
535
|
*/
|
|
577
536
|
const handleDrillDown = (node: NavNode, nodeKey: string | null) => {
|
|
537
|
+
if (!hasFullData) return;
|
|
578
538
|
if (node.pages && node.pages.length > 0) {
|
|
579
539
|
setSlideDirection('forward');
|
|
580
540
|
setAnimationKey((prev) => prev + 1);
|
|
@@ -590,7 +550,7 @@ export default function NestedSideBar() {
|
|
|
590
550
|
* Navigate back one level
|
|
591
551
|
*/
|
|
592
552
|
const navigateBack = () => {
|
|
593
|
-
if (navigationStack.length > 1) {
|
|
553
|
+
if (hasFullData && navigationStack.length > 1) {
|
|
594
554
|
setSlideDirection('backward');
|
|
595
555
|
setAnimationKey((prev) => prev + 1);
|
|
596
556
|
setNavigationStack(navigationStack.slice(0, -1));
|
|
@@ -604,7 +564,7 @@ export default function NestedSideBar() {
|
|
|
604
564
|
* Navigate to a specific level in the stack
|
|
605
565
|
*/
|
|
606
566
|
const navigateToLevel = (levelIndex: number) => {
|
|
607
|
-
if (levelIndex < navigationStack.length - 1) {
|
|
567
|
+
if (hasFullData && levelIndex < navigationStack.length - 1) {
|
|
608
568
|
setSlideDirection('backward');
|
|
609
569
|
setAnimationKey((prev) => prev + 1);
|
|
610
570
|
setNavigationStack(navigationStack.slice(0, levelIndex + 1));
|
|
@@ -634,6 +594,7 @@ export default function NestedSideBar() {
|
|
|
634
594
|
* Navigate to a favorited item
|
|
635
595
|
*/
|
|
636
596
|
const navigateToFavorite = (favorite: FavoriteItem) => {
|
|
597
|
+
if (!hasFullData) return;
|
|
637
598
|
// If it has an href and no children, just navigate to the URL
|
|
638
599
|
const node = resolveRef(favorite.nodeKey);
|
|
639
600
|
if (favorite.href && (!node?.pages || node.pages.length === 0)) {
|
|
@@ -107,6 +107,8 @@ export const saveCollapsedSections = (preferences: SectionCollapsePreferences):
|
|
|
107
107
|
};
|
|
108
108
|
|
|
109
109
|
export const loadCollapsedSections = (): SectionCollapsePreferences => {
|
|
110
|
+
// Rendered on the server for the first paint, where there is nothing saved yet
|
|
111
|
+
if (typeof localStorage === 'undefined') return createSectionCollapsePreferences();
|
|
110
112
|
try {
|
|
111
113
|
const stored = localStorage.getItem(SECTION_PREFERENCES_KEY);
|
|
112
114
|
if (stored) {
|
|
@@ -1,9 +1,130 @@
|
|
|
1
1
|
// Shared utilities for NestedSideBar components
|
|
2
2
|
|
|
3
|
-
import type { NavNode } from '@stores/sidebar-store/state';
|
|
3
|
+
import type { ChildRef, NavigationData, NavNode } from '@stores/sidebar-store/state';
|
|
4
4
|
|
|
5
5
|
export const SIDEBAR_GROUP_COLLAPSE_THRESHOLD = 5;
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Strip the configured base path from a pathname so URL pattern matching works
|
|
9
|
+
* regardless of the base path setting (e.g. `/eventcatalog/docs/...` → `/docs/...`).
|
|
10
|
+
*/
|
|
11
|
+
export const stripBasePath = (pathname: string): string => {
|
|
12
|
+
const base = __EC_BASE__.replace(/\/$/, ''); // e.g. '/eventcatalog'
|
|
13
|
+
if (base && pathname.startsWith(base)) {
|
|
14
|
+
return pathname.slice(base.length) || '/';
|
|
15
|
+
}
|
|
16
|
+
return pathname;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type NavigationLevel = {
|
|
20
|
+
key: string | null; // The key of the node that was drilled into (null for root)
|
|
21
|
+
entries: ChildRef[];
|
|
22
|
+
title: string;
|
|
23
|
+
badge?: string; // Category badge (e.g., "Domain", "Service")
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const rootLevel = (roots: ChildRef[]): NavigationLevel => ({ key: null, entries: roots, title: 'Documentation' });
|
|
27
|
+
|
|
28
|
+
/** Resolve a child reference to a node, following unversioned aliases (string → key). */
|
|
29
|
+
export const resolveNavRef = (nodes: NavigationData['nodes'], ref: ChildRef): NavNode | null => {
|
|
30
|
+
if (typeof ref !== 'string') return ref;
|
|
31
|
+
const node = nodes[ref];
|
|
32
|
+
if (!node) return null;
|
|
33
|
+
if (typeof node === 'string') return (nodes[node] as NavNode) ?? null;
|
|
34
|
+
return node;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Map of "type:id" → versioned node key, used to match URLs to nodes. */
|
|
38
|
+
export const buildNodeLookup = (nodes: NavigationData['nodes']): Map<string, string> => {
|
|
39
|
+
const lookup = new Map<string, string>();
|
|
40
|
+
|
|
41
|
+
Object.entries(nodes).forEach(([key, value]) => {
|
|
42
|
+
// Skip keys that are references (string values pointing to other keys)
|
|
43
|
+
// These are unversioned aliases like "domain:E-Commerce" -> "domain:E-Commerce:1.0.0"
|
|
44
|
+
if (typeof value === 'string') return;
|
|
45
|
+
|
|
46
|
+
// Key formats:
|
|
47
|
+
// - "type:id:version" (e.g., "service:OrdersService:0.0.3")
|
|
48
|
+
// - "type:id" (e.g., "user:john", "team:backend") - non-versioned resources
|
|
49
|
+
// - "list:name" (e.g., "list:domains") - skip these
|
|
50
|
+
const parts = key.split(':');
|
|
51
|
+
|
|
52
|
+
// Skip list items
|
|
53
|
+
if (parts[0] === 'list') return;
|
|
54
|
+
|
|
55
|
+
if (parts.length >= 2) {
|
|
56
|
+
// Store as "type:id"
|
|
57
|
+
lookup.set(`${parts[0]}:${parts[1]}`, key);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return lookup;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* What the sidebar shows for a URL before it knows the reader's saved drill-down path:
|
|
66
|
+
* the root level on the homepage or for pages without children, otherwise the matching
|
|
67
|
+
* resource's own level (the same "flattened" stack the client falls back to).
|
|
68
|
+
*/
|
|
69
|
+
export const getStackForUrl = (
|
|
70
|
+
url: string,
|
|
71
|
+
data: NavigationData,
|
|
72
|
+
nodeLookup: ReadonlyMap<string, string> = buildNodeLookup(data.nodes)
|
|
73
|
+
): NavigationLevel[] => {
|
|
74
|
+
const root = rootLevel(data.roots);
|
|
75
|
+
if (url === '/' || url === '') return [root];
|
|
76
|
+
|
|
77
|
+
const targetKey = findNodeKeyByUrl(url, data.nodes, nodeLookup);
|
|
78
|
+
const target = targetKey ? resolveNavRef(data.nodes, targetKey) : null;
|
|
79
|
+
if (!targetKey || !target?.pages?.length) return [root];
|
|
80
|
+
|
|
81
|
+
return [root, { key: targetKey, entries: target.pages, title: target.title, badge: target.badge }];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Everything the sidebar needs to render one page's level, without the whole catalog: the
|
|
86
|
+
* stack for the URL and only the nodes that level shows (its items, and the contents of its
|
|
87
|
+
* groups). Rendered on the server so the sidebar appears with the HTML, and handed to the
|
|
88
|
+
* island so it keeps showing it until the full navigation data loads.
|
|
89
|
+
*/
|
|
90
|
+
export type SidebarSnapshot = {
|
|
91
|
+
url: string;
|
|
92
|
+
stack: NavigationLevel[];
|
|
93
|
+
data: NavigationData;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const nodeLookupCache = new WeakMap<NavigationData, Map<string, string>>();
|
|
97
|
+
|
|
98
|
+
export const buildSidebarSnapshot = (data: NavigationData, url: string): SidebarSnapshot => {
|
|
99
|
+
let nodeLookup = nodeLookupCache.get(data);
|
|
100
|
+
if (!nodeLookup) {
|
|
101
|
+
nodeLookup = buildNodeLookup(data.nodes);
|
|
102
|
+
nodeLookupCache.set(data, nodeLookup);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const stack = getStackForUrl(url, data, nodeLookup);
|
|
106
|
+
const level = stack[stack.length - 1];
|
|
107
|
+
const nodes: NavigationData['nodes'] = {};
|
|
108
|
+
|
|
109
|
+
const include = (ref: ChildRef) => {
|
|
110
|
+
if (typeof ref === 'string') {
|
|
111
|
+
if (ref in nodes) return;
|
|
112
|
+
const value = data.nodes[ref];
|
|
113
|
+
if (value === undefined) return;
|
|
114
|
+
nodes[ref] = value;
|
|
115
|
+
if (typeof value === 'string' && data.nodes[value] !== undefined) nodes[value] = data.nodes[value];
|
|
116
|
+
}
|
|
117
|
+
const node = resolveNavRef(data.nodes, ref);
|
|
118
|
+
// Groups render their children inline; items with children only need their own node
|
|
119
|
+
if (node?.type === 'group') node.pages?.forEach(include);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (level.key) include(level.key);
|
|
123
|
+
level.entries.forEach(include);
|
|
124
|
+
|
|
125
|
+
return { url, stack, data: { roots: data.roots, nodes } };
|
|
126
|
+
};
|
|
127
|
+
|
|
7
128
|
/**
|
|
8
129
|
* The user's overrides of each group's default collapse state, keyed by group id.
|
|
9
130
|
* A group is in at most one set; absence means "use the group's default".
|
|
@@ -3,10 +3,18 @@ import type { HTMLAttributes } from 'astro/types';
|
|
|
3
3
|
|
|
4
4
|
interface Props extends Omit<HTMLAttributes<'div'>, 'children'> {}
|
|
5
5
|
import NestedSideBar from './NestedSideBar';
|
|
6
|
+
import { buildSidebarSnapshot, stripBasePath } from './NestedSideBar/utils';
|
|
7
|
+
import { getNestedSideBarData } from '@stores/sidebar-store/state';
|
|
6
8
|
import { ClientRouter } from 'astro:transitions';
|
|
9
|
+
|
|
10
|
+
// Render this page's sidebar level into the HTML so it shows before any JavaScript runs;
|
|
11
|
+
// the full navigation still loads from /api/sidebar-data.json (see SearchDataLoader)
|
|
12
|
+
const snapshot = buildSidebarSnapshot(await getNestedSideBarData(), stripBasePath(Astro.url.pathname));
|
|
7
13
|
---
|
|
8
14
|
|
|
9
15
|
<div {...Astro.props}>
|
|
10
16
|
<ClientRouter />
|
|
11
|
-
<NestedSideBar client:only="react"
|
|
17
|
+
<NestedSideBar client:only="react" snapshot={snapshot}>
|
|
18
|
+
<NestedSideBar slot="fallback" snapshot={snapshot} />
|
|
19
|
+
</NestedSideBar>
|
|
12
20
|
</div>
|