mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-27 23:48:19 +00:00
UI : Integrating Permissions API to get permissions for LoggedIn user. (#2557)
* UI : Integrating Permissions API to get permissions for LoggedIn user. * Adding permission check for Lineage * Adding Permission check for manage settings. * Adding permission check for entity level tags * Adding permission check for entities detail page. * Adding permission check on Tags page * Adding permission check for teams page * Addressing review comments
This commit is contained in:
parent
60aa5f3939
commit
199ca106e5
@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
import { action, makeAutoObservable } from 'mobx';
|
||||
import { ClientAuth, NewUser } from 'Models';
|
||||
import { ClientAuth, NewUser, UserPermissions } from 'Models';
|
||||
import { CurrentTourPageType } from './enums/tour.enum';
|
||||
import { Role } from './generated/entity/teams/role';
|
||||
import {
|
||||
@ -33,6 +33,7 @@ class AppState {
|
||||
userDetails: User = {} as User;
|
||||
userTeams: Array<UserTeams> = [];
|
||||
userRoles: Array<Role> = [];
|
||||
userPermissions: UserPermissions = {} as UserPermissions;
|
||||
|
||||
inPageSearchText = '';
|
||||
explorePageTab = 'tables';
|
||||
@ -50,6 +51,7 @@ class AppState {
|
||||
updateAuthState: action,
|
||||
updateUserRole: action,
|
||||
updateUsers: action,
|
||||
updateUserPermissions: action,
|
||||
});
|
||||
}
|
||||
|
||||
@ -74,6 +76,9 @@ class AppState {
|
||||
updateAuthState(state: boolean) {
|
||||
this.authDisabled = state;
|
||||
}
|
||||
updateUserPermissions(permissions: UserPermissions) {
|
||||
this.userPermissions = permissions;
|
||||
}
|
||||
}
|
||||
|
||||
export default new AppState();
|
||||
|
||||
@ -15,6 +15,7 @@ import { AxiosResponse } from 'axios';
|
||||
import { CookieStorage } from 'cookie-storage';
|
||||
import { isEmpty, isNil } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
import { UserPermissions } from 'Models';
|
||||
import { UserManager, WebStorageStateStore } from 'oidc-client';
|
||||
import React, {
|
||||
ComponentType,
|
||||
@ -32,7 +33,10 @@ import {
|
||||
} from 'react-router-dom';
|
||||
import appState from '../AppState';
|
||||
import axiosClient from '../axiosAPIs';
|
||||
import { fetchAuthorizerConfig } from '../axiosAPIs/miscAPI';
|
||||
import {
|
||||
fetchAuthorizerConfig,
|
||||
getLoggedInUserPermissions,
|
||||
} from '../axiosAPIs/miscAPI';
|
||||
import {
|
||||
getLoggedInUser,
|
||||
getUserByName,
|
||||
@ -130,6 +134,21 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const getUserPermissions = () => {
|
||||
setLoading(true);
|
||||
getLoggedInUserPermissions()
|
||||
.then((res: AxiosResponse) => {
|
||||
appState.updateUserPermissions(res.data.metadataOperations);
|
||||
})
|
||||
.catch(() =>
|
||||
showToast({
|
||||
variant: 'error',
|
||||
body: 'Error while getting user permissions',
|
||||
})
|
||||
)
|
||||
.finally(() => setLoading(false));
|
||||
};
|
||||
|
||||
const fetchUserByEmail = (user: OidcUser) => {
|
||||
getUserByName(getNameFromEmail(user.profile.email), userAPIQueryFields)
|
||||
.then((res: AxiosResponse) => {
|
||||
@ -137,6 +156,7 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
if (res.data?.isAdmin) {
|
||||
getUpdatedUser(res.data, user);
|
||||
}
|
||||
getUserPermissions();
|
||||
appState.updateUserDetails(res.data);
|
||||
fetchAllUsers();
|
||||
handledVerifiedUser();
|
||||
@ -148,6 +168,7 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
if (err.response.data.code === 404) {
|
||||
appState.updateNewUser(user.profile);
|
||||
appState.updateUserDetails({} as User);
|
||||
appState.updateUserPermissions({} as UserPermissions);
|
||||
history.push(ROUTES.SIGNUP);
|
||||
}
|
||||
});
|
||||
@ -155,6 +176,7 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
|
||||
const resetUserDetails = () => {
|
||||
appState.updateUserDetails({} as User);
|
||||
appState.updateUserPermissions({} as UserPermissions);
|
||||
cookieStorage.removeItem(oidcTokenKey);
|
||||
cookieStorage.removeItem(
|
||||
`oidc.user:${userManagerConfig?.authority}:${userManagerConfig?.client_id}`
|
||||
@ -167,11 +189,12 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
getLoggedInUser(userAPIQueryFields)
|
||||
.then((res: AxiosResponse) => {
|
||||
if (res.data) {
|
||||
getUserPermissions();
|
||||
appState.updateUserDetails(res.data);
|
||||
} else {
|
||||
resetUserDetails();
|
||||
setLoading(false);
|
||||
}
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.response.data.code === 404) {
|
||||
@ -179,6 +202,7 @@ const AuthProvider: FunctionComponent<AuthProviderProps> = ({
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const fetchAuthConfig = (): void => {
|
||||
fetchAuthorizerConfig()
|
||||
.then((res: AxiosResponse) => {
|
||||
|
||||
@ -85,3 +85,8 @@ export const deleteLineageEdge: Function = (
|
||||
`/lineage/${fromEntity}/${fromId}/${toEntity}/${toId}`
|
||||
);
|
||||
};
|
||||
|
||||
export const getLoggedInUserPermissions: Function =
|
||||
(): Promise<AxiosResponse> => {
|
||||
return APIClient.get('/permissions');
|
||||
};
|
||||
|
||||
@ -18,6 +18,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getTeamDetailsPath } from '../../constants/constants';
|
||||
import { Dashboard } from '../../generated/entity/data/dashboard';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import { User } from '../../generated/entity/teams/user';
|
||||
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
@ -425,6 +426,7 @@ const DashboardDetails = ({
|
||||
Boolean(owner)
|
||||
)}
|
||||
isOwner={hasEditAccess()}
|
||||
permission={Operation.UpdateDescription}
|
||||
position="top">
|
||||
<button
|
||||
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
||||
@ -469,6 +471,7 @@ const DashboardDetails = ({
|
||||
Boolean(owner)
|
||||
)}
|
||||
isOwner={hasEditAccess()}
|
||||
permission={Operation.UpdateTags}
|
||||
position="left"
|
||||
trigger="click">
|
||||
<TagsContainer
|
||||
|
||||
@ -38,12 +38,14 @@ import ReactFlow, {
|
||||
} from 'react-flow-renderer';
|
||||
import { getTableDetails } from '../../axiosAPIs/tableAPI';
|
||||
import { Column } from '../../generated/entity/data/table';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import {
|
||||
Edge as EntityEdge,
|
||||
EntityLineage,
|
||||
} from '../../generated/type/entityLineage';
|
||||
import { EntityReference } from '../../generated/type/entityReference';
|
||||
import { withLoader } from '../../hoc/withLoader';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import useToastContext from '../../hooks/useToastContext';
|
||||
import {
|
||||
dragHandle,
|
||||
@ -60,6 +62,7 @@ import {
|
||||
} from '../../utils/EntityLineageUtils';
|
||||
import SVGIcons from '../../utils/SvgUtils';
|
||||
import { getEntityIcon } from '../../utils/TableUtils';
|
||||
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
|
||||
import EntityInfoDrawer from '../EntityInfoDrawer/EntityInfoDrawer.component';
|
||||
import Loader from '../Loader/Loader';
|
||||
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
|
||||
@ -88,6 +91,7 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
|
||||
entityLineageHandler,
|
||||
}: EntityLineageProp) => {
|
||||
const showToast = useToastContext();
|
||||
const { userPermissions, isAuthDisabled } = useAuth();
|
||||
const reactFlowWrapper = useRef<HTMLDivElement>(null);
|
||||
const [lineageData, setLineageData] = useState<EntityLineage>(entityLineage);
|
||||
const [reactFlowInstance, setReactFlowInstance] = useState<OnLoadParams>();
|
||||
@ -659,41 +663,54 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
|
||||
className="tw-absolute tw-top-1 tw-right-1 tw-bottom-full tw-ml-4 tw-mt-4"
|
||||
fitViewParams={{ minZoom: 0.5, maxZoom: 2.5 }}>
|
||||
{!deleted && (
|
||||
<ControlButton
|
||||
className={classNames(
|
||||
'tw-h-9 tw-w-9 tw-rounded-full tw-px-1 tw-shadow-lg tw-cursor-pointer',
|
||||
{
|
||||
'tw-bg-primary': isEditMode,
|
||||
'tw-bg-primary-hover-lite': !isEditMode,
|
||||
}
|
||||
)}
|
||||
onClick={() => {
|
||||
setEditMode((pre) => !pre && !deleted);
|
||||
setSelectedNode({} as SelectedNode);
|
||||
setIsDrawerOpen(false);
|
||||
setNewAddedNode({} as FlowElement);
|
||||
}}>
|
||||
{loading ? (
|
||||
<Loader size="small" type="white" />
|
||||
) : status === 'success' ? (
|
||||
<i
|
||||
aria-hidden="true"
|
||||
className="fa fa-check tw-text-white"
|
||||
/>
|
||||
) : (
|
||||
<SVGIcons
|
||||
alt="icon-edit-lineag"
|
||||
className="tw--mt-1"
|
||||
data-testid="edit-lineage"
|
||||
icon={
|
||||
!isEditMode
|
||||
? 'icon-edit-lineage-color'
|
||||
: 'icon-edit-lineage'
|
||||
<NonAdminAction
|
||||
html={
|
||||
<>
|
||||
<p>You do not have permission to edit the lineage</p>
|
||||
</>
|
||||
}
|
||||
permission={Operation.UpdateLineage}>
|
||||
<ControlButton
|
||||
className={classNames(
|
||||
'tw-h-9 tw-w-9 tw-rounded-full tw-px-1 tw-shadow-lg tw-cursor-pointer',
|
||||
{
|
||||
'tw-bg-primary': isEditMode,
|
||||
'tw-bg-primary-hover-lite': !isEditMode,
|
||||
},
|
||||
{
|
||||
'tw-opacity-40':
|
||||
!userPermissions[Operation.UpdateLineage] &&
|
||||
!isAuthDisabled,
|
||||
}
|
||||
width="14"
|
||||
/>
|
||||
)}
|
||||
</ControlButton>
|
||||
)}
|
||||
onClick={() => {
|
||||
setEditMode((pre) => !pre && !deleted);
|
||||
setSelectedNode({} as SelectedNode);
|
||||
setIsDrawerOpen(false);
|
||||
setNewAddedNode({} as FlowElement);
|
||||
}}>
|
||||
{loading ? (
|
||||
<Loader size="small" type="white" />
|
||||
) : status === 'success' ? (
|
||||
<i
|
||||
aria-hidden="true"
|
||||
className="fa fa-check tw-text-white"
|
||||
/>
|
||||
) : (
|
||||
<SVGIcons
|
||||
alt="icon-edit-lineag"
|
||||
className="tw--mt-1"
|
||||
data-testid="edit-lineage"
|
||||
icon={
|
||||
!isEditMode
|
||||
? 'icon-edit-lineage-color'
|
||||
: 'icon-edit-lineage'
|
||||
}
|
||||
width="14"
|
||||
/>
|
||||
)}
|
||||
</ControlButton>
|
||||
</NonAdminAction>
|
||||
)}
|
||||
</CustomControls>
|
||||
{isEditMode ? (
|
||||
|
||||
@ -25,6 +25,7 @@ import {
|
||||
JoinedWith,
|
||||
Table,
|
||||
} from '../../generated/entity/data/table';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
|
||||
import {
|
||||
getHtmlForNonAdminAction,
|
||||
@ -435,6 +436,7 @@ const EntityTable = ({
|
||||
<NonAdminAction
|
||||
html={getHtmlForNonAdminAction(Boolean(owner))}
|
||||
isOwner={hasEditAccess}
|
||||
permission={Operation.UpdateTags}
|
||||
position="left"
|
||||
trigger="click">
|
||||
<TagsContainer
|
||||
@ -496,6 +498,7 @@ const EntityTable = ({
|
||||
Boolean(owner)
|
||||
)}
|
||||
isOwner={hasEditAccess}
|
||||
permission={Operation.UpdateDescription}
|
||||
position="top">
|
||||
<button
|
||||
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
||||
|
||||
@ -19,6 +19,8 @@ import { TableDetail } from 'Models';
|
||||
import React, { FunctionComponent, useEffect, useState } from 'react';
|
||||
import appState from '../../AppState';
|
||||
import { getCategory } from '../../axiosAPIs/tagAPI';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import { getUserTeams } from '../../utils/CommonUtils';
|
||||
import SVGIcons from '../../utils/SvgUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
@ -44,6 +46,7 @@ const ManageTab: FunctionComponent<Props> = ({
|
||||
onSave,
|
||||
hasEditAccess,
|
||||
}: Props) => {
|
||||
const { userPermissions, isAuthDisabled } = useAuth();
|
||||
const getOwnerList = () => {
|
||||
const user = !isEmpty(appState.userDetails)
|
||||
? appState.userDetails
|
||||
@ -220,33 +223,46 @@ const ManageTab: FunctionComponent<Props> = ({
|
||||
<div className="tw-mt-2 tw-mb-4 tw-pb-4 tw-border-b tw-border-separator">
|
||||
<span className="tw-mr-2">Owner:</span>
|
||||
<span className="tw-relative">
|
||||
<Button
|
||||
className="tw-underline"
|
||||
data-testid="owner-dropdown"
|
||||
disabled={!listOwners.length}
|
||||
size="custom"
|
||||
theme="primary"
|
||||
variant="link"
|
||||
onClick={() => setListVisible((visible) => !visible)}>
|
||||
{ownerName ? (
|
||||
<span
|
||||
className={classNames('tw-truncate', {
|
||||
'tw-w-52': ownerName.length > 32,
|
||||
})}
|
||||
title={ownerName}>
|
||||
{ownerName}
|
||||
</span>
|
||||
) : (
|
||||
'Select Owner'
|
||||
)}
|
||||
<SVGIcons
|
||||
alt="edit"
|
||||
className="tw-ml-1"
|
||||
icon="icon-edit"
|
||||
title="Edit"
|
||||
width="12px"
|
||||
/>
|
||||
</Button>
|
||||
<NonAdminAction
|
||||
html={
|
||||
<>
|
||||
<p>You do not have permissions to update the owner.</p>
|
||||
</>
|
||||
}
|
||||
isOwner={hasEditAccess || Boolean(owner)}
|
||||
permission={Operation.UpdateOwner}
|
||||
position="left">
|
||||
<Button
|
||||
className={classNames('tw-underline', {
|
||||
'tw-opacity-40':
|
||||
!userPermissions[Operation.UpdateOwner] && !isAuthDisabled,
|
||||
})}
|
||||
data-testid="owner-dropdown"
|
||||
disabled={!listOwners.length}
|
||||
size="custom"
|
||||
theme="primary"
|
||||
variant="link"
|
||||
onClick={() => setListVisible((visible) => !visible)}>
|
||||
{ownerName ? (
|
||||
<span
|
||||
className={classNames('tw-truncate', {
|
||||
'tw-w-52': ownerName.length > 32,
|
||||
})}
|
||||
title={ownerName}>
|
||||
{ownerName}
|
||||
</span>
|
||||
) : (
|
||||
'Select Owner'
|
||||
)}
|
||||
<SVGIcons
|
||||
alt="edit"
|
||||
className="tw-ml-1"
|
||||
icon="icon-edit"
|
||||
title="Edit"
|
||||
width="12px"
|
||||
/>
|
||||
</Button>
|
||||
</NonAdminAction>
|
||||
{listVisible && (
|
||||
<DropDownList
|
||||
showSearchBar
|
||||
@ -273,6 +289,7 @@ const ManageTab: FunctionComponent<Props> = ({
|
||||
}
|
||||
isOwner={hasEditAccess || Boolean(owner)}
|
||||
key={i}
|
||||
permission={Operation.UpdateTags}
|
||||
position="left">
|
||||
<CardListItem
|
||||
card={card}
|
||||
|
||||
@ -18,6 +18,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { getTeamDetailsPath } from '../../constants/constants';
|
||||
import { Pipeline, Task } from '../../generated/entity/data/pipeline';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import { User } from '../../generated/entity/teams/user';
|
||||
import { LabelType, State } from '../../generated/type/tagLabel';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
@ -377,6 +378,7 @@ const PipelineDetails = ({
|
||||
Boolean(owner)
|
||||
)}
|
||||
isOwner={hasEditAccess()}
|
||||
permission={Operation.UpdateDescription}
|
||||
position="top">
|
||||
<button
|
||||
className="tw-self-start tw-w-8 tw-h-auto tw-opacity-0 tw-ml-1 group-hover:tw-opacity-100 focus:tw-outline-none"
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import { Table } from '../../../generated/entity/data/table';
|
||||
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
|
||||
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
||||
import SVGIcons from '../../../utils/SvgUtils';
|
||||
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
|
||||
@ -94,6 +95,7 @@ const Description = ({
|
||||
<NonAdminAction
|
||||
html={getHtmlForNonAdminAction(Boolean(owner))}
|
||||
isOwner={hasEditAccess}
|
||||
permission={Operation.UpdateDescription}
|
||||
position="right">
|
||||
<button
|
||||
className="focus:tw-outline-none"
|
||||
|
||||
@ -16,6 +16,7 @@ import { isEmpty, isUndefined } from 'lodash';
|
||||
import { EntityTags, ExtraInfo, TableDetail } from 'Models';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FOLLOWERS_VIEW_CAP, LIST_SIZE } from '../../../constants/constants';
|
||||
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
|
||||
import { User } from '../../../generated/entity/teams/user';
|
||||
import { TagLabel } from '../../../generated/type/tagLabel';
|
||||
import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils';
|
||||
@ -341,6 +342,7 @@ const EntityPageInfo = ({
|
||||
<NonAdminAction
|
||||
html={getHtmlForNonAdminAction(Boolean(owner))}
|
||||
isOwner={hasEditAccess}
|
||||
permission={Operation.UpdateTags}
|
||||
position="bottom"
|
||||
trigger="click">
|
||||
<div
|
||||
|
||||
@ -11,7 +11,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UserPermissions } from 'Models';
|
||||
import React from 'react';
|
||||
import { Operation } from '../../../generated/entity/policies/accessControl/rule';
|
||||
import { useAuth } from '../../../hooks/authHooks';
|
||||
import PopOver from '../popover/PopOver';
|
||||
|
||||
@ -23,6 +25,7 @@ type Props = {
|
||||
isOwner?: boolean;
|
||||
html?: React.ReactElement;
|
||||
trigger?: 'mouseenter' | 'focus' | 'click' | 'manual';
|
||||
permission?: Operation;
|
||||
};
|
||||
|
||||
const NonAdminAction = ({
|
||||
@ -33,8 +36,9 @@ const NonAdminAction = ({
|
||||
isOwner = false,
|
||||
html,
|
||||
trigger = 'mouseenter',
|
||||
permission,
|
||||
}: Props) => {
|
||||
const { isAuthDisabled, isAdminUser } = useAuth();
|
||||
const { isAuthDisabled, isAdminUser, userPermissions } = useAuth();
|
||||
|
||||
const handleCapturedEvent = (
|
||||
e: React.KeyboardEvent | React.MouseEvent
|
||||
@ -45,7 +49,10 @@ const NonAdminAction = ({
|
||||
|
||||
return (
|
||||
<span className={className}>
|
||||
{isAdminUser || isOwner || isAuthDisabled ? (
|
||||
{isAdminUser ||
|
||||
isOwner ||
|
||||
isAuthDisabled ||
|
||||
userPermissions[permission as keyof UserPermissions] ? (
|
||||
<span>{children}</span>
|
||||
) : (
|
||||
<PopOver
|
||||
|
||||
@ -16,7 +16,8 @@ import AppState from '../AppState';
|
||||
import { ROUTES } from '../constants/constants';
|
||||
|
||||
export const useAuth = (pathname = '') => {
|
||||
const { authDisabled, userDetails, newUser, authProvider } = AppState;
|
||||
const { authDisabled, userDetails, newUser, authProvider, userPermissions } =
|
||||
AppState;
|
||||
const isAuthenticatedRoute =
|
||||
pathname !== ROUTES.SIGNUP &&
|
||||
pathname !== ROUTES.SIGNIN &&
|
||||
@ -37,5 +38,6 @@ export const useAuth = (pathname = '') => {
|
||||
isAdminUser: userDetails?.isAdmin,
|
||||
isFirstTimeUser: !isEmpty(userDetails) && !isEmpty(newUser),
|
||||
isTourRoute,
|
||||
userPermissions,
|
||||
};
|
||||
};
|
||||
|
||||
@ -484,4 +484,13 @@ declare module 'Models' {
|
||||
env?: string;
|
||||
pipelineUrl?: string;
|
||||
};
|
||||
|
||||
export interface UserPermissions {
|
||||
UpdateOwner: boolean;
|
||||
UpdateDescription: boolean;
|
||||
SuggestDescription: boolean;
|
||||
UpdateLineage: boolean;
|
||||
SuggestTags: boolean;
|
||||
UpdateTags: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ import {
|
||||
CreateTagCategory,
|
||||
TagCategoryType,
|
||||
} from '../../generated/api/tags/createTagCategory';
|
||||
import { Operation } from '../../generated/entity/policies/accessControl/rule';
|
||||
import { TagCategory, TagClass } from '../../generated/entity/tags/tagCategory';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import {
|
||||
@ -389,6 +390,7 @@ const TagsPage = () => {
|
||||
)}
|
||||
</div>
|
||||
<NonAdminAction
|
||||
permission={Operation.UpdateDescription}
|
||||
position="left"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<button
|
||||
@ -435,6 +437,7 @@ const TagsPage = () => {
|
||||
setEditTag(tag);
|
||||
}}>
|
||||
<NonAdminAction
|
||||
permission={Operation.UpdateTags}
|
||||
position="left"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}
|
||||
trigger="click">
|
||||
|
||||
@ -479,13 +479,19 @@ const TeamsPage = () => {
|
||||
</>
|
||||
) : (
|
||||
<ErrorPlaceHolder>
|
||||
<p className="w-text-lg tw-text-center">No Teams Added.</p>
|
||||
<p className="w-text-lg tw-text-center">
|
||||
<button
|
||||
className="link-text tw-underline"
|
||||
onClick={() => setIsAddingTeam(true)}>
|
||||
Click here
|
||||
</button>
|
||||
<p className="tw-text-lg tw-text-center">No Teams Added.</p>
|
||||
<p className="tw-text-lg tw-text-center">
|
||||
<NonAdminAction
|
||||
position="bottom"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<button
|
||||
className={classNames('link-text tw-underline', {
|
||||
'tw-opacity-40': !isAdminUser && !isAuthDisabled,
|
||||
})}
|
||||
onClick={() => setIsAddingTeam(true)}>
|
||||
Click here
|
||||
</button>
|
||||
</NonAdminAction>
|
||||
{' to add new Team'}
|
||||
</p>
|
||||
</ErrorPlaceHolder>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user