@hitachivantara/uikit-cli 6.0.1

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.
Files changed (109) hide show
  1. package/README.md +46 -0
  2. package/package.json +68 -0
  3. package/src/app-shell.js +106 -0
  4. package/src/baselines/app-shell/vite/_gitignore +30 -0
  5. package/src/baselines/app-shell/vite/_oxlintrc.json +5 -0
  6. package/src/baselines/app-shell/vite/_package.json +55 -0
  7. package/src/baselines/app-shell/vite/public/locales/en/example.json +8 -0
  8. package/src/baselines/app-shell/vite/src/lib/data/config.ts +15 -0
  9. package/src/baselines/app-shell/vite/src/lib/i18n.ts +44 -0
  10. package/src/baselines/app-shell/vite/src/pages/Example/index.tsx +25 -0
  11. package/src/baselines/app-shell/vite/src/providers/Provider.tsx +31 -0
  12. package/src/baselines/app-shell/vite/src/tests/mocks.ts +1 -0
  13. package/src/baselines/app-shell/vite/src/tests/providers.tsx +13 -0
  14. package/src/baselines/app-shell/vite/src/tests/setupTests.ts +24 -0
  15. package/src/baselines/app-shell/vite/src/types/theme.d.ts +8 -0
  16. package/src/baselines/app-shell/vite/src/types/vite-env.d.ts +1 -0
  17. package/src/baselines/app-shell/vite/tsconfig.json +10 -0
  18. package/src/baselines/app-shell/vite/tsconfig.node.json +9 -0
  19. package/src/baselines/app-shell/vite/uno.config.ts +6 -0
  20. package/src/baselines/app-shell/vite/vite.config.ts +45 -0
  21. package/src/baselines/vite/_gitignore +30 -0
  22. package/src/baselines/vite/_oxlintrc.json +5 -0
  23. package/src/baselines/vite/_package.json +53 -0
  24. package/src/baselines/vite/index.html +18 -0
  25. package/src/baselines/vite/public/favicon.ico +0 -0
  26. package/src/baselines/vite/public/locales/en/common.json +16 -0
  27. package/src/baselines/vite/public/locales/en/home.json +4 -0
  28. package/src/baselines/vite/public/logo192.png +0 -0
  29. package/src/baselines/vite/src/App.tsx +31 -0
  30. package/src/baselines/vite/src/assets/HitachiLogo.tsx +27 -0
  31. package/src/baselines/vite/src/components/common/Loading/Loading.test.tsx +18 -0
  32. package/src/baselines/vite/src/components/common/Loading/Loading.tsx +15 -0
  33. package/src/baselines/vite/src/components/common/Loading/index.ts +1 -0
  34. package/src/baselines/vite/src/context/NavigationContext.tsx +67 -0
  35. package/src/baselines/vite/src/lib/i18n.ts +29 -0
  36. package/src/baselines/vite/src/main.tsx +12 -0
  37. package/src/baselines/vite/src/pages/Home/index.tsx +13 -0
  38. package/src/baselines/vite/src/pages/NotFound/NotFound.tsx +39 -0
  39. package/src/baselines/vite/src/pages/NotFound/index.tsx +1 -0
  40. package/src/baselines/vite/src/pages/layout/navigation.tsx +82 -0
  41. package/src/baselines/vite/src/routes.tsx +14 -0
  42. package/src/baselines/vite/src/tests/mocks.ts +1 -0
  43. package/src/baselines/vite/src/tests/providers.tsx +13 -0
  44. package/src/baselines/vite/src/tests/setupTests.ts +24 -0
  45. package/src/baselines/vite/src/types/theme.d.ts +8 -0
  46. package/src/baselines/vite/src/vite-env.d.ts +1 -0
  47. package/src/baselines/vite/tsconfig.json +10 -0
  48. package/src/baselines/vite/tsconfig.node.json +9 -0
  49. package/src/baselines/vite/uno.config.ts +6 -0
  50. package/src/baselines/vite/vite.config.ts +31 -0
  51. package/src/contents.js +63 -0
  52. package/src/create.js +172 -0
  53. package/src/index.js +22 -0
  54. package/src/navigation.js +21 -0
  55. package/src/package.js +37 -0
  56. package/src/plop-templates/README.md.hbs +10 -0
  57. package/src/plop-templates/app-shell/app-shell.config.ts.hbs +54 -0
  58. package/src/plop-templates/app-shell/index.html.hbs +15 -0
  59. package/src/plopfile.js +61 -0
  60. package/src/templates/AssetInventory/CardView.tsx +167 -0
  61. package/src/templates/AssetInventory/ListView.tsx +56 -0
  62. package/src/templates/AssetInventory/data.tsx +255 -0
  63. package/src/templates/AssetInventory/index.tsx +198 -0
  64. package/src/templates/AssetInventory/usePaginationData.ts +158 -0
  65. package/src/templates/Canvas/Context.tsx +49 -0
  66. package/src/templates/Canvas/ListView.tsx +189 -0
  67. package/src/templates/Canvas/Node.tsx +203 -0
  68. package/src/templates/Canvas/Sidebar.tsx +51 -0
  69. package/src/templates/Canvas/StatusEdge.tsx +75 -0
  70. package/src/templates/Canvas/StickyNode.tsx +475 -0
  71. package/src/templates/Canvas/Table.tsx +202 -0
  72. package/src/templates/Canvas/TreeView.tsx +211 -0
  73. package/src/templates/Canvas/dependencies.json +7 -0
  74. package/src/templates/Canvas/index.tsx +363 -0
  75. package/src/templates/Canvas/styles.tsx +41 -0
  76. package/src/templates/Canvas/utils.tsx +70 -0
  77. package/src/templates/Dashboard/GridPanel.tsx +33 -0
  78. package/src/templates/Dashboard/Kpi.tsx +107 -0
  79. package/src/templates/Dashboard/Map.styles.ts +681 -0
  80. package/src/templates/Dashboard/Map.tsx +71 -0
  81. package/src/templates/Dashboard/data.ts +67 -0
  82. package/src/templates/Dashboard/dependencies.json +11 -0
  83. package/src/templates/Dashboard/index.tsx +173 -0
  84. package/src/templates/DetailsView/KPIs.tsx +70 -0
  85. package/src/templates/DetailsView/MetadataItem.tsx +35 -0
  86. package/src/templates/DetailsView/Properties.tsx +127 -0
  87. package/src/templates/DetailsView/Table.tsx +104 -0
  88. package/src/templates/DetailsView/data.ts +67 -0
  89. package/src/templates/DetailsView/index.tsx +102 -0
  90. package/src/templates/DetailsView/usePaginationData.ts +155 -0
  91. package/src/templates/DetailsView/utils.ts +51 -0
  92. package/src/templates/Form/index.tsx +107 -0
  93. package/src/templates/KanbanBoard/ColumnContainer.tsx +89 -0
  94. package/src/templates/KanbanBoard/TaskCard.tsx +130 -0
  95. package/src/templates/KanbanBoard/data.tsx +140 -0
  96. package/src/templates/KanbanBoard/dependencies.json +6 -0
  97. package/src/templates/KanbanBoard/index.tsx +179 -0
  98. package/src/templates/KanbanBoard/styles.tsx +76 -0
  99. package/src/templates/KanbanBoard/types.ts +21 -0
  100. package/src/templates/ListView/Indicator.tsx +42 -0
  101. package/src/templates/ListView/Kpi.tsx +120 -0
  102. package/src/templates/ListView/Table.tsx +55 -0
  103. package/src/templates/ListView/data.tsx +179 -0
  104. package/src/templates/ListView/dependencies.json +5 -0
  105. package/src/templates/ListView/index.tsx +245 -0
  106. package/src/templates/ListView/usePaginationData.ts +158 -0
  107. package/src/templates/Welcome/index.tsx +101 -0
  108. package/src/templates/package.json +30 -0
  109. package/src/utils.js +37 -0
@@ -0,0 +1,189 @@
1
+ import { forwardRef, useId, useRef, useState } from "react";
2
+ import { useDraggable } from "@dnd-kit/core";
3
+ import { css, cx } from "@emotion/css";
4
+ import {
5
+ HvInput,
6
+ HvInputProps,
7
+ HvListContainer,
8
+ HvListItem,
9
+ HvListItemProps,
10
+ HvTypography,
11
+ outlineStyles,
12
+ theme,
13
+ useForkRef,
14
+ } from "@hitachivantara/uikit-react-core";
15
+ import { Drag } from "@hitachivantara/uikit-react-icons";
16
+
17
+ import { NodeData } from "./Node";
18
+ import { iconsMapping, iconsMappingKeys } from "./utils";
19
+
20
+ const classes = {
21
+ root: css({ display: "flex", flexDirection: "column", gap: theme.space.sm }),
22
+ item: css({
23
+ display: "flex",
24
+ justifyContent: "space-between",
25
+ alignItems: "center",
26
+ border: `1px solid ${theme.colors.borderSubtle}`,
27
+ borderRadius: "12px",
28
+ backgroundColor: theme.colors.bgContainer,
29
+ padding: theme.space.xs,
30
+ height: "unset",
31
+ "&:focus-visible": {
32
+ ...outlineStyles,
33
+ },
34
+ }),
35
+ itemTitle: css({
36
+ display: "flex",
37
+ alignItems: "center",
38
+ gap: theme.space.xs,
39
+ }),
40
+ icon: css({
41
+ borderRadius: theme.radii.round,
42
+ backgroundColor: theme.colors.cat6,
43
+ }),
44
+ dragging: css({
45
+ border: `2px solid ${theme.colors.primaryStrong}`,
46
+ }),
47
+ };
48
+
49
+ const items = iconsMappingKeys.map((key, index) => ({
50
+ id: `item${index + 1}`,
51
+ title: `Item ${index + 1}`,
52
+ subtitle: `Description ${index + 1}`,
53
+ icon: key,
54
+ }));
55
+
56
+ interface ItemProps {
57
+ id: string;
58
+ title: string;
59
+ subtitle: string;
60
+ icon: string;
61
+ }
62
+
63
+ interface ItemCardProps
64
+ extends Omit<HvListItemProps, "title">,
65
+ Omit<ItemProps, "id"> {
66
+ isDragging?: boolean;
67
+ }
68
+
69
+ const ItemCard = forwardRef<HTMLLIElement, ItemCardProps>(
70
+ ({ icon, title, subtitle, isDragging, ...others }, ref) => {
71
+ return (
72
+ <HvListItem
73
+ ref={ref}
74
+ classes={{ root: cx(classes.item, { [classes.dragging]: isDragging }) }}
75
+ {...others}
76
+ >
77
+ <div className={classes.itemTitle}>
78
+ <div className={classes.icon}>
79
+ {iconsMapping[icon as keyof typeof iconsMapping]}
80
+ </div>
81
+ <HvTypography variant="label">{title}</HvTypography>
82
+ </div>
83
+ <Drag />
84
+ </HvListItem>
85
+ );
86
+ },
87
+ );
88
+
89
+ const DraggableItemCard = ({ icon, title, id, subtitle }: ItemProps) => {
90
+ const itemRef = useRef<HTMLLIElement>(null);
91
+
92
+ const { attributes, listeners, setNodeRef, isDragging, transform } =
93
+ useDraggable({
94
+ id,
95
+ data: {
96
+ // Data needed to be dropped in HvFlow
97
+ hvFlow: {
98
+ // HvFlow will use this value to populate the node's data.nodeLabel
99
+ label: title,
100
+ // Node type from nodeTypes property provided to HvFlow
101
+ type: "node",
102
+ // Item position: used by HvFlow to position the node when dropped
103
+ x: itemRef.current?.getBoundingClientRect().x,
104
+ y: itemRef.current?.getBoundingClientRect().y,
105
+ // Values to be added to the node's data
106
+ data: {
107
+ subtitle,
108
+ color: "cat6",
109
+ icon,
110
+ output: {
111
+ id: "data",
112
+ label: "Data",
113
+ },
114
+ input: {
115
+ id: "data",
116
+ label: "Data",
117
+ },
118
+ } satisfies NodeData,
119
+ },
120
+ // Data needed for the DragOverlay component
121
+ dragOverlay: {
122
+ component: (
123
+ <ItemCard
124
+ icon={icon}
125
+ title={title}
126
+ subtitle={subtitle}
127
+ isDragging
128
+ />
129
+ ),
130
+ },
131
+ },
132
+ });
133
+
134
+ const style = transform
135
+ ? {
136
+ transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`,
137
+ }
138
+ : undefined;
139
+
140
+ const forkedRef = useForkRef(itemRef, setNodeRef);
141
+
142
+ return (
143
+ <ItemCard
144
+ ref={forkedRef}
145
+ style={style}
146
+ icon={icon}
147
+ title={title}
148
+ subtitle={subtitle}
149
+ isDragging={isDragging}
150
+ {...attributes}
151
+ {...listeners}
152
+ />
153
+ );
154
+ };
155
+
156
+ export const ListView = () => {
157
+ const [listItems, setListItems] = useState(items);
158
+ const listId = useId();
159
+
160
+ const handleSearch: HvInputProps["onChange"] = (event, value) => {
161
+ if (value) {
162
+ setListItems(
163
+ items.filter((item) =>
164
+ item.title.toLowerCase().trim().includes(value.toLowerCase().trim()),
165
+ ),
166
+ );
167
+ } else {
168
+ setListItems(items);
169
+ }
170
+ };
171
+
172
+ return (
173
+ <div className={classes.root}>
174
+ <HvInput
175
+ type="search"
176
+ placeholder="Search for a node..."
177
+ aria-controls={listId}
178
+ aria-owns={listId}
179
+ onChange={handleSearch}
180
+ inputProps={{ autoComplete: "off" }}
181
+ />
182
+ <HvListContainer id={listId}>
183
+ {listItems.map((item) => (
184
+ <DraggableItemCard key={item.id} {...item} />
185
+ ))}
186
+ </HvListContainer>
187
+ </div>
188
+ );
189
+ };
@@ -0,0 +1,203 @@
1
+ import { isValidElement } from "react";
2
+ import { css, cx } from "@emotion/css";
3
+ import { Handle, NodeProps, NodeToolbar, Position } from "reactflow";
4
+ import {
5
+ HvButton,
6
+ HvColorAny,
7
+ HvIconButton,
8
+ HvTooltip,
9
+ HvTypography,
10
+ theme,
11
+ } from "@hitachivantara/uikit-react-core";
12
+ import {
13
+ HvFlowNodeInput,
14
+ HvFlowNodeOutput,
15
+ useHvNode,
16
+ } from "@hitachivantara/uikit-react-lab";
17
+
18
+ import { useCanvasContext } from "./Context";
19
+ import { FlowStatus, flowStatusesSpecs, iconsMapping } from "./utils";
20
+
21
+ const classes = {
22
+ root: css({
23
+ display: "flex",
24
+ alignItems: "center",
25
+ justifyContent: "center",
26
+ borderRadius: theme.radii.large,
27
+ backgroundColor: theme.colors.bgContainer,
28
+ boxShadow: theme.colors.shadow,
29
+ borderWidth: "1px",
30
+ minWidth: "200px",
31
+ minHeight: "100px",
32
+ borderColor: "var(--node-border-color)",
33
+ }),
34
+ content: css({
35
+ display: "flex",
36
+ alignItems: "center",
37
+ justifyContent: "center",
38
+ padding: theme.spacing("sm"),
39
+ gap: theme.space.xs,
40
+ }),
41
+ contentIcon: css({
42
+ width: 48,
43
+ height: 48,
44
+ display: "flex",
45
+ justifyContent: "center",
46
+ alignItems: "center",
47
+ borderRadius: theme.radii.round,
48
+ backgroundColor: "var(--icon-bg-color)",
49
+ }),
50
+ nodeToolbar: css({
51
+ backgroundColor: theme.colors.bgContainer,
52
+ borderRadius: theme.radii.full,
53
+ }),
54
+ handle: css({
55
+ backgroundColor: theme.colors.textSubtle,
56
+ border: `1px solid ${theme.colors.bgContainer}`,
57
+ height: 8,
58
+ width: 8,
59
+ }),
60
+ statusIcon: css({ position: "absolute", top: -8, right: -8 }),
61
+ contentInfo: css({
62
+ display: "flex",
63
+ flexDirection: "column",
64
+ alignItems: "flex-start",
65
+ justifyContent: "center",
66
+ "& > button": { marginTop: theme.space.xs, alignSelf: "center" },
67
+ }),
68
+ };
69
+
70
+ export type NodeData =
71
+ | undefined
72
+ | {
73
+ nodeLabel?: string; // nodeLabel is automatically added by HvFlow when the node is dropped
74
+ tableId?: string;
75
+ subtitle?: string;
76
+ color?: HvColorAny;
77
+ icon?: string;
78
+ output?: HvFlowNodeOutput;
79
+ input?: HvFlowNodeInput;
80
+ status?: FlowStatus;
81
+ };
82
+
83
+ export const Node = ({ id, data = {} }: NodeProps<NodeData>) => {
84
+ const {
85
+ nodeLabel: titleProp,
86
+ subtitle: subtitleProp,
87
+ color: colorProp,
88
+ icon: iconProp,
89
+ input: inputProp,
90
+ output: outputProp,
91
+ status: statusProp,
92
+ tableId,
93
+ } = data;
94
+
95
+ const {
96
+ toggleShowActions,
97
+ getNodeToolbarProps,
98
+ handleDefaultAction,
99
+ nodeActions,
100
+ color,
101
+ subtitle,
102
+ icon,
103
+ title,
104
+ } = useHvNode({
105
+ id,
106
+ title: titleProp,
107
+ subtitle: subtitleProp,
108
+ color: colorProp,
109
+ icon: iconProp
110
+ ? iconsMapping[iconProp as keyof typeof iconsMapping]
111
+ : undefined,
112
+ inputs: inputProp ? [inputProp] : undefined,
113
+ outputs: outputProp ? [outputProp] : undefined,
114
+ });
115
+
116
+ const { selectedTable, setOpenedTables, setSelectedTable } =
117
+ useCanvasContext();
118
+
119
+ const status = statusProp ? flowStatusesSpecs[statusProp] : undefined;
120
+
121
+ return (
122
+ <div
123
+ style={
124
+ {
125
+ "--node-border-color": status ? status.color : color,
126
+ "--icon-bg-color": color,
127
+ } as React.CSSProperties
128
+ }
129
+ className={cx(
130
+ "nowheel", // Disables the default canvas pan behaviour when scrolling inside the node
131
+ classes.root,
132
+ )}
133
+ onMouseEnter={toggleShowActions}
134
+ onMouseLeave={toggleShowActions}
135
+ >
136
+ <NodeToolbar className={classes.nodeToolbar} {...getNodeToolbarProps()}>
137
+ {nodeActions?.map((action) => (
138
+ <HvIconButton
139
+ key={action.id}
140
+ title={action.label}
141
+ onClick={() => handleDefaultAction(action)}
142
+ >
143
+ {isValidElement(action.icon) ? action.icon : null}
144
+ </HvIconButton>
145
+ ))}
146
+ </NodeToolbar>
147
+ {inputProp && (
148
+ <Handle
149
+ className={classes.handle}
150
+ type="target"
151
+ position={Position.Left}
152
+ id={inputProp.id ?? "0"}
153
+ />
154
+ )}
155
+ {outputProp && (
156
+ <Handle
157
+ className={classes.handle}
158
+ type="source"
159
+ position={Position.Right}
160
+ id={outputProp.id ?? "0"}
161
+ />
162
+ )}
163
+ <div className={classes.content}>
164
+ <div className={classes.contentIcon}>{icon}</div>
165
+ <div className={classes.contentInfo}>
166
+ <HvTypography variant="title4" component="p">
167
+ {title}
168
+ </HvTypography>
169
+ <HvTypography variant="caption1">{subtitle}</HvTypography>
170
+ {tableId && (
171
+ <HvButton
172
+ size="sm"
173
+ variant="primarySubtle"
174
+ onClick={() =>
175
+ setOpenedTables?.((prev) => {
176
+ const tables = prev ? [...prev] : [];
177
+ if (!tables.some((x) => x.id === tableId)) {
178
+ if (tables.length === 0 && selectedTable === "none") {
179
+ setSelectedTable?.(tableId);
180
+ }
181
+ tables.push({
182
+ id: tableId,
183
+ label: title,
184
+ });
185
+ return tables;
186
+ }
187
+ return prev;
188
+ })
189
+ }
190
+ >
191
+ View Data
192
+ </HvButton>
193
+ )}
194
+ </div>
195
+ </div>
196
+ {status && (
197
+ <HvTooltip className={classes.statusIcon} title={status.description}>
198
+ {status.icon}
199
+ </HvTooltip>
200
+ )}
201
+ </div>
202
+ );
203
+ };
@@ -0,0 +1,51 @@
1
+ import { useId, useState } from "react";
2
+ import {
3
+ DndContextProps,
4
+ DragOverlay,
5
+ useDndMonitor,
6
+ useDroppable,
7
+ } from "@dnd-kit/core";
8
+ import {
9
+ HvCanvasSidePanel,
10
+ HvCanvasSidePanelProps,
11
+ } from "@hitachivantara/uikit-react-pentaho";
12
+
13
+ export const CanvasSidebar = (props: HvCanvasSidePanelProps) => {
14
+ const [overlay, setOverlay] = useState<React.ReactNode>();
15
+
16
+ const elementId = useId();
17
+
18
+ // The sidebar is droppable to distinguish between the canvas and the sidebar
19
+ // Otherwise items dropped inside the sidebar will be added to the canvas
20
+ const { setNodeRef } = useDroppable({ id: elementId });
21
+
22
+ const handleDragStart: DndContextProps["onDragStart"] = (event) => {
23
+ if (event.active.data.current?.dragOverlay) {
24
+ setOverlay(event.active.data.current.dragOverlay?.component);
25
+ }
26
+ };
27
+
28
+ const handleDragEnd: DndContextProps["onDragEnd"] = () => {
29
+ setOverlay(undefined);
30
+ };
31
+
32
+ useDndMonitor({
33
+ onDragEnd: handleDragEnd,
34
+ onDragStart: handleDragStart,
35
+ });
36
+
37
+ return (
38
+ <>
39
+ <HvCanvasSidePanel
40
+ id={elementId}
41
+ ref={setNodeRef}
42
+ labels={{
43
+ open: "Click to Add Nodes & View Files",
44
+ }}
45
+ {...props}
46
+ />
47
+ {/** Shown when the dragged item leaves the sidebar to drop it in the canvas */}
48
+ <DragOverlay>{overlay ?? null}</DragOverlay>
49
+ </>
50
+ );
51
+ };
@@ -0,0 +1,75 @@
1
+ import {
2
+ BaseEdge,
3
+ EdgeLabelRenderer,
4
+ EdgeProps,
5
+ getBezierPath,
6
+ } from "reactflow";
7
+ import {
8
+ HvDropDownMenu,
9
+ HvDropDownMenuProps,
10
+ } from "@hitachivantara/uikit-react-core";
11
+ import { useFlowInstance } from "@hitachivantara/uikit-react-lab";
12
+
13
+ import { FlowStatus, flowStatusesSpecs } from "./utils";
14
+
15
+ export type StatusEdgeData =
16
+ | undefined
17
+ | {
18
+ status?: FlowStatus;
19
+ };
20
+
21
+ export const StatusEdge = (props: EdgeProps<StatusEdgeData>) => {
22
+ const {
23
+ id,
24
+ sourceX,
25
+ sourceY,
26
+ sourcePosition,
27
+ targetX,
28
+ targetY,
29
+ targetPosition,
30
+ data,
31
+ } = props;
32
+
33
+ const instance = useFlowInstance();
34
+
35
+ const [edgePath, labelX, labelY] = getBezierPath({
36
+ sourceX,
37
+ sourceY,
38
+ sourcePosition,
39
+ targetX,
40
+ targetY,
41
+ targetPosition,
42
+ });
43
+
44
+ const status = data?.status ? flowStatusesSpecs[data.status] : undefined;
45
+
46
+ const handleClick: HvDropDownMenuProps["onClick"] = (event, value) => {
47
+ if (value.id === "remove") {
48
+ instance.setEdges((edges) => edges.filter((edge) => edge.id !== id));
49
+ }
50
+ };
51
+
52
+ return (
53
+ <>
54
+ <BaseEdge {...props} path={edgePath} />
55
+ {status && (
56
+ <EdgeLabelRenderer>
57
+ <div
58
+ style={{
59
+ position: "absolute",
60
+ transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
61
+ pointerEvents: "all",
62
+ }}
63
+ className="nodrag nopan nowheel" // ReactFlow specific classes to prevent drag on icon
64
+ >
65
+ <HvDropDownMenu
66
+ icon={status.icon}
67
+ dataList={[{ id: "remove", label: "Remove connection" }]}
68
+ onClick={handleClick}
69
+ />
70
+ </div>
71
+ </EdgeLabelRenderer>
72
+ )}
73
+ </>
74
+ );
75
+ };