CEC-3519 Add car version history (#260)
* CEC-3519 Add car version history CEC-3455 Delete button is icon and remove column CEC-3496 Fix Issue delete * smell * Remove tab from issues details page * Fix date format
This commit is contained in:
@@ -1752,115 +1752,64 @@ exports[`App Route /issue-info authenticated 1`] = `
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<div
|
||||
class="MuiBox-root MuiBox-root-0 makeStyles-tableToolbar-0"
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-root"
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-fixed"
|
||||
style="overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
aria-label="issue tabs"
|
||||
class="MuiTabs-flexContainer"
|
||||
role="tablist"
|
||||
>
|
||||
<button
|
||||
aria-controls="tabpanel-0"
|
||||
aria-selected="true"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit Mui-selected"
|
||||
id="tab-0"
|
||||
role="tab"
|
||||
tabindex="0"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Details
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<span
|
||||
class="PrivateTabIndicator-root-0 PrivateTabIndicator-colorSecondary-0 MuiTabs-indicator"
|
||||
style="left: 0px; width: 0px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-labelledby="tab-0"
|
||||
id="tabpanel-0"
|
||||
role="tabpanel"
|
||||
>
|
||||
Issue Details
|
||||
</h6>
|
||||
<div
|
||||
class="MuiBox-root MuiBox-root-0"
|
||||
data-testid="mocked-issueprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
>
|
||||
Issue Details
|
||||
</h6>
|
||||
<div
|
||||
data-testid="mocked-issueprovider"
|
||||
class="MuiGrid-root makeStyles-root-0 MuiGrid-container MuiGrid-spacing-xs-2"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
|
||||
>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-root-0 MuiGrid-container MuiGrid-spacing-xs-2"
|
||||
>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
|
||||
>
|
||||
<p>
|
||||
<b>
|
||||
ID
|
||||
</b>
|
||||
:
|
||||
FISKER123
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
VIN
|
||||
</b>
|
||||
:
|
||||
1GNGC26RXXJ407648
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
Title
|
||||
</b>
|
||||
:
|
||||
sometitle
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
Description
|
||||
</b>
|
||||
:
|
||||
2343242
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
timestamp
|
||||
</b>
|
||||
:
|
||||
2022-12-09T23:16:38.074858Z
|
||||
</p>
|
||||
<img
|
||||
alt="Issue images"
|
||||
src="data:image/png;base64, SGVsbG8x"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
<b>
|
||||
ID
|
||||
</b>
|
||||
:
|
||||
FISKER123
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
VIN
|
||||
</b>
|
||||
:
|
||||
1GNGC26RXXJ407648
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
Title
|
||||
</b>
|
||||
:
|
||||
sometitle
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
Description
|
||||
</b>
|
||||
:
|
||||
2343242
|
||||
</p>
|
||||
<p>
|
||||
<b>
|
||||
timestamp
|
||||
</b>
|
||||
:
|
||||
12/9/2022 11:16:38 PM
|
||||
</p>
|
||||
<img
|
||||
alt="Issue images"
|
||||
src="data:image/png;base64, SGVsbG8x"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2472,29 +2421,6 @@ exports[`App Route /issues authenticated 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Description
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
@@ -2578,11 +2504,6 @@ exports[`App Route /issues authenticated 1`] = `
|
||||
>
|
||||
sometitle
|
||||
</td>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||
>
|
||||
2343242
|
||||
</td>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||
>
|
||||
@@ -2616,11 +2537,6 @@ exports[`App Route /issues authenticated 1`] = `
|
||||
>
|
||||
sometitle
|
||||
</td>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||
>
|
||||
2343242
|
||||
</td>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-body MuiTableCell-alignCenter"
|
||||
>
|
||||
@@ -2639,8 +2555,122 @@ exports[`App Route /issues authenticated 1`] = `
|
||||
<tr
|
||||
class="MuiTableRow-root MuiTableRow-footer"
|
||||
>
|
||||
<td>
|
||||
No issues found
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||
colspan="6"
|
||||
>
|
||||
<div
|
||||
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||
>
|
||||
<div
|
||||
class="MuiTablePagination-spacer"
|
||||
/>
|
||||
<p
|
||||
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||
id="mui-0"
|
||||
>
|
||||
Rows per page:
|
||||
</p>
|
||||
<div
|
||||
class="MuiInputBase-root MuiTablePagination-input MuiTablePagination-selectRoot"
|
||||
>
|
||||
<select
|
||||
aria-label="rows per page"
|
||||
class="MuiSelect-root MuiSelect-select MuiTablePagination-select MuiInputBase-input"
|
||||
id="mui-0"
|
||||
>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="5"
|
||||
>
|
||||
5
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="10"
|
||||
>
|
||||
10
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="25"
|
||||
>
|
||||
25
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="100"
|
||||
>
|
||||
100
|
||||
</option>
|
||||
</select>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSelect-icon MuiTablePagination-selectIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M7 10l5 5 5-5z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p
|
||||
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||
>
|
||||
0-0 of 0
|
||||
</p>
|
||||
<div
|
||||
class="MuiTablePagination-actions"
|
||||
>
|
||||
<button
|
||||
aria-label="Previous page"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
title="Previous page"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="Next page"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
title="Next page"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@@ -9623,8 +9653,12 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
||||
class="MuiTabs-root"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-fixed"
|
||||
style="overflow: hidden;"
|
||||
class="MuiTabs-scrollable"
|
||||
style="width: 99px; height: 99px; position: absolute; top: -9999px; overflow: scroll;"
|
||||
/>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-scrollable"
|
||||
style="margin-bottom: 0px;"
|
||||
>
|
||||
<div
|
||||
aria-label="car tabs"
|
||||
@@ -9733,7 +9767,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Remote Commands
|
||||
ECUs
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
@@ -9747,6 +9781,24 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
||||
role="tab"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Remote Commands
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-controls="tabpanel-7"
|
||||
aria-selected="false"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit"
|
||||
id="tab-7"
|
||||
role="tab"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
@@ -9972,6 +10024,12 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
||||
id="tabpanel-6"
|
||||
role="tabpanel"
|
||||
/>
|
||||
<div
|
||||
aria-labelledby="tab-7"
|
||||
hidden=""
|
||||
id="tabpanel-7"
|
||||
role="tabpanel"
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
</main>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Typography } from "@material-ui/core";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import { useParams } from "react-router";
|
||||
import clsx from "clsx";
|
||||
import { Typography } from "@material-ui/core";
|
||||
|
||||
import CarECUsTable from "../../Controls/CarECUsTable";
|
||||
import CarUpdatesTable from "../../Controls/CarUpdatesTable";
|
||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
||||
import CarUpdatesTable from "../../Controls/CarUpdatesTable";
|
||||
import CarVersionLogTable from "../../Controls/CarVersionLogTable";
|
||||
import useStyles from "../../useStyles";
|
||||
|
||||
const MainForm = () => {
|
||||
@@ -22,10 +22,8 @@ const MainForm = () => {
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6">Car Updates</Typography>
|
||||
<CarUpdatesTable vin={vin} token={token} classes={classes} />
|
||||
<Typography variant="h6" className={classes.labelInline}>
|
||||
Car ECUs
|
||||
</Typography>
|
||||
<CarECUsTable vin={vin} token={token} classes={classes} />
|
||||
<Typography variant="h6" className={classes.labelInline}>Version Log</Typography>
|
||||
<CarVersionLogTable vin={vin} token={token} classes={classes} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
jest.mock("../../Contexts/CANFiltersContext");
|
||||
jest.mock("../../Contexts/StatusContext");
|
||||
jest.mock("../../Contexts/UserContext");
|
||||
jest.mock("../../../services/vehiclesAPI");
|
||||
jest.mock("@material-ui/core/utils/unstable_useId", () =>
|
||||
jest.fn().mockReturnValue("mui-test-id")
|
||||
);
|
||||
@@ -8,12 +9,12 @@ jest.mock("@material-ui/core/utils/unstable_useId", () =>
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
import addSnapshotSerializer from "../../../utils/snapshot";
|
||||
import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing";
|
||||
import { CANFiltersProvider } from "../../Contexts/CANFiltersContext";
|
||||
import { StatusProvider } from "../../Contexts/StatusContext";
|
||||
import { UserProvider, setToken } from "../../Contexts/UserContext";
|
||||
import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing";
|
||||
import { setToken, UserProvider } from "../../Contexts/UserContext";
|
||||
import MainForm from "./CarUpdatesTab";
|
||||
import addSnapshotSerializer from "../../../utils/snapshot";
|
||||
|
||||
const renderCarUpdatesTab = async () => {
|
||||
const { container } = render(
|
||||
|
||||
36
src/components/Cars/Status/ECUsTab.jsx
Normal file
36
src/components/Cars/Status/ECUsTab.jsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Typography } from "@material-ui/core";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
import { useParams } from "react-router";
|
||||
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
||||
import CarECUsTable from "../../Controls/CarECUsTable";
|
||||
import useStyles from "../../useStyles";
|
||||
|
||||
const MainForm = () => {
|
||||
const { vin } = useParams();
|
||||
const classes = useStyles();
|
||||
const {
|
||||
token: {
|
||||
idToken: { jwtToken: token },
|
||||
},
|
||||
} = useUserContext();
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6" className={classes.labelInline}>
|
||||
Car ECUs
|
||||
</Typography>
|
||||
<CarECUsTable vin={vin} token={token} classes={classes} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const CarUpdatesTab = () => (
|
||||
<VehicleProvider>
|
||||
<MainForm />
|
||||
</VehicleProvider>
|
||||
);
|
||||
|
||||
export default CarUpdatesTab;
|
||||
44
src/components/Cars/Status/ECUsTab.test.jsx
Normal file
44
src/components/Cars/Status/ECUsTab.test.jsx
Normal file
@@ -0,0 +1,44 @@
|
||||
jest.mock("../../Contexts/CANFiltersContext");
|
||||
jest.mock("../../Contexts/StatusContext");
|
||||
jest.mock("../../Contexts/UserContext");
|
||||
jest.mock("../../../services/vehiclesAPI");
|
||||
jest.mock("@material-ui/core/utils/unstable_useId", () =>
|
||||
jest.fn().mockReturnValue("mui-test-id")
|
||||
);
|
||||
|
||||
import { render, waitFor } from "@testing-library/react";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
|
||||
import addSnapshotSerializer from "../../../utils/snapshot";
|
||||
import { TEST_AUTH_OBJECT_FISKER } from "../../../utils/testing";
|
||||
import { StatusProvider } from "../../Contexts/StatusContext";
|
||||
import { setToken, UserProvider } from "../../Contexts/UserContext";
|
||||
import MainForm from "./ECUsTab";
|
||||
|
||||
const renderECUsTab = async () => {
|
||||
const { container } = render(
|
||||
<StatusProvider>
|
||||
<UserProvider>
|
||||
<BrowserRouter>
|
||||
<MainForm vin="TESTVIN1234567890" />
|
||||
</BrowserRouter>
|
||||
</UserProvider>
|
||||
</StatusProvider>
|
||||
);
|
||||
await waitFor(() => {
|
||||
/* render */
|
||||
});
|
||||
return container;
|
||||
};
|
||||
|
||||
describe("ECUsTab", () => {
|
||||
beforeAll(() => {
|
||||
addSnapshotSerializer(expect);
|
||||
});
|
||||
|
||||
it("Render", async () => {
|
||||
setToken(TEST_AUTH_OBJECT_FISKER);
|
||||
const container = await renderECUsTab();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -173,7 +173,7 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
<h6
|
||||
class="MuiTypography-root makeStyles-labelInline-0 MuiTypography-h6"
|
||||
>
|
||||
Car ECUs
|
||||
Version Log
|
||||
</h6>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
@@ -187,6 +187,52 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
<tr
|
||||
class="MuiTableRow-root MuiTableRow-head"
|
||||
>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Type
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Version
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
aria-sort="descending"
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
@@ -198,7 +244,7 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
ECU
|
||||
Date
|
||||
<span
|
||||
class="makeStyles-hiddenSortSpan-0"
|
||||
>
|
||||
@@ -216,121 +262,6 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
SW Version
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
HW Version
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Config
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Created
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Updated
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
@@ -344,7 +275,7 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||
colspan="10"
|
||||
colspan="3"
|
||||
>
|
||||
<div
|
||||
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||
|
||||
309
src/components/Cars/Status/__snapshots__/ECUsTab.test.jsx.snap
Normal file
309
src/components/Cars/Status/__snapshots__/ECUsTab.test.jsx.snap
Normal file
@@ -0,0 +1,309 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ECUsTab Render 1`] = `
|
||||
<div>
|
||||
<div
|
||||
data-testid="mocked-statusprovider"
|
||||
>
|
||||
<div
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root makeStyles-labelInline-0 MuiTypography-h6"
|
||||
>
|
||||
Car ECUs
|
||||
</h6>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<table
|
||||
class="MuiTable-root"
|
||||
>
|
||||
<thead
|
||||
class="MuiTableHead-root"
|
||||
>
|
||||
<tr
|
||||
class="MuiTableRow-root MuiTableRow-head"
|
||||
>
|
||||
<th
|
||||
aria-sort="descending"
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root MuiTableSortLabel-active"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
ECU
|
||||
<span
|
||||
class="makeStyles-hiddenSortSpan-0"
|
||||
>
|
||||
sorted descending
|
||||
</span>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionDesc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
SW Version
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
HW Version
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Config
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Created
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Updated
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
class="MuiTableBody-root"
|
||||
/>
|
||||
<tfoot
|
||||
class="MuiTableFooter-root"
|
||||
>
|
||||
<tr
|
||||
class="MuiTableRow-root MuiTableRow-footer"
|
||||
>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||
colspan="10"
|
||||
>
|
||||
<div
|
||||
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||
>
|
||||
<div
|
||||
class="MuiTablePagination-spacer"
|
||||
/>
|
||||
<p
|
||||
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||
>
|
||||
Rows per page:
|
||||
</p>
|
||||
<div
|
||||
class="MuiInputBase-root MuiTablePagination-input MuiTablePagination-selectRoot"
|
||||
>
|
||||
<select
|
||||
aria-label="rows per page"
|
||||
class="MuiSelect-root MuiSelect-select MuiTablePagination-select MuiInputBase-input"
|
||||
>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="5"
|
||||
>
|
||||
5
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="10"
|
||||
>
|
||||
10
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="25"
|
||||
>
|
||||
25
|
||||
</option>
|
||||
<option
|
||||
class="MuiTablePagination-menuItem"
|
||||
value="100"
|
||||
>
|
||||
100
|
||||
</option>
|
||||
</select>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiSelect-icon MuiTablePagination-selectIcon"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M7 10l5 5 5-5z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<p
|
||||
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
|
||||
>
|
||||
0-0 of 0
|
||||
</p>
|
||||
<div
|
||||
class="MuiTablePagination-actions"
|
||||
>
|
||||
<button
|
||||
aria-label="Previous page"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
title="Previous page"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M15.41 16.09l-4.58-4.59 4.58-4.59L14 5.5l-6 6 6 6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
aria-label="Next page"
|
||||
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
|
||||
disabled=""
|
||||
tabindex="-1"
|
||||
title="Next page"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiIconButton-label"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M8.59 16.34l4.58-4.59-4.58-4.59L10 5.75l6 6-6 6z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -21,8 +21,12 @@ exports[`CarStatus Render 1`] = `
|
||||
class="MuiTabs-root"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-fixed"
|
||||
style="overflow: hidden;"
|
||||
class="MuiTabs-scrollable"
|
||||
style="width: 99px; height: 99px; position: absolute; top: -9999px; overflow: scroll;"
|
||||
/>
|
||||
<div
|
||||
class="MuiTabs-scroller MuiTabs-scrollable"
|
||||
style="margin-bottom: 0px;"
|
||||
>
|
||||
<div
|
||||
aria-label="car tabs"
|
||||
@@ -131,7 +135,7 @@ exports[`CarStatus Render 1`] = `
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Remote Commands
|
||||
ECUs
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
@@ -145,6 +149,24 @@ exports[`CarStatus Render 1`] = `
|
||||
role="tab"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
>
|
||||
Remote Commands
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
aria-controls="tabpanel-7"
|
||||
aria-selected="false"
|
||||
class="MuiButtonBase-root MuiTab-root MuiTab-textColorInherit"
|
||||
id="tab-7"
|
||||
role="tab"
|
||||
tabindex="-1"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="MuiTab-wrapper"
|
||||
@@ -314,6 +336,12 @@ exports[`CarStatus Render 1`] = `
|
||||
id="tabpanel-6"
|
||||
role="tabpanel"
|
||||
/>
|
||||
<div
|
||||
aria-labelledby="tab-7"
|
||||
hidden=""
|
||||
id="tabpanel-7"
|
||||
role="tabpanel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ import CANSignalsTab from "./CANSignalsTab";
|
||||
import CarUpdatesTab from "./CarUpdatesTab";
|
||||
import CarDetailsTab from "./DetailsTab";
|
||||
import DigitalTwinTab from "./DigitalTwinTab";
|
||||
import ECUsTab from "./ECUsTab";
|
||||
import FleetsTab from "./FleetsTab";
|
||||
import RemoteCommandsTab from "./RemoteCommandsTab";
|
||||
|
||||
@@ -41,6 +42,10 @@ const TabViews = [
|
||||
label: "CAN Signals",
|
||||
component: CANSignalsTab,
|
||||
},
|
||||
{
|
||||
label: "ECUs",
|
||||
component: ECUsTab,
|
||||
},
|
||||
{
|
||||
label: "Remote Commands",
|
||||
component: RemoteCommandsTab,
|
||||
@@ -110,6 +115,7 @@ const CarStatus = () => {
|
||||
value={tabIndex}
|
||||
onChange={handleTabChange}
|
||||
aria-label="car tabs"
|
||||
variant="scrollable"
|
||||
indicatorColor="secondary">
|
||||
{tabs.map((item, index) => <Tab key={index} label={item.label} {...tabProps(index)} />)}
|
||||
</Tabs>
|
||||
|
||||
@@ -233,6 +233,17 @@ export const VehicleProvider = ({ children }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getVersionLog = async (search, token) => {
|
||||
try {
|
||||
setBusy(true);
|
||||
const result = await api.getVersionLog(search, token);
|
||||
if (result.error) throw new Error(`Get version log error. ${result.message}`);
|
||||
return result;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<VehicleContext.Provider
|
||||
value={{
|
||||
@@ -258,6 +269,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
sendCommand,
|
||||
updateVehicle,
|
||||
getFleets,
|
||||
getVersionLog,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
136
src/components/Controls/CarVersionLogTable/index.jsx
Normal file
136
src/components/Controls/CarVersionLogTable/index.jsx
Normal file
@@ -0,0 +1,136 @@
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TablePagination,
|
||||
TableRow
|
||||
} from "@material-ui/core";
|
||||
import clsx from "clsx";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import { logger } from "../../../services/monitoring";
|
||||
import { LocalDateTimeString } from "../../../utils/dates";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
||||
import TableHeaderSortable from "../../Table/HeaderSortable";
|
||||
import { useLocalStorage } from "../../useLocalStorage";
|
||||
|
||||
const tableColumns = [
|
||||
{
|
||||
id: "version_source",
|
||||
label: "Type",
|
||||
},
|
||||
{
|
||||
id: "version",
|
||||
label: "Version",
|
||||
},
|
||||
{
|
||||
id: "created_at",
|
||||
label: "Date",
|
||||
},
|
||||
];
|
||||
|
||||
const PAGE_SIZE = "CAR_VERSIONLOG_TABLE_PAGE_SIZE";
|
||||
|
||||
const CarVersionLogTable = ({ vin, token, classes }) => {
|
||||
const [versions, setVersions] = useState([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [pageSize, setPageSize] = useLocalStorage(PAGE_SIZE, 10);
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [orderBy, setOrderBy] = useState("created_at");
|
||||
const [order, setOrder] = useState("desc");
|
||||
const { getVersionLog } = useVehicleContext();
|
||||
const { setMessage } = useStatusContext();
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
if (!vin || !token) return;
|
||||
const result = await getVersionLog(
|
||||
{
|
||||
vin,
|
||||
limit: pageSize,
|
||||
offset: pageSize * pageIndex,
|
||||
order: `${orderBy} ${order}`,
|
||||
},
|
||||
token
|
||||
);
|
||||
setVersions(result.data);
|
||||
if (result.total > -1) setTotal(result.total);
|
||||
} catch (e) {
|
||||
setMessage(e.message);
|
||||
logger.warn(e.stack);
|
||||
}
|
||||
})();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [vin, token, pageIndex, pageSize, orderBy, order]);
|
||||
|
||||
const handleChangePageIndex = (event, newIndex) => {
|
||||
setPageIndex(newIndex);
|
||||
};
|
||||
|
||||
const handleChangePageSize = (event) => {
|
||||
setPageSize(parseInt(event.target.value, 10));
|
||||
setPageIndex(0);
|
||||
};
|
||||
|
||||
const handleSort = (event, property) => {
|
||||
try {
|
||||
if (property === orderBy) {
|
||||
if (order === "asc") {
|
||||
setOrder("desc");
|
||||
} else {
|
||||
setOrder("asc");
|
||||
}
|
||||
} else {
|
||||
setOrderBy(property);
|
||||
setOrder("asc");
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn(e.stack);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Table>
|
||||
<TableHeaderSortable
|
||||
classes={classes}
|
||||
orderBy={orderBy}
|
||||
order={order}
|
||||
columnData={tableColumns}
|
||||
onSortRequest={handleSort}
|
||||
/>
|
||||
<TableBody>
|
||||
{versions && versions.map((row, i) => (
|
||||
<TableRow key={`row${i}`}>
|
||||
<TableCell align="center">{row.version_source}</TableCell>
|
||||
<TableCell align="center">{row.version}</TableCell>
|
||||
<TableCell align="center">{LocalDateTimeString(row.created_at)}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, 100]}
|
||||
colSpan={3}
|
||||
count={total}
|
||||
rowsPerPage={pageSize}
|
||||
page={pageIndex}
|
||||
SelectProps={{
|
||||
inputProps: { "aria-label": "rows per page" },
|
||||
native: true,
|
||||
}}
|
||||
onPageChange={handleChangePageIndex}
|
||||
onRowsPerPageChange={handleChangePageSize}
|
||||
/>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CarVersionLogTable;
|
||||
@@ -1,26 +1,26 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import PropTypes from "prop-types";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TablePagination,
|
||||
TableRow,
|
||||
Button,
|
||||
TableRow
|
||||
} from "@material-ui/core";
|
||||
import DeleteIcon from "@material-ui/icons/Delete";
|
||||
import clsx from "clsx";
|
||||
import PropTypes from "prop-types";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import { logger } from "../../../services/monitoring";
|
||||
import { LocalDateTimeString } from "../../../utils/dates";
|
||||
import { Permissions } from "../../../utils/roles";
|
||||
import { useIssueContext } from "../../Contexts/IssueContext";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import { LocalDateTimeString } from "../../../utils/dates";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import TableHeaderSortable from "../../Table/HeaderSortable";
|
||||
import { logger } from "../../../services/monitoring";
|
||||
import { useLocalStorage } from "../../useLocalStorage";
|
||||
import { RoleWrap } from "../RoleWrap";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import { Permissions } from "../../../utils/roles";
|
||||
|
||||
const tableColumns = [
|
||||
{
|
||||
@@ -35,10 +35,6 @@ const tableColumns = [
|
||||
id: "title",
|
||||
label: "Title",
|
||||
},
|
||||
{
|
||||
id: "description",
|
||||
label: "Description",
|
||||
},
|
||||
{
|
||||
id: "driver_id",
|
||||
label: "Driver ID",
|
||||
@@ -69,7 +65,7 @@ const IssueSelectionTable = (props) => {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [orderBy, setOrderBy] = useState("created_at");
|
||||
const [order, setOrder] = useState("asc");
|
||||
const { getIssues, issues, totalIssues = 0 } = useIssueContext();
|
||||
const { deleteIssue, getIssues, issues, totalIssues = 0 } = useIssueContext();
|
||||
const { groups, providers } = useUserContext();
|
||||
const { setMessage } = useStatusContext();
|
||||
|
||||
@@ -132,12 +128,19 @@ const IssueSelectionTable = (props) => {
|
||||
setPageIndex(0);
|
||||
}, [search]);
|
||||
|
||||
const { deleteIssue } = useIssueContext();
|
||||
const handleDelete = (id) => {
|
||||
deleteIssue(id, token).then(() => {
|
||||
getIssues(token)
|
||||
getIssues(
|
||||
{
|
||||
limit: pageSize,
|
||||
offset: pageSize * pageIndex,
|
||||
order: `${orderBy} ${order}`,
|
||||
},
|
||||
token
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Table>
|
||||
@@ -161,7 +164,6 @@ const IssueSelectionTable = (props) => {
|
||||
</TableCell>
|
||||
<TableCell align="center">{row.vin}</TableCell>
|
||||
<TableCell align="center">{row.title}</TableCell>
|
||||
<TableCell align="center">{row.description || ""}</TableCell>
|
||||
<TableCell align="center">{row.driver_id}</TableCell>
|
||||
<TableCell align="center">
|
||||
{LocalDateTimeString(row.timestamp)}
|
||||
@@ -172,7 +174,9 @@ const IssueSelectionTable = (props) => {
|
||||
rolesPerProvider={Permissions.FiskerDelete}
|
||||
>
|
||||
<TableCell>
|
||||
<Button onClick={() => handleDelete(row.id)}>Delete</Button>
|
||||
<Link to="#" onClick={() => handleDelete(row.id)}>
|
||||
<DeleteIcon />
|
||||
</Link>
|
||||
</TableCell>
|
||||
</RoleWrap>
|
||||
</TableRow>
|
||||
@@ -181,12 +185,9 @@ const IssueSelectionTable = (props) => {
|
||||
</TableBody>
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
{totalIssues === 0 ? (
|
||||
<td>No issues found</td>
|
||||
) : (
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, 100]}
|
||||
colSpan={7}
|
||||
colSpan={6}
|
||||
count={totalIssues}
|
||||
rowsPerPage={pageSize}
|
||||
page={pageIndex}
|
||||
@@ -197,7 +198,6 @@ const IssueSelectionTable = (props) => {
|
||||
onPageChange={handleChangePageIndex}
|
||||
onRowsPerPageChange={handleChangePageSize}
|
||||
/>
|
||||
)}
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Grid } from "@material-ui/core";
|
||||
import clsx from "clsx";
|
||||
import React, { useEffect } from "react";
|
||||
|
||||
import { LocalDateTimeString } from "../../../../utils/dates";
|
||||
import { logger } from "../../../../services/monitoring";
|
||||
import { useStatusContext } from "../../../Contexts/StatusContext";
|
||||
import { useUserContext } from "../../../Contexts/UserContext";
|
||||
@@ -11,7 +12,6 @@ import {
|
||||
} from "../../../Contexts/IssueContext";
|
||||
import useStyles from "../../../useStyles";
|
||||
|
||||
|
||||
const MainForm = ({ id }) => {
|
||||
const classes = useStyles();
|
||||
const { setMessage } = useStatusContext();
|
||||
@@ -55,7 +55,7 @@ const MainForm = ({ id }) => {
|
||||
<b>Description</b>: {issue.description}
|
||||
</p>
|
||||
<p>
|
||||
<b>timestamp</b>: {issue.timestamp}
|
||||
<b>timestamp</b>: {LocalDateTimeString(issue.timestamp)}
|
||||
</p>
|
||||
{issue.images && issue.images.map((image, index) => (
|
||||
<img key={image.id} src={`data:image/png;base64, ${image.image}`} alt="Issue images" />
|
||||
|
||||
@@ -1,55 +1,15 @@
|
||||
import { Box, Tab, Tabs } from "@material-ui/core";
|
||||
import clsx from "clsx";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useParams } from "react-router";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
import { hasRole } from "../../../utils/roles";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import TabPanel from "../../Controls/TabPanel";
|
||||
import useStyles from "../../useStyles";
|
||||
import IssueDetailsTab from "./DetailsTab";
|
||||
|
||||
|
||||
const tabHashes = ["details", "updates", "filters"];
|
||||
|
||||
const TabViews = [
|
||||
{
|
||||
label: "Details",
|
||||
component: IssueDetailsTab,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
const filterTabs = (data, groups, providers) => {
|
||||
return data.reduce((result, item) => {
|
||||
if (hasRole(groups, item.rolesPerProvider, providers)) {
|
||||
result.push(item);
|
||||
}
|
||||
return result;
|
||||
}, []);
|
||||
};
|
||||
|
||||
const IssueInfo = () => {
|
||||
const { id } = useParams();
|
||||
const classes = useStyles();
|
||||
const { setTitle, setSitePath } = useStatusContext();
|
||||
const { hash } = useLocation();
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
const [tabs, setTabs] = useState([]);
|
||||
const { groups, providers } = useUserContext();
|
||||
|
||||
useEffect(() => {
|
||||
const data = filterTabs(TabViews, groups, providers);
|
||||
setTabs(data);
|
||||
}, [groups, providers]);
|
||||
|
||||
useEffect(() => {
|
||||
const key = hash.replace("#", "");
|
||||
const index = tabHashes.findIndex((element) => element === key);
|
||||
if (index >= 0) setTabIndex(index);
|
||||
}, [hash]);
|
||||
|
||||
useEffect(() => {
|
||||
const title = `Issue ${id} Details`;
|
||||
@@ -66,39 +26,12 @@ const IssueInfo = () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [id]);
|
||||
|
||||
const handleTabChange = (_event, newIndex) => {
|
||||
setTabIndex(newIndex);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Box
|
||||
className={classes.tableToolbar}
|
||||
sx={{ borderBottom: 1, borderColor: "divider" }}
|
||||
>
|
||||
<Tabs
|
||||
value={tabIndex}
|
||||
onChange={handleTabChange}
|
||||
aria-label="issue tabs"
|
||||
indicatorColor="secondary">
|
||||
{tabs.map((item, index) => <Tab key={index} label={item.label} {...tabProps(index)} />)}
|
||||
</Tabs>
|
||||
</Box>
|
||||
{tabs.map((item, index) => (
|
||||
<TabPanel key={index} value={tabIndex} index={index}>
|
||||
<item.component id={id} />
|
||||
</TabPanel>
|
||||
))}
|
||||
<IssueDetailsTab id={id} />
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
function tabProps(index) {
|
||||
return {
|
||||
id: `tab-${index}`,
|
||||
"aria-controls": `tabpanel-${index}`,
|
||||
};
|
||||
}
|
||||
|
||||
export default IssueInfo;
|
||||
|
||||
Reference in New Issue
Block a user