CEC-5292: add battery info to fleet vehicles (#474)
* CEC-5292: add battery info to fleet vehicles * add permission requirement * set new message * responsive * fix missing status * update snapshots * update snapshots
This commit is contained in:
62
src/components/Battery/index.jsx
Normal file
62
src/components/Battery/index.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { lazy } from "react";
|
||||
import {
|
||||
Tooltip
|
||||
} from "@material-ui/core";
|
||||
import useStyles from "../useStyles";
|
||||
|
||||
const Battery0 = lazy(() => import("@mui/icons-material/Battery0Bar"));
|
||||
const BatteryFull = lazy(() => import("@mui/icons-material/BatteryFull"));
|
||||
const BatteryUnknown = lazy(() => import("@mui/icons-material/BatteryUnknown"));
|
||||
const BatteryCharging = lazy(() => import("@mui/icons-material/BatteryChargingFull"));
|
||||
const Batteries = [
|
||||
lazy(() => import("@mui/icons-material/Battery0Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery1Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery2Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery3Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery4Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery5Bar")),
|
||||
lazy(() => import("@mui/icons-material/Battery6Bar")),
|
||||
];
|
||||
|
||||
const chargingStates = [
|
||||
"V2L_trunk_active",
|
||||
];
|
||||
|
||||
function getBatteryByPercent(percent) {
|
||||
if (isNaN(percent) || percent > 100 || percent < 0) {
|
||||
return BatteryUnknown;
|
||||
}
|
||||
|
||||
if (percent === 0) {
|
||||
return Battery0;
|
||||
}
|
||||
|
||||
if (percent === 100) {
|
||||
return BatteryFull;
|
||||
}
|
||||
|
||||
const unit = 14.2857142857;
|
||||
const range = Math.floor(percent / unit);
|
||||
|
||||
return Batteries[range];
|
||||
}
|
||||
|
||||
export default function Battery({
|
||||
percent,
|
||||
charge = "unknown"
|
||||
}) {
|
||||
const classes = useStyles();
|
||||
let Battery = getBatteryByPercent(percent);
|
||||
|
||||
if (chargingStates.includes(charge)) {
|
||||
Battery = BatteryCharging;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip title={`State: ${charge}`}>
|
||||
<div className={classes.alignCenter}>
|
||||
<Battery color="disabled" /> {percent && `${percent}%`}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ export default function BulkActions({
|
||||
{
|
||||
id: "diagnostic",
|
||||
name: "Send Diagnostic",
|
||||
disabled: false, // TODO set role
|
||||
disabled: !hasRole(groups, Permissions.CarDiagnostic, providers),
|
||||
trigger: () => setActive("diagnostic"),
|
||||
}
|
||||
].filter((action) => actions.includes(action.id));
|
||||
|
||||
@@ -138,6 +138,10 @@ export const FleetProvider = ({ children }) => {
|
||||
car_update_name: vehicle.carupdate?.updatemanifest?.name || "",
|
||||
car_update_status: vehicle.carupdate?.status || "",
|
||||
car_update_type: vehicle.carupdate?.updatemanifest?.type || "",
|
||||
voltage: vehicle.carstate?.battery?.battery_voltage,
|
||||
charge: vehicle.carstate?.battery?.percent,
|
||||
charge_type: vehicle.carstate?.vcu0x260?.charge_type,
|
||||
park: vehicle.carstate?.gear?.in_park,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -155,9 +159,16 @@ export const FleetProvider = ({ children }) => {
|
||||
const result = await updatesApi.getCarUpdateProgress(
|
||||
carUpdateIdsRef.current.join(","),
|
||||
token
|
||||
).catch(() => {
|
||||
return Promise.reject();
|
||||
});
|
||||
)
|
||||
.then((result) => {
|
||||
if (!Array.isArray(result.statuses)) {
|
||||
return Promise.reject();
|
||||
}
|
||||
return result;
|
||||
})
|
||||
.catch(() => {
|
||||
return Promise.reject();
|
||||
});
|
||||
let pivot = result.statuses?.length ? result.statuses.length - 1 : 0;
|
||||
setFleetVehicles((fleetVehicles) => fleetVehicles.map((vehicle) => {
|
||||
result.statuses.find((status, i) => {
|
||||
@@ -184,6 +195,7 @@ export const FleetProvider = ({ children }) => {
|
||||
break;
|
||||
default:
|
||||
vehicle.car_update_progress = -1;
|
||||
vehicle.car_update_status = status.msg;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ const FleetCANFiltersTab = () => {
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6">CAN Filters</Typography>
|
||||
<Typography variant="h6" className={classes.textCenterAlign}>CAN Filters</Typography>
|
||||
<FleetCANFiltersTable name={name} classes={classes} />
|
||||
</div >
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ const FleetDetailsTab = () => {
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6">Fleet Details</Typography>
|
||||
<Typography variant="h6" className={classes.textCenterAlign}>Fleet Details</Typography>
|
||||
<FleetDetails name={name} classes={classes} />
|
||||
</div >
|
||||
);
|
||||
|
||||
@@ -232,6 +232,75 @@ exports[`FleetVehiclesTable Render 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Battery
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Voltage
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Park
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
@@ -251,7 +320,7 @@ exports[`FleetVehiclesTable Render 1`] = `
|
||||
>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||
colspan="8"
|
||||
colspan="9"
|
||||
>
|
||||
<div
|
||||
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||
|
||||
@@ -30,6 +30,7 @@ import TableHeaderSortable from "../../../../Table/HeaderSortable";
|
||||
import { useLocalStorage } from "../../../../useLocalStorage";
|
||||
import ConnectedIcon from "../../../../Controls/ConnectedIcon";
|
||||
import BulkActions from "../../../../BulkActions";
|
||||
import Battery from "../../../../Battery";
|
||||
import useStyles from "../../../../useStyles";
|
||||
|
||||
const tableColumns = [
|
||||
@@ -49,6 +50,18 @@ const tableColumns = [
|
||||
id: "car_update_status",
|
||||
label: "Car Update Status",
|
||||
},
|
||||
{
|
||||
id: "battery",
|
||||
label: "Battery",
|
||||
},
|
||||
{
|
||||
id: "voltage",
|
||||
label: "Voltage",
|
||||
},
|
||||
{
|
||||
id: "park", // TODO: Update to 'gear' when we confirm each possible state
|
||||
label: "Park",
|
||||
},
|
||||
{
|
||||
id: "",
|
||||
label: "Actions",
|
||||
@@ -257,13 +270,22 @@ const MainForm = ({ name }) => {
|
||||
</Link>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
<TableCell key={"cell4" + car.car_update_status}>
|
||||
<TableCell key={"cell4" + car.vin}>
|
||||
{car.car_update_status}
|
||||
{car.car_update_progress > -1 && (
|
||||
<LinearProgress variant="determinate" value={car.car_update_progress} />
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell key={"cell5" + car.vin} align="center">{Actions(car.vin)}</TableCell>
|
||||
<TableCell key={"cell5" + car.vin}>
|
||||
<Battery percent={car.charge} charge={car.charge_type} />
|
||||
</TableCell>
|
||||
<TableCell key={"cell6" + car.vin}>
|
||||
{car.voltage > 0 && `${car.voltage}V`}
|
||||
</TableCell>
|
||||
<TableCell key={"cell7" + car.vin}>
|
||||
{car.park ? "Yes" : "No"}
|
||||
</TableCell>
|
||||
<TableCell key={"cell8" + car.vin} align="center">{Actions(car.vin)}</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
})}
|
||||
@@ -272,7 +294,7 @@ const MainForm = ({ name }) => {
|
||||
<TableRow>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 10, 25, 100]}
|
||||
colSpan={8}
|
||||
colSpan={9}
|
||||
count={totalFleetVehicles}
|
||||
rowsPerPage={pageSize}
|
||||
page={pageIndex}
|
||||
|
||||
@@ -12,7 +12,7 @@ const FleetVehiclesTab = () => {
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Typography variant="h6">Vehicles</Typography>
|
||||
<Typography variant="h6" className={classes.textCenterAlign}>Vehicles</Typography>
|
||||
<FleetVehiclesTable name={name} classes={classes} />
|
||||
</div >
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`CANFiltersTab Render 1`] = `
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
class="MuiTypography-root makeStyles-textCenterAlign-0 MuiTypography-h6"
|
||||
>
|
||||
CAN Filters
|
||||
</h6>
|
||||
|
||||
@@ -15,7 +15,7 @@ exports[`DetailsTab Render 1`] = `
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
class="MuiTypography-root makeStyles-textCenterAlign-0 MuiTypography-h6"
|
||||
>
|
||||
Fleet Details
|
||||
</h6>
|
||||
|
||||
@@ -6,7 +6,7 @@ exports[`VehiclesTab Render 1`] = `
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
class="MuiTypography-root makeStyles-textCenterAlign-0 MuiTypography-h6"
|
||||
>
|
||||
Vehicles
|
||||
</h6>
|
||||
@@ -231,6 +231,75 @@ exports[`VehiclesTab Render 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Battery
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Voltage
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
>
|
||||
<span
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiTableSortLabel-root"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Park
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root MuiTableSortLabel-icon MuiTableSortLabel-iconDirectionAsc"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</th>
|
||||
<th
|
||||
class="MuiTableCell-root MuiTableCell-head MuiTableCell-alignCenter"
|
||||
scope="col"
|
||||
@@ -250,7 +319,7 @@ exports[`VehiclesTab Render 1`] = `
|
||||
>
|
||||
<td
|
||||
class="MuiTableCell-root MuiTableCell-footer MuiTablePagination-root"
|
||||
colspan="8"
|
||||
colspan="9"
|
||||
>
|
||||
<div
|
||||
class="MuiToolbar-root MuiToolbar-regular MuiTablePagination-toolbar MuiToolbar-gutters"
|
||||
|
||||
@@ -12,10 +12,10 @@ exports[`FleetStatus Render 1`] = `
|
||||
data-testid="mocked-userprovider"
|
||||
>
|
||||
<div
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
class="makeStyles-paper-0 makeStyles-paperLeft-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<div
|
||||
class="MuiBox-root MuiBox-root-0 makeStyles-tableToolbar-0"
|
||||
class="MuiBox-root MuiBox-root-0 makeStyles-tableToolbar-0 makeStyles-alignCenter-0"
|
||||
>
|
||||
<div
|
||||
class="MuiTabs-root"
|
||||
@@ -93,6 +93,7 @@ exports[`FleetStatus Render 1`] = `
|
||||
</div>
|
||||
<div
|
||||
aria-labelledby="tab-0"
|
||||
class="makeStyles-fullWidth-0"
|
||||
id="tabpanel-0"
|
||||
role="tabpanel"
|
||||
>
|
||||
@@ -103,7 +104,7 @@ exports[`FleetStatus Render 1`] = `
|
||||
class="makeStyles-paper-0 makeStyles-tableSize-0"
|
||||
>
|
||||
<h6
|
||||
class="MuiTypography-root MuiTypography-h6"
|
||||
class="MuiTypography-root makeStyles-textCenterAlign-0 MuiTypography-h6"
|
||||
>
|
||||
Fleet Details
|
||||
</h6>
|
||||
@@ -291,12 +292,14 @@ exports[`FleetStatus Render 1`] = `
|
||||
</div>
|
||||
<div
|
||||
aria-labelledby="tab-1"
|
||||
class="makeStyles-fullWidth-0"
|
||||
hidden=""
|
||||
id="tabpanel-1"
|
||||
role="tabpanel"
|
||||
/>
|
||||
<div
|
||||
aria-labelledby="tab-2"
|
||||
class="makeStyles-fullWidth-0"
|
||||
hidden=""
|
||||
id="tabpanel-2"
|
||||
role="tabpanel"
|
||||
|
||||
@@ -50,8 +50,8 @@ const FleetStatus = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={clsx(classes.paper, classes.tableSize)}>
|
||||
<Box className={classes.tableToolbar} sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<div className={clsx(classes.paper, classes.paperLeft, classes.tableSize)}>
|
||||
<Box className={clsx(classes.tableToolbar, classes.alignCenter)} sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={tabIndex} onChange={handleTabChange} aria-label="car tabs" indicatorColor="secondary">
|
||||
<Tab label="Details" {...tabProps(0)} />
|
||||
<Tab label="Vehicles" {...tabProps(1)} />
|
||||
@@ -59,15 +59,15 @@ const FleetStatus = () => {
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<TabPanel value={tabIndex} index={0}>
|
||||
<TabPanel value={tabIndex} index={0} className={classes.fullWidth}>
|
||||
<FleetDetailsTab />
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel value={tabIndex} index={1}>
|
||||
<TabPanel value={tabIndex} index={1} className={classes.fullWidth}>
|
||||
<FleetVehiclesTab />
|
||||
</TabPanel >
|
||||
|
||||
<TabPanel value={tabIndex} index={2}>
|
||||
<TabPanel value={tabIndex} index={2} className={classes.fullWidth}>
|
||||
<FleetCANFiltersTab />
|
||||
</TabPanel>
|
||||
</div >
|
||||
|
||||
@@ -10,6 +10,11 @@ const useStyles = makeStyles((theme) => ({
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
alignCenter: {
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
},
|
||||
modaldialog: {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
border: "2px solid #000",
|
||||
@@ -22,6 +27,9 @@ const useStyles = makeStyles((theme) => ({
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
},
|
||||
paperLeft: {
|
||||
alignItems: "flex-start",
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing(1),
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
@@ -253,7 +261,7 @@ const useStyles = makeStyles((theme) => ({
|
||||
padding: 15,
|
||||
paddingBottom: 20,
|
||||
},
|
||||
textJustifyAlign: { textAlign: "justifyContent" },
|
||||
textJustifyAlign: { textAlign: "justify-content" },
|
||||
textCenterAlign: { textAlign: "center" },
|
||||
textRightAlign: { textAlign: "right" },
|
||||
fullWidth: { width: "100%" },
|
||||
|
||||
Reference in New Issue
Block a user