Merge branch 'release/0.0.3'

This commit is contained in:
jwu-fisker
2022-11-09 14:38:50 -08:00
17 changed files with 503 additions and 145 deletions

View File

@@ -2,5 +2,4 @@ REACT_APP_AUTH_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/certificate
REACT_APP_UPLOAD_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update REACT_APP_UPLOAD_SERVICE_URL=https://gw.cec-prd.fiskerinc.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-prd.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cec-prd.fiskerinc.com
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://superset.cec-prd.fiskerinc.com
REACT_APP_SUPERSET_KEYS_LIST=0b01ac72-9ef4-4a5f-be34-b1ac0bf972cc

View File

@@ -2,5 +2,4 @@ REACT_APP_CERT_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/certificate
REACT_APP_AUTH_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/compute_auth REACT_APP_AUTH_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update REACT_APP_UPLOAD_SERVICE_URL=https://dev-gw.cloud.fiskerinc.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://dev-ota-admin.cloud.fiskerinc.com
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com
REACT_APP_SUPERSET_KEYS_LIST=0b01ac72-9ef4-4a5f-be34-b1ac0bf972cc

View File

@@ -2,5 +2,4 @@ REACT_APP_AUTH_SERVICE_URL=https://gw.cloud.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://gw.cloud.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://gw.cloud.fiskerinc.com/certificate
REACT_APP_UPLOAD_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update REACT_APP_UPLOAD_SERVICE_URL=https://gw.cloud.fiskerinc.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://ota-admin.cloud.fiskerinc.com
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://superset.cloud.fiskerinc.com
REACT_APP_SUPERSET_KEYS_LIST=0b01ac72-9ef4-4a5f-be34-b1ac0bf972cc

View File

@@ -2,5 +2,4 @@ REACT_APP_AUTH_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/compute_auth
REACT_APP_CERT_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/certificate REACT_APP_CERT_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/certificate
REACT_APP_UPLOAD_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update REACT_APP_UPLOAD_SERVICE_URL=https://stg-gw.cloud.fiskerinc.com/ota_update
REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.cloud.fiskerinc.com REACT_APP_AUTH_CALLBACK_URL=https://stg-ota-admin.cloud.fiskerinc.com
REACT_APP_SUPERSET_URL=https://dev-superset-new.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://stg-superset.cloud.fiskerinc.com
REACT_APP_SUPERSET_KEYS_LIST=0b01ac72-9ef4-4a5f-be34-b1ac0bf972cc

View File

@@ -2,5 +2,4 @@ REACT_APP_AUTH_SERVICE_URL=http://localhost/compute_auth
REACT_APP_UPLOAD_SERVICE_URL=http://localhost/ota_update REACT_APP_UPLOAD_SERVICE_URL=http://localhost/ota_update
REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000 REACT_APP_AUTH_CALLBACK_URL=http://localhost:3000
REACT_APP_SUPERSET_URL=https://dev-superset.cloud.fiskerinc.com REACT_APP_SUPERSET_URL=https://dev-superset.cloud.fiskerinc.com
REACT_APP_CERT_SERVICE_URL=http://localhost/certificate REACT_APP_CERT_SERVICE_URL=http://localhost/certificate
REACT_APP_SUPERSET_KEYS_LIST=0b01ac72-9ef4-4a5f-be34-b1ac0bf972cc

View File

@@ -5,8 +5,10 @@ jest.mock("../Contexts/ManifestsContext");
jest.mock("../Contexts/UserContext"); jest.mock("../Contexts/UserContext");
jest.mock("../../services/monitoring"); jest.mock("../../services/monitoring");
jest.mock("../../services/vehiclesAPI"); jest.mock("../../services/vehiclesAPI");
jest.mock("../../services/superset")
import { import {
act,
render, render,
screen, screen,
cleanup, cleanup,
@@ -30,7 +32,10 @@ const renderRoute = async (route) => {
}; };
const check = async (path, selector, compare) => { const check = async (path, selector, compare) => {
const container = await renderRoute(path); let container
await act(async () => {
container = await renderRoute(path);
})
expect(container.querySelector(selector).innerHTML).toEqual(compare); expect(container.querySelector(selector).innerHTML).toEqual(compare);
expect(container).toMatchSnapshot(); expect(container).toMatchSnapshot();
}; };

View File

@@ -210,10 +210,9 @@ exports[`App Route / authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -243,7 +242,33 @@ exports[`App Route / authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -744,10 +769,9 @@ exports[`App Route /home authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -777,7 +801,33 @@ exports[`App Route /home authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -1314,10 +1364,9 @@ exports[`App Route /package-deploy authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -1347,7 +1396,33 @@ exports[`App Route /package-deploy authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -2248,10 +2323,9 @@ exports[`App Route /package-status authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -2281,7 +2355,33 @@ exports[`App Route /package-status authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -2900,10 +3000,9 @@ exports[`App Route /packages authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -2933,7 +3032,33 @@ exports[`App Route /packages authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -3779,10 +3904,9 @@ exports[`App Route /page-not-found authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -3812,7 +3936,33 @@ exports[`App Route /page-not-found authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -4276,10 +4426,9 @@ exports[`App Route /tools/certificates/add authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -4309,7 +4458,33 @@ exports[`App Route /tools/certificates/add authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -5006,10 +5181,9 @@ exports[`App Route /tools/sms/send authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -5039,7 +5213,33 @@ exports[`App Route /tools/sms/send authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -5602,10 +5802,9 @@ exports[`App Route /vehicle-add authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -5635,7 +5834,33 @@ exports[`App Route /vehicle-add authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -6756,10 +6981,9 @@ exports[`App Route /vehicle-status authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -6789,7 +7013,33 @@ exports[`App Route /vehicle-status authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -7541,10 +7791,9 @@ exports[`App Route /vehicles authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -7574,7 +7823,33 @@ exports[`App Route /vehicles authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>

View File

@@ -4,10 +4,12 @@ import { useStatusContext } from "../Contexts/StatusContext";
import { useUserContext } from "../Contexts/UserContext"; import { useUserContext } from "../Contexts/UserContext";
import './index.css' import './index.css'
import { embedDashboard } from "@superset-ui/embedded-sdk"; import { embedDashboard } from "@superset-ui/embedded-sdk";
import { useHistory } from "react-router-dom";
const Dashboard = () => { const Dashboard = () => {
const { setTitle, setSitePath } = useStatusContext(); const { setTitle, setSitePath } = useStatusContext();
const history = useHistory()
const { const {
token: { token: {
@@ -16,17 +18,19 @@ const Dashboard = () => {
} = useUserContext(); } = useUserContext();
useEffect(() => { useEffect(() => {
const urlsplit = window.location.href.split("/")
const id = urlsplit[urlsplit.length - 1]
setTitle("Datascope"); setTitle("Datascope");
setSitePath([]); setSitePath([]);
embedDashboard({ embedDashboard({
id: api.SupersetDashboardID(), // given by the Superset embedding UI id: id, // given by the Superset embedding UI
supersetDomain: api.SupersetDashboardURL(), supersetDomain: api.SupersetDashboardURL(),
mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe
fetchGuestToken: () => api.getGuestToken(token), fetchGuestToken: () => api.getGuestToken(token),
dashboardUiConfig: { hideTab: true, hideTitle: true }, // dashboard UI config: hideTitle, hideTab, hideChartControls (optional) dashboardUiConfig: { hideTab: true, hideTitle: true }, // dashboard UI config: hideTitle, hideTab, hideChartControls (optional)
}); });
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); }, [history.location]);
return ( return (
<div style={{ <div style={{

View File

@@ -0,0 +1,38 @@
import React from "react";
import ListItemLink from "../ListItemLink";
import ListItemExternalLink from "../ListItemExternalLink"
const MenuItem = ({ item, children }) => {
return (
<li>
{item.label && (<>
{item.url ?
<ListItemExternalLink
primary={item.label}
url={item.url}
icon={item.icon}
/>
: <ListItemLink primary={item.label} to={item.to} icon={item.icon} />}
{item.component &&
<item.component />
}
</>)}
{children}
</li>
);
};
const ExpandableSideMenuItem = ({ item }) => (
<>
<span>
<MenuItem item={item}></MenuItem>
</span>
<ul style={{ marginLeft: 50 }}>
{item.submenus.map((subitem, index) => (
<MenuItem key={`submenu-${index}`} item={subitem} />
))}
</ul>
</>
);
export {ExpandableSideMenuItem, MenuItem}

View File

@@ -8,10 +8,10 @@ import AssessmentIcon from "@material-ui/icons/Assessment";
import BuildIcon from "@material-ui/icons/Build"; import BuildIcon from "@material-ui/icons/Build";
import SettingsInputCompositeIcon from "@material-ui/icons/SettingsInputComposite"; import SettingsInputCompositeIcon from "@material-ui/icons/SettingsInputComposite";
import ListItemLink from "../ListItemLink";
import ListItemExternalLink from "../ListItemExternalLink";
import { useUserContext } from "../Contexts/UserContext"; import { useUserContext } from "../Contexts/UserContext";
import { Roles, hasRole } from "../../utils/roles"; import { Roles, hasRole } from "../../utils/roles";
import { ExpandableSideMenuItem, MenuItem } from "./MenuItem";
import SupersetDashboardList from "../SupersetDashboardList/SupersetDashboardList";
const menuData = [ const menuData = [
{ {
@@ -40,9 +40,10 @@ const menuData = [
}, },
{ {
label: "Datascope", label: "Datascope",
to: "/datascope", to: null,
icon: <AssessmentIcon />, icon: <AssessmentIcon />,
roles: [Roles.READ, Roles.CREATE], roles: [Roles.READ, Roles.CREATE],
component: SupersetDashboardList
}, },
{ {
label: "Suppliers", label: "Suppliers",
@@ -70,39 +71,10 @@ const menuData = [
}, },
]; ];
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 }) => (
<>
<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 SideMenu = () => {
const { groups } = useUserContext(); const { groups } = useUserContext();
const menu = menuData.reduce((result, item) => { const menu = menuData.reduce((result, item) => {
if (hasRole(item.roles, groups)) { if (hasRole(item.roles, groups)) {
result.push(item); result.push(item);
@@ -111,6 +83,7 @@ const SideMenu = () => {
return result; return result;
}, []); }, []);
return ( return (
<List> <List>
{menu.map((item, index) => { {menu.map((item, index) => {
@@ -123,4 +96,4 @@ const SideMenu = () => {
); );
}; };
export default SideMenu; export default SideMenu;

View File

@@ -1,6 +1,7 @@
jest.mock("../Contexts/UserContext"); jest.mock("../Contexts/UserContext");
jest.mock("../../services/superset")
import { render, waitFor } from "@testing-library/react"; import { render, waitFor, screen } from "@testing-library/react";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter } from "react-router-dom";
import { UserProvider, setToken } from "../Contexts/UserContext"; import { UserProvider, setToken } from "../Contexts/UserContext";
import { TEST_AUTH_OBJECT } from "../../utils/testing"; import { TEST_AUTH_OBJECT } from "../../utils/testing";
@@ -22,17 +23,15 @@ const renderMenu = async () => {
describe("SideMenu", () => { describe("SideMenu", () => {
beforeAll(() => { beforeAll(() => {
addSnapshotSerializer(expect); addSnapshotSerializer(expect);
});
it("Unauthenticated", async () => {
setToken(null);
const container = await renderMenu();
expect(container).toMatchSnapshot();
}); });
it("Authenticated", async () => { it("Authenticated", async () => {
setToken(TEST_AUTH_OBJECT); setToken(TEST_AUTH_OBJECT);
const container = await renderMenu(); const container = await renderMenu();
await waitFor(() => {
expect(screen.getByText('Datascope')).toBeInTheDocument()
})
expect(container).toMatchSnapshot(); expect(container).toMatchSnapshot();
}); });
}); });

View File

@@ -153,10 +153,9 @@ exports[`SideMenu Authenticated 1`] = `
</a> </a>
</li> </li>
<li> <li>
<a <div
aria-disabled="false" aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button" class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/datascope"
role="button" role="button"
tabindex="0" tabindex="0"
> >
@@ -186,7 +185,33 @@ exports[`SideMenu Authenticated 1`] = `
<span <span
class="MuiTouchRipple-root" class="MuiTouchRipple-root"
/> />
</a> </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> </li>
<span> <span>
<li> <li>
@@ -278,52 +303,3 @@ exports[`SideMenu Authenticated 1`] = `
</div> </div>
</div> </div>
`; `;
exports[`SideMenu Unauthenticated 1`] = `
<div>
<div
data-testid="mocked-userprovider"
>
<ul
class="MuiList-root MuiList-padding"
>
<li>
<a
aria-disabled="false"
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
href="/home"
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"
>
<span
class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock"
>
Home
</span>
</div>
<span
class="MuiTouchRipple-root"
/>
</a>
</li>
</ul>
</div>
</div>
`;

View File

@@ -9,10 +9,13 @@ function ListItemLink(props) {
const { icon, primary, to } = props; const { icon, primary, to } = props;
const renderLink = React.useMemo( const renderLink = React.useMemo(
() => () => {
React.forwardRef((itemProps, ref) => ( if (to) {
<RouterLink to={to} ref={ref} {...itemProps} /> return React.forwardRef((itemProps, ref) => (
)), <RouterLink to={to} ref={ref} {...itemProps} />
))
}
},
[to] [to]
); );
@@ -27,7 +30,7 @@ function ListItemLink(props) {
ListItemLink.propTypes = { ListItemLink.propTypes = {
icon: PropTypes.element, icon: PropTypes.element,
primary: PropTypes.string.isRequired, primary: PropTypes.string.isRequired,
to: PropTypes.string.isRequired, to: PropTypes.string,
}; };
export default ListItemLink; export default ListItemLink;

View File

@@ -0,0 +1,45 @@
import React, { useState, useEffect } from "react";
import { useUserContext } from "../Contexts/UserContext";
import supersetAPI from "../../services/superset";
import { MenuItem } from "../Layouts/MenuItem";
const SupersetDashboardList = () => {
const [dashboardList, setDashboardList] = useState([])
const { groups } = useUserContext();
const {
token: {
idToken: { jwtToken: token },
},
} = useUserContext();
useEffect(() => {
if (groups && token) {
const internalEffect = async (token) => {
const embeddedDashboards = await await supersetAPI.getEmbeddedDashboards(token)
const submenus = embeddedDashboards.map((dashboard) => {
return {
label: dashboard.title,
to: "/datascope/" + dashboard.embedded_id,
roles: [],
}
})
setDashboardList(submenus)
}
internalEffect(token)
}
}, [groups, token])
return (
<ul style={{ marginLeft: 50 }}>
{dashboardList.map((subitem, index) => (
<MenuItem key={`submenu-${index}`} item={subitem} />
))}
</ul>
)
}
export default SupersetDashboardList

View File

@@ -0,0 +1,13 @@
const SupersetAPI = {
getEmbeddedDashboards: async () => {
return [{
title: "test title",
embedded_id: "00000000-0000-0000-0000-000000000000"
}]
},
SupersetDashboardID: () => {
return "11111100-0000-1111-1111-000000000000"
}
}
export default SupersetAPI

View File

@@ -21,15 +21,32 @@ const supersetAPI = {
let q = r["token"] let q = r["token"]
return q return q
}, },
getEmbeddedDashboards: async(token) => {
const u = addQueryParams(`${API_ENDPOINT}/dashboard/embedded-dashboards`);
let res = await fetch(u, {
method: "GET",
headers: Object.assign(
getAuthHeaderOptions(token)
),
})
if(res.status !== 200){
return [{title: "dashboard", embedded_id: GetSupersetDashboardID()}]
}
let r = await res.json()
return r
},
SupersetDashboardURL: () => { SupersetDashboardURL: () => {
const SUPERSET_BASE_URL = process.env.REACT_APP_SUPERSET_URL; const SUPERSET_BASE_URL = process.env.REACT_APP_SUPERSET_URL;
return SUPERSET_BASE_URL return SUPERSET_BASE_URL
}, },
SupersetDashboardID: () => { SupersetDashboardID: () => {
const SUPERSET_BASE_ID = process.env.REACT_APP_SUPERSET_KEYS_LIST; return GetSupersetDashboardID()
return SUPERSET_BASE_ID
} }
}
const GetSupersetDashboardID = () => {
const SUPERSET_BASE_ID = process.env.REACT_APP_SUPERSET_KEYS_LIST;
return SUPERSET_BASE_ID
} }
export default supersetAPI; export default supersetAPI;

View File

@@ -0,0 +1,15 @@
import superset from "./superset"
describe("Superset tests", () => {
it("Outdated API doesn't cause problems", async () => {
process.env.REACT_APP_SUPERSET_KEYS_LIST = "11111100-0000-1111-1111-000000000000"
global.fetch = jest.fn(() => {
return { status: 404 }
}
);
const res = await superset.getEmbeddedDashboards()
expect(res).toHaveLength(1)
expect(res[0].embedded_id).toBe("11111100-0000-1111-1111-000000000000")
})
})