CEC-775 Manifest details component (#114)
* CEC-775 Manifest details component * Code smells * Fix build warning
This commit is contained in:
@@ -4607,6 +4607,11 @@ exports[`App Route /package-status authenticated 1`] = `
|
||||
<div
|
||||
data-testid="mocked-carupdatesprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-link-1227"
|
||||
>
|
||||
Show Details
|
||||
</div>
|
||||
<div
|
||||
class="makeStyles-paper-1204 makeStyles-tableSize-1256"
|
||||
>
|
||||
|
||||
@@ -9,6 +9,21 @@ export const ManifestsProvider = ({ children }) => {
|
||||
const [manifests, setManifests] = useState([]);
|
||||
const [totalManifests, setTotalManifests] = useState(0);
|
||||
|
||||
const getManifest = async (id, token) => {
|
||||
let result;
|
||||
|
||||
try {
|
||||
setBusy(true);
|
||||
result = await api.getManifest(id, token);
|
||||
if (result.error)
|
||||
throw new Error(`Get manifests error. ${result.message}`);
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const getManifests = async (search, token) => {
|
||||
let result;
|
||||
|
||||
@@ -54,6 +69,7 @@ export const ManifestsProvider = ({ children }) => {
|
||||
busy,
|
||||
manifests,
|
||||
totalManifests,
|
||||
getManifest,
|
||||
getManifests,
|
||||
deleteManifest,
|
||||
}}
|
||||
|
||||
@@ -3,6 +3,37 @@ import React from "react";
|
||||
const ManifestsContext = React.createContext();
|
||||
|
||||
let busy = false;
|
||||
let manifest = {
|
||||
id: 1,
|
||||
name: "Test Deployment",
|
||||
version: "1.0.100",
|
||||
description: "Deployment folder test",
|
||||
release_notes: "https://releasenotes.com",
|
||||
ecu_list: "ICC 1000",
|
||||
ecu_updates: [
|
||||
{
|
||||
name: "ICC",
|
||||
part_number: "BBBBBB",
|
||||
version: "1000",
|
||||
files: [
|
||||
{
|
||||
file_id: "b0cda514c94080b4",
|
||||
filename: "LARGE.jpg",
|
||||
url: "https://upload-dev.fiskerdps.com/92bbc448-99c8-4851-91ad-f8042e4deb49/LARGE.jpg",
|
||||
file_size: 14559274,
|
||||
size: 14488498,
|
||||
type: "ODX Data",
|
||||
created: "2021-12-09T22:38:29.102813Z",
|
||||
updated: "2021-12-09T22:38:29.102813Z",
|
||||
},
|
||||
],
|
||||
created: "2021-12-09T22:38:20.408351Z",
|
||||
updated: "2022-01-14T00:47:08.996451Z",
|
||||
},
|
||||
],
|
||||
created: "2021-12-09T22:38:11.679943Z",
|
||||
updated: "2022-01-14T00:47:08.996451Z",
|
||||
};
|
||||
let manifests = [
|
||||
{
|
||||
id: 1,
|
||||
@@ -22,6 +53,7 @@ export const useManifestsContext = () => ({
|
||||
busy,
|
||||
manifests,
|
||||
totalManifests,
|
||||
getManifest: jest.fn(() => manifest),
|
||||
getManifests: jest.fn(() => manifests),
|
||||
deleteManifest: jest.fn(),
|
||||
});
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Manifest Details Component Render Hidden 1`] = `
|
||||
Object {
|
||||
"asFragment": [Function],
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
data-testid="mocked-manifestsprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-link-26"
|
||||
>
|
||||
Show Details
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>,
|
||||
"container": <div>
|
||||
<div
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
data-testid="mocked-manifestsprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-link-26"
|
||||
>
|
||||
Show Details
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
"debug": [Function],
|
||||
"findAllByAltText": [Function],
|
||||
"findAllByDisplayValue": [Function],
|
||||
"findAllByLabelText": [Function],
|
||||
"findAllByPlaceholderText": [Function],
|
||||
"findAllByRole": [Function],
|
||||
"findAllByTestId": [Function],
|
||||
"findAllByText": [Function],
|
||||
"findAllByTitle": [Function],
|
||||
"findByAltText": [Function],
|
||||
"findByDisplayValue": [Function],
|
||||
"findByLabelText": [Function],
|
||||
"findByPlaceholderText": [Function],
|
||||
"findByRole": [Function],
|
||||
"findByTestId": [Function],
|
||||
"findByText": [Function],
|
||||
"findByTitle": [Function],
|
||||
"getAllByAltText": [Function],
|
||||
"getAllByDisplayValue": [Function],
|
||||
"getAllByLabelText": [Function],
|
||||
"getAllByPlaceholderText": [Function],
|
||||
"getAllByRole": [Function],
|
||||
"getAllByTestId": [Function],
|
||||
"getAllByText": [Function],
|
||||
"getAllByTitle": [Function],
|
||||
"getByAltText": [Function],
|
||||
"getByDisplayValue": [Function],
|
||||
"getByLabelText": [Function],
|
||||
"getByPlaceholderText": [Function],
|
||||
"getByRole": [Function],
|
||||
"getByTestId": [Function],
|
||||
"getByText": [Function],
|
||||
"getByTitle": [Function],
|
||||
"queryAllByAltText": [Function],
|
||||
"queryAllByDisplayValue": [Function],
|
||||
"queryAllByLabelText": [Function],
|
||||
"queryAllByPlaceholderText": [Function],
|
||||
"queryAllByRole": [Function],
|
||||
"queryAllByTestId": [Function],
|
||||
"queryAllByText": [Function],
|
||||
"queryAllByTitle": [Function],
|
||||
"queryByAltText": [Function],
|
||||
"queryByDisplayValue": [Function],
|
||||
"queryByLabelText": [Function],
|
||||
"queryByPlaceholderText": [Function],
|
||||
"queryByRole": [Function],
|
||||
"queryByTestId": [Function],
|
||||
"queryByText": [Function],
|
||||
"queryByTitle": [Function],
|
||||
"rerender": [Function],
|
||||
"unmount": [Function],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Manifest Details Component Render Shown 1`] = `
|
||||
Object {
|
||||
"asFragment": [Function],
|
||||
"baseElement": <body>
|
||||
<div>
|
||||
<div
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
data-testid="mocked-manifestsprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-link-89"
|
||||
>
|
||||
Hide Details
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
Test Deployment 1.0.100
|
||||
</li>
|
||||
<li>
|
||||
Deployment folder test https://releasenotes.com
|
||||
</li>
|
||||
<li>
|
||||
ECUs:
|
||||
<ul>
|
||||
<li>
|
||||
ICC, Part: BBBBBB, Version: 1000
|
||||
<br />
|
||||
<ul>
|
||||
<li>
|
||||
ODX Data: LARGE.jpg
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>,
|
||||
"container": <div>
|
||||
<div
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
data-testid="mocked-manifestsprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-link-89"
|
||||
>
|
||||
Hide Details
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
Test Deployment 1.0.100
|
||||
</li>
|
||||
<li>
|
||||
Deployment folder test https://releasenotes.com
|
||||
</li>
|
||||
<li>
|
||||
ECUs:
|
||||
<ul>
|
||||
<li>
|
||||
ICC, Part: BBBBBB, Version: 1000
|
||||
<br />
|
||||
<ul>
|
||||
<li>
|
||||
ODX Data: LARGE.jpg
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
"debug": [Function],
|
||||
"findAllByAltText": [Function],
|
||||
"findAllByDisplayValue": [Function],
|
||||
"findAllByLabelText": [Function],
|
||||
"findAllByPlaceholderText": [Function],
|
||||
"findAllByRole": [Function],
|
||||
"findAllByTestId": [Function],
|
||||
"findAllByText": [Function],
|
||||
"findAllByTitle": [Function],
|
||||
"findByAltText": [Function],
|
||||
"findByDisplayValue": [Function],
|
||||
"findByLabelText": [Function],
|
||||
"findByPlaceholderText": [Function],
|
||||
"findByRole": [Function],
|
||||
"findByTestId": [Function],
|
||||
"findByText": [Function],
|
||||
"findByTitle": [Function],
|
||||
"getAllByAltText": [Function],
|
||||
"getAllByDisplayValue": [Function],
|
||||
"getAllByLabelText": [Function],
|
||||
"getAllByPlaceholderText": [Function],
|
||||
"getAllByRole": [Function],
|
||||
"getAllByTestId": [Function],
|
||||
"getAllByText": [Function],
|
||||
"getAllByTitle": [Function],
|
||||
"getByAltText": [Function],
|
||||
"getByDisplayValue": [Function],
|
||||
"getByLabelText": [Function],
|
||||
"getByPlaceholderText": [Function],
|
||||
"getByRole": [Function],
|
||||
"getByTestId": [Function],
|
||||
"getByText": [Function],
|
||||
"getByTitle": [Function],
|
||||
"queryAllByAltText": [Function],
|
||||
"queryAllByDisplayValue": [Function],
|
||||
"queryAllByLabelText": [Function],
|
||||
"queryAllByPlaceholderText": [Function],
|
||||
"queryAllByRole": [Function],
|
||||
"queryAllByTestId": [Function],
|
||||
"queryAllByText": [Function],
|
||||
"queryAllByTitle": [Function],
|
||||
"queryByAltText": [Function],
|
||||
"queryByDisplayValue": [Function],
|
||||
"queryByLabelText": [Function],
|
||||
"queryByPlaceholderText": [Function],
|
||||
"queryByRole": [Function],
|
||||
"queryByTestId": [Function],
|
||||
"queryByText": [Function],
|
||||
"queryByTitle": [Function],
|
||||
"rerender": [Function],
|
||||
"unmount": [Function],
|
||||
}
|
||||
`;
|
||||
94
src/components/Manifest/Details/index.jsx
Normal file
94
src/components/Manifest/Details/index.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
import { useManifestsContext } from "../../Contexts/ManifestsContext";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import useStyles from "../../useStyles";
|
||||
|
||||
const ECUFileList = (files) => {
|
||||
if (!files || files.length === 0) return "No files";
|
||||
return (
|
||||
<ul>
|
||||
{files.map((file) => (
|
||||
<li key={file.filename}>{`${file.type}: ${file.filename} `}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
const ECUList = (ecus) => {
|
||||
if (!ecus || ecus.length === 0) return "None";
|
||||
return (
|
||||
<ul>
|
||||
{ecus.map((ecu) => (
|
||||
<li key={ecu.name}>
|
||||
{`${ecu.name}, Part: ${ecu.part_number}, Version: ${ecu.version}`}
|
||||
<br />
|
||||
{ECUFileList(ecu.files)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
const ManifestDetails = ({ opened }) => {
|
||||
const classes = useStyles();
|
||||
const { manifest_id } = useParams();
|
||||
const [manifest, setManifest] = useState(null);
|
||||
const [open, setOpen] = useState(opened || false);
|
||||
const { getManifest } = useManifestsContext();
|
||||
const { setMessage } = useStatusContext();
|
||||
const {
|
||||
token: {
|
||||
idToken: { jwtToken: token },
|
||||
},
|
||||
} = useUserContext();
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
const result = await getManifest(manifest_id, token);
|
||||
if (result.error) {
|
||||
throw new Error(`Get manifest error. ${result.message}`);
|
||||
} else {
|
||||
setManifest(result);
|
||||
}
|
||||
} catch (e) {
|
||||
setMessage(e.message);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleOpen = (e) => {
|
||||
e.preventDefault();
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open || manifest) return;
|
||||
init();
|
||||
// eslint-disable-next-line
|
||||
}, [open]);
|
||||
|
||||
if (!open)
|
||||
return (
|
||||
<div className={classes.link} onClick={(e) => toggleOpen(e)}>
|
||||
Show Details
|
||||
</div>
|
||||
);
|
||||
if (manifest === null) return <div>Loading Manifest...</div>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={classes.link} onClick={(e) => toggleOpen(e)}>
|
||||
Hide Details
|
||||
</div>
|
||||
<ul>
|
||||
<li>{`${manifest.name} ${manifest.version}`}</li>
|
||||
<li>{`${manifest.description} ${manifest.release_notes}`}</li>
|
||||
<li>ECUs: {ECUList(manifest.ecu_updates)}</li>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManifestDetails;
|
||||
46
src/components/Manifest/Details/index.test.jsx
Normal file
46
src/components/Manifest/Details/index.test.jsx
Normal file
@@ -0,0 +1,46 @@
|
||||
jest.mock("../../Contexts/ManifestsContext");
|
||||
jest.mock("../../Contexts/UserContext");
|
||||
|
||||
import React from "react";
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
import { ManifestsProvider } from "../../Contexts/ManifestsContext";
|
||||
import { UserProvider, setToken } from "../../Contexts/UserContext";
|
||||
import { StatusProvider } from "../../Contexts/StatusContext";
|
||||
import ManifestDetails from ".";
|
||||
import { TEST_AUTH_OBJECT } from "../../../utils/testing";
|
||||
|
||||
const TestComponent = (opened) => (
|
||||
<UserProvider>
|
||||
<BrowserRouter>
|
||||
<StatusProvider>
|
||||
<ManifestsProvider>
|
||||
<ManifestDetails opened={opened} />
|
||||
</ManifestsProvider>
|
||||
</StatusProvider>
|
||||
</BrowserRouter>
|
||||
</UserProvider>
|
||||
);
|
||||
|
||||
describe("Manifest Details Component", () => {
|
||||
beforeAll(() => {
|
||||
setToken(TEST_AUTH_OBJECT);
|
||||
});
|
||||
|
||||
it("Render Hidden", async () => {
|
||||
const rendered = render(TestComponent(false));
|
||||
await waitFor(() => {
|
||||
// pause for render
|
||||
});
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("Render Shown", async () => {
|
||||
const rendered = render(TestComponent(true));
|
||||
await waitFor(() => {
|
||||
// pause for render
|
||||
});
|
||||
expect(rendered).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -26,6 +26,7 @@ import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import useStyles from "../../useStyles";
|
||||
import { LocalDateTimeString } from "../../../utils/dates";
|
||||
import { logger } from "../../../services/monitoring";
|
||||
import ManifestDetails from "../Details";
|
||||
|
||||
const MainForm = () => {
|
||||
const { manifest_id } = useParams();
|
||||
@@ -182,6 +183,7 @@ const MainForm = () => {
|
||||
const ManifestStatus = () => (
|
||||
<ManifestsProvider>
|
||||
<CarUpdatesProvider>
|
||||
<ManifestDetails />
|
||||
<MainForm />
|
||||
</CarUpdatesProvider>
|
||||
</ManifestsProvider>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
|
||||
|
||||
const manifestsAPI = {
|
||||
createCarUpdates: async (data, token) => {
|
||||
if (!data.id) data.id = 0;
|
||||
data.id++;
|
||||
return data;
|
||||
},
|
||||
|
||||
|
||||
getPackages: async (search, token) => {
|
||||
return {
|
||||
data: [
|
||||
@@ -30,9 +28,9 @@ const manifestsAPI = {
|
||||
version: "1.2",
|
||||
link: "https://cloudfront.com/download",
|
||||
ecu_list: "ECU1 1.1.0,ECU2 1.1.2",
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
updatePackage: async (data, token) => {
|
||||
@@ -54,6 +52,40 @@ const manifestsAPI = {
|
||||
getCarUpdateProgress: async (carupdateids, token) => {
|
||||
return { statuses: [] };
|
||||
},
|
||||
|
||||
getManifest: async (id, token) => {
|
||||
return {
|
||||
id,
|
||||
name: "Test Deployment",
|
||||
version: "1.0.100",
|
||||
description: "Deployment folder test",
|
||||
release_notes: "https://releasenotes.com",
|
||||
ecu_list: "ICC 1000",
|
||||
ecu_updates: [
|
||||
{
|
||||
name: "ICC",
|
||||
part_number: "BBBBBB",
|
||||
version: "1000",
|
||||
files: [
|
||||
{
|
||||
file_id: "b0cda514c94080b4",
|
||||
filename: "LARGE.jpg",
|
||||
url: "https://upload-dev.fiskerdps.com/92bbc448-99c8-4851-91ad-f8042e4deb49/LARGE.jpg",
|
||||
file_size: 14559274,
|
||||
size: 14488498,
|
||||
type: "ODX Data",
|
||||
created: "2021-12-09T22:38:29.102813Z",
|
||||
updated: "2021-12-09T22:38:29.102813Z",
|
||||
},
|
||||
],
|
||||
created: "2021-12-09T22:38:20.408351Z",
|
||||
updated: "2022-01-14T00:47:08.996451Z",
|
||||
},
|
||||
],
|
||||
created: "2021-12-09T22:38:11.679943Z",
|
||||
updated: "2022-01-14T00:47:08.996451Z",
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default manifestsAPI;
|
||||
|
||||
@@ -16,6 +16,17 @@ const manifestsAPI = {
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
|
||||
getManifest: async (id, token) => {
|
||||
const u = addQueryParams(`${API_ENDPOINT}/manifest`, { id });
|
||||
return fetch(u, {
|
||||
method: "GET",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
},
|
||||
|
||||
getManifests: async (search, token) => {
|
||||
const u = addQueryParams(`${API_ENDPOINT}/manifests`, search);
|
||||
return fetch(u, {
|
||||
|
||||
Reference in New Issue
Block a user