Fix #3152 Restrict some teams from being displayed during sign up process (#3613)

This commit is contained in:
Sachin Chaurasiya 2022-03-25 11:53:40 +05:30 committed by GitHub
parent c7cb6f22cd
commit 7eff7a0173
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 78 deletions

View File

@ -14,7 +14,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { AxiosResponse } from 'axios';
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import { isEmpty, isUndefined } from 'lodash';
import { observer } from 'mobx-react';
import { TableDetail } from 'Models';
import React, { FunctionComponent, useEffect, useState } from 'react';
@ -36,9 +36,11 @@ type Props = {
currentTier?: string;
currentUser?: string;
hideTier?: boolean;
isJoinable?: boolean;
onSave: (
owner: TableDetail['owner'],
tier: TableDetail['tier']
tier: TableDetail['tier'],
isJoinable?: boolean
) => Promise<void>;
hasEditAccess: boolean;
allowTeamOwner?: boolean;
@ -51,8 +53,9 @@ const ManageTab: FunctionComponent<Props> = ({
onSave,
hasEditAccess,
allowTeamOwner = true,
isJoinable,
}: Props) => {
const { userPermissions } = useAuth();
const { userPermissions, isAdminUser } = useAuth();
const { isAuthDisabled } = useAuthContext();
const getOwnerList = () => {
const user = !isEmpty(appState.userDetails)
@ -113,6 +116,7 @@ const ManageTab: FunctionComponent<Props> = ({
);
const [activeTier, setActiveTier] = useState(currentTier);
const [listVisible, setListVisible] = useState(false);
const [teamJoinable, setTeamJoinable] = useState(isJoinable);
const [tierData, setTierData] = useState<Array<CardWithListItems>>([]);
const [listOwners, setListOwners] = useState(getOwnerList());
@ -163,8 +167,8 @@ const ManageTab: FunctionComponent<Props> = ({
}
: undefined;
if (hideTier) {
if (newOwner) {
onSave(newOwner, '').catch(() => {
if (newOwner || !isUndefined(teamJoinable)) {
onSave(newOwner, '', Boolean(teamJoinable)).catch(() => {
setInitialLoadingState();
});
} else {
@ -172,7 +176,7 @@ const ManageTab: FunctionComponent<Props> = ({
}
} else {
const newTier = activeTier !== currentTier ? activeTier : undefined;
onSave(newOwner, newTier).catch(() => {
onSave(newOwner, newTier, Boolean(teamJoinable)).catch(() => {
setInitialLoadingState();
});
}
@ -242,71 +246,101 @@ const ManageTab: FunctionComponent<Props> = ({
setListOwners(getOwnerList());
}, [appState.users, appState.userDetails, appState.userTeams]);
useEffect(() => {
setTeamJoinable(isJoinable);
}, [isJoinable]);
return (
<div
className="tw-max-w-3xl tw-mx-auto"
data-testid="manage-tab"
id="manageTabDetails">
<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">
<NonAdminAction
html={
<>
<p>You do not have permissions to update the owner.</p>
</>
}
isOwner={hasEditAccess}
permission={Operation.UpdateOwner}
position="left">
<Button
className={classNames('tw-underline', {
'tw-opacity-40':
<div className="tw-mt-2 tw-mb-4 tw-pb-4 tw-border-b tw-border-separator ">
<div>
<span className="tw-mr-2">Owner:</span>
<span className="tw-relative">
<NonAdminAction
html={
<>
<p>You do not have permissions to update the owner.</p>
</>
}
isOwner={hasEditAccess}
permission={Operation.UpdateOwner}
position="left">
<Button
className={classNames('tw-underline', {
'tw-opacity-40':
!userPermissions[Operation.UpdateOwner] &&
!isAuthDisabled &&
!hasEditAccess,
})}
data-testid="owner-dropdown"
disabled={
!userPermissions[Operation.UpdateOwner] &&
!isAuthDisabled &&
!hasEditAccess,
})}
data-testid="owner-dropdown"
disabled={
!userPermissions[Operation.UpdateOwner] &&
!isAuthDisabled &&
!hasEditAccess
}
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"
!hasEditAccess
}
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
dropDownList={listOwners}
groupType="tab"
listGroups={getOwnerGroup()}
value={owner}
onSelect={handleOwnerSelection}
/>
</Button>
</NonAdminAction>
{listVisible && (
<DropDownList
showSearchBar
dropDownList={listOwners}
groupType="tab"
listGroups={getOwnerGroup()}
value={owner}
onSelect={handleOwnerSelection}
/>
)}
</span>
)}
</span>
</div>
{!isUndefined(isJoinable) ? (
<div className="tw-mt-3 tw-mb-1">
{isAdminUser ||
isAuthDisabled ||
userPermissions[Operation.UpdateTeam] ||
!hasEditAccess ? (
<div className="tw-flex">
<label htmlFor="join-team">
Allow users to join this team during signup
</label>
<div
className={classNames(
'toggle-switch ',
teamJoinable ? 'open' : null
)}
data-testid="team-isJoinable-switch"
id="join-team"
onClick={() => setTeamJoinable((prev) => !prev)}>
<div className="switch" />
</div>
</div>
) : null}
</div>
) : null}
</div>
{!hideTier &&
(isLoadingTierData ? (

View File

@ -33,6 +33,15 @@ jest.mock('../../auth-provider/AuthProvider', () => {
};
});
jest.mock('../../hooks/authHooks', () => ({
useAuth: jest.fn().mockReturnValue({
isAdminUser: true,
userPermissions: {
UpdateTeam: true,
},
}),
}));
const mockTierData = {
children: [
{
@ -118,4 +127,29 @@ describe('Test Manage tab Component', () => {
expect(mockFunction).toBeCalledTimes(1);
});
it('Should render switch if isJoinable is present', async () => {
const { container } = render(
<ManageTab hasEditAccess isJoinable onSave={mockFunction} />
);
const isJoinableSwitch = await findByTestId(
container,
'team-isJoinable-switch'
);
expect(isJoinableSwitch).toHaveClass('open');
fireEvent.click(
isJoinableSwitch,
new MouseEvent('click', {
bubbles: true,
cancelable: true,
})
);
expect(isJoinableSwitch).not.toHaveClass('open');
expect(isJoinableSwitch).toBeInTheDocument();
});
});

View File

@ -64,6 +64,7 @@ const jsonData = {
'update-glossary-term-error': 'Error while updating glossary term!',
'update-description-error': 'Error while updating description!',
'update-entity-error': 'Error while updating entity!',
'update-team-error': 'Error while updating team',
'update-tags-error': 'Error while updating tags!',
'update-entity-follow-error': 'Error while following entity!',
'update-entity-unfollow-error': 'Error while unfollowing entity!',

View File

@ -23,14 +23,11 @@ import { Button } from '../../components/buttons/Button/Button';
import PageContainer from '../../components/containers/PageContainer';
import DropDown from '../../components/dropdown/DropDown';
import { ROUTES } from '../../constants/constants';
import { Team } from '../../generated/entity/teams/team';
import { getNameFromEmail } from '../../utils/AuthProvider.util';
import { getImages } from '../../utils/CommonUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
import { fetchAllUsers } from '../../utils/UsedDataUtils';
type Team = {
id: string;
displayName: string;
};
const Signup = () => {
const [selectedTeams, setSelectedTeams] = useState<Array<string | undefined>>(
@ -113,12 +110,14 @@ const Signup = () => {
};
const getTeamsData = (teams: Array<Team>) => {
return teams.map((team: Team) => {
return {
name: team.displayName,
value: team.id,
};
});
return teams
.filter((team) => team.isJoinable)
.map((team: Team) => {
return {
name: team.displayName as string,
value: team.id,
};
});
};
const errorMsg = (value: string) => {
return (

View File

@ -305,10 +305,12 @@ describe('Test Teams page', () => {
it('OnClick of manage tab, manage tab content should render', async () => {
const { container } = render(<TeamsPage />);
const assets = await findByTestId(container, 'manage');
const manage = await findByTestId(container, 'manage');
expect(manage).toBeInTheDocument();
fireEvent.click(
assets,
manage,
new MouseEvent('click', {
bubbles: true,
cancelable: true,

View File

@ -565,10 +565,18 @@ const TeamsPage = () => {
return uniqueList;
};
const handleUpdateOwner = (owner: Team['owner']) => {
const handleUpdateOwner = (
owner: Team['owner'],
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_tier = '',
isJoinable?: boolean
) => {
const updatedTeam = {
...currentTeam,
owner,
owner: !isUndefined(owner) ? owner : currentTeam?.owner,
isJoinable: !isUndefined(isJoinable)
? isJoinable
: currentTeam?.isJoinable,
};
const jsonPatch = compare(currentTeam as Team, updatedTeam);
@ -629,7 +637,7 @@ const TeamsPage = () => {
title={currentTeam?.displayName ?? currentTeam?.name}>
{currentTeam?.displayName ?? currentTeam?.name}
</div>
<div>
<div className="tw-flex">
<NonAdminAction
html={
<Fragment>
@ -731,6 +739,7 @@ const TeamsPage = () => {
allowTeamOwner={false}
currentUser={currentTeam?.owner?.id}
hasEditAccess={isOwner()}
isJoinable={currentTeam?.isJoinable}
onSave={handleUpdateOwner}
/>
)}