From a08d5809a65302ae9356bf84ac47915d8cf1316e Mon Sep 17 00:00:00 2001 From: Paul Adamsen <117673433+pauladamseniii@users.noreply.github.com> Date: Fri, 6 Jan 2023 13:41:22 -0500 Subject: [PATCH 1/4] CEC-2628 - Display IP in digital twin in portal (#251) --- .../Status/__snapshots__/DigitalTwinTab.test.jsx.snap | 11 +++++++++++ src/components/Contexts/__mocks__/VehicleContext.jsx | 11 +++++++---- src/components/DigitalTwin/index.js | 7 ++++++- src/components/VehicleMap/index.jsx | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap b/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap index 607b45f..7340395 100644 --- a/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap +++ b/src/components/Cars/Status/__snapshots__/DigitalTwinTab.test.jsx.snap @@ -130,6 +130,17 @@ exports[`DigitalTwinTab Render 1`] = ` 1000000

+
+

+ + Trex IP + + : + 172.20.0.17:49850 +

+
diff --git a/src/components/Contexts/__mocks__/VehicleContext.jsx b/src/components/Contexts/__mocks__/VehicleContext.jsx index cf6bfba..f31d80c 100644 --- a/src/components/Contexts/__mocks__/VehicleContext.jsx +++ b/src/components/Contexts/__mocks__/VehicleContext.jsx @@ -70,6 +70,7 @@ let vehicleState = { temperature: 26, }, trex_version: "1000000", + ip: "172.20.0.17:49850", updated: "2022-07-26T00:26:38.880381Z", }, }; @@ -146,10 +147,12 @@ export const useVehicleContext = () => ({ command, parameters, })), - getFleets: jest.fn((vin, search,_token) => {return { - data: ["fleet1", "fleet2"], - total: 2, - }}), + getFleets: jest.fn((vin, search, _token) => { + return { + data: ["fleet1", "fleet2"], + total: 2, + } + }), }); export const setBusy = (val) => { diff --git a/src/components/DigitalTwin/index.js b/src/components/DigitalTwin/index.js index 44f0090..8129ce9 100644 --- a/src/components/DigitalTwin/index.js +++ b/src/components/DigitalTwin/index.js @@ -14,7 +14,7 @@ const mapOpenCloseState = (value) => const DigitalTwin = (props) => { const classes = useStyles(); - const { battery, doors, location, trex_version, updated, windows } = props; + const { battery, doors, location, trex_version, ip, updated, windows } = props; return (
@@ -51,6 +51,11 @@ const DigitalTwin = (props) => { {keyValueTemplate("Trex Version", trex_version)}
)} + {ip && ( +
+ {keyValueTemplate("Trex IP", ip)} +
+ )} {updated != null && (
{keyValueTemplate("Updated at", LocalDateTimeString(updated))} diff --git a/src/components/VehicleMap/index.jsx b/src/components/VehicleMap/index.jsx index c685dac..ff61861 100644 --- a/src/components/VehicleMap/index.jsx +++ b/src/components/VehicleMap/index.jsx @@ -193,6 +193,7 @@ const Component = () => { location={carState.location} windows={carState.windows} trex_version={carState.trex_version} + ip={carState.ip} updated={carState.updated} className={classes.popup} onClose={handleClose} From 097d58656af076b9b91f5122d3d614672d656cff Mon Sep 17 00:00:00 2001 From: John Wu <76966357+jwu-fisker@users.noreply.github.com> Date: Fri, 6 Jan 2023 19:06:20 -0800 Subject: [PATCH 2/4] CEC-3453 Update security dll instructions (#252) --- .../Magna/SecurityDLL/__snapshots__/index.test.jsx.snap | 8 +++++--- src/components/Magna/SecurityDLL/result.jsx | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/Magna/SecurityDLL/__snapshots__/index.test.jsx.snap b/src/components/Magna/SecurityDLL/__snapshots__/index.test.jsx.snap index 92bf6cf..74b39c3 100644 --- a/src/components/Magna/SecurityDLL/__snapshots__/index.test.jsx.snap +++ b/src/components/Magna/SecurityDLL/__snapshots__/index.test.jsx.snap @@ -4,11 +4,13 @@ exports[`Magna Security DLL page Security DLL Result page 1`] = `

- Click to download your certificates and security.dll. -
+ Please click the links below to download the certificate.pem, key.pem and the security.dll (either the 32-bit or 64-bit version to match your application). Install all files in the same folder, and then run your application of choice to connect to the Fisker cloud. +

+

- DLL will not work unless certificate.pem and key.pem are placed next to the DLL + Important Note: + Certificates expire in one month from the time they are generated. They have to be re-downloaded again to connect to the Fisker cloud.

  • diff --git a/src/components/Magna/SecurityDLL/result.jsx b/src/components/Magna/SecurityDLL/result.jsx index c81b511..f26ba06 100644 --- a/src/components/Magna/SecurityDLL/result.jsx +++ b/src/components/Magna/SecurityDLL/result.jsx @@ -8,7 +8,8 @@ const CertMimeType = "application/x-pem-file"; const Result = ({ public_key, private_key }) => ( <> -

    Click to download your certificates and security.dll.
    DLL will not work unless certificate.pem and key.pem are placed next to the DLL

    +

    Please click the links below to download the certificate.pem, key.pem and the security.dll (either the 32-bit or 64-bit version to match your application). Install all files in the same folder, and then run your application of choice to connect to the Fisker cloud.

    +

    Important Note: Certificates expire in one month from the time they are generated. They have to be re-downloaded again to connect to the Fisker cloud.

@@ -5798,6 +7648,42 @@ exports[`App Route /tools/sms/send authenticated 1`] = ` /> +
  • + +
    + +
    +
    + + Issues + +
    + +
    +
  • +
  • + +
    + +
    +
    + + Issues + +
    + +
    +
  • +
  • + +
    + +
    +
    + + Issues + +
    + +
    +
  • +
  • + +
    + +
    +
    + + Issues + +
    + +
    +
  • - -
    -
    -

    - Rows per page: -

    -
    - - -
    -

    - 0-0 of 0 -

    -
    - - -
    -
    - +

    + No Car Updates found +

    diff --git a/src/components/Contexts/IssueContext.jsx b/src/components/Contexts/IssueContext.jsx new file mode 100644 index 0000000..570929a --- /dev/null +++ b/src/components/Contexts/IssueContext.jsx @@ -0,0 +1,55 @@ +import React, { useContext, useState, useMemo, useCallback } from "react"; +import api from "../../services/issueAPI"; + +const IssueContext = React.createContext(); + +export const IssueProvider = ({ children }) => { + const [issue, setIssue] = useState({}); + const [issues, setIssues] = useState([]); + const [totalIssues, setTotalIssues] = useState(0); + + const getIssue = useCallback(async (id, token) => { + const result = await api.getIssue(id, token); + if (result.error) throw new Error(`Get issue error. ${result.message}`); + + setIssue(result.data ?? []); + return result; + }, []); + + const getIssues = useCallback(async (search,token) => { + const result = await api.getIssues(search,token); + if (result.error) { + setIssues([]); + throw new Error(`Get issues error. ${result.message}`); + } + setIssues(result.data ?? []); + if (result.total) { + setTotalIssues(result.total); + } + }, []); + + const deleteIssue = useCallback(async (id, token) => { + const result = await api.deleteIssue(id, token); + if (result.error) + throw new Error(`Delete issue error. ${result.message}`); + return result; + }, []); + + const value = useMemo(() => ({ + totalIssues, + issue, + issues, + + deleteIssue, + getIssue, + getIssues, + }), [totalIssues, issue, issues, deleteIssue, getIssue, getIssues]); + + return ( + + {children} + + ); +}; + +export const useIssueContext = () => useContext(IssueContext); diff --git a/src/components/Contexts/IssueContext.test.jsx b/src/components/Contexts/IssueContext.test.jsx new file mode 100644 index 0000000..b529158 --- /dev/null +++ b/src/components/Contexts/IssueContext.test.jsx @@ -0,0 +1,102 @@ +jest.mock("../../services/issueAPI"); + +import { + render, + cleanup, + screen, + fireEvent, + waitFor, +} from "@testing-library/react"; +import { IssueProvider, useIssueContext } from "./IssueContext"; + +const checkIssueResult = (issue) => { + expect(screen.getByTestId("issue").innerHTML).toEqual(issue); +}; + +const checkIssuesResult = (issues) => { + expect(screen.getByTestId("issues").innerHTML).toEqual(issues); +}; + +describe("IssueContext", () => { + describe("getIssues", () => { + beforeEach(() => { + const TestComp = () => { + const { issues, getIssues } = useIssueContext(); + + return ( + <> +
    {JSON.stringify(issues)}
    +
  • +
  • + +
    + +
    +
    + + Issues + +
    + +
    +
  • `; +exports[`SideMenu Magna Authenticated 1`] = ` +
    +
    + +
    +
    +`; + exports[`SideMenu Unauthenticated 1`] = `
    import("../CANFilter/Add")); const CANFilterUpdate = React.lazy(() => import("../CANFilter/Update")); +const IssuesList = React.lazy(() => import("../Issues/List")) +const IssueInfo = React.lazy(() => import("../Issues/Info")) const CarsList = React.lazy(() => import("../Cars/List")); const CarStatus = React.lazy(() => import("../Cars/Status")); const CarUpdateStatus = React.lazy(() => import("../Cars/UpdateStatus")); @@ -175,6 +177,24 @@ const SiteRoutes = () => { rolesPerGroup={Permissions.FiskerRead} providers={providers} /> + } + type={TYPES.PROTECTED} + token={token} + groups={groups} + rolesPerGroup={Permissions.FiskerRead} + providers={providers} + /> + } + type={TYPES.PROTECTED} + token={token} + groups={groups} + rolesPerGroup={Permissions.FiskerRead} + providers={providers} + /> } diff --git a/src/components/SupersetDashboardList/SupersetDashboardList.jsx b/src/components/SupersetDashboardList/SupersetDashboardList.jsx index cce2712..23714d6 100644 --- a/src/components/SupersetDashboardList/SupersetDashboardList.jsx +++ b/src/components/SupersetDashboardList/SupersetDashboardList.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useEffect, useState } from "react"; import { useUserContext } from "../Contexts/UserContext"; import supersetAPI from "../../services/superset"; @@ -29,10 +29,11 @@ const SupersetDashboardList = () => { internalEffect(token) } - + return () => { + setDashboardList([]); + } }, [groups, token]) - return (
      {dashboardList.map((subitem, index) => ( diff --git a/src/services/__mocks__/issueAPI.js b/src/services/__mocks__/issueAPI.js new file mode 100644 index 0000000..2f7459d --- /dev/null +++ b/src/services/__mocks__/issueAPI.js @@ -0,0 +1,11 @@ +const issueAPI = { + getIssues: async (token) => { + return { "data": [{ "id": 18, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 19, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 20, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 21, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 22, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 25, "vin": "1GNGC26RXXJ407648", "title": "Example HMI Problem", "description": "HMI blue screen", "driver_id": "0b6b1930-b20a-4fce-967a-efac6a01fd10", "timestamp": "2022-12-19T22:25:03.848855Z" }, { "id": 26, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 27, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }, { "id": 28, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z" }], "total": 9 } + }, + getIssue: async (token) => { + return { "data": { "id": 18, "vin": "1GNGC26RXXJ407648", "title": "sometitle", "description": "2343242", "driver_id": "valid-cognito-id-1", "timestamp": "2022-12-09T23:16:38.074858Z", "images": [{ "id": 15, "image": "SGVsbG8x", "issue_id": 18 }] } } + } +} + + +export default issueAPI; \ No newline at end of file diff --git a/src/services/__mocks__/superset.js b/src/services/__mocks__/superset.js index cd2af34..9c02e96 100644 --- a/src/services/__mocks__/superset.js +++ b/src/services/__mocks__/superset.js @@ -1,4 +1,7 @@ const SupersetAPI = { + getGuestToken: async () => { + return "" + }, getEmbeddedDashboards: async () => { return [{ title: "test title", @@ -7,7 +10,8 @@ const SupersetAPI = { }, SupersetDashboardID: () => { return "11111100-0000-1111-1111-000000000000" - } + }, + SupersetDashboardURL: () => (null), } export default SupersetAPI \ No newline at end of file diff --git a/src/services/__mocks__/suppliersAPI.js b/src/services/__mocks__/suppliersAPI.js index 7c4f2e0..9b8e4ea 100644 --- a/src/services/__mocks__/suppliersAPI.js +++ b/src/services/__mocks__/suppliersAPI.js @@ -59,6 +59,9 @@ const suppliersAPI = { if (index >= 0) data[index] = supplier; return supplier; }, + getManufactureCert: async () => { + return {public_key:"-----BEGIN CERTIFICATE-----\nTEST\n-----END CERTIFICATE-----",private_key:"-----BEGIN RSA PRIVATE KEY-----\nTEST\n-----END RSA PRIVATE KEY-----","serial_number":"66:c8:45:20:bd:75:04:79:e8:5e:0e:46:5b:5c:1a:21:8b:ea:81:9f","type":"rsa"} + }, }; export default suppliersAPI; diff --git a/src/services/issueAPI.js b/src/services/issueAPI.js new file mode 100644 index 0000000..b329b8f --- /dev/null +++ b/src/services/issueAPI.js @@ -0,0 +1,45 @@ +import { + addQueryParams, errorHandler, fetchRespHandler, getAuthHeaderOptions +} from "../utils/http"; + +const API_ENDPOINT = process.env.REACT_APP_OTA_SERVICE_URL; + +const issuesAPI = { + deleteIssue: async (id, token) => + fetch(`${API_ENDPOINT}/issues/${id}`, { + method: "DELETE", + headers: Object.assign( + { "Content-Type": "application/json" }, + getAuthHeaderOptions(token) + ), + }) + .then(fetchRespHandler) + .catch(errorHandler), + + getIssue: async (id, token) => + fetch(`${API_ENDPOINT}/issues/${id}`, { + method: "GET", + headers: Object.assign( + { "Content-Type": "application/json" }, + getAuthHeaderOptions(token) + ), + }) + .then(fetchRespHandler) + .catch(errorHandler), + + getIssues: async (search, token) => { + const u = addQueryParams(`${API_ENDPOINT}/issues`, search); + return fetch(u, { + method: "GET", + headers: Object.assign( + { "Content-Type": "application/json" }, + getAuthHeaderOptions(token) + ), + }) + .then(fetchRespHandler) + .catch(errorHandler); + }, + +}; + +export default issuesAPI; diff --git a/src/services/superset.js b/src/services/superset.js index 7d827bc..54d6036 100644 --- a/src/services/superset.js +++ b/src/services/superset.js @@ -1,5 +1,5 @@ import { - addQueryParams, getAuthHeaderOptions + addQueryParams, getAuthHeaderOptions } from "../utils/http"; //Added the token we got from the first authorization and set it as the auth token, and that allowed us to hit the request From 8698a3158668961d85eb090401b62db6d64e5297 Mon Sep 17 00:00:00 2001 From: das31 <31259710+das31@users.noreply.github.com> Date: Mon, 9 Jan 2023 15:01:01 -0500 Subject: [PATCH 4/4] Cec 2752 small fix (#253) * first commit * removed comments * remove more comments * fix build issues * fix unused vars * update snapshot * fix test * Fix connect ECONNREFUSED 127.0.0.1:80 * Test Magna side menu * attempt to pass test * fix test * remove comments * fix some code smells * fix test * resolve comments * fix bug * resolved comments * resolve comments * resolve comments * update snapshot * resolved comments * small fix Co-authored-by: jwu-fisker --- src/components/Controls/IssueSelectionTable/index.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Controls/IssueSelectionTable/index.jsx b/src/components/Controls/IssueSelectionTable/index.jsx index 98380ae..3dc8c5f 100644 --- a/src/components/Controls/IssueSelectionTable/index.jsx +++ b/src/components/Controls/IssueSelectionTable/index.jsx @@ -44,7 +44,7 @@ const tableColumns = [ label: "Driver ID", }, { - id: "timestamp", + id: "created_at", label: "Created", }, { @@ -67,7 +67,7 @@ const IssueSelectionTable = (props) => { const [pageSize, setPageSize] = useLocalStorage(PAGE_SIZE, 10); const [pageIndex, setPageIndex] = useState(0); - const [orderBy, setOrderBy] = useState("timestamp"); + const [orderBy, setOrderBy] = useState("created_at"); const [order, setOrder] = useState("asc"); const { getIssues, issues, totalIssues } = useIssueContext(); const { groups, providers } = useUserContext();