diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx index 567660fe8d9..60b4e0eccbf 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlobalSetting/GlobalSettingLeftPanel.tsx @@ -11,55 +11,28 @@ * limitations under the License. */ -import { Menu, MenuProps } from 'antd'; +import { Empty, Menu, MenuProps } from 'antd'; import { ItemType } from 'antd/lib/menu/hooks/useItems'; -import { AxiosError } from 'axios'; import { camelCase } from 'lodash'; -import React, { useEffect, useMemo, useState } from 'react'; +import React, { useMemo } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { GLOBAL_SETTING_PERMISSION_RESOURCES } from '../../constants/globalSettings.constants'; import { getGlobalSettingMenuItem, getGlobalSettingsMenuWithPermission, MenuList, } from '../../utils/GlobalSettingsUtils'; import { getSettingPath } from '../../utils/RouterUtils'; -import { showErrorToast } from '../../utils/ToastUtils'; -import Loader from '../Loader/Loader'; import { usePermissionProvider } from '../PermissionProvider/PermissionProvider'; -import { - ResourceEntity, - UIPermission, -} from '../PermissionProvider/PermissionProvider.interface'; const GlobalSettingLeftPanel = () => { const history = useHistory(); const { tab, settingCategory } = useParams<{ [key: string]: string }>(); - const [settingResourcePermission, setSettingResourcePermission] = - useState({} as UIPermission); - const [isLoading, setIsLoading] = useState(true); - - const { getResourcePermission } = usePermissionProvider(); - - const fetchResourcesPermission = async (resource: ResourceEntity) => { - setIsLoading(true); - try { - const response = await getResourcePermission(resource); - setSettingResourcePermission((prev) => ({ - ...prev, - [resource]: response, - })); - } catch (error) { - showErrorToast(error as AxiosError); - } finally { - setIsLoading(false); - } - }; + const { permissions } = usePermissionProvider(); const menuItems: ItemType[] = useMemo( () => - getGlobalSettingsMenuWithPermission(settingResourcePermission).reduce( + getGlobalSettingsMenuWithPermission(permissions).reduce( (acc: ItemType[], curr: MenuList) => { const menuItem = getGlobalSettingMenuItem( curr.category, @@ -77,7 +50,7 @@ const GlobalSettingLeftPanel = () => { }, [] as ItemType[] ), - [setSettingResourcePermission] + [permissions] ); const onClick: MenuProps['onClick'] = (e) => { @@ -86,29 +59,16 @@ const GlobalSettingLeftPanel = () => { history.push(getSettingPath(category, option)); }; - useEffect(() => { - // TODO: This will make number of API calls, need to think of better solution - GLOBAL_SETTING_PERMISSION_RESOURCES.forEach((resource) => { - fetchResourcesPermission(resource); - }); - }, []); - - if (isLoading) { - return ; - } - - return ( - <> - {menuItems.length ? ( - - ) : null} - + return menuItems.length ? ( + + ) : ( + ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx index cf0139162fb..2e5eed3ca89 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx @@ -121,25 +121,12 @@ const PermissionProvider: FC = ({ children }) => { [resource]: operationPermission, })); - /** - * Store updated resource permission - */ - setPermissions((prev) => ({ - ...prev, - [resource]: operationPermission, - })); - return operationPermission; } }; useEffect(() => { - /** - * Only fetch permission if user is logged In - */ - if (currentUser && currentUser.id) { - fetchLoggedInUserPermissions(); - } + fetchLoggedInUserPermissions(); }, [currentUser]); return ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx index a9bdb3450a4..521e020a785 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/UserList/UserListV1.tsx @@ -19,17 +19,22 @@ import React, { FC, useMemo, useState } from 'react'; import { Link, useHistory } from 'react-router-dom'; import { updateUser } from '../../axiosAPIs/userAPI'; import { getUserPath, PAGE_SIZE, ROUTES } from '../../constants/constants'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { CreateUser } from '../../generated/api/teams/createUser'; +import { Operation } from '../../generated/entity/policies/policy'; import { EntityReference, User } from '../../generated/entity/teams/user'; import { Paging } from '../../generated/type/paging'; import jsonData from '../../jsons/en'; import { getEntityName, getTeamsText } from '../../utils/CommonUtils'; +import { checkPermission } from '../../utils/PermissionsUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; import DeleteWidgetModal from '../common/DeleteWidget/DeleteWidgetModal'; import NextPrevious from '../common/next-previous/NextPrevious'; import Searchbar from '../common/searchbar/Searchbar'; import Loader from '../Loader/Loader'; +import { usePermissionProvider } from '../PermissionProvider/PermissionProvider'; +import { ResourceEntity } from '../PermissionProvider/PermissionProvider.interface'; import './usersList.less'; interface UserListV1Props { @@ -57,12 +62,23 @@ const UserListV1: FC = ({ onPagingChange, afterDeleteAction, }) => { + const { permissions } = usePermissionProvider(); const history = useHistory(); const [selectedUser, setSelectedUser] = useState(); const [showDeleteModal, setShowDeleteModal] = useState(false); const [showReactiveModal, setShowReactiveModal] = useState(false); const showRestore = showDeletedUser && !isDataLoading; + const createPermission = useMemo( + () => checkPermission(Operation.Create, ResourceEntity.USER, permissions), + [permissions] + ); + + const deletePermission = useMemo( + () => checkPermission(Operation.Delete, ResourceEntity.USER, permissions), + [permissions] + ); + const handleAddNewUser = () => { history.push(ROUTES.CREATE_USER); }; @@ -156,8 +172,11 @@ const UserListV1: FC = ({ /> )} - + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/non-admin-action/NonAdminAction.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/non-admin-action/NonAdminAction.tsx index 5d29b00c237..88d9354e595 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/non-admin-action/NonAdminAction.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/non-admin-action/NonAdminAction.tsx @@ -28,6 +28,10 @@ type Props = { permission?: Operation; }; +/** + * @deprecated + * TODO: Remove this component once we have new permission structure everywhere + */ const NonAdminAction = ({ children, className = '', diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.test.tsx index f9bab9fbb1d..090b964a564 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.test.tsx @@ -190,6 +190,41 @@ const mockCategory = [ }, ]; +jest.mock('../../components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockReturnValue({ + getEntityPermission: jest.fn().mockReturnValue({ + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + }), + permissions: { + tagCategory: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + }, + tag: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + }, + }, + }), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + checkPermission: jest.fn().mockReturnValue(true), +})); + jest.mock('../../axiosAPIs/tagAPI', () => ({ createTag: jest.fn(), createTagCategory: jest.fn(), diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.tsx index 8e234df2fad..4eb98a9b4d9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/tags/index.tsx @@ -12,14 +12,12 @@ */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Card } from 'antd'; +import { Button, Card, Tooltip } from 'antd'; import { AxiosError } from 'axios'; -import classNames from 'classnames'; import { isEmpty, isUndefined, toLower } from 'lodash'; import { FormErrorData, LoadingState } from 'Models'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { Link, useHistory, useParams } from 'react-router-dom'; -import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'; import { createTag, createTagCategory, @@ -29,11 +27,9 @@ import { updateTag, updateTagCategory, } from '../../axiosAPIs/tagAPI'; -import { Button } from '../../components/buttons/Button/Button'; import Description from '../../components/common/description/Description'; import Ellipses from '../../components/common/Ellipses/Ellipses'; import ErrorPlaceHolder from '../../components/common/error-with-placeholder/ErrorPlaceHolder'; -import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import PageContainerV1 from '../../components/containers/PageContainerV1'; import PageLayout, { @@ -43,7 +39,12 @@ import Loader from '../../components/Loader/Loader'; import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal'; import FormModal from '../../components/Modals/FormModal'; import { ModalWithMarkdownEditor } from '../../components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; -import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { + OperationPermission, + ResourceEntity, +} from '../../components/PermissionProvider/PermissionProvider.interface'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { delimiterRegex } from '../../constants/regex.constants'; import { CreateTagCategory, @@ -52,7 +53,6 @@ import { import { Operation } from '../../generated/entity/policies/accessControl/rule'; import { TagCategory, TagClass } from '../../generated/entity/tags/tagCategory'; import { EntityReference } from '../../generated/type/entityReference'; -import { useAuth } from '../../hooks/authHooks'; import jsonData from '../../jsons/en'; import { getActiveCatClass, @@ -61,6 +61,7 @@ import { isEven, isUrlFriendlyName, } from '../../utils/CommonUtils'; +import { checkPermission } from '../../utils/PermissionsUtils'; import { getExplorePathWithInitFilters, getTagPath, @@ -85,10 +86,9 @@ type DeleteTagsType = { }; const TagsPage = () => { + const { getEntityPermission, permissions } = usePermissionProvider(); const history = useHistory(); const { tagCategoryName } = useParams>(); - const { isAdminUser } = useAuth(); - const { isAuthDisabled } = useAuthContext(); const [categories, setCategoreis] = useState>([]); const [currentCategory, setCurrentCategory] = useState(); const [isEditCategory, setIsEditCategory] = useState(false); @@ -104,6 +104,35 @@ const TagsPage = () => { data: undefined, state: false, }); + const [categoryPermissions, setCategoryPermissions] = + useState({} as OperationPermission); + + const createCategoryPermission = useMemo( + () => + checkPermission( + Operation.Create, + ResourceEntity.TAG_CATEGORY, + permissions + ), + [permissions] + ); + + const createTagPermission = useMemo( + () => checkPermission(Operation.Create, ResourceEntity.TAG, permissions), + [permissions] + ); + + const fetchCurrentCategoryPermission = async () => { + try { + const response = await getEntityPermission( + ResourceEntity.TAG_CATEGORY, + currentCategory?.id as string + ); + setCategoryPermissions(response); + } catch (error) { + showErrorToast(error as AxiosError); + } + }; const fetchCategories = () => { setIsLoading(true); @@ -405,6 +434,7 @@ const TagsPage = () => { setCurrentCategory(categories[0]); if (currentCategory) { setCurrentCategory(currentCategory); + fetchCurrentCategoryPermission(); } }, [categories, currentCategory]); @@ -426,24 +456,25 @@ const TagsPage = () => { style={{ fontSize: '14px' }}> Tag Categories - + - + }> <> @@ -505,44 +536,39 @@ const TagsPage = () => { {currentCategory.displayName ?? currentCategory.name}
- + - - - - + + +
)} @@ -554,6 +580,7 @@ const TagsPage = () => { entityName={ currentCategory?.displayName ?? currentCategory?.name } + hasEditAccess={categoryPermissions.EditDescription} isEdit={isEditCategory} onCancel={() => setIsEditCategory(false)} onDescriptionEdit={() => setIsEditCategory(true)} @@ -605,10 +632,8 @@ const TagsPage = () => { )} - + + {categoryPermissions.EditDescription && ( - + )}
@@ -649,40 +674,37 @@ const TagsPage = () => {
- - - + + ) + ) : ( + + )} +