CEC-4674: add bulk cancel updates (#386)

* add bulk cancel updates

* add permission check

* remove unused import

* make trigger multi-line
This commit is contained in:
Tristan Timblin
2023-07-18 12:26:39 -04:00
committed by GitHub
parent 177a138111
commit 7dff3be1da
7 changed files with 683 additions and 137 deletions

View File

@@ -1,15 +1,14 @@
import {
Checkbox,
Grid,
LinearProgress,
Table,
TableBody,
TableCell,
TableFooter,
TableHead,
TablePagination,
TableRow,
Tooltip,
} from "@material-ui/core";
import CancelIcon from "@material-ui/icons/Cancel";
import clsx from "clsx";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router";
@@ -17,7 +16,6 @@ import { Link } from "react-router-dom";
import { logger } from "../../../services/monitoring";
import { LocalDateTimeString } from "../../../utils/dates";
import { Permissions } from "../../../utils/roles";
import {
CarUpdatesProvider,
useCarUpdatesContext
@@ -28,21 +26,47 @@ import {
} from "../../Contexts/ManifestsContext";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";
import { RoleWrap } from "../../Controls/RoleWrap";
import { useLocalStorage } from "../../useLocalStorage";
import useStyles from "../../useStyles";
import ManifestDetails from "../Details";
import TableHeaderSortable from "../../Table/HeaderSortable";
import Toolbar from "../Toolbar";
const PAGE_SIZE = "MANIFEST_STATUS_PAGE_SIZE";
const tableColumns = [
{
id: "id",
label: "ID",
},
{
id: "vin",
label: "Vehicle",
},
{
id: "status",
label: "Status",
},
{
id: "created_at",
label: "Created",
},
{
id: "updated_at",
label: "Updated",
},
];
const MainForm = () => {
const { manifest_id } = useParams();
const classes = useStyles();
const [pageSize, setPageSize] = useLocalStorage(PAGE_SIZE, 10);
const [pageIndex, setPageIndex] = useState(0);
const [orderBy, setOrderBy] = useState("id");
const [order, setOrder] = useState("asc");
const [ids, setIds] = useState([]);
const { getManifests, manifests } = useManifestsContext();
const {
cancelUpdate,
getCarUpdates,
carUpdates,
totalCarUpdates,
@@ -54,10 +78,35 @@ const MainForm = () => {
token: {
idToken: { jwtToken: token },
},
groups,
providers,
} = useUserContext();
const handleSelectAll = () => {
setIds((ids) => ids.length === 0
? carUpdates.map((carUpdate) => carUpdate.id)
: []);
}
const handleSelect = (newId, selected) => {
if (selected) {
setIds((ids) => ids.filter((id) => id !== newId));
} else {
setIds((ids) => [...ids, newId]);
}
}
const handleSort = (_event, property) => {
if (property === orderBy) {
if (order === "asc") {
setOrder("desc");
} else {
setOrder("asc");
}
} else {
setOrderBy(property);
setOrder("asc");
}
};
useEffect(() => {
(async () => {
try {
@@ -100,6 +149,7 @@ const MainForm = () => {
manifest_id,
limit: pageSize,
offset: pageSize * pageIndex,
order: `${orderBy} ${order}`,
},
token
);
@@ -109,7 +159,7 @@ const MainForm = () => {
}
})();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [pageIndex, pageSize, token]);
}, [pageIndex, pageSize, token, order, orderBy]);
useEffect(() => {
try {
@@ -134,63 +184,58 @@ const MainForm = () => {
setPageIndex(0);
};
const sendCancel = async ({ id, vin }) => {
try {
await cancelUpdate(id, token);
setMessage(`Sent cancel for ${vin}`);
} catch (e) {
setMessage(e.message);
}
};
return (
<div className={clsx(classes.paper, classes.tableSize)}>
<Grid container className={classes.root} spacing={2}>
<Grid item md={8} className={classes.textJustifyAlign}>
<ManifestDetails />
</Grid>
<Grid item md={4} className={classes.textRightAlign}>
<Toolbar ids={ids} actions={["cancel"]} />
</Grid>
</Grid>
<Table>
<TableHead>
<TableRow>
<TableCell align="center">ID</TableCell>
<TableCell align="center">Vehicle</TableCell>
<TableCell align="center">Status</TableCell>
<TableCell align="center">Created</TableCell>
<TableCell align="center">Updated</TableCell>
<TableCell align="center"></TableCell>
</TableRow>
</TableHead>
<TableHeaderSortable
classes={classes}
orderBy={orderBy}
order={order}
columnData={tableColumns}
onSortRequest={handleSort}
multiSelect={true}
onSelectAll={handleSelectAll}
selectCount={ids ? ids.length : 0}
rowCount={carUpdates ? carUpdates.length : 0}
/>
<TableBody>
{carUpdates.map((row) => (
<TableRow key={row.id}>
<TableCell align="center">{row.id}</TableCell>
<TableCell align="center" style={{ verticalAlign: "top" }}>
<Link to={`/vehicle-status/${row.vin}`}>{row.vin}</Link>
</TableCell>
<TableCell align="center">
{row.status}
{row.progress > -1 && (
<LinearProgress variant="determinate" value={row.progress} />
)}
</TableCell>
<TableCell align="center">
{LocalDateTimeString(row.created)}
</TableCell>
<TableCell align="center">
{LocalDateTimeString(row.updated)}
</TableCell>
<TableCell>
<RoleWrap
groups={groups}
providers={providers}
rolesPerProvider={Permissions.FiskerMagnaCreate}
eitherComponent={<>No action</>}
>
<Tooltip key={row.vin} title={`Send cancel for ${row.vin}`}>
<Link to="#" onClick={() => sendCancel(row)}>
<CancelIcon />
</Link>
</Tooltip>
</RoleWrap>
</TableCell>
</TableRow>
))}
{carUpdates.map((row) => {
const isSelected = ids.indexOf(row.id) !== -1;
return (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox
checked={isSelected}
onChange={() => handleSelect(row.id, isSelected)}
/>
</TableCell>
<TableCell align="center">{row.id}</TableCell>
<TableCell align="center" style={{ verticalAlign: "top" }}>
<Link to={`/vehicle-status/${row.vin}`}>{row.vin}</Link>
</TableCell>
<TableCell align="center">
{row.status}
{row.progress > -1 && (
<LinearProgress variant="determinate" value={row.progress} />
)}
</TableCell>
<TableCell align="center">
{LocalDateTimeString(row.created)}
</TableCell>
<TableCell align="center">
{LocalDateTimeString(row.updated)}
</TableCell>
</TableRow>
)
})}
</TableBody>
<TableFooter>
<TableRow>
@@ -217,7 +262,6 @@ const MainForm = () => {
const ManifestStatus = () => (
<ManifestsProvider>
<CarUpdatesProvider>
<ManifestDetails />
<MainForm />
</CarUpdatesProvider>
</ManifestsProvider>