@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,140 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Copy,
|
|
3
|
+
Edit,
|
|
4
|
+
Magnifier,
|
|
5
|
+
Success,
|
|
6
|
+
} from "@hitachivantara/uikit-react-icons";
|
|
7
|
+
|
|
8
|
+
import { Column, Task } from "./types";
|
|
9
|
+
|
|
10
|
+
export const columns: Column[] = [
|
|
11
|
+
{
|
|
12
|
+
id: "col1",
|
|
13
|
+
title: "Draft",
|
|
14
|
+
color: "info",
|
|
15
|
+
icon: <Edit color="info" />,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: "col2",
|
|
19
|
+
title: "To Review",
|
|
20
|
+
color: "negativeStrong",
|
|
21
|
+
icon: <Copy color="negativeStrong" />,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "col3",
|
|
25
|
+
title: "In Review",
|
|
26
|
+
color: "warningStrong",
|
|
27
|
+
icon: <Magnifier color="warningStrong" />,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "col4",
|
|
31
|
+
title: "Reviewed",
|
|
32
|
+
color: "positiveStrong",
|
|
33
|
+
icon: <Success color="positiveStrong" />,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
export const tasks: Task[] = [
|
|
38
|
+
{
|
|
39
|
+
id: "task1",
|
|
40
|
+
columnId: "col1",
|
|
41
|
+
title: "Task 1",
|
|
42
|
+
statusLevel: 1,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "task2",
|
|
46
|
+
columnId: "col1",
|
|
47
|
+
title: "Task 2",
|
|
48
|
+
statusLevel: 2,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: "task3",
|
|
52
|
+
columnId: "col2",
|
|
53
|
+
title: "Task 3",
|
|
54
|
+
statusLevel: 3,
|
|
55
|
+
users: [
|
|
56
|
+
{
|
|
57
|
+
name: "Ben",
|
|
58
|
+
avatar: "https://i.imgur.com/56Eeg1g.png",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "Beatrice",
|
|
62
|
+
avatar: "https://i.imgur.com/bE7vg3N.png",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: "Wayne",
|
|
66
|
+
avatar: "https://i.imgur.com/ea22egF.png",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "task4",
|
|
72
|
+
columnId: "col2",
|
|
73
|
+
title: "Task 4",
|
|
74
|
+
statusLevel: 2,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "task5",
|
|
78
|
+
columnId: "col2",
|
|
79
|
+
title: "Task 5",
|
|
80
|
+
statusLevel: 4,
|
|
81
|
+
users: [
|
|
82
|
+
{
|
|
83
|
+
name: "Beatrice",
|
|
84
|
+
avatar: "https://i.imgur.com/bE7vg3N.png",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "Wayne",
|
|
88
|
+
avatar: "https://i.imgur.com/ea22egF.png",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "task6",
|
|
94
|
+
columnId: "col3",
|
|
95
|
+
title: "Task 6",
|
|
96
|
+
statusLevel: 5,
|
|
97
|
+
users: [
|
|
98
|
+
{
|
|
99
|
+
name: "Ben",
|
|
100
|
+
avatar: "https://i.imgur.com/56Eeg1g.png",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "Beatrice",
|
|
104
|
+
avatar: "https://i.imgur.com/bE7vg3N.png",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "Wayne",
|
|
108
|
+
avatar: "https://i.imgur.com/ea22egF.png",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "Clara Soul",
|
|
112
|
+
avatar: "https://i.imgur.com/6sYhSb6.png",
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "task7",
|
|
118
|
+
columnId: "col4",
|
|
119
|
+
title: "Task 7",
|
|
120
|
+
statusLevel: 2,
|
|
121
|
+
users: [
|
|
122
|
+
{
|
|
123
|
+
name: "Ben",
|
|
124
|
+
avatar: "https://i.imgur.com/56Eeg1g.png",
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "task8",
|
|
130
|
+
columnId: "col4",
|
|
131
|
+
title: "Task 8",
|
|
132
|
+
statusLevel: 3,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: "task9",
|
|
136
|
+
columnId: "col4",
|
|
137
|
+
title: "Task 9",
|
|
138
|
+
statusLevel: 3,
|
|
139
|
+
},
|
|
140
|
+
];
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
DndContext,
|
|
4
|
+
DragEndEvent,
|
|
5
|
+
DragOverEvent,
|
|
6
|
+
DragOverlay,
|
|
7
|
+
DragStartEvent,
|
|
8
|
+
PointerSensor,
|
|
9
|
+
useSensor,
|
|
10
|
+
useSensors,
|
|
11
|
+
} from "@dnd-kit/core";
|
|
12
|
+
import { arrayMove, SortableContext } from "@dnd-kit/sortable";
|
|
13
|
+
|
|
14
|
+
import { ColumnContainer } from "./ColumnContainer";
|
|
15
|
+
import { columns as defaultColumns, tasks as defaultTasks } from "./data";
|
|
16
|
+
import classes from "./styles";
|
|
17
|
+
import { TaskCard } from "./TaskCard";
|
|
18
|
+
import { Column, Task } from "./types";
|
|
19
|
+
|
|
20
|
+
const KanbanBoard = () => {
|
|
21
|
+
const sensors = useSensors(
|
|
22
|
+
useSensor(PointerSensor, {
|
|
23
|
+
activationConstraint: {
|
|
24
|
+
distance: 2,
|
|
25
|
+
},
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const [tasks, setTasks] = useState<Task[]>(defaultTasks);
|
|
30
|
+
const [columns, setColumns] = useState<Column[]>(defaultColumns);
|
|
31
|
+
const [activeColumn, setActiveColumn] = useState<Column | null>(null);
|
|
32
|
+
const [activeTask, setActiveTask] = useState<Task | null>(null);
|
|
33
|
+
const [creatingTask, setCreatingTask] = useState<boolean>(false);
|
|
34
|
+
|
|
35
|
+
const columnsId = useMemo(() => columns.map((col) => col.id), [columns]);
|
|
36
|
+
|
|
37
|
+
const onDragStart = (event: DragStartEvent) => {
|
|
38
|
+
if (event.active.data.current?.type === "Column") {
|
|
39
|
+
setActiveColumn(event.active.data.current.column);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (event.active.data.current?.type === "Task") {
|
|
43
|
+
setActiveTask(event.active.data.current.task);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const onDragEnd = (event: DragEndEvent) => {
|
|
48
|
+
setActiveColumn(null);
|
|
49
|
+
setActiveTask(null);
|
|
50
|
+
|
|
51
|
+
const { active, over } = event;
|
|
52
|
+
if (!over) return;
|
|
53
|
+
|
|
54
|
+
const activeId = active.id;
|
|
55
|
+
const overId = over.id;
|
|
56
|
+
|
|
57
|
+
if (activeId === overId) return;
|
|
58
|
+
|
|
59
|
+
const isActiveAColumn = active.data.current?.type === "Column";
|
|
60
|
+
if (!isActiveAColumn) return;
|
|
61
|
+
|
|
62
|
+
setColumns((cs) => {
|
|
63
|
+
const activeColumnIndex = cs.findIndex((col) => col.id === activeId);
|
|
64
|
+
const overColumnIndex = cs.findIndex((col) => col.id === overId);
|
|
65
|
+
|
|
66
|
+
return arrayMove(cs, activeColumnIndex, overColumnIndex);
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const onDragOver = (event: DragOverEvent) => {
|
|
71
|
+
const { active, over } = event;
|
|
72
|
+
console.log(active, over);
|
|
73
|
+
if (!over) return;
|
|
74
|
+
|
|
75
|
+
const activeId = active.id;
|
|
76
|
+
const overId = over.id;
|
|
77
|
+
|
|
78
|
+
if (activeId === overId) return;
|
|
79
|
+
|
|
80
|
+
const isActiveATask = active.data.current?.type === "Task";
|
|
81
|
+
const isOverATask = over.data.current?.type === "Task";
|
|
82
|
+
|
|
83
|
+
if (!isActiveATask) return;
|
|
84
|
+
|
|
85
|
+
// Dropping a Task over another Task
|
|
86
|
+
if (isActiveATask && isOverATask) {
|
|
87
|
+
setTasks((ts) => {
|
|
88
|
+
const activeIndex = ts.findIndex((t) => t.id === activeId);
|
|
89
|
+
const overIndex = ts.findIndex((t) => t.id === overId);
|
|
90
|
+
|
|
91
|
+
if (ts[activeIndex].columnId !== ts[overIndex].columnId) {
|
|
92
|
+
ts[activeIndex].columnId = ts[overIndex].columnId;
|
|
93
|
+
return arrayMove(ts, activeIndex, overIndex - 1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return arrayMove(ts, activeIndex, overIndex);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const isOverAColumn = over.data.current?.type === "Column";
|
|
101
|
+
|
|
102
|
+
// Dropping a Task over a Column
|
|
103
|
+
if (isActiveATask && isOverAColumn) {
|
|
104
|
+
setTasks((ts) => {
|
|
105
|
+
const activeIndex = ts.findIndex((t) => t.id === activeId);
|
|
106
|
+
|
|
107
|
+
ts[activeIndex].columnId = overId.toString();
|
|
108
|
+
return arrayMove(ts, activeIndex, activeIndex);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const addTask = async (columnId: string) => {
|
|
114
|
+
try {
|
|
115
|
+
setCreatingTask(true);
|
|
116
|
+
|
|
117
|
+
const highestId = tasks.reduce((acc, task) => {
|
|
118
|
+
const taskId = Number.parseInt(task.id.replace("task", ""), 10);
|
|
119
|
+
return taskId > acc ? taskId : acc;
|
|
120
|
+
}, 0);
|
|
121
|
+
|
|
122
|
+
setTasks((ts) => [
|
|
123
|
+
...ts,
|
|
124
|
+
{
|
|
125
|
+
id: `task${highestId + 1}`,
|
|
126
|
+
columnId,
|
|
127
|
+
title: `Task ${highestId + 1}`,
|
|
128
|
+
},
|
|
129
|
+
]);
|
|
130
|
+
} finally {
|
|
131
|
+
setCreatingTask(false);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const deleteTask = (taskId: string) => {
|
|
136
|
+
const newTasks = tasks.filter((task) => task.id !== taskId);
|
|
137
|
+
setTasks(newTasks);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<div className={classes.root}>
|
|
142
|
+
<DndContext
|
|
143
|
+
sensors={sensors}
|
|
144
|
+
onDragStart={onDragStart}
|
|
145
|
+
onDragEnd={onDragEnd}
|
|
146
|
+
onDragOver={onDragOver}
|
|
147
|
+
>
|
|
148
|
+
<div className={classes.board}>
|
|
149
|
+
<SortableContext items={columnsId}>
|
|
150
|
+
{columns.map((column) => (
|
|
151
|
+
<ColumnContainer
|
|
152
|
+
key={column.id}
|
|
153
|
+
column={column}
|
|
154
|
+
tasks={tasks.filter((task) => task.columnId === column.id)}
|
|
155
|
+
addTask={addTask}
|
|
156
|
+
deleteTask={deleteTask}
|
|
157
|
+
addEnabled={!creatingTask}
|
|
158
|
+
/>
|
|
159
|
+
))}
|
|
160
|
+
</SortableContext>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
<DragOverlay>
|
|
164
|
+
{activeColumn && (
|
|
165
|
+
<ColumnContainer
|
|
166
|
+
column={activeColumn}
|
|
167
|
+
tasks={tasks.filter((task) => task.columnId === activeColumn.id)}
|
|
168
|
+
/>
|
|
169
|
+
)}
|
|
170
|
+
{activeTask && <TaskCard task={activeTask} deleteTask={deleteTask} />}
|
|
171
|
+
</DragOverlay>
|
|
172
|
+
</DndContext>
|
|
173
|
+
</div>
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
export { KanbanBoard as Component };
|
|
178
|
+
|
|
179
|
+
export default KanbanBoard;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { css } from "@emotion/css";
|
|
2
|
+
import { theme } from "@hitachivantara/uikit-react-core";
|
|
3
|
+
|
|
4
|
+
const styles = {
|
|
5
|
+
root: css({
|
|
6
|
+
marginTop: theme.space.md,
|
|
7
|
+
}),
|
|
8
|
+
board: css({
|
|
9
|
+
display: "flex",
|
|
10
|
+
gap: theme.space.sm,
|
|
11
|
+
}),
|
|
12
|
+
columnContainer: css({
|
|
13
|
+
// This is needed because we need to have a set height on the column container so that
|
|
14
|
+
// dnd-kit will work. In some edge cases (when content of the column is a single item with
|
|
15
|
+
// a certain height) drag between columns wouldn't work.
|
|
16
|
+
height: 100,
|
|
17
|
+
width: "100%",
|
|
18
|
+
}),
|
|
19
|
+
column: css({
|
|
20
|
+
flex: 1,
|
|
21
|
+
padding: theme.spacing("sm", "xs"),
|
|
22
|
+
borderRadius: theme.radii.large,
|
|
23
|
+
backgroundColor: theme.colors.primaryDimmed,
|
|
24
|
+
}),
|
|
25
|
+
columnHeader: css({
|
|
26
|
+
display: "flex",
|
|
27
|
+
flexDirection: "row",
|
|
28
|
+
justifyContent: "space-between",
|
|
29
|
+
alignItems: "center",
|
|
30
|
+
marginBottom: theme.space.lg,
|
|
31
|
+
padding: theme.spacing(0, "xs"),
|
|
32
|
+
"&:hover": {
|
|
33
|
+
cursor: "grab",
|
|
34
|
+
},
|
|
35
|
+
}),
|
|
36
|
+
columnTitle: css({
|
|
37
|
+
display: "flex",
|
|
38
|
+
alignItems: "center",
|
|
39
|
+
gap: theme.space.xs,
|
|
40
|
+
}),
|
|
41
|
+
columnCards: css({}),
|
|
42
|
+
count: css({
|
|
43
|
+
borderRadius: theme.radii.full,
|
|
44
|
+
width: 20,
|
|
45
|
+
height: 20,
|
|
46
|
+
backgroundColor: theme.colors.border,
|
|
47
|
+
display: "grid",
|
|
48
|
+
placeItems: "center",
|
|
49
|
+
}),
|
|
50
|
+
card: css({
|
|
51
|
+
borderRadius: theme.radii.round,
|
|
52
|
+
}),
|
|
53
|
+
cardHeader: css({
|
|
54
|
+
"&:hover": {
|
|
55
|
+
cursor: "grab",
|
|
56
|
+
},
|
|
57
|
+
backgroundColor: theme.colors.bgContainer,
|
|
58
|
+
zIndex: 200,
|
|
59
|
+
borderRadius: `${theme.radii.round} ${theme.radii.round} 0 0`,
|
|
60
|
+
}),
|
|
61
|
+
cardDeleteIcon: css({
|
|
62
|
+
position: "absolute",
|
|
63
|
+
top: theme.space.xs,
|
|
64
|
+
right: theme.space.xs,
|
|
65
|
+
}),
|
|
66
|
+
cardSemanticBar: css({
|
|
67
|
+
height: 20,
|
|
68
|
+
borderRadius: theme.radii.round,
|
|
69
|
+
top: -2,
|
|
70
|
+
}),
|
|
71
|
+
cardActions: css({
|
|
72
|
+
borderTop: "none",
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export default styles;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { HvColor } from "@hitachivantara/uikit-react-core";
|
|
2
|
+
|
|
3
|
+
export type Column = {
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
color?: HvColor;
|
|
7
|
+
icon?: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type User = {
|
|
11
|
+
name: string;
|
|
12
|
+
avatar: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type Task = {
|
|
16
|
+
id: string;
|
|
17
|
+
columnId: Column["id"];
|
|
18
|
+
title: string;
|
|
19
|
+
users?: User[];
|
|
20
|
+
statusLevel?: number;
|
|
21
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import ReactChart from "react-google-charts";
|
|
2
|
+
|
|
3
|
+
import { TrendData } from "./data";
|
|
4
|
+
|
|
5
|
+
interface IndicatorProps {
|
|
6
|
+
data?: TrendData;
|
|
7
|
+
variation?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const Indicator = ({ data, variation }: IndicatorProps) => (
|
|
11
|
+
<div style={{ pointerEvents: "none", marginRight: -4 }}>
|
|
12
|
+
<ReactChart
|
|
13
|
+
width="50px"
|
|
14
|
+
height="32px"
|
|
15
|
+
chartType="AreaChart"
|
|
16
|
+
loader={<div>Loading Chart</div>}
|
|
17
|
+
data={data}
|
|
18
|
+
options={{
|
|
19
|
+
legend: "none",
|
|
20
|
+
colors: variation === "up" ? ["green"] : ["red"],
|
|
21
|
+
tooltip: {
|
|
22
|
+
trigger: "none",
|
|
23
|
+
},
|
|
24
|
+
hAxis: {
|
|
25
|
+
minValue: 0,
|
|
26
|
+
maxValue: 10,
|
|
27
|
+
gridlines: {
|
|
28
|
+
color: "transparent",
|
|
29
|
+
},
|
|
30
|
+
baselineColor: "transparent",
|
|
31
|
+
},
|
|
32
|
+
backgroundColor: "transparent",
|
|
33
|
+
vAxis: {
|
|
34
|
+
gridlines: {
|
|
35
|
+
color: "transparent",
|
|
36
|
+
},
|
|
37
|
+
baselineColor: "transparent",
|
|
38
|
+
},
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
);
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { css, cx } from "@emotion/css";
|
|
2
|
+
import {
|
|
3
|
+
HvCard,
|
|
4
|
+
HvCardProps,
|
|
5
|
+
HvLoading,
|
|
6
|
+
HvTableInstance,
|
|
7
|
+
HvTypography,
|
|
8
|
+
theme,
|
|
9
|
+
} from "@hitachivantara/uikit-react-core";
|
|
10
|
+
import { BottomXS, TopXS } from "@hitachivantara/uikit-react-icons";
|
|
11
|
+
|
|
12
|
+
import { getStatusIcon, ListViewEntry, TrendData } from "./data";
|
|
13
|
+
import { Indicator } from "./Indicator";
|
|
14
|
+
|
|
15
|
+
const classes = {
|
|
16
|
+
container: css({
|
|
17
|
+
padding: theme.space.sm,
|
|
18
|
+
}),
|
|
19
|
+
card: css({
|
|
20
|
+
cursor: "pointer",
|
|
21
|
+
width: "100%",
|
|
22
|
+
padding: 0,
|
|
23
|
+
textAlign: "left",
|
|
24
|
+
}),
|
|
25
|
+
title: css({
|
|
26
|
+
margin: `${theme.space.xs} 0`,
|
|
27
|
+
}),
|
|
28
|
+
content: css({
|
|
29
|
+
display: "flex",
|
|
30
|
+
alignItems: "center",
|
|
31
|
+
}),
|
|
32
|
+
variation: css({
|
|
33
|
+
display: "flex",
|
|
34
|
+
flex: 1,
|
|
35
|
+
justifyContent: "flex-end",
|
|
36
|
+
alignItems: "center",
|
|
37
|
+
}),
|
|
38
|
+
selected: css({
|
|
39
|
+
outline: `1px solid ${theme.colors.borderDisabled}`,
|
|
40
|
+
}),
|
|
41
|
+
loading: css({
|
|
42
|
+
margin: `${theme.space.xs} 0`,
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
interface KpiProps {
|
|
47
|
+
title: string;
|
|
48
|
+
count?: number;
|
|
49
|
+
color: HvCardProps["statusColor"];
|
|
50
|
+
variation?: string;
|
|
51
|
+
status: number;
|
|
52
|
+
instance: HvTableInstance<ListViewEntry, string>;
|
|
53
|
+
kpiSelection: number | undefined;
|
|
54
|
+
setKpiSelection: (value: number | undefined) => void;
|
|
55
|
+
trendData?: TrendData;
|
|
56
|
+
loading?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const Kpi = ({
|
|
60
|
+
title,
|
|
61
|
+
count,
|
|
62
|
+
color,
|
|
63
|
+
variation,
|
|
64
|
+
status,
|
|
65
|
+
instance,
|
|
66
|
+
kpiSelection,
|
|
67
|
+
trendData,
|
|
68
|
+
loading,
|
|
69
|
+
setKpiSelection,
|
|
70
|
+
}: KpiProps) => {
|
|
71
|
+
const handleKpiClick = () => {
|
|
72
|
+
setKpiSelection(status);
|
|
73
|
+
if (status !== kpiSelection) {
|
|
74
|
+
instance?.setFilter?.("status", `${status}`);
|
|
75
|
+
} else {
|
|
76
|
+
instance?.setFilter?.("status", "");
|
|
77
|
+
setKpiSelection(undefined);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<HvCard
|
|
83
|
+
id={`kpi${status}`}
|
|
84
|
+
selectable
|
|
85
|
+
selected={status === kpiSelection}
|
|
86
|
+
bgcolor="bgContainer"
|
|
87
|
+
statusColor={color}
|
|
88
|
+
onClick={handleKpiClick}
|
|
89
|
+
className={cx(classes.card, {
|
|
90
|
+
[classes.selected]: status === kpiSelection,
|
|
91
|
+
})}
|
|
92
|
+
icon={getStatusIcon(status)}
|
|
93
|
+
tabIndex={0}
|
|
94
|
+
>
|
|
95
|
+
<div className={classes.container}>
|
|
96
|
+
<HvTypography variant="label">{title}</HvTypography>
|
|
97
|
+
{loading ? (
|
|
98
|
+
<HvLoading className={classes.loading} small />
|
|
99
|
+
) : (
|
|
100
|
+
<div className={classes.content}>
|
|
101
|
+
<HvTypography variant="title2" className={classes.title}>
|
|
102
|
+
{count}
|
|
103
|
+
</HvTypography>
|
|
104
|
+
<div className={classes.variation}>
|
|
105
|
+
<Indicator variation={variation} data={trendData} />
|
|
106
|
+
{variation === "up" ? (
|
|
107
|
+
<TopXS title="Up" color="positive" />
|
|
108
|
+
) : (
|
|
109
|
+
<BottomXS title="Up" color="negative" />
|
|
110
|
+
)}
|
|
111
|
+
<div>
|
|
112
|
+
<HvTypography variant="caption1">vs last 24h.</HvTypography>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
</div>
|
|
118
|
+
</HvCard>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import {
|
|
3
|
+
HvTable,
|
|
4
|
+
HvTableBody,
|
|
5
|
+
HvTableCell,
|
|
6
|
+
HvTableContainer,
|
|
7
|
+
HvTableHead,
|
|
8
|
+
HvTableHeader,
|
|
9
|
+
HvTableInstance,
|
|
10
|
+
HvTableRow,
|
|
11
|
+
} from "@hitachivantara/uikit-react-core";
|
|
12
|
+
|
|
13
|
+
import { getColumns, ListViewEntry } from "./data";
|
|
14
|
+
|
|
15
|
+
interface TableProps {
|
|
16
|
+
instance: HvTableInstance<ListViewEntry, string>;
|
|
17
|
+
id?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const Table = ({ instance, id }: TableProps) => {
|
|
21
|
+
const columns = useMemo(() => getColumns(), []);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<HvTableContainer style={{ padding: "2px" }} id={id}>
|
|
25
|
+
<HvTable variant="listrow" {...instance.getTableProps()}>
|
|
26
|
+
<HvTableHead>
|
|
27
|
+
<HvTableRow>
|
|
28
|
+
<HvTableCell variant="listcheckbox" />
|
|
29
|
+
{columns.map((col) => (
|
|
30
|
+
<HvTableHeader key={col.Header}>{col.Header}</HvTableHeader>
|
|
31
|
+
))}
|
|
32
|
+
</HvTableRow>
|
|
33
|
+
</HvTableHead>
|
|
34
|
+
<HvTableBody withNavigation {...instance.getTableBodyProps()}>
|
|
35
|
+
{instance.page.map((row) => {
|
|
36
|
+
instance.prepareRow(row);
|
|
37
|
+
const { key, ...rowProps } = row.getRowProps();
|
|
38
|
+
return (
|
|
39
|
+
<HvTableRow key={key} {...rowProps}>
|
|
40
|
+
{row.cells.map((cell) => {
|
|
41
|
+
const { key: cellKey, ...cellProps } = cell.getCellProps();
|
|
42
|
+
return (
|
|
43
|
+
<HvTableCell key={cellKey} {...cellProps}>
|
|
44
|
+
{cell.render("Cell")}
|
|
45
|
+
</HvTableCell>
|
|
46
|
+
);
|
|
47
|
+
})}
|
|
48
|
+
</HvTableRow>
|
|
49
|
+
);
|
|
50
|
+
})}
|
|
51
|
+
</HvTableBody>
|
|
52
|
+
</HvTable>
|
|
53
|
+
</HvTableContainer>
|
|
54
|
+
);
|
|
55
|
+
};
|