@eventcatalog/core 3.48.4 → 4.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/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/catalog-to-astro-content-directory.cjs +1 -1
- package/dist/{chunk-SY4XL6OQ.js → chunk-7PMNFOIL.js} +1 -1
- package/dist/chunk-BWN544LB.js +73 -0
- package/dist/{chunk-JY4H7A4S.js → chunk-D3MI3OFO.js} +1 -1
- package/dist/{chunk-FNDSHOV2.js → chunk-HN45LKSL.js} +1 -1
- package/dist/{chunk-KDLSBQRP.js → chunk-JMADW4J7.js} +1 -1
- package/dist/{chunk-XNVSSL4W.js → chunk-NAOHQDLC.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/core-node-modules.cjs +108 -0
- package/dist/core-node-modules.d.cts +7 -0
- package/dist/core-node-modules.d.ts +7 -0
- package/dist/core-node-modules.js +8 -0
- package/dist/docs/development/components/components/15-prompt.md +5 -1
- package/dist/eventcatalog.cjs +124 -48
- package/dist/eventcatalog.js +26 -15
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +27 -23
- package/eventcatalog/public/icons/languages/java.svg +1 -0
- package/eventcatalog/public/icons/payments/stripe.svg +1 -0
- package/eventcatalog/src/components/Badge.astro +10 -10
- package/eventcatalog/src/components/CopyAsMarkdown.tsx +154 -0
- package/eventcatalog/src/components/Grids/DomainGrid.tsx +207 -44
- package/eventcatalog/src/components/Grids/MessageGrid.tsx +0 -20
- package/eventcatalog/src/components/Grids/SystemGrid.tsx +185 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.astro +99 -0
- package/eventcatalog/src/components/MDX/ADRTable/ADRTable.client.tsx +400 -0
- package/eventcatalog/src/components/MDX/ContextDiagram/ContextDiagramPortal.tsx +21 -0
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +1 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +42 -6
- package/eventcatalog/src/components/MDX/Prompt/Prompt.astro +62 -9
- package/eventcatalog/src/components/MDX/ResourceRef/ResourceRef.astro +8 -1
- package/eventcatalog/src/components/MDX/SystemContextMap/SystemContextMapPortal.tsx +22 -0
- package/eventcatalog/src/components/MDX/components.tsx +7 -0
- package/eventcatalog/src/components/SchemaExplorer/SchemaExplorer.tsx +1 -1
- package/eventcatalog/src/components/SideNav/NestedSideBar/index.tsx +67 -37
- package/eventcatalog/src/components/Tables/Discover/DiscoverTable.tsx +47 -0
- package/eventcatalog/src/components/Tables/Discover/FilterComponents.tsx +10 -2
- package/eventcatalog/src/components/Tables/Discover/columns.tsx +115 -27
- package/eventcatalog/src/components/Tables/Discover/index.ts +7 -1
- package/eventcatalog/src/components/Tables/SystemResources/SystemResourcesTable.tsx +267 -0
- package/eventcatalog/src/content.config.ts +94 -8
- package/eventcatalog/src/enterprise/collections/resource-docs-utils.ts +4 -1
- package/eventcatalog/src/enterprise/custom-documentation/pages/docs/custom/index.astro +12 -13
- package/eventcatalog/src/enterprise/custom-documentation/utils/custom-docs.ts +6 -0
- package/eventcatalog/src/enterprise/feature.ts +3 -1
- package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +85 -129
- package/eventcatalog/src/layouts/VisualiserLayout.astro +66 -0
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/_index.data.ts +4 -2
- package/eventcatalog/src/pages/architecture/[type]/[id]/[version]/index.astro +2 -0
- package/eventcatalog/src/pages/diagrams/[id]/[version]/index.astro +15 -15
- package/eventcatalog/src/pages/discover/[type]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/discover/[type]/index.astro +47 -2
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/[docVersion]/index.astro +15 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/[docType]/[docId]/index.astro +13 -14
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/changelog/_index.data.ts +11 -1
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/index.astro +81 -26
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/_index.data.ts +89 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version]/resources/index.astro +85 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].md.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/[version].mdx.ts +2 -0
- package/eventcatalog/src/pages/docs/[type]/[id]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/docs/teams/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/docs/users/[id]/index.astro +24 -1
- package/eventcatalog/src/pages/index.astro +30 -7
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/_index.data.ts +1 -0
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version]/index.astro +1 -1
- package/eventcatalog/src/pages/visualiser/[type]/[id]/[version].mermaid.ts +3 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/_index.data.ts +94 -0
- package/eventcatalog/src/pages/visualiser/domains/[id]/[version]/systems-context/index.astro +51 -0
- package/eventcatalog/src/pages/visualiser/system-context-map/index.astro +41 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/_index.data.ts +91 -0
- package/eventcatalog/src/pages/visualiser/systems/[id]/[version]/context/index.astro +51 -0
- package/eventcatalog/src/stores/sidebar-store/builders/adr.ts +3 -1
- package/eventcatalog/src/stores/sidebar-store/builders/agent.ts +3 -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 +127 -49
- package/eventcatalog/src/stores/sidebar-store/builders/message.ts +1 -1
- package/eventcatalog/src/stores/sidebar-store/builders/service.ts +4 -2
- package/eventcatalog/src/stores/sidebar-store/builders/shared.ts +2 -1
- package/eventcatalog/src/stores/sidebar-store/builders/system.ts +166 -0
- package/eventcatalog/src/stores/sidebar-store/state.ts +99 -6
- package/eventcatalog/src/types/index.ts +2 -0
- package/eventcatalog/src/utils/collection-colors.ts +6 -1
- package/eventcatalog/src/utils/collections/domains.ts +35 -0
- package/eventcatalog/src/utils/collections/icons.ts +4 -5
- package/eventcatalog/src/utils/collections/systems.ts +110 -0
- package/eventcatalog/src/utils/collections/teams.ts +15 -10
- package/eventcatalog/src/utils/collections/users.ts +7 -4
- package/eventcatalog/src/utils/collections/util.ts +2 -0
- package/eventcatalog/src/utils/icon-map.ts +20 -0
- package/eventcatalog/src/utils/icon.ts +11 -0
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +12 -2
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +0 -170
- package/eventcatalog/src/utils/node-graphs/system-context-node-graph.ts +400 -0
- package/eventcatalog/src/utils/node-graphs/systems-node-graph.ts +208 -0
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +12 -0
- package/eventcatalog/src/utils/page-loaders/page-data-loader.ts +2 -0
- package/package.json +16 -13
- package/eventcatalog/src/pages/visualiser/context-map/index.astro +0 -30
|
@@ -5,6 +5,7 @@ import { getAdrAliasNodeKey, getAdrNodeKey, getAdrs, type Adr } from '@utils/col
|
|
|
5
5
|
import { ADR_STATUS_VALUES, formatAdrStatus } from '@utils/collections/adr-constants';
|
|
6
6
|
import { getContainers } from '@utils/collections/containers';
|
|
7
7
|
import { getDomains } from '@utils/collections/domains';
|
|
8
|
+
import { getSystems } from '@utils/collections/systems';
|
|
8
9
|
import { getServices } from '@utils/collections/services';
|
|
9
10
|
import { getMessages, pluralizeMessageType } from '@utils/collections/messages';
|
|
10
11
|
import { getOwner } from '@utils/collections/owners';
|
|
@@ -19,6 +20,7 @@ import { buildUrl } from '@utils/url-builder';
|
|
|
19
20
|
import type { NavigationData, NavNode, ChildRef } from './builders/shared';
|
|
20
21
|
import { buildAgentNode } from './builders/agent';
|
|
21
22
|
import { buildDomainNode } from './builders/domain';
|
|
23
|
+
import { buildSystemNode } from './builders/system';
|
|
22
24
|
import { buildServiceNode } from './builders/service';
|
|
23
25
|
import { buildMessageNode } from './builders/message';
|
|
24
26
|
import { buildContainerNode } from './builders/container';
|
|
@@ -274,6 +276,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
274
276
|
|
|
275
277
|
const [
|
|
276
278
|
domains,
|
|
279
|
+
systems,
|
|
277
280
|
agents,
|
|
278
281
|
services,
|
|
279
282
|
{ events, commands, queries },
|
|
@@ -293,6 +296,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
293
296
|
resourceDocCategories,
|
|
294
297
|
] = await Promise.all([
|
|
295
298
|
getDomains({ getAllVersions: false, includeServicesInSubdomains: false }),
|
|
299
|
+
getSystems({ getAllVersions: false }),
|
|
296
300
|
getAgents({ getAllVersions: false }),
|
|
297
301
|
getServices({ getAllVersions: false }),
|
|
298
302
|
getMessages({ getAllVersions: false }),
|
|
@@ -322,6 +326,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
322
326
|
agents,
|
|
323
327
|
services,
|
|
324
328
|
domains,
|
|
329
|
+
systems,
|
|
325
330
|
events,
|
|
326
331
|
commands,
|
|
327
332
|
queries,
|
|
@@ -392,6 +397,15 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
392
397
|
})
|
|
393
398
|
);
|
|
394
399
|
|
|
400
|
+
const systemWithOwners = await Promise.all(
|
|
401
|
+
systems.map(async (system) => {
|
|
402
|
+
const ownersInSystem = system.data.owners || [];
|
|
403
|
+
const owners = await Promise.all(ownersInSystem.map((owner) => getOwner(owner)));
|
|
404
|
+
const filteredOwners = owners.filter((o) => o !== undefined) as Array<NonNullable<(typeof owners)[0]>>;
|
|
405
|
+
return { system, owners: filteredOwners };
|
|
406
|
+
})
|
|
407
|
+
);
|
|
408
|
+
|
|
395
409
|
const adrsWithOwners = await Promise.all(
|
|
396
410
|
adrs.map(async (adr) => {
|
|
397
411
|
const owners = await Promise.all((adr.data.owners || []).map((owner) => getOwner(owner)));
|
|
@@ -607,6 +621,19 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
607
621
|
{} as Record<string, NavNode | string>
|
|
608
622
|
);
|
|
609
623
|
|
|
624
|
+
const systemNodes = systemWithOwners.reduce(
|
|
625
|
+
(acc, { system, owners }) => {
|
|
626
|
+
const versionedKey = `system:${system.data.id}:${system.data.version}`;
|
|
627
|
+
acc[versionedKey] = withArchitectureDecisionsSection(buildSystemNode(system, owners, context), system, adrs);
|
|
628
|
+
if (system.data.latestVersion === system.data.version) {
|
|
629
|
+
// Store reference to versioned key instead of duplicating the full node
|
|
630
|
+
acc[`system:${system.data.id}`] = versionedKey;
|
|
631
|
+
}
|
|
632
|
+
return acc;
|
|
633
|
+
},
|
|
634
|
+
{} as Record<string, NavNode | string>
|
|
635
|
+
);
|
|
636
|
+
|
|
610
637
|
// Get owners for data products
|
|
611
638
|
const dataProductWithOwners = await Promise.all(
|
|
612
639
|
dataProducts.map(async (dataProduct) => {
|
|
@@ -781,6 +808,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
781
808
|
{} as Record<string, NavNode>
|
|
782
809
|
);
|
|
783
810
|
|
|
811
|
+
const visualiserEnabled = config?.visualiser?.enabled !== false;
|
|
784
812
|
const rootDomainsNodes: Record<string, NavNode> = {};
|
|
785
813
|
|
|
786
814
|
if (rootDomains.length > 0) {
|
|
@@ -792,6 +820,22 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
792
820
|
};
|
|
793
821
|
}
|
|
794
822
|
|
|
823
|
+
const topLevelDiagramsNode =
|
|
824
|
+
visualiserEnabled && systems.length > 0
|
|
825
|
+
? {
|
|
826
|
+
type: 'group' as const,
|
|
827
|
+
title: 'Top level diagrams',
|
|
828
|
+
icon: 'Workflow',
|
|
829
|
+
pages: [
|
|
830
|
+
{
|
|
831
|
+
type: 'item' as const,
|
|
832
|
+
title: 'System Context Map',
|
|
833
|
+
href: buildUrl('/visualiser/system-context-map'),
|
|
834
|
+
},
|
|
835
|
+
],
|
|
836
|
+
}
|
|
837
|
+
: undefined;
|
|
838
|
+
|
|
795
839
|
const createLeaf = (items: any[], node: NavNode) => (items.length > 0 ? node : undefined);
|
|
796
840
|
|
|
797
841
|
const domainsList = createLeaf(domains, {
|
|
@@ -801,6 +845,38 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
801
845
|
pages: sortByResourceName(domains).map((domain) => `domain:${domain.data.id}:${domain.data.version}`),
|
|
802
846
|
});
|
|
803
847
|
|
|
848
|
+
// Split systems by scope (defaults to internal). When there are systems of both
|
|
849
|
+
// scopes we show two sub-sections (Internal / External), each ordered by name;
|
|
850
|
+
// otherwise we keep a flat list so a single-scope catalog isn't over-nested.
|
|
851
|
+
const internalSystems = systems.filter((system) => (system.data.scope ?? 'internal') !== 'external');
|
|
852
|
+
const externalSystems = systems.filter((system) => system.data.scope === 'external');
|
|
853
|
+
|
|
854
|
+
const systemPageKeys = (items: typeof systems) =>
|
|
855
|
+
sortByResourceName(items).map((system) => `system:${system.data.id}:${system.data.version}`);
|
|
856
|
+
|
|
857
|
+
const internalSystemsList = createLeaf(internalSystems, {
|
|
858
|
+
type: 'group',
|
|
859
|
+
title: 'Internal',
|
|
860
|
+
icon: 'Group',
|
|
861
|
+
pages: systemPageKeys(internalSystems),
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
const externalSystemsScopedList = createLeaf(externalSystems, {
|
|
865
|
+
type: 'group',
|
|
866
|
+
title: 'External',
|
|
867
|
+
icon: 'Group',
|
|
868
|
+
pages: systemPageKeys(externalSystems),
|
|
869
|
+
});
|
|
870
|
+
|
|
871
|
+
const hasBothSystemScopes = internalSystems.length > 0 && externalSystems.length > 0;
|
|
872
|
+
|
|
873
|
+
const systemsList = createLeaf(systems, {
|
|
874
|
+
type: 'item',
|
|
875
|
+
title: 'Systems',
|
|
876
|
+
icon: 'Group',
|
|
877
|
+
pages: hasBothSystemScopes ? ['list:systems-internal', 'list:systems-external'] : systemPageKeys(systems),
|
|
878
|
+
});
|
|
879
|
+
|
|
804
880
|
const agentsList = createLeaf(agents, {
|
|
805
881
|
type: 'item',
|
|
806
882
|
title: 'Agents',
|
|
@@ -811,7 +887,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
811
887
|
const adrsList = createLeaf(adrs, {
|
|
812
888
|
type: 'item',
|
|
813
889
|
title: 'Decision Records',
|
|
814
|
-
icon: '
|
|
890
|
+
icon: 'ClipboardList',
|
|
815
891
|
pages: groupAdrsByStatus(adrs),
|
|
816
892
|
});
|
|
817
893
|
|
|
@@ -939,6 +1015,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
939
1015
|
|
|
940
1016
|
const allChildrenKeys = [
|
|
941
1017
|
'list:domains',
|
|
1018
|
+
'list:systems',
|
|
942
1019
|
'list:services',
|
|
943
1020
|
'list:agents',
|
|
944
1021
|
'list:adrs',
|
|
@@ -954,6 +1031,7 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
954
1031
|
];
|
|
955
1032
|
const allChildrenNodes = [
|
|
956
1033
|
domainsList,
|
|
1034
|
+
systemsList,
|
|
957
1035
|
servicesList,
|
|
958
1036
|
agentsList,
|
|
959
1037
|
adrsList,
|
|
@@ -968,10 +1046,22 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
968
1046
|
peopleList,
|
|
969
1047
|
];
|
|
970
1048
|
|
|
1049
|
+
// The Browse list leads with the resources people reach for most — Domains,
|
|
1050
|
+
// Systems, Services then Messages — and falls back to A-Z for everything else.
|
|
1051
|
+
const browseOrderPriority = ['list:domains', 'list:systems', 'list:services', 'list:messages'];
|
|
1052
|
+
const browseRank = (key: string) => {
|
|
1053
|
+
const index = browseOrderPriority.indexOf(key);
|
|
1054
|
+
return index === -1 ? browseOrderPriority.length : index;
|
|
1055
|
+
};
|
|
1056
|
+
|
|
971
1057
|
const validAllChildren = allChildrenKeys
|
|
972
1058
|
.map((key, idx) => ({ key, node: allChildrenNodes[idx] }))
|
|
973
1059
|
.filter((item): item is { key: string; node: NavNode } => item.node !== undefined)
|
|
974
|
-
.sort((a, b) =>
|
|
1060
|
+
.sort((a, b) => {
|
|
1061
|
+
const rankDifference = browseRank(a.key) - browseRank(b.key);
|
|
1062
|
+
if (rankDifference !== 0) return rankDifference;
|
|
1063
|
+
return a.node.title.localeCompare(b.node.title);
|
|
1064
|
+
})
|
|
975
1065
|
.map((item) => item.key);
|
|
976
1066
|
|
|
977
1067
|
let allList;
|
|
@@ -986,6 +1076,9 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
986
1076
|
|
|
987
1077
|
const allNodes: Record<string, NavNode> = {
|
|
988
1078
|
...(domainsList ? { 'list:domains': domainsList } : {}),
|
|
1079
|
+
...(systemsList ? { 'list:systems': systemsList } : {}),
|
|
1080
|
+
...(internalSystemsList ? { 'list:systems-internal': internalSystemsList } : {}),
|
|
1081
|
+
...(externalSystemsScopedList ? { 'list:systems-external': externalSystemsScopedList } : {}),
|
|
989
1082
|
...(servicesList ? { 'list:services': servicesList } : {}),
|
|
990
1083
|
...(agentsList ? { 'list:agents': agentsList } : {}),
|
|
991
1084
|
...(adrsList ? { 'list:adrs': adrsList } : {}),
|
|
@@ -1008,7 +1101,6 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
1008
1101
|
|
|
1009
1102
|
// System-level views (only show if visualiser is enabled and there are domains)
|
|
1010
1103
|
const systemNode: Record<string, NavNode> = {};
|
|
1011
|
-
const visualiserEnabled = config?.visualiser?.enabled !== false;
|
|
1012
1104
|
|
|
1013
1105
|
if (visualiserEnabled && domains.length > 0) {
|
|
1014
1106
|
systemNode['list:system'] = {
|
|
@@ -1027,7 +1119,9 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
1027
1119
|
|
|
1028
1120
|
const allGeneratedNodes = {
|
|
1029
1121
|
...rootDomainsNodes,
|
|
1122
|
+
...(topLevelDiagramsNode ? { 'list:top-level-diagrams': topLevelDiagramsNode } : {}),
|
|
1030
1123
|
...domainNodes,
|
|
1124
|
+
...systemNodes,
|
|
1031
1125
|
...agentNodes,
|
|
1032
1126
|
...adrNodes,
|
|
1033
1127
|
...serviceNodes,
|
|
@@ -1047,9 +1141,8 @@ export const getNestedSideBarData = async (): Promise<NavigationData> => {
|
|
|
1047
1141
|
|
|
1048
1142
|
// only filter if child is string
|
|
1049
1143
|
const defaultPages = ['list:top-level-domains', 'list:all'];
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
defaultPages.push('list:system');
|
|
1144
|
+
if (topLevelDiagramsNode) {
|
|
1145
|
+
defaultPages.splice(1, 0, 'list:top-level-diagrams');
|
|
1053
1146
|
}
|
|
1054
1147
|
const rootNavigationConfig = config?.navigation?.pages || defaultPages;
|
|
1055
1148
|
|
|
@@ -5,6 +5,7 @@ export type CollectionTypes =
|
|
|
5
5
|
| 'events'
|
|
6
6
|
| 'queries'
|
|
7
7
|
| 'domains'
|
|
8
|
+
| 'systems'
|
|
8
9
|
| 'services'
|
|
9
10
|
| 'flows'
|
|
10
11
|
| 'channels'
|
|
@@ -22,6 +23,7 @@ export type PageTypes =
|
|
|
22
23
|
| 'queries'
|
|
23
24
|
| 'services'
|
|
24
25
|
| 'domains'
|
|
26
|
+
| 'systems'
|
|
25
27
|
| 'channels'
|
|
26
28
|
| 'flows'
|
|
27
29
|
| 'entities'
|
|
@@ -10,7 +10,8 @@ export type CollectionColor =
|
|
|
10
10
|
| 'gray'
|
|
11
11
|
| 'cyan'
|
|
12
12
|
| 'sky'
|
|
13
|
-
| 'indigo'
|
|
13
|
+
| 'indigo'
|
|
14
|
+
| 'violet';
|
|
14
15
|
|
|
15
16
|
export const getColorForCollection = (collection: string): CollectionColor => {
|
|
16
17
|
switch (collection) {
|
|
@@ -34,6 +35,8 @@ export const getColorForCollection = (collection: string): CollectionColor => {
|
|
|
34
35
|
return 'purple';
|
|
35
36
|
case 'domains':
|
|
36
37
|
return 'yellow';
|
|
38
|
+
case 'systems':
|
|
39
|
+
return 'violet';
|
|
37
40
|
case 'agents':
|
|
38
41
|
return 'sky';
|
|
39
42
|
case 'adrs':
|
|
@@ -62,6 +65,7 @@ export const tailwind500RgbByColor: Record<CollectionColor, string> = {
|
|
|
62
65
|
cyan: '6 182 212',
|
|
63
66
|
sky: '14 165 233',
|
|
64
67
|
indigo: '99 102 241',
|
|
68
|
+
violet: '139 92 246',
|
|
65
69
|
};
|
|
66
70
|
|
|
67
71
|
export const collectionTextColorClassByColor: Record<CollectionColor, string> = {
|
|
@@ -77,6 +81,7 @@ export const collectionTextColorClassByColor: Record<CollectionColor, string> =
|
|
|
77
81
|
cyan: 'text-cyan-500',
|
|
78
82
|
sky: 'text-sky-500',
|
|
79
83
|
indigo: 'text-indigo-500',
|
|
84
|
+
violet: 'text-violet-500',
|
|
80
85
|
};
|
|
81
86
|
|
|
82
87
|
export const getCollectionTextColorClass = (color: string, fallback = 'text-gray-500'): string =>
|
|
@@ -123,6 +123,7 @@ export const getDomains = async ({
|
|
|
123
123
|
allServices,
|
|
124
124
|
allEntities,
|
|
125
125
|
allFlows,
|
|
126
|
+
allSystems,
|
|
126
127
|
allEvents,
|
|
127
128
|
allCommands,
|
|
128
129
|
allQueries,
|
|
@@ -134,6 +135,7 @@ export const getDomains = async ({
|
|
|
134
135
|
getCollection('services'),
|
|
135
136
|
getCollection('entities'),
|
|
136
137
|
getCollection('flows'),
|
|
138
|
+
getCollection('systems'),
|
|
137
139
|
getCollection('events'),
|
|
138
140
|
getCollection('commands'),
|
|
139
141
|
getCollection('queries'),
|
|
@@ -151,6 +153,7 @@ export const getDomains = async ({
|
|
|
151
153
|
const serviceMap = createVersionedMap(allServices);
|
|
152
154
|
const entityMap = createVersionedMap(allEntities);
|
|
153
155
|
const flowMap = createVersionedMap(allFlows);
|
|
156
|
+
const systemMap = createVersionedMap(allSystems);
|
|
154
157
|
const dataProductMap = createVersionedMap(allDataProducts);
|
|
155
158
|
|
|
156
159
|
// 3. Filter the domains we actually want to process/return
|
|
@@ -220,6 +223,37 @@ export const getDomains = async ({
|
|
|
220
223
|
.map((flow: { id: string; version: string | undefined }) => findInMap(flowMap, flow.id, flow.version))
|
|
221
224
|
.filter((f): f is CollectionEntry<'flows'> => !!f);
|
|
222
225
|
|
|
226
|
+
// Resolve Systems (and hydrate each system's services so they can be
|
|
227
|
+
// rendered in the domain's architecture view, like subdomains)
|
|
228
|
+
const systemsInDomain = domain.data.systems || [];
|
|
229
|
+
const systems = systemsInDomain
|
|
230
|
+
.map((system: { id: string; version: string | undefined }) => findInMap(systemMap, system.id, system.version))
|
|
231
|
+
.filter((s): s is CollectionEntry<'systems'> => !!s)
|
|
232
|
+
.map((system: any) => {
|
|
233
|
+
const systemServices = enrichServices
|
|
234
|
+
? hydrateServices(system.data.services || [], serviceMap, messageMap, containerMap)
|
|
235
|
+
: (system.data.services || [])
|
|
236
|
+
.map((service: { id: string; version: string | undefined }) => findInMap(serviceMap, service.id, service.version))
|
|
237
|
+
.filter((s: any) => !!s);
|
|
238
|
+
|
|
239
|
+
// Hydrate the system's data stores (containers) so they can be
|
|
240
|
+
// rendered in the domain's architecture view.
|
|
241
|
+
const systemContainers = (system.data.containers || [])
|
|
242
|
+
.map((container: { id: string; version: string | undefined }) =>
|
|
243
|
+
findInMap(containerMap, container.id, container.version)
|
|
244
|
+
)
|
|
245
|
+
.filter((c: any) => !!c);
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
...system,
|
|
249
|
+
data: {
|
|
250
|
+
...system.data,
|
|
251
|
+
services: systemServices as any,
|
|
252
|
+
containers: systemContainers as any,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
|
|
223
257
|
// Resolve Data Products
|
|
224
258
|
const dataProductsInDomain = domain.data['data-products'] || [];
|
|
225
259
|
const dataProducts = dataProductsInDomain
|
|
@@ -274,6 +308,7 @@ export const getDomains = async ({
|
|
|
274
308
|
agents: agents as any,
|
|
275
309
|
services: services as any, // Cast to avoid deep type issues with enriched data
|
|
276
310
|
domains: subDomains as any,
|
|
311
|
+
systems: systems as any,
|
|
277
312
|
entities: entities as any,
|
|
278
313
|
flows: flows as any,
|
|
279
314
|
'data-products': dataProducts as any,
|
|
@@ -9,20 +9,21 @@ import {
|
|
|
9
9
|
UserIcon,
|
|
10
10
|
ArrowsRightLeftIcon,
|
|
11
11
|
VariableIcon,
|
|
12
|
-
MapIcon,
|
|
13
12
|
CubeIcon,
|
|
14
13
|
} from '@heroicons/react/24/outline';
|
|
15
|
-
import { BookText, Bot, Box, DatabaseIcon } from 'lucide-react';
|
|
14
|
+
import { BookText, Bot, Box, ClipboardList, DatabaseIcon, Group } from 'lucide-react';
|
|
16
15
|
import { getColorForCollection } from '@utils/collection-colors';
|
|
17
16
|
|
|
18
17
|
export const getIconForCollection = (collection: string) => {
|
|
19
18
|
switch (collection) {
|
|
20
19
|
case 'domains':
|
|
21
20
|
return RectangleGroupIcon;
|
|
21
|
+
case 'systems':
|
|
22
|
+
return Group;
|
|
22
23
|
case 'agents':
|
|
23
24
|
return Bot;
|
|
24
25
|
case 'adrs':
|
|
25
|
-
return
|
|
26
|
+
return ClipboardList;
|
|
26
27
|
case 'services':
|
|
27
28
|
return ServerIcon;
|
|
28
29
|
case 'events':
|
|
@@ -43,8 +44,6 @@ export const getIconForCollection = (collection: string) => {
|
|
|
43
44
|
return VariableIcon;
|
|
44
45
|
case 'ubiquitousLanguages':
|
|
45
46
|
return BookText;
|
|
46
|
-
case 'bounded-context-map':
|
|
47
|
-
return MapIcon;
|
|
48
47
|
case 'entities':
|
|
49
48
|
return Box;
|
|
50
49
|
case 'containers':
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { getCollection } from 'astro:content';
|
|
2
|
+
import type { CollectionEntry } from 'astro:content';
|
|
3
|
+
import { createVersionedMap, findInMap } from './util';
|
|
4
|
+
|
|
5
|
+
const CACHE_ENABLED = process.env.DISABLE_EVENTCATALOG_CACHE !== 'true';
|
|
6
|
+
export type System = CollectionEntry<'systems'>;
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
getAllVersions?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// cache for build time
|
|
13
|
+
let memoryCache: Record<string, System[]> = {};
|
|
14
|
+
|
|
15
|
+
export const getSystems = async ({ getAllVersions = true }: Props = {}): Promise<System[]> => {
|
|
16
|
+
const cacheKey = getAllVersions ? 'allVersions' : 'currentVersions';
|
|
17
|
+
|
|
18
|
+
if (memoryCache[cacheKey] && memoryCache[cacheKey].length > 0 && CACHE_ENABLED) {
|
|
19
|
+
return memoryCache[cacheKey];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const [allSystems, allServices, allFlows, allEntities, allContainers] = await Promise.all([
|
|
23
|
+
getCollection('systems'),
|
|
24
|
+
getCollection('services'),
|
|
25
|
+
getCollection('flows'),
|
|
26
|
+
getCollection('entities'),
|
|
27
|
+
getCollection('containers'),
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
// Build optimized map of id -> versions (sorted latest first)
|
|
31
|
+
const systemMap = createVersionedMap(allSystems);
|
|
32
|
+
const serviceMap = createVersionedMap(allServices);
|
|
33
|
+
const flowMap = createVersionedMap(allFlows);
|
|
34
|
+
const entityMap = createVersionedMap(allEntities);
|
|
35
|
+
const containerMap = createVersionedMap(allContainers);
|
|
36
|
+
|
|
37
|
+
// Filter systems
|
|
38
|
+
const targetSystems = allSystems.filter((system) => {
|
|
39
|
+
if (system.data.hidden === true) return false;
|
|
40
|
+
if (!getAllVersions && system.filePath?.includes('versioned')) return false;
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Enrich systems with version info
|
|
45
|
+
const processedSystems = targetSystems.map((system) => {
|
|
46
|
+
const systemVersions = systemMap.get(system.data.id) || [];
|
|
47
|
+
const latestVersion = systemVersions[0]?.data.version || system.data.version;
|
|
48
|
+
const versions = systemVersions.map((s) => s.data.version);
|
|
49
|
+
|
|
50
|
+
// Resolve service pointers to their full collection entries
|
|
51
|
+
const services = (system.data.services || [])
|
|
52
|
+
.map((service: { id: string; version?: string }) => findInMap(serviceMap, service.id, service.version))
|
|
53
|
+
.filter((s): s is NonNullable<typeof s> => !!s);
|
|
54
|
+
|
|
55
|
+
// Resolve flow pointers to their full collection entries
|
|
56
|
+
const flows = (system.data.flows || [])
|
|
57
|
+
.map((flow: { id: string; version?: string }) => findInMap(flowMap, flow.id, flow.version))
|
|
58
|
+
.filter((f): f is NonNullable<typeof f> => !!f);
|
|
59
|
+
|
|
60
|
+
// Resolve entity pointers to their full collection entries
|
|
61
|
+
const entities = (system.data.entities || [])
|
|
62
|
+
.map((entity: { id: string; version?: string }) => findInMap(entityMap, entity.id, entity.version))
|
|
63
|
+
.filter((e): e is NonNullable<typeof e> => !!e);
|
|
64
|
+
|
|
65
|
+
// Resolve container (data store) pointers to their full collection entries
|
|
66
|
+
const containers = (system.data.containers || [])
|
|
67
|
+
.map((container: { id: string; version?: string }) => findInMap(containerMap, container.id, container.version))
|
|
68
|
+
.filter((c): c is NonNullable<typeof c> => !!c);
|
|
69
|
+
|
|
70
|
+
// Resolve system-to-system relationship pointers (used by the System Diagram).
|
|
71
|
+
// Each relationship resolves to its target system while keeping the edge `label`.
|
|
72
|
+
// Dangling targets are dropped; relationships keep their label even if absent (the
|
|
73
|
+
// diagram decides whether to draw an edge based on the presence of a label).
|
|
74
|
+
const relationships = (system.data.relationships || [])
|
|
75
|
+
.map((relationship: { id: string; version?: string; label?: string }) => {
|
|
76
|
+
const target = findInMap(systemMap, relationship.id, relationship.version);
|
|
77
|
+
if (!target) return null;
|
|
78
|
+
return {
|
|
79
|
+
id: target.data.id,
|
|
80
|
+
version: target.data.version,
|
|
81
|
+
label: relationship.label,
|
|
82
|
+
data: target.data,
|
|
83
|
+
};
|
|
84
|
+
})
|
|
85
|
+
.filter((r): r is NonNullable<typeof r> => !!r);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
...system,
|
|
89
|
+
data: {
|
|
90
|
+
...system.data,
|
|
91
|
+
versions,
|
|
92
|
+
latestVersion,
|
|
93
|
+
services: services as any,
|
|
94
|
+
flows: flows as any,
|
|
95
|
+
entities: entities as any,
|
|
96
|
+
containers: containers as any,
|
|
97
|
+
relationships: relationships as any,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// order them by the name of the system
|
|
103
|
+
processedSystems.sort((a, b) => {
|
|
104
|
+
return (a.data.name || a.data.id).localeCompare(b.data.name || b.data.id);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
memoryCache[cacheKey] = processedSystems;
|
|
108
|
+
|
|
109
|
+
return processedSystems;
|
|
110
|
+
};
|
|
@@ -16,16 +16,18 @@ export const getTeams = async (): Promise<Team[]> => {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// 1. Fetch all collections in parallel
|
|
19
|
-
const [allTeams, allAgents, allDomains, allServices, allEvents, allCommands, allQueries, allAdrs] =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
const [allTeams, allAgents, allDomains, allSystems, allServices, allEvents, allCommands, allQueries, allAdrs] =
|
|
20
|
+
await Promise.all([
|
|
21
|
+
getCollection('teams'),
|
|
22
|
+
getCollection('agents'),
|
|
23
|
+
getCollection('domains'),
|
|
24
|
+
getCollection('systems'),
|
|
25
|
+
getCollection('services'),
|
|
26
|
+
getCollection('events'),
|
|
27
|
+
getCollection('commands'),
|
|
28
|
+
getCollection('queries'),
|
|
29
|
+
getAdrs({ getAllVersions: false }),
|
|
30
|
+
]);
|
|
29
31
|
|
|
30
32
|
// 2. Filter teams
|
|
31
33
|
const targetTeams = allTeams.filter((team) => team.data.hidden !== true);
|
|
@@ -50,6 +52,7 @@ export const getTeams = async (): Promise<Team[]> => {
|
|
|
50
52
|
|
|
51
53
|
addToIndex(allAgents);
|
|
52
54
|
addToIndex(allDomains);
|
|
55
|
+
addToIndex(allSystems);
|
|
53
56
|
addToIndex(allServices);
|
|
54
57
|
addToIndex(allEvents);
|
|
55
58
|
addToIndex(allCommands);
|
|
@@ -64,6 +67,7 @@ export const getTeams = async (): Promise<Team[]> => {
|
|
|
64
67
|
// Categorize items
|
|
65
68
|
const ownedAgents = ownedItems.filter((i) => i.collection === 'agents') as CollectionEntry<'agents'>[];
|
|
66
69
|
const ownedDomains = ownedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
|
|
70
|
+
const ownedSystems = ownedItems.filter((i) => i.collection === 'systems') as CollectionEntry<'systems'>[];
|
|
67
71
|
const ownedServices = ownedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
|
|
68
72
|
const ownedEvents = ownedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
|
|
69
73
|
const ownedCommands = ownedItems.filter((i) => i.collection === 'commands') as CollectionEntry<'commands'>[];
|
|
@@ -76,6 +80,7 @@ export const getTeams = async (): Promise<Team[]> => {
|
|
|
76
80
|
...team.data,
|
|
77
81
|
ownedAgents,
|
|
78
82
|
ownedDomains,
|
|
83
|
+
ownedSystems,
|
|
79
84
|
ownedServices,
|
|
80
85
|
ownedCommands,
|
|
81
86
|
ownedQueries,
|
|
@@ -17,19 +17,19 @@ export const getUsers = async (): Promise<User[]> => {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// 1. Fetch all collections in parallel
|
|
20
|
-
const [allUsers, allAgents, allDomains, allServices, allEvents, allCommands, allQueries, allTeams, allAdrs] =
|
|
21
|
-
[
|
|
20
|
+
const [allUsers, allAgents, allDomains, allSystems, allServices, allEvents, allCommands, allQueries, allTeams, allAdrs] =
|
|
21
|
+
await Promise.all([
|
|
22
22
|
getCollection('users'),
|
|
23
23
|
getCollection('agents'),
|
|
24
24
|
getCollection('domains'),
|
|
25
|
+
getCollection('systems'),
|
|
25
26
|
getCollection('services'),
|
|
26
27
|
getCollection('events'),
|
|
27
28
|
getCollection('commands'),
|
|
28
29
|
getCollection('queries'),
|
|
29
30
|
getCollection('teams'),
|
|
30
31
|
getAdrs({ getAllVersions: false }),
|
|
31
|
-
]
|
|
32
|
-
);
|
|
32
|
+
]);
|
|
33
33
|
|
|
34
34
|
// 2. Filter users
|
|
35
35
|
const targetUsers = allUsers.filter((user) => user.data.hidden !== true);
|
|
@@ -59,6 +59,7 @@ export const getUsers = async (): Promise<User[]> => {
|
|
|
59
59
|
|
|
60
60
|
addToIndex(allAgents);
|
|
61
61
|
addToIndex(allDomains);
|
|
62
|
+
addToIndex(allSystems);
|
|
62
63
|
addToIndex(allServices);
|
|
63
64
|
addToIndex(allEvents);
|
|
64
65
|
addToIndex(allCommands);
|
|
@@ -93,6 +94,7 @@ export const getUsers = async (): Promise<User[]> => {
|
|
|
93
94
|
// Categorize items
|
|
94
95
|
const ownedAgents = allOwnedItems.filter((i) => i.collection === 'agents') as CollectionEntry<'agents'>[];
|
|
95
96
|
const ownedDomains = allOwnedItems.filter((i) => i.collection === 'domains') as CollectionEntry<'domains'>[];
|
|
97
|
+
const ownedSystems = allOwnedItems.filter((i) => i.collection === 'systems') as CollectionEntry<'systems'>[];
|
|
96
98
|
const ownedServices = allOwnedItems.filter((i) => i.collection === 'services') as CollectionEntry<'services'>[];
|
|
97
99
|
const ownedEvents = allOwnedItems.filter((i) => i.collection === 'events') as CollectionEntry<'events'>[];
|
|
98
100
|
const ownedCommands = allOwnedItems.filter((i) => i.collection === 'commands') as CollectionEntry<'commands'>[];
|
|
@@ -105,6 +107,7 @@ export const getUsers = async (): Promise<User[]> => {
|
|
|
105
107
|
...user.data,
|
|
106
108
|
ownedAgents,
|
|
107
109
|
ownedDomains,
|
|
110
|
+
ownedSystems,
|
|
108
111
|
ownedServices,
|
|
109
112
|
ownedEvents,
|
|
110
113
|
ownedCommands,
|
|
@@ -180,6 +180,7 @@ export const resourceToCollectionMap = {
|
|
|
180
180
|
command: 'commands',
|
|
181
181
|
query: 'queries',
|
|
182
182
|
domain: 'domains',
|
|
183
|
+
system: 'systems',
|
|
183
184
|
flow: 'flows',
|
|
184
185
|
channel: 'channels',
|
|
185
186
|
user: 'users',
|
|
@@ -198,6 +199,7 @@ export const collectionToResourceMap = {
|
|
|
198
199
|
commands: 'command',
|
|
199
200
|
queries: 'query',
|
|
200
201
|
domains: 'domain',
|
|
202
|
+
systems: 'system',
|
|
201
203
|
flows: 'flow',
|
|
202
204
|
channels: 'channel',
|
|
203
205
|
users: 'user',
|
|
@@ -14,10 +14,13 @@ import {
|
|
|
14
14
|
ArrowDownToLine,
|
|
15
15
|
ArrowRightLeft,
|
|
16
16
|
ArrowUpFromLine,
|
|
17
|
+
BotMessageSquare,
|
|
17
18
|
BookOpen,
|
|
18
19
|
BookText,
|
|
19
20
|
Box,
|
|
20
21
|
Boxes,
|
|
22
|
+
ClipboardCheck,
|
|
23
|
+
ClipboardList,
|
|
21
24
|
Code,
|
|
22
25
|
Database,
|
|
23
26
|
File,
|
|
@@ -25,12 +28,19 @@ import {
|
|
|
25
28
|
FileCode,
|
|
26
29
|
FileImage,
|
|
27
30
|
FileJson,
|
|
31
|
+
FileWarning,
|
|
28
32
|
Globe,
|
|
33
|
+
ListChecks,
|
|
29
34
|
Mail,
|
|
30
35
|
Package,
|
|
36
|
+
Radar,
|
|
37
|
+
Radio,
|
|
38
|
+
Route,
|
|
31
39
|
Search,
|
|
32
40
|
Server,
|
|
41
|
+
ShieldCheck,
|
|
33
42
|
ShoppingCart,
|
|
43
|
+
Sparkles,
|
|
34
44
|
SquareMousePointer,
|
|
35
45
|
Telescope,
|
|
36
46
|
Terminal,
|
|
@@ -47,10 +57,13 @@ export const LUCIDE_ICON_MAP: Record<string, LucideIcon> = {
|
|
|
47
57
|
ArrowDownToLine,
|
|
48
58
|
ArrowRightLeft,
|
|
49
59
|
ArrowUpFromLine,
|
|
60
|
+
BotMessageSquare,
|
|
50
61
|
BookOpen,
|
|
51
62
|
BookText,
|
|
52
63
|
Box,
|
|
53
64
|
Boxes,
|
|
65
|
+
ClipboardCheck,
|
|
66
|
+
ClipboardList,
|
|
54
67
|
Code,
|
|
55
68
|
Database,
|
|
56
69
|
File,
|
|
@@ -58,12 +71,19 @@ export const LUCIDE_ICON_MAP: Record<string, LucideIcon> = {
|
|
|
58
71
|
FileCode,
|
|
59
72
|
FileImage,
|
|
60
73
|
FileJson,
|
|
74
|
+
FileWarning,
|
|
61
75
|
Globe,
|
|
76
|
+
ListChecks,
|
|
62
77
|
Mail,
|
|
63
78
|
Package,
|
|
79
|
+
Radar,
|
|
80
|
+
Radio,
|
|
81
|
+
Route,
|
|
64
82
|
Search,
|
|
65
83
|
Server,
|
|
84
|
+
ShieldCheck,
|
|
66
85
|
ShoppingCart,
|
|
86
|
+
Sparkles,
|
|
67
87
|
SquareMousePointer,
|
|
68
88
|
Telescope,
|
|
69
89
|
Terminal,
|