@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.
- package/README.md +46 -0
- package/package.json +68 -0
- package/src/app-shell.js +106 -0
- package/src/baselines/app-shell/vite/_gitignore +30 -0
- package/src/baselines/app-shell/vite/_oxlintrc.json +5 -0
- package/src/baselines/app-shell/vite/_package.json +55 -0
- package/src/baselines/app-shell/vite/public/locales/en/example.json +8 -0
- package/src/baselines/app-shell/vite/src/lib/data/config.ts +15 -0
- package/src/baselines/app-shell/vite/src/lib/i18n.ts +44 -0
- package/src/baselines/app-shell/vite/src/pages/Example/index.tsx +25 -0
- package/src/baselines/app-shell/vite/src/providers/Provider.tsx +31 -0
- package/src/baselines/app-shell/vite/src/tests/mocks.ts +1 -0
- package/src/baselines/app-shell/vite/src/tests/providers.tsx +13 -0
- package/src/baselines/app-shell/vite/src/tests/setupTests.ts +24 -0
- package/src/baselines/app-shell/vite/src/types/theme.d.ts +8 -0
- package/src/baselines/app-shell/vite/src/types/vite-env.d.ts +1 -0
- package/src/baselines/app-shell/vite/tsconfig.json +10 -0
- package/src/baselines/app-shell/vite/tsconfig.node.json +9 -0
- package/src/baselines/app-shell/vite/uno.config.ts +6 -0
- package/src/baselines/app-shell/vite/vite.config.ts +45 -0
- package/src/baselines/vite/_gitignore +30 -0
- package/src/baselines/vite/_oxlintrc.json +5 -0
- package/src/baselines/vite/_package.json +53 -0
- package/src/baselines/vite/index.html +18 -0
- package/src/baselines/vite/public/favicon.ico +0 -0
- package/src/baselines/vite/public/locales/en/common.json +16 -0
- package/src/baselines/vite/public/locales/en/home.json +4 -0
- package/src/baselines/vite/public/logo192.png +0 -0
- package/src/baselines/vite/src/App.tsx +31 -0
- package/src/baselines/vite/src/assets/HitachiLogo.tsx +27 -0
- package/src/baselines/vite/src/components/common/Loading/Loading.test.tsx +18 -0
- package/src/baselines/vite/src/components/common/Loading/Loading.tsx +15 -0
- package/src/baselines/vite/src/components/common/Loading/index.ts +1 -0
- package/src/baselines/vite/src/context/NavigationContext.tsx +67 -0
- package/src/baselines/vite/src/lib/i18n.ts +29 -0
- package/src/baselines/vite/src/main.tsx +12 -0
- package/src/baselines/vite/src/pages/Home/index.tsx +13 -0
- package/src/baselines/vite/src/pages/NotFound/NotFound.tsx +39 -0
- package/src/baselines/vite/src/pages/NotFound/index.tsx +1 -0
- package/src/baselines/vite/src/pages/layout/navigation.tsx +82 -0
- package/src/baselines/vite/src/routes.tsx +14 -0
- package/src/baselines/vite/src/tests/mocks.ts +1 -0
- package/src/baselines/vite/src/tests/providers.tsx +13 -0
- package/src/baselines/vite/src/tests/setupTests.ts +24 -0
- package/src/baselines/vite/src/types/theme.d.ts +8 -0
- package/src/baselines/vite/src/vite-env.d.ts +1 -0
- package/src/baselines/vite/tsconfig.json +10 -0
- package/src/baselines/vite/tsconfig.node.json +9 -0
- package/src/baselines/vite/uno.config.ts +6 -0
- package/src/baselines/vite/vite.config.ts +31 -0
- package/src/contents.js +63 -0
- package/src/create.js +172 -0
- package/src/index.js +22 -0
- package/src/navigation.js +21 -0
- package/src/package.js +37 -0
- package/src/plop-templates/README.md.hbs +10 -0
- package/src/plop-templates/app-shell/app-shell.config.ts.hbs +54 -0
- package/src/plop-templates/app-shell/index.html.hbs +15 -0
- package/src/plopfile.js +61 -0
- package/src/templates/AssetInventory/CardView.tsx +167 -0
- package/src/templates/AssetInventory/ListView.tsx +56 -0
- package/src/templates/AssetInventory/data.tsx +255 -0
- package/src/templates/AssetInventory/index.tsx +198 -0
- package/src/templates/AssetInventory/usePaginationData.ts +158 -0
- package/src/templates/Canvas/Context.tsx +49 -0
- package/src/templates/Canvas/ListView.tsx +189 -0
- package/src/templates/Canvas/Node.tsx +203 -0
- package/src/templates/Canvas/Sidebar.tsx +51 -0
- package/src/templates/Canvas/StatusEdge.tsx +75 -0
- package/src/templates/Canvas/StickyNode.tsx +475 -0
- package/src/templates/Canvas/Table.tsx +202 -0
- package/src/templates/Canvas/TreeView.tsx +211 -0
- package/src/templates/Canvas/dependencies.json +7 -0
- package/src/templates/Canvas/index.tsx +363 -0
- package/src/templates/Canvas/styles.tsx +41 -0
- package/src/templates/Canvas/utils.tsx +70 -0
- package/src/templates/Dashboard/GridPanel.tsx +33 -0
- package/src/templates/Dashboard/Kpi.tsx +107 -0
- package/src/templates/Dashboard/Map.styles.ts +681 -0
- package/src/templates/Dashboard/Map.tsx +71 -0
- package/src/templates/Dashboard/data.ts +67 -0
- package/src/templates/Dashboard/dependencies.json +11 -0
- package/src/templates/Dashboard/index.tsx +173 -0
- package/src/templates/DetailsView/KPIs.tsx +70 -0
- package/src/templates/DetailsView/MetadataItem.tsx +35 -0
- package/src/templates/DetailsView/Properties.tsx +127 -0
- package/src/templates/DetailsView/Table.tsx +104 -0
- package/src/templates/DetailsView/data.ts +67 -0
- package/src/templates/DetailsView/index.tsx +102 -0
- package/src/templates/DetailsView/usePaginationData.ts +155 -0
- package/src/templates/DetailsView/utils.ts +51 -0
- package/src/templates/Form/index.tsx +107 -0
- package/src/templates/KanbanBoard/ColumnContainer.tsx +89 -0
- package/src/templates/KanbanBoard/TaskCard.tsx +130 -0
- package/src/templates/KanbanBoard/data.tsx +140 -0
- package/src/templates/KanbanBoard/dependencies.json +6 -0
- package/src/templates/KanbanBoard/index.tsx +179 -0
- package/src/templates/KanbanBoard/styles.tsx +76 -0
- package/src/templates/KanbanBoard/types.ts +21 -0
- package/src/templates/ListView/Indicator.tsx +42 -0
- package/src/templates/ListView/Kpi.tsx +120 -0
- package/src/templates/ListView/Table.tsx +55 -0
- package/src/templates/ListView/data.tsx +179 -0
- package/src/templates/ListView/dependencies.json +5 -0
- package/src/templates/ListView/index.tsx +245 -0
- package/src/templates/ListView/usePaginationData.ts +158 -0
- package/src/templates/Welcome/index.tsx +101 -0
- package/src/templates/package.json +30 -0
- 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
|
+
};
|