From cd31c3619646df3f566cda420b49ef013b86489e Mon Sep 17 00:00:00 2001 From: Samir Kamal <1954121+skamril@users.noreply.github.com> Date: Tue, 8 Aug 2023 15:56:57 +0200 Subject: [PATCH] feat(common): update GoupedDataTable --- webapp/package.json | 2 +- .../GroupedDataTable/CreateRowDialog.tsx | 14 +-- .../common/GroupedDataTable/index.tsx | 86 +++++++++---------- 3 files changed, 50 insertions(+), 52 deletions(-) diff --git a/webapp/package.json b/webapp/package.json index dc8da4732f..a7bb313af9 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -42,7 +42,7 @@ "js-cookie": "3.0.1", "jwt-decode": "3.1.2", "lodash": "4.17.21", - "material-react-table": "^1.14.0", + "material-react-table": "1.14.0", "moment": "2.29.4", "notistack": "2.0.8", "os": "0.1.2", diff --git a/webapp/src/components/common/GroupedDataTable/CreateRowDialog.tsx b/webapp/src/components/common/GroupedDataTable/CreateRowDialog.tsx index a490a6f678..dba6c80b18 100644 --- a/webapp/src/components/common/GroupedDataTable/CreateRowDialog.tsx +++ b/webapp/src/components/common/GroupedDataTable/CreateRowDialog.tsx @@ -1,18 +1,19 @@ import { t } from "i18next"; +import { v4 as uuidv4 } from "uuid"; import AddCircleIcon from "@mui/icons-material/AddCircle"; import FormDialog from "../dialogs/FormDialog"; import StringFE from "../fieldEditors/StringFE"; import Fieldset from "../Fieldset"; import { SubmitHandlerPlus } from "../Form/types"; import SelectFE from "../fieldEditors/SelectFE"; -import { TData } from "."; +import { TRow } from "."; -interface Props { +interface Props { open: boolean; onClose: VoidFunction; onSubmit: (values: TData) => void; groups: string[]; - existingNames: TData["name"][]; + existingNames: Array; } const defaultValues = { @@ -20,13 +21,13 @@ const defaultValues = { group: "", }; -function CreateRowDialog({ +function CreateRowDialog({ open, onClose, onSubmit, groups, existingNames, -}: Props) { +}: Props) { //////////////////////////////////////////////////////////////// // Event Handlers //////////////////////////////////////////////////////////////// @@ -34,7 +35,7 @@ function CreateRowDialog({ const handleSubmit = ({ values, }: SubmitHandlerPlus) => { - onSubmit({ ...values, name: values.name.trim() }); + onSubmit({ ...values, id: uuidv4(), name: values.name.trim() } as TData); onClose(); }; @@ -78,7 +79,6 @@ function CreateRowDialog({ name="group" control={control} options={groups} - required sx={{ alignSelf: "center", }} diff --git a/webapp/src/components/common/GroupedDataTable/index.tsx b/webapp/src/components/common/GroupedDataTable/index.tsx index 0fd3e936c7..7e1ba77955 100644 --- a/webapp/src/components/common/GroupedDataTable/index.tsx +++ b/webapp/src/components/common/GroupedDataTable/index.tsx @@ -6,7 +6,6 @@ import { Button, IconButton, Tooltip } from "@mui/material"; import DeleteIcon from "@mui/icons-material/Delete"; import VisibilityIcon from "@mui/icons-material/Visibility"; import MaterialReactTable, { - MaterialReactTableProps, MRT_Row, MRT_RowSelectionState, MRT_ToggleDensePaddingButton, @@ -15,28 +14,26 @@ import MaterialReactTable, { type MRT_ColumnDef, } from "material-react-table"; import { useTranslation } from "react-i18next"; -import { useCallback, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import CreateRowDialog from "./CreateRowDialog"; import ConfirmationDialog from "../dialogs/ConfirmationDialog"; -export type TData = Record; +export type TRow = { id: string; name: string; group: string }; -export interface GroupedDataTableProps { - materialReactTableProps?: Partial; - data: T[]; - columns: MRT_ColumnDef[]; +export interface GroupedDataTableProps { + data: TData[]; + columns: MRT_ColumnDef[]; groups: string[]; - onSubmit: (values: T) => void; - onDelete: (ids: string[]) => void; + onCreate?: (values: TData) => void; + onDelete?: (ids: string[]) => void; } -function GroupedDataTable({ - materialReactTableProps, +function GroupedDataTable({ data, columns, groups, - onSubmit, + onCreate, onDelete, }: GroupedDataTableProps) { const { t } = useTranslation(); @@ -47,12 +44,13 @@ function GroupedDataTable({ const [tableData, setTableData] = useState(data); const [rowSelection, setRowSelection] = useState({}); - const isAnyRowSelected = useMemo(() => { - return Object.values(rowSelection).some((value) => value); - }, [rowSelection]); + const isAnyRowSelected = useMemo( + () => Object.values(rowSelection).some((value) => value), + [rowSelection] + ); const existingNames = useMemo( - () => tableData.map((row) => String(row.name).toLowerCase()), + () => tableData.map((row) => row.name.toLowerCase()), [tableData] ); @@ -61,35 +59,34 @@ function GroupedDataTable({ //////////////////////////////////////////////////////////////// const handleCreateRow = (values: TData) => { - onSubmit(values); - setTableData((prevTableData) => [...prevTableData, values]); + if (onCreate) { + onCreate(values); + setTableData((prevTableData) => [...prevTableData, values]); + } }; const handleDeleteSelection = () => { - /** - * `rowSelection` maps row indexes to selection status (boolean) - * convert it to an array of selected row indexes ignoring groups (non-integer) - */ + if (!onDelete) { + return; + } + const rowIndexes = Object.keys(rowSelection) .map(Number) + // ignore groups names .filter(Number.isInteger); - const rowsToDelete = rowIndexes.map((index) => tableData[index]); - const rowsToDeleteIds = rowsToDelete.map((row) => String(row.id)); - onDelete(rowsToDeleteIds); + const rowIdsToDelete = rowIndexes.map((index) => tableData[index].id); + onDelete(rowIdsToDelete); setTableData((prevTableData) => - prevTableData.filter((row) => !rowsToDelete.includes(row)) + prevTableData.filter((row) => !rowIdsToDelete.includes(row.id)) ); setRowSelection({}); setConfirmDialogOpen(false); }; - const handleRowClick = useCallback( - (row: MRT_Row) => { - const clusterId = row.original.id; - navigate(`${location.pathname}/${clusterId}`); - }, - [navigate, location.pathname] - ); + const handleRowClick = (row: MRT_Row) => { + const clusterId = row.original.id; + navigate(`${location.pathname}/${clusterId}`); + }; //////////////////////////////////////////////////////////////// // JSX @@ -98,9 +95,8 @@ function GroupedDataTable({ return ( <> columns, [columns])} + columns={columns} initialState={{ grouping: ["group"], density: "comfortable", @@ -115,15 +111,17 @@ function GroupedDataTable({ state={{ rowSelection }} renderTopToolbarCustomActions={() => ( - - {isAnyRowSelected && ( + {onCreate && ( + + )} + {isAnyRowSelected && onDelete && (