Sfoglia il codice sorgente

Merge pull request #173 from weseek/imprv/upgrade-selective-batch-deletion-in-search-result-page

# Improve/168 Selective batch deletion in search result page
Yuki Takei 8 anni fa
parent
commit
18ec9b383a

+ 5 - 3
resource/js/components/SearchPage/DeletePageListModal.js

@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import { Button, Modal } from 'react-bootstrap';
+import { Button, Modal, Checkbox } from 'react-bootstrap';
 import moment from 'moment';
 
 import ReactUtils from '../ReactUtils';
@@ -43,6 +43,7 @@ export default class DeletePageListModal extends React.Component {
         </Modal.Body>
         <Modal.Footer>
           <span className="text-danger">{this.props.errorMessage}</span>&nbsp;
+          <Checkbox onClick={this.props.toggleDeleteCompletely}>Delete completely</Checkbox>
           <Button onClick={this.props.cancel}>Cancel</Button>
           <Button onClick={this.props.confirmedToDelete} className="btn-danger">Delete</Button>
         </Modal.Footer>
@@ -56,6 +57,7 @@ DeletePageListModal.propTypes = {
   isShown: PropTypes.bool.isRequired,
   pages: PropTypes.array,
   errorMessage: PropTypes.string,
-  cancel: PropTypes.func.isRequired,            // for cancel evnet handling
-  confirmedToDelete: PropTypes.func.isRequired, // for confirmed event handling
+  cancel: PropTypes.func.isRequired,                 // for cancel evnet handling
+  confirmedToDelete: PropTypes.func.isRequired,      // for confirmed event handling
+  toggleDeleteCompletely: PropTypes.func.isRequired, // for delete completely check event handling
 };

+ 62 - 6
resource/js/components/SearchPage/SearchResult.js

@@ -12,9 +12,11 @@ export default class SearchResult extends React.Component {
     this.state = {
       deletionMode : false,
       selectedPages : new Set(),
+      isDeleteCompletely: undefined,
       isDeleteConfirmModalShown: false,
       errorMessageForDeleting: undefined,
     }
+    this.toggleDeleteCompletely = this.toggleDeleteCompletely.bind(this);
     this.deleteSelectedPages = this.deleteSelectedPages.bind(this);
     this.closeDeleteConfirmModal = this.closeDeleteConfirmModal.bind(this);
   }
@@ -50,6 +52,33 @@ export default class SearchResult extends React.Component {
     this.setState({selectedPages: this.state.selectedPages});
   }
 
+  /**
+   * check and return is all pages selected for delete?
+   *
+   * @returns all pages selected (or not)
+   * @memberof SearchResult
+   */
+  isAllSelected() {
+    return this.state.selectedPages.size == this.props.pages.length;
+  }
+
+  /**
+   * handle checkbox clicking that all pages select for delete
+   *
+   * @memberof SearchResult
+   */
+  handleAllSelect() {
+    if (this.isAllSelected()) {
+      this.state.selectedPages.clear();
+    }
+    else {
+      this.state.selectedPages.clear();
+      this.props.pages.map((page) => {
+        this.state.selectedPages.add(page);
+      });
+    }
+    this.setState({selectedPages: this.state.selectedPages});
+  }
   /**
    * change deletion mode
    *
@@ -60,33 +89,44 @@ export default class SearchResult extends React.Component {
     this.setState({deletionMode: !this.state.deletionMode});
   }
 
+  /**
+   * toggle check delete completely
+   *
+   * @memberof SearchResult
+   */
+  toggleDeleteCompletely() {
+    // request で completely が undefined でないと指定アリと見なされるため
+    this.setState({isDeleteCompletely: this.state.isDeleteCompletely? undefined : true});
+  }
+
   /**
    * delete selected pages
    *
    * @memberof SearchResult
    */
   deleteSelectedPages() {
-    let isDeleteComplete = true;
+    let isDeleted = true;
+    let deleteCompletely = this.state.isDeleteCompletely;
     Array.from(this.state.selectedPages).map((page) => {
       const pageId = page._id;
       const revisionId = page.revision._id;
       this.props.crowi.apiPost('/pages.remove',
-        {page_id: pageId, revision_id: revisionId})
+        {page_id: pageId, revision_id: revisionId, completely: deleteCompletely})
       .then(res => {
         if (res.ok) {
           this.state.selectedPages.delete(page);
         }
         else {
-          isDeleteComplete = false;
+          isDeleted = false;
         }
       }).catch(err => {
         console.log(err.message);
-        isDeleteComplete = false;
+        isDeleted = false;
         this.setState({errorMessageForDeleting: err.message});
       });
     });
 
-    if ( isDeleteComplete ) {
+    if ( isDeleted ) {
       window.location.reload();
     }
   }
@@ -143,6 +183,7 @@ export default class SearchResult extends React.Component {
     }
 
     let deletionModeButtons = '';
+    let allSelectCheck = '';
 
     if (this.state.deletionMode) {
       deletionModeButtons =
@@ -150,6 +191,17 @@ export default class SearchResult extends React.Component {
         <button type="button" className="btn btn-danger btn-xs" onClick={() => this.showDeleteConfirmModal()} disabled={this.state.selectedPages.size == 0}><i className="fa fa-trash-o"/> Delete</button>
         <button type="button" className="btn btn-default btn-xs" onClick={() => this.handleDeletionModeChange()}><i className="fa fa-undo"/> Cancel</button>
       </div>
+      allSelectCheck =
+      <div class="form-check">
+        <label class="form-check-label">
+          <input
+            type="checkbox"
+            onClick={() => this.handleAllSelect()}
+            checked={this.isAllSelected()}
+            className="form-check-input"/>
+            &nbsp;Check All
+        </label>
+      </div>
     }
     else {
       deletionModeButtons =
@@ -195,7 +247,10 @@ export default class SearchResult extends React.Component {
         <div className="search-result row" id="search-result">
           <div className="col-md-4 hidden-xs hidden-sm page-list search-result-list" id="search-result-list">
             <nav data-spy="affix" data-offset-top="120">
-              <div className="pull-right">{deletionModeButtons}</div>
+              <div className="pull-right">
+                {deletionModeButtons}
+                {allSelectCheck}
+              </div>
               <div className="search-result-meta">
                 <i className="fa fa-lightbulb-o" /> Found {this.props.searchResultMeta.total} pages with "{this.props.searchingKeyword}"
               </div>
@@ -218,6 +273,7 @@ export default class SearchResult extends React.Component {
           errorMessage={this.state.errorMessageForDeleting}
           cancel={this.closeDeleteConfirmModal}
           confirmedToDelete={this.deleteSelectedPages}
+          toggleDeleteCompletely={this.toggleDeleteCompletely}
         />
 
       </div>//content-main