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: Refactor map/reduce views to use Redux (#986)
Date Tue, 03 Oct 2017 10:11:04 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 3edbe40  Refactor map/reduce views to use Redux (#986)
3edbe40 is described below

commit 3edbe4057807d2789655c3c0a3d51fd0bdaba0f2
Author: Antonio Maranhao <30349380+Antonio-Maranhao@users.noreply.github.com>
AuthorDate: Tue Oct 3 06:11:02 2017 -0400

    Refactor map/reduce views to use Redux (#986)
    
    * Use redux IndexResults component for views
    
    * Allow disabling bulk delete for IndexResults
    
    * Fix test case
    
    * Bug fix to avoid sending empty 'keys' query param
    
    * Enable reduce query option based on sidebar selection
    
    * Remove unused code
    
    * Bug fixes
    
    * Remove unused code
    
    * Highlight Query Options header if an option is active
    
    * Bug fix when deleting view
    
    * Bug fix when creating a new view in a new design doc
    
    * Fix condition for when Query Options header should be active
    
    * Make test condition more robust
    
    * Bug fix when saving view into another design doc
    
    * Fix condition to find if view contains a reduce function
    
    * Split index-editor components to separate files and small fixes
    
    * Fix nightwatch test
    
    * Address Garren's comment
    
    * Forgot to commit components.js file
    
    * Increase buffer size to avoid failure of Grunt nightwatch task
    
    * Show error message when save view operation fails
---
 Gruntfile.js                                       |   5 +-
 .../components/components/toggleheaderbutton.js    |   4 +-
 .../documents/__tests__/index-results.test.js      |  44 +-
 .../documents/__tests__/query-options.test.js      | 197 ++++-
 app/addons/documents/__tests__/resources.test.js   | 227 +-----
 .../documents/__tests__/results-toolbar.test.js    |   3 +-
 app/addons/documents/base.js                       |   4 +-
 .../documents/components/header-docs-right.js      |  29 +-
 app/addons/documents/header/header.actions.js      |  45 --
 app/addons/documents/header/header.js              |  56 +-
 app/addons/documents/helpers.js                    |  28 +-
 app/addons/documents/index-editor/actions.js       |   8 +-
 app/addons/documents/index-editor/components.js    | 365 +--------
 .../index-editor/components/DesignDocSelector.js   | 121 +++
 .../index-editor/components/IndexEditor.js         | 167 ++++
 .../index-editor/components/ReduceEditor.js        | 123 +++
 .../index-editor/tests/viewIndex.componentsSpec.js |  57 +-
 app/addons/documents/index-results/actions.js      | 233 ------
 .../index-results/actions/queryoptions.js          |  22 +-
 app/addons/documents/index-results/api.js          |  33 +
 .../components/queryoptions/MainFieldsView.js      |   6 +-
 .../components/queryoptions/QueryOptions.js        |  45 +-
 .../components/results/IndexResults.js             |  16 +-
 .../index-results/containers/ApiBarContainer.js    |  14 +-
 .../containers/IndexResultsContainer.js            |   2 +-
 .../containers/QueryOptionsContainer.js            |  17 +-
 .../documents/index-results/helpers/json-view.js   |   6 +-
 .../index-results/helpers/shared-helpers.js        |   2 +-
 .../documents/index-results/helpers/table-view.js  |   4 +-
 .../index-results/index-results.components.js      | 486 ------------
 app/addons/documents/index-results/reducers.js     |  26 +-
 app/addons/documents/index-results/stores.js       | 865 ---------------------
 .../tests/index-results.actionsSpec.js             | 112 ---
 .../tests/index-results.componentsSpec.js          | 330 --------
 .../tests/index-results.storesSpec.js              | 722 -----------------
 app/addons/documents/layouts.js                    | 104 +--
 app/addons/documents/mangolayout.js                |   2 +-
 app/addons/documents/pagination/actions.js         | 123 ---
 app/addons/documents/pagination/actiontypes.js     |  23 -
 app/addons/documents/pagination/pagination.js      | 275 -------
 .../pagination/tests/pagination.componentSpec.js   | 121 ---
 app/addons/documents/queryoptions/actions.js       | 120 ---
 app/addons/documents/queryoptions/actiontypes.js   |  29 -
 app/addons/documents/queryoptions/queryoptions.js  | 446 -----------
 app/addons/documents/queryoptions/stores.js        | 317 --------
 .../tests/queryoptions.componentsSpec.js           | 190 -----
 .../queryoptions/tests/queryoptions.storesSpec.js  | 139 ----
 app/addons/documents/resources.js                  | 395 ----------
 app/addons/documents/routes-documents.js           |  21 +-
 app/addons/documents/routes-index-editor.js        |  58 +-
 app/addons/documents/shared-routes.js              |  38 +-
 .../sidebar/SidebarControllerContainer.js          |  44 ++
 .../header.actiontypes.js => sidebar/reducers.js}  |  19 +-
 app/addons/documents/sidebar/sidebar.js            |  11 +-
 app/addons/documents/tests/document-test-helper.js |  13 +-
 .../tests/nightwatch/viewCreateBadView.js          |   2 +
 app/addons/permissions/layout.js                   |   3 +-
 57 files changed, 1035 insertions(+), 5882 deletions(-)

diff --git a/Gruntfile.js b/Gruntfile.js
index 572823b..58a6830 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -182,7 +182,10 @@ module.exports = function (grunt) {
     exec: {
       start_nightWatch: {
         command: __dirname + '/node_modules/nightwatch/bin/nightwatch' +
-        ' -c ' + __dirname + '/test/nightwatch_tests/nightwatch.json'
+        ' -c ' + __dirname + '/test/nightwatch_tests/nightwatch.json',
+        options: {
+          maxBuffer: 1000 * 1024
+        }
       }
     },
 
diff --git a/app/addons/components/components/toggleheaderbutton.js b/app/addons/components/components/toggleheaderbutton.js
index 782c369..baaf9c4 100644
--- a/app/addons/components/components/toggleheaderbutton.js
+++ b/app/addons/components/components/toggleheaderbutton.js
@@ -29,8 +29,8 @@ export const ToggleHeaderButton = React.createClass({
   },
 
   render () {
-    const { iconDefaultClass, fonticon, innerClasses, selected, containerClasses, title, disabled, text, toggleCallback } = this.props;
-    const selectedBtnClass = (selected) ? 'js-headerbar-togglebutton-selected' : '';
+    const { iconDefaultClass, fonticon, innerClasses, selected, containerClasses, title, disabled, text, toggleCallback, active } = this.props;
+    const selectedBtnClass = (selected || active) ? 'js-headerbar-togglebutton-selected' : '';
 
     return (
       <button
diff --git a/app/addons/documents/__tests__/index-results.test.js b/app/addons/documents/__tests__/index-results.test.js
index 93734ef..b2a5ab8 100644
--- a/app/addons/documents/__tests__/index-results.test.js
+++ b/app/addons/documents/__tests__/index-results.test.js
@@ -45,23 +45,51 @@ describe('IndexResults', () => {
     expect(spy.notCalled).toBe(true);
   });
 
-  it('calls fetchAllDocs on update if ddocsOnly switches', () => {
+  it('calls fetchDocs on update if ddocsOnly switches', () => {
     const spy = sinon.spy();
     const wrapper = shallow(<IndexResults
       fetchParams={{}}
       selectedDocs={[]}
       queryOptionsParams={{}}
-      fetchDocs={() => {}}
+      fetchDocs={() => { }}
+      resetState={() => { }}
       results={[]}
       ddocsOnly={false}
       fetchAtStartup={true}
+      fetchUrl={''}
     />);
 
     wrapper.instance().componentWillUpdate({
       ddocsOnly: true,
       fetchParams: {},
       queryOptionsParams: {},
-      fetchDocs: spy
+      fetchDocs: spy,
+      resetState: () => { },
+    });
+
+    expect(spy.calledOnce).toBe(true);
+  });
+
+  it('calls fetchDocs on update if fetchUrl switches', () => {
+    const spy = sinon.spy();
+    const wrapper = shallow(<IndexResults
+      fetchParams={{}}
+      selectedDocs={[]}
+      queryOptionsParams={{}}
+      fetchDocs={() => { }}
+      resetState={() => { }}
+      results={[]}
+      ddocsOnly={false}
+      fetchAtStartup={true}
+      fetchUrl={'view1'}
+    />);
+
+    wrapper.instance().componentWillUpdate({
+      fetchParams: {},
+      queryOptionsParams: {},
+      fetchDocs: spy,
+      resetState: () => { },
+      fetchUrl: 'view2'
     });
 
     expect(spy.calledOnce).toBe(true);
@@ -74,7 +102,7 @@ describe('IndexResults', () => {
       fetchParams={{}}
       selectedDocs={[]}
       queryOptionsParams={{}}
-      fetchAllDocs={() => {}}
+      fetchAllDocs={() => { }}
       results={[]}
       fetchAtStartup={true}
     />);
@@ -89,7 +117,7 @@ describe('IndexResults', () => {
     }];
     const wrapper = shallow(<IndexResults
       selectedDocs={selectedDocs}
-      fetchAllDocs={() => {}}
+      fetchAllDocs={() => { }}
       results={[]}
       fetchAtStartup={true}
     />);
@@ -103,7 +131,7 @@ describe('IndexResults', () => {
     }];
     const wrapper = shallow(<IndexResults
       selectedDocs={selectedDocs}
-      fetchAllDocs={() => {}}
+      fetchAllDocs={() => { }}
       results={[]}
       fetchAtStartup={true}
     />);
@@ -115,7 +143,7 @@ describe('IndexResults', () => {
     const spy = sinon.spy();
     const wrapper = shallow(<IndexResults
       selectedDocs={[]}
-      fetchAllDocs={() => {}}
+      fetchAllDocs={() => { }}
       results={[]}
       selectDoc={spy}
       fetchAtStartup={true}
@@ -129,7 +157,7 @@ describe('IndexResults', () => {
     const spy = sinon.spy();
     const wrapper = shallow(<IndexResults
       selectedDocs={[]}
-      fetchAllDocs={() => {}}
+      fetchAllDocs={() => { }}
       results={[]}
       docs={[]}
       allDocumentsSelected={false}
diff --git a/app/addons/documents/__tests__/query-options.test.js b/app/addons/documents/__tests__/query-options.test.js
index fc6c6ba..d7b203d 100644
--- a/app/addons/documents/__tests__/query-options.test.js
+++ b/app/addons/documents/__tests__/query-options.test.js
@@ -22,7 +22,8 @@ describe('QueryOptions', () => {
     includeDocs: false,
     queryOptionsToggleIncludeDocs: () => {},
     reduce: false,
-    contentVisible: true
+    contentVisible: true,
+    perPage: 10
   };
 
   it('calls resetPagination and queryOptionsExecute on submit', () => {
@@ -39,6 +40,8 @@ describe('QueryOptions', () => {
       queryOptionsParams={queryOptionsParams}
       selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
       changeLayout={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
       {...props}
     />);
 
@@ -47,7 +50,7 @@ describe('QueryOptions', () => {
     expect(spy2.calledOnce).toBe(true);
   });
 
-  it('calls queryOptionsFilterOnlyDdocs if ddocsOnly is true', () => {
+  it('calls queryOptionsApplyFilterOnlyDdocs if ddocsOnly is true', () => {
     const spy = sinon.spy();
     const queryOptionsParams = {
       include_docs: false
@@ -55,7 +58,8 @@ describe('QueryOptions', () => {
 
     shallow(<QueryOptions
       ddocsOnly={true}
-      queryOptionsFilterOnlyDdocs={spy}
+      queryOptionsApplyFilterOnlyDdocs={spy}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
       queryOptionsExecute={() => {}}
       resetPagination={() => {}}
       queryOptionsToggleVisibility={() => {}}
@@ -68,7 +72,7 @@ describe('QueryOptions', () => {
     expect(spy.calledOnce).toBe(true);
   });
 
-  it('calls resetState and queryOptionsFilterOnlyDdocs if ddocsOnly switches to true on new props', () => {
+  it('calls queryOptionsApplyFilterOnlyDdocs if ddocsOnly switches to true on new props', () => {
     const spy = sinon.spy();
     const queryOptionsParams = {
       include_docs: false
@@ -76,8 +80,8 @@ describe('QueryOptions', () => {
 
     const wrapper = shallow(<QueryOptions
       ddocsOnly={false}
-      resetState={spy}
-      queryOptionsFilterOnlyDdocs={spy}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={spy}
       queryOptionsExecute={() => {}}
       resetPagination={() => {}}
       queryOptionsToggleVisibility={() => {}}
@@ -90,10 +94,10 @@ describe('QueryOptions', () => {
     wrapper.instance().componentWillReceiveProps({
       ddocsOnly: true
     });
-    expect(spy.calledTwice).toBe(true);
+    expect(spy.calledOnce).toBe(true);
   });
 
-  it('calls resetState if ddocsOnly switches to false on new props', () => {
+  it('calls queryOptionsRemoveFilterOnlyDdocs if ddocsOnly switches to false on new props', () => {
     const spy = sinon.spy();
     const queryOptionsParams = {
       include_docs: false
@@ -101,8 +105,8 @@ describe('QueryOptions', () => {
 
     const wrapper = shallow(<QueryOptions
       ddocsOnly={true}
-      resetState={spy}
-      queryOptionsFilterOnlyDdocs={() => {}}
+      queryOptionsRemoveFilterOnlyDdocs={spy}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
       queryOptionsExecute={() => {}}
       resetPagination={() => {}}
       queryOptionsToggleVisibility={() => {}}
@@ -117,4 +121,177 @@ describe('QueryOptions', () => {
     });
     expect(spy.calledOnce).toBe(true);
   });
+
+  it('button is not highlighted when query options are not set', () => {
+
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...props}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(false);
+  });
+
+  it('button is highlighted when reduce option is enabled', () => {
+    const newProps = {
+      ...props,
+      reduce: true
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is highlighted when limit option is set', () => {
+    const newProps = {
+      ...props,
+      limit: 3
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is highlighted when skip option is set', () => {
+    const newProps = {
+      ...props,
+      skip: 3
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is highlighted when betweenKeys option is set', () => {
+    const newProps = {
+      ...props,
+      betweenKeys: {startkey:"a"}
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is highlighted when byKeys option is set', () => {
+    const newProps = {
+      ...props,
+      byKeys: {}
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is highlighted when descending option is enabled', () => {
+    const newProps = {
+      ...props,
+      descending: true
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(true);
+  });
+
+  it('button is not highlighted when includeDocs option is enabled', () => {
+    const newProps = {
+      ...props,
+      includeDocs: true
+    };
+    const wrapper = shallow(<QueryOptions
+      ddocsOnly={true}
+      queryOptionsRemoveFilterOnlyDdocs={() => {}}
+      queryOptionsApplyFilterOnlyDdocs={() => {}}
+      queryOptionsExecute={() => {}}
+      resetPagination={() => {}}
+      queryOptionsToggleVisibility={() => {}}
+      queryOptionsParams={{}}
+      selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+      changeLayout={() => {}}
+      {...newProps}
+    />);
+
+    const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
+    expect(isHighlighted).toBe(false);
+  });
 });
diff --git a/app/addons/documents/__tests__/resources.test.js b/app/addons/documents/__tests__/resources.test.js
index f5a4648..daf940f 100644
--- a/app/addons/documents/__tests__/resources.test.js
+++ b/app/addons/documents/__tests__/resources.test.js
@@ -9,35 +9,13 @@
 // 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 app from "../../../app";
+
 import FauxtonAPI from "../../../core/api";
 import Models from "../resources";
 import testUtils from "../../../../test/mocha/testUtils";
 import "../base";
 import sinon from 'sinon';
-const { assert, restore } = testUtils;
-
-describe('IndexCollection', () => {
-  let collection;
-  beforeEach(() => {
-    collection = new Models.IndexCollection([{
-      id:'myId1',
-      doc: 'num1'
-    },
-    {
-      id:'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      design: '_design/myDoc'
-    });
-  });
-
-  it('creates the right api-url with an absolute url', () => {
-    assert.ok(/http:\/\/dev:8000/.test(collection.urlRef('apiurl')));
-  });
-
-});
+const { assert } = testUtils;
 
 describe('Document', () => {
   let doc;
@@ -84,170 +62,6 @@ describe('Document', () => {
   });
 });
 
-describe('MangoIndex', () => {
-  let doc;
-
-  it('is deleteable', () => {
-    const index = {
-      ddoc: null,
-      name: '_all_docs',
-      type: 'json',
-      def: {fields: [{_id: 'asc'}]}
-    };
-    doc = new Models.MangoIndex(index, {});
-
-    assert.ok(doc.isDeletable());
-  });
-
-  it('special docs are not deleteable', () => {
-    const index = {
-      ddoc: null,
-      name: '_all_docs',
-      type: 'special',
-      def: {fields: [{_id: 'asc'}]}
-    };
-    doc = new Models.MangoIndex(index, {});
-
-    assert.notOk(doc.isDeletable());
-  });
-});
-
-describe('MangoDocumentCollection', () => {
-  let collection;
-
-  afterEach(() => {
-    restore($.ajax);
-  });
-
-  it('gets 1 doc more to know if there are more than 20', () => {
-    collection = new Models.MangoDocumentCollection([{
-      name: 'myId1',
-      doc: 'num1'
-    },
-    {
-      name: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20}
-    });
-    collection.setQuery({
-      selector: '$foo',
-      fields: 'bla'
-    });
-
-    assert.deepEqual({
-      selector: '$foo',
-      fields: 'bla',
-      limit: 21,
-      skip: undefined
-    }, collection.getPaginatedQuery());
-  });
-
-  it('on next page, skips first 20', () => {
-    collection = new Models.MangoDocumentCollection([{
-      name: 'myId1',
-      doc: 'num1'
-    },
-    {
-      name: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20}
-    });
-    collection.setQuery({
-      selector: '$foo',
-      fields: 'bla'
-    });
-    collection.next();
-    assert.deepEqual({
-      selector: '$foo',
-      fields: 'bla',
-      limit: 21,
-      skip: 20
-    }, collection.getPaginatedQuery());
-  });
-
-  it('does not do a fetch if the query is null', () => {
-    collection = new Models.MangoDocumentCollection([{
-      name: 'myId1',
-      doc: 'num1'
-    },
-    {
-      name: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20}
-    });
-
-    const spy = sinon.spy($, 'ajax');
-
-    collection.fetch();
-    assert.notOk(spy.wasCalled);
-  });
-
-});
-
-describe('MangoDocumentCollection', () => {
-  let collection;
-
-  it('is not editable', () => {
-    collection = new Models.MangoIndexCollection([{
-      name: 'myId1',
-      doc: 'num1'
-    },
-    {
-      name: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20}
-    });
-
-    assert.notOk(collection.isEditable());
-  });
-});
-
-describe('IndexCollection', () => {
-  let collection;
-
-  it('design docs are editable', () => {
-    collection = new Models.IndexCollection([{
-      _id: 'myId1',
-      doc: 'num1'
-    },
-    {
-      _id: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20},
-      design: '_design/foobar'
-    });
-
-    assert.ok(collection.isEditable());
-  });
-
-  it('reduced design docs are NOT editable', () => {
-    collection = new Models.IndexCollection([{
-      _id: 'myId1',
-      doc: 'num1'
-    },
-    {
-      _id: 'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      params: {limit: 20, reduce: true},
-      design: '_design/foobar'
-    });
-
-    assert.notOk(collection.isEditable());
-  });
-});
-
 describe('AllDocs', () => {
   let collection;
 
@@ -485,40 +299,3 @@ describe('Bulk Delete', () => {
   });
 
 });
-
-// this should stay at the bottom due to manipulating the 'view' urls.  otherwise, update this to restore them.
-describe('IndexCollection', () => {
-  let collection;
-
-  beforeEach(() => {
-    FauxtonAPI.registerUrls('view', {
-      testWithTrailingQuestion: function (database, designDoc, viewName) {
-        return app.host + '/' + database + '/_design/' + designDoc + '/_view/' + viewName + "?bogusParam=foo";
-      },
-
-      server: function (database, designDoc, viewName) {
-        return app.host + '/' + database + '/_design/' + designDoc + '/_view/' + viewName;
-      },
-    });
-    collection = new Models.IndexCollection([{
-      id:'myId1',
-      doc: 'num1'
-    },
-    {
-      id:'myId2',
-      doc: 'num2'
-    }], {
-      database: {id: 'databaseId', safeID: function () { return this.id; }},
-      design: '_design/myDoc'
-    });
-  });
-
-  it('creates the right url with correct params when trailing question mark', () => {
-    assert.ok(/\?bogusParam=foo&limit=20&reduce=false/.test(collection.urlRef('testWithTrailingQuestion')));
-  });
-
-  it('creates the right url with correct params without trailing question mark', () => {
-    assert.ok(/\?limit=20&reduce=false/.test(collection.urlRef()));
-  });
-
-});
diff --git a/app/addons/documents/__tests__/results-toolbar.test.js b/app/addons/documents/__tests__/results-toolbar.test.js
index 77bccd6..6c39b1c 100644
--- a/app/addons/documents/__tests__/results-toolbar.test.js
+++ b/app/addons/documents/__tests__/results-toolbar.test.js
@@ -24,7 +24,8 @@ describe('Results Toolbar', () => {
     allDocumentsSelected: false,
     hasSelectedItem: false,
     toggleSelectAll: () => {},
-    isLoading: false
+    isLoading: false,
+    queryOptionsParams: {}
   };
 
   beforeEach(() => {
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index 8e4f950..46433e1 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -15,11 +15,13 @@ import FauxtonAPI from "../../core/api";
 import Documents from "./routes";
 import reducers from "./index-results/reducers";
 import mangoReducers from "./mango/mango.reducers";
+import sidebarReducers from "./sidebar/reducers";
 import "./assets/less/documents.less";
 
 FauxtonAPI.addReducers({
   indexResults: reducers,
-  mangoQuery: mangoReducers
+  mangoQuery: mangoReducers,
+  sidebar: sidebarReducers
 });
 
 function getQueryParam (query) {
diff --git a/app/addons/documents/components/header-docs-right.js b/app/addons/documents/components/header-docs-right.js
index 63a5dfe..23f7247 100644
--- a/app/addons/documents/components/header-docs-right.js
+++ b/app/addons/documents/components/header-docs-right.js
@@ -11,44 +11,29 @@
 // the License.
 
 import React from 'react';
-import QueryOptions from '../queryoptions/queryoptions';
 import QueryOptionsContainer from '../index-results/containers/QueryOptionsContainer';
 import JumpToDoc from './jumptodoc';
 import Actions from './actions';
 
-const { QueryOptionsController } = QueryOptions;
-
-const getQueryOptionsComponent = (hideQueryOptions, isRedux, queryDocs, ddocsOnly) => {
-  if (hideQueryOptions) {
-    return null;
-  }
-
-  let queryOptionsComponent = <QueryOptionsController />;
-  if (isRedux) {
-    queryOptionsComponent = <QueryOptionsContainer
-      ddocsOnly={ddocsOnly}
-      queryDocs={ queryDocs } />;
-  }
-
-  return queryOptionsComponent;
-};
-
-const RightAllDocsHeader = ({database, hideQueryOptions, isRedux, queryDocs, ddocsOnly}) =>
+const RightAllDocsHeader = ({database, hideQueryOptions, hideJumpToDoc, queryDocs, ddocsOnly, selectedNavItem}) =>
   <div className="header-right right-db-header flex-layout flex-row">
 
     <div className="faux-header__searchboxwrapper">
       <div className="faux-header__searchboxcontainer">
-        <JumpToDoc cache={false} loadOptions={Actions.fetchAllDocsWithKey(database)} database={database} />
+        {hideJumpToDoc ? null :
+          <JumpToDoc cache={false} loadOptions={Actions.fetchAllDocsWithKey(database)} database={database} /> }
       </div>
     </div>
-    {getQueryOptionsComponent(hideQueryOptions, isRedux, queryDocs, ddocsOnly)}
+    {hideQueryOptions ? null :
+      <QueryOptionsContainer ddocsOnly={ddocsOnly} queryDocs={ queryDocs } selectedNavItem={selectedNavItem} /> }
   </div>;
 
 RightAllDocsHeader.propTypes = {
   database: React.PropTypes.object.isRequired,
   hideQueryOptions: React.PropTypes.bool,
   isRedux: React.PropTypes.bool,
-  queryDocs: React.PropTypes.func
+  queryDocs: React.PropTypes.func,
+  selectedNavItem: React.PropTypes.object
 };
 
 RightAllDocsHeader.defaultProps = {
diff --git a/app/addons/documents/header/header.actions.js b/app/addons/documents/header/header.actions.js
deleted file mode 100644
index 3baf943..0000000
--- a/app/addons/documents/header/header.actions.js
+++ /dev/null
@@ -1,45 +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 app from "../../../app";
-import FauxtonAPI from "../../../core/api";
-import ActionTypes from "./header.actiontypes";
-import ActionsQueryOptions from "../queryoptions/actions";
-
-export default {
-
-  toggleIncludeDocs: function (state, bulkDocsCollection) {
-    var params = app.getParams();
-
-    if (state) {
-      delete params.include_docs;
-      delete params.conflicts;
-    } else {
-      params.include_docs = true;
-      params.conflicts = true;
-    }
-
-    app.utils.localStorageSet('include_docs_bulkdocs', bulkDocsCollection.toJSON());
-
-    ActionsQueryOptions.runQuery(params);
-  },
-
-  toggleLayout: function (layout) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.TOGGLE_LAYOUT,
-      options: {
-        layout: layout
-      }
-    });
-  }
-
-};
diff --git a/app/addons/documents/header/header.js b/app/addons/documents/header/header.js
index 4479220..2a0382a 100644
--- a/app/addons/documents/header/header.js
+++ b/app/addons/documents/header/header.js
@@ -11,60 +11,25 @@
 // the License.
 
 import React from 'react';
-import Actions from './header.actions';
 import Constants from '../constants';
-import IndexResultStores from '../index-results/stores';
-import QueryOptionsStore from '../queryoptions/stores';
 import { Button, ButtonGroup } from 'react-bootstrap';
 
-const { indexResultsStore } = IndexResultStores;
-const { queryOptionsStore } = QueryOptionsStore;
-
 export default class BulkDocumentHeaderController extends React.Component {
   constructor (props) {
     super(props);
-    this.state = this.getStoreState();
-  }
-
-  getStoreState () {
-    return {
-      selectedLayout: indexResultsStore.getSelectedLayout(),
-      bulkDocCollection: indexResultsStore.getBulkDocCollection(),
-      //TODO: Replace below with a test for docType
-      isMango: indexResultsStore.getIsMangoResults()
-    };
-  }
-
-  componentDidMount () {
-    indexResultsStore.on('change', this.onChange, this);
-    queryOptionsStore.on('change', this.onChange, this);
-
-  }
-
-  componentWillUnmount () {
-    indexResultsStore.off('change', this.onChange);
-    queryOptionsStore.off('change', this.onChange);
-  }
-
-  onChange () {
-    this.setState(this.getStoreState());
   }
 
   render () {
     const {
-      changeLayout,
       selectedLayout,
-      docType
+      docType,
+      queryOptionsParams
     } = this.props;
 
-    // If the changeLayout function is not undefined, default to using prop values
-    // because we're using our new redux store.
-    // TODO: migrate completely to redux and eliminate this check.
-    const layout = changeLayout ? selectedLayout : this.state.selectedLayout;
     let metadata, json, table;
     if ((docType === Constants.INDEX_RESULTS_DOC_TYPE.VIEW)) {
       metadata = <Button
-          className={layout === Constants.LAYOUT_ORIENTATION.METADATA ? 'active' : ''}
+          className={selectedLayout === Constants.LAYOUT_ORIENTATION.METADATA ? 'active' : ''}
           onClick={this.toggleLayout.bind(this, Constants.LAYOUT_ORIENTATION.METADATA)}
         >
           Metadata
@@ -76,16 +41,16 @@ export default class BulkDocumentHeaderController extends React.Component {
     // reduce doesn't allow for include_docs=true, so we'll prevent JSON and table
     // views since they force include_docs=true when reduce is checked in the
     // query options panel.
-    if (!queryOptionsStore.reduce()) {
+    if (!queryOptionsParams.reduce) {
       table = <Button
-          className={layout === Constants.LAYOUT_ORIENTATION.TABLE ? 'active' : ''}
+          className={selectedLayout === Constants.LAYOUT_ORIENTATION.TABLE ? 'active' : ''}
           onClick={this.toggleLayout.bind(this, Constants.LAYOUT_ORIENTATION.TABLE)}
         >
           <i className="fonticon-table" /> Table
         </Button>;
 
       json = <Button
-          className={layout === Constants.LAYOUT_ORIENTATION.JSON ? 'active' : ''}
+          className={selectedLayout === Constants.LAYOUT_ORIENTATION.JSON ? 'active' : ''}
           onClick={this.toggleLayout.bind(this, Constants.LAYOUT_ORIENTATION.JSON)}
         >
           <i className="fonticon-json" /> JSON
@@ -104,7 +69,6 @@ export default class BulkDocumentHeaderController extends React.Component {
   }
 
   toggleLayout (newLayout) {
-    // this will be present when using redux stores
     const {
       changeLayout,
       selectedLayout,
@@ -114,7 +78,7 @@ export default class BulkDocumentHeaderController extends React.Component {
       queryOptionsToggleIncludeDocs
     } = this.props;
 
-    if (changeLayout && newLayout !== selectedLayout) {
+    if (newLayout !== selectedLayout) {
       // change our layout to JSON, Table, or Metadata
       changeLayout(newLayout);
 
@@ -130,11 +94,5 @@ export default class BulkDocumentHeaderController extends React.Component {
       fetchDocs(fetchParams, queryOptionsParams);
       return;
     }
-
-    // fall back to old backbone style logic
-    Actions.toggleLayout(newLayout);
-    if (!this.state.isMango) {
-      Actions.toggleIncludeDocs(newLayout === Constants.LAYOUT_ORIENTATION.METADATA, this.state.bulkDocCollection);
-    }
   }
 };
diff --git a/app/addons/documents/helpers.js b/app/addons/documents/helpers.js
index e9bec3b..0886927 100644
--- a/app/addons/documents/helpers.js
+++ b/app/addons/documents/helpers.js
@@ -94,11 +94,37 @@ const getNewDocUrl = (databaseName) => {
   return FauxtonAPI.urls('new', 'newDocument', safeDatabaseName);
 };
 
+const selectedViewContainsReduceFunction = (designDocs, selectedNavItem) => {
+  if (!selectedNavItem) {
+    return false;
+  }
+
+  let showReduce = false;
+  // If a map/reduce view is selected, check if view contains reduce field
+  if (designDocs && isViewSelected(selectedNavItem)) {
+      const ddocID = '_design/' + selectedNavItem.params.designDocName;
+      const ddoc = designDocs.find(ddoc => ddoc._id === ddocID);
+      showReduce = ddoc !== undefined && ddoc.views
+        && ddoc.views[selectedNavItem.params.indexName] !== undefined
+        && ddoc.views[selectedNavItem.params.indexName].reduce !== undefined;
+  }
+  return showReduce;
+};
+
+const isViewSelected = (selectedNavItem) => {
+  return (selectedNavItem.navItem === 'designDoc'
+    && selectedNavItem.params
+    && selectedNavItem.params.designDocSection === 'Views'
+    && selectedNavItem.params.indexName);
+};
+
 export default {
   getSeqNum,
   getNewButtonLinks,
   getModifyDatabaseLinks,
   getNewDocUrl,
   parseJSON,
-  truncateDoc
+  truncateDoc,
+  selectedViewContainsReduceFunction,
+  isViewSelected
 };
diff --git a/app/addons/documents/index-editor/actions.js b/app/addons/documents/index-editor/actions.js
index 2f02396..a4dbc33 100644
--- a/app/addons/documents/index-editor/actions.js
+++ b/app/addons/documents/index-editor/actions.js
@@ -88,9 +88,9 @@ function saveView (viewInfo) {
       clear: true
     });
 
-    // if the user just saved the view to a different design doc, remove the view from the old design doc and
-    // delete if it's empty
-    if (viewInfo.originalDesignDocName !== viewInfo.designDocId) {
+    // if the user just saved an existing view to a different design doc, remove the view
+    // from the old design doc and delete if it's empty
+    if (!viewInfo.newView && viewInfo.originalDesignDocName !== viewInfo.designDocId) {
       var oldDesignDoc = findDesignDoc(viewInfo.designDocs, viewInfo.originalDesignDocName);
       safeDeleteIndex(oldDesignDoc, viewInfo.designDocs, 'views', viewInfo.originalViewName, {
         onSuccess: function () {
@@ -108,7 +108,7 @@ function saveView (viewInfo) {
     FauxtonAPI.navigate(fragment, { trigger: true });
   }, (xhr) => {
     FauxtonAPI.addNotification({
-      msg: `${xhr.responseJSON.reason}`,
+      msg: 'Save failed. ' + (xhr.responseJSON ? `Reason: ${xhr.responseJSON.reason}` : ''),
       type: 'error',
       clear: true
     });
diff --git a/app/addons/documents/index-editor/components.js b/app/addons/documents/index-editor/components.js
index 1ac8a1c..a96fab6 100644
--- a/app/addons/documents/index-editor/components.js
+++ b/app/addons/documents/index-editor/components.js
@@ -10,365 +10,16 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import app from "../../../app";
-import FauxtonAPI from "../../../core/api";
-import React from "react";
-import ReactDOM from "react-dom";
-import Stores from "./stores";
-import Actions from "./actions";
 import ReactComponents from "../../components/react-components";
+import DesignDocSelector from './components/DesignDocSelector';
+import IndexEditor from './components/IndexEditor';
+import ReduceEditor from './components/ReduceEditor';
 
-var store = Stores.indexEditorStore;
-var getDocUrl = app.helpers.getDocUrl;
-var StyledSelect = ReactComponents.StyledSelect;
-var CodeEditorPanel = ReactComponents.CodeEditorPanel;
-var ConfirmButton = ReactComponents.ConfirmButton;
-var LoadLines = ReactComponents.LoadLines;
-
-
-var DesignDocSelector = React.createClass({
-  propTypes: {
-    designDocList: React.PropTypes.array.isRequired,
-    onSelectDesignDoc: React.PropTypes.func.isRequired,
-    onChangeNewDesignDocName: React.PropTypes.func.isRequired,
-    selectedDesignDocName: React.PropTypes.string.isRequired,
-    newDesignDocName: React.PropTypes.string.isRequired,
-    designDocLabel: React.PropTypes.string,
-    docURL: React.PropTypes.string
-  },
-
-  getDefaultProps: function () {
-    return {
-      designDocLabel: 'Design Document'
-    };
-  },
-
-  validate: function () {
-    if (this.props.selectedDesignDocName === 'new-doc' && this.props.newDesignDocName === '') {
-      FauxtonAPI.addNotification({
-        msg: 'Please name your design doc.',
-        type: 'error'
-      });
-      ReactDOM.findDOMNode(this.refs.newDesignDoc).focus();
-      return false;
-    }
-    return true;
-  },
-
-  getDocList: function () {
-    return _.map(this.props.designDocList, function (designDoc) {
-      return (<option key={designDoc} value={designDoc}>{designDoc}</option>);
-    });
-  },
-
-  selectDesignDoc: function (e) {
-    this.props.onSelectDesignDoc(e.target.value);
-  },
-
-  updateDesignDocName: function (e) {
-    this.props.onChangeNewDesignDocName(e.target.value);
-  },
-
-  getNewDDocField: function () {
-    if (this.props.selectedDesignDocName !== 'new-doc') {
-      return;
-    }
-    return (
-      <div id="new-ddoc-section" className="span5">
-        <label className="control-label" htmlFor="new-ddoc">_design/</label>
-        <div className="controls">
-          <input type="text" ref="newDesignDoc" id="new-ddoc" placeholder="newDesignDoc"
-             onChange={this.updateDesignDocName}/>
-        </div>
-      </div>
-    );
-  },
-
-  getDocLink: function () {
-    if (!this.props.docLink) {
-      return null;
-    }
-    return (
-      <a className="help-link" data-bypass="true" href={this.props.docLink} target="_blank">
-        <i className="icon-question-sign" />
-      </a>
-    );
-  },
-
-  render: function () {
-    const selectContent =
-      <optgroup label="Select a document">
-        <option value="new-doc">New document</option>
-        {this.getDocList()}
-      </optgroup>;
-
-    return (
-      <div className="design-doc-group control-group">
-        <div className="span3">
-          <label htmlFor="ddoc">{this.props.designDocLabel}
-            {this.getDocLink()}
-          </label>
-          <StyledSelect
-            selectChange={this.selectDesignDoc}
-            selectValue={this.props.selectedDesignDocName}
-            selectId={"faux__edit-view__design-doc"}
-            selectContent={selectContent}
-          />
-        </div>
-        {this.getNewDDocField()}
-      </div>
-    );
-  }
-});
-
-
-var ReduceEditor = React.createClass({
-
-  getStoreState: function () {
-    return {
-      reduce: store.getReduce(),
-      reduceOptions: store.reduceOptions(),
-      reduceSelectedOption: store.reduceSelectedOption(),
-      hasCustomReduce: store.hasCustomReduce(),
-      hasReduce: store.hasReduce()
-    };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  getOptionsList: function () {
-    return _.map(this.state.reduceOptions, function (reduce, i) {
-      return <option key={i} value={reduce}>{reduce}</option>;
-    }, this);
-  },
-
-  getReduceValue: function () {
-    if (!this.state.hasReduce) {
-      return null;
-    }
-
-    if (!this.state.hasCustomReduce) {
-      return this.state.reduce;
-    }
-
-    return this.refs.reduceEditor.getValue();
-  },
-
-  getEditor: function () {
-    return this.refs.reduceEditor.getEditor();
-  },
-
-  render: function () {
-    var reduceOptions = this.getOptionsList(),
-        customReduceSection;
-
-    if (this.state.hasCustomReduce) {
-      customReduceSection = <CodeEditorPanel
-        ref='reduceEditor'
-        id='reduce-function'
-        title={'Custom Reduce function'}
-        defaultCode={this.state.reduce}
-        allowZenMode={false}
-        blur={this.updateReduceCode}
-      />;
-    }
-
-    return (
-      <div>
-        <div className="control-group">
-          <label htmlFor="reduce-function-selector">
-            <span>Reduce (optional)</span>
-            <a
-              className="help-link"
-              data-bypass="true"
-              href={getDocUrl('REDUCE_FUNCS')}
-              target="_blank"
-            >
-              <i className="icon-question-sign"></i>
-            </a>
-          </label>
-          <StyledSelect
-            selectContent={reduceOptions}
-            selectChange={this.selectChange}
-            selectId="reduce-function-selector"
-            selectValue={this.state.reduceSelectedOption} />
-        </div>
-
-        {customReduceSection}
-      </div>
-    );
-  },
-
-  updateReduceCode: function (code) {
-    Actions.updateReduceCode(code);
-  },
-
-  selectChange: function (event) {
-    Actions.selectReduceChanged(event.target.value);
-  },
-
-  onChange: function () {
-    this.setState(this.getStoreState());
-  },
-
-  componentDidMount: function () {
-    store.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    store.off('change', this.onChange);
-  }
-});
-
-
-var EditorController = React.createClass({
-
-  getStoreState: function () {
-    return {
-      database: store.getDatabase(),
-      isNewView: store.isNewView(),
-      viewName: store.getViewName(),
-      designDocs: store.getDesignDocs(),
-      designDocList: store.getAvailableDesignDocs(),
-      originalViewName: store.getOriginalViewName(),
-      originalDesignDocName: store.getOriginalDesignDocName(),
-      newDesignDoc: store.isNewDesignDoc(),
-      designDocId: store.getDesignDocId(),
-      newDesignDocName: store.getNewDesignDocName(),
-      saveDesignDoc: store.getSaveDesignDoc(),
-      map: store.getMap(),
-      isLoading: store.isLoading()
-    };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  onChange: function () {
-    this.setState(this.getStoreState());
-  },
-
-  componentDidMount: function () {
-    store.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    store.off('change', this.onChange);
-  },
-
-  // the code editor is a standalone component, so if the user goes from one edit view page to another, we need to
-  // force an update of the editor panel
-  componentDidUpdate: function (prevProps, prevState) {
-    if (this.state.map !== prevState.map && this.refs.mapEditor) {
-      this.refs.mapEditor.update();
-    }
-  },
-
-  saveView: function (e) {
-    e.preventDefault();
-
-    if (!this.refs.designDocSelector.validate()) {
-      return;
-    }
-
-    Actions.saveView({
-      database: this.state.database,
-      newView: this.state.isNewView,
-      viewName: this.state.viewName,
-      designDoc: this.state.saveDesignDoc,
-      designDocId: this.state.designDocId,
-      newDesignDoc: this.state.newDesignDoc,
-      originalViewName: this.state.originalViewName,
-      originalDesignDocName: this.state.originalDesignDocName,
-      map: this.refs.mapEditor.getValue(),
-      reduce: this.refs.reduceEditor.getReduceValue(),
-      designDocs: this.state.designDocs
-    });
-  },
-
-  viewChange: function (e) {
-    Actions.changeViewName(e.target.value);
-  },
-
-  updateMapCode: function (code) {
-    Actions.updateMapCode(code);
-  },
-
-  render: function () {
-    if (this.state.isLoading) {
-      return (
-        <div className="define-view">
-          <LoadLines />
-        </div>
-      );
-    }
-
-    var pageHeader = (this.state.isNewView) ? 'New View' : 'Edit View';
-    var btnLabel = (this.state.isNewView) ? 'Create Document and then Build Index' : 'Save Document and then Build Index';
-
-    var cancelLink = '#' + FauxtonAPI.urls('view', 'showView', this.state.database.id, this.state.designDocId, this.state.viewName);
-    return (
-      <div className="define-view">
-        <form className="form-horizontal view-query-save" onSubmit={this.saveView}>
-          <h3 className="simple-header">{pageHeader}</h3>
-
-          <div className="new-ddoc-section">
-            <DesignDocSelector
-              ref="designDocSelector"
-              designDocList={this.state.designDocList}
-              selectedDesignDocName={this.state.designDocId}
-              newDesignDocName={this.state.newDesignDocName}
-              onSelectDesignDoc={Actions.selectDesignDoc}
-              onChangeNewDesignDocName={Actions.updateNewDesignDocName}
-              docLink={getDocUrl('DESIGN_DOCS')} />
-          </div>
-
-          <div className="control-group">
-            <label htmlFor="index-name">
-              <span>Index name</span>
-              <a
-                className="help-link"
-                data-bypass="true"
-                href={getDocUrl('VIEW_FUNCS')}
-                target="_blank">
-                <i className="icon-question-sign"></i>
-              </a>
-            </label>
-            <input
-              type="text"
-              id="index-name"
-              value={this.state.viewName}
-              onChange={this.viewChange}
-              placeholder="Index name" />
-          </div>
-          <CodeEditorPanel
-            id={'map-function'}
-            ref="mapEditor"
-            title={"Map function"}
-            docLink={getDocUrl('MAP_FUNCS')}
-            blur={this.updateMapCode}
-            allowZenMode={false}
-            defaultCode={this.state.map} />
-          <ReduceEditor ref="reduceEditor" />
-          <div className="padded-box">
-            <div className="control-group">
-              <ConfirmButton id="save-view" text={btnLabel} />
-              <a href={cancelLink} className="index-cancel-link">Cancel</a>
-            </div>
-          </div>
-        </form>
-      </div>
-    );
-  }
-});
-
+const StyledSelect = ReactComponents.StyledSelect;
 
 export default {
-  EditorController: EditorController,
-  ReduceEditor: ReduceEditor,
-  DesignDocSelector: DesignDocSelector,
-  StyledSelect: StyledSelect
+  EditorController: IndexEditor,
+  ReduceEditor,
+  DesignDocSelector,
+  StyledSelect
 };
diff --git a/app/addons/documents/index-editor/components/DesignDocSelector.js b/app/addons/documents/index-editor/components/DesignDocSelector.js
new file mode 100644
index 0000000..2afacb0
--- /dev/null
+++ b/app/addons/documents/index-editor/components/DesignDocSelector.js
@@ -0,0 +1,121 @@
+// 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 React, { Component } from "react";
+import ReactDOM from "react-dom";
+import FauxtonAPI from "../../../../core/api";
+import ReactComponents from "../../../components/react-components";
+
+const { StyledSelect } = ReactComponents;
+
+export default class DesignDocSelector extends Component {
+
+  constructor(props) {
+    super(props);
+  }
+
+  validate() {
+    if (this.props.selectedDesignDocName === 'new-doc' && this.props.newDesignDocName === '') {
+      FauxtonAPI.addNotification({
+        msg: 'Please name your design doc.',
+        type: 'error'
+      });
+      this.newDesignDocInput.focus();
+      return false;
+    }
+    return true;
+  }
+
+  getDocList() {
+    if (this.props.designDocList) {
+      return this.props.designDocList.map ((designDoc) => {
+        return (<option key={designDoc} value={designDoc}>{designDoc}</option>);
+      });
+    } else {
+      return [];
+    }
+  }
+
+  selectDesignDoc(e) {
+    this.props.onSelectDesignDoc(e.target.value);
+  }
+
+  updateDesignDocName(e) {
+    this.props.onChangeNewDesignDocName(e.target.value);
+  }
+
+  getNewDDocField() {
+    if (this.props.selectedDesignDocName !== 'new-doc') {
+      return;
+    }
+    return (
+      <div id="new-ddoc-section" className="span5">
+        <label className="control-label" htmlFor="new-ddoc">_design/</label>
+        <div className="controls">
+          <input type="text" id="new-ddoc" placeholder="newDesignDoc"
+            ref={(el) => { this.newDesignDocInput = el; }}
+            onChange={this.updateDesignDocName.bind(this)} />
+        </div>
+      </div>
+    );
+  }
+
+  getDocLink() {
+    if (!this.props.docLink) {
+      return null;
+    }
+    return (
+      <a className="help-link" data-bypass="true" href={this.props.docLink} target="_blank">
+        <i className="icon-question-sign" />
+      </a>
+    );
+  }
+
+  render() {
+    const selectContent =
+      <optgroup label="Select a document">
+        <option value="new-doc">New document</option>
+        {this.getDocList()}
+      </optgroup>;
+
+    return (
+      <div className="design-doc-group control-group">
+        <div className="span3">
+          <label htmlFor="ddoc">{this.props.designDocLabel}
+            {this.getDocLink()}
+          </label>
+          <StyledSelect
+            selectChange={this.selectDesignDoc.bind(this)}
+            selectValue={this.props.selectedDesignDocName}
+            selectId={"faux__edit-view__design-doc"}
+            selectContent={selectContent}
+          />
+        </div>
+        {this.getNewDDocField()}
+      </div>
+    );
+  }
+}
+
+DesignDocSelector.defaultProps = {
+  designDocLabel: 'Design Document'
+};
+
+DesignDocSelector.propTypes = {
+  designDocList: React.PropTypes.array.isRequired,
+  onSelectDesignDoc: React.PropTypes.func.isRequired,
+  onChangeNewDesignDocName: React.PropTypes.func.isRequired,
+  selectedDesignDocName: React.PropTypes.string.isRequired,
+  newDesignDocName: React.PropTypes.string.isRequired,
+  designDocLabel: React.PropTypes.string,
+  docURL: React.PropTypes.string
+};
diff --git a/app/addons/documents/index-editor/components/IndexEditor.js b/app/addons/documents/index-editor/components/IndexEditor.js
new file mode 100644
index 0000000..0e0eece
--- /dev/null
+++ b/app/addons/documents/index-editor/components/IndexEditor.js
@@ -0,0 +1,167 @@
+// 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 React, { Component } from "react";
+import ReactDOM from "react-dom";
+import app from "../../../../app";
+import FauxtonAPI from "../../../../core/api";
+import ReactComponents from "../../../components/react-components";
+import Stores from "../stores";
+import Actions from "../actions";
+import DesignDocSelector from './DesignDocSelector';
+import ReduceEditor from './ReduceEditor';
+
+const getDocUrl = app.helpers.getDocUrl;
+const store = Stores.indexEditorStore;
+const {CodeEditorPanel, ConfirmButton, LoadLines} = ReactComponents;
+
+export default class IndexEditor extends Component {
+
+  constructor(props) {
+    super(props);
+    this.state = this.getStoreState();
+  }
+
+  getStoreState() {
+    return {
+      database: store.getDatabase(),
+      isNewView: store.isNewView(),
+      viewName: store.getViewName(),
+      designDocs: store.getDesignDocs(),
+      designDocList: store.getAvailableDesignDocs(),
+      originalViewName: store.getOriginalViewName(),
+      originalDesignDocName: store.getOriginalDesignDocName(),
+      newDesignDoc: store.isNewDesignDoc(),
+      designDocId: store.getDesignDocId(),
+      newDesignDocName: store.getNewDesignDocName(),
+      saveDesignDoc: store.getSaveDesignDoc(),
+      map: store.getMap(),
+      isLoading: store.isLoading()
+    };
+  }
+
+  onChange() {
+    this.setState(this.getStoreState());
+  }
+
+  componentDidMount() {
+    store.on('change', this.onChange, this);
+  }
+
+  componentWillUnmount() {
+    store.off('change', this.onChange);
+  }
+
+  // the code editor is a standalone component, so if the user goes from one edit view page to another, we need to
+  // force an update of the editor panel
+  componentDidUpdate(prevProps, prevState) {
+    if (this.state.map !== prevState.map && this.mapEditor) {
+      this.mapEditor.update();
+    }
+  }
+
+  saveView(el) {
+    el.preventDefault();
+
+    if (!this.designDocSelector.validate()) {
+      return;
+    }
+
+    Actions.saveView({
+      database: this.state.database,
+      newView: this.state.isNewView,
+      viewName: this.state.viewName,
+      designDoc: this.state.saveDesignDoc,
+      designDocId: this.state.designDocId,
+      newDesignDoc: this.state.newDesignDoc,
+      originalViewName: this.state.originalViewName,
+      originalDesignDocName: this.state.originalDesignDocName,
+      map: this.mapEditor.getValue(),
+      reduce: this.reduceEditor.getReduceValue(),
+      designDocs: this.state.designDocs
+    });
+  }
+
+  viewChange(el) {
+    Actions.changeViewName(el.target.value);
+  }
+
+  updateMapCode(code) {
+    Actions.updateMapCode(code);
+  }
+
+  render() {
+    if (this.state.isLoading) {
+      return (
+        <div className="define-view">
+          <LoadLines />
+        </div>
+      );
+    }
+
+    const pageHeader = (this.state.isNewView) ? 'New View' : 'Edit View';
+    const btnLabel = (this.state.isNewView) ? 'Create Document and then Build Index' : 'Save Document and then Build Index';
+    const cancelLink = '#' + FauxtonAPI.urls('view', 'showView', this.state.database.id, this.state.designDocId, this.state.viewName);
+    return (
+      <div className="define-view" >
+        <form className="form-horizontal view-query-save" onSubmit={this.saveView.bind(this)}>
+          <h3 className="simple-header">{pageHeader}</h3>
+
+          <div className="new-ddoc-section">
+            <DesignDocSelector
+              ref={(el) => { this.designDocSelector = el; }}
+              designDocList={this.state.designDocList}
+              selectedDesignDocName={this.state.designDocId}
+              newDesignDocName={this.state.newDesignDocName}
+              onSelectDesignDoc={Actions.selectDesignDoc}
+              onChangeNewDesignDocName={Actions.updateNewDesignDocName}
+              docLink={getDocUrl('DESIGN_DOCS')} />
+          </div>
+
+          <div className="control-group">
+            <label htmlFor="index-name">
+              <span>Index name</span>
+              <a
+                className="help-link"
+                data-bypass="true"
+                href={getDocUrl('VIEW_FUNCS')}
+                target="_blank">
+                <i className="icon-question-sign"></i>
+              </a>
+            </label>
+            <input
+              type="text"
+              id="index-name"
+              value={this.state.viewName}
+              onChange={this.viewChange.bind(this)}
+              placeholder="Index name" />
+          </div>
+          <CodeEditorPanel
+            id={'map-function'}
+            ref={(el) => { this.mapEditor = el; }}
+            title={"Map function"}
+            docLink={getDocUrl('MAP_FUNCS')}
+            blur={this.updateMapCode.bind(this)}
+            allowZenMode={false}
+            defaultCode={this.state.map} />
+          <ReduceEditor ref={(el) => { this.reduceEditor = el; }} />
+          <div className="padded-box">
+            <div className="control-group">
+              <ConfirmButton id="save-view" text={btnLabel} />
+              <a href={cancelLink} className="index-cancel-link">Cancel</a>
+            </div>
+          </div>
+        </form>
+      </div>
+    );
+  }
+}
diff --git a/app/addons/documents/index-editor/components/ReduceEditor.js b/app/addons/documents/index-editor/components/ReduceEditor.js
new file mode 100644
index 0000000..3158f1c
--- /dev/null
+++ b/app/addons/documents/index-editor/components/ReduceEditor.js
@@ -0,0 +1,123 @@
+// 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 React, { Component } from "react";
+import ReactDOM from "react-dom";
+import app from "../../../../app";
+import ReactComponents from "../../../components/react-components";
+import Stores from "../stores";
+import Actions from "../actions";
+
+const getDocUrl = app.helpers.getDocUrl;
+const store = Stores.indexEditorStore;
+const {CodeEditorPanel, StyledSelect} = ReactComponents;
+
+export default class ReduceEditor extends Component {
+
+  constructor(props) {
+    super(props);
+    this.state = this.getStoreState();
+  }
+
+  onChange() {
+    this.setState(this.getStoreState());
+  }
+
+  componentDidMount() {
+    store.on('change', this.onChange, this);
+  }
+
+  componentWillUnmount() {
+    store.off('change', this.onChange);
+  }
+
+  getStoreState() {
+    return {
+      reduce: store.getReduce(),
+      reduceOptions: store.reduceOptions(),
+      reduceSelectedOption: store.reduceSelectedOption(),
+      hasCustomReduce: store.hasCustomReduce(),
+      hasReduce: store.hasReduce()
+    };
+  }
+
+  getOptionsList() {
+    return _.map(this.state.reduceOptions, function (reduce, i) {
+      return <option key={i} value={reduce}>{reduce}</option>;
+    }, this);
+  }
+
+  getReduceValue() {
+    if (!this.state.hasReduce) {
+      return null;
+    }
+
+    if (!this.state.hasCustomReduce) {
+      return this.state.reduce;
+    }
+
+    return this.refs.reduceEditor.getValue();
+  }
+
+  getEditor() {
+    return this.refs.reduceEditor.getEditor();
+  }
+
+  updateReduceCode(code) {
+    Actions.updateReduceCode(code);
+  }
+
+  selectChange(event) {
+    Actions.selectReduceChanged(event.target.value);
+  }
+
+  render() {
+    const reduceOptions = this.getOptionsList();
+    let customReduceSection;
+
+    if (this.state.hasCustomReduce) {
+      customReduceSection = <CodeEditorPanel
+        ref='reduceEditor'
+        id='reduce-function'
+        title={'Custom Reduce function'}
+        defaultCode={this.state.reduce}
+        allowZenMode={false}
+        blur={this.updateReduceCode.bind(this)}
+      />;
+    }
+
+    return (
+      <div>
+        <div className="control-group">
+          <label htmlFor="reduce-function-selector">
+            <span>Reduce (optional)</span>
+            <a
+              className="help-link"
+              data-bypass="true"
+              href={getDocUrl('REDUCE_FUNCS')}
+              target="_blank"
+            >
+              <i className="icon-question-sign"></i>
+            </a>
+          </label>
+          <StyledSelect
+            selectContent={reduceOptions}
+            selectChange={this.selectChange.bind(this)}
+            selectId="reduce-function-selector"
+            selectValue={this.state.reduceSelectedOption} />
+        </div>
+
+        {customReduceSection}
+      </div>
+    );
+  }
+}
diff --git a/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.js b/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.js
index 36fec6f..ecddb40 100644
--- a/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.js
+++ b/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.js
@@ -20,10 +20,10 @@ import TestUtils from "react-addons-test-utils";
 import sinon from "sinon";
 FauxtonAPI.router = new FauxtonAPI.Router([]);
 
-var assert = utils.assert;
+const { assert } = utils;
 
 
-var resetStore = function (designDocs) {
+const resetStore = function (designDocs) {
   Actions.editIndex({
     database: { id: 'rockos-db' },
     newView: false,
@@ -33,7 +33,7 @@ var resetStore = function (designDocs) {
   });
 };
 
-var getDesignDocsCollection = function (designDocs) {
+const getDesignDocsCollection = function (designDocs) {
   designDocs = designDocs.map(function (doc) {
     return Resources.Doc.prototype.parse(doc);
   });
@@ -48,7 +48,7 @@ var getDesignDocsCollection = function (designDocs) {
 
 
 describe('reduce editor', function () {
-  var container, reduceEl;
+  let container, reduceEl;
 
   beforeEach(function () {
     container = document.createElement('div');
@@ -59,7 +59,7 @@ describe('reduce editor', function () {
   });
 
   describe('getReduceValue', function () {
-    var container;
+    let container;
 
     beforeEach(function () {
       container = document.createElement('div');
@@ -67,7 +67,7 @@ describe('reduce editor', function () {
     });
 
     it('returns null for none', function () {
-      var designDoc = {
+      const designDoc = {
         _id: '_design/test-doc',
         views: {
           'test-view': {
@@ -83,7 +83,7 @@ describe('reduce editor', function () {
     });
 
     it('returns built in for built in reduce', function () {
-      var designDoc = {
+      const designDoc = {
         _id: '_design/test-doc',
         views: {
           'test-view': {
@@ -103,34 +103,7 @@ describe('reduce editor', function () {
 });
 
 describe('DesignDocSelector component', function () {
-  var container, selectorEl;
-  var designDoc = {
-    "id": "_design/test-doc",
-    "key": "_design/test-doc",
-    "value": {
-      "rev": "20-9e4bc8b76fd7d752d620bbe6e0ea9a80"
-    },
-    "doc": {
-      "_id": "_design/test-doc",
-      "_rev": "20-9e4bc8b76fd7d752d620bbe6e0ea9a80",
-      "views": {
-        "test-view": {
-          "map": "function(doc) {\n  emit(doc._id, 2);\n}"
-        },
-        "new-view": {
-          "map": "function(doc) {\n  if (doc.class === \"mammal\" && doc.diet === \"herbivore\")\n    emit(doc._id, 1);\n}",
-          "reduce": "_sum"
-        }
-      },
-      "language": "javascript",
-      "indexes": {
-        "newSearch": {
-          "analyzer": "standard",
-          "index": "function(doc){\n index(\"default\", doc._id);\n}"
-        }
-      }
-    }
-  };
+  let container, selectorEl;
 
   beforeEach(function () {
     container = document.createElement('div');
@@ -142,10 +115,10 @@ describe('DesignDocSelector component', function () {
 
 
   it('calls onSelectDesignDoc on change', function () {
-    var spy = sinon.spy();
+    const spy = sinon.spy();
     selectorEl = TestUtils.renderIntoDocument(
       <Views.DesignDocSelector
-        designDocList={getDesignDocsCollection([designDoc])}
+        designDocList={['_design/test-doc', '_design/test-doc2']}
         selectedDDocName={'new-doc'}
         onSelectDesignDoc={spy}
       />, container);
@@ -227,7 +200,7 @@ describe('DesignDocSelector component', function () {
   });
 
   it('includes help doc link when supplied', function () {
-    var docLink = 'http://docs.com';
+    const docLink = 'http://docs.com';
     selectorEl = TestUtils.renderIntoDocument(
       <Views.DesignDocSelector
         designDocList={['_design/test-doc']}
@@ -242,7 +215,7 @@ describe('DesignDocSelector component', function () {
 
 
 describe('Editor', function () {
-  var container, editorEl, sandbox;
+  let container, editorEl, sandbox;
 
   beforeEach(function () {
     container = document.createElement('div');
@@ -258,9 +231,9 @@ describe('Editor', function () {
   });
 
   it('calls changeViewName on view name change', function () {
-    var viewName = 'new-name';
-    var spy = sandbox.spy(Actions, 'changeViewName');
-    var el = $(ReactDOM.findDOMNode(editorEl)).find('#index-name')[0];
+    const viewName = 'new-name';
+    const spy = sandbox.spy(Actions, 'changeViewName');
+    const el = $(ReactDOM.findDOMNode(editorEl)).find('#index-name')[0];
     TestUtils.Simulate.change(el, {
       target: {
         value: viewName
diff --git a/app/addons/documents/index-results/actions.js b/app/addons/documents/index-results/actions.js
deleted file mode 100644
index 554d101..0000000
--- a/app/addons/documents/index-results/actions.js
+++ /dev/null
@@ -1,233 +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 FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-import Stores from "./stores";
-import SidebarActions from "../sidebar/actions";
-import MangoActionTypes from "../mango/mango.actiontypes";
-var indexResultsStore = Stores.indexResultsStore;
-
-var errorMessage = function (ids) {
-  var msg = 'Failed to delete your document!';
-
-  if (ids) {
-    msg = 'Failed to delete: ' + ids.join(', ');
-  }
-
-  FauxtonAPI.addNotification({
-    msg: msg,
-    type: 'error',
-    clear:  true
-  });
-};
-
-export default {
-
-  togglePrioritizedTableView: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_TOGGLE_PRIORITIZED_TABLE_VIEW
-    });
-  },
-
-  sendMessageNewResultList: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_NEW_RESULTS,
-      options: options
-    });
-  },
-
-  notifyOfWarnings: function (options) {
-    var msg = options.collection.warning && options.collection.warning();
-    if (msg) {
-      FauxtonAPI.addNotification({
-        msg: msg,
-        clear:  false,
-        type: 'info'
-      });
-    }
-  },
-
-  newResultsList: function (options) {
-    this.clearResults();
-
-    if (!options.collection.fetch) { return; }
-
-    return options.collection.fetch({reset: true}).then(() => {
-      this.sendMessageNewResultList(options);
-      this.resultsListReset();
-    }, (collection, _xhr) => {
-      //Make this more robust as sometimes the colection is passed through here.
-      var xhr = collection.responseText ? collection : _xhr;
-      var errorMsg = 'Bad Request';
-      console.log('xxx', xhr);
-
-      try {
-        const responseText = JSON.parse(xhr.responseText);
-        if (responseText.reason) {
-          errorMsg = responseText.reason;
-        }
-
-        if (responseText.reason && responseText.reason === 'missing_named_view') {
-          errorMsg = `The ${options.collection.view} ${options.collection.design} does not exist.`;
-          FauxtonAPI.navigate(
-            FauxtonAPI.urls('allDocsSanitized', 'app', options.collection.database.safeID()),
-            {trigger: true}
-          );
-          return;
-        }
-      } catch (e) {
-        console.log(e);
-      }
-
-      FauxtonAPI.addNotification({
-        msg: errorMsg,
-        type: "error",
-        clear:  true
-      });
-
-    });
-  },
-
-  newMangoResultsList: function (options) {
-    this.notifyOfWarnings(options);
-
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_NEW_RESULTS,
-      options: options
-    });
-  },
-
-  runMangoFindQuery: function (options) {
-    var query = JSON.parse(options.queryCode),
-        collection = indexResultsStore.getCollection(),
-        bulkCollection = indexResultsStore.getBulkDocCollection();
-
-    this.clearResults();
-
-    FauxtonAPI.dispatch({
-      type: MangoActionTypes.MANGO_NEW_QUERY_FIND_CODE,
-      options: {
-        code: options.queryCode
-      }
-    });
-
-    return collection
-      .setQuery(query)
-      .fetch()
-      .then(function () {
-        this.resultsListReset();
-        this.newMangoResultsList({
-          collection: collection,
-          query: options.queryCode,
-          textEmptyIndex: 'No Results Found!',
-          bulkCollection: bulkCollection
-        });
-      }.bind(this), function (res) {
-        FauxtonAPI.addNotification({
-          msg: res.reason,
-          clear:  true,
-          type: 'error'
-        });
-
-        this.resultsListReset();
-      }.bind(this));
-  },
-
-  reloadResultsList: function () {
-    return this.newResultsList({
-      collection: indexResultsStore.getCollection(),
-      bulkCollection: indexResultsStore.getBulkDocCollection(),
-      typeOfIndex: indexResultsStore.getTypeOfIndex()
-    });
-  },
-
-  resultsListReset: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_RESET
-    });
-  },
-
-  selectDoc: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_SELECT_DOC,
-      options: {
-        _id: options._id,
-        _rev: options._rev,
-        _deleted: true
-      }
-    });
-  },
-
-  changeField: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_SELECT_NEW_FIELD_IN_TABLE,
-      options: options
-    });
-  },
-
-  toggleAllDocuments: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS
-    });
-  },
-
-  clearResults: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.INDEX_RESULTS_CLEAR_RESULTS
-    });
-  },
-
-  deleteSelected: function (bulkDeleteCollection, itemsLength, designDocs) {
-    var msg = (itemsLength === 1) ? 'Are you sure you want to delete this doc?' :
-      'Are you sure you want to delete these ' + itemsLength + ' docs?';
-
-    if (itemsLength === 0) {
-      window.alert('Please select the document rows you want to delete.');
-      return false;
-    }
-
-    if (!window.confirm(msg)) {
-      return false;
-    }
-
-    var reloadResultsList = _.bind(this.reloadResultsList, this);
-    var selectedIds = [];
-    const hasDesignDocs = !!bulkDeleteCollection.map(d => d.id).find((id) => /_design/.test(id));
-
-
-    bulkDeleteCollection
-      .bulkDelete()
-      .then(function (ids) {
-        FauxtonAPI.addNotification({
-          msg: 'Successfully deleted your docs',
-          clear:  true
-        });
-
-        if (!_.isEmpty(ids.errorIds)) {
-          errorMessage(ids.errorIds);
-          selectedIds = ids.errorIds;
-        }
-      }, function (ids) {
-        errorMessage(ids);
-        selectedIds = ids;
-      })
-      .always(function () {
-        if (designDocs && hasDesignDocs) {
-          SidebarActions.updateDesignDocs(designDocs);
-        }
-        reloadResultsList().then(function () {
-          bulkDeleteCollection.reset(selectedIds);
-        });
-      });
-  }
-};
diff --git a/app/addons/documents/index-results/actions/queryoptions.js b/app/addons/documents/index-results/actions/queryoptions.js
index b419103..efba5fa 100644
--- a/app/addons/documents/index-results/actions/queryoptions.js
+++ b/app/addons/documents/index-results/actions/queryoptions.js
@@ -39,9 +39,17 @@ export const queryOptionsToggleVisibility = (newVisibility) => {
 };
 
 export const queryOptionsToggleReduce = (previousReduce) => {
-  return updateQueryOptions({
-    reduce: !previousReduce
-  });
+  if (previousReduce) {
+    return updateQueryOptions({
+      reduce: !previousReduce
+    });
+  } else {
+    // Disables includeDocs if reduce is changing to true
+    return updateQueryOptions({
+      reduce: !previousReduce,
+      includeDocs: false
+    });
+  }
 };
 
 export const queryOptionsUpdateGroupLevel = (newGroupLevel) => {
@@ -111,3 +119,11 @@ export const queryOptionsFilterOnlyDdocs = () => {
     showByKeys: false
   });
 };
+
+export const queryOptionsRemoveFilterOnlyDdocs = () => {
+  return updateQueryOptions({
+    betweenKeys: {},
+    showBetweenKeys: false,
+    showByKeys: false
+  });
+};
diff --git a/app/addons/documents/index-results/api.js b/app/addons/documents/index-results/api.js
index 4846c31..7f93811 100644
--- a/app/addons/documents/index-results/api.js
+++ b/app/addons/documents/index-results/api.js
@@ -17,6 +17,39 @@ import Constants from '../constants';
 import FauxtonAPI from '../../../core/api';
 
 export const queryAllDocs = (fetchUrl, params) => {
+  // Exclude params 'group', 'reduce' and 'group_level' if present since they not allowed for '_all_docs'
+  Object.assign(params, {reduce: undefined, group: undefined, group_level: undefined});
+  const query = queryString.stringify(params);
+  const url = `${fetchUrl}${fetchUrl.includes('?') ? '&' : '?'}${query}`;
+  return fetch(url, {
+    credentials: 'include',
+    headers: {
+      'Accept': 'application/json; charset=utf-8'
+    }
+  })
+  .then(res => res.json())
+  .then(json => {
+    if (json.error) {
+      throw new Error('(' + json.error + ') ' + json.reason);
+    }
+    return {
+      docs: json.rows,
+      docType: Constants.INDEX_RESULTS_DOC_TYPE.VIEW
+    };
+  });
+};
+
+export const queryMapReduceView = (fetchUrl, params) => {
+  // Adds the 'reduce' param in case it's not defined
+  if (params.reduce === undefined) {
+    params.reduce = false;
+  }
+  // reduce cannot be true when include_docs is true
+  if (params.include_docs && params.reduce) {
+    params.reduce = false;
+    params.group = undefined;
+    params.group_level = undefined;
+  }
   const query = queryString.stringify(params);
   const url = `${fetchUrl}${fetchUrl.includes('?') ? '&' : '?'}${query}`;
   return fetch(url, {
diff --git a/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js b/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
index 735dd46..a44e070 100644
--- a/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
+++ b/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
@@ -50,6 +50,10 @@ export default class MainFieldsView extends React.Component {
     );
   }
 
+  toggleReduce () {
+    this.props.toggleReduce(this.props.reduce);
+  }
+
   reduce () {
     if (!this.props.showReduce) {
       return null;
@@ -58,7 +62,7 @@ export default class MainFieldsView extends React.Component {
     return (
       <span>
         <div className="checkbox inline">
-          <input id="qoReduce" name="reduce" onChange={this.props.toggleReduce} type="checkbox" checked={this.props.reduce} />
+          <input id="qoReduce" name="reduce" onChange={this.toggleReduce.bind(this)} type="checkbox" checked={this.props.reduce} />
           <label htmlFor="qoReduce">Reduce</label>
         </div>
         {this.groupLevel()}
diff --git a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
index 0c8058c..42b1297 100644
--- a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
+++ b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
@@ -26,26 +26,36 @@ export default class QueryOptions extends React.Component {
     super(props);
     const {
       ddocsOnly,
-      queryOptionsFilterOnlyDdocs
+      queryOptionsApplyFilterOnlyDdocs
     } = props;
 
     if (ddocsOnly) {
-      queryOptionsFilterOnlyDdocs();
+      queryOptionsApplyFilterOnlyDdocs();
     }
   }
 
   componentWillReceiveProps (nextProps) {
     const {
       ddocsOnly,
-      queryOptionsFilterOnlyDdocs,
-      resetState
+      queryOptionsApplyFilterOnlyDdocs,
+      queryOptionsRemoveFilterOnlyDdocs,
     } = this.props;
 
     if (!ddocsOnly && nextProps.ddocsOnly) {
-      resetState();
-      queryOptionsFilterOnlyDdocs();
+      queryOptionsApplyFilterOnlyDdocs();
     } else if (ddocsOnly && !nextProps.ddocsOnly) {
-      resetState();
+      queryOptionsRemoveFilterOnlyDdocs();
+    }
+  }
+
+  componentWillUnmount() {
+    const {
+      ddocsOnly,
+      queryOptionsRemoveFilterOnlyDdocs
+    } = this.props;
+    if (ddocsOnly) {
+      // Remove filter it was set before
+      queryOptionsRemoveFilterOnlyDdocs();
     }
   }
 
@@ -124,7 +134,14 @@ export default class QueryOptions extends React.Component {
     );
   }
 
+  showAsActive() {
+    const { reduce, betweenKeys, byKeys, descending, skip, limit } = this.props;
+    return !!((betweenKeys && betweenKeys.startkey) ||
+      byKeys || (limit && limit != 'none') || skip || reduce || descending);
+  }
+
   render () {
+
     return (
       <div id="header-query-options">
         <div id="query-options">
@@ -134,7 +151,8 @@ export default class QueryOptions extends React.Component {
               containerClasses="header-control-box control-toggle-queryoptions"
               title="Query Options"
               fonticon="fonticon-gears"
-              text="Options" />
+              text="Options"
+              active={this.showAsActive()} />
               {this.getTray()}
           </div>
         </div>
@@ -144,5 +162,14 @@ export default class QueryOptions extends React.Component {
 };
 
 QueryOptions.propTypes = {
-  contentVisible: React.PropTypes.bool.isRequired
+  contentVisible: React.PropTypes.bool.isRequired,
+  queryOptionsApplyFilterOnlyDdocs: React.PropTypes.func.isRequired,
+  queryOptionsRemoveFilterOnlyDdocs: React.PropTypes.func.isRequired,
+  queryOptionsExecute: React.PropTypes.func.isRequired,
+  queryOptionsParams: React.PropTypes.object.isRequired,
+  perPage: React.PropTypes.number.isRequired,
+  resetPagination: React.PropTypes.func.isRequired,
+  selectedLayout: React.PropTypes.string.isRequired,
+  changeLayout: React.PropTypes.func.isRequired,
+  queryOptionsToggleVisibility: React.PropTypes.func.isRequired
 };
diff --git a/app/addons/documents/index-results/components/results/IndexResults.js b/app/addons/documents/index-results/components/results/IndexResults.js
index e5b5cf1..339da41 100644
--- a/app/addons/documents/index-results/components/results/IndexResults.js
+++ b/app/addons/documents/index-results/components/results/IndexResults.js
@@ -37,11 +37,18 @@ export default class IndexResults extends React.Component {
       fetchDocs,
       fetchParams,
       queryOptionsParams,
-      ddocsOnly
+      ddocsOnly,
+      fetchUrl,
+      resetState
     } = nextProps;
 
-    if (this.props.ddocsOnly !== ddocsOnly) {
-      fetchDocs(fetchParams, queryOptionsParams);
+    // Indicates the selected sidebar item has changed, so it needs to fetch the new list of docs
+    if (this.props.ddocsOnly !== ddocsOnly || this.props.fetchUrl !== fetchUrl) {
+      resetState();
+      // Need to reset skip and reduce here because 'resetState()'
+      // won't change props until the next update cycle
+      fetchDocs({...fetchParams, skip: 0},
+        {...queryOptionsParams, reduce: undefined, group: undefined, group_level: undefined});
     }
   }
 
@@ -64,6 +71,9 @@ export default class IndexResults extends React.Component {
   }
 
   docChecked (_id, _rev) {
+    if (!_id) {
+      return;
+    }
     const { selectDoc, selectedDocs } = this.props;
 
     // dispatch an action to push this doc on to the array of selected docs
diff --git a/app/addons/documents/index-results/containers/ApiBarContainer.js b/app/addons/documents/index-results/containers/ApiBarContainer.js
index 145b6e8..c126090 100644
--- a/app/addons/documents/index-results/containers/ApiBarContainer.js
+++ b/app/addons/documents/index-results/containers/ApiBarContainer.js
@@ -27,12 +27,19 @@ const urlRef = (databaseName, params) => {
   return FauxtonAPI.urls('allDocs', "apiurl", encodeURIComponent(databaseName), query);
 };
 
-const mapStateToProps = ({indexResults}, {docUrl, endpoint, databaseName}) => {
+const mapStateToProps = ({indexResults}, {docUrl, endpoint, databaseName, endpointAddQueryOptions}) => {
   if (!docUrl) {
     docUrl = FauxtonAPI.constants.DOC_URLS.GENERAL;
   }
   if (!endpoint) {
     endpoint = urlRef(databaseName, getQueryOptionsParams(indexResults));
+  } else {
+    if (endpointAddQueryOptions) {
+      const query = queryString.stringify(getQueryOptionsParams(indexResults));
+      if (query) {
+        endpoint = endpoint.indexOf('?') == -1 ? `${endpoint}?${query}` : `${endpoint}&${query}`;
+      }
+    }
   }
   return { docUrl, endpoint };
 };
@@ -44,5 +51,8 @@ const ApiBarContainer = connect (
 export default ApiBarContainer;
 
 ApiBarContainer.propTypes = {
-  databaseName: React.PropTypes.string
+  databaseName: React.PropTypes.string,
+  docUrl: React.PropTypes.string,
+  endpoint: React.PropTypes.string,
+  endpointAddQueryOptions: React.PropTypes.bool
 };
diff --git a/app/addons/documents/index-results/containers/IndexResultsContainer.js b/app/addons/documents/index-results/containers/IndexResultsContainer.js
index fbb35d7..5746fac 100644
--- a/app/addons/documents/index-results/containers/IndexResultsContainer.js
+++ b/app/addons/documents/index-results/containers/IndexResultsContainer.js
@@ -46,7 +46,7 @@ const mapStateToProps = ({indexResults}, ownProps) => {
     selectedDocs: getSelectedDocs(indexResults),
     isLoading: getIsLoading(indexResults),
     hasResults: getHasResults(indexResults),
-    results: getDataForRendering(indexResults, ownProps.databaseName),
+    results: getDataForRendering(indexResults, ownProps.databaseName, ownProps.deleteEnabled),
     isEditable: getIsEditable(indexResults),
     selectedLayout: getSelectedLayout(indexResults),
     allDocumentsSelected: getAllDocsSelected(indexResults),
diff --git a/app/addons/documents/index-results/containers/QueryOptionsContainer.js b/app/addons/documents/index-results/containers/QueryOptionsContainer.js
index 9679e1e..957a43e 100644
--- a/app/addons/documents/index-results/containers/QueryOptionsContainer.js
+++ b/app/addons/documents/index-results/containers/QueryOptionsContainer.js
@@ -12,6 +12,7 @@
 
 import React from 'react';
 import { connect } from 'react-redux';
+import DocHelpers from '../../helpers';
 import QueryOptions from '../components/queryoptions/QueryOptions';
 import { changeLayout, resetState } from '../actions/base';
 import { resetPagination } from '../actions/pagination';
@@ -28,7 +29,8 @@ import {
   queryOptionsUpdateLimit,
   queryOptionsToggleIncludeDocs,
   queryOptionsToggleVisibility,
-  queryOptionsFilterOnlyDdocs
+  queryOptionsFilterOnlyDdocs,
+  queryOptionsRemoveFilterOnlyDdocs
 } from '../actions/queryoptions';
 import {
   getQueryOptionsPanel,
@@ -38,12 +40,16 @@ import {
   getSelectedLayout
 } from '../reducers';
 
-const mapStateToProps = ({indexResults}, ownProps) => {
+const showReduce = (designDocs, selectedNavItem) => {
+  return DocHelpers.selectedViewContainsReduceFunction(designDocs, selectedNavItem);
+};
+
+const mapStateToProps = ({indexResults, sidebar}, ownProps) => {
   const queryOptionsPanel = getQueryOptionsPanel(indexResults);
   return {
     contentVisible: queryOptionsPanel.isVisible,
     includeDocs: queryOptionsPanel.includeDocs,
-    showReduce: queryOptionsPanel.showReduce,
+    showReduce: showReduce(sidebar.designDocs, ownProps.selectedNavItem),
     reduce: queryOptionsPanel.reduce,
     groupLevel: queryOptionsPanel.groupLevel,
     showByKeys: queryOptionsPanel.showByKeys,
@@ -102,9 +108,12 @@ const mapDispatchToProps = (dispatch, ownProps) => {
     queryOptionsExecute: (queryOptionsParams, perPage) => {
       dispatch(queryOptionsExecute(ownProps.queryDocs, queryOptionsParams, perPage));
     },
-    queryOptionsFilterOnlyDdocs: () => {
+    queryOptionsApplyFilterOnlyDdocs: () => {
       dispatch(queryOptionsFilterOnlyDdocs());
     },
+    queryOptionsRemoveFilterOnlyDdocs: () => {
+      dispatch(queryOptionsRemoveFilterOnlyDdocs());
+    },
     changeLayout: (newLayout) => {
       dispatch(changeLayout(newLayout));
     },
diff --git a/app/addons/documents/index-results/helpers/json-view.js b/app/addons/documents/index-results/helpers/json-view.js
index 9358162..3d1f858 100644
--- a/app/addons/documents/index-results/helpers/json-view.js
+++ b/app/addons/documents/index-results/helpers/json-view.js
@@ -13,7 +13,7 @@
 import { hasBulkDeletableDoc, getDocUrl, getDocId, getDocRev } from "./shared-helpers";
 import MangoHelper from "../../mango/mango.helper";
 
-export const getJsonViewData = (docs, { databaseName, docType }) => {
+export const getJsonViewData = (docs, { databaseName, docType, deleteEnabled = true }) => {
 
   // expand on this when refactoring views to use redux
   const stagedResults = docs.map((doc) => {
@@ -24,7 +24,7 @@ export const getJsonViewData = (docs, { databaseName, docType }) => {
         id: doc.type === 'special' ? '_all_docs' : doc.ddoc,
         keylabel: '',
         url: doc.id ? getDocUrl('app', doc.id, databaseName) : null,
-        isDeletable: doc.type !== 'special',
+        isDeletable: deleteEnabled ? doc.type !== 'special' : false,
         isEditable: false
       };
     }
@@ -36,7 +36,7 @@ export const getJsonViewData = (docs, { databaseName, docType }) => {
       _rev: getDocRev(doc, docType),
       keylabel: 'id',
       url: docID ? getDocUrl('app', docID, databaseName) : null,
-      isDeletable: true,
+      isDeletable: deleteEnabled,
       isEditable: true
     };
   });
diff --git a/app/addons/documents/index-results/helpers/shared-helpers.js b/app/addons/documents/index-results/helpers/shared-helpers.js
index d1e8e63..175e04b 100644
--- a/app/addons/documents/index-results/helpers/shared-helpers.js
+++ b/app/addons/documents/index-results/helpers/shared-helpers.js
@@ -85,7 +85,7 @@ const isGhostDoc = (doc) => {
 
 const getDocId = (doc, docType = Constants.INDEX_RESULTS_DOC_TYPE.VIEW) => {
   if (docType === Constants.INDEX_RESULTS_DOC_TYPE.VIEW) {
-    return doc.id;
+    return doc.id || doc._id;
   } else if (docType === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX) {
     return doc.type === 'special' ? '_all_docs' : doc.ddoc;
   } else if (docType === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_QUERY) {
diff --git a/app/addons/documents/index-results/helpers/table-view.js b/app/addons/documents/index-results/helpers/table-view.js
index c91adea..b5c72c4 100644
--- a/app/addons/documents/index-results/helpers/table-view.js
+++ b/app/addons/documents/index-results/helpers/table-view.js
@@ -162,7 +162,7 @@ export const getTableViewData = (docs, options) => {
       header: '',
       keylabel: '',
       url: doc._id || doc.id ? getDocUrl('app', doc._id || doc.id, options.databaseName) : null,
-      isDeletable: isJSONDocBulkDeletable(doc, options.docType),
+      isDeletable: options.deleteEnabled ? isJSONDocBulkDeletable(doc, options.docType) : false,
       isEditable: isJSONDocEditable(doc, options.docType)
     };
   });
@@ -170,7 +170,7 @@ export const getTableViewData = (docs, options) => {
   return {
     notSelectedFields: notSelectedFieldsTableView,
     selectedFields: selectedFieldsTableView,
-    hasBulkDeletableDoc: hasBulkDeletableDoc(normalizedDocs, options.docType),
+    hasBulkDeletableDoc: options.deleteEnabled ? hasBulkDeletableDoc(normalizedDocs, options.docType) : false,
     schema: schema,
     results: res,
     displayedFields: isMetaData ? null : {
diff --git a/app/addons/documents/index-results/index-results.components.js b/app/addons/documents/index-results/index-results.components.js
deleted file mode 100644
index d262879..0000000
--- a/app/addons/documents/index-results/index-results.components.js
+++ /dev/null
@@ -1,486 +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 FauxtonAPI from "../../../core/api";
-import React from "react";
-import Stores from "./stores";
-import Actions from "./actions";
-import Components from "../../components/react-components";
-import Constants from "../constants";
-import ReactSelect from "react-select";
-import {ResultsToolBar} from "../components/results-toolbar";
-import "../../../../assets/js/plugins/prettify";
-import uuid from 'uuid';
-
-const {LoadLines, Copy} = Components;
-const store  = Stores.indexResultsStore;
-
-var NoResultsScreen = React.createClass({
-  propTypes: {
-    text: React.PropTypes.string.isRequired
-  },
-
-  render: function () {
-    return (
-      <div className="no-results-screen">
-        <div className="watermark-logo"></div>
-        <h3>{this.props.text}</h3>
-      </div>
-    );
-  }
-});
-
-var TableRow = React.createClass({
-  propTypes: {
-    docIdentifier: React.PropTypes.string.isRequired,
-    docChecked: React.PropTypes.func.isRequired,
-    isSelected: React.PropTypes.bool.isRequired,
-    index: React.PropTypes.number.isRequired,
-    data: React.PropTypes.object.isRequired,
-    onClick: React.PropTypes.func.isRequired
-  },
-
-  onChange: function () {
-    this.props.docChecked(this.props.el.id, this.props.el._rev);
-  },
-
-  getInitialState: function () {
-    return {
-      checked: this.props.isSelected
-    };
-  },
-
-  getRowContents: function (element, rowNumber) {
-    var el = element.content;
-
-    var row = this.props.data.selectedFields.map(function (k, i) {
-
-      var key = 'tableview-data-cell-' + rowNumber + k + i + el[k];
-      var stringified = typeof el[k] === 'object' ? JSON.stringify(el[k], null, '  ') : el[k];
-
-      return (
-        <td key={key} title={stringified} onClick={this.onClick}>
-          {stringified}
-        </td>
-      );
-    }.bind(this));
-
-    return row;
-  },
-
-  maybeGetCheckboxCell: function (el, i) {
-    return (
-      <td className="tableview-checkbox-cell" key={"tableview-checkbox-cell-" + i}>
-        {el.isDeletable ? <input
-          id={"checkbox-" + this.props.docIdentifier}
-          checked={this.props.isSelected}
-          type="checkbox"
-          onChange={this.onChange} /> : null}
-      </td>
-    );
-  },
-
-  getAdditionalInfoRow: function (el) {
-    const attachmentCount = Object.keys(el._attachments || {}).length;
-    let attachmentIndicator = null;
-    let textAttachments = null;
-
-    const conflictCount = Object.keys(el._conflicts || {}).length;
-    let conflictIndicator = null;
-    let textConflicts = null;
-
-
-    if (attachmentCount) {
-      textAttachments = attachmentCount === 1 ? attachmentCount + ' Attachment' : attachmentCount + ' Attachments';
-      attachmentIndicator = (
-        <div style={{display: 'inline', marginLeft: '5px'}} title={textAttachments}>
-          <i className="icon fonticon-paperclip"></i>{attachmentCount}
-        </div>
-      );
-    }
-
-    if (conflictCount) {
-      textConflicts = conflictCount === 1 ? conflictCount + ' Conflict' : conflictCount + ' Conflicts';
-      conflictIndicator = (
-        <div className="tableview-conflict" data-conflicts-indicator style={{display: 'inline'}} title={textConflicts}>
-          <i
-            style={{fontSize: '17px'}}
-            className="icon icon-code-fork"></i>{conflictCount}
-        </div>
-      );
-    }
-
-    return (
-      <td className="tableview-el-last" onClick={this.onClick}>
-        {conflictIndicator}
-        {attachmentIndicator}
-      </td>
-    );
-  },
-
-  getCopyButton: function (el) {
-    var text = JSON.stringify(el, null, '  ');
-    return (
-      <td title={text} className="tableview-el-copy">
-        <Copy
-          title={text}
-          text={text}
-          uniqueKey={uuid.v4()}
-          onClipboardClick={this.showCopiedMessage} />
-      </td>
-    );
-  },
-
-  showCopiedMessage: function () {
-    FauxtonAPI.addNotification({
-      msg: 'The document content has been copied to the clipboard.',
-      type: 'success',
-      clear: true
-    });
-  },
-
-  onClick: function (e) {
-    this.props.onClick(this.props.el._id, this.props.el, e);
-  },
-
-  render: function () {
-    var i = this.props.index;
-    var docContent = this.props.el.content;
-    var el = this.props.el;
-
-    return (
-      <tr key={"tableview-content-row-" + i}>
-        {this.maybeGetCheckboxCell(el, i)}
-        {this.getCopyButton(docContent)}
-        {this.getRowContents(el, i)}
-        {this.getAdditionalInfoRow(docContent)}
-      </tr>
-    );
-  }
-});
-
-const WrappedAutocomplete = ({selectedField, notSelectedFields, index, changeField, selectedFields}) => {
-  const options = notSelectedFields.map((el) => {
-    return {value: el, label: el};
-  });
-
-  const onChange = (el) => {
-    const newField = {
-      newSelectedRow: el.value,
-      index: index
-    };
-
-    // changeField will be undefined for non-redux components
-    if (changeField) {
-      changeField(newField, selectedFields);
-    } else {
-      Actions.changeField(newField);
-    }
-  };
-
-  return (
-    <div className="table-container-autocomplete">
-      <div className="table-select-wrapper">
-        <ReactSelect
-          value={selectedField}
-          options={options}
-          clearable={false}
-          onChange={onChange} />
-      </div>
-    </div>
-  );
-};
-
-
-var TableView = React.createClass({
-
-  getContentRows: function () {
-    var data = this.props.data.results;
-
-    return data.map(function (el, i) {
-
-      return (
-        <TableRow
-          onClick={this.props.onClick}
-          key={"tableview-row-component-" + i}
-          index={i}
-          el={el}
-          docIdentifier={el.id || "tableview-row-component-" + i}
-          docChecked={this.props.docChecked}
-          isSelected={this.props.isSelected(el.id)}
-          data={this.props.data} />
-      );
-    }.bind(this));
-  },
-
-  getOptionFieldRows: function (filtered) {
-    const notSelectedFields = this.props.data.notSelectedFields;
-
-    if (!notSelectedFields) {
-      return filtered.map(function (el, i) {
-        return <th key={'header-el-' + i}>{el}</th>;
-      });
-    }
-
-    return filtered.map(function (el, i) {
-      return (
-        <th key={'header-el-' + i}>
-          {this.getDropdown(
-            el,
-            this.props.data.schema,
-            i,
-            this.props.changeField,
-            this.props.data.selectedFields
-          )}
-        </th>
-      );
-    }.bind(this));
-  },
-
-  getDropdown: function (selectedField, notSelectedFields, i, changeField, selectedFields) {
-
-    return (
-      <WrappedAutocomplete
-        selectedField={selectedField}
-        notSelectedFields={notSelectedFields}
-        index={i}
-        changeField={changeField}
-        selectedFields={selectedFields} />
-    );
-  },
-
-  getHeader: function () {
-    var selectedFields = this.props.data.selectedFields;
-    var row = this.getOptionFieldRows(selectedFields);
-
-    return (
-      <tr key="tableview-content-row-header">
-        <th className="tableview-header-el-checkbox"></th>
-        <th className="tableview-el-copy"></th>
-        {row}
-        <th className="tableview-el-last"></th>
-      </tr>
-    );
-  },
-
-  render: function () {
-    var header = this.getHeader();
-    var contentRows = this.getContentRows();
-
-    return (
-      <div className="table-view-docs">
-        <table className="table table-striped">
-          <thead>
-            {header}
-          </thead>
-          <tbody>
-            {contentRows}
-          </tbody>
-        </table>
-      </div>
-    );
-  }
-});
-
-
-var ResultsScreen = React.createClass({
-
-  onClick: function (id, doc) {
-    FauxtonAPI.navigate(doc.url);
-  },
-
-  getUrlFragment: function (url) {
-    if (!this.props.isEditable) {
-      return null;
-    }
-
-    return (
-      <a href={url}>
-        <i className="fonticon-pencil"></i>
-      </a>);
-  },
-
-  getDocumentList: function () {
-    var noop = function () {};
-    var data = this.props.results.results;
-
-    return _.map(data, function (doc, i) {
-      return (
-       <Components.Document
-         key={doc.id + i}
-         doc={doc}
-         onClick={this.props.isEditable ? this.onClick : noop}
-         keylabel={doc.keylabel}
-         docContent={doc.content}
-         checked={this.props.isSelected(doc.id)}
-         header={doc.header}
-         docChecked={this.props.docChecked}
-         isDeletable={doc.isDeletable}
-         docIdentifier={doc.id} >
-         {doc.url ? this.getUrlFragment('#' + doc.url) : doc.url}
-       </Components.Document>
-     );
-    }, this);
-  },
-
-  getDocumentStyleView: function () {
-    let classNames = 'view';
-
-    if (this.props.isListDeletable) {
-      classNames += ' show-select';
-    }
-
-    return (
-      <div className={classNames}>
-        <div id="doc-list">
-          {this.getDocumentList()}
-        </div>
-      </div>
-    );
-  },
-
-  getTableStyleView: function () {
-    return (
-      <div>
-        <TableView
-          onClick={this.onClick}
-          docChecked={this.props.docChecked}
-          isSelected={this.props.isSelected}
-          isListDeletable={this.props.isListDeletable}
-          data={this.props.results}
-          isLoading={this.props.isLoading}
-          removeItem={this.props.removeItem}
-          isChecked={this.props.allDocumentsSelected}
-          hasSelectedItem={this.props.hasSelectedItem}
-          toggleSelect={this.toggleSelectAll}
-          changeField={this.props.changeTableHeaderAttribute}
-          title="Select all docs that can be..." />
-      </div>
-    );
-  },
-
-  render: function () {
-    let mainView = null;
-    const { toggleSelectAll } = this.props;
-    let toolbar = <ResultsToolBar toggleSelectAll={toggleSelectAll || this.toggleSelectAll} {...this.props} />;
-
-    if (this.props.isLoading) {
-      mainView = <div className="loading-lines-wrapper"><LoadLines /></div>;
-    } else if (!this.props.hasResults) {
-      mainView = <NoResultsScreen text={this.props.textEmptyIndex}/>;
-    } else if (this.props.selectedLayout === Constants.LAYOUT_ORIENTATION.JSON) {
-      mainView = this.getDocumentStyleView();
-    } else {
-      mainView = this.getTableStyleView();
-    }
-
-    return (
-      <div className="document-result-screen">
-        {toolbar}
-        {mainView}
-      </div>
-    );
-  },
-
-  toggleSelectAll: function () {
-    Actions.toggleAllDocuments();
-  },
-
-  componentDidMount: function () {
-    prettyPrint();
-  },
-
-  componentDidUpdate: function () {
-    prettyPrint();
-  }
-});
-
-
-
-var ViewResultListController = React.createClass({
-  propTypes: {
-    designDocs: React.PropTypes.object
-  },
-
-  getStoreState: function () {
-    const selectedItemsLength = store.getSelectedItemsLength();
-    const isLoading = store.isLoading();
-    return {
-      hasResults: store.hasResults(),
-      results: isLoading ? {} : store.getResults(),
-      isLoading: isLoading,
-      isEditable: store.isEditable(),
-      textEmptyIndex: store.getTextEmptyIndex(),
-      selectedLayout: store.getSelectedLayout(),
-      allDocumentsSelected: store.areAllDocumentsSelected(),
-      hasSelectedItem: !!selectedItemsLength,
-      selectedItemsLength: selectedItemsLength,
-      bulkDeleteCollection: store.getBulkDocCollection()
-    };
-  },
-
-  isSelected: function (id) {
-    return !!this.state.bulkDeleteCollection.get(id);
-  },
-
-  removeItem: function () {
-    Actions.deleteSelected(this.state.bulkDeleteCollection, this.state.selectedItemsLength, this.props.designDocs);
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  componentDidMount: function () {
-    store.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    store.off('change', this.onChange);
-  },
-
-  onChange: function () {
-    this.setState(this.getStoreState());
-  },
-
-  docChecked: function (_id, _rev) {
-    Actions.selectDoc({
-      _id: _id,
-      _rev: _rev
-    });
-  },
-
-  render: function () {
-    return (
-      <ResultsScreen
-        removeItem={this.removeItem}
-        hasSelectedItem={this.state.hasSelectedItem}
-        allDocumentsSelected={this.state.allDocumentsSelected}
-        isSelected={this.isSelected}
-        isEditable={this.state.isEditable}
-        isListDeletable={this.state.results.hasBulkDeletableDoc}
-        docChecked={this.docChecked}
-        isLoading={this.state.isLoading}
-        hasResults={this.state.hasResults}
-        textEmptyIndex={this.state.textEmptyIndex}
-        results={this.state.results}
-        selectedLayout={this.state.selectedLayout} />
-    );
-  }
-});
-
-export default {
-  List: ViewResultListController,
-  NoResultsScreen: NoResultsScreen,
-  ResultsScreen: ResultsScreen,
-  WrappedAutocomplete: WrappedAutocomplete
-};
diff --git a/app/addons/documents/index-results/reducers.js b/app/addons/documents/index-results/reducers.js
index d8ab896..c492127 100644
--- a/app/addons/documents/index-results/reducers.js
+++ b/app/addons/documents/index-results/reducers.js
@@ -59,7 +59,7 @@ const initialState = {
   }
 };
 
-export default function resultsState (state = initialState, action) {
+export default function resultsState(state = initialState, action) {
   switch (action.type) {
 
     case ActionTypes.INDEX_RESULTS_REDUX_RESET_STATE:
@@ -73,6 +73,8 @@ export default function resultsState (state = initialState, action) {
         pagination: Object.assign({}, initialState.pagination, {
           perPage: state.pagination.perPage
         }),
+        queryOptionsPanel: Object.assign({}, initialState.queryOptionsPanel,
+          state.queryOptionsPanel, {reduce: false, groupLevel: 'exact', showReduce: false}),
         isLoading: false
       });
 
@@ -151,6 +153,17 @@ export default function resultsState (state = initialState, action) {
       });
 
     case ActionTypes.INDEX_RESULTS_REDUX_NEW_QUERY_OPTIONS:
+      // includeDocs or reduce should be mutually exclusive
+      if (action.options.includeDocs && action.options.reduce) {
+        // includeDocs has precedence if both are set at the same time
+        action.options.reduce = false;
+      } else if (action.options.includeDocs && state.queryOptionsPanel.reduce) {
+        // Switch off reduce when includeDocs is being set to true
+        action.options.reduce = false;
+      } else if (action.options.reduce && state.queryOptionsPanel.includeDocs) {
+        // Switch off includeDocs when reduce is being set to true
+        action.options.includeDocs = false;
+      }
       return Object.assign({}, state, {
         queryOptionsPanel: Object.assign({}, state.queryOptionsPanel, action.options)
       });
@@ -166,14 +179,15 @@ export const removeGeneratedMangoDocs = (doc) => {
 };
 
 // transform the docs in to a state ready for rendering on the page
-export const getDataForRendering = (state, databaseName) => {
+export const getDataForRendering = (state, databaseName, deleteEnabled = true) => {
   const { docs } = state;
   const options = {
     databaseName: databaseName,
     selectedLayout: state.selectedLayout,
     selectedFieldsTableView: state.tableView.selectedFieldsTableView,
     showAllFieldsTableView: state.tableView.showAllFieldsTableView,
-    docType: state.docType
+    docType: state.docType,
+    deleteEnabled: deleteEnabled
   };
 
   const docsWithoutGeneratedMangoDocs = docs.filter(removeGeneratedMangoDocs);
@@ -255,7 +269,7 @@ export const getCanShowPrevious = (state) => {
   return state.pagination.currentPage > 1;
 };
 
-export const getDisplayedFields = (state, databaseName)  => {
+export const getDisplayedFields = (state, databaseName) => {
   return getDataForRendering(state, databaseName).displayedFields || {};
 };
 
@@ -277,7 +291,9 @@ export const getQueryOptionsParams = (state) => {
       params.end_key = betweenKeys.endkey;
     }
   } else if (queryOptionsPanel.showByKeys) {
-    params.keys = queryOptionsPanel.byKeys.replace(/\r?\n/g, '');
+    if (queryOptionsPanel.byKeys.trim()) {
+      params.keys = queryOptionsPanel.byKeys.replace(/\r?\n/g, '');
+    }
   }
 
   if (queryOptionsPanel.limit !== 'none') {
diff --git a/app/addons/documents/index-results/stores.js b/app/addons/documents/index-results/stores.js
deleted file mode 100644
index f0c0c42..0000000
--- a/app/addons/documents/index-results/stores.js
+++ /dev/null
@@ -1,865 +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 app from "../../../app";
-import FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-import HeaderActionTypes from "../header/header.actiontypes";
-import PaginationActionTypes from "../pagination/actiontypes";
-import MangoHelper from "../mango/mango.helper";
-import Resources from "../resources";
-import Constants from "../constants";
-
-var Stores = {};
-
-var maxDocLimit = 10000;
-
-Stores.IndexResultsStore = FauxtonAPI.Store.extend({
-
-  initialize: function () {
-    this.reset();
-  },
-
-  reset: function () {
-    this._collection = new (FauxtonAPI.Collection.extend({
-      url: ''
-    }))();
-
-    this._filteredCollection = [];
-    this._bulkDeleteDocCollection = new Resources.BulkDeleteDocCollection([], {});
-
-    this.clearSelectedItems();
-    this._isLoading = false;
-    this._textEmptyIndex = 'No Documents Found';
-    this._typeOfIndex = Constants.INDEX_RESULTS_DOC_TYPE.VIEW;
-
-    this._tableViewSelectedFields = [];
-    this._isPrioritizedEnabled = false;
-    this._explain = false;
-
-    this._tableSchema = [];
-    this._selectedLayout = Constants.LAYOUT_ORIENTATION.METADATA;
-
-    this.resetPagination();
-  },
-
-  resetPagination: function () {
-    this._pageStart = 1;
-    this._currentPage = 1;
-    this._enabled = true;
-    this._newView = false;
-    this._docLimit = _.isUndefined(this._docLimit) ? maxDocLimit : this._docLimit;
-
-    this.initPerPage();
-  },
-
-  setDocumentLimit: function (docLimit) {
-    if (docLimit) {
-      this._docLimit = docLimit;
-    } else {
-      this._docLimit = maxDocLimit;
-    }
-
-    this.initPerPage();
-  },
-
-  canShowPrevious: function () {
-    if (!this._enabled) { return false; }
-    if (!this._collection || !this._collection.hasPrevious) { return false; }
-    return this._collection.hasPrevious();
-  },
-
-  canShowNext: function () {
-    if (!this._enabled) { return this._enabled; }
-
-    if ((this._pageStart + this._perPage) >= this._docLimit) {
-      return false;
-    }
-
-    if (!this._collection || !this._collection.hasNext) { return false; }
-
-    return this._collection.hasNext();
-  },
-
-  paginateNext: function () {
-    this._currentPage += 1;
-    this._pageStart += this.getPerPage();
-    this._collection.paging.pageSize = this.documentsLeftToFetch();
-  },
-
-  paginatePrevious: function () {
-    this._currentPage -= 1;
-
-    this._pageStart = this._pageStart - this.getPerPage();
-    if (this._pageStart < 1) {
-      this._pageStart = 1;
-    }
-
-    this._collection.paging.pageSize = this.getPerPage();
-  },
-
-  getCurrentPage: function () {
-    return this._currentPage;
-  },
-
-  totalDocsViewed: function () {
-    return this._perPage * this._currentPage;
-  },
-
-  documentsLeftToFetch: function () {
-    var documentsLeftToFetch = this._docLimit - this.totalDocsViewed();
-
-    if (documentsLeftToFetch < this.getPerPage()) {
-      return documentsLeftToFetch;
-    }
-
-    return this._perPage;
-  },
-
-  getPerPage: function () {
-    return this._perPage;
-  },
-
-  initPerPage: function () {
-    var perPage = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-
-    if (window.localStorage) {
-      var storedPerPage = app.utils.localStorageGet('fauxton:perpage');
-
-      if (storedPerPage) {
-        perPage = parseInt(storedPerPage, 10);
-      }
-    }
-
-    if (this._docLimit < perPage) {
-      perPage = this._docLimit;
-    }
-
-    this.setPerPage(perPage);
-  },
-
-  setPerPage: function (perPage) {
-    this._perPage = perPage;
-    app.utils.localStorageSet('fauxton:perpage', perPage);
-
-    if (this._collection && this._collection.pageSizeReset) {
-      this._collection.pageSizeReset(perPage, {fetch: false});
-    }
-  },
-
-  getTotalRows: function () {
-    if (!this._collection) { return false; }
-
-    return this._collection.length;
-  },
-
-  setPageStart: function (options) {
-    this._pageStart = options.start + 1;
-  },
-
-  getPageStart: function () {
-    return this._pageStart;
-  },
-
-  getPageEnd: function () {
-    if (!this._collection) { return false; }
-    return this._pageStart + this._collection.length - 1;
-  },
-
-  clearSelectedItems: function () {
-    this._bulkDeleteDocCollection.reset([]);
-  },
-
-  newResults: function (options) {
-    this._collection = options.collection;
-
-    this._bulkDeleteDocCollection = options.bulkCollection;
-
-    if (options.textEmptyIndex) {
-      this._textEmptyIndex = options.textEmptyIndex;
-    }
-
-    if (options.typeOfIndex) {
-      this._typeOfIndex = options.typeOfIndex;
-    }
-
-    // layout shifting magic to support refreshes, query options, and results toolbar
-    if (this.getIsMetadataView() && (this.isIncludeDocsEnabled() || this.getIsMangoResults())) {
-      this._selectedLayout = Constants.LAYOUT_ORIENTATION.TABLE;
-    }
-
-    if (!this.getIsMetadataView() && !this.isIncludeDocsEnabled() && !this.getIsMangoResults()) {
-      this._selectedLayout = Constants.LAYOUT_ORIENTATION.METADATA;
-    }
-
-    if (this.getIsMangoIndexResults()) {
-      this._selectedLayout = Constants.LAYOUT_ORIENTATION.JSON;
-    }
-
-    this._cachedSelected = [];
-
-    this._filteredCollection = this._collection.filter(filterOutGeneratedMangoDocs);
-
-    function filterOutGeneratedMangoDocs (doc) {
-      if (doc.get && typeof doc.get === 'function') {
-        return doc.get('language') !== 'query';
-      }
-
-      return doc.language !== 'query';
-    }
-  },
-
-  getTypeOfIndex: function () {
-    return this._typeOfIndex;
-  },
-
-  isEditable: function (doc) {
-    if (!this._collection) {
-      return false;
-    }
-
-    if (doc && this.isGhostDoc(doc)) {
-      return false;
-    }
-
-    if (doc && !doc.get('_id')) {
-      return false;
-    }
-
-    if (!this._collection.isEditable) {
-      return false;
-    }
-
-    return this._collection.isEditable();
-  },
-
-  isGhostDoc: function (doc) {
-    // ghost docs are empty results where all properties were
-    // filtered away by mango
-    return !doc || !doc.attributes || !Object.keys(doc.attributes).length;
-  },
-
-  isDeletable: function (doc) {
-    if (this.isGhostDoc(doc)) {
-      return false;
-    }
-
-    return doc.isDeletable();
-  },
-
-  getCollection: function () {
-    return this._collection;
-  },
-
-  getBulkDocCollection: function () {
-    return this._bulkDeleteDocCollection;
-  },
-
-  setCachedOffset: function (options) {
-    this._cachedOffset = options.offset;
-  },
-
-  getCachedOffset: function () {
-    return this._cachedOffset;
-  },
-
-  hasCachedOffset: function () {
-    return !!this._cachedOffset;
-  },
-
-  deleteCachedOffset: function () {
-    delete this._cachedOffset;
-  },
-
-  getDocContent: function (originalDoc) {
-    var doc = originalDoc.toJSON();
-
-    return JSON.stringify(doc, null, ' ');
-  },
-
-  getDocId: function (doc) {
-
-    if (!_.isUndefined(doc.id)) {
-      return doc.id;
-    }
-
-    if (doc.get('key')) {
-      return doc.get('key').toString();
-    }
-
-    return '';
-  },
-
-  getMangoDocContent: function (originalDoc) {
-    var doc = originalDoc.toJSON();
-
-    delete doc.ddoc;
-    delete doc.name;
-
-    return JSON.stringify(doc, null, ' ');
-  },
-
-  getMangoDoc: function (doc, index) {
-    var header;
-
-    if (doc.get('def') && doc.get('def').fields) {
-
-      header = MangoHelper.getIndexName({
-        def: doc.get('def'),
-        type: doc.get('type')
-      });
-
-      return {
-        content: this.getMangoDocContent(doc),
-        header: header,
-        id: doc.getId(),
-        keylabel: '',
-        url: doc.isFromView() ? doc.url('app') : doc.url('web-index'),
-        isDeletable: this.isDeletable(doc),
-        isEditable: this.isEditable(doc)
-      };
-    }
-
-    // we filtered away our content with the fields param
-    return {
-      content: ' ',
-      header: header,
-      id: this.getDocId(doc) + index,
-      keylabel: '',
-      url: this.isEditable(doc) ? doc.url('app') : null,
-      isDeletable: this.isDeletable(doc),
-      isEditable: this.isEditable(doc)
-    };
-  },
-
-  getResults: function () {
-    if (this._selectedLayout === Constants.LAYOUT_ORIENTATION.JSON) {
-      return this.getJsonViewData();
-    } else {
-      return this.getTableViewData();
-    }
-  },
-
-  getJsonViewData: function () {
-    // JSON style views
-    const res = this._filteredCollection
-      .map(function (doc, i) {
-        if (doc.get('def') || this.isGhostDoc(doc)) {
-          return this.getMangoDoc(doc, i);
-        }
-        return {
-          content: this.getDocContent(doc),
-          id: this.getDocId(doc),
-          _rev: doc.get('_rev'),
-          header: this.getDocId(doc),
-          keylabel: doc.isFromView() ? 'key' : 'id',
-          url: this.getDocId(doc) ? doc.url('app') : null,
-          isDeletable: this.isDeletable(doc),
-          isEditable: this.isEditable(doc)
-        };
-      }, this);
-
-    return {
-      displayedFields: this.getDisplayCountForTableView(),
-      hasBulkDeletableDoc: this.hasBulkDeletableDoc(this._filteredCollection),
-      results: res
-    };
-  },
-
-  getPseudoSchema: function (data) {
-    var cache = [];
-
-    data.forEach(function (el) {
-      Object.keys(el).forEach(function (k) {
-        cache.push(k);
-      });
-    });
-
-    cache = _.uniq(cache);
-
-    // always begin with _id
-    var i = cache.indexOf('_id');
-    if (i !== -1) {
-      cache.splice(i, 1);
-      cache.unshift('_id');
-    }
-
-    return cache;
-  },
-
-  normalizeTableData: function (data, isView) {
-    // filter out cruft
-    if (isView) {
-      return data;
-    }
-
-    return data.map(function (el) {
-      return el.doc || el;
-    });
-  },
-
-  isIncludeDocsEnabled: function () {
-    var params = app.getParams();
-
-    return !!params.include_docs;
-  },
-
-  getPrioritizedFields: function (data, max) {
-    var res = data.reduce(function (acc, el) {
-      acc = acc.concat(Object.keys(el));
-      return acc;
-    }, []);
-
-    res = _.countBy(res, function (el) {
-      return el;
-    });
-
-    delete res.id;
-    delete res._rev;
-
-    res = Object.keys(res).reduce(function (acc, el) {
-      acc.push([res[el], el]);
-      return acc;
-    }, []);
-
-    res = this.sortByTwoFields(res);
-    res = res.slice(0, max);
-
-    return res.reduce(function (acc, el) {
-      acc.push(el[1]);
-      return acc;
-    }, []);
-  },
-
-   sortByTwoFields: function (elements) {
-    // given:
-    // var a = [[2, "b"], [3, "z"], [1, "a"], [3, "a"]]
-    // it sorts to:
-    // [[3, "a"], [3, "z"], [2, "b"], [1, "a"]]
-    // note that the arrays with 3 got the first two arrays
-    // _and_ that the second values in the array with 3 are also sorted
-
-    function _recursiveSort (a, b, index) {
-      if (a[index] === b[index]) {
-        return index < 2 ? _recursiveSort(a, b, index + 1) : 0;
-      }
-
-      // second elements asc
-      if (index === 1) {
-        return (a[index] < b[index]) ? -1 : 1;
-      }
-
-      // first elements desc
-      return (a[index] < b[index]) ? 1 : -1;
-    }
-
-    return elements.sort(function (a, b) {
-      return _recursiveSort(a, b, 0);
-    });
-  },
-
-  hasIdOrRev: function (schema) {
-
-    return schema.indexOf('_id') !== -1 ||
-      schema.indexOf('id') !== -1 ||
-      schema.indexOf('_rev') !== -1;
-  },
-
-  getNotSelectedFields: function (selectedFields, allFields) {
-    var without = _.without.bind(this, allFields);
-    return without.apply(this, selectedFields);
-  },
-
-  getDisplayCountForTableView: function () {
-    var allFieldCount;
-    var shownCount;
-
-    if (!this.getIsTableView()) {
-      return null;
-    }
-
-    shownCount = _.uniq(this._tableViewSelectedFields).length;
-    allFieldCount = _.without(this._tableSchema, '_attachments').length;
-
-    return {shown: shownCount, allFieldCount: allFieldCount};
-  },
-
-  getTableViewData: function () {
-    // softmigration remove backbone
-    const collectionType = this._collection.collectionType;
-    let data = this._filteredCollection.map(el => {
-      return fixDocIdForMango(el.toJSON(), collectionType);
-    });
-
-    function fixDocIdForMango (doc, docType) {
-      if (docType !== Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX) {
-        return doc;
-      }
-
-      doc.id = doc.ddoc;
-      return doc;
-    }
-
-    function isJSONDocEditable (doc, docType) {
-
-      if (!doc) {
-        return;
-      }
-
-      if (docType === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX) {
-        return false;
-      }
-
-      if (!Object.keys(doc).length) {
-        return false;
-      }
-
-      if (!doc._id) {
-        return false;
-      }
-
-      return true;
-    }
-
-    function isJSONDocBulkDeletable (doc, docType) {
-      if (docType === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX) {
-        return doc.type !== 'special';
-      }
-
-      return !!doc._id && !!doc._rev;
-    }
-
-    // softmigration end
-
-    let notSelectedFields = null;
-    let schema;  // array containing the unique attr keys in the results.  always begins with _id.
-
-    if (this.isIncludeDocsEnabled() || this.getIsMangoResults()) {
-      const isView = !!this._collection.view;
-      // remove "cruft" we don't want to display in the results
-      data = this.normalizeTableData(data, isView);
-      // build the schema container based on the normalized data
-      schema = this.getPseudoSchema(data);
-
-      // if we're showing a subset of the attr/columns in the table, set the selected fields
-      // to the previously cached fields if they exist.
-      if (!this._isPrioritizedEnabled) {
-        this._tableViewSelectedFields = this._cachedSelected || [];
-      }
-
-      // if we still don't know what attr/columns to display, build the list and update the
-      // cached fields for the next time.
-      if (this._tableViewSelectedFields.length === 0) {
-        this._tableViewSelectedFields = this.getPrioritizedFields(data, 5);
-        this._cachedSelected = this._tableViewSelectedFields;
-      }
-
-      // set the notSelectedFields to the subset excluding meta and selected attributes
-      const schemaWithoutMetaDataFields = _.without(schema, '_attachments');
-      notSelectedFields = this.getNotSelectedFields(this._tableViewSelectedFields, schemaWithoutMetaDataFields);
-
-      // if we're showing all attr/columns, we revert the notSelectedFields to null and set
-      // the selected fields to everything excluding meta.
-      if (this._isPrioritizedEnabled) {
-        notSelectedFields = null;
-        this._tableViewSelectedFields = schemaWithoutMetaDataFields;
-      }
-
-    } else {
-      // METADATA view.
-      // Build the schema based on the original data and then remove _attachment and value meta
-      // attributes.
-      schema = this.getPseudoSchema(data);
-      this._tableViewSelectedFields = _.without(schema, '_attachments');
-    }
-
-    this._notSelectedFields = notSelectedFields;
-    this._tableSchema = schema;
-
-    const res = data.map(function (doc) {
-      const safeId = app.utils.getSafeIdForDoc(doc._id || doc.id); // inconsistent apis for GET between mango and views
-
-      return {
-        content: doc,
-        id: doc._id || doc.id, // inconsistent apis for GET between mango and views
-        _rev: doc._rev,
-        header: '',
-        keylabel: '',
-        url: safeId ? FauxtonAPI.urls('document', 'app', this.getDatabase().safeID(), safeId) : '',
-        isDeletable: isJSONDocBulkDeletable(doc, collectionType),
-        isEditable: isJSONDocEditable(doc, collectionType)
-      };
-    }.bind(this));
-
-    return {
-      notSelectedFields: notSelectedFields,
-      selectedFields: this._tableViewSelectedFields,
-      hasBulkDeletableDoc: this.hasBulkDeletableDoc(this._filteredCollection),
-      schema: schema,
-      results: res,
-      displayedFields: this.getDisplayCountForTableView(),
-    };
-  },
-
-  changeTableViewFields: function (options) {
-    var newSelectedRow = options.newSelectedRow;
-    var i = options.index;
-
-    this._tableViewSelectedFields[i] = newSelectedRow;
-  },
-
-  getHasMetadata: function (schema) {
-    return _.includes(schema, '_id', '_rev');
-  },
-
-  hasBulkDeletableDoc: function (docs) {
-    var found = false;
-    var length = docs.length;
-    var i;
-
-    // use a for loop here as we can end it once we found the first id
-    for (i = 0; i < length; i++) {
-      if (docs[i].isBulkDeletable()) {
-        found = true;
-        break;
-      }
-    }
-
-    return found;
-  },
-
-  hasResults: function () {
-    if (this.isLoading()) { return !this.isLoading(); }
-    return this._collection.length > 0;
-  },
-
-  isLoading: function () {
-    return this._isLoading;
-  },
-
-  selectDoc: function (doc) {
-
-    if (!doc._id || doc._id === '_all_docs') {
-      return;
-    }
-
-    if (!this._bulkDeleteDocCollection.get(doc._id)) {
-      this._bulkDeleteDocCollection.add(doc);
-      return;
-    }
-
-    this._bulkDeleteDocCollection.remove(doc._id);
-  },
-
-  selectAllDocuments: function () {
-    this.deSelectCurrentCollection();
-
-    this._collection.each(function (doc) {
-
-      if (!doc.isBulkDeletable()) {
-        return;
-      }
-
-      this.selectDoc({
-        _id: doc.id,
-        _rev: doc.get('_rev'),
-        _deleted: true
-      });
-    }, this);
-
-  },
-
-  deSelectCurrentCollection: function () {
-    this._collection.each(function (doc) {
-
-      if (!doc.isBulkDeletable()) {
-        return;
-      }
-
-      this._bulkDeleteDocCollection.remove(doc.id);
-    }, this);
-  },
-
-  toggleSelectAllDocuments: function () {
-    if (this.areAllDocumentsSelected()) {
-      return this.deSelectCurrentCollection();
-    }
-
-    return this.selectAllDocuments();
-  },
-
-  togglePrioritizedTableView: function () {
-    this._isPrioritizedEnabled = !this._isPrioritizedEnabled;
-  },
-
-  areAllDocumentsSelected: function () {
-    if (this._collection.length === 0) {
-      return false;
-    }
-
-    var foundAllOnThisPage = true;
-
-    var selected = this._bulkDeleteDocCollection.pluck('_id');
-
-    this._collection.forEach(function (doc) {
-      if (!doc.isBulkDeletable()) {
-        return;
-      }
-
-      if (!_.includes(selected, doc.id)) {
-        foundAllOnThisPage = false;
-      }
-    }.bind(this));
-
-    return foundAllOnThisPage;
-  },
-
-  getSelectedItemsLength: function () {
-    return this._bulkDeleteDocCollection.length;
-  },
-
-  getDatabase: function () {
-    return this._collection.database;
-  },
-
-  getTextEmptyIndex: function () {
-    return this._textEmptyIndex;
-  },
-
-  hasSelectedItem: function () {
-    return this.getSelectedItemsLength() > 0;
-  },
-
-  toggleLayout: function (options) {
-    this._selectedLayout = options.layout;
-  },
-
-  getSelectedLayout: function () {
-    return this._selectedLayout;
-  },
-
-  getIsTableView: function () {
-    return this._selectedLayout === Constants.LAYOUT_ORIENTATION.TABLE;
-  },
-
-  getIsMetadataView: function () {
-    return this._selectedLayout === Constants.LAYOUT_ORIENTATION.METADATA;
-  },
-
-  getIsMangoResults: function () {
-    return this._typeOfIndex === 'mango'
-      || this._typeOfIndex === 'mango-index'
-      || this._typeOfIndex === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX; // MangoIndex is the value used by Redux components
-  },
-
-  getIsMangoIndexResults: function () {
-    return this._typeOfIndex === 'mango-index'
-    || this._typeOfIndex === Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX; // MangoIndex is the value used by Redux components;
-  },
-
-  getIsPrioritizedEnabled: function () {
-    return this._isPrioritizedEnabled;
-  },
-
-  getCurrentViewType: function () {
-
-    if (this._tableView) {
-      return 'table';
-    }
-
-    return 'expanded';
-  },
-
-  getShowPrioritizedFieldToggler: function () {
-    return (this.isIncludeDocsEnabled() || this.getIsMangoResults()) && this.getIsTableView();
-  },
-
-  clearResultsBeforeFetch: function () {
-    if (this._collection && this._collection.reset) {
-      this._collection.reset();
-    }
-    this._isLoading = true;
-  },
-
-  resultsResetFromFetch: function () {
-    this._isLoading = false;
-  },
-
-  dispatch: function (action) {
-    switch (action.type) {
-      case ActionTypes.INDEX_RESULTS_NEW_RESULTS:
-        this.newResults(action.options);
-      break;
-      case ActionTypes.INDEX_RESULTS_RESET:
-        this.resultsResetFromFetch();
-      break;
-      case ActionTypes.INDEX_RESULTS_SELECT_DOC:
-        this.selectDoc(action.options);
-      break;
-      case ActionTypes.INDEX_RESULTS_CLEAR_RESULTS:
-        this.clearResultsBeforeFetch();
-      break;
-      case ActionTypes.INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS:
-        this.toggleSelectAllDocuments();
-      break;
-      case ActionTypes.INDEX_RESULTS_SELECT_NEW_FIELD_IN_TABLE:
-        this.changeTableViewFields(action.options);
-      break;
-      case ActionTypes.INDEX_RESULTS_TOGGLE_PRIORITIZED_TABLE_VIEW:
-        this.togglePrioritizedTableView();
-      break;
-
-      case HeaderActionTypes.TOGGLE_LAYOUT:
-        this.toggleLayout(action.options);
-      break;
-
-      case PaginationActionTypes.SET_PAGINATION_DOCUMENT_LIMIT:
-        this.setDocumentLimit(action.docLimit);
-      break;
-      case PaginationActionTypes.PAGINATE_NEXT:
-        this.paginateNext();
-      break;
-      case PaginationActionTypes.PAGINATE_PREVIOUS:
-        this.paginatePrevious();
-      break;
-      case PaginationActionTypes.PER_PAGE_CHANGE:
-        this.resetPagination();
-        this.setPerPage(action.perPage);
-      break;
-      case PaginationActionTypes.SET_CACHED_OFFSET:
-        this.setCachedOffset(action.options);
-      break;
-      case PaginationActionTypes.DELETE_CACHED_OFFSET:
-        this.deleteCachedOffset();
-      break;
-      case PaginationActionTypes.SET_PAGE_START:
-        this.setPageStart(action.options);
-      break;
-      case PaginationActionTypes.RESET_PAGINATION:
-        this.resetPagination();
-      break;
-
-      default:
-      return;
-      // do nothing
-    }
-
-    this.triggerChange();
-  }
-
-});
-
-Stores.indexResultsStore = new Stores.IndexResultsStore();
-
-Stores.indexResultsStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.indexResultsStore.dispatch);
-
-export default Stores;
diff --git a/app/addons/documents/index-results/tests/index-results.actionsSpec.js b/app/addons/documents/index-results/tests/index-results.actionsSpec.js
deleted file mode 100644
index ae64afc..0000000
--- a/app/addons/documents/index-results/tests/index-results.actionsSpec.js
+++ /dev/null
@@ -1,112 +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 FauxtonAPI from "../../../../core/api";
-import Actions from "../actions";
-import Stores from "../stores";
-import Documents from "../../resources";
-import SidebarActions from "../../sidebar/actions";
-import testUtils from "../../../../../test/mocha/testUtils";
-import documentTestHelper from "../../tests/document-test-helper";
-var assert = testUtils.assert;
-var restore = testUtils.restore;
-var store;
-
-var createDocColumn = documentTestHelper.createDocColumn;
-
-describe('#deleteSelected', function () {
-  var confirmStub;
-  var bulkDeleteCollection;
-
-  beforeEach(function () {
-    Stores.indexResultsStore = new Stores.IndexResultsStore();
-    Stores.indexResultsStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.indexResultsStore.dispatch);
-    store = Stores.indexResultsStore;
-    store.reset();
-
-    bulkDeleteCollection = new Documents.BulkDeleteDocCollection([], {databaseId: '1'});
-    store._bulkDeleteDocCollection = bulkDeleteCollection;
-    store._collection = createDocColumn([{_id: 'testId1'}, {_id: 'testId2'}]);
-
-    store._selectedItems = {
-      'testId1': true,
-      'testId2': true
-    };
-
-    confirmStub = sinon.stub(window, 'confirm');
-    confirmStub.returns(true);
-
-  });
-
-  afterEach(function () {
-    restore(window.confirm);
-    restore(FauxtonAPI.addNotification);
-    restore(Actions.reloadResultsList);
-    restore(Actions.newResultsList);
-    restore(SidebarActions.updateDesignDocs);
-  });
-
-  it('doesn\'t delete if user denies confirmation', function () {
-    window.confirm.restore();
-
-    var stub = sinon.stub(window, 'confirm');
-    stub.returns(false);
-
-    var spy = sinon.spy(bulkDeleteCollection, 'bulkDelete');
-
-    Actions.deleteSelected(bulkDeleteCollection, 1);
-
-    assert.notOk(spy.calledOnce);
-  });
-
-  it('on success notifies all deleted', function (done) {
-    var spy = sinon.spy(FauxtonAPI, 'addNotification');
-    const spy2 = sinon.spy(SidebarActions, 'updateDesignDocs');
-    var promise = FauxtonAPI.Deferred();
-    var ids = {
-      errorIds: []
-    };
-    var bulkDelete = {
-      bulkDelete: function () {
-        promise.resolve(ids);
-        return promise;
-      },
-      reset: function () {
-        done();
-      },
-      map () {
-        return {
-          find () {
-            return true;
-          }
-        };
-      }
-    };
-
-    const designDocs = {
-      fetch () {
-        const designDocPromise = FauxtonAPI.Deferred();
-        designDocPromise.reject();
-        return designDocPromise;
-      }
-    };
-
-    var reloadResultsListStub = sinon.stub(Actions, 'reloadResultsList');
-    var stubPromise = FauxtonAPI.Deferred();
-    stubPromise.resolve();
-    reloadResultsListStub.returns(stubPromise);
-
-    Actions.deleteSelected(bulkDelete, 1, designDocs);
-    assert.ok(spy.calledOnce);
-    assert.ok(spy2.calledOnce);
-  });
-});
diff --git a/app/addons/documents/index-results/tests/index-results.componentsSpec.js b/app/addons/documents/index-results/tests/index-results.componentsSpec.js
deleted file mode 100644
index 359143d..0000000
--- a/app/addons/documents/index-results/tests/index-results.componentsSpec.js
+++ /dev/null
@@ -1,330 +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 FauxtonAPI from "../../../../core/api";
-import Views from "../index-results.components";
-import IndexResultsActions from "../actions";
-import Stores from "../stores";
-import Documents from "../../resources";
-import Constants from "../../constants";
-import documentTestHelper from "../../tests/document-test-helper";
-import utils from "../../../../../test/mocha/testUtils";
-import React from "react";
-import ReactDOM from "react-dom";
-import TestUtils from "react-addons-test-utils";
-
-FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-var assert = utils.assert;
-var store = Stores.indexResultsStore;
-var createDocColumn = documentTestHelper.createDocColumn;
-var createMangoIndexDocColumn = documentTestHelper.createMangoIndexDocColumn;
-
-describe('Index Results', function () {
-  var container, instance;
-
-  describe('no results text', function () {
-    beforeEach(function () {
-      container = document.createElement('div');
-      store.reset();
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(instance).parentNode);
-      store.reset();
-    });
-
-    it('renders a default text', function () {
-      IndexResultsActions.newResultsList({
-        collection: [],
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(<Views.List />, container);
-      var $el = $(ReactDOM.findDOMNode(instance)).find('.no-results-screen');
-      assert.equal($el.text(), 'No Documents Found');
-    });
-
-    it('you can change the default text', function () {
-      IndexResultsActions.newResultsList({
-        collection: {
-          forEach: function () {},
-          filter: function () { return []; },
-          fetch: function () {
-            return {
-              then: function (cb) {
-                cb();
-              }
-            };
-          }
-        },
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-        textEmptyIndex: 'I <3 Hamburg'
-      });
-
-
-      instance = TestUtils.renderIntoDocument(<Views.List />, container);
-      var $el = $(ReactDOM.findDOMNode(instance)).find('.no-results-screen');
-      assert.equal($el.text(), 'I <3 Hamburg');
-    });
-  });
-
-  describe('checkbox rendering', function () {
-    beforeEach(function () {
-      container = document.createElement('div');
-      store.reset();
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(instance).parentNode);
-      store.reset();
-    });
-
-    it('does not render checkboxes for elements with just the special index (Mango Index List)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createMangoIndexDocColumn([{foo: 'testId1', type: 'special'}]),
-        typeOfIndex: 'mango',
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.tableview-checkbox-cell input').length === 0);
-    });
-
-    it('renders checkboxes for elements with more than just the the special index (Mango Index List)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createMangoIndexDocColumn([{
-          ddoc: null,
-          name: 'biene',
-          type: 'json',
-          def: {fields: [{_id: 'desc'}]}
-        },
-        {
-          ddoc: null,
-          name: 'biene',
-          type: 'special',
-          def: {fields: [{_id: 'desc'}]}
-        }]),
-        typeOfIndex: 'mango',
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.tableview-checkbox-cell input').length > 0);
-    });
-
-    it('does not render checkboxes for elements with no id in a table (usual docs)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([{
-          ddoc: null,
-          name: 'biene',
-          type: 'special',
-          def: {fields: [{_id: 'desc'}]}
-        }]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.tableview-checkbox-cell input').length === 0);
-    });
-
-    it('does not render checkboxes for elements with no rev in a table (usual docs)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([{id: '1', foo: 'testId1'}, {id: '1', bar: 'testId1'}]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.tableview-checkbox-cell input').length === 0);
-    });
-
-    it('renders checkboxes for elements with an id and rev in a table (usual docs)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([{id: '1', foo: 'testId1', rev: 'foo'}, {bar: 'testId1', rev: 'foo'}]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.tableview-checkbox-cell input').length > 0);
-    });
-
-    it('renders checkboxes for elements with an id and rev in a json view (usual docs)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([{id: '1', emma: 'testId1', rev: 'foo'}, {bar: 'testId1'}]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      IndexResultsActions.resultsListReset();
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.JSON});
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-      assert.ok($el.find('.js-row-select').length > 0);
-    });
-
-    it('does not render checkboxes for elements with that are not deletable in a json view (usual docs)', function () {
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([{foo: 'testId1', rev: 'foo'}, {bar: 'testId1'}]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      IndexResultsActions.resultsListReset();
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.JSON});
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.notOk($el.hasClass('show-select'));
-    });
-
-  });
-
-  describe('cellcontent', function () {
-    beforeEach(function () {
-      container = document.createElement('div');
-      store.reset();
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(instance).parentNode);
-      store.reset();
-    });
-
-    it('formats title elements for better readability', function () {
-      var doc = {object: {a: 1, foo: [1, 2, 3]}};
-
-      IndexResultsActions.sendMessageNewResultList({
-        collection: createDocColumn([doc]),
-        typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-        bulkCollection: new Documents.BulkDeleteDocCollection([], {databaseId: '1'}),
-      });
-
-      store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-
-      IndexResultsActions.resultsListReset();
-
-      instance = TestUtils.renderIntoDocument(
-        <Views.List />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-      var $targetNode = $el.find('td.tableview-el-last').prev();
-
-      var formattedDoc = JSON.stringify(doc.object, null, '  ');
-      assert.equal($targetNode.attr('title'), formattedDoc);
-    });
-
-  });
-
-  describe('loading', function () {
-    beforeEach(function () {
-      container = document.createElement('div');
-      store.reset();
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(instance).parentNode);
-      store.reset();
-    });
-
-    it('should show loading component', function () {
-      var results = {results: [], selectedFields: []};
-      instance = TestUtils.renderIntoDocument(
-        <Views.ResultsScreen results={results} isLoading={true} />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.loading-lines').length === 1);
-    });
-
-    it('should not show loading component', function () {
-      var results = {results: [], selectedFields: []};
-      instance = TestUtils.renderIntoDocument(
-        <Views.ResultsScreen results={results} isLoading={false} />,
-        container
-      );
-
-      var $el = $(ReactDOM.findDOMNode(instance));
-
-      assert.ok($el.find('.loading-lines').length === 0);
-    });
-  });
-
-});
diff --git a/app/addons/documents/index-results/tests/index-results.storesSpec.js b/app/addons/documents/index-results/tests/index-results.storesSpec.js
deleted file mode 100644
index 9827184..0000000
--- a/app/addons/documents/index-results/tests/index-results.storesSpec.js
+++ /dev/null
@@ -1,722 +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 FauxtonAPI from "../../../../core/api";
-import Stores from "../stores";
-import Documents from "../../resources";
-import Constants from "../../constants";
-import documentTestHelper from "../../tests/document-test-helper";
-import testUtils from "../../../../../test/mocha/testUtils";
-import sinon from "sinon";
-var assert = testUtils.assert;
-var dispatchToken;
-var store;
-var opts;
-
-var createDocColumn = documentTestHelper.createDocColumn;
-var createMangoIndexDocColumn = documentTestHelper.createMangoIndexDocColumn;
-
-describe('Index Results Store', function () {
-  beforeEach(function () {
-    store = new Stores.IndexResultsStore();
-    store.dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
-    store.reset();
-    opts = {
-      params: {limit: 10, skip: 0},
-      database: {
-        safeID: function () { return '1';}
-      }
-    };
-
-    store.newResults({
-      collection: createDocColumn([
-        {_id: 'testId5', _rev: '1', 'value': 'one'},
-        {_id: 'testId6', _rev: '1', 'value': 'one'}
-      ]),
-      bulkCollection: new Documents.BulkDeleteDocCollection([], { databaseId: '1' })
-    });
-  });
-
-  afterEach(function () {
-    FauxtonAPI.dispatcher.unregister(store.dispatchToken);
-  });
-
-
-  it('hasResults returns true for collection', function () {
-    store.newResults({
-      collection: createDocColumn([
-        {_id: 'testId5', _rev: '1', 'value': 'one'},
-        {_id: 'testId6', _rev: '1', 'value': 'one'}
-      ]),
-      bulkCollection: new Documents.BulkDeleteDocCollection([], { databaseId: '1' })
-    });
-
-    assert.ok(store.hasResults());
-  });
-
-  it('can sort 2 dimensional arrays by the first value', function () {
-    var a = [
-      [20, 5],
-      [1, 2],
-      [3, 4]
-    ];
-
-    store.sortByTwoFields(a);
-    assert.equal(a[0][0], 20);
-    assert.equal(a[1][0], 3);
-    assert.equal(a[2][0], 1);
-  });
-
-  it('can sort 2 dimensional arrays by the second value if multiple appear', function () {
-    var a = [
-      [1, "z"],
-      [1, "g"],
-      [1, "a"]
-    ];
-
-    store.sortByTwoFields(a);
-    assert.equal(a[0][1], 'a');
-    assert.equal(a[1][1], 'g');
-    assert.equal(a[2][1], 'z');
-  });
-
-
-  it('hasResults returns false for empty collection', function () {
-    store._collection = [];
-
-    assert.notOk(store.hasResults());
-  });
-
-  it('getResults has correct doc format', function () {
-    store.newResults({
-      collection: createDocColumn([
-        {_id: 'testId', _rev: '1', 'value': 'one'},
-      ])
-    });
-    store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.JSON});
-
-    var doc = store.getResults().results[0];
-    assert.equal(doc.id, 'testId');
-    assert.equal(doc.keylabel, 'id');
-  });
-
-  it('tries to guess a pseudo schema for table views', function () {
-    var doclist = [
-      {_id: 'testId1', value: 'one'},
-      {_id: 'testId2', foo: 'one'},
-      {_id: 'testId3', bar: 'one'},
-    ];
-
-    var schema = store.getPseudoSchema(doclist);
-
-    assert.ok(schema.indexOf('_id') !== -1);
-    assert.ok(schema.indexOf('value') !== -1);
-    assert.ok(schema.indexOf('foo') !== -1);
-    assert.ok(schema.indexOf('bar') !== -1);
-  });
-
-  it('uses unique values for the pseudo schema', function () {
-    var doclist = [
-      {_id: 'testId1', foo: 'one'},
-      {_id: 'testId2', foo: 'one'}
-    ];
-
-    var schema = store.getPseudoSchema(doclist);
-
-    assert.equal(schema.length, 2);
-    assert.equal(schema.length, 2);
-    assert.ok(schema.indexOf('foo') !== -1);
-    assert.ok(schema.indexOf('_id') !== -1);
-  });
-
-  it('puts the id into the array as first element', function () {
-    var doclist = [
-      {foo: 'one', _id: 'testId1'},
-      {foo: 'one', _id: 'testId2'}
-    ];
-
-    var schema = store.getPseudoSchema(doclist);
-
-    assert.equal(schema.shift(), '_id');
-  });
-
-  it('normalizes different content from include_docs enabled', function () {
-    var doclist = [
-      {_id: 'testId2', foo: 'one', doc: {"_rev": "1", "ente": "gans", "fuchs": "hase"}},
-      {_id: 'testId3', foo: 'two', doc: {"_rev": "2", "haus": "blau", "tanne": "acht"}}
-    ];
-
-    var res = store.normalizeTableData(doclist);
-    assert.deepEqual(res[0], {"_rev": "1", "ente": "gans", "fuchs": "hase"});
-  });
-
-  it('returns the fields that occur the most without id and rev', function () {
-    var doclist = [
-      {_rev: '1', _id: '1', id: 'testId2', foo: 'one'},
-      {_rev: '1', _id: '1', id: 'testId3', foo: 'two'}
-    ];
-
-    var res = store.getPrioritizedFields(doclist, 10);
-    assert.deepEqual(res, ['_id', 'foo']);
-  });
-
-  it('sorts the fields that occure the most', function () {
-    var doclist = [
-      {id: 'testId2', foo: 'one'},
-
-      {id: 'testId3', bar: 'two'},
-      {id: 'testId3', bar: 'two'},
-      {id: 'testId3', baz: 'two'},
-      {id: 'testId3', baz: 'two'}
-    ];
-
-    var res = store.getPrioritizedFields(doclist, 10);
-    assert.deepEqual(res, ['bar', 'baz', 'foo']);
-  });
-
-  it('limits the fields that occure the most', function () {
-    var doclist = [
-      {id: 'testId2', foo: 'one'},
-
-      {id: 'testId3', bar: 'two'},
-      {id: 'testId3', bar: 'two'},
-      {id: 'testId3', baz: 'two'},
-      {id: 'testId3', baz: 'two'}
-    ];
-
-    var res = store.getPrioritizedFields(doclist, 2);
-    assert.deepEqual(res, ['bar', 'baz']);
-  });
-
-  it('if the collection is empty, no docs should be selected', function () {
-    store._collection = new Documents.AllDocs([], opts);
-
-    assert.notOk(store.areAllDocumentsSelected());
-  });
-
-  it('if the collection changes, not all docs should be selected', function () {
-    store._collection = createDocColumn([
-      {_id: 'testId1', _rev: '1', 'value': 'one'},
-      {_id: 'testId2', _rev: '1', 'value': 'one'}
-    ]);
-
-    store.selectAllDocuments();
-
-    store._collection = createDocColumn([
-      {_id: 'testId5', _rev: '1', 'value': 'one'},
-      {_id: 'testId6', _rev: '1', 'value': 'one'}
-    ]);
-
-    assert.notOk(store.areAllDocumentsSelected());
-  });
-
-  it('special mango docs are not selectable, but all should be selected', function () {
-    store._collection = createMangoIndexDocColumn([
-      {ddoc: 'testId1', type: 'special', def: {fields: [{_id: 'desc'}]}},
-      {ddoc: 'testId2', blubb: 'ba', type: 'json', def: {fields: [{_id: 'desc'}]}}
-    ]);
-
-    store.selectAllDocuments();
-
-    assert.ok(store.areAllDocumentsSelected());
-  });
-
-  it('returns true for selected docs less than collection', function () {
-    store._collection = createDocColumn([
-      {_id: 'testId1', _rev: 'foo'},
-      {_id: 'testId2', _rev: 'foo'}
-    ]);
-
-    store._selectedItems = {'testId1': true};
-    assert.notOk(store.areAllDocumentsSelected());
-  });
-
-  it('returns true even with _all_docs (mango)', function () {
-    store._collection = new Documents.AllDocs([
-      {_id: 'testId1'},
-      {_id: 'testId2'},
-      {_id: '_all_docs'}
-    ], opts);
-
-    store._selectedItems = {
-      'testId1': true,
-      'testId2': true
-    };
-
-    assert.ok(store.areAllDocumentsSelected());
-  });
-
-  it('does not count multiple fields in the prioritized table', function () {
-    store.newResults({
-      collection: createDocColumn([
-        {a: '1', 'value': 'one', b: '1'},
-        {a: '1', 'value': 'one', b: '1'},
-        {a: '1', 'value': 'one', b: '1'}
-      ]),
-      typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW
-    });
-
-    store.toggleLayout({layout: Constants.LAYOUT_ORIENTATION.TABLE});
-    const stub = sinon.stub(store, 'isIncludeDocsEnabled');
-    stub.returns(true);
-    store.getResults();
-
-    store.changeTableViewFields({index: 0, newSelectedRow: 'value'});
-
-    assert.deepEqual(store.getDisplayCountForTableView(), { shown: 2, allFieldCount: 3 });
-  });
-
-  it('selectDoc selects doc if not already selected', function () {
-    store._collection = new createDocColumn([
-      {_id: 'id', _rev: '1', 'value': 'one'},
-      {_id: 'testId6', _rev: '1', 'value': 'one'}
-    ]);
-    store.selectDoc({_id: 'id', _rev: '1'});
-    assert.equal(store.getSelectedItemsLength(), 1);
-  });
-
-  it('selectDoc deselects doc if already selected', function () {
-    store.selectDoc({_id: 'id', _rev: '1'});
-    store._collection = new createDocColumn([
-      {_id: 'id', _rev: '1', 'value': 'one'},
-      {_id: 'testId6', _rev: '1', 'value': 'one'}
-    ]);
-    store.selectDoc({_id: 'id', _rev: '1'});
-    assert.equal(store.getSelectedItemsLength(), 0);
-  });
-
-  it('selectDoc selects all documents', function () {
-    store._collection = createDocColumn([{_id: 'testId1', _rev: '1', 'value': 'one'}]);
-
-    store.selectAllDocuments();
-    assert.ok(store._bulkDeleteDocCollection.get('testId1'));
-  });
-
-  it('selectDoc does not select all documents if rev is missing', function () {
-    store._collection = createDocColumn([{_id: 'testId1', 'value': 'one'}]);
-
-    store.selectAllDocuments();
-    assert.equal(store.getSelectedItemsLength(), 0);
-  });
-
-});
-describe('toggleSelectAllDocuments', function () {
-
-  it('deselects all documents', function () {
-    store._collection = new Documents.AllDocs([{_id: 'testId1', _rev: '1', 'value': 'one'}], opts);
-
-    store.selectAllDocuments();
-    assert.ok(store._bulkDeleteDocCollection.get('testId1'));
-    store.toggleSelectAllDocuments();
-    assert.equal(store.getSelectedItemsLength(), 0);
-  });
-
-  it('deselects all documents with toggleSelectAllDocuments', function () {
-    store.reset();
-    store._collection = new Documents.AllDocs([{_id: 'testId1', _rev: '1', 'value': 'one'}], opts);
-
-    assert.equal(store._bulkDeleteDocCollection.length, 0);
-    store.toggleSelectAllDocuments();
-    assert.equal(store.getSelectedItemsLength(), 1);
-  });
-});
-
-describe('#getMangoDoc', function () {
-  beforeEach(function () {
-    store = new Stores.IndexResultsStore();
-    dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
-    opts = {
-      params: {},
-      database: {
-        safeID: function () { return '1';}
-      }
-    };
-  });
-
-  var fakeMango = {
-    ddoc: '_design/e4d338e5d6f047749f5399ab998b4fa04ba0c816',
-    def: {
-      fields: [
-        {'_id': 'asc'},
-        {'foo': 'bar'},
-        {'ente': 'gans'}
-      ]
-    },
-    name: 'e4d338e5d6f047749f5399ab998b4fa04ba0c816',
-    type: 'json'
-  };
-
-  it('creates a special id from the header fields', function () {
-    var doc = new Documents.MangoIndex(fakeMango, opts);
-    assert.equal(store.getMangoDoc(doc).header, 'json: _id, foo, ente');
-  });
-
-  it('supports custom header fields', function () {
-    FauxtonAPI.registerExtension('mango:additionalIndexes', {
-      createHeader: function () {
-        return ['foobar'];
-      }
-    });
-
-    var doc = new Documents.MangoIndex({
-      ddoc: '_design/e4d338e5d6f047749f5399ab998b4fa04ba0c816',
-      def: {
-        fields: []
-      },
-      name: 'e4d338e5d6f047749f5399ab998b4fa04ba0c816',
-      type: 'json'
-    }, opts);
-    assert.equal(store.getMangoDoc(doc).header, 'foobar');
-  });
-
-  it('removes the name and ddoc field', function () {
-    var doc = new Documents.MangoIndex(fakeMango, opts);
-    assert.ok(doc.get('name'));
-    assert.ok(doc.get('ddoc'));
-
-    store._allCollapsed = false;
-    var newDoc = store.getMangoDoc(doc);
-    assert.notOk(JSON.parse(newDoc.content).name);
-    assert.notOk(JSON.parse(newDoc.content).ddoc);
-    assert.ok(JSON.parse(newDoc.content).type);
-  });
-});
-
-describe('#getDocId', function () {
-
-  it('returns id if it exists', function () {
-    var doc = new Documents.Doc({
-      _id: 'doc-id'
-    }, opts);
-
-    assert.equal(store.getDocId(doc), 'doc-id');
-
-  });
-
-  it('returns key if it exists', function () {
-    var doc = new Documents.Doc({
-      key: 'doc-key'
-    }, opts);
-
-    assert.equal(store.getDocId(doc), 'doc-key');
-
-  });
-
-  it('returns empty string if no key or id exists', function () {
-    var doc = new Documents.Doc({
-      key: null,
-      value: 'the-value'
-    }, opts);
-
-    assert.equal(store.getDocId(doc), '');
-
-  });
-});
-
-describe('isEditable', function () {
-  store = new Stores.IndexResultsStore();
-
-  it('returns false for no collection', function () {
-    store._collection = null;
-    assert.notOk(store.isEditable());
-  });
-
-  it('returns false for empty collection', function () {
-    store._collection = [];
-    assert.notOk(store.isEditable());
-  });
-
-  it('delegates to collection', function () {
-    store._collection = {
-      attributes: {
-        fields: ["foo"]
-      }
-    };
-    store._collection.isEditable = function () { return {'stub': true}; };
-    assert.deepEqual(store.isEditable(), {'stub': true});
-    store._collection = {};
-  });
-
-  it('retuns false for ghost-docs that are filtered away', function () {
-    store._collection = {};
-    assert.equal(store.isEditable({}), false);
-  });
-});
-
-describe('isDeletable', function () {
-  store = new Stores.IndexResultsStore();
-
-  it('retuns false for ghost-docs that are filtered away', function () {
-    assert.equal(store.isDeletable({}), false);
-  });
-});
-
-describe('Index Pagination', function () {
-
-  beforeEach(function () {
-    store = new Stores.IndexResultsStore();
-    dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
-  });
-
-  afterEach(function () {
-    FauxtonAPI.dispatcher.unregister(dispatchToken);
-  });
-
-  describe('#collectionChanged', function () {
-    var collection;
-    beforeEach(function () {
-      collection = new Documents.AllDocs([{id:1}, {id: 2}], {
-        params: {},
-        database: {
-          safeID: function () { return '1';}
-        }
-      });
-      store.reset();
-      store.newResults({
-        collection: collection
-      });
-    });
-
-    it('sets total rows correctly', function () {
-      assert.equal(store.getTotalRows(), 2);
-    });
-  });
-
-  describe('canShowPrevious', function () {
-    it('cannot show previous if disabled', function () {
-      store._enabled = false;
-      assert.notOk(store.canShowPrevious());
-    });
-
-    it('can show if collection can show', function () {
-      store._enabled = true;
-      store._collection = new Backbone.Collection();
-      store._collection.hasPrevious = function () { return true;};
-      assert.ok(store.canShowPrevious());
-    });
-
-  });
-
-  describe('canShowNext', function () {
-    it('cannot show next if disabled', function () {
-      store._enabled = false;
-      assert.notOk(store.canShowNext());
-    });
-
-    it('cannot show if pageStart and perPage greater than docLimit', function () {
-      store._enabled = true;
-      store._docLimit = 10;
-      store._perPage = 20;
-
-      assert.notOk(store.canShowNext());
-    });
-
-    it('can show if collection can show', function () {
-      store._enabled = true;
-      store._docLimit = 100000;
-      store.reset();
-      store._collection = new Backbone.Collection();
-      store._collection.hasNext = function () { return true;};
-      assert.ok(store.canShowNext());
-    });
-  });
-
-  describe('paginateNext', function () {
-    beforeEach(function () {
-      store.reset();
-
-      store.newResults({
-        collection: new Documents.AllDocs(null, {
-          params: {},
-          database: {
-            safeID: function () { return '1';}
-          }
-        })
-      });
-      store.setPerPage(20);
-    });
-
-    it('should increment page number', function () {
-      store.paginateNext();
-
-      assert.equal(store.getCurrentPage(), 2);
-    });
-
-    it('should increment page start', function () {
-      store.paginateNext();
-
-      assert.equal(store.getPageStart(), 21);
-    });
-
-    it('should set correct page end', function () {
-      store._collection.length = 20;
-      store.paginateNext();
-
-      assert.equal(store.getPageEnd(), 40);
-    });
-
-    it('should set collection pageSize', function () {
-      store.paginateNext();
-
-      assert.equal(store.getCollection().paging.pageSize, 20);
-    });
-  });
-
-  describe('paginatePrevious', function () {
-    beforeEach(function () {
-      store.resetPagination();
-      store._collection = new Documents.AllDocs(null, {
-        params: {},
-        database: {
-          safeID: function () { return '1';}
-        }
-      });
-    });
-
-    it('should decrement page number', function () {
-      store.paginateNext();
-      store.paginatePrevious();
-
-      assert.equal(store.getCurrentPage(), 1);
-    });
-
-    it('should decrement page start', function () {
-      store.paginateNext();
-      store.paginatePrevious();
-
-      assert.equal(store.getPageStart(), 1);
-    });
-
-    it('should decrement page end', function () {
-      store._collection.length = 20;
-      store.paginateNext();
-      store.paginatePrevious();
-
-      assert.equal(store.getPageEnd(), 20);
-    });
-
-    it('should set collection pageSize', function () {
-      store.paginateNext();
-      store.paginatePrevious();
-
-      assert.equal(store.getCollection().paging.pageSize, 20);
-    });
-
-  });
-
-  describe('totalDocsViewed', function () {
-    beforeEach(function () {
-      store.reset();
-    });
-
-    it('returns correct count for page 1 and 20 docs per page', function () {
-      assert.equal(store.totalDocsViewed(), 20);
-    });
-
-    it('returns correct count for page 3 and 10 docs per page', function () {
-      store._perPage = 10;
-      store._currentPage = 3;
-
-      assert.equal(store.totalDocsViewed(), 30);
-    });
-  });
-
-  describe('documentsLeftToFetch', function () {
-    beforeEach(function () {
-      store.reset();
-    });
-
-    it('returns 20 documents left', function () {
-      assert.equal(store.documentsLeftToFetch(), 20);
-    });
-
-    it('returns less if close to limit', function () {
-      store._docLimit = 35;
-      store._perPage = 10;
-      store._currentPage = 3;
-      assert.equal(store.documentsLeftToFetch(), 5);
-    });
-
-  });
-
-  describe('#initPerPage', function () {
-
-    it('uses default if no local storage set', function () {
-      window.localStorage.removeItem('fauxton:perpage');
-      store.initPerPage();
-      assert.equal(store.getPerPage(), 20);
-    });
-
-    it('uses localstorage when available', function () {
-      window.localStorage.setItem('fauxton:perpage', 44);
-      store.initPerPage();
-      assert.equal(store.getPerPage(), 44);
-    });
-
-    it('uses doc limit when its less than perPage', function () {
-      window.localStorage.setItem('fauxton:perpage', 100);
-      store._docLimit = 6;
-      store.initPerPage();
-      assert.equal(store.getPerPage(), 6);
-    });
-
-  });
-
-  describe('#setDocumentLimit', function () {
-
-    it('sets document if exists', function () {
-      store.setDocumentLimit(10);
-      assert.equal(store._docLimit, 10);
-    });
-
-    it('sets perPage to doclimit if doclimit less than perPage', function () {
-      store.setPerPage(20);
-      store.setDocumentLimit(1);
-      assert.equal(store._docLimit, 1);
-    });
-
-    it('sets doclimit to 10000 if NaN', function () {
-      store.setDocumentLimit(NaN);
-      assert.equal(store._docLimit, 10000);
-    });
-  });
-
-  describe('#setPerPage', function () {
-    beforeEach(function () {
-      store.reset();
-      store._collection = new Documents.AllDocs(null, {
-        params: {},
-        database: {
-          safeID: function () { return '1';}
-        }
-      });
-
-    });
-
-    it('stores per page in local storage', function () {
-      var testPerPage = 111;
-      store.setPerPage(testPerPage);
-      var perPage = window.localStorage.getItem('fauxton:perpage');
-      assert.equal(perPage, testPerPage);
-    });
-
-    it('sets collections perPage', function () {
-      var spy = sinon.spy(store._collection, 'pageSizeReset');
-      var testPerPage = 110;
-
-      store.setPerPage(testPerPage);
-      assert.equal(spy.getCall(0).args[0], testPerPage);
-
-
-    });
-  });
-});
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index d807842..3773068 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -11,11 +11,8 @@
 // the License.
 
 import React from 'react';
-import IndexResultsComponents from './index-results/index-results.components';
-import ReactPagination from './pagination/pagination';
-import {NotificationCenterButton} from '../fauxton/notifications/notifications';
-import {ApiBarWrapper} from '../components/layouts';
-import SidebarComponents from "./sidebar/sidebar";
+import { NotificationCenterButton } from '../fauxton/notifications/notifications';
+import SidebarControllerContainer from "./sidebar/SidebarControllerContainer";
 import HeaderDocsLeft from './components/header-docs-left';
 import Changes from './changes/components';
 import IndexEditorComponents from "./index-editor/components";
@@ -24,19 +21,23 @@ import RightAllDocsHeader from './components/header-docs-right';
 import IndexResultsContainer from './index-results/containers/IndexResultsContainer';
 import PaginationContainer from './index-results/containers/PaginationContainer';
 import ApiBarContainer from './index-results/containers/ApiBarContainer';
-import { queryAllDocs } from './index-results/api';
+import { queryAllDocs, queryMapReduceView } from './index-results/api';
 import Constants from './constants';
+import Helpers from './helpers';
 
 export const TabsSidebarHeader = ({
   hideQueryOptions,
+  hideJumpToDoc,
   database,
   dbName,
   dropDownLinks,
   docURL,
   endpoint,
-  isRedux = false,
+  endpointAddQueryOptions,
   fetchUrl,
-  ddocsOnly
+  ddocsOnly,
+  queryDocs,
+  selectedNavItem
 }) => {
   return (
     <header className="two-panel-header">
@@ -45,20 +46,20 @@ export const TabsSidebarHeader = ({
           <HeaderDocsLeft
             dbName={dbName}
             dropDownLinks={dropDownLinks}
-            />
+          />
         </div>
         <div className="right-header-wrapper flex-layout flex-row flex-body">
           <div id="right-header" className="flex-fill">
             <RightAllDocsHeader
               hideQueryOptions={hideQueryOptions}
+              hideJumpToDoc={hideJumpToDoc}
               database={database}
-              isRedux={isRedux}
               fetchUrl={fetchUrl}
               ddocsOnly={ddocsOnly}
-              queryDocs={ (params) => { return queryAllDocs(fetchUrl, params); } } />
+              queryDocs={queryDocs}
+              selectedNavItem={selectedNavItem} />
           </div>
-          { isRedux ? <ApiBarContainer databaseName={dbName} /> :
-                      <ApiBarWrapper docURL={docURL} endpoint={endpoint} /> }
+          <ApiBarContainer docURL={docURL} endpoint={endpoint} endpointAddQueryOptions={endpointAddQueryOptions} />
           <div id="notification-center-btn" className="flex-fill">
             <NotificationCenterButton />
           </div>
@@ -69,13 +70,16 @@ export const TabsSidebarHeader = ({
 };
 
 TabsSidebarHeader.propTypes = {
-  dbName : React.PropTypes.string.isRequired,
-  dropDownLinks : React.PropTypes.array.isRequired,
-  docURL : React.PropTypes.string,
-  endpoint : React.PropTypes.string,
-  showIncludeAllDocs : React.PropTypes.bool,
-  hideHeaderBar : React.PropTypes.bool,
-  database : React.PropTypes.object.isRequired
+  dbName: React.PropTypes.string.isRequired,
+  dropDownLinks: React.PropTypes.array.isRequired,
+  docURL: React.PropTypes.string,
+  endpoint: React.PropTypes.string,
+  showIncludeAllDocs: React.PropTypes.bool,
+  hideQueryOptions: React.PropTypes.bool,
+  hideJumpToDoc: React.PropTypes.bool,
+  database: React.PropTypes.object.isRequired,
+  queryDocs: React.PropTypes.func,
+  selectedNavItem: React.PropTypes.object
 };
 
 TabsSidebarHeader.defaultProps = {
@@ -86,14 +90,14 @@ export const TabsSidebarContent = ({
   hideFooter,
   lowerContent,
   upperContent,
-  isRedux = false,
   fetchUrl,
-  databaseName
+  databaseName,
+  queryDocs
 }) => {
   return (
     <div className="with-sidebar tabs-with-sidebar content-area">
       <aside id="sidebar-content" className="scrollable">
-        <SidebarComponents.SidebarController />
+        <SidebarControllerContainer />
       </aside>
       <section id="dashboard-content" className="flex-layout flex-col">
         <div id="dashboard-upper-content">
@@ -103,11 +107,10 @@ export const TabsSidebarContent = ({
           {lowerContent}
         </div>
         <div id="footer">
-          {isRedux && !hideFooter ? <PaginationContainer
-                                      databaseName={databaseName}
-                                      fetchUrl={fetchUrl}
-                                      queryDocs={(params) => { return queryAllDocs(fetchUrl, params); }}/> : null}
-          {!isRedux && !hideFooter ? <ReactPagination.Footer /> : null}
+          {!hideFooter ? <PaginationContainer
+            databaseName={databaseName}
+            fetchUrl={fetchUrl}
+            queryDocs={queryDocs} /> : null}
         </div>
       </section>
     </div>
@@ -130,47 +133,50 @@ export const DocsTabsSidebarLayout = ({
   endpoint,
   dbName,
   dropDownLinks,
-  isRedux = false,
   fetchUrl,
-  ddocsOnly
+  ddocsOnly,
+  deleteEnabled = true,
+  selectedNavItem
 }) => {
-  let lowerContent;
-  if (isRedux) {
-    lowerContent = <IndexResultsContainer
-                      fetchUrl={fetchUrl}
-                      designDocs={designDocs}
-                      ddocsOnly={ddocsOnly}
-                      databaseName={dbName}
-                      fetchAtStartup={true}
-                      queryDocs={ (params) => { return queryAllDocs(fetchUrl, params); } }
-                      docType={Constants.INDEX_RESULTS_DOC_TYPE.VIEW} />;
-  } else {
-    lowerContent = <IndexResultsComponents.List designDocs={designDocs} />;
+  let queryDocs = (params) => { return queryAllDocs(fetchUrl, params); };
+  if (Helpers.isViewSelected(selectedNavItem)) {
+    queryDocs = (params) => { return queryMapReduceView(fetchUrl, params); };
   }
+  const lowerContent = <IndexResultsContainer
+    fetchUrl={fetchUrl}
+    designDocs={designDocs}
+    ddocsOnly={ddocsOnly}
+    databaseName={dbName}
+    fetchAtStartup={true}
+    queryDocs={queryDocs}
+    docType={Constants.INDEX_RESULTS_DOC_TYPE.VIEW}
+    deleteEnabled={deleteEnabled} />;
 
   return (
     <div id="dashboard" className="with-sidebar">
       <TabsSidebarHeader
         docURL={docURL}
         endpoint={endpoint}
+        endpointAddQueryOptions={true}
         dbName={dbName}
         dropDownLinks={dropDownLinks}
         database={database}
-        isRedux={isRedux}
         fetchUrl={fetchUrl}
         ddocsOnly={ddocsOnly}
+        queryDocs={queryDocs}
+        selectedNavItem={selectedNavItem}
       />
       <TabsSidebarContent
         lowerContent={lowerContent}
-        isRedux={isRedux}
         fetchUrl={fetchUrl}
         databaseName={dbName}
+        queryDocs={queryDocs}
       />
     </div>
   );
 };
 
-export const ChangesSidebarLayout = ({docURL, database, endpoint, dbName, dropDownLinks}) => {
+export const ChangesSidebarLayout = ({ docURL, database, endpoint, dbName, dropDownLinks }) => {
   return (
     <div id="dashboard" className="with-sidebar">
       <TabsSidebarHeader
@@ -179,17 +185,18 @@ export const ChangesSidebarLayout = ({docURL, database, endpoint, dbName, dropDo
         dbName={dbName}
         dropDownLinks={dropDownLinks}
         database={database}
+        hideQueryOptions={true}
       />
       <TabsSidebarContent
         upperContent={<Changes.ChangesTabContent />}
         lowerContent={<Changes.ChangesController />}
         hideFooter={true}
-        />
+      />
     </div>
   );
 };
 
-export const ViewsTabsSidebarLayout = ({showEditView, database, docURL, endpoint, dbName, dropDownLinks}) => {
+export const ViewsTabsSidebarLayout = ({ showEditView, database, docURL, endpoint, dbName, dropDownLinks }) => {
   const content = showEditView ? <IndexEditorComponents.EditorController /> : <DesignDocInfoComponents.DesignDocInfo />;
   return (
     <div id="dashboard" className="with-sidebar">
@@ -199,6 +206,9 @@ export const ViewsTabsSidebarLayout = ({showEditView, database, docURL, endpoint
         dbName={dbName}
         dropDownLinks={dropDownLinks}
         database={database}
+        queryDocs={() => { }}
+        hideQueryOptions={true}
+        hideJumpToDoc={true}
       />
       <TabsSidebarContent
         lowerContent={content}
diff --git a/app/addons/documents/mangolayout.js b/app/addons/documents/mangolayout.js
index 1cb7779..ef9d917 100644
--- a/app/addons/documents/mangolayout.js
+++ b/app/addons/documents/mangolayout.js
@@ -24,7 +24,7 @@ import FauxtonAPI from "../../core/api";
 import Constants from './constants';
 
 export const RightHeader = ({ docURL, endpoint }) => {
-  const apiBar = <ApiBarContainer docURL={docURL} endpoint={endpoint} />;
+  const apiBar = <ApiBarContainer docURL={docURL} endpoint={endpoint} includeQueryOptionsParams={false}/>;
   return (
     <div className="right-header-wrapper flex-layout flex-row flex-body">
       <div id="right-header" className="flex-body">
diff --git a/app/addons/documents/pagination/actions.js b/app/addons/documents/pagination/actions.js
deleted file mode 100644
index 695e913..0000000
--- a/app/addons/documents/pagination/actions.js
+++ /dev/null
@@ -1,123 +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 FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-import IndexResultsActions from "../index-results/actions";
-
-const updatePerPage = (perPage, collection, bulkCollection) => {
-
-  FauxtonAPI.dispatch({
-    type: ActionTypes.PER_PAGE_CHANGE,
-    perPage: perPage
-  });
-
-  IndexResultsActions.clearResults();
-  collection.fetch().then(function () {
-    IndexResultsActions.resultsListReset();
-    IndexResultsActions.sendMessageNewResultList({
-      collection: collection,
-      bulkCollection: bulkCollection
-    });
-  });
-};
-
-const setDocumentLimit = (docLimit) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.SET_PAGINATION_DOCUMENT_LIMIT,
-    docLimit: docLimit
-  });
-};
-
-const paginateNext = (collection, bulkCollection) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.PAGINATE_NEXT,
-  });
-
-  IndexResultsActions.clearResults();
-  collection.next().then(function () {
-    // update the cached offset for improved UX between layouts
-    setCachedOffset(collection.paging.params.skip);
-
-    IndexResultsActions.resultsListReset();
-
-    IndexResultsActions.sendMessageNewResultList({
-      collection: collection,
-      bulkCollection: bulkCollection
-    });
-  });
-};
-
-const paginatePrevious = (collection, bulkCollection) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.PAGINATE_PREVIOUS,
-  });
-
-  IndexResultsActions.clearResults();
-  collection.previous().then(function () {
-    // update the cached offset for improved UX between layouts
-    setCachedOffset(collection.paging.params.skip);
-
-    IndexResultsActions.resultsListReset();
-
-    IndexResultsActions.sendMessageNewResultList({
-      collection: collection,
-      bulkCollection: bulkCollection
-    });
-  });
-};
-
-const toggleTableViewType = () => {
-  IndexResultsActions.togglePrioritizedTableView();
-};
-
-const deleteCachedOffset = () => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.DELETE_CACHED_OFFSET
-  });
-};
-
-const setCachedOffset = (offset) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.SET_CACHED_OFFSET,
-    options: {
-      offset: offset
-    }
-  });
-};
-
-const setPageStart = (start) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.SET_PAGE_START,
-    options: {
-      start: start
-    }
-  });
-};
-
-const resetPagination = () => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.RESET_PAGINATION
-  });
-};
-
-export default {
-  updatePerPage,
-  setDocumentLimit,
-  paginateNext,
-  paginatePrevious,
-  toggleTableViewType,
-  deleteCachedOffset,
-  setCachedOffset,
-  setPageStart,
-  resetPagination
-};
diff --git a/app/addons/documents/pagination/actiontypes.js b/app/addons/documents/pagination/actiontypes.js
deleted file mode 100644
index d752dba..0000000
--- a/app/addons/documents/pagination/actiontypes.js
+++ /dev/null
@@ -1,23 +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.
-
-export default {
-  COLLECTION_CHANGED: 'COLLECTION_CHANGED',
-  PER_PAGE_CHANGE: 'PER_PAGE_CHANGE',
-  PAGINATE_NEXT: 'PAGINATE_NEXT',
-  PAGINATE_PREVIOUS: 'PAGINATE_PREVIOUS',
-  SET_PAGINATION_DOCUMENT_LIMIT: 'SET_PAGINATION_DOCUMENT_LIMIT',
-  SET_CACHED_OFFSET: 'SET_CACHED_OFFSET',
-  DELETE_CACHED_OFFSET: 'DELETE_CACHED_OFFSET',
-  SET_PAGE_START: 'SET_PAGE_START',
-  RESET_PAGINATION: 'RESET_PAGINATION'
-};
diff --git a/app/addons/documents/pagination/pagination.js b/app/addons/documents/pagination/pagination.js
deleted file mode 100644
index 8b1298e..0000000
--- a/app/addons/documents/pagination/pagination.js
+++ /dev/null
@@ -1,275 +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 React from "react";
-import Actions from "./actions";
-import IndexResultsStore from "../index-results/stores";
-var indexResultsStore = IndexResultsStore.indexResultsStore;
-
-var IndexPaginationController = React.createClass({
-
-  getStoreState: function () {
-    return {
-      canShowPrevious: indexResultsStore.canShowPrevious(),
-      canShowNext: indexResultsStore.canShowNext(),
-      collection: indexResultsStore.getCollection(),
-      bulkCollection: indexResultsStore.getBulkDocCollection(),
-    };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  componentDidMount: function () {
-    indexResultsStore.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    indexResultsStore.off('change', this.onChange);
-
-    // 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.
-    setTimeout(() => Actions.deleteCachedOffset());
-  },
-
-  onChange: function () {
-    this.setState(this.getStoreState());
-  },
-
-  nextClicked: function (event) {
-    event.preventDefault();
-    if (!this.state.canShowNext) { return; }
-
-    var collection = this.state.collection;
-    var bulkCollection = this.state.bulkCollection;
-    Actions.paginateNext(collection, bulkCollection);
-  },
-
-  previousClicked: function (event) {
-    event.preventDefault();
-    if (!this.state.canShowPrevious) { return; }
-
-    var collection = this.state.collection;
-    var bulkCollection = this.state.bulkCollection;
-    Actions.paginatePrevious(collection, bulkCollection);
-  },
-
-  render: function () {
-    var canShowPreviousClassName = '';
-    var canShowNextClassName = '';
-
-    if (!this.state.canShowPrevious) {
-      canShowPreviousClassName = 'disabled';
-    }
-
-    if (!this.state.canShowNext) {
-      canShowNextClassName = 'disabled';
-    }
-
-    return (
-      <div className="documents-pagination">
-        <ul className="pagination">
-          <li className={canShowPreviousClassName} >
-            <a id="previous" onClick={this.previousClicked} className="icon fonticon-left-open" href="#" data-bypass="true"></a>
-          </li>
-          <li className={canShowNextClassName} >
-            <a id="next" onClick={this.nextClicked} className="icon fonticon-right-open" href="#" data-bypass="true"></a>
-          </li>
-        </ul>
-      </div>
-    );
-  }
-
-});
-
-var PerPageSelector = React.createClass({
-
-  propTypes: {
-    perPage: React.PropTypes.number.isRequired,
-    perPageChange: React.PropTypes.func.isRequired,
-    label: React.PropTypes.string,
-    options: React.PropTypes.array
-  },
-
-  getDefaultProps: function () {
-    return {
-      label: 'Documents per page: ',
-      options: [5, 10, 20, 30, 50, 100]
-    };
-  },
-
-  perPageChange: function (e) {
-    var perPage = parseInt(e.target.value, 10);
-    this.props.perPageChange(perPage);
-  },
-
-  getOptions: function () {
-    return _.map(this.props.options, function (i) {
-      return (<option value={i} key={i}>{i}</option>);
-    });
-  },
-
-  render: function () {
-    return (
-      <div id="per-page">
-        <label htmlFor="select-per-page" className="drop-down inline">
-          {this.props.label} &nbsp;
-          <select id="select-per-page" onChange={this.perPageChange} value={this.props.perPage.toString()} className="input-small">
-            {this.getOptions()}
-          </select>
-        </label>
-      </div>
-    );
-  }
-
-});
-
-var AllDocsNumberController = React.createClass({
-
-  getStoreState: function () {
-    const isLoading = indexResultsStore.isLoading();
-    return {
-      hasResults: indexResultsStore.hasResults(),
-      totalRows: indexResultsStore.getTotalRows(),
-      pageStart: indexResultsStore.getPageStart(),
-      pageEnd: indexResultsStore.getPageEnd(),
-      perPage: indexResultsStore.getPerPage(),
-      prioritizedEnabled: indexResultsStore.getIsPrioritizedEnabled(),
-      showPrioritizedFieldToggler: indexResultsStore.getShowPrioritizedFieldToggler(),
-      displayedFields: isLoading ? {} : indexResultsStore.getResults().displayedFields,
-      collection: indexResultsStore.getCollection(),
-      bulkCollection: indexResultsStore.getBulkDocCollection(),
-    };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  componentDidMount: function () {
-    indexResultsStore.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    indexResultsStore.off('change', this.onChange);
-  },
-
-  onChange: function () {
-    this.setState(this.getStoreState());
-  },
-
-  getPageNumberText: function () {
-    if (this.state.totalRows === 0) {
-      return <span>Showing 0 documents.</span>;
-    }
-
-    return <span>Showing document {this.state.pageStart} - {this.state.pageEnd}.</span>;
-  },
-
-  perPageChange: function (perPage) {
-    var collection = this.state.collection;
-    var bulkCollection = this.state.bulkCollection;
-    Actions.updatePerPage(perPage, collection, bulkCollection);
-  },
-
-  render: function () {
-    const showTableControls = this.state.showPrioritizedFieldToggler;
-    const hasResults = this.state.hasResults;
-
-    return (
-      <div className="footer-controls">
-
-        <div className="page-controls">
-          {showTableControls && hasResults ?
-            <TableControls
-              prioritizedEnabled={this.state.prioritizedEnabled}
-              displayedFields={this.state.displayedFields} /> : null}
-        </div>
-
-        <PerPageSelector perPageChange={this.perPageChange} perPage={this.state.perPage} />
-        <div className="current-docs">
-          {this.getPageNumberText()}
-        </div>
-      </div>
-    );
-  }
-
-});
-
-var TableControls = React.createClass({
-
-  propTypes: {
-    prioritizedEnabled: React.PropTypes.bool.isRequired,
-    displayedFields: React.PropTypes.object.isRequired,
-  },
-
-  getAmountShownFields: function () {
-    var fields = this.props.displayedFields;
-
-    if (fields.shown === fields.allFieldCount) {
-      return (
-        <div className="pull-left shown-fields">
-          Showing {fields.shown} columns.
-        </div>
-      );
-    }
-
-    return (
-      <div className="pull-left shown-fields">
-        Showing {fields.shown} of {fields.allFieldCount} columns.
-      </div>
-    );
-  },
-
-  toggleTableViewType: function () {
-    Actions.toggleTableViewType();
-  },
-
-  render: function () {
-    return (
-      <div className="footer-table-control">
-        {this.getAmountShownFields()}
-        <div className="footer-doc-control-prioritized-wrapper pull-left">
-          <label htmlFor="footer-doc-control-prioritized">
-            <input
-              id="footer-doc-control-prioritized"
-              checked={this.props.prioritizedEnabled}
-              onChange={this.toggleTableViewType}
-              type="checkbox">
-            </input>
-            Show all columns.
-          </label>
-        </div>
-      </div>
-    );
-  }
-});
-
-var Footer = React.createClass({
-  render: function () {
-    return (
-      <footer className="index-pagination pagination-footer">
-        <IndexPaginationController />
-        <AllDocsNumberController />
-      </footer>
-    );
-  }
-});
-
-export default {
-  AllDocsNumber: AllDocsNumberController,
-  PerPageSelector: PerPageSelector,
-  Footer: Footer,
-  TableControls: TableControls,
-};
diff --git a/app/addons/documents/pagination/tests/pagination.componentSpec.js b/app/addons/documents/pagination/tests/pagination.componentSpec.js
deleted file mode 100644
index e807bde..0000000
--- a/app/addons/documents/pagination/tests/pagination.componentSpec.js
+++ /dev/null
@@ -1,121 +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 FauxtonAPI from "../../../../core/api";
-import Views from "../pagination";
-import utils from "../../../../../test/mocha/testUtils";
-import React from "react";
-import ReactDOM from "react-dom";
-import TestUtils from "react-addons-test-utils";
-import sinon from "sinon";
-
-FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-var assert = utils.assert;
-
-describe('All Docs Number', function () {
-
-  describe('PerPageSelector', function () {
-    var container, selectorEl, perPageChange;
-
-    beforeEach(function () {
-      perPageChange = sinon.spy();
-      container = document.createElement('div');
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(selectorEl).parentNode);
-    });
-
-    it('on new select calls callback with new page size', function () {
-      selectorEl = TestUtils.renderIntoDocument(
-        <Views.PerPageSelector
-          perPageChange={perPageChange}
-          perPage={10} />,
-        container
-      );
-      var selectEl = $(ReactDOM.findDOMNode(selectorEl)).find('#select-per-page')[0];
-      var perPage = 5;
-      TestUtils.Simulate.change(selectEl, {
-        target: {
-          value: perPage
-        }
-      });
-
-      assert.ok(perPageChange.calledWith(perPage));
-    });
-
-    it('applies custom label', function () {
-      var customLabel = 'alphabet soup';
-      selectorEl = TestUtils.renderIntoDocument(
-        <Views.PerPageSelector
-          label={customLabel}
-          perPageChange={perPageChange}
-          perPage={10} />,
-        container
-      );
-      var regexp = new RegExp(customLabel);
-      assert.ok(regexp.test(ReactDOM.findDOMNode(selectorEl).outerHTML));
-    });
-
-    it('applies custom options', function () {
-      selectorEl = TestUtils.renderIntoDocument(
-        <Views.PerPageSelector
-          options={[1, 2, 3]}
-          perPageChange={perPageChange}
-          perPage={10} />,
-        container
-      );
-      var options = $(ReactDOM.findDOMNode(selectorEl)).find('option');
-      assert.equal(options.length, 3);
-      assert.equal(options[0].innerHTML, "1");
-      assert.equal(options[1].innerHTML, "2");
-      assert.equal(options[2].innerHTML, "3");
-    });
-
-  });
-
-  describe('TableControls', function () {
-    var container, selectorEl;
-
-    beforeEach(function () {
-      container = document.createElement('div');
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(ReactDOM.findDOMNode(selectorEl).parentNode);
-    });
-
-    it('shows the amount of fields, none hidden', function () {
-
-      selectorEl = TestUtils.renderIntoDocument(
-        <Views.TableControls prioritizedEnabled={true} displayedFields={{shown: 7, allFieldCount: 7}} />,
-        container
-      );
-
-      var text = $(ReactDOM.findDOMNode(selectorEl)).find('.shown-fields').text();
-
-      assert.equal('Showing 7 columns.', text);
-    });
-
-    it('shows the amount of fields, some hidden', function () {
-
-      selectorEl = TestUtils.renderIntoDocument(
-        <Views.TableControls prioritizedEnabled={true} displayedFields={{shown: 5, allFieldCount: 7}} />,
-        container
-      );
-
-      var text = $(ReactDOM.findDOMNode(selectorEl)).find('.shown-fields').text();
-
-      assert.equal('Showing 5 of 7 columns.', text);
-    });
-  });
-});
diff --git a/app/addons/documents/queryoptions/actions.js b/app/addons/documents/queryoptions/actions.js
deleted file mode 100644
index c06da84..0000000
--- a/app/addons/documents/queryoptions/actions.js
+++ /dev/null
@@ -1,120 +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 app from "../../../app";
-import FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-
-export default {
-
-  toggleIncludeDocs: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_TOGGLE_INCLUDE_DOCS
-    });
-  },
-
-  toggleByKeys: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_TOGGLE_BY_KEYS
-    });
-  },
-
-  toggleBetweenKeys: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_TOGGLE_BETWEEN_KEYS
-    });
-  },
-
-  toggleDescending: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_TOGGLE_DESCENDING
-    });
-  },
-
-  toggleReduce: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_TOGGLE_REDUCE
-    });
-  },
-
-  updateBetweenKeys: function (betweenKeys) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_BETWEEN_KEYS,
-      betweenKeys: betweenKeys
-    });
-  },
-
-  updateByKeys: function (byKeys) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_BY_KEYS,
-      byKeys: byKeys
-    });
-  },
-
-  updateSkip: function (skip) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_SKIP,
-      skip: skip
-    });
-  },
-
-  updateLimit: function (limit) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_LIMIT,
-      limit: limit
-    });
-  },
-
-  runQuery: function (params) {
-    var url = app.utils.replaceQueryParams(params);
-    FauxtonAPI.navigate(url);
-  },
-
-  toggleQueryBarVisibility: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_VISIBILITY,
-      options: options
-    });
-  },
-
-  updateGroupLevel: function (groupLevel) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_UPDATE_GROUP_LEVEL,
-      groupLevel: groupLevel
-    });
-  },
-
-  reset: function (options) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_RESET,
-      params: options.queryParams
-    });
-
-    if (options.showReduce) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.QUERY_SHOW_REDUCE
-      });
-    }
-  },
-
-  showQueryOptions: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_SHOW
-    });
-  },
-
-  hideQueryOptions: function () {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.QUERY_HIDE
-    });
-  }
-};
diff --git a/app/addons/documents/queryoptions/actiontypes.js b/app/addons/documents/queryoptions/actiontypes.js
deleted file mode 100644
index 52e5295..0000000
--- a/app/addons/documents/queryoptions/actiontypes.js
+++ /dev/null
@@ -1,29 +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.
-
-export default {
-  QUERY_TOGGLE_INCLUDE_DOCS: 'QUERY_TOGGLE_INCLUDE_DOCS',
-  QUERY_TOGGLE_BY_KEYS: 'QUERY_TOGGLE_BY_KEYS',
-  QUERY_TOGGLE_BETWEEN_KEYS: 'QUERY_TOGGLE_BETWEEN_KEYS',
-  QUERY_UPDATE_BETWEEN_KEYS: 'QUERY_UPDATE_BETWEEN_KEYS',
-  QUERY_UPDATE_BY_KEYS: 'QUERY_UPDATE_BY_KEYS',
-  QUERY_TOGGLE_DESCENDING: 'QUERY_TOGGLE_DESCENDING',
-  QUERY_TOGGLE_REDUCE: 'QUERY_TOGGLE_REDUCE',
-  QUERY_UPDATE_SKIP: 'QUERY_UPDATE_SKIP',
-  QUERY_UPDATE_LIMIT: 'QUERY_UPDATE_LIMIT',
-  QUERY_RESET: 'QUERY_RESET',
-  QUERY_SHOW_REDUCE: 'QUERY_SHOW_REDUCE',
-  QUERY_UPDATE_GROUP_LEVEL: 'QUERY_UPDATE_GROUP_LEVEL',
-  QUERY_UPDATE_VISIBILITY: 'QUERY_UPDATE_VISIBILITY',
-  QUERY_SHOW: 'QUERY_SHOW',
-  QUERY_HIDE: 'QUERY_HIDE'
-};
diff --git a/app/addons/documents/queryoptions/queryoptions.js b/app/addons/documents/queryoptions/queryoptions.js
deleted file mode 100644
index 34e3fe9..0000000
--- a/app/addons/documents/queryoptions/queryoptions.js
+++ /dev/null
@@ -1,446 +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 FauxtonAPI from '../../../core/api';
-import React from 'react';
-import ReactDOM from 'react-dom';
-import QueryOptionsStores from './stores';
-import Actions from './actions';
-import PaginationActions from '../pagination/actions';
-import Components from '../../components/react-components';
-
-const { connectToStores, TrayWrapper, ToggleHeaderButton, TrayContents } = Components;
-
-const {queryOptionsStore: store} = QueryOptionsStores;
-
-var MainFieldsView = React.createClass({
-  propTypes: {
-    toggleIncludeDocs: React.PropTypes.func.isRequired,
-    includeDocs: React.PropTypes.bool.isRequired,
-    reduce: React.PropTypes.bool.isRequired,
-    toggleReduce: React.PropTypes.func,
-    updateGroupLevel: React.PropTypes.func,
-    docURL: React.PropTypes.string.isRequired
-  },
-
-  toggleIncludeDocs: function (e) {
-    this.props.toggleIncludeDocs(e);
-  },
-
-  groupLevelChange: function (e) {
-    this.props.updateGroupLevel(e.target.value);
-  },
-
-  groupLevel: function () {
-    if (!this.props.reduce) {
-      return null;
-    }
-
-    return (
-      <label className="drop-down inline" id="qoGroupLevelGroup">
-        Group Level
-        <select onChange={this.groupLevelChange} id="qoGroupLevel" value={this.props.groupLevel} name="group_level" className="input-small">
-          <option value="0">None</option>
-          <option value="1">1</option>
-          <option value="2">2</option>
-          <option value="3">3</option>
-          <option value="4">4</option>
-          <option value="5">5</option>
-          <option value="6">6</option>
-          <option value="7">7</option>
-          <option value="8">8</option>
-          <option value="9">9</option>
-          <option value="exact">Exact</option>
-        </select>
-      </label>
-    );
-  },
-
-  reduce: function () {
-    if (!this.props.showReduce) {
-      return null;
-    }
-
-    return (
-      <span>
-        <div className="checkbox inline">
-          <input id="qoReduce" name="reduce" onChange={this.props.toggleReduce} type="checkbox" checked={this.props.reduce} />
-          <label htmlFor="qoReduce">Reduce</label>
-        </div>
-        {this.groupLevel()}
-      </span>
-    );
-  },
-
-  render: function () {
-    var includeDocs = this.props.includeDocs;
-    return (
-      <div className="query-group" id="query-options-main-fields">
-        <span className="add-on">
-          Query Options
-          <a className="help-link" href={this.props.docURL} target="_blank" data-bypass="true">
-            <i className="icon-question-sign" />
-          </a>
-        </span>
-        <div className="controls-group qo-main-fields-row">
-          <div className="row-fluid fieldsets">
-            <div className="checkbox inline">
-              <input disabled={this.props.reduce} onChange={this.toggleIncludeDocs} id="qoIncludeDocs"
-                 name="include_docs" type="checkbox" checked={includeDocs} />
-              <label className={this.props.reduce ? 'disabled' : ''} htmlFor="qoIncludeDocs" id="qoIncludeDocsLabel">Include Docs</label>
-            </div>
-            {this.reduce()}
-          </div>
-        </div>
-      </div>
-    );
-  }
-
-});
-
-var KeySearchFields = React.createClass({
-  toggleByKeys: function () {
-    this.props.toggleByKeys();
-  },
-
-  toggleBetweenKeys: function () {
-    this.props.toggleBetweenKeys();
-  },
-
-  updateBetweenKeys: function () {
-    this.props.updateBetweenKeys({
-      startkey: ReactDOM.findDOMNode(this.refs.startkey).value,
-      endkey: ReactDOM.findDOMNode(this.refs.endkey).value,
-      include: this.props.betweenKeys.include
-    });
-  },
-
-  updateInclusiveEnd: function () {
-    this.props.updateBetweenKeys({
-      include: !this.props.betweenKeys.include,
-      startkey: this.props.betweenKeys.startkey,
-      endkey: this.props.betweenKeys.endkey
-    });
-  },
-
-  updateByKeys: function (e) {
-    this.props.updateByKeys(e.target.value);
-  },
-
-  render: function () {
-    var keysGroupClass = 'controls-group well js-query-keys-wrapper ';
-    var byKeysClass = 'row-fluid js-keys-section ';
-    var betweenKeysClass = byKeysClass;
-    var byKeysButtonClass = 'drop-down btn ';
-    var betweenKeysButtonClass = byKeysButtonClass;
-
-    if (!this.props.showByKeys && !this.props.showBetweenKeys) {
-      keysGroupClass += 'hide';
-    }
-
-    if (!this.props.showByKeys) {
-      byKeysClass += 'hide';
-    } else {
-      byKeysButtonClass += 'active';
-    }
-
-    if (!this.props.showBetweenKeys) {
-      betweenKeysClass += 'hide';
-    } else {
-      betweenKeysButtonClass += 'active';
-    }
-
-    return (
-      <div className="query-group" id="query-options-key-search">
-        <div className="add-on">Keys</div>
-        <div className="btn-group toggle-btns row-fluid">
-          <label style={{width: '101px'}} id="byKeys" onClick={this.toggleByKeys} className={byKeysButtonClass}>By Key(s)</label>
-          <label style={{width: '101px'}} id="betweenKeys" onClick={this.toggleBetweenKeys} className={betweenKeysButtonClass}>Between Keys</label>
-        </div>
-
-        <div className={keysGroupClass}>
-          <div className={byKeysClass} id="js-showKeys">
-            <div className="controls controls-row">
-              <label htmlFor="keys-input" className="drop-down">A key, or an array of keys.</label>
-              <textarea value={this.props.byKeys} onChange={this.updateByKeys} id="keys-input" className="input-xxlarge" rows="5" type="text"
-                placeholder='Enter either a single key ["123"] or an array of keys ["123", "456"]. A key value is the first parameter emitted in a map function. For example emit("123", 1) the key is "123".'></textarea>
-              <div id="keys-error" className="inline-block js-keys-error"></div>
-            </div>
-          </div>
-
-          <div className={betweenKeysClass} id="js-showStartEnd">
-            <div className="controls controls-row">
-              <div>
-                <label htmlFor="startkey" className="drop-down">Start key</label>
-                <input id="startkey" ref="startkey" type="text" onChange={this.updateBetweenKeys} value={this.props.betweenKeys.startkey} placeholder='e.g., "1234"' />
-              </div>
-              <div>
-                <label htmlFor="endkey" className="drop-down">End key</label>
-                <input id="endkey" ref="endkey" onChange={this.updateBetweenKeys} value={this.props.betweenKeys.endkey} type="text" placeholder='e.g., "1234"'/>
-                <div className="controls include-end-key-row checkbox controls-row inline">
-                  <input id="qoIncludeEndKeyInResults" ref="inclusive_end" type="checkbox" onChange={this.updateInclusiveEnd} checked={this.props.betweenKeys.include}/>
-                  <label htmlFor="qoIncludeEndKeyInResults">Include End Key in results</label>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-
-      </div>
-    );
-  }
-});
-
-var AdditionalParams = React.createClass({
-  updateSkip: function (e) {
-    e.preventDefault();
-    var val = e.target.value;
-
-    //check skip is only numbers
-    if (!/^\d*$/.test(val)) {
-      FauxtonAPI.addNotification({
-        msg: 'Skip can only be a number',
-        type: 'error'
-      });
-      val = this.props.skip;
-    }
-
-    this.props.updateSkip(val);
-  },
-
-  updateLimit: function (e) {
-    e.preventDefault();
-    this.props.updateLimit(e.target.value);
-  },
-
-  render: function () {
-    return (
-      <div className="query-group" id="query-options-additional-params">
-        <div className="add-on additionalParams">Additional Parameters</div>
-        <div className="row-fluid fieldsets">
-          <div className="dropdown inline">
-            <label className="drop-down">
-              Limit
-              <select id="qoLimit" onChange={this.updateLimit} name="limit" value={this.props.limit} className="input-small">
-                <option value="none">None</option>
-                <option value={5}>5</option>
-                <option value={10}>10</option>
-                <option value={20}>20</option>
-                <option value={30}>30</option>
-                <option value={50}>50</option>
-                <option value={100}>100</option>
-                <option value={500}>500</option>
-              </select>
-            </label>
-          </div>
-        </div>
-        <div className="row-fluid fieldsets">
-          <div className="checkbox inline">
-            <input id="qoDescending" type="checkbox" onChange={this.props.toggleDescending} checked={this.props.descending} />
-            <label htmlFor="qoDescending">Descending</label>
-          </div>
-          <div className="dropdown inline">
-            <label htmlFor="qoSkip" className="drop-down">
-              Skip
-              <input value={this.props.skip} onChange={this.updateSkip} className="input-small" type="text" id="qoSkip" placeholder="# of rows" />
-            </label>
-          </div>
-        </div>
-      </div>
-    );
-  }
-});
-
-var QueryButtons = React.createClass({
-  propTypes: {
-    onCancel: React.PropTypes.func.isRequired
-  },
-
-  hideTray: function () {
-    this.props.onCancel();
-  },
-
-  render: function () {
-    return (
-      <div className="controls-group query-group">
-        <div id="button-options" className="controls controls-row">
-          <button type="submit" className="btn btn-secondary">Run Query</button>
-          <a onClick={this.hideTray} className="btn btn-cancelDark">Cancel</a>
-        </div>
-      </div>
-    );
-  }
-});
-
-var QueryOptionsController = React.createClass({
-  getStoreState () {
-    return {
-      isVisible: store.isVisible()
-    };
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
-
-  onChange () {
-    this.setState(this.getStoreState());
-  },
-
-  componentDidMount: function () {
-    store.on('change', this.onChange, this);
-  },
-
-  componentWillUnmount: function () {
-    store.off('change', this.onChange);
-  },
-
-  getWrap: function () {
-    if (!this.TrayWrapper) {
-      this.TrayWrapper = connectToStores(TrayWrapper, [store], function () {
-
-        return {
-          includeDocs: store.includeDocs(),
-          showBetweenKeys: store.showBetweenKeys(),
-          showByKeys: store.showByKeys(),
-          betweenKeys: store.betweenKeys(),
-          byKeys: store.byKeys(),
-          descending: store.descending(),
-          skip: store.skip(),
-          limit: store.limit(),
-          showReduce: store.showReduce(),
-          reduce: store.reduce(),
-          groupLevel: store.groupLevel(),
-          contentVisible: store.getTrayVisible(),
-          queryParams: store.getQueryParams()
-        };
-      });
-    }
-
-    return this.TrayWrapper;
-  },
-
-  render: function () {
-    if (!this.state.isVisible) { return null;}
-    const TrayWrapper = this.getWrap();
-    return (
-      <div id="header-query-options">
-        <div id="query-options">
-          <TrayWrapper>
-            <QueryTray contentVisible={false} />
-          </TrayWrapper>
-        </div>
-      </div>
-    );
-  }
-});
-
-var QueryTray = React.createClass({
-
-  propTypes: {
-    contentVisible: React.PropTypes.bool.isRequired
-  },
-
-  runQuery: function (e) {
-    e.preventDefault();
-
-    // we're going to have a fresh collection, purge the cached offset!
-    PaginationActions.deleteCachedOffset();
-    Actions.runQuery(this.props.queryParams);
-    this.toggleTrayVisibility();
-  },
-
-  toggleTrayVisibility: function () {
-    Actions.toggleQueryBarVisibility(!this.props.contentVisible);
-  },
-
-  closeTray: function () {
-    Actions.toggleQueryBarVisibility(false);
-  },
-
-  toggleIncludeDocs: function () {
-    Actions.toggleIncludeDocs();
-  },
-
-  toggleReduce: function () {
-    if (this.props.includeDocs) {
-      this.toggleIncludeDocs();
-    }
-    Actions.toggleReduce();
-  },
-
-  getTray: function () {
-    return (
-      <TrayContents closeTray={this.closeTray} contentVisible={this.props.contentVisible}
-        className="query-options"
-        id="query-options-tray">
-
-        <form onSubmit={this.runQuery} className="js-view-query-update custom-inputs">
-          <MainFieldsView
-            includeDocs={this.props.includeDocs}
-            toggleIncludeDocs={this.toggleIncludeDocs}
-            showReduce={this.props.showReduce}
-            reduce={this.props.reduce}
-            toggleReduce={this.toggleReduce}
-            groupLevel={this.props.groupLevel}
-            updateGroupLevel={Actions.updateGroupLevel}
-            docURL={FauxtonAPI.constants.DOC_URLS.GENERAL} />
-          <KeySearchFields
-            key={1}
-            showByKeys={this.props.showByKeys}
-            showBetweenKeys={this.props.showBetweenKeys}
-            toggleByKeys={Actions.toggleByKeys}
-            toggleBetweenKeys={Actions.toggleBetweenKeys}
-            betweenKeys={this.props.betweenKeys}
-            updateBetweenKeys={Actions.updateBetweenKeys}
-            byKeys={this.props.byKeys}
-            updateByKeys={Actions.updateByKeys} />
-          <AdditionalParams
-            descending={this.props.descending}
-            toggleDescending={Actions.toggleDescending}
-            skip={this.props.skip}
-            updateSkip={Actions.updateSkip}
-            updateLimit={Actions.updateLimit}
-            limit={this.props.limit} />
-          <QueryButtons onCancel={this.closeTray} />
-        </form>
-      </TrayContents>
-    );
-
-  },
-
-  render: function () {
-    return (
-      <div>
-        <ToggleHeaderButton
-          toggleCallback={this.toggleTrayVisibility}
-          containerClasses="header-control-box control-toggle-queryoptions"
-          title="Query Options"
-          fonticon="fonticon-gears"
-          text="Options" />
-          {this.getTray()}
-      </div>
-    );
-  }
-
-});
-
-export default {
-  QueryOptionsController,
-  QueryButtons,
-  MainFieldsView,
-  KeySearchFields,
-  AdditionalParams,
-  render: function (el) {
-    ReactDOM.render(<QueryOptionsController />, $(el)[0]);
-  }
-};
diff --git a/app/addons/documents/queryoptions/stores.js b/app/addons/documents/queryoptions/stores.js
deleted file mode 100644
index e56d058..0000000
--- a/app/addons/documents/queryoptions/stores.js
+++ /dev/null
@@ -1,317 +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 FauxtonAPI from '../../../core/api';
-import ActionTypes from './actiontypes';
-const Stores = {};
-
-Stores.QueryOptionsStore = FauxtonAPI.Store.extend({
-
-  initialize () {
-    this._trayVisible = false;
-    this.reset();
-  },
-
-  reset () {
-    this._isVisible = true;
-    this._loading = true;
-    this._showByKeys = false;
-    this._showBetweenKeys = false;
-    this._includeDocs = false;
-    this._betweenKeys = {
-      include: true
-    };
-    this._byKeys = '';
-    this._descending = false;
-    this._skip = '';
-    this._limit = "none";
-    this._reduce = false;
-    this._groupLevel = 'exact';
-
-    this._showReduce = false;
-  },
-
-  isLoading () {
-    return this._loading;
-  },
-
-  isVisible () {
-    return this._isVisible;
-  },
-
-  hideQueryOptions () {
-    this._isVisible = false;
-  },
-
-  showQueryOptions () {
-    this._isVisible = true;
-  },
-
-  setTrayVisible (trayVisible) {
-    this._trayVisible = trayVisible;
-  },
-
-  getTrayVisible () {
-    return this._trayVisible;
-  },
-
-  showReduce () {
-    return this._showReduce;
-  },
-
-  reduce () {
-    return this._reduce;
-  },
-
-  betweenKeys () {
-    return this._betweenKeys;
-  },
-
-  updateBetweenKeys (newBetweenKeys) {
-    this._betweenKeys = newBetweenKeys;
-  },
-
-  updateSkip (skip) {
-    this._skip = skip;
-  },
-
-  skip () {
-    return this._skip;
-  },
-
-  limit () {
-    return this._limit;
-  },
-
-  updateLimit (limit) {
-    this._limit = limit;
-  },
-
-  byKeys () {
-    return this._byKeys;
-  },
-
-  updateByKeys (keys) {
-    this._byKeys = keys;
-  },
-
-  includeDocs () {
-    return this._includeDocs;
-  },
-
-  descending () {
-    return this._descending;
-  },
-
-  groupLevel () {
-    return this._groupLevel;
-  },
-
-  toggleByKeys () {
-    this._showByKeys = !this._showByKeys;
-
-    if (this._showByKeys) {
-      this._showBetweenKeys = false;
-    }
-  },
-
-  toggleBetweenKeys () {
-    this._showBetweenKeys = !this._showBetweenKeys;
-
-    if (this._showBetweenKeys) {
-      this._showByKeys = false;
-    }
-  },
-
-  showByKeys () {
-    return this._showByKeys;
-  },
-
-  showBetweenKeys () {
-    return this._showBetweenKeys;
-  },
-
-  updateGroupLevel (groupLevel) {
-    this._groupLevel = groupLevel;
-  },
-
-  sanitize (params) {
-    if (params.startkey) {
-      params.start_key = params.startkey;
-      delete params.startkey;
-    }
-
-    if (params.endkey) {
-      params.end_key = params.endkey;
-      delete params.endkey;
-    }
-
-  },
-
-  setQueryParams (params) {
-    this.reset();
-    this.sanitize(params);
-    if (params.include_docs) {
-      this._includeDocs = true;
-    }
-
-    if (params.start_key || params.end_key) {
-      let include = true;
-
-      if (params.inclusive_end) {
-        include = params.inclusive_end === 'true';
-      }
-      this._betweenKeys = { include: include };
-      if (params.start_key) {
-        this._betweenKeys.startkey = params.start_key;
-      }
-      if (params.end_key) {
-        this._betweenKeys.endkey = params.end_key;
-      }
-      this._showBetweenKeys = true;
-
-    } else if (params.keys) {
-      this._byKeys = params.keys;
-      this._showByKeys = true;
-    }
-
-    if (params.limit && params.limit !== 'none') {
-      this._limit = params.limit;
-    }
-
-    if (params.skip) {
-      this._skip = params.skip;
-    }
-
-    if (params.descending) {
-      this._descending = params.descending;
-    }
-
-    if (params.reduce) {
-      if (params.group) {
-        this._groupLevel = 'exact';
-      } else {
-        this._groupLevel = params.group_level;
-      }
-      this._reduce = true;
-    }
-  },
-
-  getQueryParams () {
-    const params = {};
-
-    if (this._includeDocs) {
-      params.include_docs = this._includeDocs;
-    }
-
-    if (this._showBetweenKeys) {
-      const betweenKeys = this._betweenKeys;
-      params.inclusive_end = betweenKeys.include;
-      if (betweenKeys.startkey && betweenKeys.startkey !== '') {
-        params.start_key = betweenKeys.startkey;
-      }
-      if (betweenKeys.endkey && betweenKeys.endkey !== '') {
-        params.end_key = betweenKeys.endkey;
-      }
-    } else if (this._showByKeys) {
-      params.keys = this._byKeys.replace(/\r?\n/g, '');
-    }
-
-    if (this._limit !== 'none') {
-      params.limit = parseInt(this._limit, 10);
-    }
-
-    if (this._skip) {
-      params.skip = parseInt(this._skip, 10);
-    }
-
-    if (this._descending) {
-      params.descending = this._descending;
-    }
-
-    if (this._reduce) {
-      params.reduce = true;
-
-      if (this._groupLevel === 'exact') {
-        params.group = true;
-      } else {
-        params.group_level = this._groupLevel;
-      }
-    }
-
-    return params;
-  },
-
-  getIncludeDocsEnabled () {
-    return this._includeDocs;
-  },
-
-  dispatch (action) {
-    switch (action.type) {
-      case ActionTypes.QUERY_RESET:
-        this.setQueryParams(action.params);
-      break;
-      case ActionTypes.QUERY_TOGGLE_INCLUDE_DOCS:
-        this._includeDocs = !this._includeDocs;
-      break;
-      case ActionTypes.QUERY_TOGGLE_DESCENDING:
-        this._descending = !this._descending;
-      break;
-      case ActionTypes.QUERY_TOGGLE_BY_KEYS:
-        this.toggleByKeys();
-      break;
-      case ActionTypes.QUERY_TOGGLE_BETWEEN_KEYS:
-        this.toggleBetweenKeys();
-      break;
-      case ActionTypes.QUERY_UPDATE_BETWEEN_KEYS:
-        this.updateBetweenKeys(action.betweenKeys);
-      break;
-      case ActionTypes.QUERY_UPDATE_BY_KEYS:
-        this.updateByKeys(action.byKeys);
-      break;
-      case ActionTypes.QUERY_UPDATE_SKIP:
-        this.updateSkip(action.skip);
-      break;
-      case ActionTypes.QUERY_UPDATE_LIMIT:
-        this.updateLimit(action.limit);
-      break;
-      case ActionTypes.QUERY_SHOW_REDUCE:
-        this._showReduce = true;
-      break;
-      case ActionTypes.QUERY_TOGGLE_REDUCE:
-        this._reduce = !this._reduce;
-      break;
-      case ActionTypes.QUERY_UPDATE_GROUP_LEVEL:
-        this.updateGroupLevel(action.groupLevel);
-      break;
-      case ActionTypes.QUERY_UPDATE_VISIBILITY:
-        this.setTrayVisible(action.options);
-      break;
-      case ActionTypes.QUERY_HIDE:
-        this.hideQueryOptions();
-      break;
-      case ActionTypes.QUERY_SHOW:
-        this.showQueryOptions();
-      break;
-      default:
-      return;
-      // do nothing
-    }
-    this.triggerChange();
-
-  }
-});
-
-Stores.queryOptionsStore = new Stores.QueryOptionsStore();
-Stores.queryOptionsStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.queryOptionsStore.dispatch);
-
-export default Stores;
diff --git a/app/addons/documents/queryoptions/tests/queryoptions.componentsSpec.js b/app/addons/documents/queryoptions/tests/queryoptions.componentsSpec.js
deleted file mode 100644
index afcc851..0000000
--- a/app/addons/documents/queryoptions/tests/queryoptions.componentsSpec.js
+++ /dev/null
@@ -1,190 +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 FauxtonAPI from "../../../../core/api";
-import Views from "../queryoptions";
-import utils from "../../../../../test/mocha/testUtils";
-import React from "react";
-import ReactDOM from "react-dom";
-import TestUtils from "react-addons-test-utils";
-import sinon from "sinon";
-FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-var assert = utils.assert;
-var restore = utils.restore;
-
-describe('Query Options', function () {
-  var container;
-
-  beforeEach(function () {
-    container = document.createElement('div');
-  });
-
-  afterEach(function () {
-    ReactDOM.unmountComponentAtNode(container);
-  });
-
-  describe('MainFieldsView', function () {
-    var mainFieldsEl;
-
-    it('returns null no reduce', function () {
-      mainFieldsEl = TestUtils.renderIntoDocument(<Views.MainFieldsView reduce={false} includeDocs={false} showReduce={false}/>, container);
-      assert.ok(_.isNull(mainFieldsEl.reduce()));
-    });
-
-    it('shows reduce and group level', function () {
-      mainFieldsEl = TestUtils.renderIntoDocument(<Views.MainFieldsView reduce={true} includeDocs={false} showReduce={true}/>, container);
-      assert.ok(!_.isNull(mainFieldsEl.reduce()));
-      assert.ok(!_.isNull(mainFieldsEl.groupLevel()));
-    });
-
-    it('updates group level', function () {
-      var spy = sinon.spy();
-      mainFieldsEl = TestUtils.renderIntoDocument(<Views.MainFieldsView updateGroupLevel={spy} reduce={true} includeDocs={false} showReduce={true}/>, container);
-      var el = $(ReactDOM.findDOMNode(mainFieldsEl)).find('#qoGroupLevel')[0];
-      TestUtils.Simulate.change(el, {target: {value: 'exact'}});
-
-      assert.ok(spy.calledOnce);
-    });
-
-    it('toggles include docs on change', function () {
-      var spy = sinon.spy();
-      mainFieldsEl = TestUtils.renderIntoDocument(<Views.MainFieldsView toggleIncludeDocs={spy} reduce={false} includeDocs={false} showReduce={false}/>, container);
-      var el = $(ReactDOM.findDOMNode(mainFieldsEl)).find('#qoIncludeDocs')[0];
-      TestUtils.Simulate.change(el);
-
-      assert.ok(spy.calledOnce);
-    });
-
-    it('uses overridden URL prop if defined', function () {
-      var customDocURL = 'http://whatever.com';
-      mainFieldsEl = TestUtils.renderIntoDocument(
-        <Views.MainFieldsView reduce={false} includeDocs={false} showReduce={false} docURL={customDocURL} />,
-        container);
-      assert.equal($(ReactDOM.findDOMNode(mainFieldsEl)).find('.help-link').attr('href'), customDocURL);
-    });
-
-  });
-
-  describe('KeySearchFields', function () {
-
-    it('toggles keys', function () {
-      var spy = sinon.spy();
-      var keysEl = TestUtils.renderIntoDocument(<Views.KeySearchFields
-        showByKeys={false}
-        showBetweenKeys={false}
-        betweenKeys={{}}
-        toggleByKeys={spy}
-        />, container);
-
-      var el = $(ReactDOM.findDOMNode(keysEl)).find('#byKeys')[0];
-      TestUtils.Simulate.click(el);
-      assert.ok(spy.calledOnce);
-    });
-
-    it('toggles between keys', function () {
-      var spy = sinon.spy();
-      var keysEl = TestUtils.renderIntoDocument(<Views.KeySearchFields
-        showByKeys={false}
-        showBetweenKeys={false}
-        toggleBetweenKeys={spy}
-        betweenKeys={{}}
-        />, container);
-
-      var el = $(ReactDOM.findDOMNode(keysEl)).find('#betweenKeys')[0];
-      TestUtils.Simulate.click(el);
-      assert.ok(spy.calledOnce);
-    });
-
-    it('updates byKeys', function () {
-      var spy = sinon.spy();
-      var keysEl = TestUtils.renderIntoDocument(<Views.KeySearchFields
-        showByKeys={false}
-        showBetweenKeys={false}
-        updateByKeys={spy}
-        betweenKeys={{}}
-        />, container);
-
-      var el = $(ReactDOM.findDOMNode(keysEl)).find('#keys-input')[0];
-      TestUtils.Simulate.change(el, {target: {value: 'boom'}});
-      assert.ok(spy.calledWith('boom'));
-    });
-
-    it('updates betweenKeys', function () {
-      var spy = sinon.spy();
-      var betweenKeys = {
-        startkey: '',
-        endkey: '',
-        inclusive_end: true
-      };
-      var keysEl = TestUtils.renderIntoDocument(<Views.KeySearchFields
-        showByKeys={false}
-        showBetweenKeys={false}
-        updateBetweenKeys={spy}
-        betweenKeys={betweenKeys}
-        />, container);
-
-      var el = $(ReactDOM.findDOMNode(keysEl)).find('#endkey')[0];
-      TestUtils.Simulate.change(el, {target: {value: 'boom'}});
-      assert.ok(spy.calledOnce);
-    });
-  });
-
-  describe('AdditionalParams', function () {
-    afterEach(function () {
-      restore(FauxtonAPI.addNotification);
-    });
-
-    it('only updates skip with numbers', function () {
-      var paramsEl = TestUtils.renderIntoDocument(<Views.AdditionalParams
-        updateSkip={function () {}}
-         />, container);
-
-      var spy = sinon.spy(FauxtonAPI, 'addNotification');
-      paramsEl.updateSkip({target: {value: 'b'}, preventDefault: function () {}});
-
-      assert.ok(spy.calledOnce);
-    });
-
-    it('updates skip if a number', function () {
-      var val = 0;
-      var paramsEl = TestUtils.renderIntoDocument(<Views.AdditionalParams
-        updateSkip={function (a) {
-          val = a;
-        }}
-         />, container);
-
-      paramsEl.updateSkip({target: {value: '3'}, preventDefault: function () {}});
-      assert.equal(val, '3');
-    });
-  });
-
-});
-
-describe('QueryButtons', function () {
-  var container;
-
-  beforeEach(function () {
-    container = document.createElement('div');
-  });
-
-  afterEach(function () {
-    ReactDOM.unmountComponentAtNode(container);
-  });
-
-  describe('cancel event fires', function () {
-    var spy = sinon.spy();
-    var component = TestUtils.renderIntoDocument(<Views.QueryButtons onCancel={spy} />, container);
-    TestUtils.Simulate.click($(ReactDOM.findDOMNode(component)).find('a')[0]);
-    assert.ok(spy.calledOnce);
-  });
-
-});
diff --git a/app/addons/documents/queryoptions/tests/queryoptions.storesSpec.js b/app/addons/documents/queryoptions/tests/queryoptions.storesSpec.js
deleted file mode 100644
index cb9de3c..0000000
--- a/app/addons/documents/queryoptions/tests/queryoptions.storesSpec.js
+++ /dev/null
@@ -1,139 +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 FauxtonAPI from "../../../../core/api";
-import Stores from "../stores";
-import testUtils from "../../../../../test/mocha/testUtils";
-var assert = testUtils.assert;
-var dispatchToken;
-var store;
-
-describe('QueryOptions Store', () => {
-  beforeEach(() => {
-    store = new Stores.QueryOptionsStore();
-    dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
-  });
-
-  afterEach(() => {
-    FauxtonAPI.dispatcher.unregister(dispatchToken);
-  });
-
-  describe('Toggle By Keys and Between Keys', () => {
-
-    it('toggling by keys sets by keys to true', () => {
-
-      store.toggleByKeys();
-
-      assert.ok(store.showByKeys());
-    });
-
-    it('toggling between keys sets between keys to true', () => {
-
-      store.toggleBetweenKeys();
-      assert.ok(store.showBetweenKeys());
-    });
-
-    it('toggling between keys sets by keys to false', () => {
-      store._showByKeys = true;
-      store.toggleBetweenKeys();
-      assert.notOk(store.showByKeys());
-    });
-
-    it('toggling by keys sets between keys to false', () => {
-      store._showBetweenKeys = true;
-      store.toggleByKeys();
-      assert.notOk(store.showBetweenKeys());
-    });
-
-  });
-
-  describe('getQueryParams', () => {
-    it('returns params for default', () => {
-      assert.deepEqual(store.getQueryParams(), {});
-    });
-
-    it('with betweenKeys', () => {
-      store.toggleBetweenKeys();
-      store.updateBetweenKeys({
-        startkey:"a",
-        endkey: "z",
-        include: true
-      });
-
-      assert.deepEqual(store.getQueryParams(), {
-        inclusive_end: true,
-        start_key: 'a',
-        end_key: 'z'
-      });
-    });
-
-    it('with byKeys', () => {
-      store.toggleByKeys();
-      store.updateByKeys("[1,2,3]");
-
-      assert.deepEqual(store.getQueryParams(), {
-        keys: "[1,2,3]"
-      });
-    });
-  });
-
-  describe('setQueryParams', () => {
-
-    it('sets all store values from given params', () => {
-
-      store.setQueryParams({
-        include_docs: true,
-        limit: 10,
-        skip: 5,
-        descending: true
-      });
-
-      assert.ok(store.includeDocs());
-      assert.ok(store.descending());
-      assert.equal(store.limit(), 10);
-      assert.equal(store.skip(), 5);
-    });
-
-    it('sets between keys', () => {
-      store.setQueryParams({
-        start_key: 1,
-        end_key: 5
-      });
-
-      assert.equal(store.betweenKeys().startkey, 1);
-      assert.equal(store.betweenKeys().endkey, 5);
-      assert.ok(store.betweenKeys().include);
-      assert.ok(store.showBetweenKeys());
-    });
-
-    it('sets by keys', () => {
-      store.setQueryParams({
-        keys: [1, 2, 3]
-      });
-
-      assert.deepEqual(store.byKeys(), [1, 2, 3]);
-      assert.ok(store.showByKeys());
-    });
-
-    it('works with startkey and endkey', () => {
-      store.setQueryParams({
-        startkey: 1,
-        endkey: 5
-      });
-
-      assert.equal(store.betweenKeys().startkey, 1);
-      assert.equal(store.betweenKeys().endkey, 5);
-      assert.ok(store.showBetweenKeys());
-    });
-
-  });
-});
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index 8a19d09..15a394a 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -13,9 +13,6 @@
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
 import Documents from "./shared-resources";
-import PagingCollection from "../../../assets/js/plugins/cloudant.pagingcollection";
-import Constants from './constants';
-
 
 Documents.UUID = FauxtonAPI.Model.extend({
   initialize: function (options) {
@@ -86,258 +83,6 @@ Documents.DdocInfo = FauxtonAPI.Model.extend({
   }
 });
 
-Documents.MangoIndex = Documents.Doc.extend({
-  idAttribute: 'ddoc',
-
-  getId: function () {
-
-    if (this.id) {
-      return this.id;
-    }
-
-
-    return '_all_docs';
-  },
-
-  isNew: function () {
-    // never use put
-    return true;
-  },
-
-  // @deprecated, see isJSONDocBulkDeletable
-  isDeletable: function () {
-    return this.get('type') !== 'special';
-  },
-
-  // @deprecated, see isJSONDocBulkDeletable
-  isBulkDeletable: function () {
-    return this.isDeletable();
-  },
-
-  isFromView: function () {
-    return false;
-  },
-
-  url: function () {
-    var database = this.database.safeID();
-
-    return FauxtonAPI.urls('mango', 'index-server', database);
-  }
-});
-
-Documents.MangoIndexCollection = PagingCollection.extend({
-  model: Documents.MangoIndex,
-  initialize: function (_attr, options) {
-    var defaultLimit = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-
-    this.database = options.database;
-    this.params = _.extend({limit: defaultLimit}, options.params);
-  },
-
-  collectionType: Constants.INDEX_RESULTS_DOC_TYPE.MANGO_INDEX,
-
-  url: function () {
-    return this.urlRef.apply(this, arguments);
-  },
-
-  updateSeq: function () {
-    return false;
-  },
-
-  //@deprecated, see isJSONDocEditable
-  isEditable: function () {
-    return false;
-  },
-
-  parse: function (res) {
-    return res.indexes;
-  },
-
-  urlRef: function (context) {
-    var database = this.database.safeID(),
-        query = '';
-
-    if (!context) {
-      context = 'index-server';
-    }
-
-    return FauxtonAPI.urls('mango', context, database, query);
-  }
-});
-
-// MANGO INDEX EDITOR
-Documents.MangoDoc = Documents.Doc.extend({
-  isMangoDoc: function () {
-    return true;
-  }
-});
-
-Documents.MangoDocumentCollection = PagingCollection.extend({
-  model: Documents.MangoDoc,
-
-  collectionType: 'MangoDocumentCollection',
-
-  initialize: function (_attr, options) {
-    var defaultLimit = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-
-    this._warning = null;
-    this.database = options.database;
-    this.params = _.extend({limit: defaultLimit}, options.params);
-
-    this.paging = _.defaults((options.paging || {}), {
-      defaultParams: _.defaults({}, options.params),
-      hasNext: false,
-      hasPrevious: false,
-      params: {},
-      pageSize: FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE,
-      direction: undefined
-    });
-
-    this.paging.params = _.clone(this.paging.defaultParams);
-  },
-
-  url: function () {
-    return this.urlRef.apply(this, arguments);
-  },
-
-  warning: function () {
-    return this._warning;
-  },
-
-  updateSeq: function () {
-    return false;
-  },
-
-  isEditable: function () {
-    return true;
-  },
-
-  setQuery: function (query) {
-    this.query = query;
-    return this;
-  },
-
-  pageSizeReset: function (pageSize, opts) {
-    var options = _.defaults((opts || {}), {fetch: true});
-    this.paging.direction = undefined;
-    this.paging.pageSize = pageSize;
-    this.paging.params = this.paging.defaultParams;
-    this.paging.params.limit = pageSize;
-
-    if (options.fetch) {
-      return this.fetch();
-    }
-  },
-
-  _iterate: function (offset) {
-    this.paging.params = this.calculateParams(this.paging.params, offset, this.paging.pageSize);
-
-    return this.fetch();
-  },
-
-  getPaginatedQuery: function () {
-    if (!this.query) {
-      return this.query;
-    }
-
-    var paginatedQuery = JSON.parse(JSON.stringify(this.query));
-
-    if (!this.paging.direction && this.paging.params.limit > 0) {
-      this.paging.direction = 'fetch';
-      this.paging.params.limit = this.paging.params.limit + 1;
-    }
-
-    // just update if NOT provided by editor
-    if (!paginatedQuery.limit) {
-      paginatedQuery.limit = this.paging.params.limit;
-    }
-
-    if (!paginatedQuery.skip) {
-      paginatedQuery.skip = this.paging.params.skip;
-    }
-
-    return paginatedQuery;
-  },
-
-  fetch: function () {
-    var url = this.urlRef(),
-        promise = FauxtonAPI.Deferred(),
-        query = this.getPaginatedQuery();
-
-    //this section can get called when updating page
-    //and the query options might not have been selected yet
-    //so we just return and don't do a fetch
-    if (!query) {
-      promise.resolve();
-      return promise;
-    }
-
-    $.ajax({
-      type: 'POST',
-      url: url,
-      contentType: 'application/json',
-      dataType: 'json',
-      data: JSON.stringify(query),
-    })
-    .then(res => {
-      this.handleResponse(res, promise);
-    }, res => {
-      promise.reject(res.responseJSON);
-    });
-
-    return promise;
-  },
-
-  parse: function (resp) {
-    var rows = [];
-
-    rows = resp.docs;
-
-    this._warning = resp.warning;
-
-    this.viewMeta = {
-      total_rows: resp.total_rows,
-      offset: resp.offset,
-      update_seq: resp.update_seq
-    };
-
-    this.paging.hasNext = this.paging.hasPrevious = false;
-
-    if (this.paging.params.skip > 0) {
-      this.paging.hasPrevious = true;
-    }
-
-    if (rows.length === this.paging.pageSize + 1) {
-      this.paging.hasNext = true;
-
-      // remove the next page marker result
-      rows.pop();
-      this.viewMeta.total_rows = this.viewMeta.total_rows - 1;
-    }
-
-    return rows;
-  },
-
-  handleResponse: function (res, promise) {
-    var models = this.parse(res);
-
-    this.reset(models);
-
-    promise.resolve();
-  },
-
-  urlRef: function (context) {
-    var database = this.database.safeID(),
-        query = '';
-
-    if (!context) {
-      context = 'query-server';
-    }
-
-    return FauxtonAPI.urls('mango', context, database, query);
-  }
-});
-
 Documents.NewDoc = Documents.Doc.extend({
   fetch: function () {
     var uuid = new Documents.UUID();
@@ -469,144 +214,4 @@ Documents.MangoBulkDeleteDocCollection = Documents.BulkDeleteDocCollection.exten
 
 });
 
-Documents.IndexCollection = PagingCollection.extend({
-  model: Documents.Doc,
-  documentation: function () {
-    return FauxtonAPI.constants.DOC_URLS.GENERAL;
-  },
-  initialize: function (_models, options) {
-    this.database = options.database;
-    this.params = _.extend({limit: 20, reduce: false}, options.params);
-
-    this.idxType = "_view";
-    this.view = options.view;
-    this.design = options.design.replace('_design/', '');
-    this.perPageLimit = options.perPageLimit || 20;
-
-    if (!this.params.limit) {
-      this.params.limit = this.perPageLimit;
-    }
-  },
-
-  isEditable: function () {
-    return !this.params.reduce;
-  },
-
-  urlRef: function (context, params) {
-    var query = "";
-
-    if (params) {
-      if (!_.isEmpty(params)) {
-        query = $.param(params);
-      } else {
-        query = '';
-      }
-    } else if (this.params) {
-      var parsedParam = Documents.QueryParams.stringify(this.params);
-      query = $.param(parsedParam);
-    }
-
-    if (!context) {
-      context = 'server';
-    }
-
-    var database = this.database.safeID(),
-        design = app.utils.safeURLName(this.design),
-        view = app.utils.safeURLName(this.view),
-        url = FauxtonAPI.urls('view', context, database, design, view);
-
-    return (url.indexOf("?") > -1) ? `${url}&${query}` : `${url}?${query}`;
-  },
-
-  url: function () {
-    return this.urlRef.apply(this, arguments);
-  },
-
-  totalRows: function () {
-    if (this.params.reduce) { return "unknown_reduce";}
-
-    return this.viewMeta.total_rows || "unknown";
-  },
-
-  updateSeq: function () {
-    if (!this.viewMeta) {
-      return false;
-    }
-
-    return this.viewMeta.update_seq || false;
-  },
-
-  simple: function () {
-    var docs = this.map(function (item) {
-      return {
-        _id: item.id,
-        key: item.get('key'),
-        value: item.get('value')
-      };
-    });
-
-    return new Documents.IndexCollection(docs, {
-      database: this.database,
-      params: this.params,
-      view: this.view,
-      design: this.design
-    });
-  },
-
-  parse: function () {
-    this.endTime = new Date().getTime();
-    this.requestDuration = (this.endTime - this.startTime);
-
-    return PagingCollection.prototype.parse.apply(this, arguments);
-  },
-
-  buildAllDocs: function () {
-    this.fetch();
-  },
-
-  // We implement our own fetch to store the starttime so we that
-  // we can get the request duration
-  fetch: function () {
-    this.startTime = new Date().getTime();
-    return PagingCollection.prototype.fetch.call(this);
-  },
-
-  allDocs: function () {
-    return this.models;
-  },
-
-  // This is taken from futon.browse.js $.timeString
-  requestDurationInString: function () {
-    var ms, sec, min, h, timeString, milliseconds = this.requestDuration;
-
-    sec = Math.floor(milliseconds / 1000.0);
-    min = Math.floor(sec / 60.0);
-    sec = (sec % 60.0).toString();
-    if (sec.length < 2) {
-      sec = "0" + sec;
-    }
-
-    h = (Math.floor(min / 60.0)).toString();
-    if (h.length < 2) {
-      h = "0" + h;
-    }
-
-    min = (min % 60.0).toString();
-    if (min.length < 2) {
-      min = "0" + min;
-    }
-
-    timeString = h + ":" + min + ":" + sec;
-
-    ms = (milliseconds % 1000.0).toString();
-    while (ms.length < 3) {
-      ms = "0" + ms;
-    }
-    timeString += "." + ms;
-
-    return timeString;
-  }
-
-});
-
 export default Documents;
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 463c2d3..ceb33a3 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -10,20 +10,15 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-//import app from '../../app';
 import React from 'react';
 import FauxtonAPI from '../../core/api';
 import BaseRoute from './shared-routes';
-//import Documents from './resources';
 import ChangesActions from './changes/actions';
 import Databases from '../databases/base';
 import Resources from './resources';
-//import IndexResultStores from './index-results/stores';
-//import IndexResultsActions from './index-results/actions';
 import SidebarActions from './sidebar/actions';
 import DesignDocInfoActions from './designdocinfo/actions';
 import ComponentsActions from '../components/actions';
-import QueryOptionsActions from './queryoptions/actions';
 import {DocsTabsSidebarLayout, ViewsTabsSidebarLayout, ChangesSidebarLayout} from './layouts';
 
 var DocumentsRouteObject = BaseRoute.extend({
@@ -64,8 +59,6 @@ var DocumentsRouteObject = BaseRoute.extend({
       designDocSection: 'metadata'
     });
 
-    QueryOptionsActions.hideQueryOptions();
-
     const dropDownLinks = this.getCrumbs(this.database);
     return <ViewsTabsSidebarLayout
       showEditView={false}
@@ -84,7 +77,6 @@ var DocumentsRouteObject = BaseRoute.extend({
   */
   allDocs: function (databaseName, options) {
     const params = this.createParams(options),
-          urlParams = params.urlParams,
           docParams = params.docParams;
 
     const url = FauxtonAPI.urls('allDocsSanitized', 'server', databaseName);
@@ -98,11 +90,14 @@ var DocumentsRouteObject = BaseRoute.extend({
       tab = 'design-docs';
     }
 
-    SidebarActions.selectNavItem(tab);
+    const selectedNavItem = {
+      navItem: tab
+    };
+    SidebarActions.selectNavItem(selectedNavItem.navItem);
     ComponentsActions.showDeleteDatabaseModal({showDeleteModal: false, dbId: ''});
 
-    const endpoint = this.database.allDocs.urlRef("apiurl", urlParams);
-    const docURL = this.database.allDocs.documentation();
+    const endpoint = this.database.allDocs.urlRef("apiurl", {});
+    const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
 
     const dropDownLinks = this.getCrumbs(this.database);
     return <DocsTabsSidebarLayout
@@ -114,7 +109,7 @@ var DocumentsRouteObject = BaseRoute.extend({
       designDocs={this.designDocs}
       fetchUrl={url}
       ddocsOnly={onlyShowDdocs}
-      isRedux={true}
+      selectedNavItem={selectedNavItem}
     />;
   },
 
@@ -124,8 +119,6 @@ var DocumentsRouteObject = BaseRoute.extend({
     });
     SidebarActions.selectNavItem('changes');
 
-    QueryOptionsActions.hideQueryOptions();
-
     return <ChangesSidebarLayout
       endpoint={FauxtonAPI.urls('changes', 'apiurl', this.database.id, '')}
       docURL={this.database.documentation()}
diff --git a/app/addons/documents/routes-index-editor.js b/app/addons/documents/routes-index-editor.js
index 84485e2..75ca693 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -13,14 +13,10 @@
 import React from 'react';
 import FauxtonAPI from "../../core/api";
 import BaseRoute from "./shared-routes";
-import Documents from "./resources";
 import ActionsIndexEditor from "./index-editor/actions";
 import Databases from "../databases/base";
-import IndexResultsStores from "./index-results/stores";
-import IndexResultsActions from "./index-results/actions";
 import SidebarActions from "./sidebar/actions";
 import {DocsTabsSidebarLayout, ViewsTabsSidebarLayout} from './layouts';
-import Constants from './constants';
 
 const IndexEditorAndResults = BaseRoute.extend({
   routes: {
@@ -51,39 +47,10 @@ const IndexEditorAndResults = BaseRoute.extend({
   },
 
   showView: function (databaseName, ddoc, viewName) {
-    const params = this.createParams(),
-          urlParams = params.urlParams,
-          docParams = params.docParams,
-          store = IndexResultsStores.indexResultsStore;
-
-    // if the user is simply switching the layout style (i.e. metadata, json, or table),
-    // there will be a cached offset value.  Use that offset when getting the "new"
-    // collection so data stays the same.
-    if (docParams.skip && store.hasCachedOffset()) {
-      docParams.skip = Math.max(store.getCachedOffset(), docParams.skip);
-    } else if (store.hasCachedOffset()) {
-      docParams.skip = store.getCachedOffset();
-    }
 
     viewName = viewName.replace(/\?.*$/, '');
-    this.indexedDocs = new Documents.IndexCollection(null, {
-      database: this.database,
-      design: ddoc,
-      view: viewName,
-      params: docParams,
-      paging: {
-        pageSize: store.getPerPage()
-      }
-    });
 
     ActionsIndexEditor.clearIndex();
-
-    IndexResultsActions.newResultsList({
-      collection: this.indexedDocs,
-      typeOfIndex: Constants.INDEX_RESULTS_DOC_TYPE.VIEW,
-      bulkCollection: new Documents.BulkDeleteDocCollection([], { databaseId: this.database.safeID() }),
-    });
-
     ActionsIndexEditor.fetchDesignDocsBeforeEdit({
       viewName: viewName,
       newView: false,
@@ -92,15 +59,20 @@ const IndexEditorAndResults = BaseRoute.extend({
       designDocId: '_design/' + ddoc
     });
 
-    SidebarActions.selectNavItem('designDoc', {
-      designDocName: ddoc,
-      designDocSection: 'Views',
-      indexName: viewName
-    });
-
-    this.showQueryOptions(urlParams, ddoc, viewName);
+    const selectedNavItem = {
+      navItem: 'designDoc',
+      params: {
+        designDocName: ddoc,
+        designDocSection: 'Views',
+        indexName: viewName
+      }
+    };
+    SidebarActions.selectNavItem(selectedNavItem.navItem, selectedNavItem.params);
 
-    const endpoint = this.indexedDocs.urlRef('apiurl');
+    const url = FauxtonAPI.urls('view', 'server', encodeURIComponent(databaseName),
+      encodeURIComponent(ddoc), encodeURIComponent(viewName));
+    const endpoint = FauxtonAPI.urls('view', 'apiurl', encodeURIComponent(databaseName),
+      encodeURIComponent(ddoc), encodeURIComponent(viewName));
     const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
 
     const dropDownLinks = this.getCrumbs(this.database);
@@ -110,6 +82,10 @@ const IndexEditorAndResults = BaseRoute.extend({
       dbName={this.database.id}
       dropDownLinks={dropDownLinks}
       database={this.database}
+      fetchUrl={url}
+      ddocsOnly={false}
+      deleteEnabled={false}
+      selectedNavItem={selectedNavItem}
       />;
   },
 
diff --git a/app/addons/documents/shared-routes.js b/app/addons/documents/shared-routes.js
index 15f5b44..ef0d2bd 100644
--- a/app/addons/documents/shared-routes.js
+++ b/app/addons/documents/shared-routes.js
@@ -13,10 +13,7 @@
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
 import Documents from "./shared-resources";
-import PaginationActions from "./pagination/actions";
-import IndexResultStores from "./index-results/stores";
 import SidebarActions from "./sidebar/actions";
-import QueryActions from './queryoptions/actions';
 
 // The Documents section is built up a lot of different route object which share code. This contains
 // base functionality that can be used across routes / addons
@@ -38,25 +35,6 @@ var BaseRoute = FauxtonAPI.RouteObject.extend({
     });
   },
 
-  showQueryOptions: function (urlParams, ddoc, viewName) {
-    var promise = this.designDocs.fetch({reset: true}),
-        hasReduceFunction;
-
-    promise.then(() => {
-      var design = _.findWhere(this.designDocs.models, {id: '_design/' + ddoc});
-      !_.isUndefined(hasReduceFunction = design.attributes.doc.views[viewName].reduce);
-
-      QueryActions.showQueryOptions();
-      QueryActions.reset({
-        queryParams: urlParams,
-        hasReduce: hasReduceFunction,
-        showReduce: !_.isUndefined(hasReduceFunction),
-        viewName: viewName,
-        ddocName: ddoc
-      });
-    });
-  },
-
   addSidebar: function (selectedNavItem) {
     var options = {
       designDocs: this.designDocs,
@@ -78,23 +56,11 @@ var BaseRoute = FauxtonAPI.RouteObject.extend({
 
   createParams: function (options) {
     const urlParams = app.getParams(options),
-          params = Documents.QueryParams.parse(urlParams),
-          store = IndexResultStores.indexResultsStore;
-
-    let start = 0;
-    if (urlParams.skip && store.hasCachedOffset()) {
-      start = Math.max(store.getCachedOffset(), parseInt(urlParams.skip, 10));
-    } else if (urlParams.skip) {
-      start = parseInt(urlParams.skip, 10);
-    } else if (store.hasCachedOffset()) {
-      start = store.getCachedOffset();
-    }
-    PaginationActions.setPageStart(start);
-    PaginationActions.setDocumentLimit(parseInt(urlParams.limit, 10));
+          params = Documents.QueryParams.parse(urlParams);
 
     return {
       urlParams: urlParams,
-      docParams: _.extend(params, {limit: store.getPerPage()})
+      docParams: params
     };
   }
 });
diff --git a/app/addons/documents/sidebar/SidebarControllerContainer.js b/app/addons/documents/sidebar/SidebarControllerContainer.js
new file mode 100644
index 0000000..4da0628
--- /dev/null
+++ b/app/addons/documents/sidebar/SidebarControllerContainer.js
@@ -0,0 +1,44 @@
+// 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 { connect } from 'react-redux';
+import SidebarComponents from './sidebar';
+import ActionTypes from './actiontypes';
+
+const reduxUpdatedDesignDocList = (designDocs) => {
+  return {
+    type: ActionTypes.SIDEBAR_UPDATED_DESIGN_DOCS,
+    options: {
+      designDocs: Array.isArray(designDocs) ? designDocs : []
+    }
+  };
+};
+
+const mapStateToProps = () => {
+  return {};
+};
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    reduxUpdatedDesignDocList: (designDocsList) => {
+      dispatch(reduxUpdatedDesignDocList(designDocsList));
+    }
+  };
+};
+
+const SidebarControllerContainer = connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(SidebarComponents.SidebarController);
+
+export default SidebarControllerContainer;
+
diff --git a/app/addons/documents/header/header.actiontypes.js b/app/addons/documents/sidebar/reducers.js
similarity index 60%
rename from app/addons/documents/header/header.actiontypes.js
rename to app/addons/documents/sidebar/reducers.js
index 7d5d9b7..ef295f4 100644
--- a/app/addons/documents/header/header.actiontypes.js
+++ b/app/addons/documents/sidebar/reducers.js
@@ -10,6 +10,21 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-export default {
-  TOGGLE_LAYOUT: 'TOGGLE_LAYOUT',
+import ActionTypes from './actiontypes';
+
+const initialState = {
+  designDocs: []
+};
+
+export default function resultsState(state = initialState, action) {
+  switch (action.type) {
+
+    case ActionTypes.SIDEBAR_UPDATED_DESIGN_DOCS:
+      return Object.assign({}, state, {
+        designDocs: action.options.designDocs
+      });
+
+    default:
+      return state;
+  }
 };
diff --git a/app/addons/documents/sidebar/sidebar.js b/app/addons/documents/sidebar/sidebar.js
index 79daa6e..f5cd83a 100644
--- a/app/addons/documents/sidebar/sidebar.js
+++ b/app/addons/documents/sidebar/sidebar.js
@@ -481,7 +481,16 @@ var SidebarController = React.createClass({
   },
 
   onChange: function () {
-    this.setState(this.getStoreState());
+
+    const newState = this.getStoreState();
+    // Workaround to signal Redux store that the design doc list was updated
+    // which is currently required by QueryOptionsContainer
+    // It should be removed once Sidebar components are refactored to use Redux
+    if (this.props.reduxUpdatedDesignDocList) {
+      this.props.reduxUpdatedDesignDocList(newState.designDocList);
+    }
+
+    this.setState(newState);
   },
 
   showDeleteDatabaseModal: function (payload) {
diff --git a/app/addons/documents/tests/document-test-helper.js b/app/addons/documents/tests/document-test-helper.js
index bb03781..b343a81 100644
--- a/app/addons/documents/tests/document-test-helper.js
+++ b/app/addons/documents/tests/document-test-helper.js
@@ -11,7 +11,7 @@
 // the License.
 import Documents from "../resources";
 
-var opts = {
+const opts = {
   params: {},
   database: {
     safeID: function () { return '1';}
@@ -26,15 +26,6 @@ function createDocColumn (docs) {
   return new Documents.AllDocs(docs, opts);
 }
 
-function createMangoIndexDocColumn (docs) {
-  docs = docs.map(function (doc) {
-    return Documents.MangoIndex.prototype.parse(doc);
-  });
-
-  return new Documents.MangoIndexCollection(docs, opts);
-}
-
 export default {
-  createDocColumn: createDocColumn,
-  createMangoIndexDocColumn: createMangoIndexDocColumn
+  createDocColumn
 };
diff --git a/app/addons/documents/tests/nightwatch/viewCreateBadView.js b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
index fc46ebc..4b3b2fa 100644
--- a/app/addons/documents/tests/nightwatch/viewCreateBadView.js
+++ b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
@@ -42,6 +42,7 @@ module.exports = {
       .clickWhenVisible('.control-toggle-queryoptions', waitTime, false)
       .clickWhenVisible('label[for="qoReduce"]', waitTime, false)
       .clickWhenVisible('.query-options .btn-secondary', waitTime, false)
+      .waitForElementVisible('div.table-view-docs', waitTime, false)
       .waitForAttribute('.table-view-docs td:nth-child(4)', 'title', function (docContents) {
         return (/_sum function requires/).test(docContents);
       })
@@ -60,6 +61,7 @@ module.exports = {
       .clickWhenVisible('.control-toggle-queryoptions', waitTime, false)
       .clickWhenVisible('label[for="qoReduce"]', waitTime, false)
       .clickWhenVisible('.query-options .btn-secondary', waitTime, false)
+      .waitForElementVisible('div.table-view-docs', waitTime, false)
       .waitForAttribute('.table-view-docs td:nth-child(4)', 'title', function (docContents) {
         return (/_sum function requires/).test(docContents);
       })
diff --git a/app/addons/permissions/layout.js b/app/addons/permissions/layout.js
index dc8558d..2569911 100644
--- a/app/addons/permissions/layout.js
+++ b/app/addons/permissions/layout.js
@@ -19,7 +19,8 @@ export const PermissionsLayout = ({docURL, database, endpoint, dbName, dropDownL
   return (
     <div id="dashboard" className="with-sidebar">
       <TabsSidebarHeader
-        hideHeaderBar={true}
+        hideQueryOptions={true}
+        hideJumpToDoc={true}
         docURL={docURL}
         endpoint={endpoint}
         dbName={dbName}

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

Mime
View raw message