Skip to content

Commit

Permalink
feat(common): update GoupedDataTable
Browse files Browse the repository at this point in the history
  • Loading branch information
skamril authored and hdinia committed Aug 8, 2023
1 parent a04631c commit f8670fd
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 51 deletions.
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
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<TData extends TRow> {
open: boolean;
onClose: VoidFunction;
onSubmit: (values: TData) => void;
groups: string[];
existingNames: TData["name"][];
existingNames: Array<TData["name"]>;
}

const defaultValues = {
name: "",
group: "",
};

function CreateRowDialog({
function CreateRowDialog<TData extends TRow>({
open,
onClose,
onSubmit,
groups,
existingNames,
}: Props) {
}: Props<TData>) {
////////////////////////////////////////////////////////////////
// Event Handlers
////////////////////////////////////////////////////////////////

const handleSubmit = ({
values,
}: SubmitHandlerPlus<typeof defaultValues>) => {
onSubmit({ ...values, name: values.name.trim() });
onSubmit({ ...values, id: uuidv4(), name: values.name.trim() });
onClose();
};

Expand Down Expand Up @@ -78,7 +79,6 @@ function CreateRowDialog({
name="group"
control={control}
options={groups}
required
sx={{
alignSelf: "center",
}}
Expand Down
86 changes: 42 additions & 44 deletions webapp/src/components/common/GroupedDataTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<string, unknown>;
export type TRow = { id: string; name: string; group: string };

export interface GroupedDataTableProps<T extends TData> {
materialReactTableProps?: Partial<MaterialReactTableProps>;
data: T[];
columns: MRT_ColumnDef<T>[];
export interface GroupedDataTableProps<TData extends TRow> {
data: TData[];
columns: MRT_ColumnDef<TData>[];
groups: string[];
onSubmit: (values: T) => void;
onDelete: (ids: string[]) => void;
onCreate?: (values: TData) => void;
onDelete?: (ids: string[]) => void;
}

function GroupedDataTable({
materialReactTableProps,
function GroupedDataTable<TData extends TRow>({
data,
columns,
groups,
onSubmit,
onCreate,
onDelete,
}: GroupedDataTableProps<TData>) {
const { t } = useTranslation();
Expand All @@ -47,12 +44,13 @@ function GroupedDataTable({
const [tableData, setTableData] = useState(data);
const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});

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]
);

Expand All @@ -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<TData>) => {
const clusterId = row.original.id;
navigate(`${location.pathname}/${clusterId}`);
},
[navigate, location.pathname]
);
const handleRowClick = (row: MRT_Row<TData>) => {
const clusterId = row.original.id;
navigate(`${location.pathname}/${clusterId}`);
};

////////////////////////////////////////////////////////////////
// JSX
Expand All @@ -98,9 +95,8 @@ function GroupedDataTable({
return (
<>
<MaterialReactTable
{...materialReactTableProps}
data={tableData}
columns={useMemo(() => columns, [columns])}
columns={columns}
initialState={{
grouping: ["group"],
density: "comfortable",
Expand All @@ -115,15 +111,17 @@ function GroupedDataTable({
state={{ rowSelection }}
renderTopToolbarCustomActions={() => (
<Box sx={{ display: "flex", gap: 1 }}>
<Button
startIcon={<AddIcon />}
variant="contained"
size="small"
onClick={() => setCreateDialogOpen(true)}
>
{t("button.add")}
</Button>
{isAnyRowSelected && (
{onCreate && (
<Button
startIcon={<AddIcon />}
variant="contained"
size="small"
onClick={() => setCreateDialogOpen(true)}
>
{t("button.add")}
</Button>
)}
{isAnyRowSelected && onDelete && (
<Tooltip title={t("global.delete")}>
<Button
startIcon={<DeleteIcon />}
Expand Down

0 comments on commit f8670fd

Please sign in to comment.