couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [couchdb-fauxton] branch master updated: Simplify Mango/Query panel layout (#950)
Date Mon, 14 Aug 2017 13:02:44 GMT
This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git


The following commit(s) were added to refs/heads/master by this push:
     new 5b56ac0  Simplify Mango/Query panel layout (#950)
5b56ac0 is described below

commit 5b56ac0b932a20f3ddf199b70b0d934b46ff0cf7
Author: Will Holley <willholley@gmail.com>
AuthorDate: Mon Aug 14 14:02:42 2017 +0100

    Simplify Mango/Query panel layout (#950)
    
    This adds some tweaks to the Mango/Query UI in an attempt to improve usability:
    
     * Remove redundant description panel
     * Remove list of available indexes. Now that queries will run with no indexes defined,
this is less important and is available in the index management page.
     * Increase query editor size and prevent redundant internal panel scrolling
     * Add explicit Mango Index React component
     * Add option to show the _explain output for the current query
     * Remove the feature which changed the default query based on the available indexes.
This seems redundant now that Mango can run with no indexes defined.
---
 app/addons/components/components/codeeditor.js     |   4 +-
 .../components/components/codeeditorpanel.js       |   1 +
 .../documents/__tests__/results-toolbar.test.js    |   7 -
 app/addons/documents/assets/less/view-editor.less  |   5 +-
 app/addons/documents/base.js                       |   8 +
 app/addons/documents/components/results-toolbar.js |  21 ++-
 app/addons/documents/header/header.js              |   5 +-
 app/addons/documents/index-results/actions.js      |  11 +-
 .../index-results/index-results.components.js      |   4 +-
 app/addons/documents/index-results/stores.js       |  11 +-
 .../mango/__tests__/mango.actions.test.js          |  60 -------
 app/addons/documents/mango/mango.actions.js        |  91 ++++------
 app/addons/documents/mango/mango.actiontypes.js    |   3 +-
 app/addons/documents/mango/mango.components.js     | 184 +++++++++++----------
 app/addons/documents/mango/mango.stores.js         |  69 ++------
 .../documents/mango/tests/mango.componentsSpec.js  |  94 -----------
 .../documents/mango/tests/mango.storesSpec.js      |  59 -------
 app/addons/documents/mangolayout.js                |  81 ++++++---
 app/addons/documents/pagination/pagination.js      |   2 +-
 app/addons/documents/resources.js                  |   6 +-
 app/addons/documents/routes-mango.js               |  15 +-
 .../documents/tests/nightwatch/mangoIndex.js       |   1 -
 .../tests/nightwatch/updatesUrlsSameRouteobject.js |   1 -
 assets/less/fauxton.less                           |   4 +
 24 files changed, 260 insertions(+), 487 deletions(-)

diff --git a/app/addons/components/components/codeeditor.js b/app/addons/components/components/codeeditor.js
index 893826b..cc605cf 100644
--- a/app/addons/components/components/codeeditor.js
+++ b/app/addons/components/components/codeeditor.js
@@ -41,6 +41,7 @@ export const CodeEditor = React.createClass({
       // these two options create auto-resizeable code editors, with a maximum number of
lines
       setHeightToLineCount: false,
       maxLines: 10,
+      minLines: 10,
 
       // optional editor key commands (e.g. specific save action)
       editorCommands: [],
@@ -165,7 +166,8 @@ export const CodeEditor = React.createClass({
     var numLines = this.editor.getSession().getDocument().getLength();
     var maxLines = (numLines > this.props.maxLines) ? this.props.maxLines : numLines;
     this.editor.setOptions({
-      maxLines: maxLines
+      maxLines: maxLines,
+      minLines: this.props.minLines
     });
   },
 
diff --git a/app/addons/components/components/codeeditorpanel.js b/app/addons/components/components/codeeditorpanel.js
index dc7910d..4ee89f5 100644
--- a/app/addons/components/components/codeeditorpanel.js
+++ b/app/addons/components/components/codeeditorpanel.js
@@ -136,6 +136,7 @@ export const CodeEditorPanel = React.createClass({
           showGutter={true}
           ignorableErrors={this.ignorableErrors}
           setHeightToLineCount={true}
+          maxLines={10000}
           blur={this.props.blur}
         />
         <Beautify code={this.state.code} beautifiedCode={this.beautify} />
diff --git a/app/addons/documents/__tests__/results-toolbar.test.js b/app/addons/documents/__tests__/results-toolbar.test.js
index 2fdd46f..7ce5331 100644
--- a/app/addons/documents/__tests__/results-toolbar.test.js
+++ b/app/addons/documents/__tests__/results-toolbar.test.js
@@ -36,11 +36,4 @@ describe('Results Toolbar', () => {
     expect(wrapper.find('.two-sides-toggle-button').length).toBe(1);
     expect(wrapper.find('.document-result-screen__toolbar-create-btn').length).toBe(1);
   });
-
-  it('only renders create button when there are no results', () => {
-    const wrapper = mount(<ResultsToolBar hasResults={false} {...restProps}/>);
-    expect(wrapper.find('.bulk-action-component').length).toBe(0);
-    expect(wrapper.find('.two-sides-toggle-button').length).toBe(0);
-    expect(wrapper.find('.document-result-screen__toolbar-create-btn').length).toBe(1);
-  });
 });
diff --git a/app/addons/documents/assets/less/view-editor.less b/app/addons/documents/assets/less/view-editor.less
index abebb70..d319b5e 100644
--- a/app/addons/documents/assets/less/view-editor.less
+++ b/app/addons/documents/assets/less/view-editor.less
@@ -35,7 +35,7 @@
     border-bottom: 1px solid #ccc;
   }
   .padded-box {
-    margin: 25px 30px;
+    margin: 15px;
   }
   .db-title {
     color: @brandHighlight;
@@ -53,10 +53,11 @@
     padding: 5px;
   }
   form {
-    padding-bottom: 50px;
+    padding-bottom: 15px;
   }
   a.edit-link {
     float: right;
+    margin-right: 5px;
   }
   .help-link {
     margin-left: 4px;
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index d44e7ae..98d2b48 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -222,6 +222,14 @@ FauxtonAPI.registerUrls('mango', {
     }
 
     return 'database/' + db + '/_find' + query;
+  },
+
+  'explain-server': function (db) {
+    return app.host + '/' + db + '/_explain';
+  },
+
+  'explain-apiurl': function (db) {
+    return window.location.origin + '/' + db + '/_explain';
   }
 });
 
diff --git a/app/addons/documents/components/results-toolbar.js b/app/addons/documents/components/results-toolbar.js
index e5c5a2a..f7c95c0 100644
--- a/app/addons/documents/components/results-toolbar.js
+++ b/app/addons/documents/components/results-toolbar.js
@@ -13,6 +13,7 @@ import React from 'react';
 import BulkDocumentHeaderController from "../header/header";
 import Stores from "../sidebar/stores";
 import Components from "../../components/react-components";
+import app from '../../../app';
 
 const {BulkActionComponent} = Components;
 const store = Stores.sidebarStore;
@@ -23,7 +24,7 @@ export class ResultsToolBar extends React.Component {
   }
 
   render () {
-    const dbName = store.getDatabase().id;
+    const database = store.getDatabase();
     const {
       hasResults,
       isListDeletable,
@@ -52,15 +53,23 @@ export class ResultsToolBar extends React.Component {
       bulkHeader = <BulkDocumentHeaderController {...this.props} />;
     }
 
-    return (
-      <div className="document-result-screen__toolbar">
-        {bulkAction}
-        {bulkHeader}
+    let createDocumentLink = null;
+    if (database) {
+      const safeDatabaseId = app.utils.safeURLName(database.id);
+      createDocumentLink = (
         <div className="document-result-screen__toolbar-flex-container">
-          <a href={`#/database/${dbName}/new`} className="btn save document-result-screen__toolbar-create-btn
btn-primary">
+          <a href={`#/database/${safeDatabaseId}/new`} className="btn save document-result-screen__toolbar-create-btn
btn-primary">
             Create Document
           </a>
         </div>
+      );
+    }
+
+    return (
+      <div className="document-result-screen__toolbar">
+        {bulkAction}
+        {bulkHeader}
+        {createDocumentLink}
       </div>
     );
   }
diff --git a/app/addons/documents/header/header.js b/app/addons/documents/header/header.js
index 0464709..0217c65 100644
--- a/app/addons/documents/header/header.js
+++ b/app/addons/documents/header/header.js
@@ -30,7 +30,8 @@ export default class BulkDocumentHeaderController extends React.Component
{
     return {
       selectedLayout: indexResultsStore.getSelectedLayout(),
       bulkDocCollection: indexResultsStore.getBulkDocCollection(),
-      isMango: indexResultsStore.getIsMangoResults()
+      isMango: indexResultsStore.getIsMangoResults(),
+      isMangoIndexList: indexResultsStore.getIsMangoIndexResults()
     };
   }
 
@@ -68,6 +69,8 @@ export default class BulkDocumentHeaderController extends React.Component
{
         >
           Metadata
         </Button>;
+    } else if (this.state.isMangoIndexList) {
+      return null;
     }
 
     // reduce doesn't allow for include_docs=true, so we'll prevent JSON and table
diff --git a/app/addons/documents/index-results/actions.js b/app/addons/documents/index-results/actions.js
index f51d88d..b893313 100644
--- a/app/addons/documents/index-results/actions.js
+++ b/app/addons/documents/index-results/actions.js
@@ -136,17 +136,10 @@ export default {
   },
 
   reloadResultsList: function () {
-    if (indexResultsStore.getTypeOfIndex() === 'mango') {
-      return this.newResultsList({
-        collection: indexResultsStore.getCollection(),
-        bulkCollection: indexResultsStore.getBulkDocCollection(),
-        typeOfIndex: 'mango'
-      });
-    }
-
     return this.newResultsList({
       collection: indexResultsStore.getCollection(),
-      bulkCollection: indexResultsStore.getBulkDocCollection()
+      bulkCollection: indexResultsStore.getBulkDocCollection(),
+      typeOfIndex: indexResultsStore.getTypeOfIndex()
     });
   },
 
diff --git a/app/addons/documents/index-results/index-results.components.js b/app/addons/documents/index-results/index-results.components.js
index 26dd135..d262879 100644
--- a/app/addons/documents/index-results/index-results.components.js
+++ b/app/addons/documents/index-results/index-results.components.js
@@ -358,7 +358,6 @@ var ResultsScreen = React.createClass({
           isListDeletable={this.props.isListDeletable}
           data={this.props.results}
           isLoading={this.props.isLoading}
-
           removeItem={this.props.removeItem}
           isChecked={this.props.allDocumentsSelected}
           hasSelectedItem={this.props.hasSelectedItem}
@@ -402,8 +401,7 @@ var ResultsScreen = React.createClass({
 
   componentDidUpdate: function () {
     prettyPrint();
-  },
-
+  }
 });
 
 
diff --git a/app/addons/documents/index-results/stores.js b/app/addons/documents/index-results/stores.js
index 821e70c..6d4932e 100644
--- a/app/addons/documents/index-results/stores.js
+++ b/app/addons/documents/index-results/stores.js
@@ -44,6 +44,7 @@ Stores.IndexResultsStore = FauxtonAPI.Store.extend({
 
     this._tableViewSelectedFields = [];
     this._isPrioritizedEnabled = false;
+    this._explain = false;
 
     this._tableSchema = [];
     this._selectedLayout = Constants.LAYOUT_ORIENTATION.METADATA;
@@ -200,6 +201,10 @@ Stores.IndexResultsStore = FauxtonAPI.Store.extend({
       this._selectedLayout = Constants.LAYOUT_ORIENTATION.METADATA;
     }
 
+    if (this.getIsMangoIndexResults()) {
+      this._selectedLayout = Constants.LAYOUT_ORIENTATION.JSON;
+    }
+
     this._cachedSelected = [];
 
     this._filteredCollection = this._collection.filter(filterOutGeneratedMangoDocs);
@@ -748,7 +753,11 @@ Stores.IndexResultsStore = FauxtonAPI.Store.extend({
   },
 
   getIsMangoResults: function () {
-    return this._typeOfIndex === 'mango';
+    return this._typeOfIndex === 'mango' || this._typeOfIndex === 'mango-index';
+  },
+
+  getIsMangoIndexResults: function () {
+    return this._typeOfIndex === 'mango-index';
   },
 
   getIsPrioritizedEnabled: function () {
diff --git a/app/addons/documents/mango/__tests__/mango.actions.test.js b/app/addons/documents/mango/__tests__/mango.actions.test.js
deleted file mode 100644
index 1d74f7c..0000000
--- a/app/addons/documents/mango/__tests__/mango.actions.test.js
+++ /dev/null
@@ -1,60 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// 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 utils from '../../../../../test/mocha/testUtils';
-import FauxtonAPI from "../../../../core/api";
-import Actions from '../mango.actions';
-import sinon from 'sinon';
-
-const {restore, assert} = utils;
-FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-describe('Mango actions', () => {
-
-  afterEach(() => {
-    restore(FauxtonAPI.navigate);
-    restore(FauxtonAPI.addNotification);
-  });
-
-  it("should show a notification and redirect if database doesn't exist", (done) => {
-    const navigateSpy = sinon.spy(FauxtonAPI, 'navigate');
-    const notificationSpy = sinon.spy(FauxtonAPI, 'addNotification');
-
-    const database = {
-      safeID : () => 'safe-id-db'
-    };
-
-    const options = {
-      database,
-      indexList: {
-        database,
-        fetch: () => {
-          return Promise.reject({
-            responseJSON: {
-              error: 'not_found'
-            }
-          });
-        },
-      }
-    };
-
-    Actions.getIndexList(options);
-    process.nextTick(() => {
-      assert.ok(notificationSpy.calledOnce);
-      assert.ok(/not exist/.test(notificationSpy.args[0][0].msg));
-      assert.ok(navigateSpy.calledOnce);
-      assert.deepEqual(navigateSpy.args[0][0], '/');
-      done();
-    });
-  });
-
-});
diff --git a/app/addons/documents/mango/mango.actions.js b/app/addons/documents/mango/mango.actions.js
index fec655f..f1540e4 100644
--- a/app/addons/documents/mango/mango.actions.js
+++ b/app/addons/documents/mango/mango.actions.js
@@ -13,7 +13,6 @@
 import FauxtonAPI from "../../../core/api";
 import Documents from "../resources";
 import ActionTypes from "./mango.actiontypes";
-import IndexResultsStores from "../index-results/stores";
 import IndexResultActions from "../index-results/actions";
 
 export default {
@@ -39,9 +38,9 @@ export default {
     });
   },
 
-  saveQuery: function (options) {
-    var queryCode = JSON.parse(options.queryCode),
-        mangoIndex = new Documents.MangoIndex(queryCode, {database: options.database});
+  saveIndex: function ({database, queryCode}) {
+    const query = JSON.parse(queryCode),
+        mangoIndex = new Documents.MangoIndex(query, {database: database});
 
     FauxtonAPI.addNotification({
       msg:  'Saving Index for Query...',
@@ -52,36 +51,18 @@ export default {
     mangoIndex
       .save()
       .then(function () {
-        var url = '#' + FauxtonAPI.urls('mango', 'query-app', options.database.safeID());
+        var url = '#' + FauxtonAPI.urls('mango', 'query-app', database.safeID());
 
-        FauxtonAPI.dispatch({
-          type: ActionTypes.MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS,
-          options: {
-            fields: queryCode.index.fields
-          }
-        });
+        // force mango index list to reload
+        IndexResultActions.reloadResultsList();
 
-        var mangoIndexCollection = new Documents.MangoIndexCollection(null, {
-          database: options.database,
-          params: null,
-          paging: {
-            pageSize: IndexResultsStores.indexResultsStore.getPerPage()
-          }
+        FauxtonAPI.addNotification({
+          msg: 'Index is ready for querying. <a href="' + url + '">Run a Query.</a>',
+          type: 'success',
+          clear: true,
+          escape: false
         });
-
-        this.getIndexList({indexList: mangoIndexCollection}).then(function () {
-
-          IndexResultActions.reloadResultsList();
-
-          FauxtonAPI.addNotification({
-            msg: 'Index is ready for querying. <a href="' + url + '">Run a Query.</a>',
-            type: 'success',
-            clear: true,
-            escape: false
-          });
-        }.bind(this));
-
-      }.bind(this))
+      })
       .fail(function (res) {
         FauxtonAPI.addNotification({
           msg: res.responseJSON.reason,
@@ -91,33 +72,29 @@ export default {
       });
   },
 
-  mangoResetIndexList: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.MANGO_RESET,
-      options: options
-    });
-  },
-
-  getIndexList: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.MANGO_NEW_AVAILABLE_INDEXES,
-      options: options
-    });
-
-    return options.indexList.fetch({reset: true}).then(() => {
-      this.mangoResetIndexList({isLoading: false});
-    }, (xhr) => {
-      let errorMsg = 'Bad request!';
-      if (xhr.responseJSON && xhr.responseJSON.error === 'not_found') {
-        const databaseName = options.indexList.database.safeID();
-        errorMsg = `The ${databaseName} database does not exist.`;
-        FauxtonAPI.navigate('/', {trigger: true});
-      }
+  runExplainQuery: function ({database, queryCode}) {
+    const url = FauxtonAPI.urls('mango', 'explain-server', database.safeID()),
+        query = JSON.parse(queryCode);
+
+    $.ajax({
+      type: 'POST',
+      url: url,
+      contentType: 'application/json; charset=utf-8',
+      dataType: 'json',
+      data: JSON.stringify(query)
+    }).then(function (explainPlan) {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.MANGO_EXPLAIN_RESULTS,
+        options: {
+          explainPlan: explainPlan
+        }
+      });
+    }).fail(function () {
       FauxtonAPI.addNotification({
-        msg: errorMsg,
-        type: "error",
-        clear:  true
-     });
+        msg: 'There was an error fetching the query plan.',
+        type: 'error',
+        clear: true
+      });
     });
   }
 };
diff --git a/app/addons/documents/mango/mango.actiontypes.js b/app/addons/documents/mango/mango.actiontypes.js
index 2e3014d..86db14a 100644
--- a/app/addons/documents/mango/mango.actiontypes.js
+++ b/app/addons/documents/mango/mango.actiontypes.js
@@ -12,9 +12,8 @@
 
 export default {
   MANGO_SET_DB: 'MANGO_SET_DB',
-  MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS: 'MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS',
   MANGO_NEW_QUERY_FIND_CODE: 'MANGO_NEW_QUERY_FIND_CODE',
   MANGO_NEW_QUERY_CREATE_INDEX_CODE: 'MANGO_NEW_QUERY_CREATE_INDEX_CODE',
   MANGO_NEW_AVAILABLE_INDEXES: 'MANGO_NEW_AVAILABLE_INDEXES',
-  MANGO_RESET: 'MANGO_RESET'
+  MANGO_EXPLAIN_RESULTS: 'MANGO_EXPLAIN_RESULTS'
 };
diff --git a/app/addons/documents/mango/mango.components.js b/app/addons/documents/mango/mango.components.js
index 2931783..285ef5a 100644
--- a/app/addons/documents/mango/mango.components.js
+++ b/app/addons/documents/mango/mango.components.js
@@ -12,12 +12,11 @@
 
 import app from "../../../app";
 import FauxtonAPI from "../../../core/api";
-import React from "react";
+import React, { Component } from 'react';
 import Stores from "./mango.stores";
 import Actions from "./mango.actions";
 import ReactComponents from "../../components/react-components";
 import IndexResultActions from "../index-results/actions";
-import MangoHelper from "./mango.helper";
 import "../../../../assets/js/plugins/prettify";
 
 var mangoStore = Stores.mangoStore;
@@ -35,11 +34,7 @@ var MangoQueryEditorController = React.createClass({
   getStoreState: function () {
     return {
       queryCode: mangoStore.getQueryFindCode(),
-      database: mangoStore.getDatabase(),
-      changedQuery: mangoStore.getQueryFindCodeChanged(),
-      availableIndexes: mangoStore.getAvailableQueryIndexes(),
-      additionalIndexes: mangoStore.getAvailableAdditionalIndexes(),
-      isLoading: mangoStore.getLoadingIndexes()
+      database: mangoStore.getDatabase()
     };
   },
 
@@ -80,25 +75,43 @@ var MangoQueryEditorController = React.createClass({
         dbName={this.state.database.id}
         onSubmit={this.runQuery}
         title={this.props.editorTitle}
-        additionalIndexesText={this.props.additionalIndexesText}
         docs={getDocUrl('MANGO_SEARCH')}
         exampleCode={this.state.queryCode}
-        changedQuery={this.state.changedQuery}
-        availableIndexes={this.state.availableIndexes}
-        additionalIndexes={this.state.additionalIndexes}
-        confirmbuttonText="Run Query" />
+        onExplainQuery={this.runExplain}
+        changedQuery={this.state.changedQuery} />
     );
   },
 
-  runQuery: function (event) {
-    event.preventDefault();
-
+  notifyOnQueryError: function() {
     if (this.getMangoEditor().hasErrors()) {
       FauxtonAPI.addNotification({
         msg:  'Please fix the Javascript errors and try again.',
         type: 'error',
         clear: true
       });
+
+      return true;
+    }
+    return false;
+  },
+
+  runExplain: function(event) {
+    event.preventDefault();
+
+    if (this.notifyOnQueryError()) {
+      return;
+    }
+
+    Actions.runExplainQuery({
+      database: this.state.database,
+      queryCode: this.getMangoEditor().getEditorValue()
+    });
+  },
+
+  runQuery: function (event) {
+    event.preventDefault();
+
+    if (this.notifyOnQueryError()) {
       return;
     }
 
@@ -110,31 +123,9 @@ var MangoQueryEditorController = React.createClass({
 });
 
 var MangoEditor = React.createClass({
-  getDefaultProps: function () {
-    return {
-      changedQuery: null,
-      availableIndexes: null,
-      additionalIndexes: null
-    };
-  },
-
   render: function () {
-    var url = '#/' + FauxtonAPI.urls('allDocs', 'app', FauxtonAPI.url.encode(this.props.dbName),
'');
-
     return (
       <div className="mango-editor-wrapper">
-        <PaddedBorderedBox>
-          <div
-            dangerouslySetInnerHTML={{__html: this.props.description}}
-            className="editor-description">
-          </div>
-        </PaddedBorderedBox>
-        <PaddedBorderedBox>
-          <strong>Database</strong>
-          <div className="db-title">
-            <a href={url}>{this.props.dbName}</a>
-          </div>
-        </PaddedBorderedBox>
         <form className="form-horizontal" onSubmit={this.props.onSubmit}>
           <PaddedBorderedBox>
             <CodeEditorPanel
@@ -143,12 +134,12 @@ var MangoEditor = React.createClass({
               title={this.props.title}
               docLink={this.props.docs}
               defaultCode={this.props.exampleCode} />
-            {this.getChangedQueryText()}
           </PaddedBorderedBox>
-          {this.getIndexBox()}
           <div className="padded-box">
-            <div className="control-group">
-              <ConfirmButton text={this.props.confirmbuttonText} id="create-index-btn"
showIcon={false} />
+            <div className="controls-group">
+              <button type="submit" id="create-index-btn" className="btn btn-primary btn-space">Run
Query</button>
+              <button type="button" id="explain-btn" className="btn btn-secondary btn-space"
onClick={this.props.onExplainQuery}>Explain</button>
+              <a className="edit-link" href={'#' + FauxtonAPI.urls('mango', 'index-app',
encodeURIComponent(this.props.dbName))}>manage indexes</a>
             </div>
           </div>
         </form>
@@ -156,51 +147,43 @@ var MangoEditor = React.createClass({
     );
   },
 
-  getChangedQueryText: function () {
-    if (!this.props.changedQuery) {
-      return null;
-    }
+  getEditorValue: function () {
+    return this.refs.field.getValue();
+  },
 
-    return (
-      <div className="info-changed-query">
-        <strong>Info:</strong>
-        <div>We changed the default query based on the last Index you created.</div>
-      </div>
-    );
+  getEditor: function () {
+    return this.refs.field.getEditor();
   },
 
-  getIndexBox: function () {
-    if (!this.props.availableIndexes) {
-      return null;
-    }
+  hasErrors: function () {
+    return this.getEditor().hasErrors();
+  }
+});
 
+var MangoIndexEditor = React.createClass({
+  render: function () {
     return (
-      <PaddedBorderedBox>
-        <strong>Queryable indexes:</strong>
-        <a className="edit-link" href={'#' + FauxtonAPI.urls('mango', 'index-app', encodeURIComponent(this.props.dbName))}>edit</a>
-        <pre
-          className="mango-available-indexes">
-          {this.getIndexes('index', this.props.availableIndexes)}
-          {this.getIndexes('additonal', this.props.additionalIndexes)}
-        </pre>
-      </PaddedBorderedBox>
+      <div className="mango-editor-wrapper">
+        <form className="form-horizontal" onSubmit={this.props.onSubmit}>
+          <PaddedBorderedBox>
+            <CodeEditorPanel
+              id="query-field"
+              ref="field"
+              title={this.props.title}
+              docLink={this.props.docs}
+              defaultCode={this.props.exampleCode} />
+          </PaddedBorderedBox>
+          <div className="padded-box">
+            <div className="control-group">
+              <ConfirmButton text="Create index" id="create-index-btn" showIcon={false}
/>
+              <a className="edit-link" href={'#' + FauxtonAPI.urls('mango', 'query-app',
encodeURIComponent(this.props.dbName))}>edit query</a>
+            </div>
+          </div>
+        </form>
+      </div>
     );
   },
 
-  getIndexes: function (prefix, indexes) {
-    if (!indexes) {
-      return;
-    }
-
-    return indexes.map(function (index, i) {
-      var name = MangoHelper.getIndexName(index);
-
-      return (
-        <div key={prefix + i}>{name}</div>
-      );
-    });
-  },
-
   getEditorValue: function () {
     return this.refs.field.getValue();
   },
@@ -239,24 +222,23 @@ var MangoIndexEditorController = React.createClass({
   },
 
   getMangoEditor: function () {
-    return this.refs.mangoEditor;
+    return this.refs.mangoIndexEditor;
   },
 
   render: function () {
     return (
-      <MangoEditor
-        ref="mangoEditor"
+      <MangoIndexEditor
+        ref="mangoIndexEditor"
         description={this.props.description}
         dbName={this.state.database.id}
-        onSubmit={this.saveQuery}
+        onSubmit={this.saveIndex}
         title="Index"
         docs={getDocUrl('MANGO_INDEX')}
-        exampleCode={this.state.queryIndexCode}
-        confirmbuttonText="Create Index" />
+        exampleCode={this.state.queryIndexCode} />
     );
   },
 
-  saveQuery: function (event) {
+  saveIndex: function (event) {
     event.preventDefault();
 
     if (this.getMangoEditor().hasErrors()) {
@@ -268,16 +250,38 @@ var MangoIndexEditorController = React.createClass({
       return;
     }
 
-    Actions.saveQuery({
+    Actions.saveIndex({
       database: this.state.database,
       queryCode: this.getMangoEditor().getEditorValue()
     });
   }
 });
 
-var Views = {
-  MangoIndexEditorController: MangoIndexEditorController,
-  MangoQueryEditorController: MangoQueryEditorController
+class ExplainPage extends Component {
+  componentDidMount () {
+    prettyPrint();
+  };
+
+  componentDidUpdate () {
+    prettyPrint();
+  };
+
+  render () {
+
+    return (
+      <div>
+        <pre className="prettyprint">{JSON.stringify(this.props.explainPlan, null,
' ')}</pre>
+      </div>
+    );
+  };
+}
+
+ExplainPage.propTypes = {
+  explainPlan: React.PropTypes.object.isRequired
 };
 
-export default Views;
+export default {
+  MangoIndexEditorController: MangoIndexEditorController,
+  MangoQueryEditorController: MangoQueryEditorController,
+  ExplainPage: ExplainPage
+};
diff --git a/app/addons/documents/mango/mango.stores.js b/app/addons/documents/mango/mango.stores.js
index 7836798..7f19db8 100644
--- a/app/addons/documents/mango/mango.stores.js
+++ b/app/addons/documents/mango/mango.stores.js
@@ -12,7 +12,7 @@
 
 import FauxtonAPI from "../../../core/api";
 import ActionTypes from "./mango.actiontypes";
-
+import IndexActionTypes from "../index-results/actiontypes";
 
 var defaultQueryIndexCode = {
   "index": {
@@ -35,8 +35,6 @@ Stores.MangoStore = FauxtonAPI.Store.extend({
     this._queryFindCode = defaultQueryFindCode;
     this._queryIndexCode = defaultQueryIndexCode;
     this._queryFindCodeChanged = false;
-    this._availableIndexes = [];
-    this._getLoadingIndexes = true;
   },
 
   getQueryIndexCode: function () {
@@ -55,37 +53,10 @@ Stores.MangoStore = FauxtonAPI.Store.extend({
     this._queryFindCode = options.code;
   },
 
-  getLoadingIndexes: function () {
-    return this._getLoadingIndexes;
-  },
-
-  setLoadingIndexes: function (options) {
-    this._getLoadingIndexes = options.isLoading;
-  },
-
   formatCode: function (code) {
     return JSON.stringify(code, null, '  ');
   },
 
-  newQueryFindCodeFromFields: function (options) {
-    var fields = options.fields,
-        queryCode = JSON.parse(JSON.stringify(this._queryFindCode)),
-        selectorContent;
-
-    if (!fields) {
-      return;
-    }
-
-    selectorContent = fields.reduce(function (acc, field) {
-      acc[field] = {"$gt": null};
-      return acc;
-    }, {});
-
-    queryCode.selector = selectorContent;
-    this._queryFindCode = queryCode;
-    this._queryFindCodeChanged = true;
-  },
-
   getQueryFindCodeChanged: function () {
     return this._queryFindCodeChanged;
   },
@@ -98,26 +69,12 @@ Stores.MangoStore = FauxtonAPI.Store.extend({
     return this._database;
   },
 
-  setAvailableIndexes: function (options) {
-    this._availableIndexes = options.indexList;
-  },
-
-  getAvailableQueryIndexes: function () {
-    return this._availableIndexes.filter(function (el) {
-      return ['json', 'special'].indexOf(el.get('type')) !== -1;
-    });
+  setExplainPlan: function (options) {
+    this._explainPlan = options && options.explainPlan;
   },
 
-  getAvailableAdditionalIndexes: function () {
-    var indexes = FauxtonAPI.getExtensions('mango:additionalIndexes')[0];
-
-    if (!indexes) {
-      return;
-    }
-
-    return this._availableIndexes.filter(function (el) {
-      return el.get('type').indexOf(indexes.type) !== -1;
-    });
+  getExplainPlan: function() {
+    return this._explainPlan;
   },
 
   dispatch: function (action) {
@@ -131,21 +88,17 @@ Stores.MangoStore = FauxtonAPI.Store.extend({
         this.setQueryIndexCode(action.options);
       break;
 
-      case ActionTypes.MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS:
-        this.newQueryFindCodeFromFields(action.options);
-      break;
-
       case ActionTypes.MANGO_NEW_QUERY_FIND_CODE:
         this.setQueryFindCode(action.options);
       break;
 
-      case ActionTypes.MANGO_NEW_AVAILABLE_INDEXES:
-        this.setAvailableIndexes(action.options);
-      break;
+      case ActionTypes.MANGO_EXPLAIN_RESULTS:
+        this.setExplainPlan(action.options);
+        break;
 
-      case ActionTypes.MANGO_RESET:
-        this.setLoadingIndexes(action.options);
-      break;
+      case IndexActionTypes.INDEX_RESULTS_CLEAR_RESULTS:
+        this.setExplainPlan(false);
+        break;
     }
 
     this.triggerChange();
diff --git a/app/addons/documents/mango/tests/mango.componentsSpec.js b/app/addons/documents/mango/tests/mango.componentsSpec.js
index f7274a0..4219f6f 100644
--- a/app/addons/documents/mango/tests/mango.componentsSpec.js
+++ b/app/addons/documents/mango/tests/mango.componentsSpec.js
@@ -48,26 +48,6 @@ describe('Mango IndexEditor', function () {
     var payload = JSON.parse(editor.getMangoEditor().getEditorValue());
     assert.equal(payload.index.fields[0], '_id');
   });
-
-  it('renders the current database', function () {
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoIndexEditorController description="foo" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-
-    assert.equal($el.find('.db-title').text(), 'testdb');
-  });
-
-  it('renders a description', function () {
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoIndexEditorController description="CouchDB Query is great!" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-
-    assert.equal($el.find('.editor-description').text(), 'CouchDB Query is great!');
-  });
 });
 
 describe('Mango QueryEditor', function () {
@@ -82,8 +62,6 @@ describe('Mango QueryEditor', function () {
       database: database
     });
 
-    MangoActions.mangoResetIndexList({isLoading: false});
-
     mangoCollection = new Resources.MangoIndexCollection([{
       ddoc: '_design/e4d338e5d6f047749f5399ab998b4fa04ba0c816',
       def: {
@@ -122,24 +100,6 @@ describe('Mango QueryEditor', function () {
     ReactDOM.unmountComponentAtNode(container);
   });
 
-  it('lists our available indexes', function () {
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoQueryEditorController description="foo" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-    assert.equal($el.find('.mango-available-indexes').length, 1);
-
-    assert.include(
-      $el.find('.mango-available-indexes').text(),
-      'json: _id, foo, ente'
-    );
-    assert.include(
-      $el.find('.mango-available-indexes').text(),
-      'json: _id'
-    );
-  });
-
   it('has a default query', function () {
     editor = ReactDOM.render(
       <Views.MangoQueryEditorController description="foo" />,
@@ -148,58 +108,4 @@ describe('Mango QueryEditor', function () {
     var json = JSON.parse(editor.getMangoEditor().getEditorValue());
     assert.equal(Object.keys(json.selector)[0], '_id');
   });
-
-  it('can render a query based on the last defined index', function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS,
-      options: {
-        fields: ['zetti', 'mussmaennchen']
-      }
-    });
-
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoQueryEditorController description="foo" />,
-      container
-    );
-
-    var json = JSON.parse(editor.getMangoEditor().getEditorValue());
-    assert.equal(Object.keys(json.selector)[0], 'zetti');
-    assert.equal(Object.keys(json.selector)[1], 'mussmaennchen');
-  });
-
-  it('informs the user that it uses a query based on the last defined index', function ()
{
-    FauxtonAPI.dispatch({
-      type: ActionTypes.MANGO_NEW_QUERY_FIND_CODE_FROM_FIELDS,
-      options: {
-        fields: ['zetti', 'mussmaennchen']
-      }
-    });
-
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoQueryEditorController description="foo" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-    assert.equal($el.find('.info-changed-query').length, 1);
-  });
-
-  it('renders the current database', function () {
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoQueryEditorController description="foo" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-
-    assert.equal($el.find('.db-title').text(), 'testdb');
-  });
-
-  it('renders a description', function () {
-    editor = TestUtils.renderIntoDocument(
-      <Views.MangoQueryEditorController description="CouchDB Query is great!" />,
-      container
-    );
-    var $el = $(ReactDOM.findDOMNode(editor));
-
-    assert.equal($el.find('.editor-description').text(), 'CouchDB Query is great!');
-  });
 });
diff --git a/app/addons/documents/mango/tests/mango.storesSpec.js b/app/addons/documents/mango/tests/mango.storesSpec.js
index 941794c..d1078f0 100644
--- a/app/addons/documents/mango/tests/mango.storesSpec.js
+++ b/app/addons/documents/mango/tests/mango.storesSpec.js
@@ -12,7 +12,6 @@
 
 import FauxtonAPI from "../../../../core/api";
 import Stores from "../mango.stores";
-import Resources from "../../resources";
 import testUtils from "../../../../../test/mocha/testUtils";
 var assert = testUtils.assert;
 var dispatchToken;
@@ -34,63 +33,5 @@ describe('Mango Store', function () {
     it('returns a default query', function () {
       assert.ok(store.getQueryFindCode());
     });
-
-    it('can set new selectors', function () {
-      store.newQueryFindCodeFromFields({fields: ['foo', 'bar']});
-      var res = store.getQueryFindCode();
-      assert.equal(res, JSON.stringify({
-        "selector": {
-          "foo": {"$gt": null},
-          "bar": {"$gt": null}
-        }
-      }, null, '  '));
-    });
-
-    it('indicates that we set another query for the user', function () {
-      assert.notOk(store.getQueryFindCodeChanged());
-      store.newQueryFindCodeFromFields({fields: ['mussman', 'zetti']});
-      assert.ok(store.getQueryFindCodeChanged());
-    });
-
-    it('alters the default query', function () {
-      assert.notOk(store.getQueryFindCodeChanged());
-      store.newQueryFindCodeFromFields({fields: ['mussman', 'zetti']});
-      assert.deepEqual(store.getQueryFindCode(), JSON.stringify({
-        "selector": {
-          "mussman": {"$gt": null},
-          "zetti": {"$gt": null}
-        }
-      }, null, '  '));
-    });
-
-    it('filters querytypes that are not needed', function () {
-
-      var collection = new Resources.MangoIndexCollection([
-        new Resources.MangoIndex({
-          ddoc: null,
-          name: 'emma',
-          type: 'special',
-          def: {fields: [{_id: 'asc'}]}
-        }, {}),
-        new Resources.MangoIndex({
-          ddoc: null,
-          name: 'biene',
-          type: 'json',
-          def: {fields: [{_id: 'desc'}]}
-        }, {}),
-        new Resources.MangoIndex({
-          ddoc: null,
-          name: 'alf',
-          type: 'nickname',
-          def: {fields: [{_id: 'asc'}]}
-        }, {})
-      ], {
-        database: {id: 'databaseId', safeID: function () { return this.id; }},
-        params: {limit: 20}
-      });
-      store._availableIndexes = collection;
-      assert.equal(store.getAvailableQueryIndexes().length, 2);
-    });
-
   });
 });
diff --git a/app/addons/documents/mangolayout.js b/app/addons/documents/mangolayout.js
index 105fd26..460e069 100644
--- a/app/addons/documents/mangolayout.js
+++ b/app/addons/documents/mangolayout.js
@@ -10,7 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import React from 'react';
+import React, { Component } from 'react';
 import app from "../../app";
 import ReactPagination from "./pagination/pagination";
 import {Breadcrumbs} from '../components/header-breadcrumbs';
@@ -18,7 +18,10 @@ import {NotificationCenterButton} from '../fauxton/notifications/notifications';
 import {ApiBarWrapper} from '../components/layouts';
 import MangoComponents from "./mango/mango.components";
 import IndexResultsComponents from "./index-results/index-results.components";
+import Stores from "./mango/mango.stores";
+import FauxtonAPI from "../../core/api";
 
+const mangoStore = Stores.mangoStore;
 
 export const RightHeader = ({docURL, endpoint}) => {
   return (
@@ -59,17 +62,23 @@ MangoHeader.defaultProps = {
   crumbs: []
 };
 
-const MangoContent = ({edit, designDocs}) => {
-  const leftContent = edit ?
-    <MangoComponents.MangoIndexEditorController
+export const MangoContent = ({edit, designDocs, explainPlan}) => {
+  const leftContent = edit ? <MangoComponents.MangoIndexEditorController
       description={app.i18n.en_US['mango-descripton-index-editor']}
-    /> :
-    <MangoComponents.MangoQueryEditorController
+    /> : <MangoComponents.MangoQueryEditorController
       description={app.i18n.en_US['mango-descripton']}
       editorTitle={app.i18n.en_US['mango-title-editor']}
       additionalIndexesText={app.i18n.en_US['mango-additional-indexes-heading']}
     />;
 
+  let resultsPage = <IndexResultsComponents.List designDocs={designDocs} />;
+  let mangoFooter = <MangoFooter />;
+
+  if (explainPlan) {
+    resultsPage = <MangoComponents.ExplainPage explainPlan={explainPlan} />;
+    mangoFooter = null;
+  }
+
   return (
     <div id="two-pane-content" className="flex-layout flex-row flex-body">
       <div id="left-content" className="flex-body">
@@ -77,24 +86,58 @@ const MangoContent = ({edit, designDocs}) => {
       </div>
       <div id="right-content" className="flex-body flex-layout flex-col">
         <div id="dashboard-lower-content" className="flex-body">
-          <IndexResultsComponents.List designDocs={designDocs} />
+          {resultsPage}
         </div>
-        <MangoFooter  />
+        {mangoFooter}
       </div>
     </div>
   );
 };
 
+export class MangoLayout extends Component {
+  constructor (props) {
+    super(props);
+    this.state = this.getStoreState();
+  };
 
-export const MangoLayout = ({edit, docURL, endpoint, crumbs, designDocs}) => {
-  return (
-    <div id="dashboard" className="two-pane flex-layout flex-col">
-      <MangoHeader
-        docURL={docURL}
-        endpoint={endpoint}
-        crumbs={crumbs}
-      />
-    <MangoContent edit={edit} designDocs={designDocs}/>
-    </div>
-  );
+  getStoreState () {
+    return {
+      explainPlan: mangoStore.getExplainPlan()
+    };
+  };
+
+  componentDidMount () {
+    mangoStore.on('change', this.onChange, this);
+  };
+
+  componentWillUnmount () {
+    mangoStore.off('change', this.onChange, this);
+  };
+
+  onChange () {
+    this.setState(this.getStoreState());
+  };
+
+  render () {
+    const {database, edit, docURL, crumbs, designDocs} = this.props;
+    let endpoint = this.props.endpoint;
+
+    if (this.state.explainPlan) {
+      endpoint = FauxtonAPI.urls('mango', 'explain-apiurl', database);
+    }
+
+    return (
+      <div id="dashboard" className="two-pane flex-layout flex-col">
+        <MangoHeader
+          docURL={docURL}
+          endpoint={endpoint}
+          crumbs={crumbs}
+        />
+      <MangoContent
+        edit={edit}
+        designDocs={designDocs}
+        explainPlan={this.state.explainPlan} />
+      </div>
+    );
+  }
 };
diff --git a/app/addons/documents/pagination/pagination.js b/app/addons/documents/pagination/pagination.js
index 47ce4b4..8b1298e 100644
--- a/app/addons/documents/pagination/pagination.js
+++ b/app/addons/documents/pagination/pagination.js
@@ -40,7 +40,7 @@ var IndexPaginationController = React.createClass({
     // Since we're migrating away from a paginated result list, don't forget
     // to delete the cached offset used for an improved UX when switching
     // between layouts.
-    Actions.deleteCachedOffset();
+    setTimeout(() => Actions.deleteCachedOffset());
   },
 
   onChange: function () {
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index ca7d43e..6323711 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -288,9 +288,9 @@ Documents.MangoDocumentCollection = PagingCollection.extend({
   },
 
   parse: function (resp) {
-    var rows = resp.docs;
+    var rows = [];
 
-    this.paging.hasNext = this.paging.hasPrevious = false;
+    rows = resp.docs;
 
     this._warning = resp.warning;
 
@@ -300,6 +300,8 @@ Documents.MangoDocumentCollection = PagingCollection.extend({
       update_seq: resp.update_seq
     };
 
+    this.paging.hasNext = this.paging.hasPrevious = false;
+
     if (this.paging.params.skip > 0) {
       this.paging.hasPrevious = true;
     }
diff --git a/app/addons/documents/routes-mango.js b/app/addons/documents/routes-mango.js
index e26711d..16995bf 100644
--- a/app/addons/documents/routes-mango.js
+++ b/app/addons/documents/routes-mango.js
@@ -62,14 +62,6 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
       }
     });
 
-    const mangoIndexList = new Resources.MangoIndexCollection(null, {
-      database: this.database,
-      params: null,
-      paging: {
-        pageSize: pageSize
-      }
-    });
-
     SidebarActions.selectNavItem('mango-query');
 
     IndexResultsActions.newMangoResultsList({
@@ -79,10 +71,6 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
       bulkCollection: new Resources.BulkDeleteDocCollection([], { databaseId: this.database.safeID()
}),
     });
 
-    MangoActions.getIndexList({
-      indexList: mangoIndexList
-    });
-
     const url = FauxtonAPI.urls(
       'allDocs', 'app', this.database.safeID(), '?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT
     );
@@ -93,6 +81,7 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
     ];
 
     return <MangoLayout
+      database={database}
       crumbs={crumbs}
       docURL={FauxtonAPI.constants.DOC_URLS.MANGO_SEARCH}
       endpoint={mangoResultCollection.urlRef('query-apiurl', '')}
@@ -125,7 +114,7 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
     IndexResultsActions.newResultsList({
       collection: mangoIndexCollection,
       bulkCollection: new Resources.MangoBulkDeleteDocCollection([], { databaseId: this.database.safeID()
}),
-      typeOfIndex: 'mango'
+      typeOfIndex: 'mango-index'
     });
 
     const url = FauxtonAPI.urls(
diff --git a/app/addons/documents/tests/nightwatch/mangoIndex.js b/app/addons/documents/tests/nightwatch/mangoIndex.js
index b7fa3b1..424466b 100644
--- a/app/addons/documents/tests/nightwatch/mangoIndex.js
+++ b/app/addons/documents/tests/nightwatch/mangoIndex.js
@@ -25,7 +25,6 @@ module.exports = {
       .populateDatabase(newDatabaseName)
       .loginToGUI()
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_index')
-      .clickWhenVisible('.fonticon-json')
       .waitForElementPresent('.prettyprint', waitTime, false)
       .waitForElementNotPresent('.loading-lines', waitTime, false)
       .execute('\
diff --git a/app/addons/fauxton/tests/nightwatch/updatesUrlsSameRouteobject.js b/app/addons/fauxton/tests/nightwatch/updatesUrlsSameRouteobject.js
index 96a347e..39c3ca0 100644
--- a/app/addons/fauxton/tests/nightwatch/updatesUrlsSameRouteobject.js
+++ b/app/addons/fauxton/tests/nightwatch/updatesUrlsSameRouteobject.js
@@ -24,7 +24,6 @@ module.exports = {
       .waitForElementVisible('.faux__jsonlink-link', waitTime, false)
       .assert.attributeContains('.faux__jsonlink-link', 'href', newDatabaseName + '/_find')
       .clickWhenVisible('.edit-link')
-      .clickWhenVisible('.fonticon-json')
       .waitForElementVisible('.prettyprint', waitTime, false)
       .waitForElementVisible('.faux__jsonlink-link', waitTime, false)
       .assert.attributeContains('.faux__jsonlink-link', 'href', newDatabaseName + '/_index')
diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less
index 31145f0..d2c3e9b 100644
--- a/assets/less/fauxton.less
+++ b/assets/less/fauxton.less
@@ -681,3 +681,7 @@ body .control-toggle-include-docs span {
     vertical-align: middle;
   }
 }
+
+.btn-space {
+  margin-right: 5px;
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@couchdb.apache.org" <commits@couchdb.apache.org>'].

Mime
View raw message