diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-10-31 16:26:09 +0100 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-11-03 14:28:18 +0100 |
commit | 20a70acea9fad007677c6e5ba28b99a6a7b532cc (patch) | |
tree | 5748fbe5568d81c5f8f0ac72ccbd6cea75d3093e /server/sonar-web/src/main/js/apps/organizations | |
parent | ee2fab297a68aaebcdcb3b71b1fc49f2f89a5d46 (diff) | |
download | sonarqube-20a70acea9fad007677c6e5ba28b99a6a7b532cc.tar.gz sonarqube-20a70acea9fad007677c6e5ba28b99a6a7b532cc.zip |
SONAR-10022 Grouping actions must be consistent
Diffstat (limited to 'server/sonar-web/src/main/js/apps/organizations')
8 files changed, 128 insertions, 181 deletions
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js index 7c5c784dfd6..1147d0239be 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js @@ -24,7 +24,9 @@ import { translateWithParameters } from '../../../helpers/l10n'; import { formatMeasure } from '../../../helpers/measures'; import RemoveMemberForm from './forms/RemoveMemberForm'; import ManageMemberGroupsForm from './forms/ManageMemberGroupsForm'; -import SettingsIcon from '../../../components/icons-components/SettingsIcon'; +import ActionsDropdown, { + ActionsDropdownDivider +} from '../../../components/controls/ActionsDropdown'; /*:: import type { Member } from '../../../store/organizationsMembers/actions'; */ /*:: import type { Organization, OrgGroup } from '../../../store/organizations/duck'; */ @@ -64,31 +66,20 @@ export default class MembersListItem extends React.PureComponent { )} {organization.canAdmin && ( <td className="nowrap text-middle text-right"> - <div className="dropdown"> - <button - className="dropdown-toggle little-spacer-right button-compact" - data-toggle="dropdown"> - <SettingsIcon style={{ marginTop: 4 }} /> <i className="icon-dropdown" /> - </button> - <ul className="dropdown-menu dropdown-menu-right"> - <li> - <ManageMemberGroupsForm - organizationGroups={this.props.organizationGroups} - organization={this.props.organization} - updateMemberGroups={this.props.updateMemberGroups} - member={this.props.member} - /> - </li> - <li role="separator" className="divider" /> - <li> - <RemoveMemberForm - organization={this.props.organization} - removeMember={this.props.removeMember} - member={this.props.member} - /> - </li> - </ul> - </div> + <ActionsDropdown> + <ManageMemberGroupsForm + organizationGroups={this.props.organizationGroups} + organization={this.props.organization} + updateMemberGroups={this.props.updateMemberGroups} + member={this.props.member} + /> + <ActionsDropdownDivider /> + <RemoveMemberForm + organization={this.props.organization} + removeMember={this.props.removeMember} + member={this.props.member} + /> + </ActionsDropdown> </td> )} </tr> diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap index 0bfde40983a..b88cbc6b739 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap +++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/__snapshots__/MembersListItem-test.js.snap @@ -31,70 +31,41 @@ exports[`should groups at 0 if the groupCount field is not defined (just added u <td className="nowrap text-middle text-right" > - <div - className="dropdown" - > - <button - className="dropdown-toggle little-spacer-right button-compact" - data-toggle="dropdown" - > - <SettingsIcon - style={ - Object { - "marginTop": 4, - } + <ActionsDropdown> + <ManageMemberGroupsForm + member={ + Object { + "avatar": "7daf6c79d4802916d83f6266e24850af", + "login": "john", + "name": "John Doe", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", + } + } + /> + <ActionsDropdownDivider /> + <RemoveMemberForm + member={ + Object { + "avatar": "7daf6c79d4802916d83f6266e24850af", + "login": "john", + "name": "John Doe", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", } - /> - - <i - className="icon-dropdown" - /> - </button> - <ul - className="dropdown-menu dropdown-menu-right" - > - <li> - <ManageMemberGroupsForm - member={ - Object { - "avatar": "7daf6c79d4802916d83f6266e24850af", - "login": "john", - "name": "John Doe", - } - } - organization={ - Object { - "canAdmin": true, - "key": "foo", - "name": "Foo", - } - } - /> - </li> - <li - className="divider" - role="separator" - /> - <li> - <RemoveMemberForm - member={ - Object { - "avatar": "7daf6c79d4802916d83f6266e24850af", - "login": "john", - "name": "John Doe", - } - } - organization={ - Object { - "canAdmin": true, - "key": "foo", - "name": "Foo", - } - } - /> - </li> - </ul> - </div> + } + /> + </ActionsDropdown> </td> </tr> `; @@ -156,72 +127,43 @@ exports[`should render actions and groups for admin 1`] = ` <td className="nowrap text-middle text-right" > - <div - className="dropdown" - > - <button - className="dropdown-toggle little-spacer-right button-compact" - data-toggle="dropdown" - > - <SettingsIcon - style={ - Object { - "marginTop": 4, - } + <ActionsDropdown> + <ManageMemberGroupsForm + member={ + Object { + "avatar": "", + "groupCount": 3, + "login": "admin", + "name": "Admin Istrator", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", + } + } + /> + <ActionsDropdownDivider /> + <RemoveMemberForm + member={ + Object { + "avatar": "", + "groupCount": 3, + "login": "admin", + "name": "Admin Istrator", + } + } + organization={ + Object { + "canAdmin": true, + "key": "foo", + "name": "Foo", } - /> - - <i - className="icon-dropdown" - /> - </button> - <ul - className="dropdown-menu dropdown-menu-right" - > - <li> - <ManageMemberGroupsForm - member={ - Object { - "avatar": "", - "groupCount": 3, - "login": "admin", - "name": "Admin Istrator", - } - } - organization={ - Object { - "canAdmin": true, - "key": "foo", - "name": "Foo", - } - } - /> - </li> - <li - className="divider" - role="separator" - /> - <li> - <RemoveMemberForm - member={ - Object { - "avatar": "", - "groupCount": 3, - "login": "admin", - "name": "Admin Istrator", - } - } - organization={ - Object { - "canAdmin": true, - "key": "foo", - "name": "Foo", - } - } - /> - </li> - </ul> - </div> + } + /> + </ActionsDropdown> </td> </tr> `; diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js index 6e8818b6e85..58f6838bc5d 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/ManageMemberGroupsForm.js @@ -24,6 +24,7 @@ import { getUserGroups } from '../../../../api/users'; import Modal from '../../../../components/controls/Modal'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; import OrganizationGroupCheckbox from '../OrganizationGroupCheckbox'; +import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown'; /*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */ /*:: import type { Organization, OrgGroup } from '../../../../store/organizations/duck'; */ @@ -45,14 +46,22 @@ type State = { */ export default class ManageMemberGroupsForm extends React.PureComponent { + /*:: mounted: boolean */ /*:: props: Props; */ state /*: State */ = { open: false }; - openForm = (evt /*: MouseEvent */) => { - evt.preventDefault(); + componentDidMount() { + this.mounted = true; + } + + componentWillUnmount() { + this.mounted = false; + } + + openForm = () => { this.loadUserGroups(); this.setState({ open: true }); }; @@ -63,9 +72,18 @@ export default class ManageMemberGroupsForm extends React.PureComponent { loadUserGroups = () => { this.setState({ loading: true }); - getUserGroups(this.props.member.login, this.props.organization.key).then(response => { - this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') }); - }); + getUserGroups(this.props.member.login, this.props.organization.key).then( + response => { + if (this.mounted) { + this.setState({ loading: false, userGroups: keyBy(response.groups, 'name') }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } + } + ); }; isGroupSelected = (groupName /*: string */) => { @@ -148,9 +166,9 @@ export default class ManageMemberGroupsForm extends React.PureComponent { render() { const buttonComponent = ( - <a key="manage-member-button" onClick={this.openForm} href="#"> + <ActionsDropdownItem onClick={this.openForm}> {translate('organization.members.manage_groups')} - </a> + </ActionsDropdownItem> ); if (this.state.open) { return [buttonComponent, this.renderModal()]; diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js index 94fb72dd24f..9a0db75be63 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/RemoveMemberForm.js @@ -20,6 +20,7 @@ // @flow import React from 'react'; import Modal from '../../../../components/controls/Modal'; +import { ActionsDropdownItem } from '../../../../components/controls/ActionsDropdown'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; /*:: import type { Member } from '../../../../store/organizationsMembers/actions'; */ /*:: import type { Organization } from '../../../../store/organizations/duck'; */ @@ -45,8 +46,7 @@ export default class RemoveMemberForm extends React.PureComponent { open: false }; - openForm = (evt /*: MouseEvent */) => { - evt.preventDefault(); + openForm = () => { this.setState({ open: true }); }; @@ -94,9 +94,9 @@ export default class RemoveMemberForm extends React.PureComponent { render() { const buttonComponent = ( - <a key="remove-member-button" onClick={this.openForm} href="#"> + <ActionsDropdownItem destructive={true} onClick={this.openForm}> {translate('organization.members.remove')} - </a> + </ActionsDropdownItem> ); if (this.state.open) { return [buttonComponent, this.renderModal()]; diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js index c28b5cbcd9a..63503e40918 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/ManageMemberGroupsForm-test.js @@ -82,7 +82,7 @@ it('should render and open the modal', () => { it('should correctly handle user interactions', () => { const form = getMountedForm(); - click(form.wrapper.find('a')); + form.wrapper.find('ActionsDropdownItem').prop('onClick')(); expect(form.wrapper.state('open')).toBeTruthy(); expect(form.instance.loadUserGroups).toBeCalled(); expect(form.wrapper.state()).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js index 5c007ae4123..0fee4e72b58 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/RemoveMemberForm-test.js @@ -42,7 +42,7 @@ it('should correctly handle user interactions', () => { <RemoveMemberForm member={member} removeMember={removeMember} organization={organization} /> ); const instance = wrapper.instance(); - click(wrapper.find('a')); + wrapper.find('ActionsDropdownItem').prop('onClick')(); expect(wrapper.state('open')).toBeTruthy(); instance.handleSubmit(mockEvent); expect(removeMember.mock.calls).toMatchSnapshot(); diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap index 51d9f708ee7..94ff9bb6705 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/ManageMemberGroupsForm-test.js.snap @@ -69,23 +69,20 @@ Object { `; exports[`should render and open the modal 1`] = ` -<a - href="#" - key="manage-member-button" +<ActionsDropdownItem onClick={[Function]} > organization.members.manage_groups -</a> +</ActionsDropdownItem> `; exports[`should render and open the modal 2`] = ` Array [ - <a - href="#" + <ActionsDropdownItem onClick={[Function]} > organization.members.manage_groups - </a>, + </ActionsDropdownItem>, <Modal contentLabel="organization.members.manage_groups" onRequestClose={[Function]} diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap index 3e362fcf4db..861e8d98f02 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/RemoveMemberForm-test.js.snap @@ -14,23 +14,22 @@ Array [ `; exports[`should render and open the modal 1`] = ` -<a - href="#" - key="remove-member-button" +<ActionsDropdownItem + destructive={true} onClick={[Function]} > organization.members.remove -</a> +</ActionsDropdownItem> `; exports[`should render and open the modal 2`] = ` Array [ - <a - href="#" + <ActionsDropdownItem + destructive={true} onClick={[Function]} > organization.members.remove - </a>, + </ActionsDropdownItem>, <Modal contentLabel="users.remove" onRequestClose={[Function]} |