Merge development (#86)
This commit is contained in:
@@ -4,7 +4,7 @@ jest.mock("../Contexts/UserContext");
|
|||||||
jest.mock("../Contexts/ManifestsContext");
|
jest.mock("../Contexts/ManifestsContext");
|
||||||
jest.mock("../Contexts/CarUpdatesContext");
|
jest.mock("../Contexts/CarUpdatesContext");
|
||||||
jest.mock("../../services/monitoring");
|
jest.mock("../../services/monitoring");
|
||||||
jest.mock("../../services/grafana");
|
jest.mock("../../services/grafanaAPI");
|
||||||
|
|
||||||
import { render, screen, cleanup, waitFor, waitForElementToBeRemoved } from "@testing-library/react";
|
import { render, screen, cleanup, waitFor, waitForElementToBeRemoved } from "@testing-library/react";
|
||||||
import { setToken } from "../Contexts/UserContext";
|
import { setToken } from "../Contexts/UserContext";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -24,9 +24,9 @@ const MainForm = () => {
|
|||||||
},
|
},
|
||||||
} = useUserContext();
|
} = useUserContext();
|
||||||
|
|
||||||
const handleSearch = (search) => {
|
const handleSearch = (query) => {
|
||||||
setSelected([]);
|
setSelected([]);
|
||||||
setSearch(search);
|
setSearch(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectAll = (cars) => {
|
const handleSelectAll = (cars) => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Button, Grid, Typography } from "@material-ui/core";
|
|||||||
|
|
||||||
import CarECUsTable from "../../Controls/CarECUsTable";
|
import CarECUsTable from "../../Controls/CarECUsTable";
|
||||||
import CarUpdatesTable from "../../Controls/CarUpdatesTable";
|
import CarUpdatesTable from "../../Controls/CarUpdatesTable";
|
||||||
|
import { logger } from "../../../services/monitoring";
|
||||||
import {
|
import {
|
||||||
VehicleProvider,
|
VehicleProvider,
|
||||||
useVehicleContext,
|
useVehicleContext,
|
||||||
@@ -12,7 +13,6 @@ import {
|
|||||||
import { useUserContext } from "../../Contexts/UserContext";
|
import { useUserContext } from "../../Contexts/UserContext";
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
import useStyles from "../../useStyles";
|
import useStyles from "../../useStyles";
|
||||||
import { logger } from "../../../services/monitoring";
|
|
||||||
|
|
||||||
const MainForm = () => {
|
const MainForm = () => {
|
||||||
const { vin } = useParams();
|
const { vin } = useParams();
|
||||||
@@ -28,9 +28,9 @@ const MainForm = () => {
|
|||||||
try {
|
try {
|
||||||
await sendCommand([vin], "ecu", "", token);
|
await sendCommand([vin], "ecu", "", token);
|
||||||
setMessage(`Sent command to ${vin}`);
|
setMessage(`Sent command to ${vin}`);
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
setMessage(e.message);
|
setMessage(error.message);
|
||||||
logger.error(e.stack);
|
logger.error(error.stack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ const MainForm = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||||
<Typography variant="h6">Car Updates</Typography>
|
<Typography variant="h6">Car Updates</Typography>
|
||||||
<CarUpdatesTable vin={vin} token={token} />
|
<CarUpdatesTable vin={vin} token={token} classes={classes} />
|
||||||
<Grid container className={classes.root} spacing={2}>
|
<Grid container className={classes.root} spacing={2}>
|
||||||
<Grid item md={4} className={classes.textJustifyAlign}></Grid>
|
<Grid item md={4} className={classes.textJustifyAlign}></Grid>
|
||||||
<Grid item md={4} className={classes.textCenterAlign}>
|
<Grid item md={4} className={classes.textCenterAlign}>
|
||||||
@@ -73,7 +73,7 @@ const MainForm = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<CarECUsTable vin={vin} token={token} />
|
<CarECUsTable vin={vin} token={token} classes={classes} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useState } from "react";
|
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { Grid, TextField } from "@material-ui/core";
|
import { Grid, TextField } from "@material-ui/core";
|
||||||
|
|
||||||
@@ -126,7 +125,7 @@ const MainForm = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Grid item md={12}>
|
<Grid item md={12}>
|
||||||
<CarUpdateStatusProgress status={status} />
|
<CarUpdateStatusProgress status={status} classes={classes} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={12}>
|
<Grid item md={12}>
|
||||||
<CarUpdateStatusTable carupdateid={carupdateid} token={token} />
|
<CarUpdateStatusTable carupdateid={carupdateid} token={token} />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
|
|
||||||
import api from "../../services/updates";
|
import api from "../../services/updatesAPI";
|
||||||
import { validateStatusMessage } from "../../utils/statusMessage";
|
import { validateStatusMessage } from "../../utils/statusMessage";
|
||||||
|
|
||||||
const FINAL_UPDATE_STATES = ["package_install_complete"];
|
const FINAL_UPDATE_STATES = ["package_install_complete"];
|
||||||
@@ -122,9 +122,9 @@ export const CarUpdatesProvider = ({ children }) => {
|
|||||||
let items = JSON.parse(JSON.stringify(carUpdates));
|
let items = JSON.parse(JSON.stringify(carUpdates));
|
||||||
|
|
||||||
statuses.forEach((status) => {
|
statuses.forEach((status) => {
|
||||||
let item = items.find((item) => status.car_update_id === item.id);
|
let x = items.find((item) => status.car_update_id === item.id);
|
||||||
if (!item || status.car_update_id === 0) return;
|
if (!x || status.car_update_id === 0) return;
|
||||||
applyProgressStatus(item, status);
|
applyProgressStatus(x, status);
|
||||||
});
|
});
|
||||||
|
|
||||||
setCarUpdates(items);
|
setCarUpdates(items);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
|
|
||||||
import api from "../../services/manifests";
|
import api from "../../services/manifestsAPI";
|
||||||
import { uploadFile, getCancelToken } from "../../services/uploadFile";
|
import { uploadFile, getCancelToken } from "../../services/uploadFile";
|
||||||
|
|
||||||
const ManifestsContext = React.createContext();
|
const ManifestsContext = React.createContext();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import auth from "../../services/auth";
|
import auth from "../../services/auth";
|
||||||
import getTimerWorker from "../../services/timer";
|
import getTimerWorker from "../../services/getTimerWorker";
|
||||||
import { parsePayload } from "../../utils/jwt";
|
import { parsePayload } from "../../utils/jwt";
|
||||||
import { getGroups } from "../../utils/roles";
|
import { getGroups } from "../../utils/roles";
|
||||||
|
|
||||||
@@ -37,8 +37,7 @@ export const UserProvider = ({ children }) => {
|
|||||||
|
|
||||||
const refreshTokens = async () => {
|
const refreshTokens = async () => {
|
||||||
if (!token || !token.refreshToken || !token.refreshToken.token) return null;
|
if (!token || !token.refreshToken || !token.refreshToken.token) return null;
|
||||||
const result = await refresh(token.refreshToken.token);
|
return refresh(token.refreshToken.token);
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const startSessionTimer = () => {
|
const startSessionTimer = () => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
jest.mock("../../services/auth");
|
jest.mock("../../services/auth");
|
||||||
jest.mock("../../services/timer");
|
jest.mock("../../services/getTimerWorker");
|
||||||
|
|
||||||
import {
|
import {
|
||||||
render,
|
render,
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from "@testing-library/react";
|
} from "@testing-library/react";
|
||||||
import { UserProvider, useUserContext } from "../Contexts/UserContext";
|
import { UserProvider, useUserContext } from "../Contexts/UserContext";
|
||||||
import auth from "../../services/auth";
|
import auth from "../../services/auth";
|
||||||
import getTimerWorker from "../../services/timer";
|
import getTimerWorker from "../../services/getTimerWorker";
|
||||||
import { TEST_AUTH_OBJECT, TEST_EXPECTED_GROUPS } from "../../utils/testing";
|
import { TEST_AUTH_OBJECT, TEST_EXPECTED_GROUPS } from "../../utils/testing";
|
||||||
|
|
||||||
const INVALID_TOKEN_RESPONSE = {
|
const INVALID_TOKEN_RESPONSE = {
|
||||||
@@ -125,14 +125,8 @@ describe("UseContext", () => {
|
|||||||
describe("Signout", () => {
|
describe("Signout", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const TestComp = () => {
|
const TestComp = () => {
|
||||||
const {
|
const { signIn, signOut, error, token, groups, fetching } =
|
||||||
signIn,
|
useUserContext();
|
||||||
signOut,
|
|
||||||
error,
|
|
||||||
token,
|
|
||||||
groups,
|
|
||||||
fetching,
|
|
||||||
} = useUserContext();
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div data-testid="error">{error}</div>
|
<div data-testid="error">{error}</div>
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { LocalDateTimeString } from "../../../utils/dates";
|
|||||||
import TableHeaderSortable from "../../Table/HeaderSortable";
|
import TableHeaderSortable from "../../Table/HeaderSortable";
|
||||||
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
import { useVehicleContext } from "../../Contexts/VehicleContext";
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
import useStyles from "../../useStyles";
|
|
||||||
import { logger } from "../../../services/monitoring";
|
import { logger } from "../../../services/monitoring";
|
||||||
|
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
@@ -59,10 +58,9 @@ const tableColumns = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const CarECUsTable = ({ vin, token }) => {
|
const CarECUsTable = ({ vin, token, classes }) => {
|
||||||
const [ecus, setECUs] = useState([]);
|
const [ecus, setECUs] = useState([]);
|
||||||
const [total, setTotal] = useState(0);
|
const [total, setTotal] = useState(0);
|
||||||
const classes = useStyles();
|
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [pageSize, setPageSize] = useState(10);
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
const [orderBy, setOrderBy] = useState("ecu");
|
const [orderBy, setOrderBy] = useState("ecu");
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import { CheckCircle, RadioButtonUnchecked, Error } from "@material-ui/icons";
|
import { CheckCircle, RadioButtonUnchecked, Error } from "@material-ui/icons";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import CircularProgress from "../CircularProgress";
|
import CircularProgress from "../CircularProgress";
|
||||||
import useStyles from "../../useStyles";
|
|
||||||
|
|
||||||
const Progress = ({ value }) => {
|
|
||||||
const classes = useStyles();
|
|
||||||
|
|
||||||
|
const Progress = ({ value, classes }) => {
|
||||||
if (value === 100)
|
if (value === 100)
|
||||||
return (
|
return (
|
||||||
<CheckCircle
|
<CheckCircle
|
||||||
@@ -24,14 +21,13 @@ const Progress = ({ value }) => {
|
|||||||
return <RadioButtonUnchecked className={classes.progressIcon} />;
|
return <RadioButtonUnchecked className={classes.progressIcon} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CarUpdateStatus = ({ status }) => {
|
const CarUpdateStatus = ({ status, classes }) => {
|
||||||
const classes = useStyles();
|
|
||||||
const [received, setReceived] = useState(-1);
|
|
||||||
const [approval, setApproval] = useState(-1);
|
const [approval, setApproval] = useState(-1);
|
||||||
const [precondition, setPrecondition] = useState(-1);
|
const [cleanup, setCleanup] = useState(-1);
|
||||||
const [download, setDownload] = useState(-1);
|
const [download, setDownload] = useState(-1);
|
||||||
const [install, setInstall] = useState(-1);
|
const [install, setInstall] = useState(-1);
|
||||||
const [cleanup, setCleanup] = useState(-1);
|
const [precondition, setPrecondition] = useState(-1);
|
||||||
|
const [received, setReceived] = useState(-1);
|
||||||
const [updated, setUpdated] = useState(-1);
|
const [updated, setUpdated] = useState(-1);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -39,10 +35,15 @@ const CarUpdateStatus = ({ status }) => {
|
|||||||
if (!status) return;
|
if (!status) return;
|
||||||
// update previous steps
|
// update previous steps
|
||||||
switch (status.msg) {
|
switch (status.msg) {
|
||||||
case "cleanup_success":
|
case "manifest_succeeded":
|
||||||
setUpdated(100);
|
setUpdated(100);
|
||||||
|
case "cleanup_success":
|
||||||
|
setCleanup(100);
|
||||||
case "package_install_complete":
|
case "package_install_complete":
|
||||||
setInstall(100);
|
setInstall(100);
|
||||||
|
case "install_approval_received":
|
||||||
|
setApproval(100);
|
||||||
|
case "install_approval_await":
|
||||||
case "install_start":
|
case "install_start":
|
||||||
case "installing":
|
case "installing":
|
||||||
case "install_complete":
|
case "install_complete":
|
||||||
@@ -53,10 +54,10 @@ const CarUpdateStatus = ({ status }) => {
|
|||||||
case "downloading":
|
case "downloading":
|
||||||
case "download_complete":
|
case "download_complete":
|
||||||
case "download_error":
|
case "download_error":
|
||||||
case "install_approval_received":
|
case "package_download_start":
|
||||||
setApproval(100);
|
|
||||||
case "requirements_succeeded":
|
case "requirements_succeeded":
|
||||||
setPrecondition(100);
|
setPrecondition(100);
|
||||||
|
case "manifest_accepted":
|
||||||
case "manifest_received":
|
case "manifest_received":
|
||||||
setReceived(100);
|
setReceived(100);
|
||||||
}
|
}
|
||||||
@@ -90,35 +91,35 @@ const CarUpdateStatus = ({ status }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={100} />
|
<Progress value={100} classes={classes} />
|
||||||
<Typography>Pending</Typography>
|
<Typography>Pending</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={received} />
|
<Progress value={received} classes={classes} />
|
||||||
<Typography>Recieved</Typography>
|
<Typography>Recieved</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={approval} />
|
<Progress value={precondition} classes={classes} />
|
||||||
<Typography>Approved</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes.textCenterAlign}>
|
|
||||||
<Progress value={precondition} />
|
|
||||||
<Typography>Precondition</Typography>
|
<Typography>Precondition</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={download} />
|
<Progress value={download} classes={classes} />
|
||||||
<Typography>Download</Typography>
|
<Typography>Download</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={install} />
|
<Progress value={approval} classes={classes} />
|
||||||
|
<Typography>Approved</Typography>
|
||||||
|
</div>
|
||||||
|
<div className={classes.textCenterAlign}>
|
||||||
|
<Progress value={install} classes={classes} />
|
||||||
<Typography>Install</Typography>
|
<Typography>Install</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={cleanup} />
|
<Progress value={cleanup} classes={classes} />
|
||||||
<Typography>Clean up</Typography>
|
<Typography>Clean up</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.textCenterAlign}>
|
<div className={classes.textCenterAlign}>
|
||||||
<Progress value={updated} />
|
<Progress value={updated} classes={classes} />
|
||||||
<Typography>Updated</Typography>
|
<Typography>Updated</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -49,16 +49,16 @@ const SendCommand = ({ vins }) => {
|
|||||||
} else {
|
} else {
|
||||||
setMessage(`Sent command to ${vins.length} cars`);
|
setMessage(`Sent command to ${vins.length} cars`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (error) {
|
||||||
setMessage(e.message);
|
setMessage(error.message);
|
||||||
logger.error(e.stack);
|
logger.error(error.stack);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getParameters = (command) => {
|
const getParameters = (cmd) => {
|
||||||
for (let i = 0, len = commands.length; i < len; i += 1) {
|
for (let i = 0, len = commands.length; i < len; i += 1) {
|
||||||
const item = commands[i];
|
const item = commands[i];
|
||||||
if (item.value === command) {
|
if (item.value === cmd) {
|
||||||
if (!item.parameters) {
|
if (!item.parameters) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { TableCell, TableRow, TextField } from "@material-ui/core";
|
import { TableCell, TableRow, TextField } from "@material-ui/core";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
const DataDisplay = ({ data, option, onDelete }) => {
|
const DataDisplay = ({ data, option, onDelete }) => {
|
||||||
const [text, setText] = useState(data[option.field]);
|
const [text, setText] = useState(data[option.field]);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { Button, Grid, Link, Paper } from "@material-ui/core";
|
import { Button, Grid, Link, Paper } from "@material-ui/core";
|
||||||
import CreateIcon from "@material-ui/icons/Create";
|
import CreateIcon from "@material-ui/icons/Create";
|
||||||
|
|
||||||
import api from "../../../services/grafana";
|
import api from "../../../services/grafanaAPI";
|
||||||
import { useStatusContext } from "../../Contexts/StatusContext";
|
import { useStatusContext } from "../../Contexts/StatusContext";
|
||||||
import useStyles from "../../useStyles";
|
import useStyles from "../../useStyles";
|
||||||
import ResponsiveIFrame from "../../Controls/ResponsiveIFrame";
|
import ResponsiveIFrame from "../../Controls/ResponsiveIFrame";
|
||||||
|
|||||||
@@ -64,15 +64,7 @@ const MenuItem = ({ item, children }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExpandableSideMenuItem = ({ item }) => {
|
const ExpandableSideMenuItem = ({ item }) => (
|
||||||
/*
|
|
||||||
const [expanded, setExpanded] = useState(true);
|
|
||||||
const clickHandler = (e) => {
|
|
||||||
setExpanded(!expanded);
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
<>
|
||||||
<span>
|
<span>
|
||||||
<MenuItem item={item}></MenuItem>
|
<MenuItem item={item}></MenuItem>
|
||||||
@@ -84,7 +76,6 @@ const ExpandableSideMenuItem = ({ item }) => {
|
|||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
|
||||||
|
|
||||||
const SideMenu = () => {
|
const SideMenu = () => {
|
||||||
const { groups } = useUserContext();
|
const { groups } = useUserContext();
|
||||||
|
|||||||
@@ -21,13 +21,13 @@ const renderMenu = async () => {
|
|||||||
describe("SideMenu", () => {
|
describe("SideMenu", () => {
|
||||||
it("Unauthenticated", async () => {
|
it("Unauthenticated", async () => {
|
||||||
setToken(null);
|
setToken(null);
|
||||||
const container = await renderMenu(null);
|
const container = await renderMenu();
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Authenticated", async () => {
|
it("Authenticated", async () => {
|
||||||
setToken(TEST_AUTH_OBJECT);
|
setToken(TEST_AUTH_OBJECT);
|
||||||
const container = await renderMenu(TEST_AUTH_OBJECT);
|
const container = await renderMenu();
|
||||||
expect(container).toMatchSnapshot();
|
expect(container).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ exports[`SideMenu Authenticated 1`] = `
|
|||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-53 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root makeStyles-menuExternalLink-54 MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||||
href="https://grafana.fiskerdps.com"
|
href="https://grafana.fiskerdps.com"
|
||||||
rel="noopener"
|
rel="noopener"
|
||||||
role="button"
|
role="button"
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ const MainForm = () => {
|
|||||||
const [redirect, setRedirect] = useState("");
|
const [redirect, setRedirect] = useState("");
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
const handleSearch = (search) => {
|
const handleSearch = (query) => {
|
||||||
setSelected([]);
|
setSelected([]);
|
||||||
setSearch(search);
|
setSearch(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectAll = (cars) => {
|
const handleSelectAll = (cars) => {
|
||||||
|
|||||||
@@ -122,8 +122,8 @@ const MainForm = () => {
|
|||||||
setPageIndex(0);
|
setPageIndex(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearch = (search) => {
|
const handleSearch = (query) => {
|
||||||
setSearch(search);
|
setSearch(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDelete = async (manifest_id) => {
|
const onDelete = async (manifest_id) => {
|
||||||
@@ -161,7 +161,7 @@ const MainForm = () => {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actions.length === 0) return "No actions";
|
if (actions.length === 0) return ["No actions"];
|
||||||
|
|
||||||
return actions.map((action) => {
|
return actions.map((action) => {
|
||||||
if (action.link != null) {
|
if (action.link != null) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
exports[`Sign In Form Should render 1`] = `
|
exports[`Sign In Form Should render 1`] = `
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
class="makeStyles-paper-3 makeStyles-textJustifyAlign-48"
|
class="makeStyles-paper-3 makeStyles-textJustifyAlign-49"
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
aria-disabled="false"
|
aria-disabled="false"
|
||||||
|
|||||||
@@ -27,20 +27,21 @@ const Component = () => {
|
|||||||
const [markers, setMarkers] = useState([]);
|
const [markers, setMarkers] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
retrieveAndStoreLocations().then((points) => {
|
if (!token) return;
|
||||||
|
retrieveAndStoreLocations(token).then((points) => {
|
||||||
centerAroundMarkers(points);
|
centerAroundMarkers(points);
|
||||||
});
|
});
|
||||||
const id = setInterval(function () {
|
const id = setInterval(function () {
|
||||||
retrieveAndStoreLocations();
|
retrieveAndStoreLocations(token);
|
||||||
}, REQUEST_INTERVAL);
|
}, REQUEST_INTERVAL);
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(id);
|
clearInterval(id);
|
||||||
};
|
};
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, [token]);
|
||||||
|
|
||||||
const retrieveAndStoreLocations = () => {
|
const retrieveAndStoreLocations = (accessToken) => {
|
||||||
return getLocations(token)
|
return getLocations(accessToken)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
if (result.data != null) {
|
if (result.data != null) {
|
||||||
const points = result.data.map((point) => [
|
const points = result.data.map((point) => [
|
||||||
@@ -73,6 +74,7 @@ const Component = () => {
|
|||||||
const [connections, setConnections] = useState({});
|
const [connections, setConnections] = useState({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (!token) return;
|
||||||
if (markers.length > 0) {
|
if (markers.length > 0) {
|
||||||
const vins = markers.map((marker) => marker[2]);
|
const vins = markers.map((marker) => marker[2]);
|
||||||
getConnections(vins, token).then((connections) => {
|
getConnections(vins, token).then((connections) => {
|
||||||
@@ -177,6 +179,7 @@ const Component = () => {
|
|||||||
doors={carState.doors}
|
doors={carState.doors}
|
||||||
location={carState.location}
|
location={carState.location}
|
||||||
windows={carState.windows}
|
windows={carState.windows}
|
||||||
|
updatedAt={carState.updated}
|
||||||
className={classes.popup}
|
className={classes.popup}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import CloseIcon from '@material-ui/icons/Close';
|
|||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
import useStyles from "../useStyles";
|
import useStyles from "../useStyles";
|
||||||
|
import { LocalDateTimeString } from "../../utils/dates";
|
||||||
|
|
||||||
const VehiclePopUp = (props) => {
|
const VehiclePopUp = (props) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { vin, online, battery, doors, location, windows, onClose } = props;
|
const { vin, online, battery, doors, location, updatedAt, windows, onClose } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
@@ -24,24 +25,35 @@ const VehiclePopUp = (props) => {
|
|||||||
{online && (
|
{online && (
|
||||||
<div>
|
<div>
|
||||||
{battery != null && (
|
{battery != null && (
|
||||||
<p><b>battery</b>: {battery.percent}%</p>
|
<p><b>Battery</b>: {battery.percent}%</p>
|
||||||
)}
|
)}
|
||||||
{doors != null && (
|
{doors != null && (
|
||||||
<div>
|
<div className={classes.popupSection}>
|
||||||
<h3>Doors</h3>
|
<h3>Doors</h3>
|
||||||
{Object.entries(doors).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
|
{Object.entries(doors).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{windows != null && (
|
{windows != null && (
|
||||||
<div>
|
<div className={classes.popupSection}>
|
||||||
<h3>Windows</h3>
|
<h3>Windows</h3>
|
||||||
{Object.entries(windows).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
|
{Object.entries(windows).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1] ? "open" : "closed"}</p>))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{location != null && (
|
{location != null && (
|
||||||
<div>
|
<div className={classes.popupSection}>
|
||||||
<h3>Location</h3>
|
<h3>Location</h3>
|
||||||
{Object.entries(location).map((value) => (<p key={value[0]}><b>{value[0]}</b>: {value[1]}</p>))}
|
{Object.entries(location).map((value) => {
|
||||||
|
if (value[0] === "altitude") {
|
||||||
|
return (<p key={value[0]}><b>{value[0]}</b>: {value[1]}</p>);
|
||||||
|
} else {
|
||||||
|
return (<p key={value[0]}><b>{value[0]}</b>: {value[1]}°</p>)
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{updatedAt != null && (
|
||||||
|
<div className={classes.popupSection}>
|
||||||
|
<p><b>Updated at</b>: {LocalDateTimeString(updatedAt)}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ function menuItemStyle(item, selectedItems, theme) {
|
|||||||
? theme.typography.fontWeightRegular
|
? theme.typography.fontWeightRegular
|
||||||
: theme.typography.fontWeightMedium,
|
: theme.typography.fontWeightMedium,
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
export default menuItemStyle
|
export default menuItemStyle;
|
||||||
|
|||||||
@@ -203,6 +203,9 @@ const useStyles = makeStyles((theme) => ({
|
|||||||
},
|
},
|
||||||
paddingBottom: "2vh",
|
paddingBottom: "2vh",
|
||||||
},
|
},
|
||||||
|
popupSection: {
|
||||||
|
marginBottom: "1vh",
|
||||||
|
},
|
||||||
toolbarFooter: {
|
toolbarFooter: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
textAlign: "right",
|
textAlign: "right",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
const updatesAPI = {
|
const manifestsAPI = {
|
||||||
createCarUpdates: async (data, token) => {
|
createCarUpdates: async (data, token) => {
|
||||||
if (!data.id) data.id = 0;
|
if (!data.id) data.id = 0;
|
||||||
data.id++;
|
data.id++;
|
||||||
@@ -14,21 +14,21 @@ const updatesAPI = {
|
|||||||
id: 1,
|
id: 1,
|
||||||
package_name: "Test",
|
package_name: "Test",
|
||||||
version: "1.0",
|
version: "1.0",
|
||||||
link: "http://cloudfront.com/download",
|
link: "https://cloudfront.com/download",
|
||||||
ecu_list: "ECU1 1.0.0,ECU2 1.0.2",
|
ecu_list: "ECU1 1.0.0,ECU2 1.0.2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
package_name: "Test",
|
package_name: "Test",
|
||||||
version: "1.1",
|
version: "1.1",
|
||||||
link: "http://cloudfront.com/download",
|
link: "https://cloudfront.com/download",
|
||||||
ecu_list: "ECU1 1.0.1,ECU2 1.0.2",
|
ecu_list: "ECU1 1.0.1,ECU2 1.0.2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
package_name: "Test",
|
package_name: "Test",
|
||||||
version: "1.2",
|
version: "1.2",
|
||||||
link: "http://cloudfront.com/download",
|
link: "https://cloudfront.com/download",
|
||||||
ecu_list: "ECU1 1.1.0,ECU2 1.1.2",
|
ecu_list: "ECU1 1.1.0,ECU2 1.1.2",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -56,4 +56,4 @@ const updatesAPI = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default updatesAPI;
|
export default manifestsAPI;
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { fetchRespHandler } from "../utils/http"
|
import { fetchRespHandler } from "../utils/http"
|
||||||
import { logger } from "../services/monitoring";
|
import { logger } from "./monitoring";
|
||||||
|
|
||||||
const API_ENDPOINT = "https://grafana.fiskerdps.com/api/datasources/proxy/2"
|
const API_ENDPOINT = "https://grafana.fiskerdps.com/api/datasources/proxy/2"
|
||||||
|
|
||||||
const grafanaAPI = {
|
const grafanaAPI = {
|
||||||
getCarsCount: async () => fetch(`${API_ENDPOINT}/?query=SELECT%20countDistinct(vin)%20as%20count%0AFROM%20default.vehicle_data%20FORMAT%20JSON`, {
|
getCarsCount: async () => fetch(`${API_ENDPOINT}/?query=SELECT%20countDistinct(VIN)%20as%20count%0AFROM%20default.vehicle_signal%0AWHERE%20Timestamp%20%3C%3D%20toDateTime64(${Date.now() / Math.pow(10, 3)}%2C%203)%20AND%20Timestamp%20%3E%3D%20toDateTime64(${Date.now() / Math.pow(10, 3) - 60 * 60 * 24}%2C%203)%20FORMAT%20JSON`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: Object.assign({ "Content-Type": "application/json" }),
|
headers: Object.assign({ "Content-Type": "application/json" }),
|
||||||
})
|
})
|
||||||
Reference in New Issue
Block a user