@eventcatalog/core 3.12.7 → 3.12.9-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/{chunk-RZOSO7BH.js → chunk-2UUS3AQ2.js} +1 -1
- package/dist/{chunk-UFF5Q7GJ.js → chunk-EDX2LGRV.js} +1 -1
- package/dist/{chunk-2EFYBMLH.js → chunk-RJOB6XEC.js} +1 -1
- package/dist/{chunk-YO6IQXB3.js → chunk-V7YMKA4P.js} +1 -1
- package/dist/{chunk-PLQAZDJI.js → chunk-WTCJKTEF.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +1 -1
- package/dist/eventcatalog.js +5 -5
- 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/src/components/MDX/Design/Design.astro +2 -2
- package/eventcatalog/src/components/MDX/EntityMap/EntityMap.astro +2 -2
- package/eventcatalog/src/components/MDX/Flow/Flow.astro +2 -2
- package/eventcatalog/src/components/MDX/NodeGraph/AstroNodeGraph.tsx +104 -0
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.astro +2 -2
- package/eventcatalog/src/components/MDX/NodeGraph/README.md +85 -0
- package/eventcatalog/src/pages/visualiser/designs/[id]/index.astro +2 -2
- package/eventcatalog/src/utils/node-graphs/container-node-graph.ts +66 -17
- package/eventcatalog/src/utils/node-graphs/data-products-node-graph.ts +14 -5
- package/eventcatalog/src/utils/node-graphs/domains-node-graph.ts +1 -1
- package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +133 -18
- package/eventcatalog/src/utils/node-graphs/services-node-graph.ts +36 -14
- package/eventcatalog/src/utils/node-graphs/utils/utils.ts +115 -4
- package/package.json +4 -4
- package/eventcatalog/src/components/MDX/NodeGraph/DownloadButton.tsx +0 -62
- package/eventcatalog/src/components/MDX/NodeGraph/Edges/AnimatedMessageEdge.tsx +0 -110
- package/eventcatalog/src/components/MDX/NodeGraph/Edges/FlowEdge.tsx +0 -96
- package/eventcatalog/src/components/MDX/NodeGraph/Edges/MultilineEdgeLabel.tsx +0 -52
- package/eventcatalog/src/components/MDX/NodeGraph/FocusMode/FocusModeContent.tsx +0 -294
- package/eventcatalog/src/components/MDX/NodeGraph/FocusMode/FocusModeNodeActions.tsx +0 -92
- package/eventcatalog/src/components/MDX/NodeGraph/FocusMode/FocusModePlaceholder.tsx +0 -26
- package/eventcatalog/src/components/MDX/NodeGraph/FocusMode/utils.ts +0 -163
- package/eventcatalog/src/components/MDX/NodeGraph/FocusModeModal.tsx +0 -99
- package/eventcatalog/src/components/MDX/NodeGraph/MermaidView.tsx +0 -242
- package/eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx +0 -1181
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Actor.tsx +0 -46
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Channel.tsx +0 -55
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Command.tsx +0 -27
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Custom.tsx +0 -159
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Data.tsx +0 -63
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/DataProduct.tsx +0 -132
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Domain.tsx +0 -155
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Entity.tsx +0 -154
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Event.tsx +0 -29
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/ExternalSystem.tsx +0 -79
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/ExternalSystem2.tsx +0 -24
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Flow.tsx +0 -107
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/MessageContextMenu.tsx +0 -63
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Query.tsx +0 -28
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Service.tsx +0 -127
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/Step.tsx +0 -64
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/User.tsx +0 -76
- package/eventcatalog/src/components/MDX/NodeGraph/Nodes/View.tsx +0 -24
- package/eventcatalog/src/components/MDX/NodeGraph/StepWalkthrough.tsx +0 -296
- package/eventcatalog/src/components/MDX/NodeGraph/StudioModal.tsx +0 -129
- package/eventcatalog/src/components/MDX/NodeGraph/VisualiserSearch.tsx +0 -258
- package/eventcatalog/src/components/MDX/NodeGraph/VisualizerDropdownContent.tsx +0 -313
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Handle, Position, type XYPosition } from '@xyflow/react';
|
|
2
|
-
|
|
3
|
-
import { nodeComponents } from '@eventcatalog/visualizer';
|
|
4
|
-
const ActorComponent = nodeComponents.actor;
|
|
5
|
-
|
|
6
|
-
interface Data {
|
|
7
|
-
data: {
|
|
8
|
-
actor: {
|
|
9
|
-
name: string;
|
|
10
|
-
summary: string;
|
|
11
|
-
};
|
|
12
|
-
mode: 'simple' | 'full';
|
|
13
|
-
};
|
|
14
|
-
type: 'actor';
|
|
15
|
-
id: string;
|
|
16
|
-
position: XYPosition;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default function ActorNode(props: Data) {
|
|
20
|
-
const componentData = {
|
|
21
|
-
...props,
|
|
22
|
-
data: {
|
|
23
|
-
...props.data,
|
|
24
|
-
name: props.data.actor.name,
|
|
25
|
-
summary: props.data.actor.summary,
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<div className="relative">
|
|
31
|
-
<Handle
|
|
32
|
-
type="target"
|
|
33
|
-
position={Position.Left}
|
|
34
|
-
style={{ width: 10, height: 10, background: 'orange', zIndex: 10 }}
|
|
35
|
-
className="bg-gray-500"
|
|
36
|
-
/>
|
|
37
|
-
<Handle
|
|
38
|
-
type="source"
|
|
39
|
-
position={Position.Right}
|
|
40
|
-
style={{ width: 10, height: 10, background: 'orange', zIndex: 10 }}
|
|
41
|
-
className="bg-gray-500"
|
|
42
|
-
/>
|
|
43
|
-
<ActorComponent {...componentData} />
|
|
44
|
-
</div>
|
|
45
|
-
);
|
|
46
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { Handle, Position } from '@xyflow/react';
|
|
2
|
-
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
3
|
-
import { buildUrl } from '@utils/url-builder';
|
|
4
|
-
|
|
5
|
-
import { nodeComponents, type ChannelNode } from '@eventcatalog/visualizer';
|
|
6
|
-
const ChannelComponent = nodeComponents.channel;
|
|
7
|
-
|
|
8
|
-
export default function ChannelNode(props: ChannelNode) {
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
const { id, version } = props.data.channel;
|
|
11
|
-
|
|
12
|
-
return (
|
|
13
|
-
<ContextMenu.Root>
|
|
14
|
-
<ContextMenu.Trigger>
|
|
15
|
-
<div className="relative">
|
|
16
|
-
<Handle
|
|
17
|
-
type="target"
|
|
18
|
-
position={Position.Left}
|
|
19
|
-
style={{ width: 10, height: 10, background: 'green', zIndex: 10 }}
|
|
20
|
-
className="bg-gray-500"
|
|
21
|
-
/>
|
|
22
|
-
<Handle
|
|
23
|
-
type="source"
|
|
24
|
-
position={Position.Right}
|
|
25
|
-
style={{ width: 10, height: 10, background: 'green', zIndex: 10 }}
|
|
26
|
-
className="bg-gray-500"
|
|
27
|
-
/>
|
|
28
|
-
<ChannelComponent {...props} />
|
|
29
|
-
</div>
|
|
30
|
-
</ContextMenu.Trigger>
|
|
31
|
-
<ContextMenu.Portal>
|
|
32
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
33
|
-
<ContextMenu.Item
|
|
34
|
-
asChild
|
|
35
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
36
|
-
>
|
|
37
|
-
<a href={buildUrl(`/docs/channels/${id}/${version}`)}>Read documentation</a>
|
|
38
|
-
</ContextMenu.Item>
|
|
39
|
-
<ContextMenu.Separator className="h-[1px] bg-gray-200 m-1" />
|
|
40
|
-
|
|
41
|
-
<ContextMenu.Item asChild>
|
|
42
|
-
<a
|
|
43
|
-
href={buildUrl(`/docs/channels/${id}/${version}/changelog`)}
|
|
44
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
45
|
-
target="_blank"
|
|
46
|
-
rel="noopener noreferrer"
|
|
47
|
-
>
|
|
48
|
-
Read changelog
|
|
49
|
-
</a>
|
|
50
|
-
</ContextMenu.Item>
|
|
51
|
-
</ContextMenu.Content>
|
|
52
|
-
</ContextMenu.Portal>
|
|
53
|
-
</ContextMenu.Root>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Handle, Position } from '@xyflow/react';
|
|
2
|
-
import MessageContextMenu from './MessageContextMenu';
|
|
3
|
-
|
|
4
|
-
import { nodeComponents, type CommandNode } from '@eventcatalog/visualizer';
|
|
5
|
-
const CommandComponent = nodeComponents.command;
|
|
6
|
-
|
|
7
|
-
export default function CommandNode(props: CommandNode) {
|
|
8
|
-
return (
|
|
9
|
-
<MessageContextMenu message={props.data.message as any} messageType="commands">
|
|
10
|
-
<div className="relative">
|
|
11
|
-
<Handle
|
|
12
|
-
type="target"
|
|
13
|
-
position={Position.Left}
|
|
14
|
-
style={{ width: 10, height: 10, background: 'blue', zIndex: 10 }}
|
|
15
|
-
className="bg-blue-500"
|
|
16
|
-
/>
|
|
17
|
-
<Handle
|
|
18
|
-
type="source"
|
|
19
|
-
position={Position.Right}
|
|
20
|
-
style={{ width: 10, height: 10, background: 'blue', zIndex: 10 }}
|
|
21
|
-
className="bg-blue-500"
|
|
22
|
-
/>
|
|
23
|
-
<CommandComponent {...props} />
|
|
24
|
-
</div>
|
|
25
|
-
</MessageContextMenu>
|
|
26
|
-
);
|
|
27
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { Handle } from '@xyflow/react';
|
|
2
|
-
import * as Icons from '@heroicons/react/24/solid';
|
|
3
|
-
import type { ComponentType } from 'react';
|
|
4
|
-
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
5
|
-
import * as Tooltip from '@radix-ui/react-tooltip';
|
|
6
|
-
|
|
7
|
-
type MenuItem = {
|
|
8
|
-
label: string;
|
|
9
|
-
url?: string;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
interface Data {
|
|
13
|
-
title: string;
|
|
14
|
-
label: string;
|
|
15
|
-
bgColor: string;
|
|
16
|
-
color: string;
|
|
17
|
-
mode: 'simple' | 'full';
|
|
18
|
-
step: { id: string; title: string; summary: string; name: string; actor: { name: string } };
|
|
19
|
-
showTarget?: boolean;
|
|
20
|
-
showSource?: boolean;
|
|
21
|
-
custom: {
|
|
22
|
-
icon?: string;
|
|
23
|
-
type?: string;
|
|
24
|
-
title?: string;
|
|
25
|
-
summary?: string;
|
|
26
|
-
url?: string;
|
|
27
|
-
color?: string;
|
|
28
|
-
properties?: Record<string, string>;
|
|
29
|
-
menu?: MenuItem[];
|
|
30
|
-
height?: number;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function classNames(...classes: any) {
|
|
35
|
-
return classes.filter(Boolean).join(' ');
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export default function UserNode({ data, sourcePosition, targetPosition }: any) {
|
|
39
|
-
const { mode, step, custom: customProps } = data as Data;
|
|
40
|
-
|
|
41
|
-
const {
|
|
42
|
-
color = 'blue',
|
|
43
|
-
title = 'Custom',
|
|
44
|
-
icon = 'UserIcon',
|
|
45
|
-
type = 'custom',
|
|
46
|
-
summary = '',
|
|
47
|
-
url = '',
|
|
48
|
-
properties = {},
|
|
49
|
-
menu = [],
|
|
50
|
-
height = 5,
|
|
51
|
-
} = customProps;
|
|
52
|
-
|
|
53
|
-
const IconComponent: ComponentType<{ className?: string }> | undefined = Icons[icon as keyof typeof Icons];
|
|
54
|
-
|
|
55
|
-
const { actor: { name } = {} } = step;
|
|
56
|
-
|
|
57
|
-
const isLongType = type && type.length > 10;
|
|
58
|
-
const displayType = isLongType ? `${type.substring(0, 10)}...` : type;
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<ContextMenu.Root>
|
|
62
|
-
<ContextMenu.Trigger>
|
|
63
|
-
<div
|
|
64
|
-
className={classNames(`w-full rounded-md border flex justify-start bg-white text-black border-${color}-400`)}
|
|
65
|
-
style={{ minHeight: mode === 'full' ? `${height}em` : '2em' }}
|
|
66
|
-
>
|
|
67
|
-
<div
|
|
68
|
-
className={classNames(
|
|
69
|
-
`bg-gradient-to-b from-${color}-400 to-${color}-600 relative flex items-center w-5 justify-center rounded-l-sm text-orange-100-500`,
|
|
70
|
-
`border-r-[1px] border-${color}`
|
|
71
|
-
)}
|
|
72
|
-
>
|
|
73
|
-
<IconComponent className="w-4 h-4 opacity-90 text-white absolute top-1 " />
|
|
74
|
-
{mode === 'full' && (
|
|
75
|
-
<Tooltip.Provider>
|
|
76
|
-
<Tooltip.Root>
|
|
77
|
-
<Tooltip.Trigger asChild>
|
|
78
|
-
<span className="rotate -rotate-90 w-1/2 text-center absolute bottom-1 text-[9px] text-white font-bold uppercase tracking-[3px] ">
|
|
79
|
-
{displayType}
|
|
80
|
-
</span>
|
|
81
|
-
</Tooltip.Trigger>
|
|
82
|
-
{isLongType && (
|
|
83
|
-
<Tooltip.Portal>
|
|
84
|
-
<Tooltip.Content
|
|
85
|
-
className="bg-slate-800 text-white rounded px-2 py-1 text-xs shadow-md z-50"
|
|
86
|
-
side="right"
|
|
87
|
-
sideOffset={5}
|
|
88
|
-
>
|
|
89
|
-
{type}
|
|
90
|
-
<Tooltip.Arrow className="fill-slate-800" />
|
|
91
|
-
</Tooltip.Content>
|
|
92
|
-
</Tooltip.Portal>
|
|
93
|
-
)}
|
|
94
|
-
</Tooltip.Root>
|
|
95
|
-
</Tooltip.Provider>
|
|
96
|
-
)}
|
|
97
|
-
</div>
|
|
98
|
-
<div className="p-1 min-w-60 max-w-[min-content]">
|
|
99
|
-
{targetPosition && <Handle type="target" position={targetPosition} />}
|
|
100
|
-
{sourcePosition && <Handle type="source" position={sourcePosition} />}
|
|
101
|
-
|
|
102
|
-
{(!summary || mode !== 'full') && (
|
|
103
|
-
<div className="h-full ">
|
|
104
|
-
<span className="text-sm font-bold block pb-0.5 w-full">{title}</span>
|
|
105
|
-
</div>
|
|
106
|
-
)}
|
|
107
|
-
|
|
108
|
-
{summary && mode === 'full' && (
|
|
109
|
-
<div>
|
|
110
|
-
<div className={classNames(mode === 'full' ? `border-b border-gray-200` : '')}>
|
|
111
|
-
<span className="text-xs font-bold block pb-0.5">{title}</span>
|
|
112
|
-
</div>
|
|
113
|
-
{mode === 'full' && (
|
|
114
|
-
<div className="divide-y divide-gray-200 ">
|
|
115
|
-
<div className="leading-3 py-1">
|
|
116
|
-
<span className="text-[8px] font-light">{summary}</span>
|
|
117
|
-
</div>
|
|
118
|
-
{properties && (
|
|
119
|
-
<div className="grid grid-cols-2 gap-x-4 py-1">
|
|
120
|
-
{Object.entries(properties).map(([key, value]) => (
|
|
121
|
-
<span key={key} className="text-xs" style={{ fontSize: '0.2em' }}>
|
|
122
|
-
{key}:{' '}
|
|
123
|
-
{typeof value === 'string' && value.startsWith('http') ? (
|
|
124
|
-
<a href={value} target="_blank" rel="noopener noreferrer" className="text-blue-500 underline">
|
|
125
|
-
{value}
|
|
126
|
-
</a>
|
|
127
|
-
) : (
|
|
128
|
-
value
|
|
129
|
-
)}
|
|
130
|
-
</span>
|
|
131
|
-
))}
|
|
132
|
-
</div>
|
|
133
|
-
)}
|
|
134
|
-
</div>
|
|
135
|
-
)}
|
|
136
|
-
</div>
|
|
137
|
-
)}
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</ContextMenu.Trigger>
|
|
141
|
-
{menu?.length > 0 && (
|
|
142
|
-
<ContextMenu.Portal>
|
|
143
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
144
|
-
{menu?.map((item) => {
|
|
145
|
-
return (
|
|
146
|
-
<ContextMenu.Item
|
|
147
|
-
asChild
|
|
148
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
149
|
-
>
|
|
150
|
-
<a href={item.url}>{item.label}</a>
|
|
151
|
-
</ContextMenu.Item>
|
|
152
|
-
);
|
|
153
|
-
})}
|
|
154
|
-
</ContextMenu.Content>
|
|
155
|
-
</ContextMenu.Portal>
|
|
156
|
-
)}
|
|
157
|
-
</ContextMenu.Root>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { Handle, Position } from '@xyflow/react';
|
|
2
|
-
|
|
3
|
-
import { nodeComponents, type DataNode } from '@eventcatalog/visualizer';
|
|
4
|
-
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
5
|
-
import { buildUrl } from '@utils/url-builder';
|
|
6
|
-
const DataComponent = nodeComponents.data;
|
|
7
|
-
|
|
8
|
-
interface Data {
|
|
9
|
-
data: {
|
|
10
|
-
data: {
|
|
11
|
-
id: string;
|
|
12
|
-
version: string;
|
|
13
|
-
name: string;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export default function DataNode(props: Data) {
|
|
19
|
-
const { id, version, name } = props.data.data;
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<ContextMenu.Root>
|
|
23
|
-
<ContextMenu.Trigger>
|
|
24
|
-
<div className="relative">
|
|
25
|
-
<Handle
|
|
26
|
-
type="target"
|
|
27
|
-
position={Position.Left}
|
|
28
|
-
style={{ width: 10, height: 10, background: 'blue', zIndex: 10 }}
|
|
29
|
-
className="bg-gray-500"
|
|
30
|
-
/>
|
|
31
|
-
<Handle
|
|
32
|
-
type="source"
|
|
33
|
-
position={Position.Right}
|
|
34
|
-
style={{ width: 10, height: 10, background: 'blue', zIndex: 10 }}
|
|
35
|
-
className="bg-gray-500"
|
|
36
|
-
/>
|
|
37
|
-
<DataComponent {...(props as any)} />
|
|
38
|
-
</div>
|
|
39
|
-
</ContextMenu.Trigger>
|
|
40
|
-
<ContextMenu.Portal>
|
|
41
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
42
|
-
<ContextMenu.Item
|
|
43
|
-
asChild
|
|
44
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
45
|
-
>
|
|
46
|
-
<a href={buildUrl(`/docs/containers/${id}/${version}`)}>Read documentation</a>
|
|
47
|
-
</ContextMenu.Item>
|
|
48
|
-
<ContextMenu.Separator className="h-[1px] bg-gray-200 m-1" />
|
|
49
|
-
<ContextMenu.Item asChild>
|
|
50
|
-
<a
|
|
51
|
-
href={buildUrl(`/docs/containers/${id}/${version}/changelog`)}
|
|
52
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
53
|
-
target="_blank"
|
|
54
|
-
rel="noopener noreferrer"
|
|
55
|
-
>
|
|
56
|
-
Read changelog
|
|
57
|
-
</a>
|
|
58
|
-
</ContextMenu.Item>
|
|
59
|
-
</ContextMenu.Content>
|
|
60
|
-
</ContextMenu.Portal>
|
|
61
|
-
</ContextMenu.Root>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { Handle } from '@xyflow/react';
|
|
2
|
-
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
3
|
-
import { buildUrl } from '@utils/url-builder';
|
|
4
|
-
import { Position } from '@xyflow/react';
|
|
5
|
-
import { Package } from 'lucide-react';
|
|
6
|
-
|
|
7
|
-
function classNames(...classes: any) {
|
|
8
|
-
return classes.filter(Boolean).join(' ');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
interface DataProductNodeProps {
|
|
12
|
-
data: {
|
|
13
|
-
mode: 'simple' | 'full';
|
|
14
|
-
dataProduct: {
|
|
15
|
-
id: string;
|
|
16
|
-
version: string;
|
|
17
|
-
name: string;
|
|
18
|
-
summary?: string;
|
|
19
|
-
inputs?: any[];
|
|
20
|
-
outputs?: any[];
|
|
21
|
-
owners?: any[];
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
selected?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export default function DataProductNode(props: DataProductNodeProps) {
|
|
28
|
-
const { id, version, name, summary, inputs = [], outputs = [], owners = [] } = props.data.dataProduct;
|
|
29
|
-
const mode = props.data.mode || 'simple';
|
|
30
|
-
const nodeLabel = 'Data Product';
|
|
31
|
-
const rotatedLabel = 'Product';
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<ContextMenu.Root>
|
|
35
|
-
<ContextMenu.Trigger>
|
|
36
|
-
<div className="relative">
|
|
37
|
-
<Handle
|
|
38
|
-
type="target"
|
|
39
|
-
position={Position.Left}
|
|
40
|
-
style={{ width: 10, height: 10, background: '#6366f1', zIndex: 10 }}
|
|
41
|
-
className="bg-indigo-500"
|
|
42
|
-
/>
|
|
43
|
-
<Handle
|
|
44
|
-
type="source"
|
|
45
|
-
position={Position.Right}
|
|
46
|
-
style={{ width: 10, height: 10, background: '#6366f1', zIndex: 10 }}
|
|
47
|
-
className="bg-indigo-500"
|
|
48
|
-
/>
|
|
49
|
-
<div
|
|
50
|
-
className={classNames(
|
|
51
|
-
'w-full rounded-md border flex justify-start bg-white text-black',
|
|
52
|
-
props.selected ? 'border-indigo-600 ring-2 ring-indigo-500 shadow-lg' : 'border-indigo-400'
|
|
53
|
-
)}
|
|
54
|
-
>
|
|
55
|
-
<div
|
|
56
|
-
className={`bg-gradient-to-b from-indigo-500 to-indigo-700 relative flex items-center w-5 justify-center rounded-l-sm text-indigo-100 border-r-[1px] border-indigo-500`}
|
|
57
|
-
>
|
|
58
|
-
<Package className="w-4 h-4 opacity-90 text-white absolute top-1" />
|
|
59
|
-
{mode === 'full' && (
|
|
60
|
-
<span
|
|
61
|
-
className={'w-1/2 text-center absolute bottom-1 text-[8px] text-white font-bold uppercase tracking-[3px]'}
|
|
62
|
-
style={{ transform: 'rotate(-90deg)' }}
|
|
63
|
-
>
|
|
64
|
-
{rotatedLabel}
|
|
65
|
-
</span>
|
|
66
|
-
)}
|
|
67
|
-
</div>
|
|
68
|
-
<div className="p-1 min-w-60 max-w-[min-content]">
|
|
69
|
-
<div className={classNames(mode === 'full' ? `border-b border-gray-200` : '')}>
|
|
70
|
-
<span className="text-xs font-bold block pt-0.5 pb-0.5">{name}</span>
|
|
71
|
-
<div className="flex justify-between">
|
|
72
|
-
<span className="text-[10px] font-light block pt-0.5 pb-0.5">v{version}</span>
|
|
73
|
-
{mode === 'simple' && (
|
|
74
|
-
<span className="text-[10px] text-gray-500 font-light block pt-0.5 pb-0.5">{nodeLabel}</span>
|
|
75
|
-
)}
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
{mode === 'full' && (
|
|
79
|
-
<div className="divide-y divide-gray-200">
|
|
80
|
-
<div className="leading-3 py-1">
|
|
81
|
-
<div
|
|
82
|
-
className="text-[8px] font-light overflow-hidden"
|
|
83
|
-
style={{
|
|
84
|
-
display: '-webkit-box',
|
|
85
|
-
WebkitLineClamp: 2,
|
|
86
|
-
WebkitBoxOrient: 'vertical',
|
|
87
|
-
}}
|
|
88
|
-
title={summary}
|
|
89
|
-
>
|
|
90
|
-
{summary}
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<div className="grid grid-cols-2 gap-x-4 py-1">
|
|
95
|
-
<span className="text-xs" style={{ fontSize: '0.2em' }}>
|
|
96
|
-
Inputs: {inputs.length}
|
|
97
|
-
</span>
|
|
98
|
-
<span className="text-xs" style={{ fontSize: '0.2em' }}>
|
|
99
|
-
Outputs: {outputs.length}
|
|
100
|
-
</span>
|
|
101
|
-
<span className="text-xs" style={{ fontSize: '0.2em' }}>
|
|
102
|
-
Owners: {owners.length}
|
|
103
|
-
</span>
|
|
104
|
-
</div>
|
|
105
|
-
</div>
|
|
106
|
-
)}
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</ContextMenu.Trigger>
|
|
111
|
-
<ContextMenu.Portal>
|
|
112
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
113
|
-
<ContextMenu.Item
|
|
114
|
-
asChild
|
|
115
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-indigo-100 rounded-sm flex items-center"
|
|
116
|
-
>
|
|
117
|
-
<a href={buildUrl(`/docs/data-products/${id}/${version}`)}>Read documentation</a>
|
|
118
|
-
</ContextMenu.Item>
|
|
119
|
-
<ContextMenu.Separator className="h-[1px] bg-gray-200 m-1" />
|
|
120
|
-
<ContextMenu.Item asChild>
|
|
121
|
-
<a
|
|
122
|
-
href={buildUrl(`/visualiser/data-products/${id}/${version}`)}
|
|
123
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-indigo-100 rounded-sm flex items-center"
|
|
124
|
-
>
|
|
125
|
-
View in Visualiser
|
|
126
|
-
</a>
|
|
127
|
-
</ContextMenu.Item>
|
|
128
|
-
</ContextMenu.Content>
|
|
129
|
-
</ContextMenu.Portal>
|
|
130
|
-
</ContextMenu.Root>
|
|
131
|
-
);
|
|
132
|
-
}
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
import type { CollectionEntry } from 'astro:content';
|
|
2
|
-
import { Handle, useReactFlow, useOnSelectionChange, Position } from '@xyflow/react';
|
|
3
|
-
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
4
|
-
import { buildUrl } from '@utils/url-builder';
|
|
5
|
-
import { getIcon } from '@utils/badges';
|
|
6
|
-
import { useState } from 'react';
|
|
7
|
-
|
|
8
|
-
interface Data {
|
|
9
|
-
mode: 'simple' | 'full';
|
|
10
|
-
domain: CollectionEntry<'domains'>;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export default function DomainNode({ data, id: nodeId }: any) {
|
|
14
|
-
const { mode, domain } = data as Data;
|
|
15
|
-
const reactFlow = useReactFlow();
|
|
16
|
-
const [highlightedServices, setHighlightedServices] = useState<Set<string>>(new Set());
|
|
17
|
-
|
|
18
|
-
const { id, version, name, services = [], styles } = domain.data;
|
|
19
|
-
const { icon = 'RectangleGroupIcon' } = styles || {};
|
|
20
|
-
|
|
21
|
-
const Icon = getIcon(icon);
|
|
22
|
-
const ServerIcon = getIcon('ServerIcon');
|
|
23
|
-
|
|
24
|
-
// Listen for selection changes to highlight connected services
|
|
25
|
-
useOnSelectionChange({
|
|
26
|
-
onChange: ({ nodes: selectedNodes }) => {
|
|
27
|
-
if (selectedNodes.length === 0) {
|
|
28
|
-
setHighlightedServices(new Set());
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const selectedNode = selectedNodes[0];
|
|
33
|
-
if (!selectedNode) {
|
|
34
|
-
setHighlightedServices(new Set());
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Get all edges
|
|
39
|
-
const edges = reactFlow.getEdges();
|
|
40
|
-
const connectedServiceIds = new Set<string>();
|
|
41
|
-
|
|
42
|
-
// Find services connected to the selected node
|
|
43
|
-
edges.forEach((edge) => {
|
|
44
|
-
if (edge.source === selectedNode.id || edge.target === selectedNode.id) {
|
|
45
|
-
// Check if this edge connects to our domain
|
|
46
|
-
if (edge.source === nodeId && edge.sourceHandle) {
|
|
47
|
-
// Extract service ID from sourceHandle (format: "serviceId-source")
|
|
48
|
-
const serviceId = edge.sourceHandle.replace('-source', '');
|
|
49
|
-
connectedServiceIds.add(serviceId);
|
|
50
|
-
}
|
|
51
|
-
if (edge.target === nodeId && edge.targetHandle) {
|
|
52
|
-
// Extract service ID from targetHandle (format: "serviceId-target")
|
|
53
|
-
const serviceId = edge.targetHandle.replace('-target', '');
|
|
54
|
-
connectedServiceIds.add(serviceId);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
setHighlightedServices(connectedServiceIds);
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<ContextMenu.Root>
|
|
65
|
-
<ContextMenu.Trigger>
|
|
66
|
-
<div className="w-full rounded-lg border-2 border-yellow-400 bg-white shadow-lg">
|
|
67
|
-
<div className="bg-yellow-100 px-3 py-2 flex items-center space-x-2">
|
|
68
|
-
{Icon && <Icon className="w-4 h-4 text-yellow-700" />}
|
|
69
|
-
<div>
|
|
70
|
-
<span className="text-sm font-bold text-yellow-900">{name}</span>
|
|
71
|
-
<span className="text-xs text-yellow-700 ml-2">v{version}</span>
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
{mode === 'full' && services.length > 0 && (
|
|
75
|
-
<div>
|
|
76
|
-
{services.map((service: any, index: number) => {
|
|
77
|
-
const isHighlighted = highlightedServices.has(service.data.id);
|
|
78
|
-
|
|
79
|
-
return (
|
|
80
|
-
<ContextMenu.Root key={`${service.data.id}-${index}`}>
|
|
81
|
-
<ContextMenu.Trigger asChild>
|
|
82
|
-
<div
|
|
83
|
-
className={`relative flex items-center justify-between px-3 py-2 cursor-pointer ${index !== services.length - 1 ? 'border-b border-gray-300' : ''} ${isHighlighted ? 'bg-pink-100 border-pink-300' : ''}`}
|
|
84
|
-
>
|
|
85
|
-
<Handle
|
|
86
|
-
type="target"
|
|
87
|
-
position={Position.Left}
|
|
88
|
-
id={`${service.data.id}-target`}
|
|
89
|
-
className="!left-[-1px] !w-2 !h-2 !bg-gray-400 !border !border-gray-500 !rounded-full !z-10"
|
|
90
|
-
style={{ left: '-1px' }}
|
|
91
|
-
/>
|
|
92
|
-
<Handle
|
|
93
|
-
type="source"
|
|
94
|
-
position={Position.Right}
|
|
95
|
-
id={`${service.data.id}-source`}
|
|
96
|
-
className="!right-[-1px] !w-2 !h-2 !bg-gray-400 !border !border-gray-500 !rounded-full !z-10"
|
|
97
|
-
style={{ right: '-1px' }}
|
|
98
|
-
/>
|
|
99
|
-
<div className="flex items-center space-x-3">
|
|
100
|
-
<div className="flex items-center justify-center w-5 h-5 bg-pink-500 rounded">
|
|
101
|
-
{ServerIcon && <ServerIcon className="w-3 h-3 text-white" />}
|
|
102
|
-
</div>
|
|
103
|
-
<span className="text-sm font-medium text-gray-900">{service.data.name || service.data.id}</span>
|
|
104
|
-
</div>
|
|
105
|
-
<div className="flex items-center space-x-4 text-sm text-gray-600">
|
|
106
|
-
<span className="text-xs">v{service.data.version}</span>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</ContextMenu.Trigger>
|
|
110
|
-
<ContextMenu.Portal>
|
|
111
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
112
|
-
<ContextMenu.Item
|
|
113
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
114
|
-
onClick={() =>
|
|
115
|
-
(window.location.href = buildUrl(`/docs/services/${service.data.id}/${service.data.version}`))
|
|
116
|
-
}
|
|
117
|
-
>
|
|
118
|
-
View Service Documentation
|
|
119
|
-
</ContextMenu.Item>
|
|
120
|
-
<ContextMenu.Item
|
|
121
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
122
|
-
onClick={() =>
|
|
123
|
-
(window.location.href = buildUrl(`/visualiser/services/${service.data.id}/${service.data.version}`))
|
|
124
|
-
}
|
|
125
|
-
>
|
|
126
|
-
View Service Visualizer
|
|
127
|
-
</ContextMenu.Item>
|
|
128
|
-
</ContextMenu.Content>
|
|
129
|
-
</ContextMenu.Portal>
|
|
130
|
-
</ContextMenu.Root>
|
|
131
|
-
);
|
|
132
|
-
})}
|
|
133
|
-
</div>
|
|
134
|
-
)}
|
|
135
|
-
</div>
|
|
136
|
-
</ContextMenu.Trigger>
|
|
137
|
-
<ContextMenu.Portal>
|
|
138
|
-
<ContextMenu.Content className="min-w-[220px] bg-white rounded-md p-1 shadow-md border border-gray-200">
|
|
139
|
-
<ContextMenu.Item
|
|
140
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
141
|
-
onClick={() => (window.location.href = buildUrl(`/docs/domains/${id}/${version}`))}
|
|
142
|
-
>
|
|
143
|
-
View Domain Documentation
|
|
144
|
-
</ContextMenu.Item>
|
|
145
|
-
<ContextMenu.Item
|
|
146
|
-
className="text-sm px-2 py-1.5 outline-none cursor-pointer hover:bg-orange-100 rounded-sm flex items-center"
|
|
147
|
-
onClick={() => (window.location.href = buildUrl(`/visualiser/domains/${id}/${version}`))}
|
|
148
|
-
>
|
|
149
|
-
View Domain Visualizer
|
|
150
|
-
</ContextMenu.Item>
|
|
151
|
-
</ContextMenu.Content>
|
|
152
|
-
</ContextMenu.Portal>
|
|
153
|
-
</ContextMenu.Root>
|
|
154
|
-
);
|
|
155
|
-
}
|