diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js index 7d64b94..f665b6e 100644 --- a/src/components/App/App.test.js +++ b/src/components/App/App.test.js @@ -9,7 +9,6 @@ jest.mock("../../services/vehiclesAPI"); jest.mock("../../services/superset"); jest.mock("../../services/suppliersAPI"); jest.mock("../../services/issueAPI"); -jest.mock("../TransformModal"); import { act, cleanup, render, diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap index e4a3185..58174e8 100644 --- a/src/components/App/__snapshots__/App.test.js.snap +++ b/src/components/App/__snapshots__/App.test.js.snap @@ -6314,6 +6314,7 @@ exports[`App Route /packages authenticated 1`] = ` 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" > @@ -12296,17 +12297,20 @@ exports[`App Route /vehicles authenticated 1`] = ` role="group" > + + + + ) +} \ No newline at end of file diff --git a/src/components/BulkActions/__snapshots__/index.test.jsx.snap b/src/components/BulkActions/__snapshots__/index.test.jsx.snap new file mode 100644 index 0000000..bd9330b --- /dev/null +++ b/src/components/BulkActions/__snapshots__/index.test.jsx.snap @@ -0,0 +1,53 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`BulkActions Render 1`] = ` +
+
+
+
+ + +
+
+
+
+`; diff --git a/src/components/BulkActions/actions/AddTags.jsx b/src/components/BulkActions/actions/AddTags.jsx new file mode 100644 index 0000000..bb90206 --- /dev/null +++ b/src/components/BulkActions/actions/AddTags.jsx @@ -0,0 +1,43 @@ +import { useState, forwardRef, useImperativeHandle } from "react"; +import { useStatusContext } from "../../Contexts/StatusContext"; +import { useUserContext } from "../../Contexts/UserContext"; +import TextInputList from "../../Controls/TextInputList"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +export default forwardRef(({ + vins, + vinCSV, +}, ref) => { + const { setMessage } = useStatusContext(); + const { token: { idToken: { jwtToken: token } } } = useUserContext(); + + const [tags, setTags] = useState([]); + + useImperativeHandle(ref, () => ({ + async submit() { + return vehiclesAPI + .addTags(vins, tags, token) + .then((data) => { + if (data.error) { + setMessage(`${data.error}: ${data.message}`); + } else if (data.tags && data.vins) { + setMessage(`Added ${data.tags.length} tags to ${data.vins.length} vehicles.`); + } else { + setMessage(JSON.stringify(data)); + } + }); + }, + })); + + return ( +
+

+ You are adding tags to the following VINs: {vinCSV}. +

+ +
+ ); +}); \ No newline at end of file diff --git a/src/components/BulkActions/actions/AddTags.test.jsx b/src/components/BulkActions/actions/AddTags.test.jsx new file mode 100644 index 0000000..b870f0e --- /dev/null +++ b/src/components/BulkActions/actions/AddTags.test.jsx @@ -0,0 +1,51 @@ +jest.mock("../../Contexts/UserContext"); +jest.mock("../../Contexts/StatusContext"); +jest.mock("../../../services/vehiclesAPI"); + +import React, { useState } from "react"; +import { + render, + act, +} from "@testing-library/react"; +import { UserProvider, setToken } from "../../Contexts/UserContext"; +import { StatusProvider } from "../../Contexts/StatusContext"; +import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing"; +import AddTags from "./AddTags"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useState: jest.fn(), +})); + +jest.mock('../../Controls/TextInputList', () => { + const React = require('react'); + return () =>
; +}); + +describe("BulkActions/AddTags", () => { + beforeAll(() => { + setToken(TEST_AUTH_OBJECT_FISKER); + }); + + it("makes request to update the config of multiple vehicles", async () => { + useState.mockReturnValue([["myTag"], jest.fn()]); + const api = jest.spyOn(vehiclesAPI, "addTags"); + const ref = React.createRef(); + + render( + + + + + + ); + + await act(async () => ref.current.submit()); + expect(api).toHaveBeenCalled(); + }); +}); diff --git a/src/components/BulkActions/actions/AddToFleet.jsx b/src/components/BulkActions/actions/AddToFleet.jsx new file mode 100644 index 0000000..39200da --- /dev/null +++ b/src/components/BulkActions/actions/AddToFleet.jsx @@ -0,0 +1,99 @@ +import { useEffect, useState, forwardRef, useImperativeHandle } from "react"; +import { + FormControl, + InputLabel, + MenuItem, + Select, +} from '@material-ui/core'; +import { useStatusContext } from "../../Contexts/StatusContext"; +import { useUserContext } from "../../Contexts/UserContext"; +import fleetsAPI from "../../../services/fleetsAPI"; + +export default forwardRef(({ + vins, + vinCSV, +}, ref) => { + const { setMessage } = useStatusContext(); + const { token: { idToken: { jwtToken: token } } } = useUserContext(); + + const [fleet, setFleet] = useState(""); + const [options, setOptions] = useState([]); + + useImperativeHandle(ref, () => ({ + async submit() { + if (!fleet) { + setMessage(`Select a valid fleet, "${fleet}" is invalid.`); + return Promise.reject("Invalid Fleet"); + } + + return fleetsAPI + .addFleetVehicles(fleet, { vins }, token) + .then((response) => { + if (response.error) { + setMessage(`${response.error}: ${response.message}`); + } + + if (response.vins) { + setMessage(`Added ${response.vins.length} vehicles to ${fleet}.`); + return; + } + + setMessage(`Something unexpected happened while attempting to add vehicles to fleet.`); + }) + .catch((error) => { + setMessage(JSON.stringify(error)); + }); + }, + })); + + useEffect(() => { + const controller = new AbortController(); + let isMounted = true; + + fleetsAPI + .getFleets({ + search: "", + limit: 10, + offset: 0, + order: `id desc`, + }, token, controller) + .then(({ data }) => { + if (isMounted) { + setOptions(data.map((fleet) => fleet.name)); + } + }); + return () => { + controller?.abort(); + isMounted = false; + } + }, [token]); + + const handleChange = (event) => { + setFleet(event.target.value); + } + + return ( +
+

+ You are adding the following VINs to a fleet: {vinCSV}. +

+ {options && ( + + + Fleet + + + + )} +
+ ); +}); \ No newline at end of file diff --git a/src/components/BulkActions/actions/AddToFleet.test.jsx b/src/components/BulkActions/actions/AddToFleet.test.jsx new file mode 100644 index 0000000..6d28e82 --- /dev/null +++ b/src/components/BulkActions/actions/AddToFleet.test.jsx @@ -0,0 +1,53 @@ +jest.mock("../../Contexts/UserContext"); +jest.mock("../../Contexts/StatusContext"); +jest.mock("../../../services/fleetsAPI"); + +import React, { useEffect, useState } from "react"; +import { + render, + act, +} from "@testing-library/react"; +import { UserProvider, setToken } from "../../Contexts/UserContext"; +import { StatusProvider } from "../../Contexts/StatusContext"; +import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing"; +import AddToFleet from "./AddToFleet"; +import fleetsAPI from "../../../services/fleetsAPI"; + +jest.mock('react', () => ({ + ...jest.requireActual('react'), + useState: jest.fn(), +})); + +jest.mock('@material-ui/core/FormControl', () => { + const React = require('react'); + return () =>
; +}); + +describe("BulkActions/AddToFleet", () => { + beforeAll(() => { + setToken(TEST_AUTH_OBJECT_FISKER); + }); + + it("makes request to update the config of multiple vehicles", async () => { + useState + .mockReturnValueOnce(["Default-Test", jest.fn()]) + .mockReturnValueOnce([["Default-Test"], jest.fn()]); + const api = jest.spyOn(fleetsAPI, "addFleetVehicles"); + const ref = React.createRef(); + + render( + + + + + + ); + + await act(async () => ref.current.submit()); + expect(api).toHaveBeenCalled(); + }); +}); diff --git a/src/components/BulkActions/actions/DeleteVehicles.jsx b/src/components/BulkActions/actions/DeleteVehicles.jsx new file mode 100644 index 0000000..452fbd3 --- /dev/null +++ b/src/components/BulkActions/actions/DeleteVehicles.jsx @@ -0,0 +1,55 @@ +import { forwardRef, useImperativeHandle } from "react"; +import { useStatusContext } from "../../Contexts/StatusContext"; +import { useUserContext } from "../../Contexts/UserContext"; +import TaskRunner from "../../../utils/taskRunner"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +export default forwardRef(({ + vins, + vinCSV, +}, ref) => { + const { setMessage } = useStatusContext(); + const { token: { idToken: { jwtToken: token } } } = useUserContext(); + + useImperativeHandle(ref, () => ({ + async submit() { + return new Promise((resolve, reject) => { + const taskRunner = new TaskRunner(5, vins.length); + let errorCount = 0; + + const task = (vin, index) => { + const progressMessage = `${index + 1}/${vins.length}`; + return async () => vehiclesAPI.deleteVehicle(vin, token) + .then((response) => { + if (response.error) { + errorCount += 1; + setMessage(`${progressMessage} ${response.error}: ${response.message}`); + } else { + setMessage(`${progressMessage} Deleted ${vin}`); + } + return response; + }) + .catch((error) => reject(error)); + } + + vins.forEach((vin, i) => { + taskRunner.push(task(vin, i)); + }); + + taskRunner.onComplete().then((responses) => { + const completeMessage = `${vins.length - errorCount}/${vins.length}`; + setMessage(`Successfully deleted ${completeMessage} vehicles.`); + resolve(responses); + }); + }); + }, + })); + + return ( +
+

+ You are about to delete the following VINs: {vinCSV}. +

+
+ ); +}); \ No newline at end of file diff --git a/src/components/BulkActions/actions/DeleteVehicles.test.jsx b/src/components/BulkActions/actions/DeleteVehicles.test.jsx new file mode 100644 index 0000000..8e019f0 --- /dev/null +++ b/src/components/BulkActions/actions/DeleteVehicles.test.jsx @@ -0,0 +1,40 @@ +jest.mock("../../Contexts/UserContext"); +jest.mock("../../Contexts/StatusContext"); +jest.mock("../../../services/vehiclesAPI"); + +import React from "react"; +import { + render, + act, +} from "@testing-library/react"; +import { UserProvider, setToken } from "../../Contexts/UserContext"; +import { StatusProvider } from "../../Contexts/StatusContext"; +import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing"; +import DeleteVehicles from "./DeleteVehicles"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +describe("BulkActions/DeleteVehicles", () => { + beforeAll(() => { + setToken(TEST_AUTH_OBJECT_FISKER); + }); + + it("makes request to delete multiple vehicles", async () => { + const api = jest.spyOn(vehiclesAPI, "deleteVehicle"); + const ref = React.createRef(); + + render( + + + + + + ); + + await act(async () => ref.current.submit()); + expect(api).toHaveBeenCalledTimes(3); + }); +}); diff --git a/src/components/BulkActions/actions/UpdateConfig.jsx b/src/components/BulkActions/actions/UpdateConfig.jsx new file mode 100644 index 0000000..a193a91 --- /dev/null +++ b/src/components/BulkActions/actions/UpdateConfig.jsx @@ -0,0 +1,74 @@ +import { useState, forwardRef, useImperativeHandle } from "react"; +import { + Checkbox, + FormControlLabel, +} from '@material-ui/core'; +import { useStatusContext } from "../../Contexts/StatusContext"; +import { useUserContext } from "../../Contexts/UserContext"; +import TaskRunner from "../../../utils/taskRunner"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +export default forwardRef(({ + vins, + vinCSV, +}, ref) => { + const { setMessage } = useStatusContext(); + const { token: { idToken: { jwtToken: token } } } = useUserContext(); + + const [forcePush, setForcePush] = useState(false); + + useImperativeHandle(ref, () => ({ + async submit() { + return new Promise((resolve, reject) => { + const taskRunner = new TaskRunner(5, vins.length); + let errorCount = 0; + + const task = (vin, index) => { + const progressMessage = `${index + 1}/${vins.length}`; + return async () => vehiclesAPI.updateConfig(vin, forcePush, token) + .then((response) => { + if (response.error) { + errorCount += 1; + setMessage(`${progressMessage} ${response.error}: ${response.message}`); + } else { + setMessage(`${progressMessage} Updated config for ${vin}`); + } + return response; + }) + .catch((error) => reject(error)); + } + + vins.forEach((vin, i) => { + taskRunner.push(task(vin, i)); + }); + + taskRunner.onComplete().then((responses) => { + const completeMessage = `${vins.length - errorCount}/${vins.length}`; + setMessage(`Successfully updated ${completeMessage} vehicles.`); + resolve(responses); + }); + }); + }, + })); + + const handleChange = () => { + setForcePush((forcePush) => !forcePush); + } + + return ( +
+

+ You are updating the config for the following VINs: {vinCSV}. +

+ handleChange()} + /> + } + /> +
+ ); +}); \ No newline at end of file diff --git a/src/components/BulkActions/actions/UpdateConfig.test.jsx b/src/components/BulkActions/actions/UpdateConfig.test.jsx new file mode 100644 index 0000000..6b5c189 --- /dev/null +++ b/src/components/BulkActions/actions/UpdateConfig.test.jsx @@ -0,0 +1,40 @@ +jest.mock("../../Contexts/UserContext"); +jest.mock("../../Contexts/StatusContext"); +jest.mock("../../../services/vehiclesAPI"); + +import React from "react"; +import { + render, + act, +} from "@testing-library/react"; +import { UserProvider, setToken } from "../../Contexts/UserContext"; +import { StatusProvider } from "../../Contexts/StatusContext"; +import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing"; +import UpdateConfig from "./UpdateConfig"; +import vehiclesAPI from "../../../services/vehiclesAPI"; + +describe("BulkActions/UpdateConfig", () => { + beforeAll(() => { + setToken(TEST_AUTH_OBJECT_FISKER); + }); + + it("makes request to update the config of multiple vehicles", async () => { + const api = jest.spyOn(vehiclesAPI, "updateConfig"); + const ref = React.createRef(); + + render( + + + + + + ); + + await act(async () => ref.current.submit()); + expect(api).toHaveBeenCalledTimes(3); + }); +}); diff --git a/src/components/BulkActions/index.jsx b/src/components/BulkActions/index.jsx index 81f5f3c..0d645d3 100644 --- a/src/components/BulkActions/index.jsx +++ b/src/components/BulkActions/index.jsx @@ -1,84 +1,86 @@ -import { useEffect, useState } from "react"; -import TransformModal from "../TransformModal"; +import { useEffect, useState, useRef, Suspense, lazy } from "react"; import DropDownButton from "../Controls/DropDownButton"; -import { useUserContext } from "../Contexts/UserContext"; -import { useStatusContext } from "../Contexts/StatusContext"; -import useAddTags from "./useAddTags"; -import useUpdateConfig from "./useUpdateConfig"; +import { Modal } from "./Modal"; -const transformArrayToCSV = (arr) => arr.join(", "); +// Code-splitting individual actions +// https://react.dev/reference/react/lazy +const AddTags = lazy(() => import("./actions/AddTags")); +const AddToFleet = lazy(() => import("./actions/AddToFleet")); +const DeleteVehicles = lazy(() => import("./actions/DeleteVehicles")); +const UpdateConfig = lazy(() => import("./actions/UpdateConfig")); export default function BulkActions({ vins = [], + actions = [], }) { - const [vinCSV, setVinCSV] = useState(transformArrayToCSV(vins)); + const [title, setTitle] = useState("Action"); const [active, setActive] = useState(null); - const actions = [ - { - name: "Update Configs", - disabled: vins.length === 0, - trigger: () => setActive("updateConfig"), - }, + const activeRef = useRef(); + + const filteredActions = [ { + id: "addTags", name: "Add Tags", - disabled: vins.length === 0, + disabled: false, trigger: () => setActive("addTags"), }, - ]; - - const updateConfig = useUpdateConfig(); - const addTags = useAddTags(); - - const { setMessage } = useStatusContext(); - const { - token: { - idToken: { jwtToken: token }, + { + id: "addToFleet", + name: "Add To Fleet", + disabled: false, + trigger: () => setActive("addToFleet"), }, - } = useUserContext(); + { + id: "deleteVehicles", + name: "Delete", + disabled: false, + trigger: () => setActive("deleteVehicles"), + }, + { + id: "updateConfig", + name: "Update Config", + disabled: false, + trigger: () => setActive("updateConfig"), + } + ].filter((action) => actions.includes(action.id)); - const handleUpdateConfig = () => { - updateConfig.submit(vins, token) - .then(() => { - setMessage(`${vins.length} vehicles updated.`); - }) - .catch((error) => { - setMessage(error.message); - }); + const payload = { + vins, + vinCSV: vins.join(", "), + ref: activeRef + }; + + const handleClose = () => { + setActive(null); } - const handleAddTags = () => { - addTags.submit(vins, token) - .then(() => setMessage(`Added ${addTags.data.tags.value.length} tags to ${vins.length} vehicles.`)) - .catch((error) => setMessage(error.message)); + const handleSubmit = () => { + activeRef.current.submit(); + handleClose(); } - const handleClose = () => setActive(null); - useEffect(() => { - setVinCSV(transformArrayToCSV(vins)); - }, [vins]); + setTitle(filteredActions.find((action) => active === action.id)?.name || "Action"); + }, [active, filteredActions]); return ( <> - - + - + submit={handleSubmit} + > + Loading...
}> +
+ {active === "addTags" && } + {active === "addToFleet" && } + {active === "deleteVehicles" && } + {active === "updateConfig" && } +
+ + - ); + ) } diff --git a/src/components/BulkActions/index.test.jsx b/src/components/BulkActions/index.test.jsx new file mode 100644 index 0000000..2471c91 --- /dev/null +++ b/src/components/BulkActions/index.test.jsx @@ -0,0 +1,77 @@ +jest.mock("../Contexts/UserContext"); +jest.mock("../Contexts/StatusContext"); + +import React from "react"; +import { + fireEvent, + render, + screen, + waitFor, +} from "@testing-library/react"; +import { UserProvider, setToken } from "../Contexts/UserContext"; +import { StatusProvider } from "../Contexts/StatusContext"; +import { TEST_AUTH_OBJECT_FISKER } from "../../utils/testing"; +import BulkActions from "."; +import addSnapshotSerializer from "../../utils/snapshot"; + +describe("BulkActions", () => { + beforeAll(() => { + setToken(TEST_AUTH_OBJECT_FISKER); + global.URL.createObjectURL = jest.fn(); + global.URL.revokeObjectURL = jest.fn(); + addSnapshotSerializer(expect); + }); + + it("Render", async () => { + const { container } = render( + + + + + + ); + await waitFor(() => { + /* render */ + }); + expect(container).toMatchSnapshot(); + }); + + it("opens a modal", async () => { + render( + + + + + + ); + + const buttonEl = screen.getByText("Add Tags"); + fireEvent.click(buttonEl); + const submitEl = screen.getByText("Submit"); + expect(submitEl).toBeTruthy(); + }); + + it("filters valid actions", async () => { + render( + + + + + + ); + + const dropdownBtn = screen.getByTestId("dropdown-button-expand"); + fireEvent.click(dropdownBtn); + const dropdownOptions = screen.getAllByRole("menuitem"); + expect(dropdownOptions.length).toBe(2); + }); +}); diff --git a/src/components/BulkActions/useAddTags.js b/src/components/BulkActions/useAddTags.js deleted file mode 100644 index 7696595..0000000 --- a/src/components/BulkActions/useAddTags.js +++ /dev/null @@ -1,22 +0,0 @@ -import { useState } from "react"; -import vehiclesAPI from "../../services/vehiclesAPI"; - -export default function useAddTags() { - const [tags, setTags] = useState({ - tags: { - label: "Tags", - type: "list.string", - value: [], - }, - }); - - const submit = async (vins, token) => { - return vehiclesAPI.addTags(vins, tags.tags.value, token); - } - - return { - data: tags, - setData: setTags, - submit, - }; -} diff --git a/src/components/BulkActions/useUpdateConfig.js b/src/components/BulkActions/useUpdateConfig.js deleted file mode 100644 index c648bd1..0000000 --- a/src/components/BulkActions/useUpdateConfig.js +++ /dev/null @@ -1,40 +0,0 @@ -import { useState } from "react"; -import TaskRunner from "../../utils/taskRunner"; -import vehiclesAPI from "../../services/vehiclesAPI"; - -export default function useUpdateConfig() { - const [config, setConfig] = useState({ - force: { - label: "Force Push", - type: "boolean", - value: false, - }, - }); - - const submit = async (vins, token) => { - return new Promise((resolve, reject) => { - const taskRunner = new TaskRunner(5); - - const task = (vin, isLast) => { - return async () => vehiclesAPI.updateConfig(vin, config.force.value, token) - .then((response) => { - if (isLast) { - if (response.error) { - reject(response); - } - resolve(response) - } - }) - .catch((error) => reject(error)); - } - - vins.forEach((vin, index) => taskRunner.push(task(vin, index === vins.length - 1))); - }); - } - - return { - data: config, - setData: setConfig, - submit, - }; -} \ No newline at end of file diff --git a/src/components/Cars/List/__snapshots__/index.test.jsx.snap b/src/components/Cars/List/__snapshots__/index.test.jsx.snap index fe97dcd..c7dacb1 100644 --- a/src/components/Cars/List/__snapshots__/index.test.jsx.snap +++ b/src/components/Cars/List/__snapshots__/index.test.jsx.snap @@ -43,17 +43,20 @@ exports[`VehicleTable Render 1`] = ` role="group" >
-
diff --git a/src/components/Cars/List/index.jsx b/src/components/Cars/List/index.jsx index e2adbb4..7fa7bd8 100644 --- a/src/components/Cars/List/index.jsx +++ b/src/components/Cars/List/index.jsx @@ -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 = () => { - + @@ -190,35 +113,6 @@ const MainForm = () => { onSelect={handleSelect} onSelectAll={handleSelectAll} /> - - {(context) => (<> - 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)} - /> - setActiveModal(null)} - title="Add Tags" - body={`You are adding tags for the following VINs: ${selectedVins.join(", ")}.`} - data={tagsToAdd} - setData={setTagsToAdd} - submit={() => handleAddTags(context.addTags)} - /> - setActiveModal(null)} - title="Delete" - message={`You are about to delete the following VINs: ${selectedVins.join(", ")}`} - actionFunction={() => handleDelete(context.deleteVehicle)} - /> - )} - ); }; diff --git a/src/components/Controls/DropDownButton/__snapshots__/index.test.jsx.snap b/src/components/Controls/DropDownButton/__snapshots__/index.test.jsx.snap index 80616fa..1e70b1f 100644 --- a/src/components/Controls/DropDownButton/__snapshots__/index.test.jsx.snap +++ b/src/components/Controls/DropDownButton/__snapshots__/index.test.jsx.snap @@ -21,6 +21,7 @@ exports[`DropDownButton Render 1`] = ` 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" > diff --git a/src/components/Controls/DropDownButton/index.jsx b/src/components/Controls/DropDownButton/index.jsx index 6820877..9da3f34 100644 --- a/src/components/Controls/DropDownButton/index.jsx +++ b/src/components/Controls/DropDownButton/index.jsx @@ -65,6 +65,7 @@ const DropDownButton = ({ actions = [], payload = [] }) => { aria-label="select action" aria-haspopup="menu" onClick={handleToggle} + data-testid="dropdown-button-expand" > diff --git a/src/components/Fleets/Status/Details/__snapshots__/index.test.jsx.snap b/src/components/Fleets/Status/Details/__snapshots__/index.test.jsx.snap index e674ba8..1d198d8 100644 --- a/src/components/Fleets/Status/Details/__snapshots__/index.test.jsx.snap +++ b/src/components/Fleets/Status/Details/__snapshots__/index.test.jsx.snap @@ -156,7 +156,7 @@ exports[`FleetDetailsTab Render 1`] = ` tabindex="0" type="button" > - Update Configs + Add Tags @@ -165,6 +165,7 @@ exports[`FleetDetailsTab Render 1`] = ` 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" > diff --git a/src/components/Fleets/Status/Details/index.jsx b/src/components/Fleets/Status/Details/index.jsx index 2926b38..efe480c 100644 --- a/src/components/Fleets/Status/Details/index.jsx +++ b/src/components/Fleets/Status/Details/index.jsx @@ -96,7 +96,7 @@ const MainForm = ({ name }) => { - + setShowDeleteModal(false)} deleteFunction={onDelete} /> diff --git a/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap b/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap index b9ee191..4e0190c 100644 --- a/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap +++ b/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap @@ -164,7 +164,7 @@ exports[`DetailsTab Render 1`] = ` tabindex="0" type="button" > - Update Configs + Add Tags @@ -173,6 +173,7 @@ exports[`DetailsTab Render 1`] = ` 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" > diff --git a/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap b/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap index 42fdb41..b7d2e95 100644 --- a/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap +++ b/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap @@ -252,7 +252,7 @@ exports[`FleetStatus Render 1`] = ` tabindex="0" type="button" > - Update Configs + Add Tags @@ -261,6 +261,7 @@ exports[`FleetStatus Render 1`] = ` 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" > diff --git a/src/components/TransformModal/__mocks__/index.jsx b/src/components/TransformModal/__mocks__/index.jsx deleted file mode 100644 index dc2966e..0000000 --- a/src/components/TransformModal/__mocks__/index.jsx +++ /dev/null @@ -1,5 +0,0 @@ -const TransformModalMock = jest.fn().mockImplementation(() => { - return
-}); - -export default TransformModalMock; diff --git a/src/components/TransformModal/__snapshots__/index.test.jsx.snap b/src/components/TransformModal/__snapshots__/index.test.jsx.snap deleted file mode 100644 index c2a5f3f..0000000 --- a/src/components/TransformModal/__snapshots__/index.test.jsx.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TransformModal Render 1`] = ` -