@eventcatalog/core 2.12.2 → 2.13.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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/public/icons/protocols/kafka.svg +1 -0
- package/scripts/catalog-to-astro-content-directory.js +13 -1
- package/scripts/default-files-for-collections/channels.md +8 -0
- package/scripts/map-catalog-to-astro.js +1 -0
- package/src/components/DocsNavigation.astro +4 -4
- package/src/components/Header.astro +3 -3
- package/src/components/Lists/PillListFlat.tsx +19 -12
- package/src/components/Lists/ProtocolList.tsx +88 -0
- package/src/components/MDX/ChannelInformation/ChannelInformation.tsx +79 -0
- package/src/components/MDX/Flow/Flow.astro +3 -3
- package/src/components/MDX/NodeGraph/DownloadButton.tsx +3 -3
- package/src/components/MDX/NodeGraph/Edges/AnimatedMessageEdge.tsx +82 -0
- package/src/components/MDX/NodeGraph/NodeGraph.astro +24 -67
- package/src/components/MDX/NodeGraph/NodeGraph.tsx +188 -17
- package/src/components/MDX/NodeGraph/Nodes/Channel.tsx +133 -0
- package/src/components/MDX/components.tsx +2 -0
- package/src/components/Seo.astro +0 -2
- package/src/components/SideBars/CatalogResourcesSideBar/index.tsx +4 -13
- package/src/components/SideBars/ChannelSideBar.astro +117 -0
- package/src/components/SideBars/MessageSideBar.astro +13 -0
- package/src/content/config.ts +37 -0
- package/src/icons/protocols/WebSocket.svg +1 -0
- package/src/icons/protocols/amqp.svg +1 -0
- package/src/icons/protocols/eventbridge.svg +6 -0
- package/src/icons/protocols/googlepubsub.svg +1 -0
- package/src/icons/protocols/http.svg +1 -0
- package/src/icons/protocols/index.ts +15 -0
- package/src/icons/protocols/jms.svg +1 -0
- package/src/icons/protocols/kafka.svg +1 -0
- package/src/icons/protocols/mercure.svg +20 -0
- package/src/icons/protocols/mqtt.svg +17 -0
- package/src/icons/protocols/nats.svg +13 -0
- package/src/icons/protocols/pulsar.svg +4 -0
- package/src/icons/protocols/redis.svg +1 -0
- package/src/icons/protocols/sns.svg +6 -0
- package/src/icons/protocols/solace.svg +1 -0
- package/src/icons/protocols/sqs.svg +7 -0
- package/src/icons/protocols/ws.svg +1 -0
- package/src/layouts/DiscoverLayout.astro +3 -3
- package/src/layouts/VerticalSideBarLayout.astro +10 -5
- package/src/layouts/VisualiserLayout.astro +3 -3
- package/src/pages/discover/[type]/index.astro +3 -3
- package/src/pages/docs/[type]/[id]/[version]/asyncapi/index.astro +2 -2
- package/src/pages/docs/[type]/[id]/[version]/changelog/index.astro +2 -2
- package/src/pages/docs/[type]/[id]/[version]/index.astro +11 -4
- package/src/pages/docs/[type]/[id]/[version]/spec/index.astro +2 -2
- package/src/pages/docs/[type]/[id]/index.astro +17 -4
- package/src/pages/index.astro +3 -3
- package/src/pages/visualiser/[type]/[id]/[version]/index.astro +2 -2
- package/src/pages/visualiser/[type]/[id]/index.astro +2 -2
- package/src/remark-plugins/mermaid.ts +0 -1
- package/src/types/index.ts +2 -2
- package/src/utils/channels.ts +64 -0
- package/src/utils/collections/icons.ts +6 -0
- package/src/utils/commands.ts +6 -0
- package/src/utils/{config → eventcatalog-config}/catalog.ts +1 -1
- package/src/utils/events.ts +5 -0
- package/src/utils/{domains/node-graph.ts → node-graphs/domains-node-graph.ts} +2 -2
- package/src/utils/{flows/node-graph.ts → node-graphs/flows-node-graph.ts} +2 -2
- package/src/utils/node-graphs/message-node-graph.ts +216 -0
- package/src/utils/{services/node-graph.ts → node-graphs/services-node-graph.ts} +79 -54
- package/src/utils/node-graphs/utils/utils.ts +128 -0
- package/src/utils/{pages/pages.ts → page-loaders/page-data-loader.ts} +4 -2
- package/src/utils/queries.ts +5 -0
- package/tsconfig.json +2 -1
- package/src/remark-plugins/remark-modified-time.mjs +0 -9
- package/src/utils/commands/node-graph.ts +0 -144
- package/src/utils/events/node-graph.ts +0 -145
- package/src/utils/node-graph-utils/utils.ts +0 -29
- package/src/utils/queries/node-graph.ts +0 -144
- /package/src/pages/docs/[type]/[id]/[version]/spec/{styles.css → _styles.css} +0 -0
- /package/src/utils/{changelogs → collections}/changelogs.ts +0 -0
- /package/src/utils/{domains → collections}/domains.ts +0 -0
- /package/src/utils/{flows → collections}/flows.ts +0 -0
- /package/src/utils/{services → collections}/services.ts +0 -0
- /package/src/utils/{versions → collections}/versions.ts +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { getCollection, type CollectionEntry } from 'astro:content';
|
|
2
|
+
import { MarkerType, Position, type Edge, type Node } from 'reactflow';
|
|
3
|
+
import dagre from 'dagre';
|
|
4
|
+
import { getItemsFromCollectionByIdAndSemverOrLatest } from '@utils/collections/util';
|
|
5
|
+
import type { CollectionTypes } from '@types';
|
|
6
|
+
|
|
7
|
+
export const generateIdForNode = (node: CollectionEntry<CollectionTypes>) => {
|
|
8
|
+
return `${node.data.id}-${node.data.version}`;
|
|
9
|
+
};
|
|
10
|
+
export const generateIdForNodes = (nodes: any) => {
|
|
11
|
+
return nodes.map((node: any) => `${node.data.id}-${node.data.version}`).join('-');
|
|
12
|
+
};
|
|
13
|
+
export const generatedIdForEdge = (source: CollectionEntry<CollectionTypes>, target: CollectionEntry<CollectionTypes>) => {
|
|
14
|
+
return `${source.data.id}-${source.data.version}-${target.data.id}-${target.data.version}`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const calculatedNodes = (flow: dagre.graphlib.Graph, nodes: Node[]) => {
|
|
18
|
+
return nodes.map((node: any) => {
|
|
19
|
+
const { x, y } = flow.node(node.id);
|
|
20
|
+
return { ...node, position: { x, y } };
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// Creates a new dagre graph
|
|
25
|
+
export const createDagreGraph = ({ ranksep = 180, nodesep = 50, ...rest }: any) => {
|
|
26
|
+
const graph = new dagre.graphlib.Graph({ compound: true });
|
|
27
|
+
graph.setGraph({ rankdir: 'LR', ranksep, nodesep, ...rest });
|
|
28
|
+
graph.setDefaultEdgeLabel(() => ({}));
|
|
29
|
+
return graph;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const createEdge = (edgeOptions: Edge) => {
|
|
33
|
+
return {
|
|
34
|
+
label: 'subscribed by',
|
|
35
|
+
animated: false,
|
|
36
|
+
markerEnd: {
|
|
37
|
+
type: MarkerType.ArrowClosed,
|
|
38
|
+
width: 40,
|
|
39
|
+
height: 40,
|
|
40
|
+
},
|
|
41
|
+
style: {
|
|
42
|
+
strokeWidth: 1,
|
|
43
|
+
},
|
|
44
|
+
...edgeOptions,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const createNode = (values: Node): Node => {
|
|
49
|
+
return {
|
|
50
|
+
sourcePosition: Position.Right,
|
|
51
|
+
targetPosition: Position.Left,
|
|
52
|
+
...values,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const getChannelNodesAndEdges = ({
|
|
57
|
+
channels: channelsCollection,
|
|
58
|
+
channelsToRender,
|
|
59
|
+
source,
|
|
60
|
+
target,
|
|
61
|
+
channelToTargetLabel = 'sends from channel',
|
|
62
|
+
sourceToChannelLabel = 'sends to channel',
|
|
63
|
+
mode = 'full',
|
|
64
|
+
currentNodes = [],
|
|
65
|
+
}: {
|
|
66
|
+
channels: CollectionEntry<'channels'>[];
|
|
67
|
+
channelsToRender: { id: string; version: string }[];
|
|
68
|
+
source: CollectionEntry<CollectionTypes>;
|
|
69
|
+
target: CollectionEntry<CollectionTypes>;
|
|
70
|
+
channelToTargetLabel?: string;
|
|
71
|
+
sourceToChannelLabel?: string;
|
|
72
|
+
mode?: 'simple' | 'full';
|
|
73
|
+
currentNodes?: Node[];
|
|
74
|
+
}) => {
|
|
75
|
+
const nodes: Node[] = [];
|
|
76
|
+
const edges: Edge[] = [];
|
|
77
|
+
|
|
78
|
+
// Get the channels from the collection
|
|
79
|
+
const channels = channelsToRender
|
|
80
|
+
.map((channel) => getItemsFromCollectionByIdAndSemverOrLatest(channelsCollection, channel.id, channel.version)[0])
|
|
81
|
+
.filter((channel) => channel !== undefined);
|
|
82
|
+
|
|
83
|
+
channels.forEach((channel) => {
|
|
84
|
+
const channelId = generateIdForNodes([source, channel, target]);
|
|
85
|
+
|
|
86
|
+
// Need to check if the channel node is already in the graph
|
|
87
|
+
// if (!currentNodes.find((node) => node.id === channelId)) {
|
|
88
|
+
nodes.push(
|
|
89
|
+
createNode({
|
|
90
|
+
id: channelId,
|
|
91
|
+
data: { title: channel?.data.id, mode, channel, source, target },
|
|
92
|
+
position: { x: 0, y: 0 },
|
|
93
|
+
type: channel?.collection,
|
|
94
|
+
})
|
|
95
|
+
);
|
|
96
|
+
// }
|
|
97
|
+
|
|
98
|
+
// if the source (left node) is a service, use the target as the edge message
|
|
99
|
+
const edgeMessage = source.collection === 'services' ? target : source;
|
|
100
|
+
|
|
101
|
+
// Link from left to channel
|
|
102
|
+
edges.push(
|
|
103
|
+
createEdge({
|
|
104
|
+
// id: generatedIdForEdge(source, channel),
|
|
105
|
+
id: generateIdForNodes([source, channel, target]),
|
|
106
|
+
source: generateIdForNode(source),
|
|
107
|
+
target: channelId,
|
|
108
|
+
label: '',
|
|
109
|
+
// label: sourceToChannelLabel,
|
|
110
|
+
data: { message: edgeMessage },
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Link channel to service
|
|
115
|
+
edges.push(
|
|
116
|
+
createEdge({
|
|
117
|
+
// id: generatedIdForEdge(channel, target),
|
|
118
|
+
id: generateIdForNodes([channel, target, source]),
|
|
119
|
+
source: channelId,
|
|
120
|
+
target: generateIdForNode(target),
|
|
121
|
+
label: channelToTargetLabel,
|
|
122
|
+
data: { message: edgeMessage },
|
|
123
|
+
})
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
return { nodes, edges };
|
|
128
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { CollectionTypes, PageTypes } from '@types';
|
|
2
|
-
import {
|
|
2
|
+
import { getChannels } from '@utils/channels';
|
|
3
|
+
import { getDomains } from '@utils/collections/domains';
|
|
3
4
|
import { getCommands, getEvents } from '@utils/messages';
|
|
4
5
|
import { getQueries } from '@utils/queries';
|
|
5
|
-
import { getServices } from '@utils/
|
|
6
|
+
import { getServices } from '@utils/collections/services';
|
|
6
7
|
import type { CollectionEntry } from 'astro:content';
|
|
7
8
|
|
|
8
9
|
export const pageDataLoader: Record<PageTypes, () => Promise<CollectionEntry<CollectionTypes>[]>> = {
|
|
@@ -11,4 +12,5 @@ export const pageDataLoader: Record<PageTypes, () => Promise<CollectionEntry<Col
|
|
|
11
12
|
queries: getQueries,
|
|
12
13
|
services: getServices,
|
|
13
14
|
domains: getDomains,
|
|
15
|
+
channels: getChannels,
|
|
14
16
|
};
|
package/src/utils/queries.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const getQueries = async ({ getAllVersions = true }: Props = {}): Promise
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
const services = await getCollection('services');
|
|
26
|
+
const allChannels = await getCollection('channels');
|
|
26
27
|
|
|
27
28
|
return queries.map((query) => {
|
|
28
29
|
const { latestVersion, versions } = getVersionForCollectionItem(query, queries);
|
|
@@ -43,10 +44,14 @@ export const getQueries = async ({ getAllVersions = true }: Props = {}): Promise
|
|
|
43
44
|
})
|
|
44
45
|
);
|
|
45
46
|
|
|
47
|
+
const messageChannels = query.data.channels || [];
|
|
48
|
+
const channelsForQuery = allChannels.filter((c) => messageChannels.some((channel) => c.data.id === channel.id));
|
|
49
|
+
|
|
46
50
|
return {
|
|
47
51
|
...query,
|
|
48
52
|
data: {
|
|
49
53
|
...query.data,
|
|
54
|
+
messageChannels: channelsForQuery,
|
|
50
55
|
producers,
|
|
51
56
|
consumers,
|
|
52
57
|
versions,
|
package/tsconfig.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"baseUrl": ".",
|
|
6
6
|
"paths": {
|
|
7
7
|
"@config": ["./eventcatalog.config.js"],
|
|
8
|
-
"@eventcatalog": ["src/utils/config/catalog.ts"],
|
|
8
|
+
"@eventcatalog": ["src/utils/eventcatalog-config/catalog.ts"],
|
|
9
|
+
"@icons/*": ["src/icons/*"],
|
|
9
10
|
"@components/*": ["src/components/*"],
|
|
10
11
|
"@catalog/components/*": ["src/custom-defined-components/*"],
|
|
11
12
|
"@types": ["src/types/index.ts"],
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { execSync } from "child_process";
|
|
2
|
-
|
|
3
|
-
export function remarkModifiedTime() {
|
|
4
|
-
return function (_, file) {
|
|
5
|
-
const filepath = file.history[0];
|
|
6
|
-
const result = execSync(`git log -1 --pretty="format:%cI" "${filepath}"`);
|
|
7
|
-
file.data.astro.frontmatter.lastModified = result.toString();
|
|
8
|
-
};
|
|
9
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { findMatchingNodes } from '@utils/collections/util';
|
|
2
|
-
import { getCommands } from '@utils/commands';
|
|
3
|
-
import { calculatedNodes, createDagreGraph, generateIdForNode, generatedIdForEdge } from '@utils/node-graph-utils/utils';
|
|
4
|
-
import { type CollectionEntry } from 'astro:content';
|
|
5
|
-
import dagre from 'dagre';
|
|
6
|
-
import { MarkerType } from 'reactflow';
|
|
7
|
-
|
|
8
|
-
type DagreGraph = any;
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
id: string;
|
|
12
|
-
version: string;
|
|
13
|
-
defaultFlow?: DagreGraph;
|
|
14
|
-
mode?: 'simple' | 'full';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple' }: Props) => {
|
|
18
|
-
const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
|
|
19
|
-
const nodes = [] as any,
|
|
20
|
-
edges = [] as any;
|
|
21
|
-
|
|
22
|
-
const commands = await getCommands();
|
|
23
|
-
|
|
24
|
-
const command = commands.find((command) => command.data.id === id && command.data.version === version);
|
|
25
|
-
|
|
26
|
-
// Nothing found...
|
|
27
|
-
if (!command) {
|
|
28
|
-
return {
|
|
29
|
-
nodes: [],
|
|
30
|
-
edges: [],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const producers = (command.data.producers as CollectionEntry<'services'>[]) || [];
|
|
35
|
-
const consumers = (command.data.consumers as CollectionEntry<'services'>[]) || [];
|
|
36
|
-
|
|
37
|
-
// Track nodes that are both sent and received
|
|
38
|
-
const bothSentAndReceived = findMatchingNodes(producers, consumers);
|
|
39
|
-
|
|
40
|
-
if (producers && producers.length > 0) {
|
|
41
|
-
producers.forEach((producer, index) => {
|
|
42
|
-
nodes.push({
|
|
43
|
-
id: generateIdForNode(producer),
|
|
44
|
-
type: producer?.collection,
|
|
45
|
-
sourcePosition: 'right',
|
|
46
|
-
targetPosition: 'left',
|
|
47
|
-
data: { mode, service: producer },
|
|
48
|
-
position: { x: 250, y: 0 },
|
|
49
|
-
});
|
|
50
|
-
edges.push({
|
|
51
|
-
id: generatedIdForEdge(producer, command),
|
|
52
|
-
source: generateIdForNode(producer),
|
|
53
|
-
target: generateIdForNode(command),
|
|
54
|
-
type: 'smoothstep',
|
|
55
|
-
label: 'invokes',
|
|
56
|
-
animated: false,
|
|
57
|
-
markerEnd: {
|
|
58
|
-
type: MarkerType.ArrowClosed,
|
|
59
|
-
width: 40,
|
|
60
|
-
height: 40,
|
|
61
|
-
},
|
|
62
|
-
style: {
|
|
63
|
-
strokeWidth: 1,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// The service itself
|
|
70
|
-
nodes.push({
|
|
71
|
-
id: generateIdForNode(command),
|
|
72
|
-
sourcePosition: 'right',
|
|
73
|
-
targetPosition: 'left',
|
|
74
|
-
data: { mode, message: command },
|
|
75
|
-
position: { x: 0, y: 0 },
|
|
76
|
-
type: command.collection,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// The messages the service sends
|
|
80
|
-
consumers.forEach((consumer) => {
|
|
81
|
-
nodes.push({
|
|
82
|
-
id: generateIdForNode(consumer),
|
|
83
|
-
sourcePosition: 'right',
|
|
84
|
-
targetPosition: 'left',
|
|
85
|
-
data: { title: consumer?.data.id, mode, service: consumer },
|
|
86
|
-
position: { x: 0, y: 0 },
|
|
87
|
-
type: consumer?.collection,
|
|
88
|
-
});
|
|
89
|
-
edges.push({
|
|
90
|
-
id: generatedIdForEdge(command, consumer),
|
|
91
|
-
source: generateIdForNode(command),
|
|
92
|
-
target: generateIdForNode(consumer),
|
|
93
|
-
type: 'smoothstep',
|
|
94
|
-
label: 'accepts',
|
|
95
|
-
animated: false,
|
|
96
|
-
markerEnd: {
|
|
97
|
-
type: MarkerType.ArrowClosed,
|
|
98
|
-
width: 40,
|
|
99
|
-
height: 40,
|
|
100
|
-
},
|
|
101
|
-
style: {
|
|
102
|
-
strokeWidth: 1,
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Handle nodes that are both sent and received
|
|
108
|
-
bothSentAndReceived.forEach((message) => {
|
|
109
|
-
if (message) {
|
|
110
|
-
edges.push({
|
|
111
|
-
id: generatedIdForEdge(command, message) + '-both',
|
|
112
|
-
source: generateIdForNode(command),
|
|
113
|
-
target: generateIdForNode(message),
|
|
114
|
-
type: 'smoothstep',
|
|
115
|
-
label: `publishes and subscribes`,
|
|
116
|
-
animated: false,
|
|
117
|
-
markerEnd: {
|
|
118
|
-
type: MarkerType.ArrowClosed,
|
|
119
|
-
width: 40,
|
|
120
|
-
height: 40,
|
|
121
|
-
},
|
|
122
|
-
style: {
|
|
123
|
-
strokeWidth: 1,
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
nodes.forEach((node: any) => {
|
|
130
|
-
flow.setNode(node.id, { width: 150, height: 100 });
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
edges.forEach((edge: any) => {
|
|
134
|
-
flow.setEdge(edge.source, edge.target);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Render the diagram in memory getting hte X and Y
|
|
138
|
-
dagre.layout(flow);
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
nodes: calculatedNodes(flow, nodes),
|
|
142
|
-
edges: edges,
|
|
143
|
-
};
|
|
144
|
-
};
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
// import { getColor } from '@utils/colors';
|
|
2
|
-
import { getEvents } from '@utils/events';
|
|
3
|
-
import type { CollectionEntry } from 'astro:content';
|
|
4
|
-
import dagre from 'dagre';
|
|
5
|
-
import { calculatedNodes, createDagreGraph, generatedIdForEdge, generateIdForNode } from '../node-graph-utils/utils';
|
|
6
|
-
import { MarkerType } from 'reactflow';
|
|
7
|
-
import { findMatchingNodes } from '@utils/collections/util';
|
|
8
|
-
|
|
9
|
-
type DagreGraph = any;
|
|
10
|
-
|
|
11
|
-
interface Props {
|
|
12
|
-
id: string;
|
|
13
|
-
version: string;
|
|
14
|
-
defaultFlow?: DagreGraph;
|
|
15
|
-
mode?: 'simple' | 'full';
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple' }: Props) => {
|
|
19
|
-
const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
|
|
20
|
-
const nodes = [] as any,
|
|
21
|
-
edges = [] as any;
|
|
22
|
-
|
|
23
|
-
const events = await getEvents();
|
|
24
|
-
|
|
25
|
-
const event = events.find((event) => event.data.id === id && event.data.version === version);
|
|
26
|
-
|
|
27
|
-
// Nothing found...
|
|
28
|
-
if (!event) {
|
|
29
|
-
return {
|
|
30
|
-
nodes: [],
|
|
31
|
-
edges: [],
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const producers = (event.data.producers as CollectionEntry<'services'>[]) || [];
|
|
36
|
-
const consumers = (event.data.consumers as CollectionEntry<'services'>[]) || [];
|
|
37
|
-
|
|
38
|
-
// Track nodes that are both sent and received
|
|
39
|
-
const bothSentAndReceived = findMatchingNodes(producers, consumers);
|
|
40
|
-
|
|
41
|
-
if (producers && producers.length > 0) {
|
|
42
|
-
producers.forEach((producer) => {
|
|
43
|
-
nodes.push({
|
|
44
|
-
id: generateIdForNode(producer),
|
|
45
|
-
type: producer?.collection,
|
|
46
|
-
sourcePosition: 'right',
|
|
47
|
-
targetPosition: 'left',
|
|
48
|
-
data: { mode, service: producer, showTarget: false },
|
|
49
|
-
position: { x: 250, y: 0 },
|
|
50
|
-
});
|
|
51
|
-
edges.push({
|
|
52
|
-
id: generatedIdForEdge(producer, event),
|
|
53
|
-
source: generateIdForNode(producer),
|
|
54
|
-
target: generateIdForNode(event),
|
|
55
|
-
type: 'smoothstep',
|
|
56
|
-
label: 'publishes event',
|
|
57
|
-
animated: false,
|
|
58
|
-
markerEnd: {
|
|
59
|
-
type: MarkerType.ArrowClosed,
|
|
60
|
-
width: 40,
|
|
61
|
-
height: 40,
|
|
62
|
-
},
|
|
63
|
-
style: {
|
|
64
|
-
strokeWidth: 1,
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// The event itself
|
|
71
|
-
nodes.push({
|
|
72
|
-
id: generateIdForNode(event),
|
|
73
|
-
sourcePosition: 'right',
|
|
74
|
-
targetPosition: 'left',
|
|
75
|
-
data: { mode, message: event, showTarget: producers.length > 0, showSource: consumers.length > 0 },
|
|
76
|
-
position: { x: 0, y: 0 },
|
|
77
|
-
type: event.collection,
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// The messages the service sends
|
|
81
|
-
consumers.forEach((consumer) => {
|
|
82
|
-
nodes.push({
|
|
83
|
-
id: generateIdForNode(consumer),
|
|
84
|
-
sourcePosition: 'right',
|
|
85
|
-
targetPosition: 'left',
|
|
86
|
-
data: { title: consumer?.data.id, mode, service: consumer, showSource: false },
|
|
87
|
-
position: { x: 0, y: 0 },
|
|
88
|
-
type: consumer?.collection,
|
|
89
|
-
});
|
|
90
|
-
edges.push({
|
|
91
|
-
id: generatedIdForEdge(event, consumer),
|
|
92
|
-
source: generateIdForNode(event),
|
|
93
|
-
target: generateIdForNode(consumer),
|
|
94
|
-
type: 'smoothstep',
|
|
95
|
-
label: 'subscribed by',
|
|
96
|
-
animated: false,
|
|
97
|
-
markerEnd: {
|
|
98
|
-
type: MarkerType.ArrowClosed,
|
|
99
|
-
width: 40,
|
|
100
|
-
height: 40,
|
|
101
|
-
},
|
|
102
|
-
style: {
|
|
103
|
-
strokeWidth: 1,
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
// Handle messages that are both sent and received
|
|
109
|
-
bothSentAndReceived.forEach((message) => {
|
|
110
|
-
if (message) {
|
|
111
|
-
edges.push({
|
|
112
|
-
id: generatedIdForEdge(event, message) + '-both',
|
|
113
|
-
source: generateIdForNode(event),
|
|
114
|
-
target: generateIdForNode(message),
|
|
115
|
-
type: 'smoothstep',
|
|
116
|
-
label: `publishes and subscribes`,
|
|
117
|
-
animated: false,
|
|
118
|
-
markerEnd: {
|
|
119
|
-
type: MarkerType.ArrowClosed,
|
|
120
|
-
width: 40,
|
|
121
|
-
height: 40,
|
|
122
|
-
},
|
|
123
|
-
style: {
|
|
124
|
-
strokeWidth: 1,
|
|
125
|
-
},
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
nodes.forEach((node: any) => {
|
|
131
|
-
flow.setNode(node.id, { width: 150, height: 100 });
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
edges.forEach((edge: any) => {
|
|
135
|
-
flow.setEdge(edge.source, edge.target);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// Render the diagram in memory getting hte X and Y
|
|
139
|
-
dagre.layout(flow);
|
|
140
|
-
|
|
141
|
-
return {
|
|
142
|
-
nodes: calculatedNodes(flow, nodes),
|
|
143
|
-
edges: edges,
|
|
144
|
-
};
|
|
145
|
-
};
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { CollectionEntry } from 'astro:content';
|
|
2
|
-
import type { Node } from 'reactflow';
|
|
3
|
-
import dagre from 'dagre';
|
|
4
|
-
|
|
5
|
-
export const generateIdForNode = (node: CollectionEntry<'events' | 'services' | 'commands' | 'queries'>) => {
|
|
6
|
-
return `${node.data.id}-${node.data.version}`;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const generatedIdForEdge = (
|
|
10
|
-
source: CollectionEntry<'events' | 'services' | 'commands' | 'queries'>,
|
|
11
|
-
target: CollectionEntry<'events' | 'services' | 'commands' | 'queries'>
|
|
12
|
-
) => {
|
|
13
|
-
return `${source.data.id}-${source.data.version}-${target.data.id}-${target.data.version}`;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const calculatedNodes = (flow: dagre.graphlib.Graph, nodes: Node[]) => {
|
|
17
|
-
return nodes.map((node: any) => {
|
|
18
|
-
const { x, y } = flow.node(node.id);
|
|
19
|
-
return { ...node, position: { x, y } };
|
|
20
|
-
});
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
// Creates a new dagre graph
|
|
24
|
-
export const createDagreGraph = ({ ranksep = 180, nodesep = 50, ...rest }: any) => {
|
|
25
|
-
const graph = new dagre.graphlib.Graph({ compound: true });
|
|
26
|
-
graph.setGraph({ rankdir: 'LR', ranksep, nodesep, ...rest });
|
|
27
|
-
graph.setDefaultEdgeLabel(() => ({}));
|
|
28
|
-
return graph;
|
|
29
|
-
};
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { getQueries } from '@utils/queries';
|
|
2
|
-
import type { CollectionEntry } from 'astro:content';
|
|
3
|
-
import dagre from 'dagre';
|
|
4
|
-
import { calculatedNodes, createDagreGraph, generatedIdForEdge, generateIdForNode } from '../node-graph-utils/utils';
|
|
5
|
-
import { MarkerType } from 'reactflow';
|
|
6
|
-
import { findMatchingNodes } from '@utils/collections/util';
|
|
7
|
-
|
|
8
|
-
type DagreGraph = any;
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
id: string;
|
|
12
|
-
version: string;
|
|
13
|
-
defaultFlow?: DagreGraph;
|
|
14
|
-
mode?: 'simple' | 'full';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple' }: Props) => {
|
|
18
|
-
const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
|
|
19
|
-
const nodes = [] as any,
|
|
20
|
-
edges = [] as any;
|
|
21
|
-
|
|
22
|
-
const queries = await getQueries();
|
|
23
|
-
|
|
24
|
-
const query = queries.find((query) => query.data.id === id && query.data.version === version);
|
|
25
|
-
|
|
26
|
-
// Nothing found...
|
|
27
|
-
if (!query) {
|
|
28
|
-
return {
|
|
29
|
-
nodes: [],
|
|
30
|
-
edges: [],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const producers = (query.data.producers as CollectionEntry<'services'>[]) || [];
|
|
35
|
-
const consumers = (query.data.consumers as CollectionEntry<'services'>[]) || [];
|
|
36
|
-
|
|
37
|
-
// Track nodes that are both sent and received
|
|
38
|
-
const bothSentAndReceived = findMatchingNodes(producers, consumers);
|
|
39
|
-
|
|
40
|
-
if (producers && producers.length > 0) {
|
|
41
|
-
producers.forEach((producer) => {
|
|
42
|
-
nodes.push({
|
|
43
|
-
id: generateIdForNode(producer),
|
|
44
|
-
type: producer?.collection,
|
|
45
|
-
sourcePosition: 'right',
|
|
46
|
-
targetPosition: 'left',
|
|
47
|
-
data: { mode, service: producer },
|
|
48
|
-
position: { x: 250, y: 0 },
|
|
49
|
-
});
|
|
50
|
-
edges.push({
|
|
51
|
-
id: generatedIdForEdge(producer, query),
|
|
52
|
-
source: generateIdForNode(producer),
|
|
53
|
-
target: generateIdForNode(query),
|
|
54
|
-
type: 'smoothstep',
|
|
55
|
-
label: 'requests',
|
|
56
|
-
animated: false,
|
|
57
|
-
markerEnd: {
|
|
58
|
-
type: MarkerType.ArrowClosed,
|
|
59
|
-
width: 40,
|
|
60
|
-
height: 40,
|
|
61
|
-
},
|
|
62
|
-
style: {
|
|
63
|
-
strokeWidth: 1,
|
|
64
|
-
},
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// The query itself
|
|
70
|
-
nodes.push({
|
|
71
|
-
id: generateIdForNode(query),
|
|
72
|
-
sourcePosition: 'right',
|
|
73
|
-
targetPosition: 'left',
|
|
74
|
-
data: { mode, message: query },
|
|
75
|
-
position: { x: 0, y: 0 },
|
|
76
|
-
type: query.collection,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// The messages the service sends
|
|
80
|
-
consumers.forEach((consumer) => {
|
|
81
|
-
nodes.push({
|
|
82
|
-
id: generateIdForNode(consumer),
|
|
83
|
-
sourcePosition: 'right',
|
|
84
|
-
targetPosition: 'left',
|
|
85
|
-
data: { title: consumer?.data.id, mode, service: consumer },
|
|
86
|
-
position: { x: 0, y: 0 },
|
|
87
|
-
type: consumer?.collection,
|
|
88
|
-
});
|
|
89
|
-
edges.push({
|
|
90
|
-
id: generatedIdForEdge(query, consumer),
|
|
91
|
-
source: generateIdForNode(query),
|
|
92
|
-
target: generateIdForNode(consumer),
|
|
93
|
-
type: 'smoothstep',
|
|
94
|
-
label: 'accepts',
|
|
95
|
-
animated: false,
|
|
96
|
-
markerEnd: {
|
|
97
|
-
type: MarkerType.ArrowClosed,
|
|
98
|
-
width: 40,
|
|
99
|
-
height: 40,
|
|
100
|
-
},
|
|
101
|
-
style: {
|
|
102
|
-
strokeWidth: 1,
|
|
103
|
-
},
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Handle nodes that are both sent and received
|
|
108
|
-
bothSentAndReceived.forEach((message) => {
|
|
109
|
-
if (message) {
|
|
110
|
-
edges.push({
|
|
111
|
-
id: generatedIdForEdge(query, message) + '-both',
|
|
112
|
-
source: generateIdForNode(query),
|
|
113
|
-
target: generateIdForNode(message),
|
|
114
|
-
type: 'smoothstep',
|
|
115
|
-
label: `publishes and subscribes`,
|
|
116
|
-
animated: false,
|
|
117
|
-
markerEnd: {
|
|
118
|
-
type: MarkerType.ArrowClosed,
|
|
119
|
-
width: 40,
|
|
120
|
-
height: 40,
|
|
121
|
-
},
|
|
122
|
-
style: {
|
|
123
|
-
strokeWidth: 1,
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
nodes.forEach((node: any) => {
|
|
130
|
-
flow.setNode(node.id, { width: 150, height: 100 });
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
edges.forEach((edge: any) => {
|
|
134
|
-
flow.setEdge(edge.source, edge.target);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
// Render the diagram in memory getting hte X and Y
|
|
138
|
-
dagre.layout(flow);
|
|
139
|
-
|
|
140
|
-
return {
|
|
141
|
-
nodes: calculatedNodes(flow, nodes),
|
|
142
|
-
edges: edges,
|
|
143
|
-
};
|
|
144
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|