diff options
4 files changed, 70 insertions, 14 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx index a98face63c4..5baaba4ab74 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.tsx @@ -27,6 +27,7 @@ import Modal from 'sonar-ui-common/components/controls/Modal'; import Radio from 'sonar-ui-common/components/controls/Radio'; import SearchSelect from 'sonar-ui-common/components/controls/SearchSelect'; import Select from 'sonar-ui-common/components/controls/Select'; +import Tooltip from 'sonar-ui-common/components/controls/Tooltip'; import IssueTypeIcon from 'sonar-ui-common/components/icons/IssueTypeIcon'; import { Alert } from 'sonar-ui-common/components/ui/Alert'; import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n'; @@ -255,6 +256,19 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> { })); } + canSubmit = () => { + const { addTags, assignee, removeTags, severity, transition, type } = this.state; + + return Boolean( + (addTags && addTags.length > 0) || + (removeTags && removeTags.length > 0) || + assignee || + severity || + transition || + type + ); + }; + renderLoading = () => ( <div> <div className="modal-head"> @@ -487,6 +501,7 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> { const { issues, paging, submitting } = this.state; const limitReached = paging && paging.total > MAX_PAGE_SIZE; + const canSubmit = this.canSubmit(); return ( <form id="bulk-change-form" onSubmit={this.handleSubmit}> @@ -520,9 +535,13 @@ export default class BulkChangeModal extends React.PureComponent<Props, State> { <div className="modal-foot"> {submitting && <i className="spinner spacer-right" />} - <SubmitButton disabled={submitting || issues.length === 0} id="bulk-change-submit"> - {translate('apply')} - </SubmitButton> + <Tooltip overlay={!canSubmit ? translate('issue_bulk_change.no_change_selected') : null}> + <SubmitButton + disabled={!canSubmit || submitting || issues.length === 0} + id="bulk-change-submit"> + {translate('apply')} + </SubmitButton> + </Tooltip> <ResetButtonLink onClick={this.props.onClose}>{translate('cancel')}</ResetButtonLink> </div> </form> diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx b/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx index 9bc940e960c..ec7b73572db 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/BulkChangeModal-test.tsx @@ -19,7 +19,9 @@ */ import { shallow } from 'enzyme'; import * as React from 'react'; -import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; +import { SubmitButton } from 'sonar-ui-common/components/controls/buttons'; +import Select from 'sonar-ui-common/components/controls/Select'; +import { change, waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; import { searchIssueTags } from '../../../../api/issues'; import { mockIssue } from '../../../../helpers/testMocks'; import BulkChangeModal, { MAX_PAGE_SIZE } from '../BulkChangeModal'; @@ -99,6 +101,32 @@ it('should properly handle the search for tags', async () => { expect(searchIssueTags).toBeCalled(); }); +it('should disable the submit button unless some change is configured', async () => { + const wrapper = getWrapper([mockIssue(false, { actions: ['set_severity', 'comment'] })]); + await waitAndUpdate(wrapper); + + return new Promise<void>((resolve, reject) => { + expect(wrapper.find(SubmitButton).props().disabled).toBe(true); + + // Setting a comment is not sufficient; some other change must occur. + change(wrapper.find('#comment'), 'Some comment'); + expect(wrapper.find(SubmitButton).props().disabled).toBe(true); + + const { onChange } = wrapper + .find(Select) + .at(0) + .props(); + if (!onChange) { + reject(); + return; + } + + onChange({ value: 'foo' }); + expect(wrapper.find(SubmitButton).props().disabled).toBe(false); + resolve(); + }); +}); + const getWrapper = (issues: T.Issue[]) => { return shallow<BulkChangeModal>( <BulkChangeModal diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/BulkChangeModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/BulkChangeModal-test.tsx.snap index e8fb769f862..88ef96d3ceb 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/BulkChangeModal-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/__snapshots__/BulkChangeModal-test.tsx.snap @@ -29,12 +29,16 @@ exports[`should display error message when no issues available 1`] = ` <div className="modal-foot" > - <SubmitButton - disabled={true} - id="bulk-change-submit" + <Tooltip + overlay="issue_bulk_change.no_change_selected" > - apply - </SubmitButton> + <SubmitButton + disabled={true} + id="bulk-change-submit" + > + apply + </SubmitButton> + </Tooltip> <ResetButtonLink onClick={[Function]} > @@ -83,12 +87,16 @@ exports[`should display form when issues are present 1`] = ` <div className="modal-foot" > - <SubmitButton - disabled={false} - id="bulk-change-submit" + <Tooltip + overlay="issue_bulk_change.no_change_selected" > - apply - </SubmitButton> + <SubmitButton + disabled={true} + id="bulk-change-submit" + > + apply + </SubmitButton> + </Tooltip> <ResetButtonLink onClick={[Function]} > diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index ec14f5372d2..e0d6b6463e1 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -975,6 +975,7 @@ issue_bulk_change.comment.help=This comment will be applied only to issues that issue_bulk_change.max_issues_reached=There are more issues available than can be treated by a single bulk action. Your changes will only be applied to the first {max} issues. issue_bulk_change.x_issues={0} issues issue_bulk_change.no_match=There is no issue matching your filter selection +issue_bulk_change.no_change_selected=Make at least 1 change (e.g.: change assignee) in order to update the selected issues. #------------------------------------------------------------------------------ |