Reorganize app pages (#73)
* Update layout and menus * Add breadcrumbs Add menu icons Add ECU drop down * Implement submenu Update download progress * revamped dashboard section - failing app.test.js * Clean up Co-authored-by: Drew Taylor <dtaylor@fiskerinc.com>
This commit is contained in:
@@ -1,26 +1,26 @@
|
||||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import Drawer from "@material-ui/core/Drawer";
|
||||
import AppBar from "@material-ui/core/AppBar";
|
||||
import Toolbar from "@material-ui/core/Toolbar";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Divider from "@material-ui/core/Divider";
|
||||
import {
|
||||
Container,
|
||||
Drawer,
|
||||
AppBar,
|
||||
Toolbar,
|
||||
Typography,
|
||||
Divider,
|
||||
} from "@material-ui/core";
|
||||
|
||||
import SideMenu from "./SideMenu";
|
||||
import useStyles from "../useStyles";
|
||||
import { useUserContext } from "../Contexts/UserContext";
|
||||
import { useStatusContext } from "../Contexts/StatusContext";
|
||||
import { Button, Container } from "@material-ui/core";
|
||||
import UserMenu from "./UserMenu";
|
||||
import SiteBreadcrumbs from "../Controls/SiteBreadCrumbs";
|
||||
import logo from "../../assets/fisker-badge.svg";
|
||||
|
||||
export default function MenuDrawer({ children }) {
|
||||
const classes = useStyles();
|
||||
const { title } = useStatusContext();
|
||||
const { signOut, token } = useUserContext();
|
||||
|
||||
const onSignOut = () => {
|
||||
document.location = signOut();
|
||||
};
|
||||
const { title, sitePath } = useStatusContext();
|
||||
const { token } = useUserContext();
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
@@ -31,17 +31,14 @@ export default function MenuDrawer({ children }) {
|
||||
})}
|
||||
>
|
||||
<Toolbar>
|
||||
<Typography variant="h6" noWrap>
|
||||
{title}
|
||||
</Typography>
|
||||
<div>
|
||||
<Typography variant="h6" noWrap>
|
||||
{title}
|
||||
</Typography>
|
||||
<SiteBreadcrumbs path={sitePath} className={classes.breadcrumbs} />
|
||||
</div>
|
||||
{token !== null && (
|
||||
<Button
|
||||
color="inherit"
|
||||
onClick={onSignOut}
|
||||
className={classes.rightToolbar}
|
||||
>
|
||||
Sign Out
|
||||
</Button>
|
||||
<UserMenu color="inherit" className={classes.rightToolbar} />
|
||||
)}
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
@@ -4,46 +4,89 @@ import ListItemLink from "../ListItemLink";
|
||||
import ListItemExternalLink from "../ListItemExternalLink";
|
||||
import { useUserContext } from "../Contexts/UserContext";
|
||||
import { Roles, hasRole } from "../../utils/roles";
|
||||
import HomeIcon from "@material-ui/icons/Home";
|
||||
import CommuteIcon from "@material-ui/icons/Commute";
|
||||
import CloudDownloadIcon from "@material-ui/icons/CloudDownload";
|
||||
import AssessmentIcon from "@material-ui/icons/Assessment";
|
||||
|
||||
const menuData = [
|
||||
{
|
||||
label: "Home",
|
||||
to: "/home",
|
||||
icon: <HomeIcon />,
|
||||
roles: [],
|
||||
},
|
||||
{
|
||||
label: "Dashboard",
|
||||
to: "/dashboard",
|
||||
roles: [Roles.CREATE, Roles.READ],
|
||||
},
|
||||
{
|
||||
label: "Deploy Packages",
|
||||
label: "Deployments",
|
||||
to: "/packages",
|
||||
icon: <CloudDownloadIcon />,
|
||||
roles: [Roles.CREATE, Roles.READ],
|
||||
},
|
||||
{
|
||||
label: "Create Package",
|
||||
to: "/package-create",
|
||||
roles: [Roles.CREATE],
|
||||
},
|
||||
{
|
||||
label: "View Vehicles",
|
||||
label: "Vehicles",
|
||||
to: "/vehicles",
|
||||
icon: <CommuteIcon />,
|
||||
roles: [Roles.CREATE],
|
||||
},
|
||||
{
|
||||
label: "Datascope",
|
||||
to: "/datascope",
|
||||
icon: <AssessmentIcon />,
|
||||
roles: [Roles.CREATE, Roles.READ],
|
||||
},
|
||||
{
|
||||
label: "Add Vehicle",
|
||||
to: "/vehicle-add",
|
||||
roles: [Roles.CREATE],
|
||||
},
|
||||
{
|
||||
label: "Send Command",
|
||||
to: "/vehicles-command",
|
||||
roles: [Roles.CREATE],
|
||||
submenus: [
|
||||
{
|
||||
label: "Battery",
|
||||
to: "/datascope/battery",
|
||||
},
|
||||
{
|
||||
label: "Diagnostics",
|
||||
url: "https://grafana.fiskerdps.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default function SideMenu() {
|
||||
const MenuItem = ({ item, children }) => {
|
||||
return (
|
||||
<li>
|
||||
{item.to && (
|
||||
<ListItemLink primary={item.label} to={item.to} icon={item.icon} />
|
||||
)}
|
||||
{item.url && (
|
||||
<ListItemExternalLink
|
||||
primary={item.label}
|
||||
url={item.url}
|
||||
icon={item.icon}
|
||||
/>
|
||||
)}
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
const ExpandableSideMenuItem = ({ item }) => {
|
||||
/*
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
const clickHandler = (e) => {
|
||||
setExpanded(!expanded);
|
||||
};
|
||||
*/
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
<MenuItem item={item}></MenuItem>
|
||||
</span>
|
||||
<ul style={{ marginLeft: 50 }}>
|
||||
{item.submenus.map((subitem, index) => (
|
||||
<MenuItem key={`submenu-${index}`} item={subitem} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const SideMenu = () => {
|
||||
const { groups } = useUserContext();
|
||||
const menu = menuData.reduce((result, item) => {
|
||||
if (hasRole(item.roles, groups)) {
|
||||
@@ -55,14 +98,14 @@ export default function SideMenu() {
|
||||
|
||||
return (
|
||||
<List>
|
||||
{menu.map((item, index) => (
|
||||
<li key={index}>
|
||||
{item.to && <ListItemLink primary={item.label} to={item.to} />}
|
||||
{item.url && (
|
||||
<ListItemExternalLink primary={item.label} url={item.url} />
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
{menu.map((item, index) => {
|
||||
const key = `menu-${index}`;
|
||||
if (item.submenus)
|
||||
return <ExpandableSideMenuItem key={key} item={item} />;
|
||||
return <MenuItem key={key} item={item} />;
|
||||
})}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SideMenu;
|
||||
|
||||
48
src/components/Layouts/UserMenu/index.jsx
Normal file
48
src/components/Layouts/UserMenu/index.jsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React, { useState } from "react";
|
||||
import { Button, Fade, Menu, MenuItem } from "@material-ui/core";
|
||||
|
||||
import { useUserContext } from "../../Contexts/UserContext";
|
||||
import { getName } from "../../../utils/jwt";
|
||||
|
||||
const UserMenu = (props) => {
|
||||
const { signOut, token } = useUserContext();
|
||||
const [anchorEl, setAnchorEl] = useState(null);
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const handleClick = (event) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleSignOut = () => {
|
||||
document.location = signOut();
|
||||
};
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<Button
|
||||
aria-controls="fade-menu"
|
||||
aria-haspopup="true"
|
||||
onClick={handleClick}
|
||||
color="inherit"
|
||||
>
|
||||
{getName(token)}
|
||||
</Button>
|
||||
<Menu
|
||||
id="fade-menu"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
TransitionComponent={Fade}
|
||||
>
|
||||
<MenuItem onClick={handleSignOut}>Sign out</MenuItem>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserMenu;
|
||||
@@ -16,6 +16,20 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemIcon-root"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
@@ -30,28 +44,6 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/dashboard"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Dashboard
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
@@ -61,34 +53,26 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
class="MuiListItemIcon-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
Deploy Packages
|
||||
</span>
|
||||
<path
|
||||
d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/package-create"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Create Package
|
||||
Deployments
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
@@ -105,34 +89,26 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
class="MuiListItemIcon-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
View Vehicles
|
||||
</span>
|
||||
<path
|
||||
d="M12 4H5C3.34 4 2 5.34 2 7v8c0 1.66 1.34 3 3 3l-1 1v1h1l2-2.03L9 18v-5H4V5.98L13 6v2h2V7c0-1.66-1.34-3-3-3zM5 14c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm15.57-4.34c-.14-.4-.52-.66-.97-.66h-7.19c-.46 0-.83.26-.98.66L10 13.77l.01 5.51c0 .38.31.72.69.72h.62c.38 0 .68-.38.68-.76V18h8v1.24c0 .38.31.76.69.76h.61c.38 0 .69-.34.69-.72l.01-1.37v-4.14l-1.43-4.11zm-8.16.34h7.19l1.03 3h-9.25l1.03-3zM12 16c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm8 0c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/vehicle-add"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Add Vehicle
|
||||
Vehicles
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
@@ -140,28 +116,95 @@ exports[`SideMenu Authenticated 1`] = `
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/vehicles-command"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
<span>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/datascope"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
<div
|
||||
class="MuiListItemIcon-root"
|
||||
>
|
||||
Send Command
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Datascope
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</span>
|
||||
<ul
|
||||
style="margin-left: 50px;"
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||
href="/datascope/battery"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Battery
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="MuiTypography-root MuiLink-root MuiLink-underlineHover MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button MuiTypography-colorPrimary"
|
||||
href="https://grafana.fiskerdps.com"
|
||||
rel="noopener"
|
||||
role="button"
|
||||
style="text-decoration: inherit;"
|
||||
tabindex="0"
|
||||
target="_blank"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
<span
|
||||
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
|
||||
>
|
||||
Diagnostics
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="MuiTouchRipple-root"
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -183,6 +226,20 @@ exports[`SideMenu Unauthenticated 1`] = `
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="MuiListItemIcon-root"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="MuiListItemText-root"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user