diff options
author | Guillaume Peoc'h <guillaume.peoch@sonarsource.com> | 2022-08-31 14:33:29 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-09-02 20:02:50 +0000 |
commit | 8d93c685bdcd3a867b12020e1ebc20f12ba3a3ac (patch) | |
tree | 5e6920afb634f5f9a50b0eea6ea14ec7b0ee3fda /server/sonar-web | |
parent | 687d0b26d6355627ce5704dbc3118b66ebad85c6 (diff) | |
download | sonarqube-8d93c685bdcd3a867b12020e1ebc20f12ba3a3ac.tar.gz sonarqube-8d93c685bdcd3a867b12020e1ebc20f12ba3a3ac.zip |
SONAR-17242 Add anonymize checkbox to user deactivation form
Diffstat (limited to 'server/sonar-web')
3 files changed, 89 insertions, 5 deletions
diff --git a/server/sonar-web/src/main/js/api/users.ts b/server/sonar-web/src/main/js/api/users.ts index a5154d91839..423c3b67b80 100644 --- a/server/sonar-web/src/main/js/api/users.ts +++ b/server/sonar-web/src/main/js/api/users.ts @@ -92,7 +92,7 @@ export function updateUser(data: { }); } -export function deactivateUser(data: { login: string }): Promise<User> { +export function deactivateUser(data: { login: string; anonymize?: boolean }): Promise<User> { return postJSON('/api/users/deactivate', data).catch(throwGlobalError); } diff --git a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx index 8f4b6414e0f..f0705457e0b 100644 --- a/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx +++ b/server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx @@ -18,9 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; +import { FormattedMessage } from 'react-intl'; import { deactivateUser } from '../../../api/users'; import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons'; +import Checkbox from '../../../components/controls/Checkbox'; import Modal from '../../../components/controls/Modal'; +import { Alert } from '../../../components/ui/Alert'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { UserActive } from '../../../types/users'; @@ -32,11 +35,12 @@ export interface Props { interface State { submitting: boolean; + anonymize: boolean; } export default class DeactivateForm extends React.PureComponent<Props, State> { mounted = false; - state: State = { submitting: false }; + state: State = { submitting: false, anonymize: false }; componentDidMount() { this.mounted = true; @@ -46,10 +50,14 @@ export default class DeactivateForm extends React.PureComponent<Props, State> { this.mounted = false; } + handleAnonymize = (checked: boolean) => { + this.setState({ anonymize: checked }); + }; + handleDeactivate = (event: React.SyntheticEvent<HTMLFormElement>) => { event.preventDefault(); this.setState({ submitting: true }); - deactivateUser({ login: this.props.user.login }).then( + deactivateUser({ login: this.props.user.login, anonymize: this.state.anonymize }).then( () => { this.props.onUpdateUsers(); this.props.onClose(); @@ -64,7 +72,7 @@ export default class DeactivateForm extends React.PureComponent<Props, State> { render() { const { user } = this.props; - const { submitting } = this.state; + const { submitting, anonymize } = this.state; const header = translate('users.deactivate_user'); return ( @@ -73,8 +81,35 @@ export default class DeactivateForm extends React.PureComponent<Props, State> { <header className="modal-head"> <h2>{header}</h2> </header> - <div className="modal-body"> + <div className="modal-body display-flex-column"> {translateWithParameters('users.deactivate_user.confirmation', user.name, user.login)} + <Checkbox + id="delete-user" + className="big-spacer-top" + checked={anonymize} + onCheck={this.handleAnonymize}> + <label className="little-spacer-left" htmlFor="delete-user"> + {translate('users.delete_user')} + </label> + </Checkbox> + {anonymize && ( + <Alert variant="warning" className="big-spacer-top"> + <FormattedMessage + defaultMessage={translate('users.delete_user.help')} + id="delete-user-warning" + values={{ + link: ( + <a + href="/documentation/instance-administration/authentication/overview/" + rel="noopener noreferrer" + target="_blank"> + {translate('users.delete_user.help.link')} + </a> + ) + }} + /> + </Alert> + )} </div> <footer className="modal-foot"> {submitting && <i className="spinner spacer-right" />} diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/DeactivateForm-test.tsx b/server/sonar-web/src/main/js/apps/users/components/__tests__/DeactivateForm-test.tsx new file mode 100644 index 00000000000..ac27a479063 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/DeactivateForm-test.tsx @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { render, screen } from '@testing-library/react'; +import * as React from 'react'; +import { IntlProvider } from 'react-intl'; +import { deactivateUser } from '../../../../api/users'; +import { mockUser } from '../../../../helpers/testMocks'; +import { UserActive } from '../../../../types/users'; +import DeactivateForm from '../DeactivateForm'; + +jest.mock('../../../../api/users', () => ({ + deactivateUser: jest.fn().mockResolvedValue({}) +})); + +it.each([true, false])('should deactivate user with anonymize set to %s', anonymize => { + const user = mockUser() as UserActive; + renderDeactivateForm(user); + if (anonymize) { + screen.getByRole('checkbox').click(); + expect(screen.getByRole('alert')).toBeInTheDocument(); + } + screen.getByRole('button', { name: 'users.deactivate' }).click(); + expect(deactivateUser).toBeCalledWith({ login: user.login, anonymize }); +}); + +function renderDeactivateForm(user: UserActive) { + return render( + <IntlProvider defaultLocale="en" locale="en"> + <DeactivateForm onClose={jest.fn()} onUpdateUsers={jest.fn()} user={user} /> + </IntlProvider> + ); +} |