diff --git a/src/components/App/App.test.js b/src/components/App/App.test.js
index f5de9f0..24f282c 100644
--- a/src/components/App/App.test.js
+++ b/src/components/App/App.test.js
@@ -5,8 +5,10 @@ jest.mock("../Contexts/ManifestsContext");
jest.mock("../Contexts/UserContext");
jest.mock("../../services/monitoring");
jest.mock("../../services/vehiclesAPI");
+jest.mock("../../services/superset")
import {
+ act,
render,
screen,
cleanup,
@@ -30,7 +32,10 @@ const renderRoute = async (route) => {
};
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).toMatchSnapshot();
};
diff --git a/src/components/App/__snapshots__/App.test.js.snap b/src/components/App/__snapshots__/App.test.js.snap
index 666d7a0..89272a9 100644
--- a/src/components/App/__snapshots__/App.test.js.snap
+++ b/src/components/App/__snapshots__/App.test.js.snap
@@ -209,42 +209,6 @@ exports[`App Route / authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -743,42 +771,6 @@ exports[`App Route /home authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -1313,42 +1433,6 @@ exports[`App Route /package-deploy authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -2247,42 +2715,6 @@ exports[`App Route /package-status authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -2899,42 +3651,6 @@ exports[`App Route /packages authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -3778,42 +4750,6 @@ exports[`App Route /page-not-found authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -4275,42 +5403,6 @@ exports[`App Route /tools/certificates/add authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -5005,42 +6737,6 @@ exports[`App Route /tools/sms/send authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -5601,42 +8001,6 @@ exports[`App Route /vehicle-add authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -6755,42 +9567,6 @@ exports[`App Route /vehicle-status authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
@@ -7540,42 +10892,6 @@ exports[`App Route /vehicles authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Datascope
+
+
+
+
+
+
+
diff --git a/src/components/Dashboard/index.jsx b/src/components/Dashboard/index.jsx
index 3570980..107d6c5 100644
--- a/src/components/Dashboard/index.jsx
+++ b/src/components/Dashboard/index.jsx
@@ -4,10 +4,12 @@ import { useStatusContext } from "../Contexts/StatusContext";
import { useUserContext } from "../Contexts/UserContext";
import './index.css'
import { embedDashboard } from "@superset-ui/embedded-sdk";
+import { useHistory } from "react-router-dom";
const Dashboard = () => {
const { setTitle, setSitePath } = useStatusContext();
+ const history = useHistory()
const {
token: {
@@ -16,17 +18,19 @@ const Dashboard = () => {
} = useUserContext();
useEffect(() => {
+ const urlsplit = window.location.href.split("/")
+ const id = urlsplit[urlsplit.length - 1]
setTitle("Datascope");
setSitePath([]);
embedDashboard({
- id: api.SupersetDashboardID(), // given by the Superset embedding UI
+ id: id, // given by the Superset embedding UI
supersetDomain: api.SupersetDashboardURL(),
mountPoint: document.getElementById("my-superset-container"), // any html element that can contain an iframe
fetchGuestToken: () => api.getGuestToken(token),
dashboardUiConfig: { hideTab: true, hideTitle: true }, // dashboard UI config: hideTitle, hideTab, hideChartControls (optional)
});
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [history.location]);
return (
,
roles: [Roles.READ, Roles.CREATE],
},
- {
- label: "Datascope",
- to: "/datascope",
- icon: ,
- roles: [Roles.READ, Roles.CREATE],
- },
{
label: "Suppliers",
to: "/suppliers",
@@ -103,13 +99,30 @@ const ExpandableSideMenuItem = ({ item }) => (
const SideMenu = () => {
const { groups } = useUserContext();
- const menu = menuData.reduce((result, item) => {
- if (hasRole(item.roles, groups)) {
- result.push(item);
+ const [menu, setMenu] = useState(menuData)
+ const {
+ token: {
+ idToken: { jwtToken: token },
+ },
+ } = useUserContext();
+
+ useEffect(() => {
+ if (groups && token) {
+ const internalEffect = async (token) => {
+ const datasscopeitem = await SupersetItemList(token)
+ menuData.push(datasscopeitem)
+ FilterAccessible(groups, setMenu)
+ }
+
+ internalEffect(token)
}
- return result;
- }, []);
+ }, [groups, token])
+
+ useEffect(() => {
+ FilterAccessible(groups, setMenu)
+ }, [groups])
+
return (
@@ -123,4 +136,36 @@ const SideMenu = () => {
);
};
-export default 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: ,
+ roles: [Roles.READ, Roles.CREATE],
+ submenus: submenus
+ }
+}
+
+export default SideMenu;
\ No newline at end of file
diff --git a/src/components/Layouts/SideMenu.test.jsx b/src/components/Layouts/SideMenu.test.jsx
index fb0cdc2..476a22a 100644
--- a/src/components/Layouts/SideMenu.test.jsx
+++ b/src/components/Layouts/SideMenu.test.jsx
@@ -1,6 +1,7 @@
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 { UserProvider, setToken } from "../Contexts/UserContext";
import { TEST_AUTH_OBJECT } from "../../utils/testing";
@@ -22,17 +23,15 @@ const renderMenu = async () => {
describe("SideMenu", () => {
beforeAll(() => {
addSnapshotSerializer(expect);
- });
- it("Unauthenticated", async () => {
- setToken(null);
- const container = await renderMenu();
- expect(container).toMatchSnapshot();
});
it("Authenticated", async () => {
setToken(TEST_AUTH_OBJECT);
const container = await renderMenu();
+ await waitFor(() => {
+ expect(screen.getByText('Datascope')).toBeInTheDocument()
+ })
expect(container).toMatchSnapshot();
});
});
diff --git a/src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap b/src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap
index 9e9c905..ac71be0 100644
--- a/src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap
+++ b/src/components/Layouts/__snapshots__/SideMenu.test.jsx.snap
@@ -152,42 +152,6 @@ exports[`SideMenu Authenticated 1`] = `
/>
-
-
-
-
-
- Datascope
-
-
-
-
-
-
-
-
-`;
-
-exports[`SideMenu Unauthenticated 1`] = `
-
diff --git a/src/services/__mocks__/superset.js b/src/services/__mocks__/superset.js
new file mode 100644
index 0000000..cd2af34
--- /dev/null
+++ b/src/services/__mocks__/superset.js
@@ -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
\ No newline at end of file
diff --git a/src/services/superset.js b/src/services/superset.js
index 3c13b81..4d13078 100644
--- a/src/services/superset.js
+++ b/src/services/superset.js
@@ -21,15 +21,32 @@ const supersetAPI = {
let q = r["token"]
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: () => {
const SUPERSET_BASE_URL = process.env.REACT_APP_SUPERSET_URL;
return SUPERSET_BASE_URL
},
SupersetDashboardID: () => {
- const SUPERSET_BASE_ID = process.env.REACT_APP_SUPERSET_KEYS_LIST;
- return SUPERSET_BASE_ID
+ return GetSupersetDashboardID()
}
+}
+const GetSupersetDashboardID = () => {
+ const SUPERSET_BASE_ID = process.env.REACT_APP_SUPERSET_KEYS_LIST;
+ return SUPERSET_BASE_ID
}
export default supersetAPI;
\ No newline at end of file
diff --git a/src/services/superset.test.js b/src/services/superset.test.js
new file mode 100644
index 0000000..c5fb037
--- /dev/null
+++ b/src/services/superset.test.js
@@ -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")
+ })
+})
\ No newline at end of file