]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10476 Add a checkbox on top of issues list to allow global selection/unselectio...
authorPascal Mugnier <pascal.mugnier@sonarsource.com>
Thu, 8 Mar 2018 10:14:02 +0000 (11:14 +0100)
committerGitHub <noreply@github.com>
Thu, 8 Mar 2018 10:14:02 +0000 (11:14 +0100)
server/sonar-web/src/main/js/apps/issues/components/App.js
server/sonar-web/src/main/js/apps/issues/components/__tests__/App-test.js

index 02c1a0e1e47fe20afcc9ee6db0ad370975c22b3c..2c7181ff027b013f2e88cba29c228c37858cd01a 100644 (file)
@@ -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" />
index 7cf87139121a525a39b96912811bfbf66fd1bc8a..dfc109dcb2b059b6d96b57d769d86324cc48f8fb 100644 (file)
@@ -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);
+});