aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web
diff options
context:
space:
mode:
authorPascal Mugnier <pascal.mugnier@sonarsource.com>2018-03-08 11:14:02 +0100
committerGitHub <noreply@github.com>2018-03-08 11:14:02 +0100
commit5bafba36f7cfadcfe035153d33b3fdf495d62811 (patch)
tree53e76f73b02f912286f83e71159744c3fb8f6ed8 /server/sonar-web
parent115d4dae736d0f0c31675de7c0d8286db02a4798 (diff)
downloadsonarqube-5bafba36f7cfadcfe035153d33b3fdf495d62811.tar.gz
sonarqube-5bafba36f7cfadcfe035153d33b3fdf495d62811.zip
SONAR-10476 Add a checkbox on top of issues list to allow global selection/unselection (#3131)
Diffstat (limited to 'server/sonar-web')
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/App.js24
-rw-r--r--server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js28
2 files changed, 50 insertions, 2 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.js b/server/sonar-web/src/main/js/apps/issues/components/App.js
index 02c1a0e1e47..2c7181ff027 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/App.js
+++ b/server/sonar-web/src/main/js/apps/issues/components/App.js
@@ -62,6 +62,7 @@ import ScreenPositionHelper from '../../../components/common/ScreenPositionHelpe
import { getBranchName, isShortLivingBranch } from '../../../helpers/branches';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { scrollToElement } from '../../../helpers/scrolling';
+import Checkbox from '../../../components/controls/Checkbox';
/*:: import type { Issue } from '../../../components/issue/types'; */
/*:: import type { RawQuery } from '../../../helpers/query'; */
import '../styles.css';
@@ -741,9 +742,21 @@ export default class App extends React.PureComponent {
selectNextFlow = () => this.setState(actions.selectNextFlow);
selectPreviousFlow = () => this.setState(actions.selectPreviousFlow);
+ onCheckAll = (checked /*: boolean */) => {
+ if (checked) {
+ this.setState(state => ({ checked: state.issues.map(issue => issue.key) }));
+ } else {
+ this.setState(state => ({ checked: [] }));
+ }
+ };
+
renderBulkChange(openIssue /*: ?Issue */) {
const { component, currentUser } = this.props;
- const { bulkChange, checked, paging } = this.state;
+ const { bulkChange, checked, paging, issues } = this.state;
+
+ const isAllChecked = checked.length > 0 && issues.length === checked.length;
+ const thirdState = checked.length > 0 && !isAllChecked;
+ const isChecked = isAllChecked || thirdState;
if (!currentUser.isLoggedIn || openIssue != null) {
return null;
@@ -751,8 +764,15 @@ export default class App extends React.PureComponent {
return (
<div className="pull-left">
+ <Checkbox
+ checked={isChecked}
+ className="spacer-right vertical-middle"
+ id="issues-selection"
+ onCheck={this.onCheckAll}
+ thirdState={thirdState}
+ />
{checked.length > 0 ? (
- <div className="dropdown">
+ <div className="dropdown display-inline-block">
<button id="issues-bulk-change" data-toggle="dropdown">
{translate('bulk_change')}
<i className="icon-dropdown little-spacer-left" />
diff --git a/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js b/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js
index 7cf87139121..dfc109dcb2b 100644
--- a/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js
+++ b/server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js
@@ -92,3 +92,31 @@ it('should avoid non-existing keys', async () => {
wrapper.instance().handleIssueCheck('non-existing-key', eventWithShiftKey);
expect(wrapper.state().checked.length).toBe(1);
});
+
+it('should be able to uncheck all issue with global checkbox', async () => {
+ const wrapper = shallowWithIntl(<App {...PROPS} />, {
+ context: { router: { replace } }
+ });
+
+ await waitAndUpdate(wrapper);
+ expect(wrapper.state().issues.length).toBe(4);
+
+ wrapper.instance().handleIssueCheck('foo', eventNoShiftKey);
+ wrapper.instance().handleIssueCheck('bar', eventNoShiftKey);
+ expect(wrapper.state().checked.length).toBe(2);
+
+ wrapper.instance().onCheckAll(false);
+ expect(wrapper.state().checked.length).toBe(0);
+});
+
+it('should be able to check all issue with global checkbox', async () => {
+ const wrapper = shallowWithIntl(<App {...PROPS} />, {
+ context: { router: { replace } }
+ });
+
+ await waitAndUpdate(wrapper);
+
+ expect(wrapper.state().checked.length).toBe(0);
+ wrapper.instance().onCheckAll(true);
+ expect(wrapper.state().checked.length).toBe(wrapper.state().issues.length);
+});