Merge branch 'develop'
This commit is contained in:
2
.env.dev
2
.env.dev
@@ -2,4 +2,4 @@ REACT_APP_CERT_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/certificate
|
||||
REACT_APP_AUTH_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/compute_auth
|
||||
REACT_APP_UPLOAD_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update
|
||||
REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.cloud.fiskerinc.com
|
||||
REACT_APP_SUPERSET_URL=http://superset-dev.fiskercloud.internal
|
||||
REACT_APP_SUPERSET_URL=https://dev-superset.cloud.fiskerinc.com
|
||||
|
||||
@@ -2,4 +2,4 @@ REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
|
||||
REACT_APP_CERT_SERVICE_URL=http://localhost/certificate
|
||||
REACT_APP_UPLOAD_SERVICE_URL=http://localhost/ota_update
|
||||
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000
|
||||
REACT_APP_SUPERSET_URL=http://superset-dev.fiskercloud.internal
|
||||
REACT_APP_SUPERSET_URL=https://dev-superset.cloud.fiskerinc.com
|
||||
|
||||
2
.env.prd
2
.env.prd
@@ -2,4 +2,4 @@ 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_UPLOAD_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update
|
||||
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cloud.fiskerinc.com
|
||||
REACT_APP_SUPERSET_URL=http://superset.fiskercloud.internal
|
||||
REACT_APP_SUPERSET_URL=https://superset.cloud.fiskerinc.com
|
||||
|
||||
2
.env.stg
2
.env.stg
@@ -2,4 +2,4 @@ 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_UPLOAD_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update
|
||||
REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.cloud.fiskerinc.com
|
||||
REACT_APP_SUPERSET_URL=http://superset-stg.fiskercloud.internal
|
||||
REACT_APP_SUPERSET_URL=https://stg-superset.cloud.fiskerinc.com
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
|
||||
REACT_APP_UPLOAD_SERVICE_URL=http://localhost/ota_update
|
||||
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000
|
||||
REACT_APP_SUPERSET_URL=http://superset-dev.fisker.internal
|
||||
REACT_APP_SUPERSET_URL=https://dev-superset.cloud.fiskerinc.com
|
||||
REACT_APP_CERT_SERVICE_URL=http://localhost/certificate
|
||||
|
||||
8
.github/workflows/test.yml
vendored
8
.github/workflows/test.yml
vendored
@@ -1,6 +1,10 @@
|
||||
name: Node.js CI
|
||||
|
||||
on: [pull_request]
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -14,7 +18,7 @@ jobs:
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14"
|
||||
node-version: "16"
|
||||
cache: "npm"
|
||||
- run: npm install
|
||||
- run: npm run build --if-present
|
||||
|
||||
@@ -6,7 +6,7 @@ Front-end web application for administrating services
|
||||
|
||||
Running locally
|
||||
|
||||
1. Install Node 14
|
||||
1. Install Node 16
|
||||
2. Run `npm install`
|
||||
3. Copy .env.template to .env and edit the service urls for authentication and api services
|
||||
4. Run `./run.sh` from the terminal
|
||||
|
||||
17453
package-lock.json
generated
17453
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -213,7 +213,7 @@ exports[`App Route / authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -711,7 +711,7 @@ exports[`App Route /home authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -1245,7 +1245,7 @@ exports[`App Route /package-create authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -2742,7 +2742,7 @@ exports[`App Route /package-deploy authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -3614,7 +3614,7 @@ exports[`App Route /package-status authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -4222,7 +4222,7 @@ exports[`App Route /packages authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -5032,7 +5032,7 @@ exports[`App Route /page-not-found authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -5453,7 +5453,7 @@ exports[`App Route /tools/certificates/add authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -6112,7 +6112,7 @@ exports[`App Route /vehicle-add authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -7246,7 +7246,7 @@ exports[`App Route /vehicle-status authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -7911,7 +7911,7 @@ exports[`App Route /vehicles authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-0000 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
|
||||
@@ -1,66 +1,32 @@
|
||||
import React from "react";
|
||||
import { useParams } from "react-router";
|
||||
import clsx from "clsx";
|
||||
import { Button, Grid, Typography } from "@material-ui/core";
|
||||
import { Typography } from "@material-ui/core";
|
||||
|
||||
import CarECUsTable from "../../Controls/CarECUsTable";
|
||||
import CarUpdatesTable from "../../Controls/CarUpdatesTable";
|
||||
import { logger } from "../../../services/monitoring";
|
||||
import {
|
||||
VehicleProvider,
|
||||
useVehicleContext,
|
||||
} from "../../Contexts/VehicleContext";
|
||||
import { VehicleProvider } from "../../Contexts/VehicleContext";
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||
import useStyles from "../../useStyles";
|
||||
|
||||
|
||||
const MainForm = () => {
|
||||
const { vin } = useParams();
|
||||
const classes = useStyles();
|
||||
const { setMessage } = useStatusContext();
|
||||
const { busy, sendCommand } = useVehicleContext();
|
||||
const {
|
||||
token: {
|
||||
idToken: { jwtToken: token },
|
||||
},
|
||||
} = useUserContext();
|
||||
const updateHandler = async (e) => {
|
||||
try {
|
||||
await sendCommand([vin], "ecu", "", token);
|
||||
setMessage(`Sent command to ${vin}`);
|
||||
} catch (error) {
|
||||
setMessage(error.message);
|
||||
logger.error(error.stack);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6">Car Updates</Typography>
|
||||
<CarUpdatesTable vin={vin} token={token} classes={classes} />
|
||||
<Grid container className={classes.root} spacing={2}>
|
||||
<Grid item md={4} className={classes.textJustifyAlign}></Grid>
|
||||
<Grid item md={4} className={classes.textCenterAlign}>
|
||||
<Typography variant="h6" className={classes.labelInline}>
|
||||
Car ECUs
|
||||
</Typography>
|
||||
</Grid>
|
||||
<Grid item md={4} className={classes.textRightAlign}>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={busy}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={clsx(classes.formControl, classes.textField)}
|
||||
onClick={updateHandler}
|
||||
>
|
||||
{busy ? "Sending..." : "Refresh"}
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Typography variant="h6" className={classes.labelInline}>
|
||||
Car ECUs
|
||||
</Typography>
|
||||
<CarECUsTable vin={vin} token={token} classes={classes} />
|
||||
</div >
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -278,40 +278,11 @@ exports[`CarUpdatesTab Render 1`] = `
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-root-14 MuiGrid-container MuiGrid-spacing-xs-2"
|
||||
<h6
|
||||
class="MuiTypography-root makeStyles-labelInline-9 MuiTypography-h6"
|
||||
>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-textJustifyAlign-47 MuiGrid-item MuiGrid-grid-md-4"
|
||||
/>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-textCenterAlign-48 MuiGrid-item MuiGrid-grid-md-4"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root makeStyles-labelInline-9 MuiTypography-h6"
|
||||
>
|
||||
Car ECUs
|
||||
</h6>
|
||||
</div>
|
||||
<div
|
||||
class="MuiGrid-root makeStyles-textRightAlign-49 MuiGrid-item MuiGrid-grid-md-4"
|
||||
>
|
||||
<button
|
||||
class="MuiButtonBase-root MuiButton-root MuiButton-contained makeStyles-formControl-7 makeStyles-textField-29 MuiButton-containedPrimary"
|
||||
tabindex="0"
|
||||
type="submit"
|
||||
>
|
||||
<span
|
||||
class="MuiButton-label"
|
||||
>
|
||||
Refresh
|
||||
</span>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
Car ECUs
|
||||
</h6>
|
||||
<div
|
||||
class="makeStyles-paper-3 makeStyles-tableSize-53"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
jest.mock("../../services/CANFiltersAPI")
|
||||
jest.mock("../../services/CANFiltersAPI");
|
||||
|
||||
import {
|
||||
render,
|
||||
@@ -83,9 +83,7 @@ describe("CANFiltersContext", () => {
|
||||
<button data-testid="addFilterNoCANID" onClick={() => add({})} />
|
||||
<button
|
||||
data-testid="addFilter"
|
||||
onClick={() =>
|
||||
add({ can_id: "123", interval: 1000 })
|
||||
}
|
||||
onClick={() => add({ can_id: "123", interval: 1000 })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -149,13 +147,17 @@ describe("CANFiltersContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="updateFilterNull" onClick={() => update(null)} />
|
||||
<button data-testid="updateFilterNoCANID" onClick={() => update({})} />
|
||||
<button
|
||||
data-testid="updateFilterNull"
|
||||
onClick={() => update(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="updateFilterNoCANID"
|
||||
onClick={() => update({})}
|
||||
/>
|
||||
<button
|
||||
data-testid="updateFilter"
|
||||
onClick={() =>
|
||||
update({ can_id: "123", interval: 1000 })
|
||||
}
|
||||
onClick={() => update({ can_id: "123", interval: 1000 })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -182,7 +184,10 @@ describe("CANFiltersContext", () => {
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("busy").innerHTML).toEqual("false")
|
||||
);
|
||||
checkBaseResults("Cannot read property 'can_id' of null", "false");
|
||||
checkBaseResults(
|
||||
"Cannot read properties of null (reading 'can_id')",
|
||||
"false"
|
||||
);
|
||||
});
|
||||
|
||||
it("updateFilterNoCANID", async () => {
|
||||
@@ -219,14 +224,15 @@ describe("CANFiltersContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="deleteFilterNull" onClick={() => deleteF(null)} />
|
||||
<button data-testid="deleteFilterNonexistent" onClick={() => deleteF(-1)} />
|
||||
<button
|
||||
data-testid="deleteFilter"
|
||||
onClick={() =>
|
||||
deleteF(123)
|
||||
}
|
||||
data-testid="deleteFilterNull"
|
||||
onClick={() => deleteF(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFilterNonexistent"
|
||||
onClick={() => deleteF(-1)}
|
||||
/>
|
||||
<button data-testid="deleteFilter" onClick={() => deleteF(123)} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -276,14 +282,14 @@ describe("CANFiltersContext", () => {
|
||||
const expectedFiltersData = [
|
||||
{
|
||||
can_id: "123",
|
||||
interval: 1000
|
||||
interval: 1000,
|
||||
},
|
||||
{
|
||||
can_id: "456",
|
||||
interval: 0
|
||||
interval: 0,
|
||||
},
|
||||
{
|
||||
can_id: "789-1000",
|
||||
interval: 5
|
||||
interval: 5,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
jest.mock("../../services/fleetsAPI")
|
||||
jest.mock("../../services/fleetsAPI");
|
||||
|
||||
import {
|
||||
render,
|
||||
@@ -23,12 +23,12 @@ const checkFleetsResults = (error, busy, fleets) => {
|
||||
const checkFleetVehicleResults = (error, busy, vehicles) => {
|
||||
checkBaseResults(error, busy);
|
||||
expect(screen.getByTestId("fleet-vehicles").innerHTML).toEqual(vehicles);
|
||||
}
|
||||
};
|
||||
|
||||
const checkFleetCANFilterResults = (error, busy, filters) => {
|
||||
checkBaseResults(error, busy);
|
||||
expect(screen.getByTestId("fleet-filters").innerHTML).toEqual(filters);
|
||||
}
|
||||
};
|
||||
|
||||
const checkBaseResults = (error, busy) => {
|
||||
expect(screen.getByTestId("error").innerHTML).toEqual(error);
|
||||
@@ -46,10 +46,7 @@ describe("FleetContext", () => {
|
||||
<div data-testid="error">{error}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<div data-testid="fleets">{JSON.stringify(fleets)}</div>
|
||||
<button
|
||||
data-testid="getFleets"
|
||||
onClick={() => getFleets()}
|
||||
/>
|
||||
<button data-testid="getFleets" onClick={() => getFleets()} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -140,7 +137,11 @@ describe("FleetContext", () => {
|
||||
<button
|
||||
data-testid="addFleet"
|
||||
onClick={() =>
|
||||
add({ name: "EU-WEST", log_level: "warn", canbus: { enabled: false } })
|
||||
add({
|
||||
name: "EU-WEST",
|
||||
log_level: "warn",
|
||||
canbus: { enabled: false },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
@@ -205,12 +206,22 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="updateFleetNull" onClick={() => update(null)} />
|
||||
<button data-testid="updateFleetNoName" onClick={() => update({})} />
|
||||
<button
|
||||
data-testid="updateFleetNull"
|
||||
onClick={() => update(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="updateFleetNoName"
|
||||
onClick={() => update({})}
|
||||
/>
|
||||
<button
|
||||
data-testid="updateFleet"
|
||||
onClick={() =>
|
||||
update({ name: "EU-WEST", log_level: "warn", canbus: { enabled: false } })
|
||||
update({
|
||||
name: "EU-WEST",
|
||||
log_level: "warn",
|
||||
canbus: { enabled: false },
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
@@ -275,13 +286,17 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="deleteFleetNull" onClick={() => deleteF(null)} />
|
||||
<button data-testid="deleteFleetNonexistent" onClick={() => deleteF("INVALID")} />
|
||||
<button
|
||||
data-testid="deleteFleetNull"
|
||||
onClick={() => deleteF(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleetNonexistent"
|
||||
onClick={() => deleteF("INVALID")}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleet"
|
||||
onClick={() =>
|
||||
deleteF("US-WEST")
|
||||
}
|
||||
onClick={() => deleteF("US-WEST")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -331,13 +346,16 @@ describe("FleetContext", () => {
|
||||
describe("getFleetVehicles", () => {
|
||||
beforeEach(() => {
|
||||
const TestComp = () => {
|
||||
const { busy, error, fleetVehicles, getFleetVehicles } = useFleetContext();
|
||||
const { busy, error, fleetVehicles, getFleetVehicles } =
|
||||
useFleetContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-testid="error">{error}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<div data-testid="fleet-vehicles">{JSON.stringify(fleetVehicles)}</div>
|
||||
<div data-testid="fleet-vehicles">
|
||||
{JSON.stringify(fleetVehicles)}
|
||||
</div>
|
||||
<button
|
||||
data-testid="getFleetVehicles"
|
||||
onClick={() => getFleetVehicles("US-WEST")}
|
||||
@@ -365,7 +383,11 @@ describe("FleetContext", () => {
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("fleet-vehicles").innerHTML).not.toBe("[]")
|
||||
);
|
||||
checkFleetVehicleResults("", "false", JSON.stringify(expectedFleetVehiclesData));
|
||||
checkFleetVehicleResults(
|
||||
"",
|
||||
"false",
|
||||
JSON.stringify(expectedFleetVehiclesData)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -386,13 +408,17 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="addFleetVehicleNull" onClick={() => add(null)} />
|
||||
<button data-testid="addFleetVehicleNoName" onClick={() => add({})} />
|
||||
<button
|
||||
data-testid="addFleetVehicleNull"
|
||||
onClick={() => add(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="addFleetVehicleNoName"
|
||||
onClick={() => add({})}
|
||||
/>
|
||||
<button
|
||||
data-testid="addFleetVehicle"
|
||||
onClick={() =>
|
||||
add("US-TEST", { vin: "TESTVIN1234567890" })
|
||||
}
|
||||
onClick={() => add("US-TEST", { vin: "TESTVIN1234567890" })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -456,13 +482,17 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="deleteFleetVehicleNull" onClick={() => deleteFV("US-WEST", null)} />
|
||||
<button data-testid="deleteFleetVehicleInvalid" onClick={() => deleteFV("US-WEST", "INVALID")} />
|
||||
<button
|
||||
data-testid="deleteFleetVehicleNull"
|
||||
onClick={() => deleteFV("US-WEST", null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleetVehicleInvalid"
|
||||
onClick={() => deleteFV("US-WEST", "INVALID")}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleetVehicle"
|
||||
onClick={() =>
|
||||
deleteFV("US-WEST", { vin: "USWESTVIN12345678" })
|
||||
}
|
||||
onClick={() => deleteFV("US-WEST", { vin: "USWESTVIN12345678" })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -489,7 +519,10 @@ describe("FleetContext", () => {
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("busy").innerHTML).toEqual("false")
|
||||
);
|
||||
checkBaseResults("Cannot read property 'vin' of null", "false");
|
||||
checkBaseResults(
|
||||
"Cannot read properties of null (reading 'vin')",
|
||||
"false"
|
||||
);
|
||||
});
|
||||
|
||||
it("deleteFleetVehicleNonexistent", async () => {
|
||||
@@ -512,13 +545,16 @@ describe("FleetContext", () => {
|
||||
describe("getFleetCANFilters", () => {
|
||||
beforeEach(() => {
|
||||
const TestComp = () => {
|
||||
const { busy, error, fleetCANFilters, getFleetCANFilters } = useFleetContext();
|
||||
const { busy, error, fleetCANFilters, getFleetCANFilters } =
|
||||
useFleetContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<div data-testid="error">{error}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<div data-testid="fleet-filters">{JSON.stringify(fleetCANFilters)}</div>
|
||||
<div data-testid="fleet-filters">
|
||||
{JSON.stringify(fleetCANFilters)}
|
||||
</div>
|
||||
<button
|
||||
data-testid="getFleetCANFilters"
|
||||
onClick={() => getFleetCANFilters("US-TEST")}
|
||||
@@ -546,7 +582,11 @@ describe("FleetContext", () => {
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("fleet-filters").innerHTML).not.toBe("[]")
|
||||
);
|
||||
checkFleetCANFilterResults("", "false", JSON.stringify(expectedFleetCANFiltersData));
|
||||
checkFleetCANFilterResults(
|
||||
"",
|
||||
"false",
|
||||
JSON.stringify(expectedFleetCANFiltersData)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -567,13 +607,17 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="addFleetCANFilterNull" onClick={() => add(null)} />
|
||||
<button data-testid="addFleetCANFilterNoName" onClick={() => add({})} />
|
||||
<button
|
||||
data-testid="addFleetCANFilterNull"
|
||||
onClick={() => add(null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="addFleetCANFilterNoName"
|
||||
onClick={() => add({})}
|
||||
/>
|
||||
<button
|
||||
data-testid="addFleetCANFilter"
|
||||
onClick={() =>
|
||||
add("US-TEST", { can_id: "111", interval: 222 })
|
||||
}
|
||||
onClick={() => add("US-TEST", { can_id: "111", interval: 222 })}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -637,13 +681,17 @@ describe("FleetContext", () => {
|
||||
<>
|
||||
<div data-testid="error">{message}</div>
|
||||
<div data-testid="busy">{busy.toString()}</div>
|
||||
<button data-testid="deleteFleetCANFilterNull" onClick={() => deleteFF("US-WEST", null)} />
|
||||
<button data-testid="deleteFleetCANFilterInvalid" onClick={() => deleteFF("US-WEST", "INVALID")} />
|
||||
<button
|
||||
data-testid="deleteFleetCANFilterNull"
|
||||
onClick={() => deleteFF("US-WEST", null)}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleetCANFilterInvalid"
|
||||
onClick={() => deleteFF("US-WEST", "INVALID")}
|
||||
/>
|
||||
<button
|
||||
data-testid="deleteFleetCANFilter"
|
||||
onClick={() =>
|
||||
deleteFF("US-WEST", "123-456")
|
||||
}
|
||||
onClick={() => deleteFF("US-WEST", "123-456")}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -694,59 +742,80 @@ describe("FleetContext", () => {
|
||||
const expectedFilters = [
|
||||
{
|
||||
can_id: "123-456",
|
||||
interval: 789
|
||||
interval: 789,
|
||||
},
|
||||
{
|
||||
can_id: "1",
|
||||
interval: 1000
|
||||
interval: 1000,
|
||||
},
|
||||
{
|
||||
can_id: "1000",
|
||||
interval: 1
|
||||
}
|
||||
]
|
||||
interval: 1,
|
||||
},
|
||||
];
|
||||
|
||||
const expectedFleetData = {
|
||||
name: "US-WEST",
|
||||
log_level: "info",
|
||||
canbus: { enabled: true, data_logger_enabled: true, max_mem_buffer_size: 1, max_disk_buffer_size: 2, filters: expectedFilters },
|
||||
vehicles: ["USWESTVIN12345678", "USWESTVIN12345679", "USWESTVIN12345670"]
|
||||
}
|
||||
canbus: {
|
||||
enabled: true,
|
||||
data_logger_enabled: true,
|
||||
max_mem_buffer_size: 1,
|
||||
max_disk_buffer_size: 2,
|
||||
filters: expectedFilters,
|
||||
},
|
||||
vehicles: ["USWESTVIN12345678", "USWESTVIN12345679", "USWESTVIN12345670"],
|
||||
};
|
||||
|
||||
const expectedFleetsData = [
|
||||
{
|
||||
name: "US-WEST",
|
||||
log_level: "info",
|
||||
canbus: { enabled: true, data_logger_enabled: true, max_mem_buffer_size: 1, max_disk_buffer_size: 2, filters: expectedFilters },
|
||||
vehicles: ["USWESTVIN12345678", "USWESTVIN12345679", "USWESTVIN12345670"]
|
||||
canbus: {
|
||||
enabled: true,
|
||||
data_logger_enabled: true,
|
||||
max_mem_buffer_size: 1,
|
||||
max_disk_buffer_size: 2,
|
||||
filters: expectedFilters,
|
||||
},
|
||||
vehicles: ["USWESTVIN12345678", "USWESTVIN12345679", "USWESTVIN12345670"],
|
||||
},
|
||||
{
|
||||
name: "US-CENTRAL",
|
||||
log_level: "warn",
|
||||
canbus: { enabled: false, data_logger_enabled: false, max_mem_buffer_size: 0, max_disk_buffer_size: 0 },
|
||||
vehicles: ["USCENTVIN12345678", "USCENTVIN12345679", "USCENTVIN12345670"]
|
||||
canbus: {
|
||||
enabled: false,
|
||||
data_logger_enabled: false,
|
||||
max_mem_buffer_size: 0,
|
||||
max_disk_buffer_size: 0,
|
||||
},
|
||||
vehicles: ["USCENTVIN12345678", "USCENTVIN12345679", "USCENTVIN12345670"],
|
||||
},
|
||||
{
|
||||
name: "US-EAST",
|
||||
log_level: "error",
|
||||
canbus: { enabled: true },
|
||||
vehicles: ["USEASTVIN12345678", "USEASTVIN12345679", "USEASTVIN12345670"]
|
||||
vehicles: ["USEASTVIN12345678", "USEASTVIN12345679", "USEASTVIN12345670"],
|
||||
},
|
||||
];
|
||||
|
||||
const expectedFleetVehiclesData = ["USWESTVIN12345678", "USWESTVIN12345679", "USWESTVIN12345670"];
|
||||
const expectedFleetVehiclesData = [
|
||||
"USWESTVIN12345678",
|
||||
"USWESTVIN12345679",
|
||||
"USWESTVIN12345670",
|
||||
];
|
||||
|
||||
const expectedFleetCANFiltersData = [
|
||||
{
|
||||
can_id: "123-456",
|
||||
interval: 789
|
||||
interval: 789,
|
||||
},
|
||||
{
|
||||
can_id: "1",
|
||||
interval: 1000
|
||||
interval: 1000,
|
||||
},
|
||||
{
|
||||
can_id: "1000",
|
||||
interval: 1
|
||||
}
|
||||
interval: 1,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -127,12 +127,12 @@ export const VehicleProvider = ({ children }) => {
|
||||
const result = await api.getVehicle(vin, token);
|
||||
if (result.error) throw new Error(`Get vehicle error. ${result.message}`);
|
||||
|
||||
setVehicle(result);
|
||||
setVehicle(result ?? []);
|
||||
return result;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getVehicles = async (search, token) => {
|
||||
try {
|
||||
@@ -143,7 +143,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
throw new Error(`Get vehicles error. ${result.message}`);
|
||||
}
|
||||
await addConnections(result.data, token);
|
||||
setVehicles(result.data);
|
||||
setVehicles(result.data ?? []);
|
||||
if (result.total) {
|
||||
setTotalVehicles(result.total);
|
||||
}
|
||||
@@ -188,7 +188,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteVehicle = async (vin, token) => {
|
||||
try {
|
||||
@@ -202,7 +202,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<VehicleContext.Provider
|
||||
@@ -224,7 +224,7 @@ export const VehicleProvider = ({ children }) => {
|
||||
getVehicle,
|
||||
getVehicles,
|
||||
sendCommand,
|
||||
updateVehicle
|
||||
updateVehicle,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@@ -246,5 +246,4 @@ const validateVIN = (vin) => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const useVehicleContext = () => useContext(VehicleContext);
|
||||
|
||||
@@ -48,7 +48,15 @@ const tableColumns = [
|
||||
];
|
||||
|
||||
const CarSelectionTable = (props) => {
|
||||
const { token, classes, search, multiSelect, selected, onSelect, onSelectAll } = props;
|
||||
const {
|
||||
token,
|
||||
classes,
|
||||
search,
|
||||
multiSelect,
|
||||
selected,
|
||||
onSelect,
|
||||
onSelectAll,
|
||||
} = props;
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [orderBy, setOrderBy] = useState("vin");
|
||||
@@ -126,19 +134,23 @@ const CarSelectionTable = (props) => {
|
||||
multiSelect={multiSelect}
|
||||
onSelectAll={handleSelectAll}
|
||||
selectCount={selected ? selected.length : 0}
|
||||
rowCount={vehicles.length}
|
||||
rowCount={vehicles ? vehicles.length : 0}
|
||||
/>
|
||||
<TableBody>
|
||||
{vehicles.map((row) => {
|
||||
const isSelected = selected ? selected.indexOf(row.vin) !== -1 : false;
|
||||
const isSelected = selected
|
||||
? selected.indexOf(row.vin) !== -1
|
||||
: false;
|
||||
return (
|
||||
<TableRow key={row.vin}>
|
||||
{multiSelect && (<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onChange={(event) => handleSelect(event, row.vin)}
|
||||
/>
|
||||
</TableCell>)}
|
||||
{multiSelect && (
|
||||
<TableCell padding="checkbox">
|
||||
<Checkbox
|
||||
checked={isSelected}
|
||||
onChange={(event) => handleSelect(event, row.vin)}
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell align="center">
|
||||
<ConnectedIcon
|
||||
connected={row.connected}
|
||||
|
||||
@@ -8,22 +8,26 @@ import s from "./Statuses";
|
||||
|
||||
const AwaitStatus = -1;
|
||||
const ErrorStatus = -100;
|
||||
const CompleteStatus = 100;
|
||||
|
||||
const PHASES = [
|
||||
{
|
||||
label: "Pending",
|
||||
events: [s.Pending],
|
||||
progress: () => 100,
|
||||
progress: () => CompleteStatus,
|
||||
},
|
||||
{
|
||||
label: "Received",
|
||||
events: [s.ManifestAccepted, s.ManifestReceived, s.ManifestRejected],
|
||||
progress: () => 100,
|
||||
progress: (msg) => {
|
||||
if (msg === s.ManifestRejected) return ErrorStatus;
|
||||
return CompleteStatus;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Precondition",
|
||||
events: [s.PreconditionAwait, s.PreconditionSuceeded],
|
||||
progress: () => 100,
|
||||
progress: () => CompleteStatus,
|
||||
},
|
||||
{
|
||||
label: "Download",
|
||||
@@ -55,14 +59,14 @@ const PHASES = [
|
||||
],
|
||||
progress: (msg, progress) => {
|
||||
if (msg === s.InstallFailed) return ErrorStatus;
|
||||
if (msg === s.PackageInstallCompleted) return 100;
|
||||
if (msg === s.PackageInstallCompleted) return CompleteStatus;
|
||||
return progress;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Updated",
|
||||
events: [s.ManifestSucceeded],
|
||||
progress: (_msg, _progress) => 100,
|
||||
progress: (_msg, _progress) => CompleteStatus,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -84,7 +88,7 @@ const Progress = ({ value, classes }) => {
|
||||
|
||||
const getProgress = (index, phase, progress) => {
|
||||
if (index === phase) return progress;
|
||||
if (index < phase) return 100;
|
||||
if (index < phase) return CompleteStatus;
|
||||
return -1;
|
||||
};
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-52 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="http://superset-dev.fiskercloud.internal/r/3"
|
||||
href="https://dev-superset.cloud.fiskerinc.com/r/3"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
|
||||
@@ -246,16 +246,6 @@ const useStyles = makeStyles((theme) => ({
|
||||
menuExternalLink: {
|
||||
textDecoration: "inherit",
|
||||
color: "inherit",
|
||||
"&:link": {
|
||||
textDecoration: "inherit",
|
||||
color: "inherit",
|
||||
cursor: "auto",
|
||||
},
|
||||
"&:visited": {
|
||||
textDecoration: "inherit",
|
||||
color: "inherit",
|
||||
cursor: "auto",
|
||||
},
|
||||
},
|
||||
tableSize: { height: 700, width: "100%" },
|
||||
whiteBackground: { backgroundColor: "White" },
|
||||
|
||||
@@ -1,49 +1,58 @@
|
||||
import {
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
} from "../utils/http";
|
||||
|
||||
const API_ENDPOINT = process.env.REACT_APP_UPLOAD_SERVICE_URL;
|
||||
|
||||
const canFiltersAPI = {
|
||||
addFilter: async (vin, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter`, {
|
||||
method: "POST",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter)
|
||||
}).then(fetchRespHandler),
|
||||
addFilter: async (vin, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter`, {
|
||||
method: "POST",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getFilters: async (vin, search, token) =>
|
||||
fetch(addQueryParams(`${API_ENDPOINT}/vehicle/${vin}/filters`, search), {
|
||||
method: "GET",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
getFilters: async (vin, search, token) =>
|
||||
fetch(addQueryParams(`${API_ENDPOINT}/vehicle/${vin}/filters`, search), {
|
||||
method: "GET",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
updateFilter: async (vin, canID, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter/${canID}`, {
|
||||
method: "PUT",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter)
|
||||
}).then(fetchRespHandler),
|
||||
updateFilter: async (vin, canID, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter/${canID}`, {
|
||||
method: "PUT",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteFilter: async (vin, canID, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter/${canID}`, {
|
||||
method: "DELETE",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
deleteFilter: async (vin, canID, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}/filter/${canID}`, {
|
||||
method: "DELETE",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default canFiltersAPI;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { fetchRespHandler } from "../utils/http";
|
||||
import { errorHandler, fetchRespHandler } from "../utils/http";
|
||||
|
||||
const AUTH_URL = process.env.REACT_APP_AUTH_SERVICE_URL;
|
||||
const CALLBACK_URL = process.env.REACT_APP_AUTH_CALLBACK_URL;
|
||||
@@ -16,7 +16,9 @@ const auth = {
|
||||
code,
|
||||
redirect: CALLBACK_URL,
|
||||
}),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
verify: (idToken) =>
|
||||
fetch(`${AUTH_URL}/verify`, {
|
||||
@@ -25,7 +27,9 @@ const auth = {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ token: idToken }),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
refresh: (refreshToken) =>
|
||||
fetch(`${AUTH_URL}/refresh`, {
|
||||
@@ -34,7 +38,9 @@ const auth = {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ refresh_token: refreshToken }),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default auth;
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { getAuthHeaderOptions, fetchRespHandler } from "../utils/http";
|
||||
import {
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
} from "../utils/http";
|
||||
|
||||
const API_ENDPOINT = process.env.REACT_APP_CERT_SERVICE_URL;
|
||||
|
||||
@@ -11,7 +15,9 @@ const certificatesAPI = {
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(data),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default certificatesAPI;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
@@ -14,8 +15,10 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(fleet)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(fleet),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getFleet: async (name, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}`, {
|
||||
@@ -23,8 +26,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getFleets: async (search, token) =>
|
||||
fetch(addQueryParams(`${API_ENDPOINT}/fleets`, search), {
|
||||
@@ -33,7 +38,9 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
updateFleet: async (name, fleet, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}`, {
|
||||
@@ -42,8 +49,10 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(fleet)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(fleet),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteFleet: async (name, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}`, {
|
||||
@@ -51,8 +60,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getFleetVehicles: async (name, search, token) =>
|
||||
fetch(addQueryParams(`${API_ENDPOINT}/fleet/${name}/vehicles`, search), {
|
||||
@@ -60,8 +71,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
addFleetVehicle: async (name, vehicle, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}/vehicle`, {
|
||||
@@ -70,8 +83,10 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(vehicle)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(vehicle),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteFleetVehicle: async (name, vehicle, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}/vehicle/${vehicle.vin}`, {
|
||||
@@ -79,8 +94,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getFleetCANFilters: async (name, search, token) =>
|
||||
fetch(addQueryParams(`${API_ENDPOINT}/fleet/${name}/filters`, search), {
|
||||
@@ -88,8 +105,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
addFleetCANFilter: async (name, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}/filter`, {
|
||||
@@ -98,8 +117,10 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(filter),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
updateFleetCANFilter: async (name, can_id, filter, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}/filter/${can_id}`, {
|
||||
@@ -108,8 +129,10 @@ const fleetsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(filter)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(filter),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteFleetCANFilter: async (name, can_id, token) =>
|
||||
fetch(`${API_ENDPOINT}/fleet/${name}/filter/${can_id}`, {
|
||||
@@ -117,8 +140,10 @@ const fleetsAPI = {
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
)
|
||||
}).then(fetchRespHandler),
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default fleetsAPI;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
@@ -14,7 +15,22 @@ const manifestsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getManifest: async (id, token) => {
|
||||
const u = addQueryParams(`${API_ENDPOINT}/manifest`, { id });
|
||||
return fetch(u, {
|
||||
method: "GET",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getManifest: async (id, token) => {
|
||||
const u = addQueryParams(`${API_ENDPOINT}/manifest`, { id });
|
||||
@@ -35,7 +51,9 @@ const manifestsAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
createManifest: async (data, token) =>
|
||||
@@ -46,7 +64,9 @@ const manifestsAPI = {
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(data),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
createManifestECU: async (data, token) =>
|
||||
fetch(`${API_ENDPOINT}/manifestecu`, {
|
||||
@@ -56,7 +76,9 @@ const manifestsAPI = {
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(data),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default manifestsAPI;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
@@ -15,7 +16,9 @@ const updatesAPI = {
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(data),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getCarUpdateLog: async (query, token) => {
|
||||
const u = addQueryParams(`${API_ENDPOINT}/carupdateslog`, query);
|
||||
@@ -25,7 +28,9 @@ const updatesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getCarUpdateProgress: async (carupdateids, token) => {
|
||||
@@ -36,7 +41,9 @@ const updatesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getCarUpdates: async (search, token) => {
|
||||
@@ -47,7 +54,9 @@ const updatesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getVINUpdates: async (vin, token) => {
|
||||
@@ -58,7 +67,9 @@ const updatesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
errorHandler,
|
||||
getAuthHeaderOptions,
|
||||
fetchRespHandler,
|
||||
addQueryParams,
|
||||
@@ -15,7 +16,20 @@ const vehiclesAPI = {
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(vehicle),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteVehicle: async (vin, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
|
||||
method: "DELETE",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
deleteVehicle: async (vin, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
|
||||
@@ -34,7 +48,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getECUs: async (search, token) => {
|
||||
@@ -45,7 +61,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getModels: async (token) =>
|
||||
@@ -55,7 +73,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getLocations: async (token) =>
|
||||
fetch(`${API_ENDPOINT}/carslocations`, {
|
||||
@@ -64,7 +84,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getState: async (token, vin) =>
|
||||
fetch(`${API_ENDPOINT}/carstate?vin=${vin}`, {
|
||||
@@ -73,7 +95,20 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getVehicle: async (vin, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
|
||||
method: "GET",
|
||||
headers: Object.assign(
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
getVehicle: async (vin, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
|
||||
@@ -92,7 +127,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler);
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler);
|
||||
},
|
||||
|
||||
getYears: async (token) =>
|
||||
@@ -102,7 +139,9 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
sendCommand: async (vins, command, parameters, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehiclecommand`, {
|
||||
@@ -116,7 +155,9 @@ const vehiclesAPI = {
|
||||
command,
|
||||
parameters,
|
||||
}),
|
||||
}).then(fetchRespHandler),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
|
||||
updateVehicle: async (vin, vehicle, token) =>
|
||||
fetch(`${API_ENDPOINT}/vehicle/${vin}`, {
|
||||
@@ -125,8 +166,10 @@ const vehiclesAPI = {
|
||||
{ "Content-Type": "application/json" },
|
||||
getAuthHeaderOptions(token)
|
||||
),
|
||||
body: JSON.stringify(vehicle)
|
||||
}).then(fetchRespHandler),
|
||||
body: JSON.stringify(vehicle),
|
||||
})
|
||||
.then(fetchRespHandler)
|
||||
.catch(errorHandler),
|
||||
};
|
||||
|
||||
export default vehiclesAPI;
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { logger } from "../services/monitoring";
|
||||
|
||||
export const getAuthHeaderOptions = (token) => ({
|
||||
"Authorization": `Bearer ${token}`,
|
||||
});
|
||||
export const addQueryParams = (url, params) => {
|
||||
if (!params) return url;
|
||||
|
||||
const u = new URL(url);
|
||||
|
||||
Object.keys(params).forEach((key) => u.searchParams.append(key, params[key]));
|
||||
|
||||
return u.toString();
|
||||
};
|
||||
|
||||
export const errorHandler = (e) => {
|
||||
logger.error(e.stack);
|
||||
return {
|
||||
error: e.name,
|
||||
message: e.message,
|
||||
};
|
||||
};
|
||||
|
||||
export const fetchRespHandler = (response) => {
|
||||
if (response.ok) return response.json();
|
||||
|
||||
return response.text()
|
||||
return response
|
||||
.text()
|
||||
.then((text) => {
|
||||
if (response.status >= 500) logger.error(text);
|
||||
return JSON.parse(text);
|
||||
@@ -18,15 +33,9 @@ export const fetchRespHandler = (response) => {
|
||||
error: response.statusText,
|
||||
message: `${response.status} ${response.statusText}`,
|
||||
};
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const addQueryParams = (url, params) => {
|
||||
if (!params) return url;
|
||||
|
||||
const u = new URL(url);
|
||||
|
||||
Object.keys(params).forEach(key => u.searchParams.append(key, params[key]))
|
||||
|
||||
return u.toString();
|
||||
}
|
||||
export const getAuthHeaderOptions = (token) => ({
|
||||
Authorization: `Bearer ${token}`,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user