CEC-4640: add bulk add to fleet (#384)

* refactor bulkactions component

* refactor bulk actions

* update dom tests

* add addToFleet hook

* make signal optional

* implement code splitting

* add deps

* remove test label
This commit is contained in:
Tristan Timblin
2023-07-10 17:30:11 -04:00
committed by GitHub
parent db88d5eba1
commit 754e445c09
33 changed files with 739 additions and 437 deletions

View File

@@ -43,17 +43,20 @@ exports[`VehicleTable Render 1`] = `
role="group"
>
<button
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium Mui-disabled MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary css-sghohy-MuiButtonBase-root-MuiButton-root"
disabled=""
tabindex="-1"
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeMedium MuiButton-containedSizeMedium MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary css-sghohy-MuiButtonBase-root-MuiButton-root"
tabindex="0"
type="button"
>
Update Configs
Add Tags
<span
class="MuiTouchRipple-root css-8je8zh-MuiTouchRipple-root"
/>
</button>
<button
aria-haspopup="menu"
aria-label="select action"
class="MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary MuiButton-root MuiButton-contained MuiButton-containedPrimary MuiButton-sizeSmall MuiButton-containedSizeSmall MuiButtonGroup-grouped MuiButtonGroup-groupedHorizontal MuiButtonGroup-groupedContained MuiButtonGroup-groupedContainedHorizontal MuiButtonGroup-groupedContainedPrimary css-11qr2p8-MuiButtonBase-root-MuiButton-root"
data-testid="dropdown-button-expand"
tabindex="0"
type="button"
>
@@ -482,7 +485,6 @@ exports[`VehicleTable Render 1`] = `
</tfoot>
</table>
</div>
<div />
</div>
</div>
</div>

View File

@@ -7,17 +7,14 @@ import { Link } from "react-router-dom";
import { Permissions } from "../../../utils/roles";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";
import { VehicleProvider, VehicleConsumer } from "../../Contexts/VehicleContext";
import { VehicleProvider } from "../../Contexts/VehicleContext";
import CarSelectionTable from "../../Controls/CarSelectionTable";
import OptionsDropdown from "../../Controls/OptionsDropdown";
import { RoleWrap } from "../../Controls/RoleWrap";
import SearchField from "../../Controls/SearchField";
import DropDownButton from "../../Controls/DropDownButton";
import TransformModal from "../../TransformModal";
import BulkActions from "../../BulkActions";
import { useLocalStorage } from "../../useLocalStorage";
import useStyles from "../../useStyles";
import TaskRunner from "../../../utils/taskRunner";
import GeneralConfirmation from "../../GeneralConfirmation";
const MainForm = () => {
const classes = useStyles();
@@ -25,22 +22,7 @@ const MainForm = () => {
const [online, setOnline] = useState(false);
const [onlineHMI, setOnlineHMI] = useState(false);
const [selectedVins, setSelectedVins] = useState([]);
const [config, setConfig] = useState({
force: {
label: "Force push",
type: "boolean",
value: false
},
});
const [tagsToAdd, setTagsToAdd] = useState({
tags: {
label: "Tags",
type: "list.string",
value: [],
},
});
const [activeModal, setActiveModal] = useState(null);
const { setTitle, setSitePath, setMessage } = useStatusContext();
const { setTitle, setSitePath } = useStatusContext();
const {
token: {
idToken: { jwtToken: token },
@@ -70,65 +52,6 @@ const MainForm = () => {
});
};
const handleUploadConfig = (fn) => {
const taskRunner = new TaskRunner(5);
const request = (vin, i) => {
const messagePrefix = `${i + 1}/${selectedVins.length} "${vin}":`;
return async () => {
const result = await fn(vin, config.force.value, token)
.then(() => {
setMessage(`${messagePrefix} updated.`);
})
.catch((error) => {
setMessage(`${messagePrefix} ${error.message}`);
});
return result;
}
}
selectedVins.forEach((vin, i) => taskRunner.push(request(vin, i)))
}
const handleAddTags = async (fn) => {
await fn(selectedVins, tagsToAdd.tags.value, token)
.then(() => setMessage(`Added ${tagsToAdd.tags.value.length} tags to ${selectedVins.length} vehicles.`))
.catch((error) => setMessage(error.message));
};
const handleDelete = async (fn) => {
const taskRunner = new TaskRunner(5);
const request = (vin) => {
return async () => {
return fn(vin, token)
.then(() => {
setMessage(`Deleted ${selectedVins.length} vehicles`);
setSelectedVins([]);
})
.catch((error) => {
setMessage(error.message);
})
}
}
selectedVins.forEach((vin) => taskRunner.push(request(vin)));
};
const actions = [
{
name: "Update Configs",
disabled: selectedVins.length === 0,
trigger: () => setActiveModal("updateConfig"),
},
{
name: "Add Tags",
disabled: selectedVins.length === 0,
trigger: () => setActiveModal("addTags"),
},
{
name: "Delete",
disabled: selectedVins.length === 0,
trigger: () => setActiveModal("delete"),
},
];
const handleOnlineHMI = (event) => {
setOnlineHMI(event.target.checked);
};
@@ -152,7 +75,7 @@ const MainForm = () => {
<AddCircleIcon fontSize="large" />
</Link>
</RoleWrap>
<DropDownButton actions={actions} payload={[selectedVins]} />
<BulkActions vins={selectedVins} actions={["addTags", "addToFleet", "deleteVehicles", "updateConfig"]} />
</Grid>
<Grid item md={4} className={classes.textCenterAlign}>
<SearchField classes={classes} onSearch={handleSearch} savedSearchValue={search} />
@@ -190,35 +113,6 @@ const MainForm = () => {
onSelect={handleSelect}
onSelectAll={handleSelectAll}
/>
<VehicleConsumer>
{(context) => (<>
<TransformModal
open={activeModal === "updateConfig"}
close={() => setActiveModal(null)}
title="Update Configs"
body={`You are updating the config for the following VINs: ${selectedVins.join(", ")}.`}
data={config}
setData={setConfig}
submit={() => handleUploadConfig(context.uploadConfig)}
/>
<TransformModal
open={activeModal === "addTags"}
close={() => setActiveModal(null)}
title="Add Tags"
body={`You are adding tags for the following VINs: ${selectedVins.join(", ")}.`}
data={tagsToAdd}
setData={setTagsToAdd}
submit={() => handleAddTags(context.addTags)}
/>
<GeneralConfirmation
open={activeModal === "delete"}
close={() => setActiveModal(null)}
title="Delete"
message={`You are about to delete the following VINs: ${selectedVins.join(", ")}`}
actionFunction={() => handleDelete(context.deleteVehicle)}
/>
</>)}
</VehicleConsumer>
</div>
);
};