CEC-3071: Fixed Duplicate datascope menu (#232)
* CEC-3071: Fixed Duplicate datascope menu * Mde item type dynamic Co-authored-by: Alexander Andrews <aandrews@fiskerinc.com>
This commit is contained in:
committed by
GitHub
parent
2d298368c5
commit
61982c4ba5
File diff suppressed because it is too large
Load Diff
38
src/components/Layouts/MenuItem.jsx
Normal file
38
src/components/Layouts/MenuItem.jsx
Normal 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}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React from "react";
|
||||||
import { List } from "@material-ui/core";
|
import { List } from "@material-ui/core";
|
||||||
import HomeIcon from "@material-ui/icons/Home";
|
import HomeIcon from "@material-ui/icons/Home";
|
||||||
import DirectionsCarIcon from "@material-ui/icons/DirectionsCar";
|
import DirectionsCarIcon from "@material-ui/icons/DirectionsCar";
|
||||||
@@ -8,12 +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 supersetAPI from "../../services/superset";
|
import SupersetDashboardList from "../SupersetDashboardList/SupersetDashboardList";
|
||||||
|
|
||||||
const menuData = [
|
const menuData = [
|
||||||
{
|
{
|
||||||
@@ -40,6 +38,13 @@ const menuData = [
|
|||||||
icon: <CommuteIcon />,
|
icon: <CommuteIcon />,
|
||||||
roles: [Roles.READ, Roles.CREATE],
|
roles: [Roles.READ, Roles.CREATE],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "Datascope",
|
||||||
|
to: null,
|
||||||
|
icon: <AssessmentIcon />,
|
||||||
|
roles: [Roles.READ, Roles.CREATE],
|
||||||
|
component: SupersetDashboardList
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: "Suppliers",
|
label: "Suppliers",
|
||||||
to: "/suppliers",
|
to: "/suppliers",
|
||||||
@@ -66,62 +71,17 @@ 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, setMenu] = useState(menuData)
|
|
||||||
const {
|
|
||||||
token: {
|
|
||||||
idToken: { jwtToken: token },
|
|
||||||
},
|
|
||||||
} = useUserContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
const menu = menuData.reduce((result, item) => {
|
||||||
if (groups && token) {
|
if (hasRole(item.roles, groups)) {
|
||||||
const internalEffect = async (token) => {
|
result.push(item);
|
||||||
const datasscopeitem = await SupersetItemList(token)
|
|
||||||
menuData.push(datasscopeitem)
|
|
||||||
FilterAccessible(groups, setMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
internalEffect(token)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [groups, token])
|
return result;
|
||||||
|
}, []);
|
||||||
useEffect(() => {
|
|
||||||
FilterAccessible(groups, setMenu)
|
|
||||||
}, [groups])
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -136,36 +96,4 @@ const SideMenu = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FilterAccessible = (groups, setMenu) => {
|
|
||||||
|
|
||||||
const filteredMenu = menuData.reduce((result, item) => {
|
|
||||||
if (hasRole(item.roles, groups)) {
|
|
||||||
result.push(item);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}, [])
|
|
||||||
setMenu(filteredMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will get the set of superset embeddable dashboards, and put it in the submenu style
|
|
||||||
const SupersetItemList = async (token) => {
|
|
||||||
const embeddedDashboards = await supersetAPI.getEmbeddedDashboards(token)
|
|
||||||
|
|
||||||
const submenus = embeddedDashboards.map((dashboard) => {
|
|
||||||
return {
|
|
||||||
label: dashboard.title,
|
|
||||||
to: "/datascope/" + dashboard.embedded_id,
|
|
||||||
roles: [],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
|
||||||
label: "Datascope",
|
|
||||||
to: "/datascope",
|
|
||||||
icon: <AssessmentIcon />,
|
|
||||||
roles: [Roles.READ, Roles.CREATE],
|
|
||||||
submenus: submenus
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default SideMenu;
|
export default SideMenu;
|
||||||
@@ -152,6 +152,67 @@ exports[`SideMenu Authenticated 1`] = `
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<div
|
||||||
|
aria-disabled="false"
|
||||||
|
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiListItemIcon-root"
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
/>
|
||||||
|
</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>
|
<span>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
@@ -238,70 +299,6 @@ exports[`SideMenu Authenticated 1`] = `
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<span>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root MuiListItem-root MuiListItem-gutters MuiListItem-button"
|
|
||||||
href="/datascope"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiListItemIcon-root"
|
|
||||||
>
|
|
||||||
<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/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>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
Reference in New Issue
Block a user