Merge branch 'release/0.0.3'

This commit is contained in:
jwu-fisker
2023-01-16 09:48:01 -08:00
24 changed files with 936 additions and 466 deletions

View File

@@ -1,40 +1,13 @@
name: Blackduck
on:
schedule:
# run scans twice a month
- cron: "0 2 1,15 * *"
schedule:
# run scans twice a month
- cron: '0 2 1,15 * *'
jobs:
blackduck:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: "16"
cache: "npm"
- run: npm install
- run: npm run build
# ota-admin-portal
- name: Run Synopsys Detect - ota-admin-portal
uses: synopsys-sig/detect-action@v0.3.2
env:
DETECT_PROJECT_NAME: ota-admin-portal
DETECT_EXCLUDED_DIRECTORIES: node_modules
DETECT_PROJECT_VERSION_NAME: default
DETECT_NPM_INCLUDE_DEV_DEPENDENCIES: "FALSE"
# DETECT_DETECTOR_SEARCH_EXCLUSION_DEFAULTS: "true"
DETECT_DETECTOR_SEARCH_DEPTH: 0
DETECT_DETECTOR_SEARCH_CONTINUE: "true"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
detect-version: 7.9.0
blackduck-url: ${{ secrets.BLACKDUCK_URL }}
blackduck-api-token: ${{ secrets.BLACKDUCK_API_KEY }}
scan-mode: INTELLIGENT
name: Blackduck scan
uses: Fisker-Inc/github-actions/.github/workflows/blackduck.yml@main
with:
project: ota-admin-portal

20
package-lock.json generated
View File

@@ -17,7 +17,7 @@
"@material-ui/icons": "^4.11.3",
"@material-ui/pickers": "^3.3.10",
"@mui/material": "^5.10.14",
"@superset-ui/embedded-sdk": "^0.1.0-alpha.7",
"@superset-ui/embedded-sdk": "^0.1.0-alpha.8",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
@@ -4821,11 +4821,12 @@
}
},
"node_modules/@superset-ui/embedded-sdk": {
"version": "0.1.0-alpha.7",
"resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.7.tgz",
"integrity": "sha512-sBzfSnPvRw15D6A053t4gpKDydHaAjyn88By1Z3Vl3PWZScW6sTHh8n/5A69qMSJVorqFQ3g0IUquTF8sutGEQ==",
"version": "0.1.0-alpha.8",
"resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.8.tgz",
"integrity": "sha512-X07s8uMbvQDEMe5GRyKXhVW5XzPm+yV4KQSo7WifWz7TdqLUT+rjNsL4jZAGAoO0/n0Fj7gFoDpT6bGlSULe5g==",
"dependencies": {
"@superset-ui/switchboard": "^0.18.26-0"
"@superset-ui/switchboard": "^0.18.26-0",
"jwt-decode": "^3.1.2"
}
},
"node_modules/@superset-ui/switchboard": {
@@ -21106,11 +21107,12 @@
}
},
"@superset-ui/embedded-sdk": {
"version": "0.1.0-alpha.7",
"resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.7.tgz",
"integrity": "sha512-sBzfSnPvRw15D6A053t4gpKDydHaAjyn88By1Z3Vl3PWZScW6sTHh8n/5A69qMSJVorqFQ3g0IUquTF8sutGEQ==",
"version": "0.1.0-alpha.8",
"resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.8.tgz",
"integrity": "sha512-X07s8uMbvQDEMe5GRyKXhVW5XzPm+yV4KQSo7WifWz7TdqLUT+rjNsL4jZAGAoO0/n0Fj7gFoDpT6bGlSULe5g==",
"requires": {
"@superset-ui/switchboard": "^0.18.26-0"
"@superset-ui/switchboard": "^0.18.26-0",
"jwt-decode": "^3.1.2"
}
},
"@superset-ui/switchboard": {

View File

@@ -12,7 +12,7 @@
"@material-ui/icons": "^4.11.3",
"@material-ui/pickers": "^3.3.10",
"@mui/material": "^5.10.14",
"@superset-ui/embedded-sdk": "^0.1.0-alpha.7",
"@superset-ui/embedded-sdk": "^0.1.0-alpha.8",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",

View File

@@ -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>
Created
</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"
>
@@ -2641,7 +2557,7 @@ exports[`App Route /issues authenticated 1`] = `
>
<td
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
colspan="7"
colspan="6"
>
<div
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
@@ -2702,7 +2618,7 @@ exports[`App Route /issues authenticated 1`] = `
<p
class="MuiTypography-root MuiTablePagination-caption MuiTypography-body2 MuiTypography-colorInherit"
>
1-NaN of undefined
0-0 of 0
</p>
<div
class="MuiTablePagination-actions"
@@ -2732,8 +2648,9 @@ exports[`App Route /issues authenticated 1`] = `
</button>
<button
aria-label="Next page"
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit"
tabindex="0"
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorInherit Mui-disabled Mui-disabled"
disabled=""
tabindex="-1"
title="Next page"
type="button"
>
@@ -2751,9 +2668,6 @@ exports[`App Route /issues authenticated 1`] = `
/>
</svg>
</span>
<span
class="MuiTouchRipple-root"
/>
</button>
</div>
</div>
@@ -9739,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"
@@ -9849,7 +9767,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
<span
class="MuiTab-wrapper"
>
Remote Commands
ECUs
</span>
<span
class="MuiTouchRipple-root"
@@ -9863,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"
@@ -10088,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>

View File

@@ -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>
);
};

View File

@@ -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(

View 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;

View 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();
});
});

View File

@@ -164,16 +164,16 @@ exports[`CarUpdatesTab Render 1`] = `
<tr
class="MuiTableRow-root MuiTableRow-footer"
>
<p>
<td>
No Car Updates found
</p>
</td>
</tr>
</tfoot>
</table>
<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"

View File

@@ -91,6 +91,41 @@ exports[`DigitalTwinTab Render 1`] = `
closed
</p>
</div>
<div
class="makeStyles-popupSection-0"
>
<h3>
Door Locks
</h3>
<p>
<b>
driver
</b>
:
Closed
</p>
<p>
<b>
all
</b>
:
Locked
</p>
</div>
<div
class="makeStyles-popupSection-0"
>
<h3>
Sunroof
</h3>
<p>
<b>
sunroof
</b>
:
closed
</p>
</div>
<div
class="makeStyles-popupSection-0"
>
@@ -152,6 +187,17 @@ exports[`DigitalTwinTab Render 1`] = `
7/26/2022 12:26:38 AM
</p>
</div>
<div
class="makeStyles-popupSection-0"
>
<p>
<b>
DBC version
</b>
:
d439abd3662dd20099f49dd8f43f7b145202e961caa2b5aba2c6154c8096348b
</p>
</div>
</div>
</div>
</div>

View 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>
`;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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}

View File

@@ -70,6 +70,7 @@ let vehicleState = {
temperature: 26,
},
trex_version: "1000000",
dbc_version: "d439abd3662dd20099f49dd8f43f7b145202e961caa2b5aba2c6154c8096348b",
ip: "172.20.0.17:49850",
updated: "2022-07-26T00:26:38.880381Z",
},

View File

@@ -6,7 +6,7 @@ import {
TableFooter,
TablePagination,
TableRow,
Tooltip,
Tooltip
} from "@material-ui/core";
import CancelIcon from "@material-ui/icons/Cancel";
import React, { useEffect, useState } from "react";
@@ -16,7 +16,7 @@ import { logger } from "../../../services/monitoring";
import { LocalDateTimeString } from "../../../utils/dates";
import {
CarUpdatesProvider,
useCarUpdatesContext,
useCarUpdatesContext
} from "../../Contexts/CarUpdatesContext";
import { useStatusContext } from "../../Contexts/StatusContext";
import { useUserContext } from "../../Contexts/UserContext";
@@ -198,7 +198,7 @@ const MainForm = ({ vin, token }) => {
<TableFooter>
<TableRow>
{totalCarUpdates === 0 ? (
<p>No Car Updates found</p>
<td>No Car Updates found</td>
) : (
<TablePagination
rowsPerPageOptions={[5, 10, 25, 100]}

View 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;

View File

@@ -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 } = 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 ? (
<p>No issues found</p>
) : (
<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>

View File

@@ -1,7 +1,7 @@
import React from "react";
import useStyles from "../useStyles";
import { LocalDateTimeString } from "../../utils/dates";
import useStyles from "../useStyles";
const keyValueTemplate = (key, value) => (
<p key={key}>
@@ -14,7 +14,7 @@ const mapOpenCloseState = (value) =>
const DigitalTwin = (props) => {
const classes = useStyles();
const { battery, doors, location, trex_version, ip, updated, windows } = props;
const { battery, doors, location, trex_version, ip, updated, windows, misc_windows, sunroof, dbc_version, door_locks } = props;
return (
<div>
@@ -28,10 +28,55 @@ const DigitalTwin = (props) => {
{Object.entries(doors).map(mapOpenCloseState)}
</div>
)}
{door_locks != null && (
<div className={classes.popupSection}>
<h3>Door Locks</h3>
{Object.entries(door_locks).map((value) => {
if (value[0] === "driver") {
return keyValueTemplate(value[0], value[1] ? "Open" : "Closed");
} else {
return keyValueTemplate(value[0], value[1] ? "Unlocked" : "Locked");
}
})}
</div>
)}
{windows != null && (
<div className={classes.popupSection}>
<h3>Windows</h3>
{Object.entries(windows).map(mapOpenCloseState)}
{Object.entries(windows).map((value) => {
if (value[1] === 0) {
return keyValueTemplate(value[0], "closed");
} else {
const percentOpen = Math.min(value[1], 100);
return keyValueTemplate(value[0], `${percentOpen}% open`);
}
})}
</div>
)}
{misc_windows != null && (
<div className={classes.popupSection}>
<h3>Misc Windows</h3>
{Object.entries(misc_windows).map((value) => {
if (value[1] === 0) {
return keyValueTemplate(value[0], "closed");
} else {
const percentOpen = Math.min(value[1], 100);
return keyValueTemplate(value[0], `${percentOpen}% open`);
}
})}
</div>
)}
{sunroof != null && (
<div className={classes.popupSection}>
<h3>Sunroof</h3>
{Object.entries(sunroof).map((value) => {
if (value[1] === 0) {
return keyValueTemplate(value[0], "closed");
} else {
const percentOpen = Math.min(value[1], 100);
return keyValueTemplate(value[0], `${percentOpen}% open`);
}
})}
</div>
)}
{location != null && (
@@ -61,6 +106,11 @@ const DigitalTwin = (props) => {
{keyValueTemplate("Updated at", LocalDateTimeString(updated))}
</div>
)}
{dbc_version != null && (
<div className={classes.popupSection}>
{keyValueTemplate("DBC version", dbc_version)}
</div>
)}
</div>
);
};

View File

@@ -3,15 +3,14 @@ import clsx from "clsx";
import React, { useEffect } from "react";
import { logger } from "../../../../services/monitoring";
import { LocalDateTimeString } from "../../../../utils/dates";
import {
IssueProvider, useIssueContext
} from "../../../Contexts/IssueContext";
import { useStatusContext } from "../../../Contexts/StatusContext";
import { useUserContext } from "../../../Contexts/UserContext";
import {
useIssueContext,
IssueProvider
} from "../../../Contexts/IssueContext";
import useStyles from "../../../useStyles";
const MainForm = ({ id }) => {
const classes = useStyles();
const { setMessage } = useStatusContext();
@@ -55,7 +54,7 @@ const MainForm = ({ id }) => {
<b>Description</b>: {issue.description}
</p>
<p>
<b>timestamp</b>: {issue.timestamp}
<b>Created</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" />

View File

@@ -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;

View File

@@ -1,15 +1,15 @@
import React, { useEffect, useState } from "react";
import useStyles from "../useStyles";
import L from "leaflet";
import { MapContainer, TileLayer, Marker, Popup, useMap } from "react-leaflet";
import { Button } from "@material-ui/core";
import L from "leaflet";
import React, { useEffect, useState } from "react";
import { MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
import useStyles from "../useStyles";
import GrayMarkerIcon from "../../assets/gray-marker.png";
import GreenMarkerIcon from "../../assets/green-marker.png";
import { logger } from "../../services/monitoring";
import { useUserContext } from "../Contexts/UserContext";
import { useVehicleContext, VehicleProvider } from "../Contexts/VehicleContext";
import { VehiclePopUp } from "./popup";
import GreenMarkerIcon from "../../assets/green-marker.png";
import GrayMarkerIcon from "../../assets/gray-marker.png";
import { logger } from "../../services/monitoring";
const Component = () => {
const classes = useStyles();
@@ -185,16 +185,7 @@ const Component = () => {
{carState ? (
<VehiclePopUp
key={carState.vin}
vin={carState.vin}
online={carState.online}
onlineHMI={carState.online_hmi}
battery={carState.battery}
doors={carState.doors}
location={carState.location}
windows={carState.windows}
trex_version={carState.trex_version}
ip={carState.ip}
updated={carState.updated}
{...carState}
className={classes.popup}
onClose={handleClose}
/>

View File

@@ -116,7 +116,26 @@ const vehiclesAPI = {
},
getCANSignals: async (vin, vehicle) => {
return signals;
}
},
getVersionLog: async (vin) => ({
"data": [
{
"id": 1,
"vin": "${vin}",
"version_source": "TREX",
"version": "0.9.56",
"created_at": "2023-01-13T02:11:33.327214Z"
},
{
"id": 2,
"vin": "${vin}",
"version_source": "DBC",
"version": "386c18977a1be3cda60c953e5902c680dbe82b89523f2527e80cd9db863db991",
"created_at": "2023-01-13T02:11:33.330932Z"
}
],
"total": 2
})
};
export default vehiclesAPI;

View File

@@ -1,5 +1,5 @@
import {
addQueryParams, errorHandler, fetchRespHandler, getAuthHeaderOptions
addQueryParams, errorHandler, fetchRespHandler, getAuthHeaderOptions
} from "../utils/http";
const API_ENDPOINT = process.env.REACT_APP_OTA_SERVICE_URL;
@@ -172,6 +172,19 @@ const vehiclesAPI = {
})
.then(fetchRespHandler)
.catch(errorHandler),
getVersionLog: async ({vin, ...search}, token) => {
const u = addQueryParams(`${API_ENDPOINT}/vehicle/${vin}/version/logs`, search);
return fetch(u, {
method: "GET",
headers: Object.assign(
{ "Content-Type": "application/json" },
getAuthHeaderOptions(token)
),
})
.then(fetchRespHandler)
.catch(errorHandler)
},
};
export default vehiclesAPI;