mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-17 11:43:54 +00:00
Refactor(UI): Global settings Teams page refactoring and roles and policies update. (#7032)
* - Made organisation page default page for global settings page for teams option - Unnecessary actions for organisation removed * Added support for new permissions API in teams page * Replaced hard coded path with existing util function. * Worked on comments * Fixed minor bug and cypress test * fixed failing cypress tests
This commit is contained in:
parent
a39c4db8e7
commit
6547beeffc
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { addNewTagToEntity } from '../../common/common';
|
||||
import { searchEntity } from '../../common/common';
|
||||
import { DELETE_TERM, NEW_GLOSSARY, NEW_GLOSSARY_TERMS, SEARCH_ENTITY_TABLE } from '../../constants/constants';
|
||||
|
||||
const createGlossaryTerm = (term) => {
|
||||
@ -227,6 +227,11 @@ describe('Glossary page should work properly', () => {
|
||||
.as('synonyms');
|
||||
cy.get('@synonyms').clear();
|
||||
cy.get('@synonyms').type(uSynonyms);
|
||||
|
||||
cy.intercept({ method: 'PATCH', url: '/api/v1/glossaryTerms/*' }).as(
|
||||
'getGlossary'
|
||||
);
|
||||
|
||||
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
|
||||
cy.wait(100);
|
||||
cy.get('[data-testid="synonyms-container"]')
|
||||
@ -237,6 +242,8 @@ describe('Glossary page should work properly', () => {
|
||||
cy.get('@synonyms-container').contains(synonym).should('be.visible');
|
||||
});
|
||||
|
||||
cy.wait('@getGlossary').its('response.statusCode').should('eq', 200);
|
||||
|
||||
// updating References
|
||||
cy.get('[data-testid="section-references"] [data-testid="add-button"]')
|
||||
.should('exist')
|
||||
@ -316,6 +323,7 @@ describe('Glossary page should work properly', () => {
|
||||
});
|
||||
|
||||
it('Assets Tab should work properly', () => {
|
||||
const glossary = NEW_GLOSSARY.name;
|
||||
const term = NEW_GLOSSARY_TERMS.term_1.name;
|
||||
const entity = SEARCH_ENTITY_TABLE.table_3.term;
|
||||
goToAssetsTab(term);
|
||||
@ -323,7 +331,46 @@ describe('Glossary page should work properly', () => {
|
||||
.contains('No assets available.')
|
||||
.should('be.visible');
|
||||
|
||||
addNewTagToEntity(entity, term);
|
||||
searchEntity(entity);
|
||||
cy.wait(500);
|
||||
cy.get('[data-testid="table-link"]').first().contains(entity).click();
|
||||
|
||||
//Add tag to breadcrumb
|
||||
cy.get('[data-testid="tag-container"] [data-testid="tags"]')
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[class*="-control"]').should('be.visible').type(term);
|
||||
cy.wait(500);
|
||||
cy.get('[id*="-option-0"]').should('be.visible').click();
|
||||
cy.get(
|
||||
'[data-testid="tags-wrapper"] [data-testid="tag-container"]'
|
||||
).contains(term);
|
||||
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
|
||||
cy.wait(1000);
|
||||
|
||||
cy.get('[data-testid="entity-tags"]')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.contains(term);
|
||||
|
||||
//Add tag to schema table
|
||||
cy.get('[data-testid="tag-container"] [data-testid="tags"]')
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[class*="-control"]').should('be.visible').type(term);
|
||||
cy.wait(500);
|
||||
cy.get('[id*="-option-0"]').should('be.visible').click();
|
||||
cy.get(
|
||||
'[data-testid="tags-wrapper"] [data-testid="tag-container"]'
|
||||
).contains(term);
|
||||
cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click();
|
||||
cy.wait(1000);
|
||||
cy.get(`[data-testid="tag-${glossary}.${term}"]`)
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.contains(term);
|
||||
|
||||
cy.get('[data-testid="appbar-item-glossary"]')
|
||||
.should('exist')
|
||||
@ -353,34 +400,17 @@ describe('Glossary page should work properly', () => {
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get(':nth-child(1) > .css-xb97g8')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get(':nth-child(1) > .css-xb97g8')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[role="button"]').eq(0).should('be.visible').click();
|
||||
cy.get('[role="button"]').eq(0).should('be.visible').click();
|
||||
|
||||
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
||||
|
||||
//Remove the added column tag from entity
|
||||
cy.get(
|
||||
':nth-child(1) > :nth-child(5) span.tw-text-primary > [data-testid="tags"]'
|
||||
)
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
cy.get(':nth-child(1) > .css-xb97g8')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get(':nth-child(1) > .css-xb97g8')
|
||||
.scrollIntoView()
|
||||
.should('be.visible')
|
||||
.click();
|
||||
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
||||
cy.get('[data-testid="remove"]').eq(0).should('be.visible').click();
|
||||
|
||||
cy.wait(500);
|
||||
cy.get('[data-testid="remove"]').eq(0).should('be.visible').click();
|
||||
|
||||
cy.get('[data-testid="appbar-item-glossary"]')
|
||||
.should('exist')
|
||||
|
@ -16,12 +16,14 @@ import { ItemType } from 'antd/lib/menu/hooks/useItems';
|
||||
import { camelCase } from 'lodash';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { GlobalSettingOptions } from '../../constants/globalSettings.constants';
|
||||
import { TeamType } from '../../generated/entity/teams/team';
|
||||
import {
|
||||
getGlobalSettingMenuItem,
|
||||
getGlobalSettingsMenuWithPermission,
|
||||
MenuList,
|
||||
} from '../../utils/GlobalSettingsUtils';
|
||||
import { getSettingPath } from '../../utils/RouterUtils';
|
||||
import { getSettingPath, getTeamsWithFqnPath } from '../../utils/RouterUtils';
|
||||
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
||||
|
||||
const GlobalSettingLeftPanel = () => {
|
||||
@ -56,7 +58,11 @@ const GlobalSettingLeftPanel = () => {
|
||||
const onClick: MenuProps['onClick'] = (e) => {
|
||||
// As we are setting key as "category.option" and extracting here category and option
|
||||
const [category, option] = e.key.split('.');
|
||||
history.push(getSettingPath(category, option));
|
||||
if (option === GlobalSettingOptions.TEAMS) {
|
||||
history.push(getTeamsWithFqnPath(TeamType.Organization));
|
||||
} else {
|
||||
history.push(getSettingPath(category, option));
|
||||
}
|
||||
};
|
||||
|
||||
return menuItems.length ? (
|
||||
|
@ -15,6 +15,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {
|
||||
Button as ButtonAntd,
|
||||
Col,
|
||||
Empty,
|
||||
Modal,
|
||||
Row,
|
||||
Space,
|
||||
@ -24,6 +25,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { ColumnsType } from 'antd/lib/table';
|
||||
import { AxiosError } from 'axios';
|
||||
import classNames from 'classnames';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { cloneDeep, isEmpty, isUndefined, orderBy } from 'lodash';
|
||||
@ -35,13 +37,15 @@ import {
|
||||
getTeamAndUserDetailsPath,
|
||||
getUserPath,
|
||||
PAGE_SIZE,
|
||||
TITLE_FOR_NON_ADMIN_ACTION,
|
||||
TITLE_FOR_NON_OWNER_ACTION,
|
||||
} from '../../constants/constants';
|
||||
import {
|
||||
GlobalSettingOptions,
|
||||
GlobalSettingsMenuCategory,
|
||||
} from '../../constants/globalSettings.constants';
|
||||
import {
|
||||
NO_PERMISSION_FOR_ACTION,
|
||||
NO_PERMISSION_TO_VIEW,
|
||||
} from '../../constants/HelperTextUtil';
|
||||
import { EntityType } from '../../enums/entity.enum';
|
||||
import { OwnerType } from '../../enums/user.enum';
|
||||
import { Operation } from '../../generated/entity/policies/policy';
|
||||
@ -51,8 +55,8 @@ import {
|
||||
User,
|
||||
} from '../../generated/entity/teams/user';
|
||||
import { EntityReference } from '../../generated/type/entityReference';
|
||||
import { useAuth } from '../../hooks/authHooks';
|
||||
import { TeamDetailsProp } from '../../interface/teamsAndUsers.interface';
|
||||
import jsonData from '../../jsons/en';
|
||||
import AddAttributeModal from '../../pages/RolesPage/AddAttributeModal/AddAttributeModal';
|
||||
import UserCard from '../../pages/teams/UserCard';
|
||||
import {
|
||||
@ -61,9 +65,10 @@ import {
|
||||
hasEditAccess,
|
||||
} from '../../utils/CommonUtils';
|
||||
import { filterEntityAssets } from '../../utils/EntityUtils';
|
||||
import { hasPemission } from '../../utils/PermissionsUtils';
|
||||
import { checkPermission } from '../../utils/PermissionsUtils';
|
||||
import { getSettingPath, getTeamsWithFqnPath } from '../../utils/RouterUtils';
|
||||
import SVGIcons, { Icons } from '../../utils/SvgUtils';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import { Button } from '../buttons/Button/Button';
|
||||
import Description from '../common/description/Description';
|
||||
import Ellipses from '../common/Ellipses/Ellipses';
|
||||
@ -71,14 +76,19 @@ import ManageButton from '../common/entityPageInfo/ManageButton/ManageButton';
|
||||
import EntitySummaryDetails from '../common/EntitySummaryDetails/EntitySummaryDetails';
|
||||
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
|
||||
import NextPrevious from '../common/next-previous/NextPrevious';
|
||||
import NonAdminAction from '../common/non-admin-action/NonAdminAction';
|
||||
import Searchbar from '../common/searchbar/Searchbar';
|
||||
import TabsPane from '../common/TabsPane/TabsPane';
|
||||
import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component';
|
||||
import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface';
|
||||
import Loader from '../Loader/Loader';
|
||||
import ConfirmationModal from '../Modals/ConfirmationModal/ConfirmationModal';
|
||||
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
||||
import {
|
||||
OperationPermission,
|
||||
ResourceEntity,
|
||||
} from '../PermissionProvider/PermissionProvider.interface';
|
||||
import ListEntities from './RolesAndPoliciesList';
|
||||
import { getTabs } from './TeamDetailsV1.utils';
|
||||
import TeamHierarchy from './TeamHierarchy';
|
||||
import './teams.less';
|
||||
interface AddAttribute {
|
||||
@ -109,14 +119,13 @@ const TeamDetailsV1 = ({
|
||||
removeUserFromTeam,
|
||||
afterDeleteAction,
|
||||
}: TeamDetailsProp) => {
|
||||
const isOrganization =
|
||||
currentTeam.name === TeamType.Organization.toLowerCase();
|
||||
const isOrganization = currentTeam.name === TeamType.Organization;
|
||||
const DELETE_USER_INITIAL_STATE = {
|
||||
user: undefined,
|
||||
state: false,
|
||||
leave: false,
|
||||
};
|
||||
const { userPermissions } = useAuth();
|
||||
const { permissions, getEntityPermission } = usePermissionProvider();
|
||||
const [currentTab, setCurrentTab] = useState(1);
|
||||
const [isHeadingEditing, setIsHeadingEditing] = useState(false);
|
||||
const [currentUser, setCurrentUser] = useState<User>();
|
||||
@ -138,6 +147,15 @@ const TeamDetailsV1 = ({
|
||||
attribute: 'defaultRoles' | 'policies';
|
||||
record: EntityReference;
|
||||
}>();
|
||||
const [entityPermissions, setEntityPermissions] =
|
||||
useState<OperationPermission>({} as OperationPermission);
|
||||
|
||||
const createTeamPermission = useMemo(
|
||||
() =>
|
||||
!isEmpty(permissions) &&
|
||||
checkPermission(Operation.Create, ResourceEntity.TEAM, permissions),
|
||||
[permissions]
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if current team is the owner or not
|
||||
@ -162,39 +180,6 @@ const TeamDetailsV1 = ({
|
||||
setDeletingUser({ user, state: true, leave });
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
name: 'Teams',
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
count: currentTeam.children?.length || 0,
|
||||
},
|
||||
{
|
||||
name: 'Users',
|
||||
isProtected: false,
|
||||
position: 2,
|
||||
count: teamUserPagin?.total,
|
||||
},
|
||||
{
|
||||
name: 'Assets',
|
||||
isProtected: false,
|
||||
position: 3,
|
||||
count: filterEntityAssets(currentTeam?.owns || []).length,
|
||||
},
|
||||
{
|
||||
name: 'Roles',
|
||||
isProtected: false,
|
||||
position: 4,
|
||||
count: currentTeam?.defaultRoles?.length,
|
||||
},
|
||||
{
|
||||
name: 'Policies',
|
||||
isProtected: false,
|
||||
position: 5,
|
||||
count: currentTeam?.policies?.length,
|
||||
},
|
||||
];
|
||||
|
||||
const columns: ColumnsType<User> = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
@ -230,8 +215,13 @@ const TeamDetailsV1 = ({
|
||||
align="center"
|
||||
className="tw-w-full tw-justify-center remove-icon"
|
||||
size={8}>
|
||||
<Tooltip placement="bottom" title="Remove">
|
||||
<Tooltip
|
||||
placement="bottomRight"
|
||||
title={
|
||||
entityPermissions?.EditAll ? 'Remove' : NO_PERMISSION_FOR_ACTION
|
||||
}>
|
||||
<ButtonAntd
|
||||
disabled={!entityPermissions?.EditAll}
|
||||
icon={
|
||||
<SVGIcons
|
||||
alt="Remove"
|
||||
@ -425,6 +415,25 @@ const TeamDetailsV1 = ({
|
||||
updateTeamHandler(updatedTeamData);
|
||||
};
|
||||
|
||||
const fetchPermissions = async () => {
|
||||
try {
|
||||
const perms = await getEntityPermission(
|
||||
ResourceEntity.TEAM,
|
||||
currentTeam.id
|
||||
);
|
||||
setEntityPermissions(perms);
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['fetch-user-permission-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
!isEmpty(currentTeam) && fetchPermissions();
|
||||
}, [currentTeam]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentTeam) {
|
||||
const perents =
|
||||
@ -493,22 +502,23 @@ const TeamDetailsV1 = ({
|
||||
|
||||
{currentTeamUsers.length > 0 && isActionAllowed() && (
|
||||
<div>
|
||||
<NonAdminAction
|
||||
isOwner={isActionAllowed()}
|
||||
position="bottom"
|
||||
title={TITLE_FOR_NON_OWNER_ACTION}>
|
||||
<Button
|
||||
className="tw-h-8 tw-px-2"
|
||||
data-testid="add-user"
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
handleAddUser(true);
|
||||
}}>
|
||||
Add User
|
||||
</Button>
|
||||
</NonAdminAction>
|
||||
<Button
|
||||
className="tw-h-8 tw-px-2"
|
||||
data-testid="add-user"
|
||||
disabled={!entityPermissions?.EditAll}
|
||||
size="small"
|
||||
theme="primary"
|
||||
title={
|
||||
entityPermissions?.EditAll
|
||||
? 'Add User'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
variant="contained"
|
||||
onClick={() => {
|
||||
handleAddUser(true);
|
||||
}}>
|
||||
Add User
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -524,26 +534,22 @@ const TeamDetailsV1 = ({
|
||||
? `as ${teamUsersSearchText}.`
|
||||
: `added yet.`}
|
||||
</p>
|
||||
{isActionAllowed(
|
||||
hasPemission(
|
||||
Operation.EditUsers,
|
||||
EntityType.TEAM,
|
||||
userPermissions
|
||||
)
|
||||
) ? (
|
||||
<>
|
||||
<p>Would like to start adding some?</p>
|
||||
<Button
|
||||
className="tw-h-8 tw-rounded tw-my-2"
|
||||
data-testid="add-new-user"
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="contained"
|
||||
onClick={() => handleAddUser(true)}>
|
||||
Add new user
|
||||
</Button>
|
||||
</>
|
||||
) : null}
|
||||
<p>Would like to start adding some?</p>
|
||||
<Button
|
||||
className="tw-h-8 tw-rounded tw-my-2"
|
||||
data-testid="add-new-user"
|
||||
disabled={!entityPermissions?.EditAll}
|
||||
size="small"
|
||||
theme="primary"
|
||||
title={
|
||||
entityPermissions?.EditAll
|
||||
? 'Add New User'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
variant="contained"
|
||||
onClick={() => handleAddUser(true)}>
|
||||
Add new user
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Fragment>
|
||||
@ -649,7 +655,7 @@ const TeamDetailsV1 = ({
|
||||
|
||||
const getTeamHeading = () => {
|
||||
return (
|
||||
<div className="tw-heading tw-text-link tw-text-base tw-mb-0">
|
||||
<div className="tw-heading tw-text-link tw-text-base tw-mb-2">
|
||||
{isHeadingEditing ? (
|
||||
<div className="tw-flex tw-items-center tw-gap-1">
|
||||
<input
|
||||
@ -690,21 +696,26 @@ const TeamDetailsV1 = ({
|
||||
</Ellipses>
|
||||
{isActionAllowed() && (
|
||||
<div className={classNames('tw-w-5 tw-min-w-max')}>
|
||||
<NonAdminAction
|
||||
position="right"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<Tooltip
|
||||
placement="bottomLeft"
|
||||
title={
|
||||
entityPermissions?.EditDisplayName
|
||||
? 'Edit Display Name'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}>
|
||||
<button
|
||||
className="tw-ml-2 focus:tw-outline-none"
|
||||
data-testid="edit-synonyms"
|
||||
disabled={!entityPermissions?.EditDisplayName}
|
||||
onClick={() => setIsHeadingEditing(true)}>
|
||||
<SVGIcons
|
||||
alt="edit"
|
||||
className="tw-mb-1"
|
||||
icon="icon-edit"
|
||||
title="Edit"
|
||||
width="16px"
|
||||
/>
|
||||
</button>
|
||||
</NonAdminAction>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -713,7 +724,10 @@ const TeamDetailsV1 = ({
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
const viewPermission =
|
||||
!isEmpty(entityPermissions) && entityPermissions.ViewAll;
|
||||
|
||||
return viewPermission ? (
|
||||
<div
|
||||
className="tw-h-full tw-flex tw-flex-col tw-flex-grow"
|
||||
data-testid="team-details-container">
|
||||
@ -724,37 +738,43 @@ const TeamDetailsV1 = ({
|
||||
className="tw-flex tw-justify-between tw-items-center"
|
||||
data-testid="header">
|
||||
{getTeamHeading()}
|
||||
<Space align="center">
|
||||
{!isUndefined(currentUser) &&
|
||||
teamActionButton(
|
||||
!isAlreadyJoinedTeam(currentTeam.id),
|
||||
currentTeam.isJoinable || false
|
||||
)}
|
||||
<NonAdminAction
|
||||
position="bottom"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
{!isOrganization && (
|
||||
<Space align="center">
|
||||
{!isUndefined(currentUser) &&
|
||||
teamActionButton(
|
||||
!isAlreadyJoinedTeam(currentTeam.id),
|
||||
currentTeam.isJoinable || false
|
||||
)}
|
||||
<ManageButton
|
||||
afterDeleteAction={afterDeleteAction}
|
||||
buttonClassName="tw-p-4"
|
||||
disabled={!entityPermissions.EditAll}
|
||||
entityId={currentTeam.id}
|
||||
entityName={
|
||||
currentTeam.fullyQualifiedName || currentTeam.name
|
||||
}
|
||||
entityType="team"
|
||||
title={
|
||||
entityPermissions.EditAll
|
||||
? 'Manage'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
/>
|
||||
</NonAdminAction>
|
||||
</Space>
|
||||
</div>
|
||||
<div className="tw-mb-3">
|
||||
<Switch
|
||||
checked={currentTeam.isJoinable}
|
||||
className="tw-mr-2"
|
||||
size="small"
|
||||
title="Open Group"
|
||||
onChange={handleOpenToJoinToggle}
|
||||
/>
|
||||
<span>Open Group</span>
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
{!isOrganization && (
|
||||
<div className="tw-mb-3">
|
||||
<Switch
|
||||
checked={currentTeam.isJoinable}
|
||||
className="tw-mr-2"
|
||||
size="small"
|
||||
title="Open Group"
|
||||
onChange={handleOpenToJoinToggle}
|
||||
/>
|
||||
<span>Open Group</span>
|
||||
</div>
|
||||
)}
|
||||
<EntitySummaryDetails data={extraInfo} updateOwner={updateOwner} />
|
||||
<div
|
||||
className="tw-mb-3 tw--ml-5 tw-mt-2"
|
||||
@ -762,7 +782,7 @@ const TeamDetailsV1 = ({
|
||||
<Description
|
||||
description={currentTeam?.description || ''}
|
||||
entityName={currentTeam?.displayName ?? currentTeam?.name}
|
||||
hasEditAccess={isOwner()}
|
||||
hasEditAccess={entityPermissions.EditDescription}
|
||||
isEdit={isDescriptionEditable}
|
||||
onCancel={() => descriptionHandler(false)}
|
||||
onDescriptionEdit={() => descriptionHandler(true)}
|
||||
@ -774,7 +794,7 @@ const TeamDetailsV1 = ({
|
||||
<TabsPane
|
||||
activeTab={currentTab}
|
||||
setActiveTab={(tab) => setCurrentTab(tab)}
|
||||
tabs={tabs}
|
||||
tabs={getTabs(currentTeam, teamUserPagin, isOrganization)}
|
||||
/>
|
||||
|
||||
<div className="tw-flex-grow tw-flex tw-flex-col tw-pt-4">
|
||||
@ -795,6 +815,12 @@ const TeamDetailsV1 = ({
|
||||
className="tw-w-full"
|
||||
direction="vertical">
|
||||
<ButtonAntd
|
||||
disabled={!createTeamPermission}
|
||||
title={
|
||||
createTeamPermission
|
||||
? 'Add Team'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
type="primary"
|
||||
onClick={() => handleAddTeam(true)}>
|
||||
Add Team
|
||||
@ -819,6 +845,12 @@ const TeamDetailsV1 = ({
|
||||
direction="vertical">
|
||||
<ButtonAntd
|
||||
data-testid="add-role"
|
||||
disabled={!entityPermissions.EditAll}
|
||||
title={
|
||||
entityPermissions.EditAll
|
||||
? 'Add Role'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
setAddAttribute({
|
||||
@ -843,6 +875,12 @@ const TeamDetailsV1 = ({
|
||||
direction="vertical">
|
||||
<ButtonAntd
|
||||
data-testid="add-policy"
|
||||
disabled={!entityPermissions.EditAll}
|
||||
title={
|
||||
entityPermissions.EditAll
|
||||
? 'Add Policy'
|
||||
: NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
type="primary"
|
||||
onClick={() =>
|
||||
setAddAttribute({
|
||||
@ -868,18 +906,17 @@ const TeamDetailsV1 = ({
|
||||
<ErrorPlaceHolder>
|
||||
<p className="tw-text-lg tw-text-center">No Teams Added.</p>
|
||||
<div className="tw-text-lg tw-text-center">
|
||||
<NonAdminAction
|
||||
position="bottom"
|
||||
title={TITLE_FOR_NON_ADMIN_ACTION}>
|
||||
<Button
|
||||
disabled={!isActionAllowed()}
|
||||
size="small"
|
||||
theme="primary"
|
||||
variant="outlined"
|
||||
onClick={() => handleAddTeam(true)}>
|
||||
Click here
|
||||
</Button>
|
||||
</NonAdminAction>
|
||||
<Button
|
||||
disabled={!createTeamPermission}
|
||||
size="small"
|
||||
theme="primary"
|
||||
title={
|
||||
createTeamPermission ? 'Add Team' : NO_PERMISSION_FOR_ACTION
|
||||
}
|
||||
variant="outlined"
|
||||
onClick={() => handleAddTeam(true)}>
|
||||
Click here
|
||||
</Button>
|
||||
{' to add new Team'}
|
||||
</div>
|
||||
</ErrorPlaceHolder>
|
||||
@ -931,6 +968,12 @@ const TeamDetailsV1 = ({
|
||||
</Modal>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<Row align="middle" className="tw-h-full">
|
||||
<Col span={24}>
|
||||
<Empty description={NO_PERMISSION_TO_VIEW} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2022 Collate
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Team } from '../../generated/entity/teams/team';
|
||||
import { Paging } from '../../generated/type/paging';
|
||||
import { filterEntityAssets } from '../../utils/EntityUtils';
|
||||
|
||||
export const getTabs = (
|
||||
currentTeam: Team,
|
||||
teamUserPagin: Paging,
|
||||
isOrganization: boolean
|
||||
) => {
|
||||
const commonTabs = [
|
||||
{
|
||||
name: 'Roles',
|
||||
isProtected: false,
|
||||
position: 4,
|
||||
count: currentTeam?.defaultRoles?.length,
|
||||
},
|
||||
{
|
||||
name: 'Policies',
|
||||
isProtected: false,
|
||||
position: 5,
|
||||
count: currentTeam?.policies?.length,
|
||||
},
|
||||
];
|
||||
|
||||
if (isOrganization) {
|
||||
return [
|
||||
{
|
||||
name: 'Teams',
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
count: currentTeam.children?.length || 0,
|
||||
},
|
||||
...commonTabs,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'Teams',
|
||||
isProtected: false,
|
||||
position: 1,
|
||||
count: currentTeam.children?.length || 0,
|
||||
},
|
||||
{
|
||||
name: 'Users',
|
||||
isProtected: false,
|
||||
position: 2,
|
||||
count: teamUserPagin?.total,
|
||||
},
|
||||
{
|
||||
name: 'Assets',
|
||||
isProtected: false,
|
||||
position: 3,
|
||||
count: filterEntityAssets(currentTeam?.owns || []).length,
|
||||
},
|
||||
...commonTabs,
|
||||
];
|
||||
};
|
@ -11,9 +11,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Button, Col, Row, Space, Switch } from 'antd';
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { Button, Col, Empty, Row, Space, Switch, Tooltip } from 'antd';
|
||||
import { AxiosError } from 'axios';
|
||||
import React, { FC, useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
NO_PERMISSION_FOR_ACTION,
|
||||
NO_PERMISSION_TO_VIEW,
|
||||
} from '../../constants/HelperTextUtil';
|
||||
import { Team } from '../../generated/entity/teams/team';
|
||||
import jsonData from '../../jsons/en';
|
||||
import { showErrorToast } from '../../utils/ToastUtils';
|
||||
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
||||
import {
|
||||
OperationPermission,
|
||||
ResourceEntity,
|
||||
} from '../PermissionProvider/PermissionProvider.interface';
|
||||
import TeamHierarchy from './TeamHierarchy';
|
||||
import './teams.less';
|
||||
|
||||
@ -36,6 +48,10 @@ const Teams: FC<TeamsProps> = ({
|
||||
onAddTeamClick,
|
||||
onTeamExpand,
|
||||
}) => {
|
||||
const { getResourcePermission } = usePermissionProvider();
|
||||
const [resourcePermissions, setResourcePermissions] =
|
||||
useState<OperationPermission>();
|
||||
|
||||
const filteredData = useMemo(
|
||||
() =>
|
||||
data.filter(
|
||||
@ -45,7 +61,23 @@ const Teams: FC<TeamsProps> = ({
|
||||
[data, showDeletedTeam]
|
||||
);
|
||||
|
||||
return (
|
||||
const fetchPermissions = async () => {
|
||||
try {
|
||||
const perms = await getResourcePermission(ResourceEntity.TEAM);
|
||||
setResourcePermissions(perms);
|
||||
} catch (error) {
|
||||
showErrorToast(
|
||||
error as AxiosError,
|
||||
jsonData['api-error-messages']['fetch-user-permission-error']
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchPermissions();
|
||||
}, []);
|
||||
|
||||
return resourcePermissions?.ViewAll ? (
|
||||
<Row className="team-list-container" gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<Space align="center" className="tw-w-full tw-justify-end" size={16}>
|
||||
@ -57,15 +89,30 @@ const Teams: FC<TeamsProps> = ({
|
||||
/>
|
||||
<span>Deleted Teams</span>
|
||||
</Space>
|
||||
<Button type="primary" onClick={() => onAddTeamClick(true)}>
|
||||
Add Team
|
||||
</Button>
|
||||
<Tooltip
|
||||
placement="bottom"
|
||||
title={
|
||||
resourcePermissions.Create ? 'Add Team' : NO_PERMISSION_FOR_ACTION
|
||||
}>
|
||||
<Button
|
||||
disabled={!resourcePermissions.Create}
|
||||
type="primary"
|
||||
onClick={() => onAddTeamClick(true)}>
|
||||
Add Team
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<TeamHierarchy data={filteredData} onTeamExpand={onTeamExpand} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : (
|
||||
<Row align="middle" className="tw-h-full">
|
||||
<Col span={24}>
|
||||
<Empty description={NO_PERMISSION_TO_VIEW} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -25,12 +25,14 @@ interface Props {
|
||||
allowSoftDelete?: boolean;
|
||||
afterDeleteAction?: () => void;
|
||||
buttonClassName?: string;
|
||||
disabled?: boolean;
|
||||
entityName: string;
|
||||
entityId?: string;
|
||||
entityType?: string;
|
||||
entityFQN?: string;
|
||||
isRecursiveDelete?: boolean;
|
||||
deleteMessage?: string;
|
||||
title?: string;
|
||||
onAnnouncementClick?: () => void;
|
||||
}
|
||||
|
||||
@ -39,10 +41,12 @@ const ManageButton: FC<Props> = ({
|
||||
afterDeleteAction,
|
||||
buttonClassName,
|
||||
deleteMessage,
|
||||
disabled,
|
||||
entityName,
|
||||
entityType,
|
||||
entityId,
|
||||
isRecursiveDelete,
|
||||
title,
|
||||
onAnnouncementClick,
|
||||
}) => {
|
||||
const [showActions, setShowActions] = useState<boolean>(false);
|
||||
@ -114,6 +118,7 @@ const ManageButton: FC<Props> = ({
|
||||
<>
|
||||
<Dropdown
|
||||
align={{ targetOffset: [-12, 0] }}
|
||||
disabled={disabled}
|
||||
overlay={menu}
|
||||
overlayStyle={{ width: '350px' }}
|
||||
placement="bottomRight"
|
||||
@ -126,7 +131,9 @@ const ManageButton: FC<Props> = ({
|
||||
buttonClassName
|
||||
)}
|
||||
data-testid="manage-button"
|
||||
disabled={disabled}
|
||||
size="small"
|
||||
title={title ?? 'Manage'}
|
||||
type="default"
|
||||
onClick={() => setShowActions(true)}>
|
||||
<FontAwesomeIcon
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
GlobalSettingsMenuCategory,
|
||||
} from '../constants/globalSettings.constants';
|
||||
import { Operation } from '../generated/entity/policies/policy';
|
||||
import { TeamType } from '../generated/entity/teams/team';
|
||||
import TeamsPage from '../pages/teams/TeamsPage';
|
||||
import { checkPermission } from '../utils/PermissionsUtils';
|
||||
import { getSettingCategoryPath, getSettingPath } from '../utils/RouterUtils';
|
||||
@ -80,10 +81,10 @@ const GlobalSettingRouter = () => {
|
||||
<Switch>
|
||||
<Route exact path={getSettingPath()}>
|
||||
<Redirect
|
||||
to={getSettingPath(
|
||||
to={`${getSettingPath(
|
||||
GlobalSettingsMenuCategory.MEMBERS,
|
||||
GlobalSettingOptions.TEAMS
|
||||
)}
|
||||
)}/${TeamType.Organization}`}
|
||||
/>
|
||||
</Route>
|
||||
<Route
|
||||
|
Loading…
x
Reference in New Issue
Block a user