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