diff --git a/frontend/src/layout/TreeMenu/TreeMenu.js b/frontend/src/layout/TreeMenu/TreeMenu.js index 9c6c03fa..4edc2f72 100644 --- a/frontend/src/layout/TreeMenu/TreeMenu.js +++ b/frontend/src/layout/TreeMenu/TreeMenu.js @@ -1,10 +1,11 @@ import React, { useState, useEffect, useMemo } from "react"; -import { useResourceDefinitions, Logout, Menu, useGetIdentity, MenuItemLink, useTranslate } from "react-admin"; +import { useResourceDefinitions, Logout, Menu, useGetIdentity, MenuItemLink, useTranslate, useAuthProvider } from "react-admin"; import { useLocation } from "react-router"; import { useMediaQuery, Divider } from "@mui/material"; import DefaultIcon from "@mui/icons-material/ViewList"; import LockOpenIcon from '@mui/icons-material/LockOpen'; import LoginIcon from '@mui/icons-material/Login'; +import { useCreateContainerUri } from "@semapps/semantic-data-provider"; import SubMenu from "./SubMenu"; import ResourceMenuLink from "./ResourceMenuLink"; @@ -17,6 +18,36 @@ const TreeMenu = () => { [resourceDefinitions] ); + const [resourcesPermissions, setResourcesPermissions] = useState({}); + const getCreateContainerUri = useCreateContainerUri(); + const authProvider = useAuthProvider(); + + useEffect(() => { + const fetchPermissions = async () => { + const filteredResources = resources.filter(resource => resource.hasList); + + const names = filteredResources.map(resource => resource.name); + const containersUri = filteredResources.map(resource => getCreateContainerUri(resource.name)); + + if (containersUri.every(uri => !uri)) { + return; + } + + const permissions = await Promise.all(containersUri.map(containerUri => { + return authProvider.getPermissions(containerUri || {}); + })); + + const obj = names.reduce((acc, name, index) => { + acc[name] = permissions[index].some(p => p['acl:mode'] === 'acl:Read'); + return acc; + }, {}); + + setResourcesPermissions(obj); + }; + + fetchPermissions(); + }, [authProvider, resources, getCreateContainerUri]); + const location = useLocation(); const matches = location.pathname.match(/^\/([^/]+)/); const currentResourceName = matches ? matches[1] : null; @@ -40,13 +71,13 @@ const TreeMenu = () => { // Calculate available categories const categories = useMemo(() => { const names = resources.reduce((categories, resource) => { - if (resource.options?.parent) { + if (resource.options?.parent && resource.hasList && resourcesPermissions[resource.name]) { categories.push(resource.options.parent); } return categories; }, []); return resources.filter((resource) => names.includes(resource.name)); - }, [resources]); + }, [resources, resourcesPermissions]); // Open submenu of current page useEffect(() => { @@ -75,13 +106,13 @@ const TreeMenu = () => { icon={menuRootItem.icon ? : } > {resources - .filter(resource => resource.hasList && resource.options.parent === menuRootItem.name) + .filter(resource => resource.hasList && resourcesPermissions[resource.name] && resource.options.parent === menuRootItem.name) .map(resource => ( ))} ) : ( - menuRootItem.hasList && ( + menuRootItem.hasList && resourcesPermissions[menuRootItem.name] && ( ) ); diff --git a/frontend/src/layout/list/ListView.js b/frontend/src/layout/list/ListView.js index 3742ea09..7bce75ec 100644 --- a/frontend/src/layout/list/ListView.js +++ b/frontend/src/layout/list/ListView.js @@ -1,10 +1,18 @@ import React from 'react'; -import { useListContext, Pagination } from 'react-admin'; +import { useListContext, Pagination, useResourceContext } from 'react-admin'; import { Box } from '@mui/material'; +import { useCheckPermissions } from '@semapps/auth-provider'; +import { useCreateContainer } from '@semapps/semantic-data-provider'; import BaseView from "../BaseView"; const ListView = ({ title, children, aside, actions, pagination }) => { const listContext = useListContext(); + + const resource = useResourceContext(); + const containerUri = useCreateContainer(resource); + + useCheckPermissions(containerUri, 'list'); + return(