You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by GitBox <gi...@apache.org> on 2018/03/19 10:44:16 UTC

[GitHub] garrensmith closed pull request #1065: Remove JQuery uses from documents addon

garrensmith closed pull request #1065: Remove JQuery uses from documents addon
URL: https://github.com/apache/couchdb-fauxton/pull/1065
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/app/addons/documents/__tests__/resources.test.js b/app/addons/documents/__tests__/resources.test.js
index c6951ea2e..4505015d1 100644
--- a/app/addons/documents/__tests__/resources.test.js
+++ b/app/addons/documents/__tests__/resources.test.js
@@ -181,6 +181,8 @@ describe('Bulk Delete', () => {
   let databaseId = 'ente',
       collection,
       promise,
+      resolve,
+      reject,
       values;
 
   values = [{
@@ -204,7 +206,10 @@ describe('Bulk Delete', () => {
       databaseId: databaseId
     });
 
-    promise = FauxtonAPI.Deferred();
+    promise = new FauxtonAPI.Promise((res, rej) => {
+      resolve = res;
+      reject = rej;
+    });
   });
 
   it('contains the models', () => {
@@ -219,7 +224,7 @@ describe('Bulk Delete', () => {
     collection.handleResponse([
       {'ok': true, 'id': '1', 'rev': '10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok': true, 'id': '2', 'rev': '6-da537822b9672a4b2f42adb1be04a5b1'}
-    ], promise);
+    ], resolve, reject);
 
     return promise.then(() => {
       assert.equal(collection.length, 1);
@@ -235,7 +240,7 @@ describe('Bulk Delete', () => {
     collection.handleResponse([
       {'ok': true, 'id': 'Deferred', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok': true, 'id': 'DeskSet', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'}
-    ], promise);
+    ], resolve, reject);
   });
 
   it('triggers a error event with all errored ids', (done) => {
@@ -247,7 +252,7 @@ describe('Bulk Delete', () => {
     collection.handleResponse([
       {'error':'conflict', 'id':'Deferred', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok':true, 'id':'DeskSet', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'}
-    ], promise);
+    ], resolve, reject);
   });
 
   it('removes successfull deleted from the collection but keeps one with errors', () => {
@@ -255,7 +260,7 @@ describe('Bulk Delete', () => {
       {'error':'conflict', 'id':'1', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok':true, 'id':'2', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'},
       {'error':'conflict', 'id':'3', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'}
-    ], promise);
+    ], resolve, reject);
 
     return promise.then(() => {
       assert.ok(collection.get('1'));
@@ -271,7 +276,7 @@ describe('Bulk Delete', () => {
     collection.handleResponse([
       {'ok':true, 'id':'Deferred', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok':true, 'id':'DeskSet', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'}
-    ], promise);
+    ], resolve, reject);
 
     return promise.then(() => {
       assert.ok(spy.calledOnce);
@@ -290,7 +295,7 @@ describe('Bulk Delete', () => {
       {'ok':true, 'id':'Deferred', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
       {'ok':true, 'id':'DeskSet', 'rev':'6-da537822b9672a4b2f42adb1be04a5b1'},
       {'error':'conflict', 'id':'1', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'},
-    ], promise);
+    ], resolve, reject);
 
     return promise.then(() => {
       assert.ok(spy.calledWith(ids));
@@ -300,7 +305,7 @@ describe('Bulk Delete', () => {
   it('triggers reject for failed delete', () => {
     collection.handleResponse([
       {'error':'conflict', 'id':'1', 'rev':'10-72cd2edbcc0d197ce96188a229a7af01'}
-    ], promise);
+    ], resolve, reject);
 
     return promise.catch((errors) => {
       assert.deepEqual(errors, ['1']);
diff --git a/app/addons/documents/changes/actions.js b/app/addons/documents/changes/actions.js
index a414c470e..224bd12ff 100644
--- a/app/addons/documents/changes/actions.js
+++ b/app/addons/documents/changes/actions.js
@@ -13,6 +13,7 @@
 
 import app from "../../../app";
 import FauxtonAPI from "../../../core/api";
+import { get } from "../../../core/ajax";
 import ActionTypes from "./actiontypes";
 import Stores from "./stores";
 import Helpers from "../helpers";
@@ -61,8 +62,18 @@ export default {
     const query = app.utils.queryParams(params);
     const db = app.utils.safeURLName(changesStore.getDatabaseName());
     const endpoint = FauxtonAPI.urls('changes', 'server', db, '?' + query);
-    currentRequest = $.getJSON(endpoint);
-    currentRequest.then(this.updateChanges.bind(this));
+    get(endpoint).then((res) => {
+      if (res.error) {
+        throw new Error(res.reason || res.error);
+      }
+      this.updateChanges(res);
+    }).catch((err) => {
+      FauxtonAPI.addNotification({
+        msg: 'Error loading list of changes. Reason: ' + err.message,
+        type: 'error',
+        clear: true
+      });
+    });
   },
 
   updateChanges: function (json) {
diff --git a/app/addons/documents/components/actions.js b/app/addons/documents/components/actions.js
index b0f9e5f1a..765c7cb15 100644
--- a/app/addons/documents/components/actions.js
+++ b/app/addons/documents/components/actions.js
@@ -9,9 +9,9 @@
 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 // License for the specific language governing permissions and limitations under
 // the License.
-import $ from 'jquery';
 import app from "../../../app";
 import FauxtonAPI from "../../../core/api";
+import { get } from "../../../core/ajax";
 
 export default {
   fetchAllDocsWithKey: (database) => {
@@ -23,17 +23,15 @@ export default {
       });
 
       const url = FauxtonAPI.urls('allDocs', 'server', database.safeID(), query);
-      $.ajax({
-        cache: false,
-        url: url,
-        dataType: 'json'
-      }).then(({rows}) => {
-        const options = rows.map(row => {
-          return { value: row.id, label: row.id};
-        });
-        callback(null, {
-          options: options
-        });
+      get(url).then(res => {
+        let options = [];
+        if (!res.error) {
+          const {rows} = res;
+          options = rows.map(row => {
+            return { value: row.id, label: row.id};
+          });
+        }
+        callback(null, { options: options });
       });
     };
   }
diff --git a/app/addons/documents/doc-editor/__tests__/doc-editor.actions.test.js b/app/addons/documents/doc-editor/__tests__/doc-editor.actions.test.js
index 85527f03a..603a0e61a 100644
--- a/app/addons/documents/doc-editor/__tests__/doc-editor.actions.test.js
+++ b/app/addons/documents/doc-editor/__tests__/doc-editor.actions.test.js
@@ -22,11 +22,23 @@ const { restore } = utils;
 describe('DocEditorActions', () => {
   const database = new Databases.Model({ id: 'db1' });
   const doc = new Documents.Doc({ _id: 'foo' }, { database: database });
+  let fakeXMLHttpRequest, fakeOpen;
+
+  beforeEach(() => {
+    fakeXMLHttpRequest = sinon.stub(global, 'XMLHttpRequest');
+    fakeOpen = sinon.stub();
+    fakeXMLHttpRequest.returns({
+      send: sinon.stub(),
+      setRequestHeader: sinon.stub(),
+      open: fakeOpen
+    });
+  });
 
   afterEach(() => {
     restore(FauxtonAPI.addNotification);
     restore(FauxtonAPI.navigate);
     restore(FauxtonAPI.urls);
+    fakeXMLHttpRequest.restore();
   });
 
   it('uploadAttachment handles filenames with special chars', () => {
@@ -34,7 +46,6 @@ describe('DocEditorActions', () => {
     sinon.stub(FauxtonAPI, 'urls').callsFake((p1, p2, p3, p4, p5, p6) => {
       return [p1, p2, p3, p4, p5, p6].join('/');
     });
-    const stub = sinon.stub($, 'ajax');
     const params = {
       rev: 'rev-num',
       doc: doc,
@@ -47,10 +58,10 @@ describe('DocEditorActions', () => {
     };
 
     Actions.uploadAttachment(params);
-    sinon.assert.calledWithMatch(stub,
-      {
-        url: 'document/attachment/db1/foo/' + encodeURIComponent(params.files[0].name) + '/?rev=rev-num'
-      }
+    sinon.assert.calledWithExactly(
+      fakeOpen,
+      'PUT',
+      'document/attachment/db1/foo/' + encodeURIComponent(params.files[0].name) + '/?rev=rev-num'
     );
   });
 
diff --git a/app/addons/documents/doc-editor/actions.js b/app/addons/documents/doc-editor/actions.js
index 2c0da69a5..6d0abc121 100644
--- a/app/addons/documents/doc-editor/actions.js
+++ b/app/addons/documents/doc-editor/actions.js
@@ -13,9 +13,10 @@
 /* global FormData */
 
 import FauxtonAPI from "../../../core/api";
+import { deleteRequest } from "../../../core/ajax";
 import ActionTypes from "./actiontypes";
 
-var xhr;
+var currentUploadHttpRequest;
 
 function initDocEditor (params) {
   var doc = params.doc;
@@ -79,33 +80,25 @@ function hideDeleteDocModal () {
 }
 
 function deleteDoc (doc) {
-  var databaseName = doc.database.safeID();
-  var query = '?rev=' + doc.get('_rev');
-
-  $.ajax({
-    url: FauxtonAPI.urls('document', 'server', databaseName, doc.safeID(), query),
-    type: 'DELETE',
-    headers: {
-      'Accept': 'application/json',
-      'Content-Type': 'application/json',
-    },
-    xhrFields: {
-      withCredentials: true
-    },
-    success: function () {
-      FauxtonAPI.addNotification({
-        msg: 'Your document has been successfully deleted.',
-        clear: true
-      });
-      FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', databaseName, ''));
-    },
-    error: function () {
-      FauxtonAPI.addNotification({
-        msg: 'Failed to delete your document!',
-        type: 'error',
-        clear: true
-      });
+  const databaseName = doc.database.safeID();
+  const query = '?rev=' + doc.get('_rev');
+  const url = FauxtonAPI.urls('document', 'server', databaseName, doc.safeID(), query);
+  deleteRequest(url).then(res => {
+    if (res.error) {
+      throw new Error(res.reason || res.error);
     }
+    FauxtonAPI.addNotification({
+      msg: 'Your document has been successfully deleted.',
+      type: 'success',
+      clear: true
+    });
+    FauxtonAPI.navigate(FauxtonAPI.urls('allDocs', 'app', databaseName, ''));
+  }).catch(err => {
+    FauxtonAPI.addNotification({
+      msg: 'Failed to delete your document. Reason: ' + err.message,
+      type: 'error',
+      clear: true
+    });
   });
 }
 
@@ -156,75 +149,88 @@ function uploadAttachment (params) {
     });
     return;
   }
-
   FauxtonAPI.dispatch({ type: ActionTypes.START_FILE_UPLOAD });
 
-  // store the xhr in parent scope to allow us to cancel any uploads if the user closes the modal
-  xhr = $.ajaxSettings.xhr();
-
-  var query = '?rev=' + params.rev;
-  var db = params.doc.getDatabase().safeID();
-  var docId = params.doc.safeID();
-  var file = params.files[0];
-
-  $.ajax({
-    url: FauxtonAPI.urls('document', 'attachment', db, docId, encodeURIComponent(file.name), query),
-    type: 'PUT',
-    data: file,
-    contentType: file.type,
-    headers: {
-      Accept: "application/json; charset=utf-8"
-    },
-    processData: false,
-    xhrFields: {
-      withCredentials: true
-    },
-    xhr: function () {
-      xhr.upload.onprogress = function (evt) {
-        var percentComplete = evt.loaded / evt.total * 100;
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SET_FILE_UPLOAD_PERCENTAGE,
-          options: {
-            percent: percentComplete
-          }
-        });
-      };
-      return xhr;
-    },
-    success: function () {
-
-      // re-initialize the document editor. Only announce it's been updated when
-      initDocEditor({
-        doc: params.doc,
-        onLoaded: function () {
-          FauxtonAPI.dispatch({ type: ActionTypes.FILE_UPLOAD_SUCCESS });
-          FauxtonAPI.addNotification({
-            msg: 'Document saved successfully.',
-            type: 'success',
-            clear: true
-          });
-        }.bind(this)
-      });
+  const query = '?rev=' + params.rev;
+  const db = params.doc.getDatabase().safeID();
+  const docId = params.doc.safeID();
+  const file = params.files[0];
+  const url = FauxtonAPI.urls('document', 'attachment', db, docId, encodeURIComponent(file.name), query);
 
-    },
-    error: function (resp) {
-      // cancelled uploads throw an ajax error but they don't contain a response. We don't want to publish an error
-      // event in those cases
-      if (_.isEmpty(resp.responseText)) {
-        return;
-      }
+  const onProgress = (evt) => {
+    if (evt.lengthComputable) {
+      const percentComplete = evt.loaded / evt.total * 100;
       FauxtonAPI.dispatch({
-        type: ActionTypes.FILE_UPLOAD_ERROR,
+        type: ActionTypes.SET_FILE_UPLOAD_PERCENTAGE,
         options: {
-          error: resp.responseJSON ? resp.responseJSON.reason : 'Error uploading file: (' + resp.statusText + ')'
+          percent: percentComplete
         }
       });
     }
-  });
+  };
+  const onSuccess = (doc) => {
+    // re-initialize the document editor. Only announce it's been updated when
+    initDocEditor({
+      doc: doc,
+      onLoaded: () => {
+        FauxtonAPI.dispatch({ type: ActionTypes.FILE_UPLOAD_SUCCESS });
+        FauxtonAPI.addNotification({
+          msg: 'Document saved successfully.',
+          type: 'success',
+          clear: true
+        });
+      }
+    });
+  };
+  const onError = (msg) => {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.FILE_UPLOAD_ERROR,
+      options: {
+        error: msg
+      }
+    });
+  };
+  const httpRequest = new XMLHttpRequest();
+  currentUploadHttpRequest = httpRequest;
+  httpRequest.withCredentials = true;
+  if (httpRequest.upload) {
+    httpRequest.upload.onprogress = onProgress;
+  }
+  httpRequest.onloadend = () => {
+    currentUploadHttpRequest = undefined;
+  };
+  httpRequest.onerror = () => {
+    onError('Error uploading file');
+  };
+  httpRequest.onload = (e) => {
+    if (httpRequest.status >= 200 && httpRequest.status < 300) {
+      onSuccess(params.doc);
+    } else {
+      let errorMsg = 'Error uploading file. ';
+      if (e.responseText) {
+        try {
+          const json = JSON.parse(e.responseText);
+          if (json.error) {
+            errorMsg += 'Reason: ' + (json.reason || json.error);
+          }
+        } catch (err) {
+          //ignore parsing error
+        }
+      }
+      onError(errorMsg);
+    }
+  };
+  httpRequest.open('PUT', url);
+  httpRequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+  httpRequest.setRequestHeader('Content-Type', file.type || `application/octet-stream`);
+  httpRequest.setRequestHeader('Accept', 'application/json');
+  httpRequest.send(file);
 }
 
 function cancelUpload () {
-  xhr.abort();
+  if (currentUploadHttpRequest) {
+    currentUploadHttpRequest.abort();
+  }
 }
 
 function resetUploadModal () {
diff --git a/app/addons/documents/doc-editor/components.js b/app/addons/documents/doc-editor/components.js
index 72441e278..3e3aba9f6 100644
--- a/app/addons/documents/doc-editor/components.js
+++ b/app/addons/documents/doc-editor/components.js
@@ -22,8 +22,6 @@ import GeneralComponents from "../../components/react-components";
 import { Modal } from "react-bootstrap";
 import Helpers from "../../../helpers";
 
-import DocumentResources from '../resources';
-
 var store = Stores.docEditorStore;
 
 class DocEditorController extends React.Component {
@@ -328,13 +326,15 @@ class UploadModal extends React.Component {
   state = this.getStoreState();
 
   render() {
-    var errorClasses = 'alert alert-error';
+    let errorClasses = 'alert alert-error';
     if (this.state.errorMessage === '') {
       errorClasses += ' hide';
     }
-    var loadIndicatorClasses = 'progress progress-info';
+    let loadIndicatorClasses = 'progress progress-info';
+    let disabledAttribute = {disabled: 'disabled'};
     if (!this.state.inProgress) {
       loadIndicatorClasses += ' hide';
+      disabledAttribute = {};
     }
 
     return (
@@ -350,7 +350,7 @@ class UploadModal extends React.Component {
                 Select a file to upload as an attachment to this document. Uploading a file saves the document as a new
                 revision.
               </p>
-              <input ref={el => this.attachments = el} type="file" name="_attachments" />
+              <input ref={el => this.attachments = el} type="file" name="_attachments" {...disabledAttribute}/>
               <br />
             </form>
 
@@ -361,7 +361,7 @@ class UploadModal extends React.Component {
         </Modal.Body>
         <Modal.Footer>
           <a href="#" data-bypass="true" className="cancel-link" onClick={this.closeModal}>Cancel</a>
-          <button href="#" id="upload-btn" data-bypass="true" className="btn btn-primary save" onClick={this.upload}>
+          <button href="#" id="upload-btn" data-bypass="true" className="btn btn-primary save" onClick={this.upload} {...disabledAttribute}>
             <i className="icon icon-upload" /> Upload Attachment
           </button>
         </Modal.Footer>
@@ -391,12 +391,12 @@ class CloneDocModal extends React.Component {
   };
 
   componentDidUpdate() {
-    //XXX model-code in component
     if (this.state.uuid === null) {
-      var uuid = new DocumentResources.UUID();
-      uuid.fetch().then(function () {
-        this.setState({ uuid: uuid.next() });
-      }.bind(this));
+      Helpers.getUUID().then((res) => {
+        if (res.uuids) {
+          this.setState({ uuid: res.uuids[0] });
+        }
+      });
     }
   }
 
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index 5ae57a27a..4fda5f73d 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -11,25 +11,11 @@
 // the License.
 
 import app from "../../app";
+import Helpers from '../../helpers';
 import FauxtonAPI from "../../core/api";
+import { post } from "../../core/ajax";
 import Documents from "./shared-resources";
 
-Documents.UUID = FauxtonAPI.Model.extend({
-  initialize: function (options) {
-    options = _.extend({count: 1}, options);
-    this.count = options.count;
-  },
-
-  url: function () {
-    return app.host + "/_uuids?count=" + this.count;
-  },
-
-  next: function () {
-    return this.get("uuids").pop();
-  }
-});
-
-
 Documents.QueryParams = (function () {
   var _eachParams = function (params, action) {
     // clone to avoid in-place modification
@@ -85,18 +71,19 @@ Documents.DdocInfo = FauxtonAPI.Model.extend({
 
 Documents.NewDoc = Documents.Doc.extend({
   fetch: function () {
-    var uuid = new Documents.UUID();
-    var deferred = this.deferred = $.Deferred();
-    var that = this;
-
-    uuid.fetch().done(function () {
-      that.set("_id", uuid.next());
-      deferred.resolve();
+    return Helpers.getUUID().then((res) => {
+      if (res.uuids) {
+        this.set("_id", res.uuids[0]);
+      } else {
+        this.set("_id", 'enter_document_id');
+      }
+      return res;
+    }).catch(() => {
+      // Don't throw error so the user is still able
+      // to edit the new doc
+      this.set("_id", 'enter_document_id');
     });
-
-    return deferred.promise();
   }
-
 });
 
 Documents.BulkDeleteDoc = FauxtonAPI.Model.extend({
@@ -120,31 +107,25 @@ Documents.BulkDeleteDocCollection = FauxtonAPI.Collection.extend({
   },
 
   bulkDelete: function () {
-    var payload = this.createPayload(this.toJSON()),
-        promise = FauxtonAPI.Deferred(),
-        that = this;
-
-    $.ajax({
-      type: 'POST',
-      url: this.url(),
-      contentType: 'application/json',
-      dataType: 'json',
-      data: JSON.stringify(payload),
-    }).then(function (res) {
-      that.handleResponse(res, promise);
-    }).fail(function () {
-      var ids = _.reduce(that.toArray(), function (acc, doc) {
-        acc.push(doc.id);
-        return acc;
-      }, []);
-      that.trigger('error', ids);
-      promise.reject(ids);
+    const payload = this.createPayload(this.toJSON());
+    return new FauxtonAPI.Promise((resolve, reject) => {
+      post(this.url(), payload).then(res => {
+        if (res.error) {
+          throw new Error(res.reason || res.error);
+        }
+        this.handleResponse(res, resolve, reject);
+      }).catch(() => {
+        const ids = _.reduce(this.toArray(), (acc, doc) => {
+          acc.push(doc.id);
+          return acc;
+        }, []);
+        this.trigger('error', ids);
+        reject(ids);
+      });
     });
-
-    return promise;
   },
 
-  handleResponse: function (res, promise) {
+  handleResponse: function (res, resolve, reject) {
     var ids = _.reduce(res, function (ids, doc) {
       if (doc.error) {
         ids.errorIds.push(doc.id);
@@ -155,7 +136,7 @@ Documents.BulkDeleteDocCollection = FauxtonAPI.Collection.extend({
       }
 
       return ids;
-    }, {errorIds: [], successIds: []});
+    }, { errorIds: [], successIds: [] });
 
     this.removeDocuments(ids.successIds);
 
@@ -166,9 +147,9 @@ Documents.BulkDeleteDocCollection = FauxtonAPI.Collection.extend({
     // This is kind of tricky. If there are no documents deleted then rejects
     // otherwise resolve with list of successful and failed documents
     if (!_.isEmpty(ids.successIds)) {
-      promise.resolve(ids);
+      resolve(ids);
     } else {
-      promise.reject(ids.errorIds);
+      reject(ids.errorIds);
     }
 
     this.trigger('updated');
diff --git a/app/addons/documents/shared-resources.js b/app/addons/documents/shared-resources.js
index 807dea880..c59bd2e49 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -12,6 +12,7 @@
 
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
+import { deleteRequest } from "../../core/ajax";
 import PagingCollection from "../../../assets/js/plugins/cloudant.pagingcollection";
 
 // defined here because this is contains the base resources used throughout the addon and outside,
@@ -149,11 +150,12 @@ Documents.Doc = FauxtonAPI.Model.extend({
   },
 
   destroy: function () {
-    var url = this.url() + "?rev=" + this.get('_rev');
-    return $.ajax({
-      url: url,
-      dataType: 'json',
-      type: 'DELETE'
+    const url = this.url() + "?rev=" + this.get('_rev');
+    return deleteRequest(url).then(res => {
+      if (res.error) {
+        throw new Error(res.reason || res.error);
+      }
+      return res;
     });
   },
 
diff --git a/app/addons/documents/sidebar/actions.js b/app/addons/documents/sidebar/actions.js
index 168305d11..ab93c2cb0 100644
--- a/app/addons/documents/sidebar/actions.js
+++ b/app/addons/documents/sidebar/actions.js
@@ -74,11 +74,12 @@ function toggleContent (designDoc, indexGroup) {
 //       Actions.selectNavItem('designDoc', { designDocName: 'my-design-doc', section: 'metadata' });
 //       Actions.selectNavItem('designDoc', { designDocName: 'my-design-doc', section: 'Views', indexName: 'my-view' });
 function selectNavItem (navItem, params) {
-  var settings = $.extend(true, {}, {
+  const settings = {
     designDocName: '',
     designDocSection: '',
-    indexName: ''
-  }, params);
+    indexName: '',
+    ...params
+  };
   settings.navItem = navItem;
 
   FauxtonAPI.dispatch({
diff --git a/app/addons/documents/tests/nightwatch/deletesDocuments.js b/app/addons/documents/tests/nightwatch/deletesDocuments.js
index 14354618e..ec34cba83 100644
--- a/app/addons/documents/tests/nightwatch/deletesDocuments.js
+++ b/app/addons/documents/tests/nightwatch/deletesDocuments.js
@@ -149,6 +149,7 @@ module.exports = {
       .url(baseUrl + '#/database/' + newDatabaseName + '/' + newDocumentName)
       .waitForElementPresent('#editor-container', waitTime, false)
       .clickWhenVisible('#doc-editor-actions-panel button[title="Delete"]')
+      .waitForElementVisible('.confirmation-modal', waitTime, false)
       .clickWhenVisible('.confirmation-modal button.btn.btn-primary')
       .waitForElementPresent('.jump-to-doc', waitTime, false)
 
diff --git a/app/helpers.js b/app/helpers.js
index 2e652287e..0b49194f0 100644
--- a/app/helpers.js
+++ b/app/helpers.js
@@ -17,7 +17,9 @@
 // want to change this later, but for now this should be thought of as a
 // "purely functional" helper system.
 
+import app from "./app";
 import constants from "./constants";
+import { get } from "./core/ajax";
 import utils from "./core/utils";
 import moment from "moment";
 import _ from 'lodash';
@@ -69,4 +71,9 @@ Helpers.isIE1X = function() {
   return document.documentMode == 11 || document.documentMode == 10;
 };
 
+Helpers.getUUID = function (count = 1) {
+  const url = `${app.host}/_uuids?count=${count}`;
+  return get(url);
+};
+
 export default Helpers;


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services