@eventcatalog/core 4.12.3 → 5.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +226 -95
- package/NOTICE +30 -0
- package/README.md +3 -2
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +43 -16
- package/dist/analytics/log-build.d.cts +6 -5
- package/dist/analytics/log-build.d.ts +6 -5
- package/dist/analytics/log-build.js +4 -3
- package/dist/{chunk-U4YJSTGV.js → chunk-AYNZXUB5.js} +2 -10
- package/dist/{chunk-TV3YAWKQ.js → chunk-CR6AK5LR.js} +1 -1
- package/dist/{chunk-M577VUOX.js → chunk-LR7AGRHN.js} +13 -16
- package/dist/chunk-TQLRG35T.js +203 -0
- package/dist/{chunk-HPC6KUDQ.js → chunk-TWN43V4T.js} +1 -1
- package/dist/{chunk-ZYTCBNB3.js → chunk-WAIADKQE.js} +1 -1
- package/dist/{chunk-5BPN6QEC.js → chunk-ZHKEARLJ.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +407 -291
- package/dist/eventcatalog.config.d.cts +2 -3
- package/dist/eventcatalog.config.d.ts +2 -3
- package/dist/eventcatalog.js +35 -98
- package/dist/federation/content-cache.d.cts +0 -5
- package/dist/federation/content-cache.d.ts +0 -5
- package/dist/federation/diagnostics.d.cts +0 -5
- package/dist/federation/diagnostics.d.ts +0 -5
- package/dist/federation/federate.cjs +0 -9
- package/dist/federation/federate.d.cts +0 -5
- package/dist/federation/federate.d.ts +0 -5
- package/dist/federation/federate.js +4 -5
- package/dist/federation/filesystem-source-provider.d.cts +0 -5
- package/dist/federation/filesystem-source-provider.d.ts +0 -5
- package/dist/federation/github-source-provider.d.cts +0 -5
- package/dist/federation/github-source-provider.d.ts +0 -5
- package/dist/federation/output-transaction.d.cts +0 -4
- package/dist/federation/output-transaction.d.ts +0 -4
- package/dist/federation/public-assets.d.cts +0 -5
- package/dist/federation/public-assets.d.ts +0 -5
- package/dist/federation/source-provider.d.cts +0 -5
- package/dist/federation/source-provider.d.ts +0 -5
- package/dist/federation/types.d.cts +0 -5
- package/dist/federation/types.d.ts +0 -5
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/license-C1y-56bb.d.cts +23 -0
- package/dist/license-C1y-56bb.d.ts +23 -0
- package/dist/runtime-dependencies/@eventcatalog__visualiser__layout.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__react.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__ext-apps__server.mjs +3 -0
- package/dist/runtime-dependencies/@modelcontextprotocol__sdk__types.js.mjs +3 -0
- package/dist/runtime-dependencies/manifest.json +12 -1
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__graphql.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__json.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__markup.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__protobuf.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__languages__prism__yaml.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-dark.mjs +3 -0
- package/dist/runtime-dependencies/react-syntax-highlighter__dist__esm__styles__prism__one-light.mjs +3 -0
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/dist/utils/license-status.cjs +240 -0
- package/dist/utils/license-status.d.cts +28 -0
- package/dist/utils/license-status.d.ts +28 -0
- package/dist/utils/license-status.js +12 -0
- package/eventcatalog/astro.config.mjs +1 -1
- package/eventcatalog/integrations/eventcatalog-runtime.mjs +1 -1
- package/eventcatalog/src/components/ChatPanel/ChatPanel.tsx +29 -19
- package/eventcatalog/src/components/ChatPanel/OfflineReply.tsx +74 -0
- package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +24 -28
- package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +16 -11
- package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +4 -218
- package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +27 -36
- package/eventcatalog/src/components/Header.astro +43 -58
- package/eventcatalog/src/components/Lists/PillListFlat.styles.css +17 -17
- package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +1 -1
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +4 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +14 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +49 -18
- package/eventcatalog/src/components/MDX/RemoteFile.astro +2 -24
- package/eventcatalog/src/components/SchemaExplorer/ApiAccessSection.tsx +59 -93
- package/eventcatalog/src/components/SchemaExplorer/ApiContentViewer.tsx +1 -32
- package/eventcatalog/src/components/SchemaExplorer/DiffViewer.tsx +20 -67
- package/eventcatalog/src/components/SchemaExplorer/SchemaContentViewer.tsx +2 -11
- package/eventcatalog/src/components/SchemaExplorer/SchemaDetailsPanel.tsx +11 -60
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -3
- package/eventcatalog/src/components/SchemaExplorer/SchemaPageViewer.tsx +0 -3
- package/eventcatalog/src/components/SchemaExplorer/VersionHistoryModal.tsx +2 -9
- package/eventcatalog/src/components/SchemaExplorer/parse-schema.ts +46 -0
- package/eventcatalog/src/components/SchemaExplorer/utils.ts +11 -0
- package/eventcatalog/src/components/Settings/AssistantSettingsForm.tsx +2 -9
- package/eventcatalog/src/components/Settings/LicenseSettings.tsx +288 -0
- package/eventcatalog/src/components/Settings/LlmAccessSettingsForm.tsx +3 -19
- package/eventcatalog/src/components/Settings/McpSettingsForm.tsx +85 -30
- package/eventcatalog/src/components/Settings/SettingsShared.tsx +7 -75
- package/eventcatalog/src/components/SideNav/CustomDocsNav.astro +2 -2
- package/eventcatalog/src/components/TrialBadge.astro +82 -0
- package/eventcatalog/src/content.config.ts +9 -96
- package/eventcatalog/src/{enterprise → features}/ai/chat-api.ts +22 -34
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/ga4.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/gtm.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/adapters/posthog.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsHead.astro +2 -4
- package/eventcatalog/src/{enterprise → features}/analytics/components/AnalyticsTracker.astro +2 -4
- package/eventcatalog/src/{enterprise → features}/analytics/tracker.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/api/catalog.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/[...auth].ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware-auth.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/auth/middleware/middleware.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/custom-pages.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/index.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/collections/resource-docs.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/collection.ts +0 -5
- package/eventcatalog/src/features/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +9 -0
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/CustomDocsNavWrapper.tsx +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NestedItem.tsx +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/components/NoResultsFound.tsx +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/index.tsx +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/components/CustomDocsNav/types.ts +0 -5
- package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/index.astro → features/custom-documentation/components/CustomDocumentationPage.astro} +5 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/badge-styles.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/custom-docs.ts +1 -6
- package/eventcatalog/src/{enterprise → features}/custom-documentation/utils/docs-search.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/custom-pages/routes.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/directory/user-team-directory.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/field-extractor.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/field-indexer.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/fields-db.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/fields/pages/api/fields.ts +1 -6
- package/eventcatalog/src/{enterprise → features}/fields/pages/fields.astro +1 -2
- package/eventcatalog/src/{enterprise → features}/integrations/eventcatalog-features.ts +17 -75
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/links.ts +59 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/node-chat.tsx +299 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/shared.ts +14 -0
- package/eventcatalog/src/features/mcp/apps/architecture-diagram/view.tsx +454 -0
- package/eventcatalog/src/features/mcp/apps/generated/viewer.html +432 -0
- package/eventcatalog/src/features/mcp/apps/mermaid-stub.ts +10 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/schema-code.tsx +65 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/shared.ts +23 -0
- package/eventcatalog/src/features/mcp/apps/schema-viewer/view.tsx +170 -0
- package/eventcatalog/src/features/mcp/apps/shared/app-view.tsx +98 -0
- package/eventcatalog/src/features/mcp/apps/shared/resource-types.ts +15 -0
- package/eventcatalog/src/features/mcp/apps/viewer/shared.ts +24 -0
- package/eventcatalog/src/features/mcp/apps/viewer/styles.css +25 -0
- package/eventcatalog/src/features/mcp/apps/viewer/view.tsx +59 -0
- package/eventcatalog/src/features/mcp/mcp-app-icons.ts +63 -0
- package/eventcatalog/src/features/mcp/mcp-apps.ts +160 -0
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-auth.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-scope.ts +7 -7
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-scoped-tools.ts +47 -40
- package/eventcatalog/src/{enterprise → features}/mcp/mcp-server.ts +347 -34
- package/eventcatalog/src/{enterprise → features}/mcp/oauth-protected-resource.ts +0 -5
- package/eventcatalog/src/features/mcp/schema-viewer.ts +24 -0
- package/eventcatalog/src/{enterprise → features}/tools/catalog-tools.ts +133 -102
- package/eventcatalog/src/features/tools/index.ts +5 -0
- package/eventcatalog/src/{enterprise → features}/visualizer-layout/reset.ts +0 -5
- package/eventcatalog/src/{enterprise → features}/visualizer-layout/save.ts +0 -5
- package/eventcatalog/src/layouts/BaseLayout.astro +2 -2
- package/eventcatalog/src/layouts/Footer.astro +31 -39
- package/eventcatalog/src/layouts/SettingsLayout.astro +6 -6
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +7 -37
- package/eventcatalog/src/{enterprise → pages}/api/schemas/[collection]/[id]/[version]/index.ts +0 -22
- package/eventcatalog/src/{enterprise → pages}/api/schemas/services/[id]/[version]/[specification]/index.ts +0 -19
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/_index.data.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/_index.data.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +1 -5
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].md.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId].mdx.ts +2 -6
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +9 -5
- package/eventcatalog/src/pages/docs/custom/[...path]/index.astro +12 -0
- package/eventcatalog/src/{enterprise/custom-documentation/pages/docs/custom/root-index.astro → pages/docs/custom/index.astro} +1 -23
- package/eventcatalog/src/pages/docs/llm/llms-full.txt.ts +4 -9
- package/eventcatalog/src/pages/docs/llm/llms.txt.ts +4 -4
- package/eventcatalog/src/pages/docs/llm/schemas.txt.ts +0 -11
- package/eventcatalog/src/pages/docs/services/[id]/[docType]/[docId]/index.astro +2 -2
- package/eventcatalog/src/pages/index.astro +2 -2
- package/eventcatalog/src/pages/schemas/[type]/[id]/[version]/index.astro +0 -3
- package/eventcatalog/src/pages/schemas/explorer/index.astro +1 -4
- package/eventcatalog/src/pages/settings/assistant.astro +2 -4
- package/eventcatalog/src/pages/settings/license.astro +18 -0
- package/eventcatalog/src/pages/settings/llm-access.astro +1 -4
- package/eventcatalog/src/pages/settings/mcp.astro +33 -4
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -2
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/data/index.astro +2 -45
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/entity-map/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +7 -109
- package/eventcatalog/src/pages/visualiser/_mermaid-route.ts +78 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/_index.data.ts +44 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/entity-map/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/index.astro +56 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +3 -40
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version].mermaid.ts +20 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/_index.data.ts +29 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +3 -38
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/index.astro +56 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version].mermaid.ts +20 -0
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/container.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/data-product.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/domain.ts +7 -32
- package/eventcatalog/src/stores/sidebar-store/builders/entity.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +2 -8
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +2 -12
- package/eventcatalog/src/stores/sidebar-store/custom-sidebar.ts +0 -10
- package/eventcatalog/src/stores/sidebar-store/state.ts +4 -6
- package/eventcatalog/src/styles/theme.css +22 -18
- package/eventcatalog/src/styles/themes/forest.css +8 -8
- package/eventcatalog/src/styles/themes/ocean.css +8 -8
- package/eventcatalog/src/styles/themes/sapphire.css +8 -8
- package/eventcatalog/src/styles/themes/sunset.css +8 -8
- package/eventcatalog/src/utils/clipboard.ts +4 -4
- package/eventcatalog/src/utils/collections/flow-step-schema.ts +117 -0
- package/eventcatalog/src/utils/collections/pointer-schema.ts +7 -0
- package/eventcatalog/src/utils/collections/resource-docs.ts +677 -14
- package/eventcatalog/src/utils/collections/schema-loader.ts +0 -5
- package/eventcatalog/src/utils/feature.ts +14 -23
- package/eventcatalog/src/utils/license.ts +114 -0
- package/eventcatalog/src/utils/node-graphs/architecture-diagram-types.ts +32 -0
- package/eventcatalog/src/utils/node-graphs/architecture-diagram.ts +84 -0
- package/eventcatalog/src/utils/node-graphs/channel-node-graph.ts +4 -25
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -39
- package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +11 -27
- package/eventcatalog/src/utils/node-graphs/domain-levels-node-graph.ts +679 -0
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +3 -20
- package/eventcatalog/src/utils/node-graphs/export-mermaid.ts +51 -4
- package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +8 -23
- package/eventcatalog/src/utils/node-graphs/flow-lanes.ts +119 -0
- package/eventcatalog/src/utils/node-graphs/flows-node-graph.ts +133 -47
- package/eventcatalog/src/utils/node-graphs/layout-node-graph.ts +28 -0
- package/eventcatalog/src/utils/node-graphs/layout-persistence.ts +3 -3
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +16 -34
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +11 -25
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +18 -54
- package/eventcatalog/src/utils/node-graphs/system-levels-node-graph.ts +59 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +20 -80
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +1 -78
- package/eventcatalog/src/utils/trial.ts +36 -0
- package/eventcatalog/tsconfig.json +1 -1
- package/package.json +11 -11
- package/dist/chunk-FV56YFM4.js +0 -7
- package/dist/federation/entitlement.cjs +0 -31
- package/dist/federation/entitlement.d.cts +0 -12
- package/dist/federation/entitlement.d.ts +0 -12
- package/dist/federation/entitlement.js +0 -6
- package/dist/runtime-dependencies/dagre.mjs +0 -3
- package/eventcatalog/src/components/Settings/BillingSettingsForm.tsx +0 -265
- package/eventcatalog/src/enterprise/LICENSE +0 -57
- package/eventcatalog/src/enterprise/README.md +0 -5
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +0 -691
- package/eventcatalog/src/enterprise/custom-documentation/components/CustomDocsNav/CustomDocsNav.astro +0 -9
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/[...path]/index.astro +0 -18
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/feature.astro +0 -171
- package/eventcatalog/src/enterprise/feature.ts +0 -75
- package/eventcatalog/src/enterprise/tools/index.ts +0 -10
- package/eventcatalog/src/hooks/eventcatalog-visualizer.ts +0 -126
- package/eventcatalog/src/pages/settings/billing.astro +0 -17
- package/eventcatalog/src/pages/visualiser/domain-integrations/index.astro +0 -26
- package/eventcatalog/src/types/mcp-modules.d.ts +0 -67
- package/eventcatalog/src/utils/node-graphs/domains-canvas.ts +0 -261
- package/eventcatalog/src/utils/node-graphs/export-node-graph.ts +0 -91
- /package/eventcatalog/src/{enterprise → features}/auth/error.astro +0 -0
- /package/eventcatalog/src/{enterprise → features}/auth/login.astro +0 -0
- /package/eventcatalog/src/{enterprise → features}/auth/unauthorized.astro +0 -0
- /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path]/_index.data.ts +0 -0
- /package/eventcatalog/src/{enterprise/custom-documentation/pages → pages}/docs/custom/[...path].mdx.ts +0 -0
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { getCollection } from 'astro:content';
|
|
2
2
|
import {
|
|
3
|
-
createDagreGraph,
|
|
4
|
-
calculatedNodes,
|
|
5
3
|
generateIdForNode,
|
|
6
4
|
getEdgeLabelForServiceAsTarget,
|
|
7
5
|
generatedIdForEdge,
|
|
8
6
|
createEdge,
|
|
9
|
-
layoutDagreGraph,
|
|
10
7
|
} from '@utils/node-graphs/utils/utils';
|
|
8
|
+
import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
|
|
11
9
|
import { getNodesAndEdges as getServicesNodeAndEdges } from './services-node-graph';
|
|
12
10
|
import { getNodesAndEdges as getAgentsNodeAndEdges } from './agents-node-graph';
|
|
13
11
|
import { getNodesAndEdges as getDataProductsNodeAndEdges } from './data-products-node-graph';
|
|
@@ -16,12 +14,9 @@ import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
|
16
14
|
import { getProducersOfMessage } from '@utils/collections/services';
|
|
17
15
|
import { getProducersOfMessage as getAgentProducersOfMessage } from '@utils/collections/agents';
|
|
18
16
|
|
|
19
|
-
type DagreGraph = any;
|
|
20
|
-
|
|
21
17
|
interface NodesAndEdgesProps {
|
|
22
18
|
id: string;
|
|
23
19
|
version: string;
|
|
24
|
-
defaultFlow?: DagreGraph;
|
|
25
20
|
mode: 'simple' | 'full';
|
|
26
21
|
group?: boolean;
|
|
27
22
|
channelRenderMode?: 'single' | 'flat';
|
|
@@ -31,13 +26,11 @@ interface NodesAndEdgesProps {
|
|
|
31
26
|
export const getNodesAndEdges = async ({
|
|
32
27
|
id,
|
|
33
28
|
version,
|
|
34
|
-
defaultFlow,
|
|
35
29
|
mode = 'simple',
|
|
36
30
|
group = false,
|
|
37
31
|
channelRenderMode = 'flat',
|
|
38
32
|
layout = true,
|
|
39
33
|
}: NodesAndEdgesProps) => {
|
|
40
|
-
const flow = defaultFlow || createDagreGraph({ ranksep: 360, nodesep: 50, edgesep: 50 });
|
|
41
34
|
let nodes = new Map(),
|
|
42
35
|
edges = new Map();
|
|
43
36
|
|
|
@@ -97,7 +90,6 @@ export const getNodesAndEdges = async ({
|
|
|
97
90
|
const { nodes: serviceNodes, edges: serviceEdges } = await getServicesNodeAndEdges({
|
|
98
91
|
id: service.id,
|
|
99
92
|
version: service.version,
|
|
100
|
-
defaultFlow: flow,
|
|
101
93
|
mode,
|
|
102
94
|
renderAllEdges: true,
|
|
103
95
|
channelRenderMode,
|
|
@@ -122,7 +114,6 @@ export const getNodesAndEdges = async ({
|
|
|
122
114
|
const { nodes: agentNodes, edges: agentEdges } = await getAgentsNodeAndEdges({
|
|
123
115
|
id: agent.id,
|
|
124
116
|
version: agent.version,
|
|
125
|
-
defaultFlow: flow,
|
|
126
117
|
mode,
|
|
127
118
|
renderAllEdges: true,
|
|
128
119
|
channelRenderMode,
|
|
@@ -139,7 +130,6 @@ export const getNodesAndEdges = async ({
|
|
|
139
130
|
const { nodes: dataProductNodes, edges: dataProductEdges } = await getDataProductsNodeAndEdges({
|
|
140
131
|
id: dataProduct.id,
|
|
141
132
|
version: dataProduct.version,
|
|
142
|
-
defaultFlow: flow,
|
|
143
133
|
mode,
|
|
144
134
|
layout: false,
|
|
145
135
|
});
|
|
@@ -154,7 +144,6 @@ export const getNodesAndEdges = async ({
|
|
|
154
144
|
const { nodes: subDomainNodes, edges: subDomainEdges } = await getNodesAndEdges({
|
|
155
145
|
id: subDomain.id,
|
|
156
146
|
version: subDomain.version,
|
|
157
|
-
defaultFlow: flow,
|
|
158
147
|
mode,
|
|
159
148
|
group: true,
|
|
160
149
|
channelRenderMode,
|
|
@@ -175,12 +164,6 @@ export const getNodesAndEdges = async ({
|
|
|
175
164
|
});
|
|
176
165
|
}
|
|
177
166
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return {
|
|
183
|
-
nodes: calculatedNodes(flow, Array.from(nodes.values())),
|
|
184
|
-
edges: [...edges.values()],
|
|
185
|
-
};
|
|
167
|
+
const graph = { nodes: [...nodes.values()], edges: [...edges.values()] };
|
|
168
|
+
return layout ? layoutNodeGraph(graph) : graph;
|
|
186
169
|
};
|
|
@@ -33,6 +33,9 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
|
|
|
33
33
|
channel: ['[(', ')]'],
|
|
34
34
|
domains: ['[', ']'], // rectangle
|
|
35
35
|
domain: ['[', ']'],
|
|
36
|
+
'context-domain': ['[', ']'], // another domain, shown as a single card
|
|
37
|
+
systems: ['[[', ']]'], // a system shown as a single node
|
|
38
|
+
'context-actor': ['((', '))'], // circle
|
|
36
39
|
flows: ['([', '])'], // stadium (rounded)
|
|
37
40
|
flow: ['([', '])'],
|
|
38
41
|
systems: ['[[', ']]'],
|
|
@@ -52,6 +55,9 @@ const NODE_SHAPE_MAP: Record<string, [string, string]> = {
|
|
|
52
55
|
note: ['[', ']'], // rectangle
|
|
53
56
|
};
|
|
54
57
|
|
|
58
|
+
/** Node types that are boundaries around other nodes, rendered as subgraphs */
|
|
59
|
+
const GROUP_NODE_TYPES = new Set(['system-group', 'domain-group']);
|
|
60
|
+
|
|
55
61
|
/**
|
|
56
62
|
* Mermaid class definitions for styling different node types
|
|
57
63
|
*/
|
|
@@ -72,6 +78,9 @@ const NODE_STYLE_CLASSES: Record<string, string> = {
|
|
|
72
78
|
channel: 'fill:#6b7280,stroke:#374151,color:#fff',
|
|
73
79
|
domains: 'fill:#eab308,stroke:#a16207,color:#000',
|
|
74
80
|
domain: 'fill:#eab308,stroke:#a16207,color:#000',
|
|
81
|
+
'context-domain': 'fill:#eab308,stroke:#a16207,color:#000',
|
|
82
|
+
systems: 'fill:#7c3aed,stroke:#5b21b6,color:#fff',
|
|
83
|
+
'context-actor': 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
|
|
75
84
|
flows: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
|
|
76
85
|
flow: 'fill:#14b8a6,stroke:#0f766e,color:#fff',
|
|
77
86
|
systems: 'fill:#8b5cf6,stroke:#6d28d9,color:#fff',
|
|
@@ -176,6 +185,16 @@ export function getNodeLabel(node: Node): string {
|
|
|
176
185
|
return formatLabelWithVersion(name, version);
|
|
177
186
|
}
|
|
178
187
|
|
|
188
|
+
if (type === 'systems' || type === 'system-group') {
|
|
189
|
+
const system = (data as any).system;
|
|
190
|
+
return formatLabelWithVersion(system?.name || system?.id || node.id, system?.version);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (type === 'context-domain' || type === 'domain-group') {
|
|
194
|
+
const domain = (data as any).domain;
|
|
195
|
+
return formatLabelWithVersion(domain?.name || domain?.id || node.id, domain?.version);
|
|
196
|
+
}
|
|
197
|
+
|
|
179
198
|
if (type === 'domains' || type === 'domain') {
|
|
180
199
|
const domain = (data as any).domain;
|
|
181
200
|
// Domain data can be nested in .data
|
|
@@ -230,6 +249,11 @@ export function getNodeLabel(node: Node): string {
|
|
|
230
249
|
return entity?.name || entity?.id || node.id;
|
|
231
250
|
}
|
|
232
251
|
|
|
252
|
+
if (type === 'custom') {
|
|
253
|
+
const custom = (data as any).custom ?? {};
|
|
254
|
+
return custom.title || (data as any).step?.title || node.id;
|
|
255
|
+
}
|
|
256
|
+
|
|
233
257
|
if (type === 'note') {
|
|
234
258
|
return (data as any).text || (data as any).label || 'Note';
|
|
235
259
|
}
|
|
@@ -286,16 +310,37 @@ export function convertToMermaid(nodes: Node[], edges: Edge[], options: MermaidE
|
|
|
286
310
|
});
|
|
287
311
|
}
|
|
288
312
|
|
|
289
|
-
// Add node definitions
|
|
313
|
+
// Add node definitions. Nodes inside a group (a system or domain boundary)
|
|
314
|
+
// are nested in a subgraph for that group, so containment is kept
|
|
290
315
|
lines.push('');
|
|
291
316
|
lines.push(' %% Nodes');
|
|
292
317
|
|
|
318
|
+
const nodeIds = new Set(nodes.map((node) => node.id));
|
|
319
|
+
const childrenOf = new Map<string, Node[]>();
|
|
320
|
+
const topLevelNodes: Node[] = [];
|
|
293
321
|
nodes.forEach((node) => {
|
|
322
|
+
if (node.parentId && nodeIds.has(node.parentId)) {
|
|
323
|
+
childrenOf.set(node.parentId, [...(childrenOf.get(node.parentId) ?? []), node]);
|
|
324
|
+
} else {
|
|
325
|
+
topLevelNodes.push(node);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const addNode = (node: Node, depth: number) => {
|
|
330
|
+
const indent = ' '.repeat(depth);
|
|
294
331
|
const sanitizedId = sanitizeMermaidId(node.id);
|
|
295
332
|
const label = escapeMermaidLabel(getNodeLabel(node));
|
|
296
|
-
const
|
|
333
|
+
const children = childrenOf.get(node.id);
|
|
297
334
|
|
|
298
|
-
|
|
335
|
+
if (children || GROUP_NODE_TYPES.has(node.type ?? '')) {
|
|
336
|
+
lines.push(`${indent}subgraph ${sanitizedId}["${label}"]`);
|
|
337
|
+
children?.forEach((child) => addNode(child, depth + 1));
|
|
338
|
+
lines.push(`${indent}end`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const [prefix, suffix] = getMermaidNodeShape(node.type || 'custom');
|
|
343
|
+
let nodeLine = `${indent}${sanitizedId}${prefix}"${label}"${suffix}`;
|
|
299
344
|
|
|
300
345
|
// Add class reference if styles are enabled
|
|
301
346
|
if (includeStyles && node.type && usedTypes.has(node.type)) {
|
|
@@ -303,7 +348,9 @@ export function convertToMermaid(nodes: Node[], edges: Edge[], options: MermaidE
|
|
|
303
348
|
}
|
|
304
349
|
|
|
305
350
|
lines.push(nodeLine);
|
|
306
|
-
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
topLevelNodes.forEach((node) => addNode(node, 1));
|
|
307
354
|
|
|
308
355
|
// Add edge definitions
|
|
309
356
|
lines.push('');
|
|
@@ -1,15 +1,6 @@
|
|
|
1
1
|
import type { Node, Edge } from '@xyflow/react';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
createDagreGraph,
|
|
5
|
-
calculatedNodes,
|
|
6
|
-
createEdge,
|
|
7
|
-
createNode,
|
|
8
|
-
buildContextMenuForMessage,
|
|
9
|
-
buildContextMenuForService,
|
|
10
|
-
DEFAULT_NODE_WIDTH,
|
|
11
|
-
DEFAULT_NODE_HEIGHT,
|
|
12
|
-
} from './utils/utils';
|
|
2
|
+
import { createEdge, createNode, buildContextMenuForMessage, buildContextMenuForService } from './utils/utils';
|
|
3
|
+
import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
|
|
13
4
|
|
|
14
5
|
export interface FieldOccurrence {
|
|
15
6
|
messageId: string;
|
|
@@ -28,15 +19,16 @@ interface Props {
|
|
|
28
19
|
fieldType: string;
|
|
29
20
|
occurrences: FieldOccurrence[];
|
|
30
21
|
mode?: 'simple' | 'full';
|
|
22
|
+
layout?: boolean;
|
|
31
23
|
}
|
|
32
24
|
|
|
33
|
-
export const getNodesAndEdges = ({
|
|
25
|
+
export const getNodesAndEdges = async ({
|
|
34
26
|
fieldPath,
|
|
35
27
|
fieldType,
|
|
36
28
|
occurrences,
|
|
37
29
|
mode = 'full',
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
layout = true,
|
|
31
|
+
}: Props): Promise<{ nodes: Node[]; edges: Edge[] }> => {
|
|
40
32
|
const nodes: Node[] = [];
|
|
41
33
|
const edges: Edge[] = [];
|
|
42
34
|
const addedNodes = new Set<string>();
|
|
@@ -179,14 +171,7 @@ export const getNodesAndEdges = ({
|
|
|
179
171
|
}
|
|
180
172
|
}
|
|
181
173
|
|
|
182
|
-
|
|
183
|
-
for (const node of nodes) {
|
|
184
|
-
flow.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
|
|
185
|
-
}
|
|
186
|
-
for (const edge of edges) {
|
|
187
|
-
flow.setEdge(edge.source, edge.target);
|
|
188
|
-
}
|
|
189
|
-
dagre.layout(flow);
|
|
174
|
+
if (!layout) return { nodes, edges };
|
|
190
175
|
|
|
191
|
-
return { nodes
|
|
176
|
+
return layoutNodeGraph({ nodes, edges });
|
|
192
177
|
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { CollectionEntry } from 'astro:content';
|
|
2
|
+
|
|
3
|
+
export type Lane = { id: string; name: string };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The lanes a flow step's resource belongs to, for grouping a flow into
|
|
7
|
+
* swimlanes by domain, system or owning team. Only set for resources that
|
|
8
|
+
* belong somewhere themselves (services, agents, data stores, data products,
|
|
9
|
+
* systems);
|
|
10
|
+
* the visualiser puts other steps (messages, custom steps, sub-flows) in the
|
|
11
|
+
* lane of the step that leads to them. `external` steps (actors and external
|
|
12
|
+
* systems) get a lane of their own.
|
|
13
|
+
*/
|
|
14
|
+
export type StepLanes = {
|
|
15
|
+
domain?: Lane;
|
|
16
|
+
system?: Lane;
|
|
17
|
+
team?: Lane;
|
|
18
|
+
external?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type LaneCollections = {
|
|
22
|
+
domains: CollectionEntry<'domains'>[];
|
|
23
|
+
systems: CollectionEntry<'systems'>[];
|
|
24
|
+
teams: CollectionEntry<'teams'>[];
|
|
25
|
+
users: CollectionEntry<'users'>[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** A resource a step points at (a service, agent, data store, data product or system) */
|
|
29
|
+
type Resource = { data: { id: string; name?: string; owners?: (string | { id: string })[] } };
|
|
30
|
+
|
|
31
|
+
// Lanes use the latest version of each domain and system (as the collection
|
|
32
|
+
// utils do when they don't ask for every version)
|
|
33
|
+
const isLatest = (entry: { filePath?: string }) => !entry.filePath?.includes('versioned');
|
|
34
|
+
const toLane = (entry: Resource): Lane => ({ id: entry.data.id, name: entry.data.name || entry.data.id });
|
|
35
|
+
const pointerIds = (pointers?: { id: string }[]) => (pointers || []).map((pointer) => pointer.id);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Indexes which domain, system and team each resource belongs to (by id).
|
|
39
|
+
* A resource listed by a domain directly belongs to that domain, otherwise to
|
|
40
|
+
* the domain of the system it's in. Built once per flow from the collections,
|
|
41
|
+
* rather than asking `getDomainsForService`, `getOwner` and so on for each step,
|
|
42
|
+
* so it follows their rules: latest versions only, and hidden teams and users
|
|
43
|
+
* are left out.
|
|
44
|
+
*/
|
|
45
|
+
export const createLaneIndex = ({ domains, systems, teams, users }: LaneCollections) => {
|
|
46
|
+
const systemOf = new Map<string, Lane>();
|
|
47
|
+
const domainOf = new Map<string, Lane>();
|
|
48
|
+
|
|
49
|
+
const latestSystems = systems.filter(isLatest);
|
|
50
|
+
for (const system of latestSystems) {
|
|
51
|
+
for (const id of [...pointerIds(system.data.services), ...pointerIds(system.data.containers)]) {
|
|
52
|
+
if (!systemOf.has(id)) systemOf.set(id, toLane(system));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const latestDomains = domains.filter(isLatest);
|
|
57
|
+
// Resources a domain lists directly win over ones it gets through its systems
|
|
58
|
+
for (const domain of latestDomains) {
|
|
59
|
+
const direct = [
|
|
60
|
+
...pointerIds(domain.data.services),
|
|
61
|
+
...pointerIds(domain.data.agents),
|
|
62
|
+
...pointerIds(domain.data['data-products']),
|
|
63
|
+
...pointerIds(domain.data.systems),
|
|
64
|
+
];
|
|
65
|
+
for (const id of direct) {
|
|
66
|
+
if (!domainOf.has(id)) domainOf.set(id, toLane(domain));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
for (const system of latestSystems) {
|
|
70
|
+
const domain = domainOf.get(system.data.id);
|
|
71
|
+
if (!domain) continue;
|
|
72
|
+
for (const id of [...pointerIds(system.data.services), ...pointerIds(system.data.containers)]) {
|
|
73
|
+
if (!domainOf.has(id)) domainOf.set(id, domain);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const owners = new Map<string, { lane: Lane; isTeam: boolean }>();
|
|
78
|
+
const hiddenOwners = new Set<string>();
|
|
79
|
+
for (const [entries, isTeam] of [
|
|
80
|
+
[users, false],
|
|
81
|
+
[teams, true],
|
|
82
|
+
] as const) {
|
|
83
|
+
for (const owner of entries) {
|
|
84
|
+
if (owner.data.hidden) hiddenOwners.add(owner.data.id);
|
|
85
|
+
else owners.set(owner.data.id, { lane: toLane(owner), isTeam });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// A team owner wins over a user owner
|
|
90
|
+
const teamOf = (resource: Resource): Lane | undefined => {
|
|
91
|
+
const resolved = (resource.data.owners || [])
|
|
92
|
+
.map((owner) => (typeof owner === 'string' ? owner : owner.id))
|
|
93
|
+
.filter((id) => !hiddenOwners.has(id))
|
|
94
|
+
.map((id) => owners.get(id) ?? { lane: { id, name: id }, isTeam: false })
|
|
95
|
+
.sort((a, b) => Number(b.isTeam) - Number(a.isTeam));
|
|
96
|
+
return resolved[0]?.lane;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const lanesFor = (resource: Resource): StepLanes | undefined => {
|
|
100
|
+
const id = resource.data.id;
|
|
101
|
+
const team = teamOf(resource);
|
|
102
|
+
const lanes: StepLanes = {
|
|
103
|
+
...(domainOf.has(id) && { domain: domainOf.get(id) }),
|
|
104
|
+
...(systemOf.has(id) && { system: systemOf.get(id) }),
|
|
105
|
+
...(team && { team }),
|
|
106
|
+
};
|
|
107
|
+
return Object.keys(lanes).length > 0 ? lanes : undefined;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/** A system is in its own system lane (and the domain that lists it) */
|
|
111
|
+
const lanesForSystem = (system: Resource): StepLanes => ({
|
|
112
|
+
...lanesFor(system),
|
|
113
|
+
system: toLane(system),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
return { lanesFor, lanesForSystem };
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export type LaneIndex = ReturnType<typeof createLaneIndex>;
|
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
2
|
import {
|
|
3
|
-
createDagreGraph,
|
|
4
|
-
calculatedNodes,
|
|
5
|
-
DEFAULT_NODE_WIDTH,
|
|
6
|
-
DEFAULT_NODE_HEIGHT,
|
|
7
3
|
buildContextMenuForResource,
|
|
8
4
|
buildContextMenuForService,
|
|
9
5
|
buildContextMenuForSystem,
|
|
10
|
-
layoutDagreGraph,
|
|
11
6
|
} from '@utils/node-graphs/utils/utils';
|
|
7
|
+
import { layoutNodeGraph } from '@utils/node-graphs/layout-node-graph';
|
|
12
8
|
import { MarkerType } from '@xyflow/react';
|
|
13
9
|
import type { Node as NodeType } from '@xyflow/react';
|
|
14
10
|
import { createVersionedMap, findInMap } from '@utils/collections/util';
|
|
15
|
-
|
|
16
|
-
type DagreGraph = any;
|
|
11
|
+
import { createLaneIndex, type LaneIndex } from '@utils/node-graphs/flow-lanes';
|
|
17
12
|
|
|
18
13
|
interface Props {
|
|
19
14
|
id: string;
|
|
20
15
|
version: string;
|
|
21
|
-
defaultFlow?: DagreGraph;
|
|
22
16
|
mode?: 'simple' | 'full';
|
|
23
|
-
|
|
17
|
+
layout?: boolean;
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
interface Maps {
|
|
@@ -31,6 +25,8 @@ interface Maps {
|
|
|
31
25
|
containerMap: Map<string, any[]>;
|
|
32
26
|
dataProductMap: Map<string, any[]>;
|
|
33
27
|
systemMap: Map<string, any[]>;
|
|
28
|
+
channelMap: Map<string, any[]>;
|
|
29
|
+
laneIndex: LaneIndex;
|
|
34
30
|
}
|
|
35
31
|
|
|
36
32
|
const getServiceNode = (step: any, serviceMap: Map<string, any[]>) => {
|
|
@@ -90,6 +86,15 @@ const getSystemNode = (step: any, systemMap: Map<string, any[]>) => {
|
|
|
90
86
|
};
|
|
91
87
|
};
|
|
92
88
|
|
|
89
|
+
const getChannelNode = (step: any, channelMap: Map<string, any[]>) => {
|
|
90
|
+
const channel = findInMap(channelMap, step.channel.id, step.channel.version);
|
|
91
|
+
return {
|
|
92
|
+
...step,
|
|
93
|
+
type: channel ? 'channels' : 'step',
|
|
94
|
+
channel,
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
|
|
93
98
|
const getMessageNode = (step: any, messageMap: Map<string, any[]>) => {
|
|
94
99
|
const message = findInMap(messageMap, step.message.id, step.message.version);
|
|
95
100
|
return {
|
|
@@ -99,6 +104,68 @@ const getMessageNode = (step: any, messageMap: Map<string, any[]>) => {
|
|
|
99
104
|
};
|
|
100
105
|
};
|
|
101
106
|
|
|
107
|
+
// The whole graph is sent to the browser, so a step's resource is in its node's
|
|
108
|
+
// data once (e.g. `data.service`), without what's only needed to build the
|
|
109
|
+
// catalog (its markdown body, file path, ...), and the step is just the step
|
|
110
|
+
const RESOURCE_KEYS = ['message', 'agent', 'service', 'flow', 'container', 'dataProduct', 'system', 'channel'];
|
|
111
|
+
const resourceForNode = (entry: any) => {
|
|
112
|
+
// Only what the nodes read: its id, collection and frontmatter (nested, as
|
|
113
|
+
// e.g. the sub-flow node reads `flow.data`, and spread on top)
|
|
114
|
+
const { id, collection, data } = entry;
|
|
115
|
+
return { id, collection, data, ...data };
|
|
116
|
+
};
|
|
117
|
+
const stepForNode = (step: any) => {
|
|
118
|
+
const own = { ...step, ...step.data };
|
|
119
|
+
RESOURCE_KEYS.forEach((key) => delete own[key]);
|
|
120
|
+
return { ...own, title: titleOf(step) };
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// A step without a title is named after what it points at (or its id). A
|
|
124
|
+
// custom step is labelled with its own title first, as its node is.
|
|
125
|
+
const titleOf = (step: any): string => {
|
|
126
|
+
if (step.custom?.title) return step.custom.title;
|
|
127
|
+
if (step.title) return step.title;
|
|
128
|
+
const resource = RESOURCE_KEYS.map((key) => step[key]).find((entry) => entry?.data);
|
|
129
|
+
return resource?.data.name || resource?.data.id || step.actor?.name || step.externalSystem?.name || String(step.id);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// Mistakes in a flow (a typo in a next step, a resource that was renamed)
|
|
133
|
+
// would otherwise just drop an arrow or draw a plain box, so they're logged,
|
|
134
|
+
// once each (a flow is drawn on several pages). Once per process on purpose:
|
|
135
|
+
// in `astro dev` a problem that's fixed and then made again isn't logged again
|
|
136
|
+
// until the server restarts, which is fine for a warning.
|
|
137
|
+
const warned = new Set<string>();
|
|
138
|
+
const warnOnce = (flow: any, problem: string) => {
|
|
139
|
+
const message = `[flows] Flow "${flow.data.id}" (${flow.data.version}): ${problem}`;
|
|
140
|
+
if (warned.has(message)) return;
|
|
141
|
+
warned.add(message);
|
|
142
|
+
console.warn(message);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// The keys a step points at a resource with, as authors write them
|
|
146
|
+
const POINTER_KEYS: Record<string, string> = {
|
|
147
|
+
message: 'message',
|
|
148
|
+
agent: 'agent',
|
|
149
|
+
service: 'service',
|
|
150
|
+
systems: 'system',
|
|
151
|
+
system: 'system',
|
|
152
|
+
channel: 'channel',
|
|
153
|
+
flow: 'flow',
|
|
154
|
+
container: 'container',
|
|
155
|
+
dataProduct: 'data product',
|
|
156
|
+
};
|
|
157
|
+
const warnAboutMissingResource = (flow: any, step: any, hydrated: any) => {
|
|
158
|
+
for (const [key, kind] of Object.entries(POINTER_KEYS)) {
|
|
159
|
+
const pointer = step[key];
|
|
160
|
+
const resourceKey = key === 'systems' ? 'system' : key;
|
|
161
|
+
if (!pointer || hydrated[resourceKey]) continue;
|
|
162
|
+
warnOnce(
|
|
163
|
+
flow,
|
|
164
|
+
`step "${step.id}" points at ${kind} "${pointer.id}" (${pointer.version ?? 'latest'}), which is not in the catalog, so it is shown as a plain step.`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
102
169
|
// Rewrite every id/source/target in a precomputed sub-flow graph with a
|
|
103
170
|
// namespace prefix so inlined copies don't collide with the parent. Nested
|
|
104
171
|
// `data.expandedNodes` / `data.expandedEdges` payloads are rewritten too so
|
|
@@ -145,6 +212,7 @@ const buildFlowGraphInternal = (
|
|
|
145
212
|
if (step.flow) return getFlowNode(step, maps.flowMap);
|
|
146
213
|
if (step.container) return getContainerNode(step, maps.containerMap);
|
|
147
214
|
if (step.dataProduct) return getDataProductNode(step, maps.dataProductMap);
|
|
215
|
+
if (step.channel) return getChannelNode(step, maps.channelMap);
|
|
148
216
|
if (step.message) return getMessageNode(step, maps.messageMap);
|
|
149
217
|
if (step.actor) return { ...step, type: 'actor', actor: step.actor };
|
|
150
218
|
if (step.custom) return { ...step, type: 'custom', custom: step.custom };
|
|
@@ -152,23 +220,26 @@ const buildFlowGraphInternal = (
|
|
|
152
220
|
return { ...step, type: 'step' };
|
|
153
221
|
});
|
|
154
222
|
|
|
155
|
-
|
|
223
|
+
steps.forEach((step: any, index: number) => warnAboutMissingResource(flow, step, hydratedSteps[index]));
|
|
224
|
+
const stepIds = new Set(steps.map((step: any) => String(step.id)));
|
|
225
|
+
|
|
226
|
+
hydratedSteps.forEach((step: any) => {
|
|
156
227
|
const node: NodeType = {
|
|
157
228
|
id: stepNodeId(step.id),
|
|
158
229
|
sourcePosition: 'right',
|
|
159
230
|
targetPosition: 'left',
|
|
160
231
|
data: {
|
|
161
232
|
mode,
|
|
162
|
-
step:
|
|
233
|
+
step: stepForNode(step),
|
|
163
234
|
showTarget: true,
|
|
164
235
|
showSource: true,
|
|
165
236
|
},
|
|
166
|
-
position: { x:
|
|
237
|
+
position: { x: 0, y: 0 },
|
|
167
238
|
type: step.type,
|
|
168
239
|
} as NodeType;
|
|
169
240
|
|
|
170
241
|
if (step.agent) {
|
|
171
|
-
node.data.agent =
|
|
242
|
+
node.data.agent = resourceForNode(step.agent);
|
|
172
243
|
node.data.contextMenu = buildContextMenuForResource({
|
|
173
244
|
collection: 'agents',
|
|
174
245
|
id: step.agent.data.id,
|
|
@@ -176,7 +247,7 @@ const buildFlowGraphInternal = (
|
|
|
176
247
|
});
|
|
177
248
|
}
|
|
178
249
|
if (step.service) {
|
|
179
|
-
node.data.service =
|
|
250
|
+
node.data.service = resourceForNode(step.service);
|
|
180
251
|
node.data.contextMenu = buildContextMenuForService({
|
|
181
252
|
id: step.service.data.id,
|
|
182
253
|
version: step.service.data.version,
|
|
@@ -185,14 +256,14 @@ const buildFlowGraphInternal = (
|
|
|
185
256
|
});
|
|
186
257
|
}
|
|
187
258
|
if (step.system?.data) {
|
|
188
|
-
node.data.system =
|
|
259
|
+
node.data.system = resourceForNode(step.system);
|
|
189
260
|
node.data.contextMenu = buildContextMenuForSystem({
|
|
190
261
|
id: step.system.data.id,
|
|
191
262
|
version: step.system.data.version,
|
|
192
263
|
});
|
|
193
264
|
}
|
|
194
265
|
if (step.flow) {
|
|
195
|
-
node.data.flow =
|
|
266
|
+
node.data.flow = resourceForNode(step.flow);
|
|
196
267
|
node.data.contextMenu = buildContextMenuForResource({
|
|
197
268
|
collection: 'flows',
|
|
198
269
|
id: step.flow.data.id,
|
|
@@ -215,7 +286,7 @@ const buildFlowGraphInternal = (
|
|
|
215
286
|
}
|
|
216
287
|
}
|
|
217
288
|
if (step.message) {
|
|
218
|
-
node.data.message =
|
|
289
|
+
node.data.message = resourceForNode(step.message);
|
|
219
290
|
node.data.contextMenu = buildContextMenuForResource({
|
|
220
291
|
collection: step.message.collection,
|
|
221
292
|
id: step.message.data.id,
|
|
@@ -224,15 +295,23 @@ const buildFlowGraphInternal = (
|
|
|
224
295
|
}
|
|
225
296
|
if (step.container?.data) {
|
|
226
297
|
node.data.data = { ...step.container.data };
|
|
227
|
-
node.data.container =
|
|
298
|
+
node.data.container = resourceForNode(step.container);
|
|
228
299
|
node.data.contextMenu = buildContextMenuForResource({
|
|
229
300
|
collection: 'containers',
|
|
230
301
|
id: step.container.data.id,
|
|
231
302
|
version: step.container.data.version,
|
|
232
303
|
});
|
|
233
304
|
}
|
|
305
|
+
if (step.channel?.data) {
|
|
306
|
+
node.data.channel = resourceForNode(step.channel);
|
|
307
|
+
node.data.contextMenu = buildContextMenuForResource({
|
|
308
|
+
collection: 'channels',
|
|
309
|
+
id: step.channel.data.id,
|
|
310
|
+
version: step.channel.data.version,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
234
313
|
if (step.dataProduct?.data) {
|
|
235
|
-
node.data.dataProduct =
|
|
314
|
+
node.data.dataProduct = resourceForNode(step.dataProduct);
|
|
236
315
|
node.data.contextMenu = buildContextMenuForResource({
|
|
237
316
|
collection: 'data-products',
|
|
238
317
|
id: step.dataProduct.data.id,
|
|
@@ -245,6 +324,17 @@ const buildFlowGraphInternal = (
|
|
|
245
324
|
}
|
|
246
325
|
if (step.externalSystem) node.data.externalSystem = { ...step.externalSystem, ...step.externalSystem.data };
|
|
247
326
|
if (step.custom) node.data.custom = { ...step.custom, ...step.custom.data };
|
|
327
|
+
|
|
328
|
+
// Which domain, system and team the step belongs to, for swimlanes
|
|
329
|
+
const resource = step.agent || step.service || step.container || step.dataProduct;
|
|
330
|
+
const lanes =
|
|
331
|
+
step.actor || step.externalSystem
|
|
332
|
+
? { external: true }
|
|
333
|
+
: step.system?.data
|
|
334
|
+
? maps.laneIndex.lanesForSystem(step.system)
|
|
335
|
+
: resource && maps.laneIndex.lanesFor(resource);
|
|
336
|
+
if (lanes) node.data.lanes = lanes;
|
|
337
|
+
|
|
248
338
|
nodes.push(node);
|
|
249
339
|
});
|
|
250
340
|
|
|
@@ -267,6 +357,10 @@ const buildFlowGraphInternal = (
|
|
|
267
357
|
});
|
|
268
358
|
|
|
269
359
|
paths.forEach((path: any) => {
|
|
360
|
+
if (!stepIds.has(String(path.id))) {
|
|
361
|
+
warnOnce(flow, `step "${step.id}" leads to step "${path.id}", but the flow has no step with that id.`);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
270
364
|
edges.push({
|
|
271
365
|
id: `step-${step.id}-step-${path.id}`,
|
|
272
366
|
source: stepNodeId(step.id),
|
|
@@ -291,20 +385,23 @@ const buildFlowGraphInternal = (
|
|
|
291
385
|
return { nodes, edges };
|
|
292
386
|
};
|
|
293
387
|
|
|
294
|
-
export const getNodesAndEdges = async ({ id,
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
388
|
+
export const getNodesAndEdges = async ({ id, version, mode = 'simple', layout = true }: Props) => {
|
|
389
|
+
const [flows, events, commands, queries, agents, services, containers, dataProducts, domains, systems, channels, teams, users] =
|
|
390
|
+
await Promise.all([
|
|
391
|
+
getCollection('flows'),
|
|
392
|
+
getCollection('events'),
|
|
393
|
+
getCollection('commands'),
|
|
394
|
+
getCollection('queries'),
|
|
395
|
+
getCollection('agents'),
|
|
396
|
+
getCollection('services'),
|
|
397
|
+
getCollection('containers'),
|
|
398
|
+
getCollection('data-products'),
|
|
399
|
+
getCollection('domains'),
|
|
400
|
+
getCollection('systems'),
|
|
401
|
+
getCollection('channels'),
|
|
402
|
+
getCollection('teams'),
|
|
403
|
+
getCollection('users'),
|
|
404
|
+
]);
|
|
308
405
|
|
|
309
406
|
const flow = flows.find((flow) => flow.data.id === id && flow.data.version === version);
|
|
310
407
|
|
|
@@ -324,6 +421,8 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
|
|
|
324
421
|
containerMap: createVersionedMap(containers),
|
|
325
422
|
dataProductMap: createVersionedMap(dataProducts),
|
|
326
423
|
systemMap: createVersionedMap(systems),
|
|
424
|
+
channelMap: createVersionedMap(channels),
|
|
425
|
+
laneIndex: createLaneIndex({ domains, systems, teams, users }),
|
|
327
426
|
};
|
|
328
427
|
|
|
329
428
|
const subFlowCache = new Map<string, { nodes: any[]; edges: any[] }>();
|
|
@@ -335,18 +434,5 @@ export const getNodesAndEdges = async ({ id, defaultFlow, version, mode = 'simpl
|
|
|
335
434
|
new Set([`${flow.data.id}@${flow.data.version}`])
|
|
336
435
|
);
|
|
337
436
|
|
|
338
|
-
|
|
339
|
-
graph.setNode(node.id, { width: DEFAULT_NODE_WIDTH, height: DEFAULT_NODE_HEIGHT });
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
edges.forEach((edge: any) => {
|
|
343
|
-
graph.setEdge(edge.source, edge.target);
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
layoutDagreGraph(graph);
|
|
347
|
-
|
|
348
|
-
return {
|
|
349
|
-
nodes: calculatedNodes(graph, nodes),
|
|
350
|
-
edges: edges,
|
|
351
|
-
};
|
|
437
|
+
return layout ? await layoutNodeGraph({ nodes, edges }) : { nodes, edges };
|
|
352
438
|
};
|