CEC-2385 Only show software updates (#193)
* CEC-2385 Only show software updates * Update browser list * update threshold * Clean up
This commit is contained in:
26
package-lock.json
generated
26
package-lock.json
generated
@@ -6505,13 +6505,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001314",
|
"version": "1.0.30001387",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001387.tgz",
|
||||||
"integrity": "sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw==",
|
"integrity": "sha512-fKDH0F1KOJvR+mWSOvhj8lVRr/Q/mc5u5nabU2vi1/sgvlSqEsE8dOq0Hy/BqVbDkCYQPRRHB1WRjW6PGB/7PA==",
|
||||||
"funding": {
|
"funding": [
|
||||||
"type": "opencollective",
|
{
|
||||||
"url": "https://opencollective.com/browserslist"
|
"type": "opencollective",
|
||||||
}
|
"url": "https://opencollective.com/browserslist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"node_modules/case-sensitive-paths-webpack-plugin": {
|
"node_modules/case-sensitive-paths-webpack-plugin": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
@@ -21996,9 +22002,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"caniuse-lite": {
|
"caniuse-lite": {
|
||||||
"version": "1.0.30001314",
|
"version": "1.0.30001387",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001314.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001387.tgz",
|
||||||
"integrity": "sha512-0zaSO+TnCHtHJIbpLroX7nsD+vYuOVjl3uzFbJO1wMVbuveJA0RK2WcQA9ZUIOiO0/ArMiMgHJLxfEZhQiC0kw=="
|
"integrity": "sha512-fKDH0F1KOJvR+mWSOvhj8lVRr/Q/mc5u5nabU2vi1/sgvlSqEsE8dOq0Hy/BqVbDkCYQPRRHB1WRjW6PGB/7PA=="
|
||||||
},
|
},
|
||||||
"case-sensitive-paths-webpack-plugin": {
|
"case-sensitive-paths-webpack-plugin": {
|
||||||
"version": "2.4.0",
|
"version": "2.4.0",
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
"coverageThreshold": {
|
"coverageThreshold": {
|
||||||
"global": {
|
"global": {
|
||||||
"branches": 39,
|
"branches": 39,
|
||||||
"functions": 47,
|
"functions": 45.5,
|
||||||
"lines": 50,
|
"lines": 50,
|
||||||
"statements": 49
|
"statements": 49
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
jest.mock("../Contexts/CarUpdatesContext");
|
jest.mock("../Contexts/CarUpdatesContext");
|
||||||
jest.mock("../Contexts/FileUploadContext");
|
jest.mock("../Contexts/FileUploadContext");
|
||||||
jest.mock("../Contexts/VehicleContext");
|
jest.mock("../Contexts/VehicleContext");
|
||||||
jest.mock("../Contexts/ManifestCreateContext");
|
|
||||||
jest.mock("../Contexts/ManifestsContext");
|
jest.mock("../Contexts/ManifestsContext");
|
||||||
jest.mock("../Contexts/UserContext");
|
jest.mock("../Contexts/UserContext");
|
||||||
jest.mock("../../services/monitoring");
|
jest.mock("../../services/monitoring");
|
||||||
@@ -73,10 +72,6 @@ describe("App", () => {
|
|||||||
await check("/package-deploy/1", "span.MuiButton-label", "Sign In");
|
await check("/package-deploy/1", "span.MuiButton-label", "Sign In");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /package-create unauthenticated", async () => {
|
|
||||||
await check("/package-create", "span.MuiButton-label", "Sign In");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Route /vehicle-add unauthenticated", async () => {
|
it("Route /vehicle-add unauthenticated", async () => {
|
||||||
await check("/vehicle-add", "span.MuiButton-label", "Sign In");
|
await check("/vehicle-add", "span.MuiButton-label", "Sign In");
|
||||||
});
|
});
|
||||||
@@ -146,11 +141,6 @@ describe("App", () => {
|
|||||||
await check("/package-deploy/1", "h6", "Deploy Test Manifest 1.0");
|
await check("/package-deploy/1", "h6", "Deploy Test Manifest 1.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Route /package-create authenticated", async () => {
|
|
||||||
setToken(TEST_AUTH_OBJECT);
|
|
||||||
await check("/package-create", "h6", "Create Deployments");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("Route /vehicle-add authenticated", async () => {
|
it("Route /vehicle-add authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
await check("/vehicle-add", "h6", "Add Vehicle");
|
await check("/vehicle-add", "h6", "Add Vehicle");
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ exports[`CarStatus Render 1`] = `
|
|||||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-64 makeStyles-tableToolbar-0"
|
class="MuiBox-root MuiBox-root-0 makeStyles-tableToolbar-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTabs-root"
|
class="MuiTabs-root"
|
||||||
@@ -133,7 +133,7 @@ exports[`CarStatus Render 1`] = `
|
|||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-69"
|
class="MuiBox-root MuiBox-root-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||||
|
|||||||
@@ -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);
|
|
||||||
@@ -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(),
|
|
||||||
});
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableFooter,
|
|
||||||
TableRow,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
|
|
||||||
import FileDragArea from "../FileDragArea";
|
|
||||||
import ListHead from "../ListHead";
|
|
||||||
import SubListItem from "../SubListItem";
|
|
||||||
import { useManifestCreateContext } from "../../Contexts/ManifestCreateContext";
|
|
||||||
import ManifestECUFileTypes from "../ManifestECUFileTypes";
|
|
||||||
|
|
||||||
const options = [
|
|
||||||
{
|
|
||||||
label: "Filename",
|
|
||||||
field: "filename",
|
|
||||||
readonly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Offset",
|
|
||||||
field: "offset",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Checksum",
|
|
||||||
field: "checksum",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Type",
|
|
||||||
field: "type",
|
|
||||||
control: ManifestECUFileTypes,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "",
|
|
||||||
field: "filename",
|
|
||||||
delete: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ManifestECUFileList = ({ data }) => {
|
|
||||||
const { addECUFile, deleteECUFile } = useManifestCreateContext();
|
|
||||||
|
|
||||||
const onAddFile = (files) => {
|
|
||||||
addECUFile(data.data_id, files);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeletFile = (filename) => {
|
|
||||||
deleteECUFile(data.data_id, filename);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Table>
|
|
||||||
{data && data.files && data.files.length > 0 && (
|
|
||||||
<ListHead options={options} />
|
|
||||||
)}
|
|
||||||
<TableBody>
|
|
||||||
{data.files.map((file) => (
|
|
||||||
<SubListItem
|
|
||||||
key={file.filename}
|
|
||||||
data={file}
|
|
||||||
options={options}
|
|
||||||
onDelete={onDeletFile}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
<TableFooter>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={options.length}>
|
|
||||||
<FileDragArea onFileSelect={onAddFile}>ADD FILES</FileDragArea>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableFooter>
|
|
||||||
</Table>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ManifestECUFileList;
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableFooter,
|
|
||||||
TableRow,
|
|
||||||
} from "@material-ui/core";
|
|
||||||
|
|
||||||
import ECUDropDrop from "../ECUDropDown";
|
|
||||||
import ListHead from "../ListHead";
|
|
||||||
import ManifestECURow from "../ManifestECURow";
|
|
||||||
import { useManifestCreateContext } from "../../Contexts/ManifestCreateContext";
|
|
||||||
import PageDragPreventDefault from "../PageDragPreventDefault";
|
|
||||||
|
|
||||||
const options = [
|
|
||||||
{
|
|
||||||
label: "ID",
|
|
||||||
field: "data_id",
|
|
||||||
readonly: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "ECU",
|
|
||||||
field: "name",
|
|
||||||
control: ECUDropDrop,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Version",
|
|
||||||
field: "version",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Hardware",
|
|
||||||
field: "hw_version",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "",
|
|
||||||
delete: true,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const ManifestECUList = () => {
|
|
||||||
const { ecus, addECU } = useManifestCreateContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<PageDragPreventDefault />
|
|
||||||
<Table>
|
|
||||||
<ListHead options={options} />
|
|
||||||
<TableBody>
|
|
||||||
{ecus.map((item) => {
|
|
||||||
return (
|
|
||||||
<ManifestECURow
|
|
||||||
key={item.data_id}
|
|
||||||
data={item}
|
|
||||||
options={options}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
<TableFooter>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={5} align="center">
|
|
||||||
<Button onClick={addECU}>Add ECU</Button>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</TableFooter>
|
|
||||||
</Table>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ManifestECUList;
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
import { TableCell, TableRow } from "@material-ui/core";
|
|
||||||
|
|
||||||
import ManifestECUFileList from "../ManifestECUFileList";
|
|
||||||
import SubListItem from "../SubListItem";
|
|
||||||
import { useManifestCreateContext } from "../../Contexts/ManifestCreateContext";
|
|
||||||
|
|
||||||
const ManifestECURow = ({ data, options }) => {
|
|
||||||
const { deleteECU } = useManifestCreateContext();
|
|
||||||
|
|
||||||
const onDeleteECU = () => {
|
|
||||||
deleteECU(data.data_id);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<SubListItem
|
|
||||||
key={data.data_id}
|
|
||||||
data={data}
|
|
||||||
options={options}
|
|
||||||
onDelete={onDeleteECU}
|
|
||||||
/>
|
|
||||||
<TableRow>
|
|
||||||
<TableCell colSpan={options.length}>
|
|
||||||
<ManifestECUFileList data={data} />
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ManifestECURow;
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import { Button, Grid, LinearProgress, Typography } from "@material-ui/core";
|
|
||||||
|
|
||||||
import { useManifestCreateContext } from "../../Contexts/ManifestCreateContext";
|
|
||||||
|
|
||||||
const ManifestUploadProgress = (props) => {
|
|
||||||
const { uploadProgress, uploadStatus, uploadFileIndex, uploadedFiles } =
|
|
||||||
useManifestCreateContext();
|
|
||||||
const [progress, setProgress] = useState(0);
|
|
||||||
const [completed, setCompleted] = useState(0);
|
|
||||||
const [total, setTotal] = useState(0);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const x = uploadedFiles.reduce(
|
|
||||||
(current, { file }) => current + file.size,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
setTotal(x);
|
|
||||||
}, [uploadedFiles]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (uploadFileIndex === 0 || uploadFileIndex >= uploadedFiles.length)
|
|
||||||
return;
|
|
||||||
let uploaded = 0;
|
|
||||||
uploadedFiles.forEach(({ file }, i) => {
|
|
||||||
if (i < uploadFileIndex) uploaded += file.size;
|
|
||||||
});
|
|
||||||
setCompleted(uploaded);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [uploadFileIndex]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (total === 0 || uploadFileIndex >= uploadedFiles.length) return;
|
|
||||||
const { file } = uploadedFiles[uploadFileIndex];
|
|
||||||
const uploaded = completed + file.size * uploadProgress;
|
|
||||||
const x = Math.min(99, Math.floor((uploaded / total) * 100));
|
|
||||||
setProgress(x);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [uploadProgress, completed]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Grid container>
|
|
||||||
<Grid xs={12}>
|
|
||||||
<Typography align="center">
|
|
||||||
{`File ${uploadFileIndex + 1} of ${
|
|
||||||
uploadedFiles.length
|
|
||||||
}. ${uploadStatus}`}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
<Grid container alignContent="center" spacing={0}>
|
|
||||||
<Grid xs={11}>
|
|
||||||
<LinearProgress
|
|
||||||
variant="determinate"
|
|
||||||
value={progress}
|
|
||||||
style={{ marginTop: 16 }}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid xs={1} alignContent="flex-end" align="right">
|
|
||||||
<Button onClick={props.onCancel}>Cancel</Button>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ManifestUploadProgress;
|
|
||||||
@@ -8,7 +8,7 @@ exports[`TabPanel Render 1`] = `
|
|||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-1"
|
class="MuiBox-root MuiBox-root-0"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
Test
|
Test
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ exports[`FleetStatus Render 1`] = `
|
|||||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-64 makeStyles-tableToolbar-0"
|
class="MuiBox-root MuiBox-root-0 makeStyles-tableToolbar-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTabs-root"
|
class="MuiTabs-root"
|
||||||
@@ -97,7 +97,7 @@ exports[`FleetStatus Render 1`] = `
|
|||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiBox-root MuiBox-root-69"
|
class="MuiBox-root MuiBox-root-0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
|
||||||
import { Redirect } from "react-router";
|
|
||||||
import { Button, TextField, Typography } from "@material-ui/core";
|
|
||||||
|
|
||||||
import { useUserContext } from "../../Contexts/UserContext";
|
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
|
||||||
import {
|
|
||||||
ManifestCreateProvider,
|
|
||||||
useManifestCreateContext,
|
|
||||||
} from "../../Contexts/ManifestCreateContext";
|
|
||||||
import useStyles from "../../useStyles";
|
|
||||||
import { logger } from "../../../services/monitoring";
|
|
||||||
import ManifestECUList from "../../Controls/ManifestECUList";
|
|
||||||
import ManifestUploadProgress from "../../Controls/ManifestUploadProgress";
|
|
||||||
|
|
||||||
const MainForm = () => {
|
|
||||||
const { createManifest, cancelUpload, busy } = useManifestCreateContext();
|
|
||||||
const { token } = useUserContext();
|
|
||||||
const { setMessage, setTitle, setSitePath } = useStatusContext();
|
|
||||||
const [redirect, setRedirect] = useState(null);
|
|
||||||
const classes = useStyles();
|
|
||||||
const packagenameEl = useRef(null);
|
|
||||||
const versionEl = useRef(null);
|
|
||||||
const descEl = useRef(null);
|
|
||||||
const releasenotesEl = useRef(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setTitle("Create Deployments");
|
|
||||||
setSitePath([
|
|
||||||
{
|
|
||||||
label: "Deployments",
|
|
||||||
link: "/packages",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Create Deployments",
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onSubmit = async (event) => {
|
|
||||||
try {
|
|
||||||
event.preventDefault();
|
|
||||||
const {
|
|
||||||
idToken: { jwtToken: authToken },
|
|
||||||
} = token;
|
|
||||||
const formData = {
|
|
||||||
name: packagenameEl.current.value,
|
|
||||||
version: versionEl.current.value,
|
|
||||||
description: descEl.current.value,
|
|
||||||
release_notes: releasenotesEl.current.value,
|
|
||||||
};
|
|
||||||
const manifest = await createManifest(formData, authToken);
|
|
||||||
|
|
||||||
if (!manifest || manifest.error) return;
|
|
||||||
|
|
||||||
cancelUpload();
|
|
||||||
setMessage(`Package uploaded`);
|
|
||||||
setRedirect(`/package-deploy/${manifest.id}`);
|
|
||||||
} catch (e) {
|
|
||||||
setMessage(e.message);
|
|
||||||
logger.warn(e.stack);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (redirect && redirect.length > 0) {
|
|
||||||
return <Redirect to={redirect} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.paper}>
|
|
||||||
<form className={classes.form} noValidate action="{onSubmit}">
|
|
||||||
<TextField
|
|
||||||
id="packagename"
|
|
||||||
name="packagename"
|
|
||||||
label="Package name"
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
inputProps={{
|
|
||||||
maxLength: "255",
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
inputRef={packagenameEl}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
id="version"
|
|
||||||
name="version"
|
|
||||||
label="Version"
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
inputProps={{
|
|
||||||
maxLength: "255",
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
inputRef={versionEl}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
id="description"
|
|
||||||
name="description"
|
|
||||||
label="Description"
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
inputProps={{
|
|
||||||
maxLength: "5120",
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
multiline
|
|
||||||
minRows={4}
|
|
||||||
placeholder="Package description"
|
|
||||||
inputRef={descEl}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
id="release_notes"
|
|
||||||
name="release_notes"
|
|
||||||
label="Release Notes URL"
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
inputProps={{
|
|
||||||
maxLength: "1024",
|
|
||||||
}}
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
placeholder="Release Notes URL"
|
|
||||||
inputRef={releasenotesEl}
|
|
||||||
/>
|
|
||||||
<Typography variant="h6">ECU Files</Typography>
|
|
||||||
<ManifestECUList />
|
|
||||||
{busy ? (
|
|
||||||
<ManifestUploadProgress onCancel={cancelUpload} />
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
type="submit"
|
|
||||||
disabled={busy}
|
|
||||||
fullWidth
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
className={classes.submit}
|
|
||||||
onClick={onSubmit}
|
|
||||||
>
|
|
||||||
Submit
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function FileUploadForm() {
|
|
||||||
return (
|
|
||||||
<ManifestCreateProvider>
|
|
||||||
<MainForm />
|
|
||||||
</ManifestCreateProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,8 @@ import SearchField from "../../Controls/SearchField";
|
|||||||
import { logger } from "../../../services/monitoring";
|
import { logger } from "../../../services/monitoring";
|
||||||
import ECUList from "../../Controls/ECUList";
|
import ECUList from "../../Controls/ECUList";
|
||||||
import { Roles, hasRole } from "../../../utils/roles";
|
import { Roles, hasRole } from "../../../utils/roles";
|
||||||
import {useLocalStorage} from "../../useLocalStorage";
|
import { useLocalStorage } from "../../useLocalStorage";
|
||||||
|
import { TYPE_MANIFEST_SOFTWARE } from "../../../utils/manifest_types";
|
||||||
|
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
{
|
{
|
||||||
@@ -57,7 +58,7 @@ const tableColumns = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const PAGE_SIZE="MANIFEST_LIST_PAGE_SIZE";
|
const PAGE_SIZE = "MANIFEST_LIST_PAGE_SIZE";
|
||||||
|
|
||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
@@ -103,6 +104,7 @@ const MainForm = () => {
|
|||||||
limit: pageSize,
|
limit: pageSize,
|
||||||
offset: pageSize * pageIndex,
|
offset: pageSize * pageIndex,
|
||||||
order: `${orderBy} ${order}`,
|
order: `${orderBy} ${order}`,
|
||||||
|
manifest_type: TYPE_MANIFEST_SOFTWARE,
|
||||||
search,
|
search,
|
||||||
},
|
},
|
||||||
token
|
token
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ const Home = React.lazy(() => import("../Home"));
|
|||||||
const Manifests = React.lazy(() => import("../Manifest/List"));
|
const Manifests = React.lazy(() => import("../Manifest/List"));
|
||||||
const ManifestDeploy = React.lazy(() => import("../Manifest/Deploy"));
|
const ManifestDeploy = React.lazy(() => import("../Manifest/Deploy"));
|
||||||
const ManifestStatus = React.lazy(() => import("../Manifest/Status"));
|
const ManifestStatus = React.lazy(() => import("../Manifest/Status"));
|
||||||
const ManifestCreate = React.lazy(() => import("../Manifest/Create"));
|
|
||||||
const PageNotFound = React.lazy(() => import("../404"));
|
const PageNotFound = React.lazy(() => import("../404"));
|
||||||
const SSOForm = React.lazy(() => import("../SSOForm"));
|
const SSOForm = React.lazy(() => import("../SSOForm"));
|
||||||
const VehicleAddForm = React.lazy(() => import("../Cars/Add"));
|
const VehicleAddForm = React.lazy(() => import("../Cars/Add"));
|
||||||
@@ -137,14 +136,6 @@ const SiteRoutes = () => {
|
|||||||
groups={groups}
|
groups={groups}
|
||||||
roles={[Roles.READ, Roles.CREATE]}
|
roles={[Roles.READ, Roles.CREATE]}
|
||||||
/>
|
/>
|
||||||
<AuthRoute
|
|
||||||
path="/package-create"
|
|
||||||
render={() => <ManifestCreate />}
|
|
||||||
type={TYPES.PROTECTED}
|
|
||||||
token={token}
|
|
||||||
groups={groups}
|
|
||||||
roles={[Roles.CREATE]}
|
|
||||||
/>
|
|
||||||
<AuthRoute
|
<AuthRoute
|
||||||
path="/package-deploy/:manifest_id"
|
path="/package-deploy/:manifest_id"
|
||||||
render={() => <ManifestDeploy />}
|
render={() => <ManifestDeploy />}
|
||||||
|
|||||||
2
src/utils/manifest_types.js
Normal file
2
src/utils/manifest_types.js
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const TYPE_MANIFEST_SOFTWARE = 1;
|
||||||
|
export const TYPE_MANIFEST_CONFIG = 2;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const rxStyles = /(mui|makeStyles|Private)([^\s]*)-\d+/g;
|
const rxStyles = /(mui|MuiBox-root|makeStyles|Private)([^\s]*)-\d+/g;
|
||||||
|
|
||||||
const snapshotSerializers = [
|
const snapshotSerializers = [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user