mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-30 18:17:53 +00:00 
			
		
		
		
	* fix(#12954): restrict roles and policy in settings for admins only * chore: address comments
This commit is contained in:
		
							parent
							
								
									011eaf8ad5
								
							
						
					
					
						commit
						80c11ab4f5
					
				| @ -19,15 +19,16 @@ import { ROUTES } from '../../constants/constants'; | |||||||
| import { useAuth } from '../../hooks/authHooks'; | import { useAuth } from '../../hooks/authHooks'; | ||||||
| 
 | 
 | ||||||
| interface AdminProtectedRouteProps extends RouteProps { | interface AdminProtectedRouteProps extends RouteProps { | ||||||
|   hasPermission: boolean; |   hasPermission?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const AdminProtectedRoute = (routeProps: AdminProtectedRouteProps) => { | const AdminProtectedRoute = (routeProps: AdminProtectedRouteProps) => { | ||||||
|   const { isAdminUser } = useAuth(); |   const { isAdminUser } = useAuth(); | ||||||
|  |   const hasPermission = Boolean(routeProps.hasPermission); | ||||||
| 
 | 
 | ||||||
|   if (isAdminUser || routeProps.hasPermission) { |   if (isAdminUser || hasPermission) { | ||||||
|     return <Route {...routeProps} />; |     return <Route {...routeProps} />; | ||||||
|   } else if (!routeProps.hasPermission) { |   } else if (!hasPermission) { | ||||||
|     return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />; |     return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />; | ||||||
|   } else { |   } else { | ||||||
|     return <Redirect to={ROUTES.SIGNIN} />; |     return <Redirect to={ROUTES.SIGNIN} />; | ||||||
|  | |||||||
| @ -175,17 +175,13 @@ const GlobalSettingRouter = () => { | |||||||
|       <AdminProtectedRoute |       <AdminProtectedRoute | ||||||
|         exact |         exact | ||||||
|         component={RolesListPage} |         component={RolesListPage} | ||||||
|         hasPermission={userPermissions.hasViewPermissions( |  | ||||||
|           ResourceEntity.ROLE, |  | ||||||
|           permissions |  | ||||||
|         )} |  | ||||||
|         path={getSettingPath( |         path={getSettingPath( | ||||||
|           GlobalSettingsMenuCategory.ACCESS, |           GlobalSettingsMenuCategory.ACCESS, | ||||||
|           GlobalSettingOptions.ROLES |           GlobalSettingOptions.ROLES | ||||||
|         )} |         )} | ||||||
|       /> |       /> | ||||||
| 
 | 
 | ||||||
|       <Route |       <AdminProtectedRoute | ||||||
|         exact |         exact | ||||||
|         component={RolesDetailPage} |         component={RolesDetailPage} | ||||||
|         path={getSettingPath( |         path={getSettingPath( | ||||||
| @ -201,16 +197,12 @@ const GlobalSettingRouter = () => { | |||||||
|       <AdminProtectedRoute |       <AdminProtectedRoute | ||||||
|         exact |         exact | ||||||
|         component={PoliciesListPage} |         component={PoliciesListPage} | ||||||
|         hasPermission={userPermissions.hasViewPermissions( |  | ||||||
|           ResourceEntity.POLICY, |  | ||||||
|           permissions |  | ||||||
|         )} |  | ||||||
|         path={getSettingPath( |         path={getSettingPath( | ||||||
|           GlobalSettingsMenuCategory.ACCESS, |           GlobalSettingsMenuCategory.ACCESS, | ||||||
|           GlobalSettingOptions.POLICIES |           GlobalSettingOptions.POLICIES | ||||||
|         )} |         )} | ||||||
|       /> |       /> | ||||||
|       <Route |       <AdminProtectedRoute | ||||||
|         exact |         exact | ||||||
|         component={PoliciesDetailPage} |         component={PoliciesDetailPage} | ||||||
|         path={getSettingPath( |         path={getSettingPath( | ||||||
|  | |||||||
| @ -57,20 +57,6 @@ jest.mock('components/Loader/Loader', () => | |||||||
|   jest.fn().mockReturnValue(<div>Loader</div>) |   jest.fn().mockReturnValue(<div>Loader</div>) | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| jest.mock('components/PermissionProvider/PermissionProvider', () => ({ |  | ||||||
|   usePermissionProvider: jest.fn().mockReturnValue({ |  | ||||||
|     getEntityPermissionByFqn: jest.fn().mockReturnValue({ |  | ||||||
|       Create: true, |  | ||||||
|       Delete: true, |  | ||||||
|       ViewAll: true, |  | ||||||
|       EditAll: true, |  | ||||||
|       EditDescription: true, |  | ||||||
|       EditDisplayName: true, |  | ||||||
|       EditCustomFields: true, |  | ||||||
|     }), |  | ||||||
|   }), |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| jest.mock('../../../constants/HelperTextUtil', () => ({ | jest.mock('../../../constants/HelperTextUtil', () => ({ | ||||||
|   NO_PERMISSION_FOR_ACTION: '', |   NO_PERMISSION_FOR_ACTION: '', | ||||||
|   NO_PERMISSION_TO_VIEW: '', |   NO_PERMISSION_TO_VIEW: '', | ||||||
| @ -80,18 +66,6 @@ jest.mock('../../../utils/CommonUtils', () => ({ | |||||||
|   getEntityName: jest.fn().mockReturnValue(''), |   getEntityName: jest.fn().mockReturnValue(''), | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
| jest.mock('../../../utils/PermissionsUtils', () => ({ |  | ||||||
|   DEFAULT_ENTITY_PERMISSION: { |  | ||||||
|     Create: true, |  | ||||||
|     Delete: true, |  | ||||||
|     ViewAll: true, |  | ||||||
|     EditAll: true, |  | ||||||
|     EditDescription: true, |  | ||||||
|     EditDisplayName: true, |  | ||||||
|     EditCustomFields: true, |  | ||||||
|   }, |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| jest.mock('../../../utils/RouterUtils', () => ({ | jest.mock('../../../utils/RouterUtils', () => ({ | ||||||
|   getAddPolicyRulePath: jest.fn(), |   getAddPolicyRulePath: jest.fn(), | ||||||
|   getEditPolicyRulePath: jest.fn(), |   getEditPolicyRulePath: jest.fn(), | ||||||
|  | |||||||
| @ -22,7 +22,6 @@ import { | |||||||
|   Row, |   Row, | ||||||
|   Space, |   Space, | ||||||
|   Tabs, |   Tabs, | ||||||
|   Tooltip, |  | ||||||
|   Typography, |   Typography, | ||||||
| } from 'antd'; | } from 'antd'; | ||||||
| import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg'; | import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg'; | ||||||
| @ -32,12 +31,6 @@ import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlac | |||||||
| import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer'; | import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer'; | ||||||
| import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component'; | import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component'; | ||||||
| import Loader from 'components/Loader/Loader'; | import Loader from 'components/Loader/Loader'; | ||||||
| import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; |  | ||||||
| import { |  | ||||||
|   OperationPermission, |  | ||||||
|   ResourceEntity, |  | ||||||
| } from 'components/PermissionProvider/PermissionProvider.interface'; |  | ||||||
| import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum'; |  | ||||||
| import { compare } from 'fast-json-patch'; | import { compare } from 'fast-json-patch'; | ||||||
| import { isEmpty, isUndefined, startCase } from 'lodash'; | import { isEmpty, isUndefined, startCase } from 'lodash'; | ||||||
| import React, { useCallback, useEffect, useMemo, useState } from 'react'; | import React, { useCallback, useEffect, useMemo, useState } from 'react'; | ||||||
| @ -59,7 +52,6 @@ import { EntityType } from '../../../enums/entity.enum'; | |||||||
| import { Rule } from '../../../generated/api/policies/createPolicy'; | import { Rule } from '../../../generated/api/policies/createPolicy'; | ||||||
| import { Policy } from '../../../generated/entity/policies/policy'; | import { Policy } from '../../../generated/entity/policies/policy'; | ||||||
| import { EntityReference } from '../../../generated/type/entityReference'; | import { EntityReference } from '../../../generated/type/entityReference'; | ||||||
| import { DEFAULT_ENTITY_PERMISSION } from '../../../utils/PermissionsUtils'; |  | ||||||
| import { | import { | ||||||
|   getAddPolicyRulePath, |   getAddPolicyRulePath, | ||||||
|   getEditPolicyRulePath, |   getEditPolicyRulePath, | ||||||
| @ -78,7 +70,6 @@ const PoliciesDetailPage = () => { | |||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const history = useHistory(); |   const history = useHistory(); | ||||||
|   const { fqn } = useParams<{ fqn: string }>(); |   const { fqn } = useParams<{ fqn: string }>(); | ||||||
|   const { getEntityPermissionByFqn } = usePermissionProvider(); |  | ||||||
| 
 | 
 | ||||||
|   const [policy, setPolicy] = useState<Policy>({} as Policy); |   const [policy, setPolicy] = useState<Policy>({} as Policy); | ||||||
|   const [isLoading, setLoading] = useState<boolean>(false); |   const [isLoading, setLoading] = useState<boolean>(false); | ||||||
| @ -87,10 +78,6 @@ const PoliciesDetailPage = () => { | |||||||
|   const [selectedEntity, setEntity] = |   const [selectedEntity, setEntity] = | ||||||
|     useState<{ attribute: Attribute; record: EntityReference }>(); |     useState<{ attribute: Attribute; record: EntityReference }>(); | ||||||
| 
 | 
 | ||||||
|   const [policyPermission, setPolicyPermission] = useState<OperationPermission>( |  | ||||||
|     DEFAULT_ENTITY_PERMISSION |  | ||||||
|   ); |  | ||||||
| 
 |  | ||||||
|   const policiesPath = getSettingPath( |   const policiesPath = getSettingPath( | ||||||
|     GlobalSettingsMenuCategory.ACCESS, |     GlobalSettingsMenuCategory.ACCESS, | ||||||
|     GlobalSettingOptions.POLICIES |     GlobalSettingOptions.POLICIES | ||||||
| @ -110,21 +97,6 @@ const PoliciesDetailPage = () => { | |||||||
|     [policy] |     [policy] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   const fetchPolicyPermission = async () => { |  | ||||||
|     setLoading(true); |  | ||||||
|     try { |  | ||||||
|       const response = await getEntityPermissionByFqn( |  | ||||||
|         ResourceEntity.POLICY, |  | ||||||
|         fqn |  | ||||||
|       ); |  | ||||||
|       setPolicyPermission(response); |  | ||||||
|     } catch (error) { |  | ||||||
|       showErrorToast(error as AxiosError); |  | ||||||
|     } finally { |  | ||||||
|       setLoading(false); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const fetchPolicy = async () => { |   const fetchPolicy = async () => { | ||||||
|     setLoading(true); |     setLoading(true); | ||||||
|     try { |     try { | ||||||
| @ -256,7 +228,6 @@ const PoliciesDetailPage = () => { | |||||||
|     (rule: Rule) => { |     (rule: Rule) => { | ||||||
|       return ( |       return ( | ||||||
|         <Dropdown |         <Dropdown | ||||||
|           disabled={!policyPermission.EditAll} |  | ||||||
|           overlay={ |           overlay={ | ||||||
|             <Menu |             <Menu | ||||||
|               items={[ |               items={[ | ||||||
| @ -307,39 +278,25 @@ const PoliciesDetailPage = () => { | |||||||
|           } |           } | ||||||
|           placement="bottomRight" |           placement="bottomRight" | ||||||
|           trigger={['click']}> |           trigger={['click']}> | ||||||
|           <Tooltip |           <Button | ||||||
|             title={ |             data-testid={`manage-button-${rule.name}`} | ||||||
|               policyPermission.EditAll |             icon={<EllipsisOutlined className="text-grey-body" rotate={90} />} | ||||||
|                 ? t('label.manage-rule') |             size="small" | ||||||
|                 : t('message.no-permission-for-action') |             type="text" | ||||||
|             }> |             onClick={(e) => { | ||||||
|             <Button |               e.stopPropagation(); | ||||||
|               data-testid={`manage-button-${rule.name}`} |             }} | ||||||
|               disabled={!policyPermission.EditAll} |           /> | ||||||
|               icon={<EllipsisOutlined className="text-grey-body" rotate={90} />} |  | ||||||
|               size="small" |  | ||||||
|               type="text" |  | ||||||
|               onClick={(e) => { |  | ||||||
|                 e.stopPropagation(); |  | ||||||
|               }} |  | ||||||
|             /> |  | ||||||
|           </Tooltip> |  | ||||||
|         </Dropdown> |         </Dropdown> | ||||||
|       ); |       ); | ||||||
|     }, |     }, | ||||||
|     [policy, policyPermission] |     [policy] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     fetchPolicyPermission(); |     fetchPolicy(); | ||||||
|   }, [fqn]); |   }, [fqn]); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |  | ||||||
|     if (policyPermission.ViewAll || policyPermission.ViewBasic) { |  | ||||||
|       fetchPolicy(); |  | ||||||
|     } |  | ||||||
|   }, [policyPermission, fqn]); |  | ||||||
| 
 |  | ||||||
|   if (isLoading) { |   if (isLoading) { | ||||||
|     return <Loader />; |     return <Loader />; | ||||||
|   } |   } | ||||||
| @ -347,198 +304,178 @@ const PoliciesDetailPage = () => { | |||||||
|   return ( |   return ( | ||||||
|     <div data-testid="policy-details-container"> |     <div data-testid="policy-details-container"> | ||||||
|       <TitleBreadcrumb titleLinks={breadcrumb} /> |       <TitleBreadcrumb titleLinks={breadcrumb} /> | ||||||
|       {policyPermission.ViewAll || policyPermission.ViewBasic ? ( |  | ||||||
|         <> |  | ||||||
|           {isEmpty(policy) ? ( |  | ||||||
|             <ErrorPlaceHolder> |  | ||||||
|               <div className="text-center"> |  | ||||||
|                 <p> |  | ||||||
|                   {t('message.no-entity-found-for-name', { |  | ||||||
|                     entity: t('label.policy-lowercase'), |  | ||||||
|                     name: fqn, |  | ||||||
|                   })} |  | ||||||
|                 </p> |  | ||||||
|                 <Button |  | ||||||
|                   size="small" |  | ||||||
|                   type="primary" |  | ||||||
|                   onClick={() => history.push(policiesPath)}> |  | ||||||
|                   {t('label.go-back')} |  | ||||||
|                 </Button> |  | ||||||
|               </div> |  | ||||||
|             </ErrorPlaceHolder> |  | ||||||
|           ) : ( |  | ||||||
|             <div className="policies-detail" data-testid="policy-details"> |  | ||||||
|               <Typography.Title |  | ||||||
|                 className="m-b-0 m-t-xs" |  | ||||||
|                 data-testid="heading" |  | ||||||
|                 level={5}> |  | ||||||
|                 {getEntityName(policy)} |  | ||||||
|               </Typography.Title> |  | ||||||
|               <Description |  | ||||||
|                 className="m-b-md" |  | ||||||
|                 description={policy.description || ''} |  | ||||||
|                 entityFqn={policy.fullyQualifiedName} |  | ||||||
|                 entityName={getEntityName(policy)} |  | ||||||
|                 entityType={EntityType.POLICY} |  | ||||||
|                 hasEditAccess={ |  | ||||||
|                   policyPermission.EditAll || policyPermission.EditDescription |  | ||||||
|                 } |  | ||||||
|                 isEdit={editDescription} |  | ||||||
|                 onCancel={() => setEditDescription(false)} |  | ||||||
|                 onDescriptionEdit={() => setEditDescription(true)} |  | ||||||
|                 onDescriptionUpdate={handleDescriptionUpdate} |  | ||||||
|               /> |  | ||||||
| 
 | 
 | ||||||
|               <Tabs defaultActiveKey="rules"> |       <> | ||||||
|                 <TabPane key="rules" tab={t('label.rule-plural')}> |         {isEmpty(policy) ? ( | ||||||
|                   {isEmpty(policy.rules) ? ( |           <ErrorPlaceHolder> | ||||||
|                     <ErrorPlaceHolder /> |             <div className="text-center"> | ||||||
|                   ) : ( |               <p> | ||||||
|                     <Space |                 {t('message.no-entity-found-for-name', { | ||||||
|                       className="w-full tabpane-space" |                   entity: t('label.policy-lowercase'), | ||||||
|                       direction="vertical"> |                   name: fqn, | ||||||
|                       <Tooltip |                 })} | ||||||
|                         title={ |               </p> | ||||||
|                           policyPermission.EditAll |               <Button | ||||||
|                             ? t('label.add-entity', { |                 size="small" | ||||||
|                                 entity: t('label.rule'), |                 type="primary" | ||||||
|                               }) |                 onClick={() => history.push(policiesPath)}> | ||||||
|                             : t('message.no-permission-for-action') |                 {t('label.go-back')} | ||||||
|                         }> |               </Button> | ||||||
|                         <Button |  | ||||||
|                           data-testid="add-rule" |  | ||||||
|                           disabled={!policyPermission.EditAll} |  | ||||||
|                           type="primary" |  | ||||||
|                           onClick={() => |  | ||||||
|                             history.push(getAddPolicyRulePath(fqn)) |  | ||||||
|                           }> |  | ||||||
|                           {t('label.add-entity', { |  | ||||||
|                             entity: t('label.rule'), |  | ||||||
|                           })} |  | ||||||
|                         </Button> |  | ||||||
|                       </Tooltip> |  | ||||||
| 
 |  | ||||||
|                       <Space className="w-full" direction="vertical" size={20}> |  | ||||||
|                         {policy.rules.map((rule) => ( |  | ||||||
|                           <Card |  | ||||||
|                             data-testid="rule-card" |  | ||||||
|                             key={rule.name || 'rule'}> |  | ||||||
|                             <Space |  | ||||||
|                               align="baseline" |  | ||||||
|                               className="w-full justify-between p-b-lg" |  | ||||||
|                               direction="horizontal"> |  | ||||||
|                               <Typography.Text |  | ||||||
|                                 className="font-medium text-base text-grey-body" |  | ||||||
|                                 data-testid="rule-name"> |  | ||||||
|                                 {rule.name} |  | ||||||
|                               </Typography.Text> |  | ||||||
|                               {getRuleActionElement(rule)} |  | ||||||
|                             </Space> |  | ||||||
| 
 |  | ||||||
|                             <Space |  | ||||||
|                               className="w-full" |  | ||||||
|                               direction="vertical" |  | ||||||
|                               size={12}> |  | ||||||
|                               {rule.description && ( |  | ||||||
|                                 <Row data-testid="description"> |  | ||||||
|                                   <Col span={2}> |  | ||||||
|                                     <Typography.Text className="text-grey-muted"> |  | ||||||
|                                       {`${t('label.description')}:`} |  | ||||||
|                                     </Typography.Text> |  | ||||||
|                                   </Col> |  | ||||||
|                                   <Col span={22}> |  | ||||||
|                                     <RichTextEditorPreviewer |  | ||||||
|                                       markdown={rule.description || ''} |  | ||||||
|                                     /> |  | ||||||
|                                   </Col> |  | ||||||
|                                 </Row> |  | ||||||
|                               )} |  | ||||||
| 
 |  | ||||||
|                               <Row data-testid="resources"> |  | ||||||
|                                 <Col span={2}> |  | ||||||
|                                   <Typography.Text className="text-grey-muted m-b-0"> |  | ||||||
|                                     {`${t('label.resource-plural')}:`} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                                 <Col span={22}> |  | ||||||
|                                   <Typography.Text className="text-grey-body"> |  | ||||||
|                                     {rule.resources |  | ||||||
|                                       ?.map((resource) => startCase(resource)) |  | ||||||
|                                       ?.join(', ')} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                               </Row> |  | ||||||
| 
 |  | ||||||
|                               <Row data-testid="operations"> |  | ||||||
|                                 <Col span={2}> |  | ||||||
|                                   <Typography.Text className="text-grey-muted"> |  | ||||||
|                                     {`${t('label.operation-plural')}:`} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                                 <Col span={22}> |  | ||||||
|                                   <Typography.Text className="text-grey-body"> |  | ||||||
|                                     {rule.operations?.join(', ')} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                               </Row> |  | ||||||
|                               <Row data-testid="effect"> |  | ||||||
|                                 <Col span={2}> |  | ||||||
|                                   <Typography.Text className="text-grey-muted"> |  | ||||||
|                                     {`${t('label.effect')}:`} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                                 <Col span={22}> |  | ||||||
|                                   <Typography.Text className="text-grey-body"> |  | ||||||
|                                     {startCase(rule.effect)} |  | ||||||
|                                   </Typography.Text> |  | ||||||
|                                 </Col> |  | ||||||
|                               </Row> |  | ||||||
|                               {rule.condition && ( |  | ||||||
|                                 <Row data-testid="condition"> |  | ||||||
|                                   <Col span={2}> |  | ||||||
|                                     <Typography.Text className="text-grey-muted"> |  | ||||||
|                                       {`${t('label.condition')}:`} |  | ||||||
|                                     </Typography.Text> |  | ||||||
|                                   </Col> |  | ||||||
|                                   <Col span={22}> |  | ||||||
|                                     <code>{rule.condition}</code> |  | ||||||
|                                   </Col> |  | ||||||
|                                 </Row> |  | ||||||
|                               )} |  | ||||||
|                             </Space> |  | ||||||
|                           </Card> |  | ||||||
|                         ))} |  | ||||||
|                       </Space> |  | ||||||
|                     </Space> |  | ||||||
|                   )} |  | ||||||
|                 </TabPane> |  | ||||||
|                 <TabPane key="roles" tab={t('label.role-plural')}> |  | ||||||
|                   <PoliciesDetailsList |  | ||||||
|                     hasAccess={policyPermission.EditAll} |  | ||||||
|                     list={policy.roles ?? []} |  | ||||||
|                     type="role" |  | ||||||
|                     onDelete={(record) => |  | ||||||
|                       setEntity({ record, attribute: 'roles' }) |  | ||||||
|                     } |  | ||||||
|                   /> |  | ||||||
|                 </TabPane> |  | ||||||
|                 <TabPane key="teams" tab={t('label.team-plural')}> |  | ||||||
|                   <PoliciesDetailsList |  | ||||||
|                     hasAccess={policyPermission.EditAll} |  | ||||||
|                     list={policy.teams ?? []} |  | ||||||
|                     type="team" |  | ||||||
|                     onDelete={(record) => |  | ||||||
|                       setEntity({ record, attribute: 'teams' }) |  | ||||||
|                     } |  | ||||||
|                   /> |  | ||||||
|                 </TabPane> |  | ||||||
|               </Tabs> |  | ||||||
|             </div> |             </div> | ||||||
|           )} |           </ErrorPlaceHolder> | ||||||
|         </> |         ) : ( | ||||||
|       ) : ( |           <div className="policies-detail" data-testid="policy-details"> | ||||||
|         <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} /> |             <Typography.Title | ||||||
|       )} |               className="m-b-0 m-t-xs" | ||||||
|  |               data-testid="heading" | ||||||
|  |               level={5}> | ||||||
|  |               {getEntityName(policy)} | ||||||
|  |             </Typography.Title> | ||||||
|  |             <Description | ||||||
|  |               hasEditAccess | ||||||
|  |               className="m-b-md" | ||||||
|  |               description={policy.description || ''} | ||||||
|  |               entityFqn={policy.fullyQualifiedName} | ||||||
|  |               entityName={getEntityName(policy)} | ||||||
|  |               entityType={EntityType.POLICY} | ||||||
|  |               isEdit={editDescription} | ||||||
|  |               onCancel={() => setEditDescription(false)} | ||||||
|  |               onDescriptionEdit={() => setEditDescription(true)} | ||||||
|  |               onDescriptionUpdate={handleDescriptionUpdate} | ||||||
|  |             /> | ||||||
|  | 
 | ||||||
|  |             <Tabs defaultActiveKey="rules"> | ||||||
|  |               <TabPane key="rules" tab={t('label.rule-plural')}> | ||||||
|  |                 {isEmpty(policy.rules) ? ( | ||||||
|  |                   <ErrorPlaceHolder /> | ||||||
|  |                 ) : ( | ||||||
|  |                   <Space className="w-full tabpane-space" direction="vertical"> | ||||||
|  |                     <Button | ||||||
|  |                       data-testid="add-rule" | ||||||
|  |                       type="primary" | ||||||
|  |                       onClick={() => history.push(getAddPolicyRulePath(fqn))}> | ||||||
|  |                       {t('label.add-entity', { | ||||||
|  |                         entity: t('label.rule'), | ||||||
|  |                       })} | ||||||
|  |                     </Button> | ||||||
|  | 
 | ||||||
|  |                     <Space className="w-full" direction="vertical" size={20}> | ||||||
|  |                       {policy.rules.map((rule) => ( | ||||||
|  |                         <Card data-testid="rule-card" key={rule.name || 'rule'}> | ||||||
|  |                           <Space | ||||||
|  |                             align="baseline" | ||||||
|  |                             className="w-full justify-between p-b-lg" | ||||||
|  |                             direction="horizontal"> | ||||||
|  |                             <Typography.Text | ||||||
|  |                               className="font-medium text-base text-grey-body" | ||||||
|  |                               data-testid="rule-name"> | ||||||
|  |                               {rule.name} | ||||||
|  |                             </Typography.Text> | ||||||
|  |                             {getRuleActionElement(rule)} | ||||||
|  |                           </Space> | ||||||
|  | 
 | ||||||
|  |                           <Space | ||||||
|  |                             className="w-full" | ||||||
|  |                             direction="vertical" | ||||||
|  |                             size={12}> | ||||||
|  |                             {rule.description && ( | ||||||
|  |                               <Row data-testid="description"> | ||||||
|  |                                 <Col span={2}> | ||||||
|  |                                   <Typography.Text className="text-grey-muted"> | ||||||
|  |                                     {`${t('label.description')}:`} | ||||||
|  |                                   </Typography.Text> | ||||||
|  |                                 </Col> | ||||||
|  |                                 <Col span={22}> | ||||||
|  |                                   <RichTextEditorPreviewer | ||||||
|  |                                     markdown={rule.description || ''} | ||||||
|  |                                   /> | ||||||
|  |                                 </Col> | ||||||
|  |                               </Row> | ||||||
|  |                             )} | ||||||
|  | 
 | ||||||
|  |                             <Row data-testid="resources"> | ||||||
|  |                               <Col span={2}> | ||||||
|  |                                 <Typography.Text className="text-grey-muted m-b-0"> | ||||||
|  |                                   {`${t('label.resource-plural')}:`} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                               <Col span={22}> | ||||||
|  |                                 <Typography.Text className="text-grey-body"> | ||||||
|  |                                   {rule.resources | ||||||
|  |                                     ?.map((resource) => startCase(resource)) | ||||||
|  |                                     ?.join(', ')} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                             </Row> | ||||||
|  | 
 | ||||||
|  |                             <Row data-testid="operations"> | ||||||
|  |                               <Col span={2}> | ||||||
|  |                                 <Typography.Text className="text-grey-muted"> | ||||||
|  |                                   {`${t('label.operation-plural')}:`} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                               <Col span={22}> | ||||||
|  |                                 <Typography.Text className="text-grey-body"> | ||||||
|  |                                   {rule.operations?.join(', ')} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                             </Row> | ||||||
|  |                             <Row data-testid="effect"> | ||||||
|  |                               <Col span={2}> | ||||||
|  |                                 <Typography.Text className="text-grey-muted"> | ||||||
|  |                                   {`${t('label.effect')}:`} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                               <Col span={22}> | ||||||
|  |                                 <Typography.Text className="text-grey-body"> | ||||||
|  |                                   {startCase(rule.effect)} | ||||||
|  |                                 </Typography.Text> | ||||||
|  |                               </Col> | ||||||
|  |                             </Row> | ||||||
|  |                             {rule.condition && ( | ||||||
|  |                               <Row data-testid="condition"> | ||||||
|  |                                 <Col span={2}> | ||||||
|  |                                   <Typography.Text className="text-grey-muted"> | ||||||
|  |                                     {`${t('label.condition')}:`} | ||||||
|  |                                   </Typography.Text> | ||||||
|  |                                 </Col> | ||||||
|  |                                 <Col span={22}> | ||||||
|  |                                   <code>{rule.condition}</code> | ||||||
|  |                                 </Col> | ||||||
|  |                               </Row> | ||||||
|  |                             )} | ||||||
|  |                           </Space> | ||||||
|  |                         </Card> | ||||||
|  |                       ))} | ||||||
|  |                     </Space> | ||||||
|  |                   </Space> | ||||||
|  |                 )} | ||||||
|  |               </TabPane> | ||||||
|  |               <TabPane key="roles" tab={t('label.role-plural')}> | ||||||
|  |                 <PoliciesDetailsList | ||||||
|  |                   hasAccess | ||||||
|  |                   list={policy.roles ?? []} | ||||||
|  |                   type="role" | ||||||
|  |                   onDelete={(record) => | ||||||
|  |                     setEntity({ record, attribute: 'roles' }) | ||||||
|  |                   } | ||||||
|  |                 /> | ||||||
|  |               </TabPane> | ||||||
|  |               <TabPane key="teams" tab={t('label.team-plural')}> | ||||||
|  |                 <PoliciesDetailsList | ||||||
|  |                   hasAccess | ||||||
|  |                   list={policy.teams ?? []} | ||||||
|  |                   type="team" | ||||||
|  |                   onDelete={(record) => | ||||||
|  |                     setEntity({ record, attribute: 'teams' }) | ||||||
|  |                   } | ||||||
|  |                 /> | ||||||
|  |               </TabPane> | ||||||
|  |             </Tabs> | ||||||
|  |           </div> | ||||||
|  |         )} | ||||||
|  |       </> | ||||||
|  | 
 | ||||||
|       {selectedEntity && ( |       {selectedEntity && ( | ||||||
|         <Modal |         <Modal | ||||||
|           centered |           centered | ||||||
|  | |||||||
| @ -60,20 +60,6 @@ jest.mock('../../../utils/RouterUtils', () => ({ | |||||||
|   getTeamsWithFqnPath: jest.fn(), |   getTeamsWithFqnPath: jest.fn(), | ||||||
| })); | })); | ||||||
| 
 | 
 | ||||||
| jest.mock('components/PermissionProvider/PermissionProvider', () => ({ |  | ||||||
|   usePermissionProvider: jest.fn().mockReturnValue({ |  | ||||||
|     getEntityPermissionByFqn: jest.fn().mockReturnValue({ |  | ||||||
|       Create: true, |  | ||||||
|       Delete: true, |  | ||||||
|       ViewAll: true, |  | ||||||
|       EditAll: true, |  | ||||||
|       EditDescription: true, |  | ||||||
|       EditDisplayName: true, |  | ||||||
|       EditCustomFields: true, |  | ||||||
|     }), |  | ||||||
|   }), |  | ||||||
| })); |  | ||||||
| 
 |  | ||||||
| describe('Test Roles Details Page', () => { | describe('Test Roles Details Page', () => { | ||||||
|   it('Should render the detail component', async () => { |   it('Should render the detail component', async () => { | ||||||
|     render(<RolesDetailPage />); |     render(<RolesDetailPage />); | ||||||
|  | |||||||
| @ -11,17 +11,12 @@ | |||||||
|  *  limitations under the License. |  *  limitations under the License. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { Button, Modal, Space, Tabs, Tooltip, Typography } from 'antd'; | import { Button, Modal, Space, Tabs, Typography } from 'antd'; | ||||||
| import { AxiosError } from 'axios'; | import { AxiosError } from 'axios'; | ||||||
| import Description from 'components/common/description/Description'; | import Description from 'components/common/description/Description'; | ||||||
| import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder'; | import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder'; | ||||||
| import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component'; | import TitleBreadcrumb from 'components/common/title-breadcrumb/title-breadcrumb.component'; | ||||||
| import Loader from 'components/Loader/Loader'; | import Loader from 'components/Loader/Loader'; | ||||||
| import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider'; |  | ||||||
| import { |  | ||||||
|   OperationPermission, |  | ||||||
|   ResourceEntity, |  | ||||||
| } from 'components/PermissionProvider/PermissionProvider.interface'; |  | ||||||
| import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum'; | import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum'; | ||||||
| import { compare } from 'fast-json-patch'; | import { compare } from 'fast-json-patch'; | ||||||
| import { isEmpty, isUndefined } from 'lodash'; | import { isEmpty, isUndefined } from 'lodash'; | ||||||
| @ -39,7 +34,6 @@ import { | |||||||
| import { EntityType } from '../../../enums/entity.enum'; | import { EntityType } from '../../../enums/entity.enum'; | ||||||
| import { Role } from '../../../generated/entity/teams/role'; | import { Role } from '../../../generated/entity/teams/role'; | ||||||
| import { EntityReference } from '../../../generated/type/entityReference'; | import { EntityReference } from '../../../generated/type/entityReference'; | ||||||
| import { DEFAULT_ENTITY_PERMISSION } from '../../../utils/PermissionsUtils'; |  | ||||||
| import { getSettingPath } from '../../../utils/RouterUtils'; | import { getSettingPath } from '../../../utils/RouterUtils'; | ||||||
| import { showErrorToast } from '../../../utils/ToastUtils'; | import { showErrorToast } from '../../../utils/ToastUtils'; | ||||||
| import AddAttributeModal from '../AddAttributeModal/AddAttributeModal'; | import AddAttributeModal from '../AddAttributeModal/AddAttributeModal'; | ||||||
| @ -58,7 +52,6 @@ interface AddAttribute { | |||||||
| const RolesDetailPage = () => { | const RolesDetailPage = () => { | ||||||
|   const history = useHistory(); |   const history = useHistory(); | ||||||
|   const { t } = useTranslation(); |   const { t } = useTranslation(); | ||||||
|   const { getEntityPermissionByFqn } = usePermissionProvider(); |  | ||||||
|   const { fqn } = useParams<{ fqn: string }>(); |   const { fqn } = useParams<{ fqn: string }>(); | ||||||
| 
 | 
 | ||||||
|   const [role, setRole] = useState<Role>({} as Role); |   const [role, setRole] = useState<Role>({} as Role); | ||||||
| @ -70,10 +63,6 @@ const RolesDetailPage = () => { | |||||||
| 
 | 
 | ||||||
|   const [addAttribute, setAddAttribute] = useState<AddAttribute>(); |   const [addAttribute, setAddAttribute] = useState<AddAttribute>(); | ||||||
| 
 | 
 | ||||||
|   const [rolePermission, setRolePermission] = useState<OperationPermission>( |  | ||||||
|     DEFAULT_ENTITY_PERMISSION |  | ||||||
|   ); |  | ||||||
| 
 |  | ||||||
|   const rolesPath = getSettingPath( |   const rolesPath = getSettingPath( | ||||||
|     GlobalSettingsMenuCategory.ACCESS, |     GlobalSettingsMenuCategory.ACCESS, | ||||||
|     GlobalSettingOptions.ROLES |     GlobalSettingOptions.ROLES | ||||||
| @ -93,18 +82,6 @@ const RolesDetailPage = () => { | |||||||
|     [role] |     [role] | ||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   const fetchRolePermission = async () => { |  | ||||||
|     setLoading(true); |  | ||||||
|     try { |  | ||||||
|       const response = await getEntityPermissionByFqn(ResourceEntity.ROLE, fqn); |  | ||||||
|       setRolePermission(response); |  | ||||||
|     } catch (error) { |  | ||||||
|       showErrorToast(error as AxiosError); |  | ||||||
|     } finally { |  | ||||||
|       setLoading(false); |  | ||||||
|     } |  | ||||||
|   }; |  | ||||||
| 
 |  | ||||||
|   const fetchRole = async () => { |   const fetchRole = async () => { | ||||||
|     setLoading(true); |     setLoading(true); | ||||||
|     try { |     try { | ||||||
| @ -238,15 +215,9 @@ const RolesDetailPage = () => { | |||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     fetchRolePermission(); |     fetchRole(); | ||||||
|   }, [fqn]); |   }, [fqn]); | ||||||
| 
 | 
 | ||||||
|   useEffect(() => { |  | ||||||
|     if (rolePermission.ViewAll || rolePermission.ViewBasic) { |  | ||||||
|       fetchRole(); |  | ||||||
|     } |  | ||||||
|   }, [rolePermission, fqn]); |  | ||||||
| 
 |  | ||||||
|   if (isLoading) { |   if (isLoading) { | ||||||
|     return <Loader />; |     return <Loader />; | ||||||
|   } |   } | ||||||
| @ -254,112 +225,99 @@ const RolesDetailPage = () => { | |||||||
|   return ( |   return ( | ||||||
|     <div data-testid="role-details-container"> |     <div data-testid="role-details-container"> | ||||||
|       <TitleBreadcrumb titleLinks={breadcrumb} /> |       <TitleBreadcrumb titleLinks={breadcrumb} /> | ||||||
|       {rolePermission.ViewAll || rolePermission.ViewBasic ? ( |  | ||||||
|         <> |  | ||||||
|           {isEmpty(role) ? ( |  | ||||||
|             <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.CUSTOM}> |  | ||||||
|               <div className="text-center"> |  | ||||||
|                 <p> |  | ||||||
|                   {t('message.no-entity-found-for-name', { |  | ||||||
|                     entity: t('label.role'), |  | ||||||
|                     name: fqn, |  | ||||||
|                   })} |  | ||||||
|                 </p> |  | ||||||
|                 <Button |  | ||||||
|                   ghost |  | ||||||
|                   className="m-t-sm" |  | ||||||
|                   type="primary" |  | ||||||
|                   onClick={() => history.push(rolesPath)}> |  | ||||||
|                   {t('label.go-back')} |  | ||||||
|                 </Button> |  | ||||||
|               </div> |  | ||||||
|             </ErrorPlaceHolder> |  | ||||||
|           ) : ( |  | ||||||
|             <div className="roles-detail" data-testid="role-details"> |  | ||||||
|               <Typography.Title |  | ||||||
|                 className="m-b-0 m-t-xs" |  | ||||||
|                 data-testid="heading" |  | ||||||
|                 level={5}> |  | ||||||
|                 {getEntityName(role)} |  | ||||||
|               </Typography.Title> |  | ||||||
|               <Description |  | ||||||
|                 className="m-b-md" |  | ||||||
|                 description={role.description || ''} |  | ||||||
|                 entityFqn={role.fullyQualifiedName} |  | ||||||
|                 entityName={getEntityName(role)} |  | ||||||
|                 entityType={EntityType.ROLE} |  | ||||||
|                 hasEditAccess={ |  | ||||||
|                   rolePermission.EditAll || rolePermission.EditDescription |  | ||||||
|                 } |  | ||||||
|                 isEdit={editDescription} |  | ||||||
|                 onCancel={() => setEditDescription(false)} |  | ||||||
|                 onDescriptionEdit={() => setEditDescription(true)} |  | ||||||
|                 onDescriptionUpdate={handleDescriptionUpdate} |  | ||||||
|               /> |  | ||||||
| 
 | 
 | ||||||
|               <Tabs data-testid="tabs" defaultActiveKey="policies"> |       <> | ||||||
|                 <TabPane key="policies" tab={t('label.policy-plural')}> |         {isEmpty(role) ? ( | ||||||
|                   <Space className="w-full" direction="vertical"> |           <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.CUSTOM}> | ||||||
|                     <Tooltip |             <div className="text-center"> | ||||||
|                       title={ |               <p> | ||||||
|                         rolePermission.EditAll |                 {t('message.no-entity-found-for-name', { | ||||||
|                           ? t('label.add-entity', { |                   entity: t('label.role'), | ||||||
|                               entity: t('label.policy'), |                   name: fqn, | ||||||
|                             }) |                 })} | ||||||
|                           : t('message.no-permission-for-action') |               </p> | ||||||
|                       }> |               <Button | ||||||
|                       <Button |                 ghost | ||||||
|                         data-testid="add-policy" |                 className="m-t-sm" | ||||||
|                         disabled={!rolePermission.EditAll} |                 type="primary" | ||||||
|                         type="primary" |                 onClick={() => history.push(rolesPath)}> | ||||||
|                         onClick={() => |                 {t('label.go-back')} | ||||||
|                           setAddAttribute({ |               </Button> | ||||||
|                             type: EntityType.POLICY, |  | ||||||
|                             selectedData: role.policies || [], |  | ||||||
|                           }) |  | ||||||
|                         }> |  | ||||||
|                         {t('label.add-entity', { |  | ||||||
|                           entity: t('label.policy'), |  | ||||||
|                         })} |  | ||||||
|                       </Button> |  | ||||||
|                     </Tooltip> |  | ||||||
|                     <RolesDetailPageList |  | ||||||
|                       hasAccess={rolePermission.EditAll} |  | ||||||
|                       list={role.policies ?? []} |  | ||||||
|                       type="policy" |  | ||||||
|                       onDelete={(record) => |  | ||||||
|                         setEntity({ record, attribute: 'policies' }) |  | ||||||
|                       } |  | ||||||
|                     /> |  | ||||||
|                   </Space> |  | ||||||
|                 </TabPane> |  | ||||||
|                 <TabPane key="teams" tab={t('label.team-plural')}> |  | ||||||
|                   <RolesDetailPageList |  | ||||||
|                     hasAccess={rolePermission.EditAll} |  | ||||||
|                     list={role.teams ?? []} |  | ||||||
|                     type="team" |  | ||||||
|                     onDelete={(record) => |  | ||||||
|                       setEntity({ record, attribute: 'teams' }) |  | ||||||
|                     } |  | ||||||
|                   /> |  | ||||||
|                 </TabPane> |  | ||||||
|                 <TabPane key="users" tab={t('label.user-plural')}> |  | ||||||
|                   <RolesDetailPageList |  | ||||||
|                     hasAccess={rolePermission.EditAll} |  | ||||||
|                     list={role.users ?? []} |  | ||||||
|                     type="user" |  | ||||||
|                     onDelete={(record) => |  | ||||||
|                       setEntity({ record, attribute: 'users' }) |  | ||||||
|                     } |  | ||||||
|                   /> |  | ||||||
|                 </TabPane> |  | ||||||
|               </Tabs> |  | ||||||
|             </div> |             </div> | ||||||
|           )} |           </ErrorPlaceHolder> | ||||||
|         </> |         ) : ( | ||||||
|       ) : ( |           <div className="roles-detail" data-testid="role-details"> | ||||||
|         <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} /> |             <Typography.Title | ||||||
|       )} |               className="m-b-0 m-t-xs" | ||||||
|  |               data-testid="heading" | ||||||
|  |               level={5}> | ||||||
|  |               {getEntityName(role)} | ||||||
|  |             </Typography.Title> | ||||||
|  |             <Description | ||||||
|  |               hasEditAccess | ||||||
|  |               className="m-b-md" | ||||||
|  |               description={role.description || ''} | ||||||
|  |               entityFqn={role.fullyQualifiedName} | ||||||
|  |               entityName={getEntityName(role)} | ||||||
|  |               entityType={EntityType.ROLE} | ||||||
|  |               isEdit={editDescription} | ||||||
|  |               onCancel={() => setEditDescription(false)} | ||||||
|  |               onDescriptionEdit={() => setEditDescription(true)} | ||||||
|  |               onDescriptionUpdate={handleDescriptionUpdate} | ||||||
|  |             /> | ||||||
|  | 
 | ||||||
|  |             <Tabs data-testid="tabs" defaultActiveKey="policies"> | ||||||
|  |               <TabPane key="policies" tab={t('label.policy-plural')}> | ||||||
|  |                 <Space className="w-full" direction="vertical"> | ||||||
|  |                   <Button | ||||||
|  |                     data-testid="add-policy" | ||||||
|  |                     type="primary" | ||||||
|  |                     onClick={() => | ||||||
|  |                       setAddAttribute({ | ||||||
|  |                         type: EntityType.POLICY, | ||||||
|  |                         selectedData: role.policies || [], | ||||||
|  |                       }) | ||||||
|  |                     }> | ||||||
|  |                     {t('label.add-entity', { | ||||||
|  |                       entity: t('label.policy'), | ||||||
|  |                     })} | ||||||
|  |                   </Button> | ||||||
|  | 
 | ||||||
|  |                   <RolesDetailPageList | ||||||
|  |                     hasAccess | ||||||
|  |                     list={role.policies ?? []} | ||||||
|  |                     type="policy" | ||||||
|  |                     onDelete={(record) => | ||||||
|  |                       setEntity({ record, attribute: 'policies' }) | ||||||
|  |                     } | ||||||
|  |                   /> | ||||||
|  |                 </Space> | ||||||
|  |               </TabPane> | ||||||
|  |               <TabPane key="teams" tab={t('label.team-plural')}> | ||||||
|  |                 <RolesDetailPageList | ||||||
|  |                   hasAccess | ||||||
|  |                   list={role.teams ?? []} | ||||||
|  |                   type="team" | ||||||
|  |                   onDelete={(record) => | ||||||
|  |                     setEntity({ record, attribute: 'teams' }) | ||||||
|  |                   } | ||||||
|  |                 /> | ||||||
|  |               </TabPane> | ||||||
|  |               <TabPane key="users" tab={t('label.user-plural')}> | ||||||
|  |                 <RolesDetailPageList | ||||||
|  |                   hasAccess | ||||||
|  |                   list={role.users ?? []} | ||||||
|  |                   type="user" | ||||||
|  |                   onDelete={(record) => | ||||||
|  |                     setEntity({ record, attribute: 'users' }) | ||||||
|  |                   } | ||||||
|  |                 /> | ||||||
|  |               </TabPane> | ||||||
|  |             </Tabs> | ||||||
|  |           </div> | ||||||
|  |         )} | ||||||
|  |       </> | ||||||
|  | 
 | ||||||
|       {selectedEntity && ( |       {selectedEntity && ( | ||||||
|         <Modal |         <Modal | ||||||
|           centered |           centered | ||||||
|  | |||||||
| @ -102,19 +102,13 @@ export const getGlobalSettingsMenuWithPermission = ( | |||||||
|       items: [ |       items: [ | ||||||
|         { |         { | ||||||
|           label: i18next.t('label.role-plural'), |           label: i18next.t('label.role-plural'), | ||||||
|           isProtected: userPermissions.hasViewPermissions( |           isProtected: Boolean(isAdminUser), | ||||||
|             ResourceEntity.ROLE, |  | ||||||
|             permissions |  | ||||||
|           ), |  | ||||||
|           key: 'access.roles', |           key: 'access.roles', | ||||||
|           icon: <RolesIcon className="side-panel-icons" />, |           icon: <RolesIcon className="side-panel-icons" />, | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           label: i18next.t('label.policy-plural'), |           label: i18next.t('label.policy-plural'), | ||||||
|           isProtected: userPermissions.hasViewPermissions( |           isProtected: Boolean(isAdminUser), | ||||||
|             ResourceEntity.POLICY, |  | ||||||
|             permissions |  | ||||||
|           ), |  | ||||||
|           key: 'access.policies', |           key: 'access.policies', | ||||||
|           icon: <PoliciesIcon className="side-panel-icons" />, |           icon: <PoliciesIcon className="side-panel-icons" />, | ||||||
|         }, |         }, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Sachin Chaurasiya
						Sachin Chaurasiya