CEC-3944 Static dashboard (#301)

* CEC-3944 Static dashboard

* Unit test
This commit is contained in:
John Wu
2023-03-22 19:39:48 -07:00
committed by GitHub
parent 5a8e823822
commit 6ddcf795a1
13 changed files with 2331 additions and 786 deletions

View File

@@ -7,4 +7,5 @@ REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cec-euprd.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cec-euprd.fiskerinc.com/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://superset.cec-euprd.fiskerinc.com REACT_APP_SUPERSET_URL=https://superset.cec-euprd.fiskerinc.com

View File

@@ -7,4 +7,5 @@ REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://superset.cec-prd.fiskerinc.com REACT_APP_SUPERSET_URL=https://superset.cec-prd.fiskerinc.com

View File

@@ -7,4 +7,5 @@ REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c
REACT_APP_OTA_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com

View File

@@ -7,4 +7,6 @@ REACT_APP_MAGNA_GROUP_ID=efcc3025-e2d8-4212-8227-805c7be39d2c
REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update REACT_APP_OTA_SERVICE_URL=http://localhost/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com

View File

@@ -7,4 +7,5 @@ REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://superset.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://superset.cloud.fiskerinc.com

View File

@@ -7,4 +7,5 @@ REACT_APP_MAGNA_GROUP_ID=68273225-9da4-4fa7-aea5-38e16ec471fe
REACT_APP_OTA_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update REACT_APP_OTA_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update
REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll REACT_APP_SECURITY_DLL_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_32.dll
REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll REACT_APP_SECURITY_DLL_64_URL=https://assets.fiskerdps.com/cloud-supplier/fisker_security_64.dll
REACT_APP_STATIC_DASHBOARDS_URL=https://assets.fiskerdps.com/dashboards
REACT_APP_SUPERSET_URL=https://stg-superset.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://stg-superset.cloud.fiskerinc.com

View File

@@ -126,6 +126,10 @@ describe("App", () => {
await check("/tools/security-dll", "span.MuiButton-label", "Sign In"); await check("/tools/security-dll", "span.MuiButton-label", "Sign In");
}); });
it("Route /dashboards/0 unauthenticated", async () => {
await check("/dashboards/0", "span.MuiButton-label", "Sign In");
});
it("Route /page-not-found unauthenticated", async () => { it("Route /page-not-found unauthenticated", async () => {
await check("/page-not-found", "h1", "Page Not Found"); await check("/page-not-found", "h1", "Page Not Found");
}); });
@@ -200,4 +204,15 @@ describe("App", () => {
setToken(TEST_AUTH_OBJECT_MAGNA); setToken(TEST_AUTH_OBJECT_MAGNA);
await sleepAndCheck("/tools/security-dll", "h6", "Security.dll Download"); await sleepAndCheck("/tools/security-dll", "h6", "Security.dll Download");
}); });
it("Route /dashboards/0 authenticated", async () => {
setToken(TEST_AUTH_OBJECT_FISKER);
await check("/dashboards/0", "h6", "Datascope");
});
// test bad dashboard
it("Route /dashboards/1000 authenticated", async () => {
setToken(TEST_AUTH_OBJECT_FISKER);
await check("/dashboards/1000", "span.error", "Invalid Dashboard");
});
}); });

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
import { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { getStaticDashboard } from "../../services/staticDashboards";
import { useStatusContext } from "../Contexts/StatusContext";
import useStyles from "../useStyles";
const StaticDashboard = () => {
const classes = useStyles();
const [dashboard, setDashboard] = useState(null);
const { setTitle, setSitePath } = useStatusContext();
const { index } = useParams();
useEffect(() => {
const result = getStaticDashboard(parseInt(index));
setDashboard(result);
setTitle("Datascope");
setSitePath([{ label: result.label}]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [index]);
if (!dashboard) return <div>Loading...</div>;
if (dashboard.error) return <span className="error">{dashboard.error}</span>;
return <iframe className={classes.iframe} src={dashboard.url} title={dashboard.label}/>;
};
export default StaticDashboard;

View File

@@ -1,19 +1,19 @@
import { List } from "@material-ui/core"; import { List } from "@material-ui/core";
import AssessmentIcon from "@material-ui/icons/Assessment"; import AssessmentIcon from "@material-ui/icons/Assessment";
import BugReportIcon from "@material-ui/icons/BugReport";
import BuildIcon from "@material-ui/icons/Build"; import BuildIcon from "@material-ui/icons/Build";
import CloudDownloadIcon from "@material-ui/icons/CloudDownload"; import CloudDownloadIcon from "@material-ui/icons/CloudDownload";
import CommuteIcon from "@material-ui/icons/Commute"; import CommuteIcon from "@material-ui/icons/Commute";
import DirectionsCarIcon from "@material-ui/icons/DirectionsCar"; import DirectionsCarIcon from "@material-ui/icons/DirectionsCar";
import BugReportIcon from "@material-ui/icons/BugReport";
import HomeIcon from "@material-ui/icons/Home"; import HomeIcon from "@material-ui/icons/Home";
import SettingsInputCompositeIcon from "@material-ui/icons/SettingsInputComposite"; import SettingsInputCompositeIcon from "@material-ui/icons/SettingsInputComposite";
import { default as React, useEffect, useState } from "react"; import { default as React, useEffect, useState } from "react";
import { getStaticDashboardSubmenu } from "../../services/staticDashboards";
import { hasRole, Permissions } from "../../utils/roles"; import { hasRole, Permissions } from "../../utils/roles";
import { useUserContext } from "../Contexts/UserContext"; import { useUserContext } from "../Contexts/UserContext";
import SupersetDashboardList from "../SupersetDashboardList/SupersetDashboardList"; import SupersetDashboardList from "../SupersetDashboardList/SupersetDashboardList";
import { ExpandableSideMenuItem, MenuItem } from "./MenuItem"; import { ExpandableSideMenuItem, MenuItem } from "./MenuItem";
const menuData = [ const menuData = [
{ {
label: "Home", label: "Home",
@@ -51,6 +51,7 @@ const menuData = [
icon: <AssessmentIcon />, icon: <AssessmentIcon />,
rolesPerProvider: Permissions.FiskerRead, rolesPerProvider: Permissions.FiskerRead,
component: SupersetDashboardList, component: SupersetDashboardList,
submenus: getStaticDashboardSubmenu(Permissions.FiskerRead),
}, },
{ {
label: "Suppliers", label: "Suppliers",

View File

@@ -188,67 +188,95 @@ exports[`SideMenu Authenticated 1`] = `
/> />
</a> </a>
</li> </li>
<li> <span>
<div <li>
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
role="button"
tabindex="0"
>
<div <div
class="MuiListItemIcon-root" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
role="button"
tabindex="0"
> >
<svg <div
aria-hidden="true" class="MuiListItemIcon-root"
class="MuiSvgIcon-root"
focusable="false"
viewBox="0 0 24 24"
> >
<path <svg
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" aria-hidden="true"
/> class="MuiSvgIcon-root"
</svg> focusable="false"
</div> viewBox="0 0 24 24"
<div
class="MuiListItemText-root"
>
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Datascope
</span>
</div>
<span
class="MuiTouchRipple-root"
/>
</div>
<ul
style="margin-left: 50px;"
>
<li>
<a
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope/00000000-0000-0000-0000-000000000000"
role="button"
tabindex="0"
>
<div
class="MuiListItemText-root"
> >
<span <path
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock" 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"
> />
test title </svg>
</span> </div>
</div> <div
class="MuiListItemText-root"
>
<span <span
class="MuiTouchRipple-root" class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
/> >
</a> Datascope
</li> </span>
</ul> </div>
</li> <span
class="MuiTouchRipple-root"
/>
</div>
<ul
style="margin-left: 50px;"
>
<li>
<a
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope/00000000-0000-0000-0000-000000000000"
role="button"
tabindex="0"
>
<div
class="MuiListItemText-root"
>
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
test title
</span>
</div>
<span
class="MuiTouchRipple-root"
/>
</a>
</li>
</ul>
</li>
</span>
<ul
style="margin-left: 50px;"
>
<li>
<a
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/dashboards/0"
role="button"
tabindex="0"
>
<div
class="MuiListItemText-root"
>
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Vehicle Paths
</span>
</div>
<span
class="MuiTouchRipple-root"
/>
</a>
</li>
</ul>
<li> <li>
<a <a
aria-disabled="false" aria-disabled="false"

View File

@@ -41,6 +41,8 @@ const SMSSend = React.lazy(() => import("../SMS/Send"));
const SuppliersList = React.lazy(() => import("../Suppliers/List")); const SuppliersList = React.lazy(() => import("../Suppliers/List"));
const SupplierDetails = React.lazy(() => import("../Suppliers/Details")); const SupplierDetails = React.lazy(() => import("../Suppliers/Details"));
const Datascope = React.lazy(() => import("../Dashboard")); const Datascope = React.lazy(() => import("../Dashboard"));
const StaticDashboard = React.lazy(() => import("../DashboardStatic"));
const SiteRoutes = () => { const SiteRoutes = () => {
const { token, groups, providers } = useUserContext(); const { token, groups, providers } = useUserContext();
return ( return (
@@ -54,6 +56,15 @@ const SiteRoutes = () => {
type={TYPES.GUEST} type={TYPES.GUEST}
token={token} token={token}
/> />
<AuthRoute
path="/dashboards/:index"
render={() => <StaticDashboard />}
type={TYPES.PROTECTED}
token={token}
groups={groups}
rolesPerGroup={Permissions.FiskerRead}
providers={providers}
/>
<AuthRoute <AuthRoute
path="/filter-add" path="/filter-add"
render={() => <CANFilterCreate />} render={() => <CANFilterCreate />}

View File

@@ -0,0 +1,26 @@
const STATIC_DASHBOARDS_URL = process.env.REACT_APP_STATIC_DASHBOARDS_URL;
const INVALID_DASHBOARD = {
label: "Invalid Dashboard",
error: "Invalid Dashboard"
}
export const StaticDashboardList = [
{
label: "Vehicle Paths",
url: `${STATIC_DASHBOARDS_URL}/paths.html`
}
];
export const getStaticDashboard = (index) => {
if (index < 0 || index >= StaticDashboardList.length) return INVALID_DASHBOARD;
return StaticDashboardList[index];
};
export const getStaticDashboardSubmenu = (role) => {
return StaticDashboardList.map((item, index) => ({
label: item.label,
to: `/dashboards/${index}`,
rolesPerProvider: role,
}));
}