diff --git a/src/components/Contexts/VehicleContext.jsx b/src/components/Contexts/VehicleContext.jsx
index eb09f0e..ef6b781 100644
--- a/src/components/Contexts/VehicleContext.jsx
+++ b/src/components/Contexts/VehicleContext.jsx
@@ -354,6 +354,26 @@ export const VehicleProvider = ({ children }) => {
}
}
+ const addFlashpackVersionECUMapping = async (model, trim, year, flashpack, ecuName, ecuVersion, token) => {
+ try {
+ setBusy(true);
+
+ const data = {
+ "car_ecu_name": ecuName,
+ "car_ecu_version": ecuVersion,
+ }
+
+ const result = await api.addFlashpackVersionECUMapping(model, trim, year, flashpack, data, token)
+ if (result.error) {
+ throw new Error(`Add flashpack version ECU mapping error. ${result.message}`);
+ }
+
+ return result;
+ } finally {
+ setBusy(false)
+ }
+ }
+
const deleteFlashpackVersion = async (model, trim, year, flashpack, token) => {
try {
setBusy(true);
@@ -367,7 +387,22 @@ export const VehicleProvider = ({ children }) => {
const result = await api.deleteFlashpackVersion(data, token);
if (result.error) {
- throw new Error(`Delete flashpack ecu mappings error. ${result.message}`);
+ throw new Error(`Delete flashpack version error. ${result.message}`);
+ }
+
+ return result;
+ } finally {
+ setBusy(false);
+ }
+ };
+
+ const deleteFlashpackVersionECUMapping = async (model, trim, year, flashpack, ecuName, ecuVersion, token) => {
+ try {
+ setBusy(true);
+
+ const result = await api.deleteFlashpackVersionECUMapping(model, trim, year, flashpack, ecuName, ecuVersion, token);
+ if (result.error) {
+ throw new Error(`Delete flashpack ecu mapping error. ${result.message}`);
}
return result;
@@ -427,7 +462,9 @@ export const VehicleProvider = ({ children }) => {
flashpackECUMappings,
getFlashpackECUMappings,
addFlashpackVersion,
+ addFlashpackVersionECUMapping,
deleteFlashpackVersion,
+ deleteFlashpackVersionECUMapping,
getCarFlashpackVersionInfo,
}}
>
diff --git a/src/components/Flashpack/AddMapping/__snapshots__/index.test.jsx.snap b/src/components/Flashpack/AddMapping/__snapshots__/index.test.jsx.snap
new file mode 100644
index 0000000..f85f07c
--- /dev/null
+++ b/src/components/Flashpack/AddMapping/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,612 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`FlashpackECUMappingAdd Render 1`] = `
+
+`;
diff --git a/src/components/Flashpack/AddMapping/index.jsx b/src/components/Flashpack/AddMapping/index.jsx
new file mode 100644
index 0000000..2da1a17
--- /dev/null
+++ b/src/components/Flashpack/AddMapping/index.jsx
@@ -0,0 +1,134 @@
+import {
+ Button,
+ TextField
+} from "@material-ui/core";
+import ECUDropDown from "../../Controls/ECUDropDown";
+import React, { useEffect, useState } from "react";
+import { useParams } from "react-router-dom";
+import { Redirect } from "react-router";
+import { logger } from "../../../services/monitoring";
+import { useStatusContext } from "../../Contexts/StatusContext";
+import { useVehicleContext, VehicleProvider } from "../../Contexts/VehicleContext";
+import { useUserContext } from "../../Contexts/UserContext";
+import useStyles from "../../useStyles";
+
+const MainForm = () => {
+ const { model, trim, year, flashpack } = useParams();
+ const {
+ token: {
+ idToken: { jwtToken: token },
+ },
+ } = useUserContext();
+ const classes = useStyles();
+ const [redirect, setRedirect] = useState(null);
+ const { setMessage, setTitle, setSitePath } = useStatusContext();
+ const [ecuName, setECUName] = useState("");
+ const [ecuVersion, setECUVersion] = useState("");
+ const {
+ addFlashpackVersionECUMapping,
+ busy,
+ } = useVehicleContext();
+
+ useEffect(() => {
+ setTitle(`Add Flashpack ECU Version Mapping`);
+ setSitePath([
+ {
+ label: "Tools",
+ link: "/tools/flashpacks",
+ },
+ {
+ label: "Flashpack Versions",
+ link: "/tools/flashpacks",
+ },
+ {
+ label: `Flashpack ${flashpack}`,
+ link: `/tools/flashpack/${model}/${trim}/${year}/${flashpack}`
+ },
+ {
+ label: `Add Flashpack ECU Version Mapping`,
+ },
+ ]);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ const onCarECUNameChange = (event) => {
+ let newECU = event.target.value
+
+ setECUName(newECU)
+ }
+
+ const onCarECUVersionChange = (event) => {
+ let newECUVersion = event.target.value
+
+ setECUVersion(newECUVersion)
+ }
+
+ const onSubmit = async (event) => {
+ try {
+ event.preventDefault();
+
+ const result = await addFlashpackVersionECUMapping(model, trim, parseInt(year), flashpack, ecuName, ecuVersion, token);
+ if (!result || result.error) return;
+
+ setMessage(`Added ${year} ${model} ${trim} ${flashpack} ${ecuName} ${ecuVersion}`);
+ setRedirect(`/tools/flashpack/${model}/${trim}/${year}/${flashpack}`);
+ } catch (e) {
+ setMessage(e.message);
+ logger.warn(e.stack);
+ }
+ };
+
+ if (redirect && redirect.length > 0) {
+ return ;
+ }
+
+ return (
+
+ );
+};
+
+const FlashpackECUMappingAdd = () => (
+
+
+
+);
+
+export default FlashpackECUMappingAdd;
\ No newline at end of file
diff --git a/src/components/Flashpack/AddMapping/index.test.jsx b/src/components/Flashpack/AddMapping/index.test.jsx
new file mode 100644
index 0000000..3076847
--- /dev/null
+++ b/src/components/Flashpack/AddMapping/index.test.jsx
@@ -0,0 +1,46 @@
+jest.mock("../../Contexts/VehicleContext");
+jest.mock("../../Contexts/StatusContext");
+jest.mock("../../Contexts/UserContext");
+jest.mock("@material-ui/core/utils/unstable_useId", () =>
+ jest.fn().mockReturnValue("mui-test-id")
+);
+import { render, waitFor } from "@testing-library/react";
+import { MemoryRouter, Route } from "react-router-dom";
+import { VehicleProvider } from "../../Contexts/VehicleContext";
+import { StatusProvider } from "../../Contexts/StatusContext";
+import { UserProvider, setToken } from "../../Contexts/UserContext";
+import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing";
+import MainForm from "./index";
+import addSnapshotSerializer from "../../../utils/snapshot";
+
+const renderFlashpackECUMappingAdd = async () => {
+ const { container } = render(
+
+
+
+
+
+
+
+
+
+
+
+ );
+ await waitFor(() => {
+ /* render */
+ });
+ return container;
+};
+
+describe("FlashpackECUMappingAdd", () => {
+ beforeAll(() => {
+ addSnapshotSerializer(expect);
+ });
+
+ it("Render", async () => {
+ setToken(TEST_AUTH_OBJECT_FISKER);
+ const container = await renderFlashpackECUMappingAdd();
+ expect(container).toMatchSnapshot();
+ });
+});
diff --git a/src/components/Flashpack/Details/__snapshots__/index.test.jsx.snap b/src/components/Flashpack/Details/__snapshots__/index.test.jsx.snap
index 303487f..f4e0c40 100644
--- a/src/components/Flashpack/Details/__snapshots__/index.test.jsx.snap
+++ b/src/components/Flashpack/Details/__snapshots__/index.test.jsx.snap
@@ -15,6 +15,29 @@ exports[`FlashpackDetails Render 1`] = `
data-testid="mocked-vehicleprovider"
>
+
@@ -70,6 +93,29 @@ exports[`FlashpackDetails Render 1`] = `
+ |
+
+ Delete
+
+
+ |
+
diff --git a/src/components/Flashpack/Details/index.jsx b/src/components/Flashpack/Details/index.jsx
index 9eec669..974e4f4 100644
--- a/src/components/Flashpack/Details/index.jsx
+++ b/src/components/Flashpack/Details/index.jsx
@@ -1,6 +1,8 @@
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import {
+ Grid,
+ IconButton,
Table,
TableBody,
TableCell,
@@ -8,12 +10,18 @@ import {
TablePagination,
TableRow,
} from "@material-ui/core";
+import AddCircleIcon from "@material-ui/icons/AddCircle";
import { logger } from "../../../services/monitoring";
+import DeleteIcon from "@material-ui/icons/Delete";
+import clsx from "clsx";
+import { Link } from "react-router-dom";
import { useVehicleContext, VehicleProvider } from "../../Contexts/VehicleContext";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";
import TableHeaderSortable from "../../Table/HeaderSortable";
import { useLocalStorage } from "../../useLocalStorage";
+import DeleteConfirmation from "../../DeleteConfirmation";
+import { RoleWrap } from "../../Controls/RoleWrap";
import useStyles from "../../useStyles";
const tableColumns = [
@@ -25,6 +33,10 @@ const tableColumns = [
id: "car_ecu_version",
label: "ECU Version",
},
+ {
+ id: "delete",
+ label: "Delete",
+ },
];
const PAGE_SIZE = "FLASHPACK_MAPPINGS_TABLE_PAGE_SIZE";
@@ -37,15 +49,20 @@ const MainForm = () => {
const [pageIndex, setPageIndex] = useState(0);
const [orderBy, setOrderBy] = useState("flashpack");
const [order, setOrder] = useState("desc");
+ const [showDeleteModal, setShowDeleteModal] = useState(false);
+ const [rowToDelete, setRowToDelete] = useState({});
const {
getFlashpackECUMappings,
flashpackECUMappings,
totalFlashpackECUMappings,
+ deleteFlashpackVersionECUMapping,
} = useVehicleContext();
const {
token: {
idToken: { jwtToken: token },
},
+ groups,
+ providers,
} = useUserContext();
useEffect(() => {
@@ -118,8 +135,35 @@ const MainForm = () => {
}
};
+ const onDeleteClick = (row) => {
+ setRowToDelete(row);
+ setShowDeleteModal(true);
+ }
+
+ const sendDelete = async () => {
+ if (rowToDelete) {
+ try {
+ const result = await deleteFlashpackVersionECUMapping(rowToDelete.car_model, rowToDelete.car_trim, rowToDelete.car_year, rowToDelete.flashpack, rowToDelete.car_ecu_name, rowToDelete.car_ecu_version, token);
+ if (!result || result.error) return;
+
+ setMessage(`Deleted ${rowToDelete.car_year} ${rowToDelete.car_model} ${rowToDelete.car_trim} ${rowToDelete.flashpack} ${rowToDelete.car_ecu_name} ${rowToDelete.car_ecu_version}`);
+ loadFlashpackECUMappings();
+ } catch (e) {
+ setMessage(e.message);
+ logger.warn(e.stack);
+ }
+ }
+ };
+
return (
+
+
+
+
+
+
+
{
{row.car_ecu_version}
+
+
+ onDeleteClick(row)}
+ aria-label={`Send delete for ${row.car_year} ${row.car_model} ${row.car_trim} ${row.flashpack} ${row.car_ecu_name} ${row.car_ecu_version}`}
+ size="small"
+ color="primary"
+ >
+
+
+
+
))}
@@ -147,7 +207,7 @@ const MainForm = () => {
) : (
{
+
setShowDeleteModal(false)}
+ deleteFunction={sendDelete}
+ />
);
};
diff --git a/src/components/Flashpack/Details/index.test.jsx b/src/components/Flashpack/Details/index.test.jsx
index b0f11fb..f366725 100644
--- a/src/components/Flashpack/Details/index.test.jsx
+++ b/src/components/Flashpack/Details/index.test.jsx
@@ -18,8 +18,8 @@ const renderFlashpackDetails = async () => {
-
-
+
+
diff --git a/src/components/Routes/SiteRoutes.jsx b/src/components/Routes/SiteRoutes.jsx
index ada8471..2c6cc5e 100644
--- a/src/components/Routes/SiteRoutes.jsx
+++ b/src/components/Routes/SiteRoutes.jsx
@@ -36,6 +36,7 @@ const SuppliersList = React.lazy(() => import("../Suppliers/List"));
const SupplierDetails = React.lazy(() => import("../Suppliers/Details"));
const Flashpacks = React.lazy(() => import("../Flashpack"));
const FlashpackDetails = React.lazy(() => import("../Flashpack/Details"));
+const FlashpackECUMappingAdd = React.lazy(() => import("../Flashpack/AddMapping"))
const FlashpackAdd = React.lazy(() => import("../Flashpack/Add"))
const Datascope = React.lazy(() => import("../Dashboard"));
const Sums = React.lazy(() => import("../SUMS/List"))
@@ -297,6 +298,15 @@ const SiteRoutes = () => {
rolesPerGroup={Permissions.FiskerRead}
providers={providers}
/>
+ }
+ type={TYPES.PROTECTED}
+ token={token}
+ groups={groups}
+ rolesPerGroup={Permissions.FiskerCreate}
+ providers={providers}
+ />
}
diff --git a/src/services/vehiclesAPI.js b/src/services/vehiclesAPI.js
index 2f4ea17..c908f27 100644
--- a/src/services/vehiclesAPI.js
+++ b/src/services/vehiclesAPI.js
@@ -295,6 +295,18 @@ const vehiclesAPI = {
.catch(errorHandler)
},
+ addFlashpackVersionECUMapping: async (model, trim, year, flashpack, data, token) => {
+ return fetch(`${API_ENDPOINT}/flashpack_version_ecu_mapping/${model}/${trim}/${year}/${flashpack}`, {
+ method: "POST",
+ headers: Object.assign(
+ { "Content-Type": "application/json" },
+ getAuthHeaderOptions(token),
+ ),
+ body: JSON.stringify(data),
+ }).then(fetchRespHandler)
+ .catch(errorHandler)
+ },
+
deleteFlashpackVersion: async (data, token) => {
return fetch(`${API_ENDPOINT}/flashpack_version`, {
method: "DELETE",
@@ -307,6 +319,17 @@ const vehiclesAPI = {
.catch(errorHandler)
},
+ deleteFlashpackVersionECUMapping: async (model, trim, year, flashpack, ecuName, ecuVersion, token) => {
+ return fetch(`${API_ENDPOINT}/flashpack_version_ecu_mapping/${model}/${trim}/${year}/${flashpack}/${ecuName}/${ecuVersion}`, {
+ method: "DELETE",
+ headers: Object.assign(
+ { "Content-Type": "application/json" },
+ getAuthHeaderOptions(token)
+ ),
+ }).then(fetchRespHandler)
+ .catch(errorHandler)
+ },
+
getCarFlashpackVersionInfo: async (vin, token) => {
return fetch(`${API_ENDPOINT}/flashpack_version_info/${vin}`, {
method: "GET",