Push to prod (#201)
* CEC-2056 safari map (#186) * CEC-2056 Fix Safari map popup * Snapshot serializer for Private styles * Combine serializers * CEC-2207 Add is-online filter for vehicles list (#187) * Add OptionsDropdown component * Add is-online filter * CEC-2237 Track sign in and keys (#188) * Update stage (#189) * CEC-2056 safari map (#186) * CEC-2056 Fix Safari map popup * Snapshot serializer for Private styles * Combine serializers * CEC-2207 Add is-online filter for vehicles list (#187) * Add OptionsDropdown component * Add is-online filter * CEC-2237 Track sign in and keys (#188) Co-authored-by: arpanetus <arpanetus@protonmail.com> * CEC-2281 Update certificate form (#190) * CEC-2281 Fix cert name * CEC-2360 Fix filename display and add manifest type (#191) * CEC-2360 Fix filename display and add manifest type * const * Push to Stage (#200) * CEC-2144, CEC-2338 Add deploy by fleets and fix fleets table (#192) * Add fix for fleets search * Decompose fleets table * Add deploy by fleets * Add snapshots * CEC-2385 Only show software updates (#193) * CEC-2385 Only show software updates * Update browser list * update threshold * Clean up * CEC-2291 Remote Commands (#194) * CEC-2378 Add fix for fleet vehicles' search * CEC-1235 Fix fleet name update (#196) Co-authored-by: arpanetus <arpanetus@protonmail.com> Co-authored-by: arpanetus <arpanetus@protonmail.com>
This commit is contained in:
@@ -6,7 +6,8 @@ import { validateStatusMessage } from "../../utils/statusMessage";
|
||||
const FINAL_UPDATE_STATES = ["package_install_complete"];
|
||||
const CarUpdatesContext = React.createContext();
|
||||
|
||||
const validateDeployCarUpdates = (data) => {
|
||||
|
||||
const validateDeployClosure = (data, propertyName, errPfx) => {
|
||||
if (data === null) {
|
||||
throw new Error("No car update data");
|
||||
}
|
||||
@@ -15,11 +16,21 @@ const validateDeployCarUpdates = (data) => {
|
||||
throw new Error("Manifest id required");
|
||||
}
|
||||
|
||||
if (!data.vins || data.vins.length === 0) {
|
||||
throw new Error("Cars are required");
|
||||
const { [propertyName]: value } = data;
|
||||
if (!value || value.length === 0) {
|
||||
throw new Error(`${errPfx} are required`);
|
||||
}
|
||||
}
|
||||
|
||||
const validateDeployCarUpdates = (data) => {
|
||||
return validateDeployClosure(data, 'vins', 'Cars')
|
||||
};
|
||||
|
||||
const validateDeployFleetUpdates = (data) => {
|
||||
return validateDeployClosure(data, 'fleet_names', 'Fleets')
|
||||
};
|
||||
|
||||
|
||||
export const CarUpdatesProvider = ({ children }) => {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [carUpdates, setCarUpdates] = useState([]);
|
||||
@@ -43,6 +54,22 @@ export const CarUpdatesProvider = ({ children }) => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const deployFleetUpdates = async (data, token) => {
|
||||
let result;
|
||||
|
||||
try {
|
||||
setBusy(true);
|
||||
validateDeployFleetUpdates(data);
|
||||
result = await api.createFleetUpdates(data, token);
|
||||
if (result.error)
|
||||
throw new Error(`Deploy fleet updates error. ${result.message}`);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const getCarUpdates = async (search, token) => {
|
||||
let result;
|
||||
|
||||
@@ -204,6 +231,7 @@ export const CarUpdatesProvider = ({ children }) => {
|
||||
carUpdates,
|
||||
totalCarUpdates,
|
||||
deployCarUpdates,
|
||||
deployFleetUpdates,
|
||||
getCarUpdates,
|
||||
getLog,
|
||||
getVINUpdates,
|
||||
|
||||
@@ -8,11 +8,12 @@ export const CertTypes = {
|
||||
TBOX: "TBOX",
|
||||
ICC: "ICC",
|
||||
Charging: "Charging",
|
||||
Aftersales: "Aftersales",
|
||||
};
|
||||
|
||||
const validateCreate = (data) => {
|
||||
if (!data.type) throw new Error("type is required");
|
||||
if (!data.vin) throw new Error("vin is required");
|
||||
if (!data.common_name) throw new Error("common name is required");
|
||||
};
|
||||
|
||||
export const CertificateProvider = ({ children }) => {
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
import React, { useContext, useState } from "react";
|
||||
|
||||
import api from "../../services/manifestsAPI";
|
||||
import { uploadFile, getCancelToken } from "../../services/uploadFile";
|
||||
import { useStatusContext } from "./StatusContext";
|
||||
import {
|
||||
validateManifest,
|
||||
validateManifestECUs,
|
||||
} from "../../utils/manifestValidation";
|
||||
|
||||
const ManifestCreateContext = React.createContext();
|
||||
|
||||
const checkExistingManifest = async (data, token) => {
|
||||
const check = {
|
||||
name: data.name,
|
||||
version: data.version,
|
||||
};
|
||||
const { data: result } = await api.getManifests(check, token);
|
||||
if (result.length > 0)
|
||||
throw new Error(`Update ${data.name} ${data.version} already exists`);
|
||||
};
|
||||
|
||||
const ECUTemplate = {
|
||||
name: "AGS",
|
||||
version: "",
|
||||
hw_version: "",
|
||||
configuration_mask: "",
|
||||
configuration: "",
|
||||
files: [],
|
||||
manifest_id: 0,
|
||||
};
|
||||
|
||||
const FileTemplate = {
|
||||
offset: "0",
|
||||
checksum: "",
|
||||
type: "none",
|
||||
};
|
||||
|
||||
export const ManifestCreateProvider = ({ children }) => {
|
||||
const { setMessage } = useStatusContext();
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [uploadStatus, setUploadStatus] = useState(null);
|
||||
const [cancelUploadToken, setCancelUploadToken] = useState(null);
|
||||
const [uploadFileIndex, setUploadFileIndex] = useState(0);
|
||||
const [uploadedFiles, setUploadedFiles] = useState([]);
|
||||
const [ecus, setECUs] = useState([]);
|
||||
const [ecuIndex, setECUIndex] = useState(0);
|
||||
|
||||
const addECU = () => {
|
||||
try {
|
||||
const result = ecus.concat(
|
||||
Object.assign({ data_id: ecuIndex }, ECUTemplate)
|
||||
);
|
||||
setECUIndex(ecuIndex + 1);
|
||||
setECUs(result);
|
||||
} catch (err) {
|
||||
setMessage(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteECU = (data_id) => {
|
||||
try {
|
||||
const result = ecus.filter((item) => item.data_id !== data_id);
|
||||
setECUs(result);
|
||||
} catch (err) {
|
||||
setMessage(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const getECU = (ecu_data_id) =>
|
||||
ecus.find((item) => item.data_id === ecu_data_id);
|
||||
|
||||
const getECUFile = (ecu, filename) =>
|
||||
ecu.files.find((file) => file.filename === filename);
|
||||
|
||||
const validateECUFiles = (ecu, files) => {
|
||||
files.forEach((file) => {
|
||||
if (file.size === 0) throw new Error(`${file.name} is 0 size`);
|
||||
const result = getECUFile(ecu, file.name);
|
||||
if (result) throw new Error(`${file.name} already exists`);
|
||||
});
|
||||
};
|
||||
|
||||
const getAllECUFiles = () => {
|
||||
let result = [];
|
||||
|
||||
for (let i = 0, len = ecus.length; i < len; i++) {
|
||||
const ecu = ecus[i];
|
||||
result = result.concat(ecu.files);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const addECUFile = (ecu_data_id, items) => {
|
||||
try {
|
||||
const ecu = getECU(ecu_data_id);
|
||||
if (ecu === undefined) return;
|
||||
|
||||
const files = Array.from(items);
|
||||
validateECUFiles(ecu, files);
|
||||
|
||||
const total = ecu.files.length;
|
||||
const result = files.map((file, index) =>
|
||||
Object.assign(
|
||||
{ order: total + index, file: file, filename: file.name },
|
||||
FileTemplate
|
||||
)
|
||||
);
|
||||
ecu.files = ecu.files.concat(result);
|
||||
updateECUs();
|
||||
} catch (err) {
|
||||
setMessage(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const sortECUFiles = (ecu) => {
|
||||
ecu.files.sort((x, y) => {
|
||||
if (x.order === y.order) return 0;
|
||||
return x.order < y.order ? -1 : 1;
|
||||
});
|
||||
};
|
||||
|
||||
const deleteECUFile = (ecu_data_id, filename) => {
|
||||
try {
|
||||
const ecu = getECU(ecu_data_id);
|
||||
if (ecu === undefined) return;
|
||||
ecu.files = ecu.files.filter((file) => file.filename !== filename);
|
||||
sortECUFiles(ecu);
|
||||
updateECUs();
|
||||
} catch (err) {
|
||||
setMessage(err.message);
|
||||
}
|
||||
};
|
||||
|
||||
const updateECUs = () => {
|
||||
setECUs(ecus.concat([]));
|
||||
};
|
||||
|
||||
const createManifest = async (data, token) => {
|
||||
let result;
|
||||
let currentFileIndex = 0;
|
||||
const incremFileIndex = () => {
|
||||
setUploadFileIndex(currentFileIndex);
|
||||
currentFileIndex++;
|
||||
};
|
||||
|
||||
try {
|
||||
setBusy(true);
|
||||
validateManifest(data, token);
|
||||
validateManifestECUs(ecus);
|
||||
await checkExistingManifest(data, token);
|
||||
|
||||
setUploadedFiles(getAllECUFiles());
|
||||
if (result !== null) result = await api.createManifest(data, token);
|
||||
if (result.error)
|
||||
throw new Error(`Create manifest error. ${result.message}`);
|
||||
|
||||
for (let i = 0, len = ecus.length; i < len; i++) {
|
||||
const ecu = ecus[i];
|
||||
ecu.manifest_id = result.id;
|
||||
await createManifestECU(ecu, token, incremFileIndex);
|
||||
}
|
||||
} finally {
|
||||
setBusy(false);
|
||||
setUploadFileIndex(0);
|
||||
setUploadedFiles([]);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const createManifestECU = async (ecu, token, incremFileIndexFn) => {
|
||||
const { files, ...data } = ecu;
|
||||
|
||||
const result = await api.createManifestECU(data, token);
|
||||
if (result.error)
|
||||
throw new Error(`Create manifest error. ${result.message}`);
|
||||
|
||||
for (let i = 0, len = ecu.files.length; i < len; i++) {
|
||||
const file = ecu.files[i];
|
||||
file.manifest_ecu_id = result.id;
|
||||
incremFileIndexFn();
|
||||
const resp = await uploadECUFile(file, token);
|
||||
if (resp.error)
|
||||
throw new Error(`Upload manifest file error. ${resp.error}`);
|
||||
}
|
||||
};
|
||||
|
||||
const cancelUpload = () => {
|
||||
if (cancelUploadToken) cancelUploadToken.cancel();
|
||||
setBusy(false);
|
||||
setUploadStatus("Upload cancelled");
|
||||
setCancelUploadToken(null);
|
||||
setUploadProgress(0);
|
||||
};
|
||||
|
||||
const uploadECUFile = async (file, accessToken) => {
|
||||
const cancel = getCancelToken();
|
||||
|
||||
setUploadProgress(0);
|
||||
setUploadStatus(`Uploading ${file.filename}`);
|
||||
setCancelUploadToken(cancel);
|
||||
|
||||
const result = await uploadFile(
|
||||
file,
|
||||
accessToken,
|
||||
setUploadProgress,
|
||||
cancel.token
|
||||
);
|
||||
if (result.message) {
|
||||
throw new Error(`${result.error}. ${result.message}`);
|
||||
}
|
||||
|
||||
setUploadStatus(`Uploaded ${file.filename}`);
|
||||
setCancelUploadToken(null);
|
||||
setUploadProgress(100);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return (
|
||||
<ManifestCreateContext.Provider
|
||||
value={{
|
||||
busy,
|
||||
ecus,
|
||||
uploadedFiles,
|
||||
uploadFileIndex,
|
||||
uploadProgress,
|
||||
uploadStatus,
|
||||
addECU,
|
||||
addECUFile,
|
||||
cancelUpload,
|
||||
createManifest,
|
||||
createManifestECU,
|
||||
deleteECU,
|
||||
deleteECUFile,
|
||||
updateECUs,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ManifestCreateContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useManifestCreateContext = () => useContext(ManifestCreateContext);
|
||||
@@ -164,10 +164,10 @@ export const VehicleProvider = ({ children }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const sendCommand = async (vins, command, parameters, token) => {
|
||||
const sendCommand = async (vins, command, token) => {
|
||||
try {
|
||||
setBusy(true);
|
||||
const result = await api.sendCommand(vins, command, parameters, token);
|
||||
const result = await api.sendCommand(vins, command, token);
|
||||
if (result.error)
|
||||
throw new Error(`Send command error. ${result.message}`);
|
||||
return result;
|
||||
|
||||
@@ -317,6 +317,55 @@ describe("VehicleContext", () => {
|
||||
checkBaseResults("", "false");
|
||||
});
|
||||
});
|
||||
|
||||
describe("sendCommand", () => {
|
||||
beforeEach(async () => {
|
||||
const TestComp = () => {
|
||||
const {busy, sendCommand} = useVehicleContext();
|
||||
const { message, setMessage } = useStatusContext();
|
||||
|
||||
const sendC = async (vin, command) => {
|
||||
try {
|
||||
await sendCommand(vin, command);
|
||||
} catch (e) {
|
||||
setMessage(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="sendCommandNullVin" onClick={() => sendC(null, {command:"doors_lock"})} />
|
||||
<button data-testid="sendCommandNonexistentVin" onClick={() => sendC(["11111111111111111"], {command:"doors_lock"})} />
|
||||
<button
|
||||
data-testid="sendCommandVin"
|
||||
onClick={() => sendC("3C4PDCBG0ET127145", {command:"doors_lock"})}
|
||||
/>
|
||||
<button
|
||||
data-testid="sendCommandWrongCommand"
|
||||
onClick={() => sendC("3C4PDCBG0ET127145", {command:"noSuchCommand"})}
|
||||
/>
|
||||
</>
|
||||
);}
|
||||
render(
|
||||
<StatusProvider>
|
||||
<VehicleProvider>
|
||||
<TestComp />
|
||||
</VehicleProvider>
|
||||
</StatusProvider>
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it("initial state", () => {
|
||||
checkBaseResults("", "false");
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
const expectedFilters = [
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
const ManifestsContext = React.createContext();
|
||||
|
||||
let busy = false;
|
||||
let ecus = [
|
||||
{
|
||||
data_id: 0,
|
||||
name: "AGS",
|
||||
version: "",
|
||||
hw_version: "",
|
||||
manifest_id: 0,
|
||||
files: [
|
||||
{
|
||||
filename: "test.bin",
|
||||
order: 0,
|
||||
offset: "0",
|
||||
checksum: "",
|
||||
self_download: false,
|
||||
mode: "D",
|
||||
type: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
let uploadedFiles = [];
|
||||
let uploadFileIndex = 0;
|
||||
let uploadProgress = 0;
|
||||
let uploadStatus = null;
|
||||
|
||||
export const ManifestCreateProvider = ({ children }) => {
|
||||
return <div data-testid="mocked-manifestcreateprovider">{children}</div>;
|
||||
};
|
||||
|
||||
export const useManifestCreateContext = () => ({
|
||||
busy,
|
||||
ecus,
|
||||
uploadedFiles,
|
||||
uploadFileIndex,
|
||||
uploadProgress,
|
||||
uploadStatus,
|
||||
addECU: jest.fn(),
|
||||
addECUFile: jest.fn(),
|
||||
cancelUpload: jest.fn(),
|
||||
createManifest: jest.fn(),
|
||||
createManifestECU: jest.fn(),
|
||||
deleteECU: jest.fn(),
|
||||
deleteECUFile: jest.fn(),
|
||||
updateECUs: jest.fn(),
|
||||
});
|
||||
@@ -18,7 +18,6 @@ let manifest = {
|
||||
files: [
|
||||
{
|
||||
file_id: "b0cda514c94080b4",
|
||||
filename: "LARGE.jpg",
|
||||
url: "https://upload-dev.fiskerdps.com/92bbc448-99c8-4851-91ad-f8042e4deb49/LARGE.jpg",
|
||||
write_region: {
|
||||
offset: 100,
|
||||
@@ -35,7 +34,6 @@ let manifest = {
|
||||
},
|
||||
{
|
||||
file_id: "4B897b1DcbeCds8e9",
|
||||
filename: "SMALL.jpg",
|
||||
url: "https://upload-dev.fiskerdps.com/92bbc448-99c8-4851-91ad-f8042e4deb49/SMALL.jpg",
|
||||
write_region: {
|
||||
offset: 120559274,
|
||||
|
||||
Reference in New Issue
Block a user