@eventcatalog/core 5.0.0-beta.3 → 5.0.0-beta.31
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-BH2F5WPN.js → chunk-2UCCTEIH.js} +1 -1
- package/dist/{chunk-RFIXKATC.js → chunk-4G7FSRPN.js} +35 -42
- package/dist/{chunk-TQLRG35T.js → chunk-AD7CL772.js} +78 -45
- package/dist/{chunk-NDJOAITI.js → chunk-BNSLGNQI.js} +9 -3
- package/dist/chunk-CA6WCQ2T.js +54 -0
- package/dist/chunk-CPW6G62V.js +17 -0
- package/dist/{chunk-MDWB5HLO.js → chunk-NKNOXQ62.js} +1 -1
- package/dist/{chunk-423S2KHN.js → chunk-OUEGYMBA.js} +4 -2
- 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-GYIVJXOJ.js → chunk-WADZVNCA.js} +1 -1
- package/dist/{chunk-6OC46WQJ.js → chunk-XRFL642Z.js} +66 -35
- 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
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { PageTypes } from '@types';
|
|
2
|
+
import { isVisualiserEnabled } from '@utils/feature';
|
|
3
|
+
import { pageDataLoader } from '@utils/page-loaders/page-data-loader';
|
|
4
|
+
|
|
5
|
+
/** Resources with a visualiser page (domains and systems have their own, under the same URLs) */
|
|
6
|
+
const VISUALISER_TYPES: PageTypes[] = [
|
|
7
|
+
'domains',
|
|
8
|
+
'systems',
|
|
9
|
+
'agents',
|
|
10
|
+
'services',
|
|
11
|
+
'events',
|
|
12
|
+
'commands',
|
|
13
|
+
'queries',
|
|
14
|
+
'flows',
|
|
15
|
+
'containers',
|
|
16
|
+
'channels',
|
|
17
|
+
'data-products',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const isVisualiserType = (type: string | undefined): type is PageTypes => VISUALISER_TYPES.includes(type as PageTypes);
|
|
21
|
+
|
|
22
|
+
const getLatestWithVisualiser = async (type: PageTypes) =>
|
|
23
|
+
(await pageDataLoader[type]({ getAllVersions: false })).filter((item) => (item.data as any).visualiser !== false);
|
|
24
|
+
|
|
25
|
+
/** The latest version of every resource with a visualiser page: the pages a static build redirects from */
|
|
26
|
+
export const getVisualiserResources = async () => {
|
|
27
|
+
if (!isVisualiserEnabled()) return [];
|
|
28
|
+
const resources = await Promise.all(
|
|
29
|
+
VISUALISER_TYPES.map(async (type) => (await getLatestWithVisualiser(type)).map((item) => ({ type, item })))
|
|
30
|
+
);
|
|
31
|
+
return resources.flat();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** The latest version of a resource with a visualiser page, looked up from its URL (a server renders pages on request) */
|
|
35
|
+
export const findVisualiserResource = async (type: string | undefined, id: string | undefined) => {
|
|
36
|
+
if (!isVisualiserEnabled() || !isVisualiserType(type) || !id) return undefined;
|
|
37
|
+
return (await getLatestWithVisualiser(type)).find((item) => item.data.id === id);
|
|
38
|
+
};
|
|
@@ -1,59 +1,36 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Seo from '@components/Seo.astro';
|
|
3
3
|
import { buildUrl } from '@utils/url-builder';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { getServices } from '@utils/collections/services';
|
|
7
|
-
import { getDomains } from '@utils/collections/domains';
|
|
8
|
-
import { getContainers } from '@utils/collections/containers';
|
|
9
|
-
import type { CollectionEntry } from 'astro:content';
|
|
10
|
-
import type { CollectionTypes } from '@types';
|
|
11
|
-
import { isVisualiserEnabled } from '@utils/feature';
|
|
4
|
+
import { isSSR } from '@utils/feature';
|
|
5
|
+
import { findVisualiserResource, getVisualiserResources } from './_index.data';
|
|
12
6
|
|
|
13
|
-
export
|
|
14
|
-
if (!isVisualiserEnabled()) {
|
|
15
|
-
return [];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const [events, commands, services, domains, containers] = await Promise.all([
|
|
19
|
-
getEvents(),
|
|
20
|
-
getCommands(),
|
|
21
|
-
getServices(),
|
|
22
|
-
getDomains(),
|
|
23
|
-
getContainers(),
|
|
24
|
-
]);
|
|
7
|
+
export const prerender = !isSSR();
|
|
25
8
|
|
|
26
|
-
|
|
27
|
-
const
|
|
9
|
+
export async function getStaticPaths() {
|
|
10
|
+
const resources = await getVisualiserResources();
|
|
11
|
+
return resources.map(({ type, item }) => ({ params: { type, id: item.data.id }, props: item }));
|
|
12
|
+
}
|
|
28
13
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
params: {
|
|
32
|
-
type: item.collection,
|
|
33
|
-
id: item.data.id,
|
|
34
|
-
},
|
|
35
|
-
props: {
|
|
36
|
-
type: item.collection,
|
|
37
|
-
...item,
|
|
38
|
-
},
|
|
39
|
-
}));
|
|
40
|
-
};
|
|
14
|
+
// A static build gets the resource from getStaticPaths; a server, which has no static paths, looks it up
|
|
15
|
+
const resource = isSSR() ? await findVisualiserResource(Astro.params.type, Astro.params.id) : Astro.props;
|
|
41
16
|
|
|
42
|
-
|
|
17
|
+
if (!resource?.data) {
|
|
18
|
+
return new Response(null, { status: 404, statusText: 'Not found' });
|
|
43
19
|
}
|
|
44
20
|
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
const { pathname } = Astro.url;
|
|
21
|
+
const pageTitle = `${resource.collection} | ${resource.data.name}`.replace(/^\w/, (c) => c.toUpperCase());
|
|
22
|
+
const redirectUrl = buildUrl(`${Astro.url.pathname.replace(/\/$/, '')}/${resource.data.latestVersion}`, false, true);
|
|
49
23
|
|
|
50
|
-
|
|
24
|
+
// A server redirects straight away (with any query string); a static page redirects in the browser
|
|
25
|
+
if (isSSR()) {
|
|
26
|
+
return Astro.redirect(`${redirectUrl}${Astro.url.search}`);
|
|
27
|
+
}
|
|
51
28
|
---
|
|
52
29
|
|
|
53
30
|
<!doctype html>
|
|
54
31
|
<html lang="en">
|
|
55
32
|
<head>
|
|
56
|
-
<Seo title={
|
|
33
|
+
<Seo title={pageTitle} />
|
|
57
34
|
</head>
|
|
58
35
|
<body>
|
|
59
36
|
<p>You are being redirected to <a href={redirectUrl}>{redirectUrl}</a></p>
|
|
@@ -45,13 +45,6 @@ export class Page extends HybridPage {
|
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
protected static createNotFoundResponse(): Response {
|
|
49
|
-
return new Response(null, {
|
|
50
|
-
status: 404,
|
|
51
|
-
statusText: 'Design not found',
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
48
|
static get clientAuthScript(): string {
|
|
56
49
|
if (!isAuthEnabled() || !isVisualiserEnabled()) {
|
|
57
50
|
return '';
|
|
@@ -13,7 +13,8 @@ const isChatEnabled = isEventCatalogChatVisible();
|
|
|
13
13
|
export const prerender = Page.prerender;
|
|
14
14
|
export const getStaticPaths = Page.getStaticPaths;
|
|
15
15
|
|
|
16
|
-
const props = Astro
|
|
16
|
+
const props = await Page.getData(Astro);
|
|
17
|
+
if (!props) return Astro.rewrite('/404');
|
|
17
18
|
|
|
18
19
|
const { data } = props;
|
|
19
20
|
---
|
|
@@ -47,13 +47,6 @@ export class Page extends HybridPage {
|
|
|
47
47
|
return item;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
protected static createNotFoundResponse(): Response {
|
|
51
|
-
return new Response(null, {
|
|
52
|
-
status: 404,
|
|
53
|
-
statusText: 'Domain entity map page not found',
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
50
|
static get clientAuthScript(): string {
|
|
58
51
|
if (!isAuthEnabled() || !isVisualiserEnabled()) {
|
|
59
52
|
return '';
|
package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts
CHANGED
|
@@ -58,13 +58,6 @@ export class Page extends HybridPage {
|
|
|
58
58
|
return item;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
protected static createNotFoundResponse(): Response {
|
|
62
|
-
return new Response(null, {
|
|
63
|
-
status: 404,
|
|
64
|
-
statusText: 'Domain System Diagram page not found',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
61
|
static get clientAuthScript(): string {
|
|
69
62
|
if (!isAuthEnabled() || !isVisualiserEnabled()) {
|
|
70
63
|
return '';
|
package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro
CHANGED
|
@@ -8,6 +8,7 @@ export const getStaticPaths = Page.getStaticPaths;
|
|
|
8
8
|
|
|
9
9
|
// Get data
|
|
10
10
|
const props = await Page.getData(Astro);
|
|
11
|
+
if (!props) return Astro.rewrite('/404');
|
|
11
12
|
|
|
12
13
|
// The System Diagram is now level 1 of the domain's visualiser page
|
|
13
14
|
return Astro.redirect(buildUrl(`/visualiser/domains/${props.data.id}/${props.data.version}?level=1`));
|
|
@@ -61,13 +61,6 @@ export class Page extends HybridPage {
|
|
|
61
61
|
return item;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
protected static createNotFoundResponse(): Response {
|
|
65
|
-
return new Response(null, {
|
|
66
|
-
status: 404,
|
|
67
|
-
statusText: 'System Diagram page not found',
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
64
|
static get clientAuthScript(): string {
|
|
72
65
|
if (!isAuthEnabled() || !isVisualiserEnabled()) {
|
|
73
66
|
return '';
|
|
@@ -8,6 +8,7 @@ export const getStaticPaths = Page.getStaticPaths;
|
|
|
8
8
|
|
|
9
9
|
// Get data
|
|
10
10
|
const props = await Page.getData(Astro);
|
|
11
|
+
if (!props) return Astro.rewrite('/404');
|
|
11
12
|
|
|
12
13
|
// The System Context diagram is now level 1 of the system's visualiser page
|
|
13
14
|
return Astro.redirect(buildUrl(`/visualiser/systems/${props.data.id}/${props.data.version}?level=1`));
|
|
@@ -12,3 +12,13 @@ declare module 'react-syntax-highlighter' {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
declare module 'react-syntax-highlighter/dist/esm/styles/prism/material-light';
|
|
15
|
+
|
|
16
|
+
declare module 'react-syntax-highlighter/dist/cjs/create-element.js' {
|
|
17
|
+
import type { CSSProperties } from 'react';
|
|
18
|
+
|
|
19
|
+
export function createStyleObject(
|
|
20
|
+
classNames: string[],
|
|
21
|
+
elementStyle?: CSSProperties,
|
|
22
|
+
stylesheet?: { [selector: string]: CSSProperties }
|
|
23
|
+
): CSSProperties;
|
|
24
|
+
}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import type { CollectionTypes } from '@types';
|
|
2
2
|
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import path from 'node:path';
|
|
4
3
|
import { compareVersions, toComparableVersion, versionSatisfiesRange } from './version-compare';
|
|
5
4
|
|
|
6
5
|
// --- FILE PATH HELPERS ---
|
|
7
6
|
|
|
7
|
+
// Without node:path: node graph builders that import this module also run in the browser (the Fields Explorer)
|
|
8
|
+
const pathSegments = (filePath: string) => filePath.split(/[\\/]/).filter(Boolean);
|
|
9
|
+
const getBasename = (filePath: string) => pathSegments(filePath).at(-1) ?? '';
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Extract the folder name from an Astro collection entry's filePath.
|
|
10
13
|
* Replaces the expensive SDK getResourceFolderName which globs + reads every file.
|
|
11
14
|
*/
|
|
12
15
|
export const getFolderNameFromFilePath = (filePath: string): string => {
|
|
13
|
-
return
|
|
16
|
+
return pathSegments(filePath).at(-2) ?? '';
|
|
14
17
|
};
|
|
15
18
|
|
|
16
19
|
// --- SPECIFICATION HELPERS ---
|
|
@@ -73,8 +76,9 @@ export const processSpecifications = (
|
|
|
73
76
|
return specs.map((spec) => ({
|
|
74
77
|
...spec,
|
|
75
78
|
name: spec.name || getDefaultSpecificationName(spec.type),
|
|
76
|
-
filename:
|
|
77
|
-
|
|
79
|
+
filename: getBasename(spec.path),
|
|
80
|
+
// Keeps a leading dot, as path.extname does (`.env` has no extension)
|
|
81
|
+
filenameWithoutExtension: getBasename(spec.path).replace(/(?<=.)\.[^.]*$/, ''),
|
|
78
82
|
}));
|
|
79
83
|
};
|
|
80
84
|
|
|
@@ -27,4 +27,12 @@ export const isAuthEnabled = () =>
|
|
|
27
27
|
(config?.auth?.enabled ?? false) && fs.existsSync(join(projectDirectory(), 'eventcatalog.auth.js')) && isSSR();
|
|
28
28
|
|
|
29
29
|
export const isEventCatalogMCPEnabled = () => isSSR() && (config?.mcp?.enabled ?? true);
|
|
30
|
+
|
|
31
|
+
// Collaborative canvases (EventCatalog Studio, /studio) are an experiment: on the dev server (unless studio.enabled is
|
|
32
|
+
// false), and in production (server output) when studio.enabled is set. With sign-in on, only signed-in people can
|
|
33
|
+
// open them.
|
|
34
|
+
export const isCanvasEnabled = () => {
|
|
35
|
+
const enabled = config?.studio?.enabled;
|
|
36
|
+
return enabled !== false && (isDevMode() || (isSSR() && enabled === true));
|
|
37
|
+
};
|
|
30
38
|
export const isEventCatalogMCPAuthEnabled = () => isEventCatalogMCPEnabled() && (config?.mcp?.auth?.enabled ?? false);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import shell from 'shelljs';
|
|
5
4
|
|
|
6
5
|
type Commit = { timestamp: number; author: string };
|
|
7
6
|
|
|
@@ -9,10 +8,6 @@ const COMMIT_MARKER = '\x1e';
|
|
|
9
8
|
|
|
10
9
|
const newestCommitsByRepository = new Map<string, Map<string, Commit> | undefined>();
|
|
11
10
|
|
|
12
|
-
export function hasGit() {
|
|
13
|
-
return !!shell.which('git');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
const runGit = (args: string[]) => {
|
|
17
12
|
try {
|
|
18
13
|
return execFileSync('git', ['-c', 'log.showSignature=false', ...args], {
|
|
@@ -25,6 +20,17 @@ const runGit = (args: string[]) => {
|
|
|
25
20
|
}
|
|
26
21
|
};
|
|
27
22
|
|
|
23
|
+
// Checked once per PATH, as git history is read for every page
|
|
24
|
+
const gitInstalledByPath = new Map<string | undefined, boolean>();
|
|
25
|
+
|
|
26
|
+
export function hasGit() {
|
|
27
|
+
const searchPath = process.env.PATH;
|
|
28
|
+
if (!gitInstalledByPath.has(searchPath)) {
|
|
29
|
+
gitInstalledByPath.set(searchPath, runGit(['--version']) !== undefined);
|
|
30
|
+
}
|
|
31
|
+
return gitInstalledByPath.get(searchPath)!;
|
|
32
|
+
}
|
|
33
|
+
|
|
28
34
|
const parseCommit = (header: string): Commit => {
|
|
29
35
|
const [timestamp, ...author] = header.split(',');
|
|
30
36
|
return { timestamp: Number(timestamp) * 1_000, author: author.join(',') };
|
|
@@ -81,6 +87,17 @@ const readCommit = (filePath: string, age: 'newest' | 'oldest'): Commit => {
|
|
|
81
87
|
return parseCommit(match.groups.header);
|
|
82
88
|
};
|
|
83
89
|
|
|
90
|
+
/**
|
|
91
|
+
* When a file was last committed, from the history read once for the whole repository: never runs git for one file,
|
|
92
|
+
* so it's cheap to ask for many (e.g. every resource on the homepage). Undefined without git, or for a file that isn't
|
|
93
|
+
* committed.
|
|
94
|
+
*/
|
|
95
|
+
export function getLastCommitDate(filePath: string): Date | undefined {
|
|
96
|
+
if (!hasGit()) return undefined;
|
|
97
|
+
const commit = getNewestCommits()?.get(toRealPath(filePath));
|
|
98
|
+
return commit ? new Date(commit.timestamp) : undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
84
101
|
export function getGitHistory(
|
|
85
102
|
filePath: string,
|
|
86
103
|
{
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { statSync } from 'node:fs';
|
|
3
|
+
import { getCollection } from 'astro:content';
|
|
4
|
+
import { getLastCommitDate } from '@utils/git';
|
|
5
|
+
import { buildUrl } from '@utils/url-builder';
|
|
6
|
+
|
|
7
|
+
/** The resources the dashboard shows, by collection */
|
|
8
|
+
export type DashboardCollection = 'domains' | 'services' | 'events' | 'commands' | 'queries' | 'flows';
|
|
9
|
+
|
|
10
|
+
type Owner = { id: string };
|
|
11
|
+
|
|
12
|
+
/** The fields the dashboard reads from a collection entry */
|
|
13
|
+
export type DashboardEntry = {
|
|
14
|
+
filePath?: string;
|
|
15
|
+
data: {
|
|
16
|
+
id: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
version: string;
|
|
19
|
+
summary?: string;
|
|
20
|
+
hidden?: boolean;
|
|
21
|
+
owners?: Owner[];
|
|
22
|
+
schemaPath?: string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type DashboardResource = {
|
|
27
|
+
collection: DashboardCollection;
|
|
28
|
+
id: string;
|
|
29
|
+
version: string;
|
|
30
|
+
name: string;
|
|
31
|
+
summary?: string;
|
|
32
|
+
href: string;
|
|
33
|
+
owners: { id: string; name: string }[];
|
|
34
|
+
updatedAt?: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type DashboardData = {
|
|
38
|
+
counts: Record<DashboardCollection | 'messages' | 'schemas' | 'teams' | 'users', number>;
|
|
39
|
+
recentlyUpdated: DashboardResource[];
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const MESSAGE_COLLECTIONS = ['events', 'commands', 'queries'] as const;
|
|
43
|
+
|
|
44
|
+
// The latest version of a resource that isn't hidden (older versions live in a `versioned` folder)
|
|
45
|
+
const isCurrent = (entry: DashboardEntry) => entry.data.hidden !== true && !entry.filePath?.includes('versioned');
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Everything the homepage dashboard shows, from the catalog's collections: counts, and what changed recently.
|
|
49
|
+
*/
|
|
50
|
+
export const buildDashboard = ({
|
|
51
|
+
collections,
|
|
52
|
+
teams,
|
|
53
|
+
users,
|
|
54
|
+
getUpdatedAt,
|
|
55
|
+
}: {
|
|
56
|
+
collections: Record<DashboardCollection, DashboardEntry[]>;
|
|
57
|
+
teams: DashboardEntry[];
|
|
58
|
+
users: DashboardEntry[];
|
|
59
|
+
/** When a resource's file last changed (unix ms), if known */
|
|
60
|
+
getUpdatedAt: (entry: DashboardEntry) => number | undefined;
|
|
61
|
+
}): DashboardData => {
|
|
62
|
+
const ownerNames = new Map<string, string>();
|
|
63
|
+
for (const owner of [...teams, ...users]) ownerNames.set(owner.data.id, owner.data.name ?? owner.data.id);
|
|
64
|
+
|
|
65
|
+
const toResource = (collection: DashboardCollection, entry: DashboardEntry): DashboardResource => ({
|
|
66
|
+
collection,
|
|
67
|
+
id: entry.data.id,
|
|
68
|
+
version: entry.data.version,
|
|
69
|
+
name: entry.data.name ?? entry.data.id,
|
|
70
|
+
summary: entry.data.summary?.trim() || undefined,
|
|
71
|
+
href: buildUrl(`/docs/${collection}/${entry.data.id}/${entry.data.version}`),
|
|
72
|
+
owners: (entry.data.owners ?? []).map(({ id }) => ({ id, name: ownerNames.get(id) ?? id })),
|
|
73
|
+
updatedAt: getUpdatedAt(entry),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const current = Object.fromEntries(
|
|
77
|
+
Object.entries(collections).map(([collection, entries]) => [collection, entries.filter(isCurrent)])
|
|
78
|
+
) as Record<DashboardCollection, DashboardEntry[]>;
|
|
79
|
+
const messages = MESSAGE_COLLECTIONS.flatMap((collection) => current[collection]);
|
|
80
|
+
const all = (Object.keys(current) as DashboardCollection[]).flatMap((collection) =>
|
|
81
|
+
current[collection].map((entry) => ({ entry, resource: toResource(collection, entry) }))
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const recentlyUpdated = all
|
|
85
|
+
.map(({ resource }) => resource)
|
|
86
|
+
.filter((resource) => resource.updatedAt !== undefined)
|
|
87
|
+
.sort((a, b) => b.updatedAt! - a.updatedAt!)
|
|
88
|
+
.slice(0, 8);
|
|
89
|
+
|
|
90
|
+
const withSchema = messages.filter((entry) => entry.data.schemaPath).length;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
counts: {
|
|
94
|
+
domains: current.domains.length,
|
|
95
|
+
services: current.services.length,
|
|
96
|
+
events: current.events.length,
|
|
97
|
+
commands: current.commands.length,
|
|
98
|
+
queries: current.queries.length,
|
|
99
|
+
flows: current.flows.length,
|
|
100
|
+
messages: messages.length,
|
|
101
|
+
schemas: withSchema,
|
|
102
|
+
teams: teams.filter(isCurrent).length,
|
|
103
|
+
users: users.filter(isCurrent).length,
|
|
104
|
+
},
|
|
105
|
+
recentlyUpdated,
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// When a resource's file last changed: its last commit, or (without git, or before it's committed) the file's date
|
|
110
|
+
const getUpdatedAt = (entry: DashboardEntry) => {
|
|
111
|
+
if (!entry.filePath) return undefined;
|
|
112
|
+
const file = path.resolve(process.env.PROJECT_DIR || process.cwd(), entry.filePath);
|
|
113
|
+
const committed = getLastCommitDate(file);
|
|
114
|
+
if (committed) return committed.getTime();
|
|
115
|
+
try {
|
|
116
|
+
return statSync(file).mtimeMs;
|
|
117
|
+
} catch {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** The homepage dashboard for this catalog */
|
|
123
|
+
export const getDashboard = async (): Promise<DashboardData> => {
|
|
124
|
+
const [domains, services, events, commands, queries, flows, teams, users] = await Promise.all([
|
|
125
|
+
getCollection('domains'),
|
|
126
|
+
getCollection('services'),
|
|
127
|
+
getCollection('events'),
|
|
128
|
+
getCollection('commands'),
|
|
129
|
+
getCollection('queries'),
|
|
130
|
+
getCollection('flows'),
|
|
131
|
+
getCollection('teams'),
|
|
132
|
+
getCollection('users'),
|
|
133
|
+
]);
|
|
134
|
+
return buildDashboard({
|
|
135
|
+
collections: { domains, services, events, commands, queries, flows } as unknown as Record<
|
|
136
|
+
DashboardCollection,
|
|
137
|
+
DashboardEntry[]
|
|
138
|
+
>,
|
|
139
|
+
teams: teams as unknown as DashboardEntry[],
|
|
140
|
+
users: users as unknown as DashboardEntry[],
|
|
141
|
+
getUpdatedAt,
|
|
142
|
+
});
|
|
143
|
+
};
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { clearCache, hasCommercialLicense, verifyOfflineLicense } from '@eventcatalog/license';
|
|
4
4
|
|
|
5
|
-
export { LICENSE_FAQ_URL, LICENSE_RENEW_URL } from './trial';
|
|
5
|
+
export { BUY_BUSINESS_URL, LICENSE_FAQ_URL, LICENSE_RENEW_URL, PRICING_URL } from './trial';
|
|
6
6
|
|
|
7
7
|
// Details from the license token
|
|
8
8
|
export type LicenseDetails = { org?: string; licenseId?: string; issuedAt?: Date };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { Parser } from 'htmlparser2';
|
|
4
4
|
import picomatch from 'picomatch';
|
|
5
5
|
|
|
6
6
|
export type LinkValidationSeverity = 'warn' | 'error' | 'ignore';
|
|
@@ -42,30 +42,36 @@ const decodeUrlPart = (value: string): string => {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
// Elements whose contents browsers don't render as markup (<noscript> when scripts run)
|
|
46
|
+
const INERT_ELEMENTS = new Set(['template', 'noscript']);
|
|
47
|
+
|
|
45
48
|
// Parse HTML rather than searching markup with a regex: attributes can contain
|
|
46
49
|
// entities, quoted > characters, or single/unquoted values. Scripts and inert
|
|
47
50
|
// template contents must not be mistaken for rendered links or anchor targets.
|
|
51
|
+
// A streaming parser, not a document tree: pages can be large (island props),
|
|
52
|
+
// and building a tree of each one made link validation a large part of a build.
|
|
48
53
|
const readPage = (html: string, source: string): PageLinks => {
|
|
49
54
|
const page: PageLinks = { source, anchors: new Set(), links: new Set() };
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
let inert = 0;
|
|
56
|
+
const parser = new Parser({
|
|
57
|
+
onopentag(tagName, attrs) {
|
|
58
|
+
if (inert === 0) {
|
|
59
|
+
if (attrs.id) page.anchors.add(attrs.id);
|
|
60
|
+
if (tagName === 'a' && attrs.name) page.anchors.add(attrs.name);
|
|
61
|
+
const href = attrs.href;
|
|
62
|
+
if (href !== undefined) {
|
|
63
|
+
// Parsed in document order, so the first <base href> wins
|
|
64
|
+
if (tagName === 'base' && page.baseHref === undefined) page.baseHref = href;
|
|
65
|
+
if (tagName === 'a' || tagName === 'area') page.links.add(href);
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
}
|
|
68
|
+
if (INERT_ELEMENTS.has(tagName)) inert++;
|
|
69
|
+
},
|
|
70
|
+
onclosetag(tagName) {
|
|
71
|
+
if (INERT_ELEMENTS.has(tagName) && inert > 0) inert--;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
parser.end(html);
|
|
69
75
|
return page;
|
|
70
76
|
};
|
|
71
77
|
|
|
@@ -212,7 +212,9 @@ export const getNodesAndEdges = async ({ id, version, entities, type = 'domains'
|
|
|
212
212
|
height: 20,
|
|
213
213
|
},
|
|
214
214
|
});
|
|
215
|
-
} else {
|
|
215
|
+
} else if (!entityMap.has(referencedEntityId)) {
|
|
216
|
+
// Only a reference to an entity missing from the catalog is broken. An external entity's own
|
|
217
|
+
// references can point further away than this map shows: those edges are left out.
|
|
216
218
|
console.warn(`Referenced entity "${referencedEntityId}" not found for ${entity.data.name}.${referenceProperty.name}`);
|
|
217
219
|
}
|
|
218
220
|
}
|
|
@@ -267,7 +267,7 @@ export const buildDomainGraph = ({
|
|
|
267
267
|
draggable: false,
|
|
268
268
|
selectable: false,
|
|
269
269
|
data: {
|
|
270
|
-
domain: { name: d.data.name, version: d.data.version },
|
|
270
|
+
domain: { id: d.data.id, name: d.data.name, version: d.data.version },
|
|
271
271
|
// The domain viewed may itself be a subdomain of another
|
|
272
272
|
subdomain: !!parentId || parentDomainOf.has(d.data.id),
|
|
273
273
|
isFocused: !parentId,
|
|
@@ -309,7 +309,7 @@ export const buildDomainGraph = ({
|
|
|
309
309
|
position: { x: 0, y: 0 },
|
|
310
310
|
...(parentId ? { parentId } : {}),
|
|
311
311
|
data: {
|
|
312
|
-
domain: { name: other.data.name, version: other.data.version },
|
|
312
|
+
domain: { id: other.data.id, name: other.data.name, version: other.data.version },
|
|
313
313
|
subdomain: !!parentId,
|
|
314
314
|
isFocused: false,
|
|
315
315
|
otherDomain: true,
|
|
@@ -375,7 +375,7 @@ export const buildDomainGraph = ({
|
|
|
375
375
|
type: 'system-group',
|
|
376
376
|
parentId: domainGroup,
|
|
377
377
|
position: { x: 0, y: 0 },
|
|
378
|
-
data: { system: { name: system.data.name, version: system.data.version } },
|
|
378
|
+
data: { system: { id: system.data.id, name: system.data.name, version: system.data.version } },
|
|
379
379
|
});
|
|
380
380
|
}
|
|
381
381
|
addNodes(graph.nodes);
|
|
@@ -38,7 +38,6 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
|
|
|
38
38
|
'context-actor': ['((', '))'], // circle
|
|
39
39
|
flows: ['([', '])'], // stadium (rounded)
|
|
40
40
|
flow: ['([', '])'],
|
|
41
|
-
systems: ['[[', ']]'],
|
|
42
41
|
system: ['[[', ']]'],
|
|
43
42
|
step: ['[', ']'], // rectangle
|
|
44
43
|
user: ['((', '))'], // circle
|
|
@@ -79,7 +78,6 @@ const NODE_STYLE_CLASSES: Record<string, string> = {
|
|
|
79
78
|
domains: 'fill:#eab308,stroke:#a16207,color:#000',
|
|
80
79
|
domain: 'fill:#eab308,stroke:#a16207,color:#000',
|
|
81
80
|
'context-domain': 'fill:#eab308,stroke:#a16207,color:#000',
|
|
82
|
-
systems: 'fill:#7c3aed,stroke:#5b21b6,color:#fff',
|
|
83
81
|
'context-actor': 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
|
|
84
82
|
flows: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
|
|
85
83
|
flow: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Node, Edge } from '@xyflow/react';
|
|
2
2
|
import { createEdge, createNode, buildContextMenuForMessage, buildContextMenuForService } from './utils/utils';
|
|
3
|
-
import {
|
|
3
|
+
import { layoutWithElk } from '@eventcatalog/visualiser/layout';
|
|
4
4
|
|
|
5
5
|
export interface FieldOccurrence {
|
|
6
6
|
messageId: string;
|
|
@@ -173,5 +173,7 @@ export const getNodesAndEdges = async ({
|
|
|
173
173
|
|
|
174
174
|
if (!layout) return { nodes, edges };
|
|
175
175
|
|
|
176
|
-
|
|
176
|
+
// Lays out with ELK directly rather than layoutNodeGraph: this runs in the browser (the Fields Explorer),
|
|
177
|
+
// and layoutNodeGraph's cache reads the catalog's config, which would put the config in the browser's bundle
|
|
178
|
+
return (await layoutWithElk({ nodes, edges })) as unknown as { nodes: Node[]; edges: Edge[] };
|
|
177
179
|
};
|