Fix #3001: Support to provide team deletion from UI (#3495)

This commit is contained in:
darth-coder00 2022-03-18 10:32:27 +05:30 committed by GitHub
parent 87335137e5
commit c586bb1aed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 150 additions and 26 deletions

View File

@ -44,3 +44,7 @@ export const patchTeamDetail: Function = (id: string, data: Team) => {
return APIClient.patch(`/teams/${id}`, data, configOptions);
};
export const deleteTeam = (id: string): Promise<AxiosResponse> => {
return APIClient.delete(`/teams/${id}`);
};

View File

@ -19,6 +19,7 @@ import { Link } from 'react-router-dom';
import AppState from '../../AppState';
import {
getExplorePathWithSearch,
getTeamDetailsPath,
ROUTES,
TITLE_FOR_NON_ADMIN_ACTION,
} from '../../constants/constants';
@ -103,7 +104,7 @@ const MyAssetStats: FunctionComponent<Props> = ({
icon: Icons.TEAMS_GREY,
data: 'Teams',
count: userTeams.length,
link: ROUTES.TEAMS,
link: getTeamDetailsPath(),
dataTestId: 'terms',
},
};

View File

@ -274,9 +274,12 @@ export const getPipelineDetailsPath = (pipelineFQN: string, tab?: string) => {
return path;
};
export const getTeamDetailsPath = (teamName: string) => {
let path = ROUTES.TEAM_DETAILS;
path = path.replace(PLACEHOLDER_ROUTE_TEAM, teamName);
export const getTeamDetailsPath = (teamName?: string) => {
let path = ROUTES.TEAMS;
if (teamName) {
path = ROUTES.TEAM_DETAILS;
path = path.replace(PLACEHOLDER_ROUTE_TEAM, teamName);
}
return path;
};

View File

@ -17,6 +17,7 @@ const jsonData = {
'add-glossary-term-error': 'Error while adding glossary term!',
'delete-glossary-error': 'Error while deleting glossary!',
'delete-glossary-term-error': 'Error while deleting glossary term!',
'delete-team-error': 'Error while deleting team!',
'elastic-search-error': 'Error while fetch data from Elasticsearch!',
'fetch-data-error': 'Error while fetching data!',
'fetch-glossary-error': 'Error while fetching glossary!',

View File

@ -107,6 +107,7 @@ jest.mock('../../axiosAPIs/teamsAPI', () => ({
Promise.resolve({ data: { data: mockTeamsData } })
),
patchTeamDetail: jest.fn(),
deleteTeam: jest.fn(),
}));
jest.mock(
@ -269,4 +270,30 @@ describe('Test Teams page', () => {
expect(await findByTestId(container, 'form-modal')).toBeInTheDocument();
});
it('onClick of delete team button, delete modal should open', async () => {
const { container } = render(<TeamsPage />);
const deleteTeamButton = await findByTestId(
container,
'delete-team-button'
);
expect(deleteTeamButton).toBeInTheDocument();
fireEvent.click(
deleteTeamButton,
new MouseEvent('click', {
bubbles: true,
cancelable: true,
})
);
const confirmationModal = await findByTestId(
container,
'confirmation-modal'
);
expect(confirmationModal).toBeInTheDocument();
});
});

View File

@ -11,6 +11,7 @@
* limitations under the License.
*/
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { AxiosError, AxiosResponse } from 'axios';
import classNames from 'classnames';
import { compare } from 'fast-json-patch';
@ -23,6 +24,7 @@ import AppState from '../../AppState';
import { useAuthContext } from '../../auth-provider/AuthProvider';
import {
createTeam,
deleteTeam,
getTeamByName,
getTeams,
patchTeamDetail,
@ -50,6 +52,7 @@ import {
} from '../../generated/entity/teams/user';
import { useAuth } from '../../hooks/authHooks';
import useToastContext from '../../hooks/useToastContext';
import jsonData from '../../jsons/en';
import {
getActiveCatClass,
getCountBadge,
@ -58,7 +61,6 @@ import {
import AddUsersModal from './AddUsersModal';
import Form from './Form';
import UserCard from './UserCard';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const TeamsPage = () => {
const { team } = useParams() as Record<string, string>;
@ -79,9 +81,20 @@ const TeamsPage = () => {
user: EntityReference | undefined;
state: boolean;
}>({ user: undefined, state: false });
const [deletingTeam, setDeletingTeam] = useState<{
team: Team | undefined;
state: boolean;
}>({ team: undefined, state: false });
const showToast = useToastContext();
const handleShowErrorToast = (errMessage: string) => {
showToast({
variant: 'error',
body: errMessage,
});
};
const fetchTeams = () => {
setIsLoading(true);
getTeams(['users', 'owns', 'defaultRoles'])
@ -102,6 +115,15 @@ const TeamsPage = () => {
});
};
const goToTeams = () => {
if (team) {
history.push(getTeamDetailsPath());
} else {
fetchTeams();
setCurrentTab(1);
}
};
const fetchCurrentTeam = (name: string, update = false) => {
if (currentTeam?.name !== name || update) {
setIsLoading(true);
@ -226,6 +248,33 @@ const TeamsPage = () => {
});
};
const deleteTeamHandler = () => {
const team = currentTeam;
setDeletingTeam({ team: team, state: true });
};
const deleteTeamById = (id: string) => {
deleteTeam(id)
.then((res: AxiosResponse) => {
if (res.data) {
goToTeams();
} else {
handleShowErrorToast(
jsonData['api-error-messages']['delete-team-error']
);
}
})
.catch((err: AxiosError) => {
handleShowErrorToast(
err.response?.data?.message ||
jsonData['api-error-messages']['delete-team-error']
);
})
.finally(() => {
setDeletingTeam({ team: undefined, state: false });
});
};
const getActiveTabClass = (tab: number) => {
return tab === currentTab ? 'active' : '';
};
@ -514,27 +563,50 @@ const TeamsPage = () => {
title={currentTeam?.displayName ?? currentTeam?.name}>
{currentTeam?.displayName ?? currentTeam?.name}
</div>
<NonAdminAction
html={
<>You do not have permission to update the team.</>
}
permission={Operation.UpdateTeam}
position="bottom">
<Button
className={classNames('tw-h-8 tw-rounded tw-mb-3', {
'tw-opacity-40':
!isAdminUser &&
!isAuthDisabled &&
!userPermissions[Operation.UpdateTeam],
})}
data-testid="add-new-user-button"
size="small"
theme="primary"
variant="contained"
onClick={() => setIsAddingUsers(true)}>
Add new user
</Button>
</NonAdminAction>
<div>
<NonAdminAction
html={
<>You do not have permission to update the team.</>
}
permission={Operation.UpdateTeam}
position="bottom">
<Button
className={classNames('tw-h-8 tw-rounded tw-mb-3', {
'tw-opacity-40':
!isAdminUser &&
!isAuthDisabled &&
!userPermissions[Operation.UpdateTeam],
})}
data-testid="add-new-user-button"
size="small"
theme="primary"
variant="contained"
onClick={() => setIsAddingUsers(true)}>
Add new user
</Button>
</NonAdminAction>
<NonAdminAction
html={
<>You do not have permission to delete the team.</>
}
position="bottom">
<Button
className={classNames(
'tw-h-8 tw-rounded tw-mb-3 tw-ml-2',
{
'tw-opacity-40':
!isAdminUser && !isAuthDisabled,
}
)}
data-testid="delete-team-button"
size="small"
theme="primary"
variant="contained"
onClick={() => deleteTeamHandler()}>
Delete Team
</Button>
</NonAdminAction>
</div>
</div>
<div
className="tw-mb-3 tw--ml-5"
@ -625,6 +697,22 @@ const TeamsPage = () => {
}}
/>
)}
{deletingTeam.state && (
<ConfirmationModal
bodyText={`Are you sure you want to delete the team "${
deletingTeam.team?.displayName || deletingTeam.team?.name
}"?`}
cancelText="Cancel"
confirmText="Confirm"
header="Delete Team"
onCancel={() =>
setDeletingTeam({ team: undefined, state: false })
}
onConfirm={() => {
deleteTeamById(deletingTeam.team?.id as string);
}}
/>
)}
</div>
)}
</PageLayout>