Merge branch 'develop' into release/0.0.3

This commit is contained in:
jwu-fisker
2023-02-08 18:29:57 -08:00
27 changed files with 1019 additions and 493 deletions

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-euprd.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-euprd.fiskerinc.com
REACT_APP_AUTH_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate
REACT_APP_ENV=cec-euprd
REACT_APP_MAGNA_PROVIDER=Magna REACT_APP_MAGNA_PROVIDER=Magna
REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cec-euprd.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cec-euprd.fiskerinc.com/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-prd.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-prd.fiskerinc.com
REACT_APP_AUTH_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate
REACT_APP_ENV=cec-prd
REACT_APP_MAGNA_PROVIDER=Magna REACT_APP_MAGNA_PROVIDER=Magna
REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.cloud.fiskerinc.com
REACT_APP_AUTH_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/certificate
REACT_APP_ENV=dev
REACT_APP_MAGNA_PROVIDER=Fisker-QA REACT_APP_MAGNA_PROVIDER=Fisker-QA
REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c
REACT_APP_OTA_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000 REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000
REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
REACT_APP_CERT_SERVICE_URL=http://localhost/certificate REACT_APP_CERT_SERVICE_URL=http://localhost/certificate
REACT_APP_ENV=local
REACT_APP_MAGNA_PROVIDER=Fisker-QA REACT_APP_MAGNA_PROVIDER=Fisker-QA
REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c
REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cloud.fiskerinc.com
REACT_APP_AUTH_SERVICE_URL=https://gw.cloud.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://gw.cloud.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://gw.cloud.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://gw.cloud.fiskerinc.com/certificate
REACT_APP_ENV=prd
REACT_APP_MAGNA_PROVIDER=Magna REACT_APP_MAGNA_PROVIDER=Magna
REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.cloud.fiskerinc.com
REACT_APP_AUTH_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/certificate
REACT_APP_ENV=stg
REACT_APP_MAGNA_PROVIDER=Magna REACT_APP_MAGNA_PROVIDER=Magna
REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update

View File

@@ -1,6 +1,7 @@
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000 REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000
REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
REACT_APP_CERT_SERVICE_URL=http://localhost/certificate REACT_APP_CERT_SERVICE_URL=http://localhost/certificate
REACT_APP_ENV=local
REACT_APP_MAGNA_PROVIDER=Magna REACT_APP_MAGNA_PROVIDER=Magna
REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update

29
.eslintrc.json Normal file
View File

@@ -0,0 +1,29 @@
{
"env": {
"browser": true,
"es6": true,
"jest": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/jsx-runtime",
"react-app",
"react-app/jest"
],
"overrides": [],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"react"
],
"rules": {
"no-unused-vars": "warn"
},
"ignorePatterns": [
"build/**/*",
"*.test.*"
]
}

View File

@@ -11,3 +11,7 @@ jobs:
uses: Fisker-Inc/github-actions/.github/workflows/blackduck.yml@main uses: Fisker-Inc/github-actions/.github/workflows/blackduck.yml@main
with: with:
project: ota-admin-portal project: ota-admin-portal
secrets:
github-token: ${{ secrets.GITHUB_TOKEN }}
blackduck-url: ${{ secrets.BLACKDUCK_URL }}
blackduck-api-token: ${{ secrets.BLACKDUCK_API_KEY }}

1244
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -68,6 +68,8 @@
"node": "^16.13.0" "node": "^16.13.0"
}, },
"devDependencies": { "devDependencies": {
"eslint": "^8.32.0",
"eslint-plugin-react": "^7.32.1",
"react-test-renderer": "^17.0.2" "react-test-renderer": "^17.0.2"
}, },
"jest": { "jest": {

View File

@@ -1778,6 +1778,13 @@ exports[`App Route /issue-info authenticated 1`] = `
: :
FISKER123 FISKER123
</p> </p>
<p>
<b>
Driver ID
</b>
:
valid-cognito-id-1
</p>
<p> <p>
<b> <b>
VIN VIN
@@ -9959,6 +9966,16 @@ exports[`App Route /vehicle-status authenticated 1`] = `
3 3
</p> </p>
</div> </div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<p>
<b>
DebugMask
</b>
:
</p>
</div>
<div <div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12" class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
> >

View File

@@ -137,6 +137,16 @@ exports[`VehicleDetailsTab Render 1`] = `
3 3
</p> </p>
</div> </div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<p>
<b>
DebugMask
</b>
:
</p>
</div>
<div <div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12" class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
> >

View File

@@ -32,6 +32,9 @@ const MainForm = ({ vin }) => {
providers, providers,
} = useUserContext(); } = useUserContext();
const ENV = process.env.REACT_APP_ENV;
const showDebugMask = (ENV === 'local' || ENV === 'dev' || ENV === 'stg')
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {
@@ -120,6 +123,13 @@ const MainForm = ({ vin }) => {
</p> </p>
</Grid> </Grid>
)} )}
{showDebugMask && (
<Grid item md={12} className={classes.textCenterAlign}>
<p>
<b>DebugMask</b>: {vehicle.debug_mask}
</p>
</Grid>
)}
<Grid item md={12} className={classes.textCenterAlign}> <Grid item md={12} className={classes.textCenterAlign}>
<RoleWrap <RoleWrap
groups={groups} groups={groups}

View File

@@ -80,6 +80,29 @@ exports[`CarUpdatesTab Render 1`] = `
</svg> </svg>
</span> </span>
</th> </th>
<th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col"
>
<span
aria-disabled="false"
class="MuiButtonBase-root MuiTableSortLabel-root"
role="button"
tabindex="0"
>
Username
<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 <th
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter" class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
scope="col" scope="col"

View File

@@ -145,6 +145,16 @@ exports[`DetailsTab Render 1`] = `
3 3
</p> </p>
</div> </div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<p>
<b>
DebugMask
</b>
:
</p>
</div>
<div <div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12" class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
> >

View File

@@ -272,6 +272,16 @@ exports[`CarStatus Render 1`] = `
: :
</p> </p>
</div> </div>
<div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
>
<p>
<b>
DebugMask
</b>
:
</p>
</div>
<div <div
class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12" class="MuiGrid-root makeStyles-textCenterAlign-0 MuiGrid-item MuiGrid-grid-md-12"
> >

View File

@@ -931,6 +931,43 @@ exports[`VehicleUpdate Render 1`] = `
</fieldset> </fieldset>
</div> </div>
</div> </div>
<div
class="MuiFormControl-root MuiTextField-root MuiFormControl-marginNormal MuiFormControl-fullWidth"
>
<label
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-outlined"
data-shrink="true"
for="debug_mask"
id="debug_mask-label"
>
DebugMask
</label>
<div
class="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-fullWidth MuiInputBase-formControl"
>
<input
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="debug_mask"
maxlength="255"
name="debug_mask"
type="text"
value=""
/>
<fieldset
aria-hidden="true"
class="PrivateNotchedOutline-root-0 MuiOutlinedInput-notchedOutline"
>
<legend
class="PrivateNotchedOutline-legendLabelled-0 PrivateNotchedOutline-legendNotched-0"
>
<span>
DebugMask
</span>
</legend>
</fieldset>
</div>
</div>
<button <button
class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-submit-0 MuiButton-containedPrimary MuiButton-fullWidth" class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-submit-0 MuiButton-containedPrimary MuiButton-fullWidth"
tabindex="0" tabindex="0"

View File

@@ -46,6 +46,10 @@ const MainForm = () => {
const [dataLoggerEnabled, setDataLoggerEnabled] = useState(false); const [dataLoggerEnabled, setDataLoggerEnabled] = useState(false);
const [maxMemBufferSize, setMaxMemBufferSize] = useState(0); const [maxMemBufferSize, setMaxMemBufferSize] = useState(0);
const [maxDiskBufferSize, setMaxDiskBufferSize] = useState(0); const [maxDiskBufferSize, setMaxDiskBufferSize] = useState(0);
const debugMaskEl = useRef(null);
const ENV = process.env.REACT_APP_ENV;
const showDebugMask = (ENV === 'local' || ENV === 'dev' || ENV === 'stg')
useEffect(() => { useEffect(() => {
setTitle("Update Vehicle"); setTitle("Update Vehicle");
@@ -93,6 +97,11 @@ const MainForm = () => {
setMaxMemBufferSize(vehicle.canbus.max_mem_buffer_size ?? maxMemBufferSize); setMaxMemBufferSize(vehicle.canbus.max_mem_buffer_size ?? maxMemBufferSize);
setMaxDiskBufferSize(vehicle.canbus.max_disk_buffer_size ?? maxDiskBufferSize); setMaxDiskBufferSize(vehicle.canbus.max_disk_buffer_size ?? maxDiskBufferSize);
} }
if (showDebugMask) {
debugMaskEl.current.value = vehicle.debug_mask ?? ""
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [vehicle]); }, [vehicle]);
@@ -136,7 +145,8 @@ const MainForm = () => {
data_logger_enabled: canbusEnabled ? dataLoggerEnabled : false, data_logger_enabled: canbusEnabled ? dataLoggerEnabled : false,
max_mem_buffer_size: canbusEnabled ? parseInt(maxMemBufferSize) : 0, max_mem_buffer_size: canbusEnabled ? parseInt(maxMemBufferSize) : 0,
max_disk_buffer_size: canbusEnabled && dataLoggerEnabled ? parseInt(maxDiskBufferSize) : 0 max_disk_buffer_size: canbusEnabled && dataLoggerEnabled ? parseInt(maxDiskBufferSize) : 0
} },
debug_mask: debugMaskEl.current.value
}; };
const result = await updateVehicle(vin, formData, token); const result = await updateVehicle(vin, formData, token);
@@ -379,6 +389,24 @@ const MainForm = () => {
required required
fullWidth fullWidth
/> />
{showDebugMask && (
<TextField
id="debug_mask"
name="debug_mask"
label="DebugMask"
InputLabelProps={{
shrink: true
}}
defaultValue=""
variant="outlined"
margin="normal"
inputProps={{
maxLength: "255",
}}
fullWidth
inputRef={debugMaskEl}
/>
)}
<Button <Button
type="submit" type="submit"
disabled={busy} disabled={busy}

View File

@@ -192,6 +192,7 @@ export const CarUpdatesProvider = ({ children }) => {
applyProgressStatuses(result.statuses); applyProgressStatuses(result.statuses);
} catch (e) { } catch (e) {
throw new Error(`Get update progress error. ${e}`);
} finally { } finally {
setBusy(false); setBusy(false);
} }

View File

@@ -30,6 +30,7 @@ let carUpdateLog = {
{ {
id: 90, id: 90,
carupdate_id: 283, carupdate_id: 283,
username: "test username 1",
status: "package_install_complete", status: "package_install_complete",
error_code: 0, error_code: 0,
created: "2021-08-23T17:06:38.410115Z", created: "2021-08-23T17:06:38.410115Z",
@@ -38,6 +39,7 @@ let carUpdateLog = {
{ {
id: 89, id: 89,
carupdate_id: 283, carupdate_id: 283,
username: "test username 2",
status: "package_install_start", status: "package_install_start",
error_code: 0, error_code: 0,
info: "TEST", info: "TEST",
@@ -47,6 +49,7 @@ let carUpdateLog = {
{ {
id: 88, id: 88,
carupdate_id: 284, carupdate_id: 284,
username: "test username 3",
status: "install_approval_await", status: "install_approval_await",
error_code: 0, error_code: 0,
info: "TEST", info: "TEST",

View File

@@ -35,6 +35,10 @@ const tableColumns = [
id: "update_package_id", id: "update_package_id",
label: "Name", label: "Name",
}, },
{
id: "username",
label: "Username",
},
{ {
id: "status", id: "status",
label: "Status", label: "Status",
@@ -168,6 +172,9 @@ const MainForm = ({ vin, token }) => {
{updateName(row)} {updateName(row)}
</Link> </Link>
</TableCell> </TableCell>
<TableCell align="center">
{row.username}
</TableCell>
<TableCell align="center"> <TableCell align="center">
{row.status} {row.status}
{row.progress > -1 && ( {row.progress > -1 && (

View File

@@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import { LocalDateTimeString } from "../../utils/dates"; import { LocalDateTimeString } from "../../utils/dates";
import { ValidateLocationByParam } from "../../utils/locations"
import useStyles from "../useStyles"; import useStyles from "../useStyles";
const keyValueTemplate = (key, value) => ( const keyValueTemplate = (key, value) => (
@@ -83,6 +84,9 @@ const DigitalTwin = (props) => {
<div className={classes.popupSection}> <div className={classes.popupSection}>
<h3>Location</h3> <h3>Location</h3>
{Object.entries(location).map((value) => { {Object.entries(location).map((value) => {
if (ValidateLocationByParam(value[0], value[1]) === false) {
return keyValueTemplate(value[0], "Invalid")
}
if (value[0] === "altitude") { if (value[0] === "altitude") {
return keyValueTemplate(value[0], value[1]); return keyValueTemplate(value[0], value[1]);
} else { } else {

View File

@@ -26,7 +26,9 @@ export default class ErrorBoundary extends Component {
if (this.state.hasError) { if (this.state.hasError) {
try { try {
logger.error(this.state.error.stack); logger.error(this.state.error.stack);
} catch (e) {} } catch (e) {
logger.error(e);
}
if (this.state.error && this.state.error.name === "ChunkLoadError") { if (this.state.error && this.state.error.name === "ChunkLoadError") {
reload(); reload();

View File

@@ -44,6 +44,9 @@ const MainForm = ({ id }) => {
<p> <p>
<b>ID</b>: {id} <b>ID</b>: {id}
</p> </p>
<p>
<b>Driver ID</b>: {issue.driver_id}
</p>
<p> <p>
<b>VIN</b>: {issue.vin} <b>VIN</b>: {issue.vin}
</p> </p>

View File

@@ -7,6 +7,7 @@ import { Button } from "@material-ui/core";
import { useUserContext } from "../Contexts/UserContext"; import { useUserContext } from "../Contexts/UserContext";
import { useVehicleContext, VehicleProvider } from "../Contexts/VehicleContext"; import { useVehicleContext, VehicleProvider } from "../Contexts/VehicleContext";
import { VehiclePopUp } from "./popup"; import { VehiclePopUp } from "./popup";
import { ValidateLocationData } from "../../utils/locations"
import GreenMarkerIcon from "../../assets/green-marker.png"; import GreenMarkerIcon from "../../assets/green-marker.png";
import GrayMarkerIcon from "../../assets/gray-marker.png"; import GrayMarkerIcon from "../../assets/gray-marker.png";
import { logger } from "../../services/monitoring"; import { logger } from "../../services/monitoring";
@@ -44,7 +45,7 @@ const Component = () => {
const retrieveAndStoreLocations = (accessToken) => { const retrieveAndStoreLocations = (accessToken) => {
return getLocations(accessToken) return getLocations(accessToken)
.then((result) => { .then((result) => {
if (result.data != null) { if (result.data != null && ValidateLocationData(result.data) !== false) {
const points = result.data.map((point) => [ const points = result.data.map((point) => [
point.latitude, point.latitude,
point.longitude, point.longitude,

22
src/utils/locations.js Normal file
View File

@@ -0,0 +1,22 @@
export const ValidateLocationData = (location) => {
if (Math.abs(location.latitude) > 90 || Math.abs(location.longitude) > 180) {
return false;
}
if (location.altitude === 1401) {
return false;
}
return true;
}
export const ValidateLocationByParam = (parameter, value) => {
switch (parameter) {
case "latitude":
return Math.abs(value) <= 90;
case "longitude":
return Math.abs(value) <= 180;
case "altitude":
return value !== 1401;
default:
return false;
}
}