From f73b5125a36a5890b8b2e20dbc956ccce8865fda Mon Sep 17 00:00:00 2001
From: Tristan Timblin
Date: Wed, 21 Jun 2023 23:28:53 -0400
Subject: [PATCH 01/15] CEC-4594: add bulk actions to fleet (#368)
* CEC-4594: add bulk actions to fleet
* add reject case
---
src/components/BulkActions/index.jsx | 84 +++++++++++++++++++
src/components/BulkActions/useAddTags.js | 22 +++++
src/components/BulkActions/useUpdateConfig.js | 40 +++++++++
.../Controls/DropDownButton/index.jsx | 4 +
.../Details/__snapshots__/index.test.jsx.snap | 42 ++++++++++
.../Fleets/Status/Details/index.jsx | 4 +
.../__snapshots__/DetailsTab.test.jsx.snap | 42 ++++++++++
.../Status/__snapshots__/index.test.jsx.snap | 42 ++++++++++
src/components/TransformModal/index.jsx | 2 +-
9 files changed, 281 insertions(+), 1 deletion(-)
create mode 100644 src/components/BulkActions/index.jsx
create mode 100644 src/components/BulkActions/useAddTags.js
create mode 100644 src/components/BulkActions/useUpdateConfig.js
diff --git a/src/components/BulkActions/index.jsx b/src/components/BulkActions/index.jsx
new file mode 100644
index 0000000..81f5f3c
--- /dev/null
+++ b/src/components/BulkActions/index.jsx
@@ -0,0 +1,84 @@
+import { useEffect, useState } from "react";
+import TransformModal from "../TransformModal";
+import DropDownButton from "../Controls/DropDownButton";
+import { useUserContext } from "../Contexts/UserContext";
+import { useStatusContext } from "../Contexts/StatusContext";
+import useAddTags from "./useAddTags";
+import useUpdateConfig from "./useUpdateConfig";
+
+const transformArrayToCSV = (arr) => arr.join(", ");
+
+export default function BulkActions({
+ vins = [],
+}) {
+ const [vinCSV, setVinCSV] = useState(transformArrayToCSV(vins));
+ const [active, setActive] = useState(null);
+ const actions = [
+ {
+ name: "Update Configs",
+ disabled: vins.length === 0,
+ trigger: () => setActive("updateConfig"),
+ },
+ {
+ name: "Add Tags",
+ disabled: vins.length === 0,
+ trigger: () => setActive("addTags"),
+ },
+ ];
+
+ const updateConfig = useUpdateConfig();
+ const addTags = useAddTags();
+
+ const { setMessage } = useStatusContext();
+ const {
+ token: {
+ idToken: { jwtToken: token },
+ },
+ } = useUserContext();
+
+ const handleUpdateConfig = () => {
+ updateConfig.submit(vins, token)
+ .then(() => {
+ setMessage(`${vins.length} vehicles updated.`);
+ })
+ .catch((error) => {
+ setMessage(error.message);
+ });
+ }
+
+ 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 handleClose = () => setActive(null);
+
+ useEffect(() => {
+ setVinCSV(transformArrayToCSV(vins));
+ }, [vins]);
+
+ return (
+ <>
+
+
+
+ >
+ );
+}
diff --git a/src/components/BulkActions/useAddTags.js b/src/components/BulkActions/useAddTags.js
new file mode 100644
index 0000000..7696595
--- /dev/null
+++ b/src/components/BulkActions/useAddTags.js
@@ -0,0 +1,22 @@
+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
new file mode 100644
index 0000000..c648bd1
--- /dev/null
+++ b/src/components/BulkActions/useUpdateConfig.js
@@ -0,0 +1,40 @@
+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/Controls/DropDownButton/index.jsx b/src/components/Controls/DropDownButton/index.jsx
index 77a5562..6820877 100644
--- a/src/components/Controls/DropDownButton/index.jsx
+++ b/src/components/Controls/DropDownButton/index.jsx
@@ -40,6 +40,10 @@ const DropDownButton = ({ actions = [], payload = [] }) => {
setOpen(false);
};
+ if (!actions.length) {
+ return <>>;
+ }
+
return (
<>
+
diff --git a/src/components/Fleets/Status/Details/index.jsx b/src/components/Fleets/Status/Details/index.jsx
index 8b81643..2926b38 100644
--- a/src/components/Fleets/Status/Details/index.jsx
+++ b/src/components/Fleets/Status/Details/index.jsx
@@ -15,6 +15,7 @@ import { FleetProvider, useFleetContext } from "../../../Contexts/FleetContext"
import useStyles from "../../../useStyles";
import { logger } from "../../../../services/monitoring";
import DeleteConfirmation from "../../../DeleteConfirmation";
+import BulkActions from "../../../BulkActions";
const MainForm = ({ name }) => {
const classes = useStyles();
@@ -94,6 +95,9 @@ 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 b62b7fd..b9ee191 100644
--- a/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap
+++ b/src/components/Fleets/Status/__snapshots__/DetailsTab.test.jsx.snap
@@ -151,6 +151,48 @@ exports[`DetailsTab Render 1`] = `
+
diff --git a/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap b/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap
index 19171b8..42fdb41 100644
--- a/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap
+++ b/src/components/Fleets/Status/__snapshots__/index.test.jsx.snap
@@ -239,6 +239,48 @@ exports[`FleetStatus Render 1`] = `
+
diff --git a/src/components/TransformModal/index.jsx b/src/components/TransformModal/index.jsx
index 8a58a0c..ee0b13f 100644
--- a/src/components/TransformModal/index.jsx
+++ b/src/components/TransformModal/index.jsx
@@ -28,7 +28,7 @@ const TransformModal = ({
const handleChange = (key, value) => {
setData((data) => {
- const {[key]: toChange, ...rest} = data;
+ const { [key]: toChange, ...rest } = data;
switch (data[key].type) {
case "boolean":
toChange.value = !toChange.value;
From 3d4a07d8d8587317b368957697011d6b881b3a0b Mon Sep 17 00:00:00 2001
From: Paul Adamsen <117673433+pauladamseniii@users.noreply.github.com>
Date: Thu, 22 Jun 2023 15:32:30 -0400
Subject: [PATCH 02/15] CEC-4561 - Add in_park to digital twin display (#371)
---
.../Status/__snapshots__/DigitalTwinTab.test.jsx.snap | 11 +++++++++++
src/components/Contexts/__mocks__/VehicleContext.jsx | 3 +++
src/components/DigitalTwin/index.js | 9 ++++++++-
3 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap b/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap
index f12a979..c7e54ae 100644
--- a/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap
+++ b/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap
@@ -237,6 +237,17 @@ exports[`DigitalTwinTab Render 1`] = `
77.7 km/h
+
{
if (value || value === 0) return `${value}${units}`;
@@ -32,7 +34,7 @@ const windowState = (value) => {
const DigitalTwin = (props) => {
const classes = useStyles();
- const { battery, doors, location, trex_version, ip, updated, windows, misc_windows, sunroof, dbc_version, door_locks, vcu0x260, charging_metrics, max_range, vehicle_speed } = props;
+ const { battery, doors, location, trex_version, ip, updated, windows, misc_windows, sunroof, dbc_version, door_locks, vcu0x260, charging_metrics, max_range, vehicle_speed, gear } = props;
return (
@@ -133,6 +135,11 @@ const DigitalTwin = (props) => {
{keyValueTemplate("Vehicle Speed", appendUnits(vehicle_speed?.speed, " km/h"))}
)}
+ {gear && (
+
+ {keyValueTemplate("Parked", gear.in_park ? PARKED : NOT_PARKED)}
+
+ )}
);
};
From fc7c1ea514df9e66ab0a749212351f0d0e039993 Mon Sep 17 00:00:00 2001
From: Eduard Voronkin <116690094+eduardvoronkin@users.noreply.github.com>
Date: Fri, 23 Jun 2023 12:38:09 -0700
Subject: [PATCH 03/15] CEC-4517 reset TBOX remote command (#369)
* CEC-4517 Diagnostic Commands tab
* snapshot
---
.../App/__snapshots__/App.test.js.snap | 27 +++-
.../Cars/Status/RemoteDiagnosticCommands.jsx | 30 +++++
.../Status/__snapshots__/index.test.jsx.snap | 27 +++-
src/components/Cars/Status/index.jsx | 6 +
src/components/Contexts/VehicleContext.jsx | 15 ++-
.../Controls/SendDiagnosticCommand/index.jsx | 119 ++++++++++++++++++
src/services/vehiclesAPI.js | 15 +++
7 files changed, 236 insertions(+), 3 deletions(-)
create mode 100644 src/components/Cars/Status/RemoteDiagnosticCommands.jsx
create mode 100644 src/components/Controls/SendDiagnosticCommand/index.jsx
diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap
index 5a5eea9..8dc8aac 100644
--- a/src/components/App/__snapshots__/App.test.js.snap
+++ b/src/components/App/__snapshots__/App.test.js.snap
@@ -11242,7 +11242,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
- Fleets
+ Remote Diagnostic Commands
+
+ Fleets
+
+
+
+
+
From 787bb122608cd53834666c6fa1adc688eefd87ec Mon Sep 17 00:00:00 2001
From: Paul Adamsen <117673433+pauladamseniii@users.noreply.github.com>
Date: Mon, 26 Jun 2023 11:55:38 -0400
Subject: [PATCH 05/15] CEC-4595 - show online status of cars in fleet (#374)
* CEC-4595 - show online status of cars in fleet
* fix mocking
---
src/components/Contexts/FleetContext.jsx | 18 +++++-
src/components/Contexts/FleetContext.test.jsx | 19 ++++++-
.../Contexts/__mocks__/FleetContext.jsx | 21 ++++++-
.../Contexts/__mocks__/VehicleContext.jsx | 12 ++--
.../Table/__snapshots__/index.test.jsx.snap | 57 +------------------
.../Fleets/Status/Vehicles/Table/index.jsx | 20 +++++--
.../__snapshots__/VehiclesTab.test.jsx.snap | 57 +------------------
src/services/__mocks__/vehiclesAPI.js | 1 +
8 files changed, 79 insertions(+), 126 deletions(-)
diff --git a/src/components/Contexts/FleetContext.jsx b/src/components/Contexts/FleetContext.jsx
index dd62c6d..551a762 100644
--- a/src/components/Contexts/FleetContext.jsx
+++ b/src/components/Contexts/FleetContext.jsx
@@ -1,5 +1,6 @@
import React, { useContext, useState } from "react";
import api from "../../services/fleetsAPI";
+import vehiclesAPI from "../../services/vehiclesAPI";
import { validateCANID, validateFilter, validateVIN } from "../../utils/validationSupplier";
const FleetContext = React.createContext();
@@ -112,7 +113,22 @@ export const FleetProvider = ({ children }) => {
throw new Error(`Get fleet vehicles error. ${result.message}`);
}
- setFleetVehicles(result.data)
+ const connectionsResult = await vehiclesAPI.getConnections(result.data, token)
+ if (result.error) {
+ setFleetVehicles([])
+ throw new Error(`Get vehicles connections error. ${result.message}`);
+ }
+
+ var cars = []
+ result.data.forEach((vin) => {
+ cars.push({
+ vin: vin,
+ connected: connectionsResult[vin] || false,
+ connectedHMI: connectionsResult[`2:${vin}`] || false
+ })
+ })
+
+ setFleetVehicles(cars)
if (result.total) {
setTotalFleetVehicles(result.total);
}
diff --git a/src/components/Contexts/FleetContext.test.jsx b/src/components/Contexts/FleetContext.test.jsx
index 93b88a1..b3b883d 100644
--- a/src/components/Contexts/FleetContext.test.jsx
+++ b/src/components/Contexts/FleetContext.test.jsx
@@ -1,4 +1,5 @@
jest.mock("../../services/fleetsAPI");
+jest.mock("../../services/vehiclesAPI");
import {
render,
@@ -800,9 +801,21 @@ const expectedFleetsData = [
];
const expectedFleetVehiclesData = [
- "USWESTVIN12345678",
- "USWESTVIN12345679",
- "USWESTVIN12345670",
+ {
+ vin: "USWESTVIN12345678",
+ connected: true,
+ connectedHMI: false,
+ },
+ {
+ vin: "USWESTVIN12345679",
+ connected: true,
+ connectedHMI: false,
+ },
+ {
+ vin: "USWESTVIN12345670",
+ connected: true,
+ connectedHMI: false,
+ },
];
const expectedFleetCANFiltersData = [
diff --git a/src/components/Contexts/__mocks__/FleetContext.jsx b/src/components/Contexts/__mocks__/FleetContext.jsx
index 7c9c613..6b081c2 100644
--- a/src/components/Contexts/__mocks__/FleetContext.jsx
+++ b/src/components/Contexts/__mocks__/FleetContext.jsx
@@ -62,7 +62,26 @@ export const useFleetContext = () => ({
fleetVehicles,
totalFleetVehicles,
- getFleetVehicles: jest.fn(),
+ getFleetVehicles: jest.fn().mockImplementation((name, search, _token) => {
+ const result = [
+ {
+ vin: "USWESTVIN12345678",
+ connected: false,
+ connectedHMI: false
+ },
+ {
+ vin: "USWESTVIN12345679",
+ connected: true,
+ connectedHMI: true
+ },
+ {
+ vin: "USWESTVIN12345670",
+ connected: false,
+ connectedHMI: false
+ },
+ ];
+ return Promise.resolve(result);
+ }),
addFleetVehicles: jest.fn(),
deleteFleetVehicle: jest.fn(),
diff --git a/src/components/Contexts/__mocks__/VehicleContext.jsx b/src/components/Contexts/__mocks__/VehicleContext.jsx
index 18cc9b0..52bd9fb 100644
--- a/src/components/Contexts/__mocks__/VehicleContext.jsx
+++ b/src/components/Contexts/__mocks__/VehicleContext.jsx
@@ -112,10 +112,14 @@ export const useVehicleContext = () => ({
addVehicle: jest.fn(),
getConnections: jest
.fn().mockImplementation((vins, _token) => {
- const result = {};
- vins.forEach((vin) => {
- result[vin] = true;
- });
+ const result = {
+ "USWESTVIN12345678": true,
+ "2:USWESTVIN12345678": false,
+ "USWESTVIN12345679": true,
+ "2:USWESTVIN12345679": false,
+ "USWESTVIN12345670": true,
+ "2:USWESTVIN12345670": false,
+ };
return Promise.resolve(result);
}),
getECUs: jest.fn(() => {
diff --git a/src/components/Fleets/Status/Vehicles/Table/__snapshots__/index.test.jsx.snap b/src/components/Fleets/Status/Vehicles/Table/__snapshots__/index.test.jsx.snap
index 9cad130..2c81f3a 100644
--- a/src/components/Fleets/Status/Vehicles/Table/__snapshots__/index.test.jsx.snap
+++ b/src/components/Fleets/Status/Vehicles/Table/__snapshots__/index.test.jsx.snap
@@ -137,62 +137,7 @@ exports[`FleetVehiclesTable Render 1`] = `
-
- |
-
- USWESTVIN12345678
-
- |
-
- No actions
- |
-
-
- |
-
- USWESTVIN12345679
-
- |
-
- No actions
- |
-
-
- |
-
- USWESTVIN12345670
-
- |
-
- No actions
- |
-
-
+ />