You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by GitBox <gi...@apache.org> on 2018/11/07 01:04:27 UTC

[GitHub] Antonio-Maranhao closed pull request #1151: Update documents/index-editor to use Redux

Antonio-Maranhao closed pull request #1151: Update documents/index-editor to use Redux
URL: https://github.com/apache/couchdb-fauxton/pull/1151
 
 
   

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

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

diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index cff9a82b6..21515ebd8 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -22,6 +22,7 @@ import partitionKeyReducers from "./partition-key/reducers";
 import revisionBrowserReducers from './rev-browser/reducers';
 import docEditorReducers from './doc-editor/reducers';
 import changesReducers from './changes/reducers';
+import indexEditorReducers from './index-editor/reducers';
 import "./assets/less/documents.less";
 
 FauxtonAPI.addReducers({
@@ -32,7 +33,8 @@ FauxtonAPI.addReducers({
   partitionKey: partitionKeyReducers,
   docEditor: docEditorReducers,
   changes: changesReducers,
-  designDocInfo: designDocInfoReducers
+  designDocInfo: designDocInfoReducers,
+  indexEditor: indexEditorReducers
 });
 
 function getQueryParam (query) {
diff --git a/app/addons/documents/index-editor/__tests__/actions.test.js b/app/addons/documents/index-editor/__tests__/actions.test.js
index cba84f556..c01e4695d 100644
--- a/app/addons/documents/index-editor/__tests__/actions.test.js
+++ b/app/addons/documents/index-editor/__tests__/actions.test.js
@@ -10,22 +10,20 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import FauxtonAPI from "../../../../core/api";
-import Actions from "../actions";
-import Documents from "../../resources";
-import testUtils from "../../../../../test/mocha/testUtils";
-import sinon from "sinon";
-import "../../../documents/base";
-var assert = testUtils.assert;
-var restore = testUtils.restore;
-
+import FauxtonAPI from '../../../../core/api';
+import Actions from '../actions';
+import Documents from '../../resources';
+import testUtils from '../../../../../test/mocha/testUtils';
+import sinon from 'sinon';
+import '../../../documents/base';
+
+const restore = testUtils.restore;
 FauxtonAPI.router = new FauxtonAPI.Router([]);
 
-
 describe('Index Editor Actions', function () {
 
   describe('delete view', function () {
-    var designDocs, database, designDoc, designDocCollection, designDocId, viewName;
+    let designDocs, database, designDoc, designDocCollection, designDocId, viewName;
     beforeEach(function () {
       FauxtonAPI.reduxDispatch = sinon.stub();
       database = {
@@ -61,7 +59,7 @@ describe('Index Editor Actions', function () {
       designDoc.save = function () {
         return FauxtonAPI.Promise.resolve();
       };
-      var saveSpy = sinon.spy(designDoc, 'save');
+      const saveSpy = sinon.spy(designDoc, 'save');
       designDocs.fetch = function () {
         return FauxtonAPI.Promise.resolve();
       };
@@ -73,7 +71,7 @@ describe('Index Editor Actions', function () {
         designDoc: designDoc
       });
 
-      assert.ok(saveSpy.calledOnce);
+      sinon.assert.calledOnce(saveSpy);
     });
 
     it('deletes design doc if has no other views', function () {
@@ -82,7 +80,7 @@ describe('Index Editor Actions', function () {
       designDoc.destroy = function () {
         return FauxtonAPI.Promise.resolve();
       };
-      var destroySpy = sinon.spy(designDoc, 'destroy');
+      const destroySpy = sinon.spy(designDoc, 'destroy');
       designDocs.remove = function () {};
       designDocs.fetch = function () {
         return FauxtonAPI.Promise.resolve();
@@ -95,11 +93,11 @@ describe('Index Editor Actions', function () {
         designDoc: designDoc
       });
 
-      assert.ok(destroySpy.calledOnce);
+      sinon.assert.calledOnce(destroySpy);
     });
 
     it('navigates to all docs if was on view', function () {
-      var spy = sinon.spy(FauxtonAPI, 'navigate');
+      const spy = sinon.spy(FauxtonAPI, 'navigate');
 
       designDoc.save = function () {
         return FauxtonAPI.Promise.resolve();
@@ -114,8 +112,8 @@ describe('Index Editor Actions', function () {
         designDoc: designDoc,
         isOnIndex: true
       }).then(() => {
-        assert.ok(spy.getCall(0).args[0].match(/_all_docs/));
-        assert.ok(spy.calledOnce);
+        sinon.assert.calledWithMatch(spy, /_all_docs/);
+        sinon.assert.calledOnce(spy);
       });
     });
 
@@ -124,27 +122,27 @@ describe('Index Editor Actions', function () {
       const ddocModel = new Documents.Doc(ddoc, { database: database });
 
       ddocModel.setDdocView('testview', '() => {}', '() => {}');
-      assert.deepEqual(ddocModel.get('views'), {
+      expect(ddocModel.get('views')).toEqual({
         testview: {
           map: '() => {}',
           reduce: '() => {}'
         }
       });
-      assert.equal(ddocModel.get('language'), 'javascript');
+      expect(ddocModel.get('language')).toBe('javascript');
     });
 
     it('removes old view only when editting', function () {
       const viewInfo = {
-        newView: false,
+        isNewView: false,
         originalDesignDocName: 'test',
         designDocId: 'test',
         originalViewName: 'foo',
         viewName: 'bar'
       };
-      assert.isTrue(Actions.shouldRemoveDdocView(viewInfo));
+      expect(Actions.shouldRemoveDdocView(viewInfo)).toBe(true);
 
-      viewInfo.newView = true;
-      assert.isFalse(Actions.shouldRemoveDdocView(viewInfo));
+      viewInfo.isNewView = true;
+      expect(Actions.shouldRemoveDdocView(viewInfo)).toBe(false);
     });
   });
 });
diff --git a/app/addons/documents/index-editor/__tests__/viewIndex.components.test.js b/app/addons/documents/index-editor/__tests__/components.test.js
similarity index 62%
rename from app/addons/documents/index-editor/__tests__/viewIndex.components.test.js
rename to app/addons/documents/index-editor/__tests__/components.test.js
index 0c07d418b..fde338c18 100644
--- a/app/addons/documents/index-editor/__tests__/viewIndex.components.test.js
+++ b/app/addons/documents/index-editor/__tests__/components.test.js
@@ -9,81 +9,42 @@
 // 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 Resources from "../../resources";
-import Views from "../components";
-import Actions from "../actions";
-import utils from "../../../../../test/mocha/testUtils";
-import React from "react";
-import ReactDOM from "react-dom";
+
+import React from 'react';
 import {mount} from 'enzyme';
-import sinon from "sinon";
+import sinon from 'sinon';
+import FauxtonAPI from '../../../../core/api';
+import Views from '../components';
 import '../../base';
-FauxtonAPI.router = new FauxtonAPI.Router([]);
-
-const { assert } = utils;
-
-
-const resetStore = (designDocs) => {
-  Actions.editIndex({
-    database: { id: 'rockos-db' },
-    newView: false,
-    viewName: 'test-view',
-    designDocs: getDesignDocsCollection(designDocs),
-    designDocId: designDocs[0]._id
-  });
-};
-
-const getDesignDocsCollection = (designDocs) => {
-  designDocs = designDocs.map(function (doc) {
-    return Resources.Doc.prototype.parse(doc);
-  });
-
-  return new Resources.AllDocs(designDocs, {
-    params: { limit: 10 },
-    database: {
-      safeID: () => { return 'id'; }
-    }
-  });
-};
 
+FauxtonAPI.router = new FauxtonAPI.Router([]);
 
-describe('reduce editor', () => {
-  let reduceEl;
-
+describe('ReduceEditor', () => {
   describe('getReduceValue', () => {
+    const defaultProps = {
+      reduceOptions: [],
+      hasReduce: false,
+      hasCustomReduce: false,
+      reduce: null,
+      reduceSelectedOption: 'NONE',
+      updateReduceCode: () => {},
+      selectReduceChanged: () => {}
+    };
 
     it('returns null for none', () => {
-      const designDoc = {
-        _id: '_design/test-doc',
-        views: {
-          'test-view': {
-            map: '() => {};'
-          }
-        }
-      };
-
-      resetStore([designDoc]);
-
-      reduceEl = mount(<Views.ReduceEditor/>);
-      assert.ok(_.isNull(reduceEl.instance().getReduceValue()));
+      const reduceEl = mount(<Views.ReduceEditor
+        {...defaultProps}
+      />);
+      expect(reduceEl.instance().getReduceValue()).toBeNull();
     });
 
     it('returns built in for built in reduce', () => {
-      const designDoc = {
-        _id: '_design/test-doc',
-        views: {
-          'test-view': {
-            map: '() => {};',
-            reduce: '_sum'
-          }
-        }
-      };
-
-      resetStore([designDoc]);
-
-      reduceEl = mount(<Views.ReduceEditor/>);
-      assert.equal(reduceEl.instance().getReduceValue(), '_sum');
+      const reduceEl = mount(<Views.ReduceEditor
+        {...defaultProps}
+        reduce='_sum'
+        hasReduce={true}
+      />);
+      expect(reduceEl.instance().getReduceValue()).toBe('_sum');
     });
 
   });
@@ -107,7 +68,7 @@ describe('DesignDocSelector component', () => {
         value: '_design/test-doc'
       }
     });
-    assert.ok(spy.calledOnce);
+    sinon.assert.calledOnce(spy);
   });
 
   it('shows new design doc field when set to new-doc', () => {
@@ -119,7 +80,7 @@ describe('DesignDocSelector component', () => {
         onChangeNewDesignDocName={() => {}}
       />);
 
-    assert.equal(selectorEl.find('#new-ddoc-section').length, 1);
+    expect(selectorEl.find('#new-ddoc-section').length).toBe(1);
   });
 
   it('hides new design doc field when design doc selected', () => {
@@ -131,7 +92,7 @@ describe('DesignDocSelector component', () => {
         onChangeNewDesignDocName={() => {}}
       />);
 
-    assert.equal(selectorEl.find('#new-ddoc-section').length, 0);
+    expect(selectorEl.find('#new-ddoc-section').length).toBe(0);
   });
 
   it('always passes validation when design doc selected', () => {
@@ -143,7 +104,7 @@ describe('DesignDocSelector component', () => {
         onChangeNewDesignDocName={() => {}}
       />);
 
-    assert.equal(selectorEl.instance().validate(), true);
+    expect(selectorEl.instance().validate()).toBe(true);
   });
 
   it('fails validation if new doc name entered/not entered', () => {
@@ -157,7 +118,7 @@ describe('DesignDocSelector component', () => {
       />);
 
     // it shouldn't validate at this point: no new design doc name has been entered
-    assert.equal(selectorEl.instance().validate(), false);
+    expect(selectorEl.instance().validate()).toBe(false);
   });
 
   it('passes validation if new doc name entered/not entered', () => {
@@ -169,7 +130,7 @@ describe('DesignDocSelector component', () => {
         onSelectDesignDoc={() => { }}
         onChangeNewDesignDocName={() => {}}
       />);
-    assert.equal(selectorEl.instance().validate(), true);
+    expect(selectorEl.instance().validate()).toBe(true);
   });
 
 
@@ -181,7 +142,7 @@ describe('DesignDocSelector component', () => {
         onSelectDesignDoc={() => { }}
         onChangeNewDesignDocName={() => {}}
       />);
-    assert.equal(selectorEl.find('.help-link').length, 0);
+    expect(selectorEl.find('.help-link').length).toBe(0);
   });
 
   it('includes help doc link when supplied', () => {
@@ -194,27 +155,51 @@ describe('DesignDocSelector component', () => {
         docLink={docLink}
         onChangeNewDesignDocName={() => {}}
       />);
-    assert.equal(selectorEl.find('.help-link').length, 1);
-    assert.equal(selectorEl.find('.help-link').prop('href'), docLink);
+    expect(selectorEl.find('.help-link').length).toBe(1);
+    expect(selectorEl.find('.help-link').prop('href')).toBe(docLink);
   });
 });
 
-
-describe('Editor', () => {
-  let editorEl;
-
-  beforeEach(() => {
-    editorEl = mount(<Views.EditorController />);
-  });
+describe('IndexEditor', () => {
+  const defaultProps = {
+    isLoading: false,
+    isNewView: false,
+    isNewDesignDoc: false,
+    viewName: '',
+    database: {},
+    originalViewName: '',
+    originalDesignDocName: '',
+    designDoc: {},
+    designDocId: '',
+    designDocList: [],
+    map: '',
+    reduce: '',
+    designDocs: {},
+    updateNewDesignDocName: () => {},
+    updateMapCode: () => {},
+    selectDesignDoc: () => {},
+    onChangeNewDesignDocName: () => {},
+    reduceOptions: [],
+    reduceSelectedOption: 'NONE',
+    hasReduce: false,
+    hasCustomReduce: false,
+    updateReduceCode: () => {},
+    selectReduceChanged: () => {}
+  };
 
   it('calls changeViewName on view name change', () => {
-    const viewName = 'new-name';
-    const spy = sinon.spy(Actions, 'changeViewName');
+    const spy = sinon.spy();
+    const editorEl = mount(<Views.IndexEditor
+      {...defaultProps}
+      viewName='new-name'
+      changeViewName={spy}
+    />);
+
     editorEl.find('#index-name').simulate('change', {
       target: {
-        value: viewName
+        value: 'newViewName'
       }
     });
-    assert.ok(spy.calledWith(viewName));
+    sinon.assert.calledWith(spy, 'newViewName');
   });
 });
diff --git a/app/addons/documents/index-editor/__tests__/reducers.test.js b/app/addons/documents/index-editor/__tests__/reducers.test.js
new file mode 100644
index 000000000..ee60b4ec3
--- /dev/null
+++ b/app/addons/documents/index-editor/__tests__/reducers.test.js
@@ -0,0 +1,299 @@
+// 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 Documents from '../../../documents/resources';
+import reducer, { hasCustomReduce, getDesignDocIds } from '../reducers';
+import ActionTypes from '../actiontypes';
+import '../../base';
+
+describe('IndexEditor Reducer', () => {
+  describe('map editor', () => {
+    it('new view is assigned the default map code', () => {
+      const action = {
+        type: ActionTypes.EDIT_NEW_INDEX,
+        options: {
+          isNewView: true,
+          //designDocs: {find: () => { return { dDocModel: () => {}}; }}
+        }
+      };
+      const newState = reducer(undefined, action);
+      expect(newState.view.map).toBe('function (doc) {\n  emit(doc._id, 1);\n}');
+    });
+  });
+
+  describe('reduce editor', () => {
+    describe('hasCustomReduce', () => {
+      it('is false for no reduce', () => {
+        const designDoc = {
+          _id: '_design/test-doc',
+          views: {
+            'test-view': {
+              map: '() => {};'
+            }
+          }
+        };
+        const designDocs = new Documents.AllDocs([designDoc], {
+          params: { limit: 10 },
+          database: {
+            safeID: () => { return 'id';}
+          }
+        });
+        const action = {
+          type: ActionTypes.EDIT_NEW_INDEX,
+          options: {
+            isNewView: false,
+            viewName: 'test-view',
+            designDocs: designDocs,
+            designDocId: designDoc._id
+          }
+        };
+        const newState = reducer(undefined, action);
+        expect(hasCustomReduce(newState)).toBe(false);
+      });
+
+      it('is false for built in reduce', () => {
+        const designDoc = {
+          _id: '_design/test-doc',
+          views: {
+            'test-view': {
+              map: '() => {};',
+              reduce: '_sum'
+            }
+          }
+        };
+        const designDocs = new Documents.AllDocs([designDoc], {
+          params: { limit: 10 },
+          database: {
+            safeID: () => { return 'id';}
+          }
+        });
+        const action = {
+          type: ActionTypes.EDIT_NEW_INDEX,
+          options: {
+            isNewView: false,
+            viewName: 'test-view',
+            designDocs: designDocs,
+            designDocId: designDoc._id
+          }
+        };
+        const newState = reducer(undefined, action);
+        expect(hasCustomReduce(newState)).toBe(false);
+      });
+
+      it('is true for custom reduce', () => {
+        const designDoc = {
+          _id: '_design/test-doc',
+          views: {
+            'test-view': {
+              map: '() => {};',
+              reduce: 'function (reduce) { reduce(); }'
+            }
+          }
+        };
+        const designDocs = new Documents.AllDocs([designDoc], {
+          params: { limit: 10 },
+          database: {
+            safeID: () => { return 'id';}
+          }
+        });
+        const action = {
+          type: ActionTypes.EDIT_NEW_INDEX,
+          options: {
+            isNewView: false,
+            viewName: 'test-view',
+            designDocs: designDocs,
+            designDocId: designDoc._id
+          }
+        };
+
+        const newState = reducer(undefined, action);
+        expect(hasCustomReduce(newState)).toBe(true);
+      });
+    });
+
+    describe('SELECT_REDUCE_CHANGE', () => {
+      const designDoc = {
+        _id: '_design/test-doc',
+        views: {
+          'test-view': {
+            map: '() => {};'
+          }
+        }
+      };
+      const designDocs = new Documents.AllDocs([designDoc], {
+        params: { limit: 10 },
+        database: {
+          safeID: () => { return 'id';}
+        }
+      });
+      const editAction = {
+        type: ActionTypes.EDIT_NEW_INDEX,
+        options: {
+          isNewView: false,
+          viewName: 'test-view',
+          designDocs: designDocs,
+          designDocId: designDoc._id
+        }
+      };
+
+      it('NONE returns null reduce', () => {
+        let newState = reducer(undefined, editAction);
+        const selectReduceaction = {
+          type: ActionTypes.SELECT_REDUCE_CHANGE,
+          reduceSelectedOption: 'NONE'
+        };
+        newState = reducer(newState, selectReduceaction);
+        expect(newState.view.reduce).toBe('');
+      });
+
+      it('builtin returns builtin reduce', () => {
+        let newState = reducer(undefined, editAction);
+        const selectReduceAction = {
+          type: ActionTypes.SELECT_REDUCE_CHANGE,
+          reduceSelectedOption: '_sum'
+        };
+        newState = reducer(newState, selectReduceAction);
+        expect(newState.view.reduce).toBe('_sum');
+      });
+
+      it('custom returns custom reduce', () => {
+        let newState = reducer(undefined, editAction);
+        const selectReduceAction = {
+          type: ActionTypes.SELECT_REDUCE_CHANGE,
+          reduceSelectedOption: 'CUSTOM'
+        };
+        newState = reducer(newState, selectReduceAction);
+        expect(newState.view.reduce).toBe('function (keys, values, rereduce) {\n  if (rereduce) {\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}');
+      });
+    });
+  });
+
+  describe('design doc selector', () => {
+    const designDoc = {
+      _id: '_design/test-doc',
+      views: {
+        'test-view': {
+          map: 'boom'
+        }
+      }
+    };
+
+    const mangoDoc = {
+      "_id": "_design/123mango",
+      "id": "_design/123mango",
+      "key": "_design/123mango",
+      "value": {
+        "rev": "20-9e4bc8b76fd7d752d620bbe6e0ea9a80"
+      },
+      "doc": {
+        "_id": "_design/123mango",
+        "_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": "query",
+        "indexes": {
+          "newSearch": {
+            "analyzer": "standard",
+            "index": "function(doc){\n index(\"default\", doc._id);\n}"
+          }
+        }
+      }
+    };
+
+    const designDocArray = _.map([designDoc, mangoDoc], (doc) => {
+      return Documents.Doc.prototype.parse(doc);
+    });
+
+    const designDocs = new Documents.AllDocs(designDocArray, {
+      params: { limit: 10 },
+      database: {
+        safeID: () => { return 'id'; }
+      }
+    });
+
+    const editAction = {
+      type: ActionTypes.EDIT_INDEX,
+      options: {
+        isNewView: false,
+        viewName: 'test-view',
+        designDocs: designDocs,
+        designDocId: designDoc._id
+      }
+    };
+
+    it('DESIGN_DOC_CHANGE changes design doc id', () => {
+      let newState = reducer(undefined, editAction);
+      const designDocId = 'another-one';
+      const ddocChangeAction = {
+        type: ActionTypes.DESIGN_DOC_CHANGE,
+        options: {
+          value: designDocId
+        }
+      };
+      newState = reducer(newState, ddocChangeAction);
+      expect(newState.designDocId).toBe(designDocId);
+    });
+
+    it('only filters mango docs', () => {
+      const newState = reducer(undefined, editAction);
+      const designDocs = getDesignDocIds(newState);
+
+      expect(designDocs.length).toBe(1);
+      expect(designDocs[0]).toBe('_design/test-doc');
+    });
+  });
+
+  describe('EDIT_INDEX', () => {
+    const designDoc = {
+      _id: '_design/test-doc',
+      views: {
+        'test-view': {
+          map: 'boom'
+        }
+      }
+    };
+    const designDocs = new Documents.AllDocs([designDoc], {
+      params: { limit: 10 },
+      database: {
+        safeID: () => { return 'id';}
+      }
+    });
+
+    it('can set reduce for new design doc', () => {
+      const editAction = {
+        type: ActionTypes.EDIT_INDEX,
+        options: {
+          isNewView: true,
+          isNewDesignDoc: true,
+          viewName: 'test-view',
+          designDocs: designDocs,
+          designDocId: undefined
+        }
+      };
+      let newState = reducer(undefined, editAction);
+
+      const selectReduceAction = {
+        type: ActionTypes.SELECT_REDUCE_CHANGE,
+        reduceSelectedOption: '_sum'
+      };
+      newState = reducer(newState, selectReduceAction);
+      expect(newState.view.reduce).toBe('_sum');
+    });
+  });
+});
diff --git a/app/addons/documents/index-editor/__tests__/stores.test.js b/app/addons/documents/index-editor/__tests__/stores.test.js
deleted file mode 100644
index 2e1e6e764..000000000
--- a/app/addons/documents/index-editor/__tests__/stores.test.js
+++ /dev/null
@@ -1,337 +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 ActionTypes from "../actiontypes";
-import Documents from "../../../documents/resources";
-import testUtils from "../../../../../test/mocha/testUtils";
-import '../../base';
-const assert = testUtils.assert;
-let store;
-let dispatchToken;
-
-describe('IndexEditorStore', () => {
-
-  beforeEach(() => {
-    store = new Stores.IndexEditorStore();
-    dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch.bind(store));
-  });
-
-  afterEach(() => {
-    FauxtonAPI.dispatcher.unregister(dispatchToken);
-  });
-
-  describe('map editor', () => {
-
-    describe('new view', () => {
-
-      beforeEach(() => {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.EDIT_NEW_INDEX,
-          options: {
-            newView: true
-          }
-        });
-      });
-
-      it('returns default map', () => {
-        assert.equal(store.getMap(), 'function (doc) {\n  emit(doc._id, 1);\n}');
-      });
-    });
-
-  });
-
-  describe('reduce editor', () => {
-    describe('has custom reduce', () => {
-      it('is false for no reduce', () => {
-        const designDoc = {
-          _id: '_design/test-doc',
-          views: {
-            'test-view': {
-              map: '() => {};'
-            }
-          }
-        };
-
-        const designDocs = new Documents.AllDocs([designDoc], {
-          params: { limit: 10 },
-          database: {
-            safeID: () => { return 'id';}
-          }
-        });
-
-        FauxtonAPI.dispatch({
-          type: ActionTypes.EDIT_NEW_INDEX,
-          options: {
-            newView: false,
-            viewName: 'test-view',
-            designDocs: designDocs,
-            designDocId: designDoc._id
-          }
-        });
-
-        assert.notOk(store.hasCustomReduce());
-      });
-
-      it('is false for built in reduce', () => {
-        const designDoc = {
-          _id: '_design/test-doc',
-          views: {
-            'test-view': {
-              map: '() => {};',
-              reduce: '_sum'
-            }
-          }
-        };
-
-        const designDocs = new Documents.AllDocs([designDoc], {
-          params: { limit: 10 },
-          database: {
-            safeID: () => { return 'id';}
-          }
-        });
-        FauxtonAPI.dispatch({
-          type: ActionTypes.EDIT_NEW_INDEX,
-          options: {
-            newView: false,
-            viewName: 'test-view',
-            designDocs: designDocs,
-            designDocId: designDoc._id
-          }
-        });
-
-        assert.notOk(store.hasCustomReduce());
-      });
-
-      it('is true for custom reduce', () => {
-        const designDoc = {
-          _id: '_design/test-doc',
-          views: {
-            'test-view': {
-              map: '() => {};',
-              reduce: 'function (reduce) { reduce(); }'
-            }
-          }
-        };
-
-        const designDocs = new Documents.AllDocs([designDoc], {
-          params: { limit: 10 },
-          database: {
-            safeID: () => { return 'id';}
-          }
-        });
-
-        FauxtonAPI.dispatch({
-          type: ActionTypes.EDIT_NEW_INDEX,
-          options: {
-            newView: false,
-            viewName: 'test-view',
-            designDocs: designDocs,
-            designDocId: designDoc._id
-          }
-        });
-
-        assert.ok(store.hasCustomReduce());
-      });
-
-    });
-
-    //show default reduce
-    describe('SELECT_REDUCE_CHANGE', () => {
-
-      beforeEach(() => {
-        const designDoc = {
-          _id: '_design/test-doc',
-          views: {
-            'test-view': {
-              map: '() => {};'
-            }
-          }
-        };
-
-        const designDocs = new Documents.AllDocs([designDoc], {
-          params: { limit: 10 },
-          database: {
-            safeID: () => { return 'id';}
-          }
-        });
-
-        FauxtonAPI.dispatch({
-          type: ActionTypes.EDIT_NEW_INDEX,
-          options: {
-            newView: false,
-            viewName: 'test-view',
-            designDocs: designDocs,
-            designDocId: designDoc._id
-          }
-        });
-      });
-
-      it('NONE returns null reduce', () => {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SELECT_REDUCE_CHANGE,
-          reduceSelectedOption: 'NONE'
-        });
-        assert.ok(_.isNull(store.getReduce()));
-      });
-
-      it('builtin returns bultin reduce', () => {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SELECT_REDUCE_CHANGE,
-          reduceSelectedOption: '_sum'
-        });
-        assert.equal(store.getReduce(), '_sum');
-      });
-
-      it('custom returns custom reduce', () => {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SELECT_REDUCE_CHANGE,
-          reduceSelectedOption: 'CUSTOM'
-        });
-        assert.equal(store.getReduce(), 'function (keys, values, rereduce) {\n  if (rereduce) {\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}');
-      });
-    });
-  });
-
-
-  describe('design doc selector', () => {
-    let designDoc;
-
-    beforeEach(() => {
-      designDoc = {
-        _id: '_design/test-doc',
-        views: {
-          'test-view': {
-            map: 'boom'
-          }
-        }
-      };
-
-      const mangoDoc = {
-        "_id": "_design/123mango",
-        "id": "_design/123mango",
-        "key": "_design/123mango",
-        "value": {
-          "rev": "20-9e4bc8b76fd7d752d620bbe6e0ea9a80"
-        },
-        "doc": {
-          "_id": "_design/123mango",
-          "_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": "query",
-          "indexes": {
-            "newSearch": {
-              "analyzer": "standard",
-              "index": "function(doc){\n index(\"default\", doc._id);\n}"
-            }
-          }
-        }
-      };
-
-      const designDocArray = _.map([designDoc, mangoDoc], (doc) => {
-        return Documents.Doc.prototype.parse(doc);
-      });
-
-      var designDocs = new Documents.AllDocs(designDocArray, {
-        params: { limit: 10 },
-        database: {
-          safeID: () => { return 'id'; }
-        }
-      });
-
-      FauxtonAPI.dispatch({
-        type: ActionTypes.EDIT_INDEX,
-        options: {
-          newView: false,
-          viewName: 'test-view',
-          designDocs: designDocs,
-          designDocId: designDoc._id
-        }
-      });
-    });
-
-    afterEach(() => {
-      store.reset();
-    });
-
-    it('DESIGN_DOC_CHANGE changes design doc id', () => {
-      const designDocId = 'another-one';
-      FauxtonAPI.dispatch({
-        type: ActionTypes.DESIGN_DOC_CHANGE,
-        options: {
-          value: designDocId
-        }
-      });
-      assert.equal(store.getDesignDocId(), designDocId);
-    });
-
-    it('only filters mango docs', () => {
-      const designDocs = store.getAvailableDesignDocs();
-      assert.equal(designDocs.length, 1);
-      assert.equal(designDocs[0], '_design/test-doc');
-    });
-  });
-
-  describe('EDIT_INDEX', () => {
-    let designDoc, designDocs;
-
-    beforeEach(() => {
-      designDoc = {
-        _id: '_design/test-doc',
-        views: {
-          'test-view': {
-            map: 'boom'
-          }
-        }
-      };
-
-      designDocs = new Documents.AllDocs([designDoc], {
-        params: { limit: 10 },
-        database: {
-          safeID: () => { return 'id';}
-        }
-      });
-
-    });
-
-    it('can set reduce for new design doc', () => {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.EDIT_INDEX,
-        options: {
-          newView: true,
-          newDesignDoc: true,
-          viewName: 'test-view',
-          designDocs: designDocs,
-          designDocId: undefined
-        }
-      });
-
-      FauxtonAPI.dispatch({
-        type: ActionTypes.SELECT_REDUCE_CHANGE,
-        reduceSelectedOption: '_sum'
-      });
-
-      assert.equal(store.getReduce(), '_sum');
-    });
-
-  });
-
-});
diff --git a/app/addons/documents/index-editor/actions.js b/app/addons/documents/index-editor/actions.js
index c25fa99d4..ad261e0d2 100644
--- a/app/addons/documents/index-editor/actions.js
+++ b/app/addons/documents/index-editor/actions.js
@@ -10,40 +10,40 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import app from "../../../app";
-import FauxtonAPI from "../../../core/api";
-import Documents from "../resources";
-import ActionTypes from "./actiontypes";
-import SidebarActions from "../sidebar/actions";
-
-function selectReduceChanged (reduceOption) {
-  FauxtonAPI.dispatch({
+import app from '../../../app';
+import FauxtonAPI from '../../../core/api';
+import Documents from '../resources';
+import ActionTypes from './actiontypes';
+import SidebarActions from '../sidebar/actions';
+
+const selectReduceChanged = (reduceOption) => (dispatch) => {
+  dispatch({
     type: ActionTypes.SELECT_REDUCE_CHANGE,
     reduceSelectedOption: reduceOption
   });
-}
+};
 
-function changeViewName (name) {
-  FauxtonAPI.dispatch({
+const changeViewName = (name) => (dispatch) => {
+  dispatch({
     type: ActionTypes.VIEW_NAME_CHANGE,
     name: name
   });
-}
+};
 
-function editIndex (options) {
-  FauxtonAPI.dispatch({
+const editIndex = (options) => (dispatch) => {
+  dispatch({
     type: ActionTypes.EDIT_INDEX,
     options: options
   });
-}
+};
 
-function clearIndex () {
-  FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX });
-}
+const dispatchClearIndex = () => {
+  FauxtonAPI.reduxDispatch({ type: ActionTypes.CLEAR_INDEX });
+};
 
-function fetchDesignDocsBeforeEdit (options) {
+const dispatchFetchDesignDocsBeforeEdit = (options) => {
   options.designDocs.fetch({reset: true}).then(() => {
-    this.editIndex(options);
+    editIndex(options)(FauxtonAPI.reduxDispatch);
   }, xhr => {
     let errorMsg = 'Error';
     if (xhr.responseJSON && xhr.responseJSON.error === 'not_found') {
@@ -57,16 +57,16 @@ function fetchDesignDocsBeforeEdit (options) {
       clear:  true
     });
   });
-}
+};
 
-function shouldRemoveDdocView(viewInfo) {
-  return !viewInfo.newView &&
+const shouldRemoveDdocView = (viewInfo) => {
+  return !viewInfo.isNewView &&
           viewInfo.originalDesignDocName === viewInfo.designDocId &&
           viewInfo.originalViewName !== viewInfo.viewName;
-}
+};
 
-function saveView (viewInfo) {
-  var designDoc = viewInfo.designDoc;
+const saveView = (viewInfo) => (dispatch) => {
+  const designDoc = viewInfo.designDoc;
   designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce);
 
   FauxtonAPI.addNotification({
@@ -89,8 +89,8 @@ function saveView (viewInfo) {
 
     // 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);
+    if (!viewInfo.isNewView && viewInfo.originalDesignDocName !== viewInfo.designDocId) {
+      const oldDesignDoc = findDesignDoc(viewInfo.designDocs, viewInfo.originalDesignDocName);
       safeDeleteIndex(oldDesignDoc, viewInfo.designDocs, 'views', viewInfo.originalViewName, {
         onSuccess: function () {
           SidebarActions.dispatchUpdateDesignDocs(viewInfo.designDocs);
@@ -102,8 +102,8 @@ function saveView (viewInfo) {
       addDesignDoc(designDoc);
     }
     SidebarActions.dispatchUpdateDesignDocs(viewInfo.designDocs);
-    FauxtonAPI.dispatch({ type: ActionTypes.VIEW_SAVED });
-    var fragment = FauxtonAPI.urls('view', 'showView', viewInfo.database.safeID(), designDoc.safeID(), app.utils.safeURLName(viewInfo.viewName));
+    dispatch({ type: ActionTypes.VIEW_SAVED });
+    const fragment = FauxtonAPI.urls('view', 'showView', viewInfo.database.safeID(), designDoc.safeID(), app.utils.safeURLName(viewInfo.viewName));
     FauxtonAPI.navigate(fragment, { trigger: true });
   }, (xhr) => {
     FauxtonAPI.addNotification({
@@ -112,16 +112,16 @@ function saveView (viewInfo) {
       clear: true
     });
   });
-}
+};
 
-function addDesignDoc (designDoc) {
-  FauxtonAPI.dispatch({
+const addDesignDoc = (designDoc) => (dispatch) => {
+  dispatch({
     type: ActionTypes.VIEW_ADD_DESIGN_DOC,
     designDoc: designDoc.toJSON()
   });
-}
+};
 
-function deleteView (options) {
+const deleteView = (options) => {
 
   function onSuccess () {
 
@@ -143,11 +143,11 @@ function deleteView (options) {
   }
 
   return safeDeleteIndex(options.designDoc, options.designDocs, 'views', options.indexName, { onSuccess: onSuccess });
-}
+};
 
-function cloneView (params) {
-  var targetDesignDoc = getDesignDoc(params.designDocs, params.targetDesignDocName, params.newDesignDocName, params.database);
-  var indexes = targetDesignDoc.get('views');
+const cloneView = (params) => {
+  const targetDesignDoc = getDesignDoc(params.designDocs, params.targetDesignDocName, params.newDesignDocName, params.database);
+  let indexes = targetDesignDoc.get('views');
   if (indexes && _.has(indexes, params.newIndexName)) {
     FauxtonAPI.addNotification({
       msg: 'That index name is already used in this design doc. Please enter a new name.',
@@ -159,14 +159,14 @@ function cloneView (params) {
   if (!indexes) {
     indexes = {};
   }
-  var sourceDesignDoc = findDesignDoc(params.designDocs, '_design/' + params.sourceDesignDocName);
-  var sourceDesignDocJSON = sourceDesignDoc.toJSON();
+  const sourceDesignDoc = findDesignDoc(params.designDocs, '_design/' + params.sourceDesignDocName);
+  const sourceDesignDocJSON = sourceDesignDoc.toJSON();
 
   // this sets whatever content is in the source index into the target design doc under the new index name
   indexes[params.newIndexName] = sourceDesignDocJSON.views[params.sourceIndexName];
   targetDesignDoc.set({ views: indexes });
 
-  targetDesignDoc.save().then(function () {
+  targetDesignDoc.save().then(() => {
     params.onComplete();
     FauxtonAPI.addNotification({
       msg: 'The index has been cloned.',
@@ -174,63 +174,62 @@ function cloneView (params) {
       clear: true
     });
     SidebarActions.dispatchUpdateDesignDocs(params.designDocs);
-  },
-  function (xhr) {
+  }, (xhr) => {
     params.onComplete();
-    var responseText = JSON.parse(xhr.responseText).reason;
+    const responseText = JSON.parse(xhr.responseText).reason;
     FauxtonAPI.addNotification({
       msg: 'Clone failed: ' + responseText,
       type: 'error',
       clear: true
     });
   });
-}
+};
 
-function gotoEditViewPage (databaseName, partitionKey, designDocName, indexName) {
+const gotoEditViewPage = (databaseName, partitionKey, designDocName, indexName) => {
   FauxtonAPI.navigate('#' + FauxtonAPI.urls('view', 'edit', encodeURIComponent(databaseName),
     (partitionKey ? encodeURIComponent(partitionKey) : ''),
     encodeURIComponent(designDocName), encodeURIComponent(indexName)));
-}
+};
 
-function updateMapCode (code) {
-  FauxtonAPI.dispatch({
+const updateMapCode = (code) => (dispatch) => {
+  dispatch({
     type: ActionTypes.VIEW_UPDATE_MAP_CODE,
     code: code
   });
-}
+};
 
-function updateReduceCode (code) {
-  FauxtonAPI.dispatch({
+const updateReduceCode = (code) => (dispatch) => {
+  dispatch({
     type: ActionTypes.VIEW_UPDATE_REDUCE_CODE,
     code: code
   });
-}
+};
 
-function selectDesignDoc (designDoc) {
-  FauxtonAPI.dispatch({
+const selectDesignDoc = (designDoc) => (dispatch) => {
+  dispatch({
     type: ActionTypes.DESIGN_DOC_CHANGE,
     options: {
       value: designDoc
     }
   });
-}
+};
 
-function updateNewDesignDocName (designDocName) {
-  FauxtonAPI.dispatch({
+const updateNewDesignDocName = (designDocName) => (dispatch) => {
+  dispatch({
     type: ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED,
     options: {
       value: designDocName
     }
   });
-}
+};
 
 // safely deletes an index of any type. It only deletes the actual design doc if there are no
 // other indexes of any type left in the doc
-function safeDeleteIndex (designDoc, designDocs, indexPropName, indexName, options) {
-  var opts = _.extend({
+const safeDeleteIndex = (designDoc, designDocs, indexPropName, indexName, options) => {
+  const opts = _.extend({
     onSuccess: function () { },
     onError: function (xhr) {
-      var responseText = JSON.parse(xhr.responseText).reason;
+      const responseText = JSON.parse(xhr.responseText).reason;
       FauxtonAPI.addNotification({
         msg: 'Delete failed: ' + responseText,
         type: 'error',
@@ -239,21 +238,21 @@ function safeDeleteIndex (designDoc, designDocs, indexPropName, indexName, optio
     }
   }, options);
 
-  var indexes = designDoc.get(indexPropName) || {};
+  const indexes = designDoc.get(indexPropName) || {};
   delete indexes[indexName];
-  var newIndexes = {};
+  const newIndexes = {};
   newIndexes[indexPropName] = indexes;
   designDoc.set(newIndexes);
 
   // we either save the design doc with the now-removed index, or we remove it altogether if there are no indexes
   // of any type left in the design doc
-  var indexTypePropNames = FauxtonAPI.getIndexTypePropNames();
-  var hasRemainingIndex = _.some(indexTypePropNames, function (propName) {
+  const indexTypePropNames = FauxtonAPI.getIndexTypePropNames();
+  const hasRemainingIndex = _.some(indexTypePropNames, function (propName) {
     return designDoc.get(propName) && _.keys(designDoc.get(propName)).length > 0;
   });
 
-  var promise;
-  var deleteDesignDoc = false;
+  let promise;
+  let deleteDesignDoc = false;
   if (hasRemainingIndex) {
     promise = designDoc.save();
   } else {
@@ -266,21 +265,21 @@ function safeDeleteIndex (designDoc, designDocs, indexPropName, indexName, optio
     }
     opts.onSuccess();
   }, opts.onError);
-}
+};
 
 
 
 // ---- helpers ----
 
-function findDesignDoc (designDocs, designDocName) {
+const findDesignDoc = (designDocs, designDocName) => {
   return designDocs.find(function (doc) {
     return doc.id === designDocName;
   }).dDocModel();
-}
+};
 
-function getDesignDoc (designDocs, targetDesignDocName, newDesignDocName, database) {
+const getDesignDoc = (designDocs, targetDesignDocName, newDesignDocName, database) => {
   if (targetDesignDocName === 'new-doc') {
-    var doc = {
+    const doc = {
       "_id": "_design/" + newDesignDocName,
       "views": {},
       "language": "javascript"
@@ -288,32 +287,32 @@ function getDesignDoc (designDocs, targetDesignDocName, newDesignDocName, databa
     return new Documents.Doc(doc, { database: database });
   }
 
-  var foundDoc = designDocs.find(function (ddoc) {
+  const foundDoc = designDocs.find(function (ddoc) {
     return ddoc.id === targetDesignDocName;
   });
   return (!foundDoc) ? null : foundDoc.dDocModel();
-}
+};
 
 
 export default {
   helpers: {
-    findDesignDoc: findDesignDoc,
-    getDesignDoc: getDesignDoc
+    findDesignDoc,
+    getDesignDoc
   },
-  safeDeleteIndex: safeDeleteIndex,
-  selectReduceChanged: selectReduceChanged,
-  changeViewName: changeViewName,
-  editIndex: editIndex,
-  clearIndex: clearIndex,
-  fetchDesignDocsBeforeEdit: fetchDesignDocsBeforeEdit,
-  shouldRemoveDdocView: shouldRemoveDdocView,
-  saveView: saveView,
-  addDesignDoc: addDesignDoc,
-  deleteView: deleteView,
-  cloneView: cloneView,
-  gotoEditViewPage: gotoEditViewPage,
-  updateMapCode: updateMapCode,
-  updateReduceCode: updateReduceCode,
-  selectDesignDoc: selectDesignDoc,
-  updateNewDesignDocName: updateNewDesignDocName
+  safeDeleteIndex,
+  selectReduceChanged,
+  changeViewName,
+  editIndex,
+  dispatchClearIndex,
+  dispatchFetchDesignDocsBeforeEdit,
+  shouldRemoveDdocView,
+  saveView,
+  addDesignDoc,
+  deleteView,
+  cloneView,
+  gotoEditViewPage,
+  updateMapCode,
+  updateReduceCode,
+  selectDesignDoc,
+  updateNewDesignDocName
 };
diff --git a/app/addons/documents/index-editor/components.js b/app/addons/documents/index-editor/components.js
index a96fab629..3cf69bd0e 100644
--- a/app/addons/documents/index-editor/components.js
+++ b/app/addons/documents/index-editor/components.js
@@ -10,15 +10,17 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import ReactComponents from "../../components/react-components";
+import ReactComponents from '../../components/react-components';
 import DesignDocSelector from './components/DesignDocSelector';
 import IndexEditor from './components/IndexEditor';
+import IndexEditorContainer from './components/IndexEditorContainer';
 import ReduceEditor from './components/ReduceEditor';
 
 const StyledSelect = ReactComponents.StyledSelect;
 
 export default {
-  EditorController: IndexEditor,
+  IndexEditorContainer,
+  IndexEditor,
   ReduceEditor,
   DesignDocSelector,
   StyledSelect
diff --git a/app/addons/documents/index-editor/components/DesignDocSelector.js b/app/addons/documents/index-editor/components/DesignDocSelector.js
index 956978f17..57c6bbcd8 100644
--- a/app/addons/documents/index-editor/components/DesignDocSelector.js
+++ b/app/addons/documents/index-editor/components/DesignDocSelector.js
@@ -11,11 +11,9 @@
 // the License.
 
 import PropTypes from 'prop-types';
-
-import React, { Component } from "react";
-import ReactDOM from "react-dom";
-import FauxtonAPI from "../../../../core/api";
-import ReactComponents from "../../../components/react-components";
+import React, { Component } from 'react';
+import FauxtonAPI from '../../../../core/api';
+import ReactComponents from '../../../components/react-components';
 
 const { StyledSelect } = ReactComponents;
 
diff --git a/app/addons/documents/index-editor/components/IndexEditor.js b/app/addons/documents/index-editor/components/IndexEditor.js
index 884858d07..332b74900 100644
--- a/app/addons/documents/index-editor/components/IndexEditor.js
+++ b/app/addons/documents/index-editor/components/IndexEditor.js
@@ -10,61 +10,27 @@
 // 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 PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import app from '../../../../app';
+import FauxtonAPI from '../../../../core/api';
+import ReactComponents from '../../../components/react-components';
 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) {
+  componentDidUpdate(prevProps) {
+    if (this.props.map !== prevProps.map && this.mapEditor) {
       this.mapEditor.update();
     }
   }
@@ -76,31 +42,31 @@ export default class IndexEditor extends Component {
       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,
+    this.props.saveView({
+      database: this.props.database,
+      isNewView: this.props.isNewView,
+      viewName: this.props.viewName,
+      designDoc: this.props.saveDesignDoc,
+      designDocId: this.props.designDocId,
+      isNewDesignDoc: this.props.isNewDesignDoc,
+      originalViewName: this.props.originalViewName,
+      originalDesignDocName: this.props.originalDesignDocName,
       map: this.mapEditor.getValue(),
       reduce: this.reduceEditor.getReduceValue(),
-      designDocs: this.state.designDocs
+      designDocs: this.props.designDocs
     });
   }
 
   viewChange(el) {
-    Actions.changeViewName(el.target.value);
+    this.props.changeViewName(el.target.value);
   }
 
   updateMapCode(code) {
-    Actions.updateMapCode(code);
+    this.props.updateMapCode(code);
   }
 
   render() {
-    if (this.state.isLoading) {
+    if (this.props.isLoading) {
       return (
         <div className="define-view">
           <LoadLines />
@@ -108,9 +74,9 @@ export default class IndexEditor extends Component {
       );
     }
 
-    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);
+    const pageHeader = (this.props.isNewView) ? 'New View' : 'Edit View';
+    const btnLabel = (this.props.isNewView) ? 'Create Document and then Build Index' : 'Save Document and then Build Index';
+    const cancelLink = '#' + FauxtonAPI.urls('view', 'showView', this.props.database.id, this.props.designDocId, this.props.viewName);
     return (
       <div className="define-view" >
         <form className="form-horizontal view-query-save" onSubmit={this.saveView.bind(this)}>
@@ -119,11 +85,11 @@ export default class IndexEditor extends Component {
           <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}
+              designDocList={this.props.designDocList}
+              selectedDesignDocName={this.props.designDocId}
+              newDesignDocName={this.props.newDesignDocName}
+              onSelectDesignDoc={this.props.selectDesignDoc}
+              onChangeNewDesignDocName={this.props.updateNewDesignDocName}
               docLink={getDocUrl('DESIGN_DOCS')} />
           </div>
 
@@ -142,7 +108,7 @@ export default class IndexEditor extends Component {
             <input
               type="text"
               id="index-name"
-              value={this.state.viewName}
+              value={this.props.viewName}
               onChange={this.viewChange.bind(this)}
               placeholder="Index name" />
           </div>
@@ -153,8 +119,8 @@ export default class IndexEditor extends Component {
             docLink={getDocUrl('MAP_FUNCS')}
             blur={this.updateMapCode.bind(this)}
             allowZenMode={false}
-            defaultCode={this.state.map} />
-          <ReduceEditor ref={(el) => { this.reduceEditor = el; }} />
+            defaultCode={this.props.map} />
+          <ReduceEditor ref={(el) => { this.reduceEditor = el; }} {...this.props} />
           <div className="padded-box">
             <div className="control-group">
               <ConfirmButton id="save-view" text={btnLabel} />
@@ -166,3 +132,19 @@ export default class IndexEditor extends Component {
     );
   }
 }
+
+IndexEditor.propTypes = {
+  isLoading:PropTypes.bool.isRequired,
+  isNewView: PropTypes.bool.isRequired,
+  database: PropTypes.object.isRequired,
+  designDocId: PropTypes.string.isRequired,
+  viewName: PropTypes.string.isRequired,
+  isNewDesignDoc: PropTypes.bool.isRequired,
+  originalViewName: PropTypes.string,
+  originalDesignDocName: PropTypes.string,
+  designDocs: PropTypes.object,
+  saveDesignDoc: PropTypes.object,
+  updateNewDesignDocName: PropTypes.func.isRequired,
+  changeViewName: PropTypes.func.isRequired,
+  updateMapCode: PropTypes.func.isRequired
+};
diff --git a/app/addons/documents/index-editor/components/IndexEditorContainer.js b/app/addons/documents/index-editor/components/IndexEditorContainer.js
new file mode 100644
index 000000000..445b02954
--- /dev/null
+++ b/app/addons/documents/index-editor/components/IndexEditorContainer.js
@@ -0,0 +1,78 @@
+// 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 IndexEditor from './IndexEditor';
+import Actions from '../actions';
+import { getSaveDesignDoc, getDesignDocIds, reduceSelectedOption, hasCustomReduce } from '../reducers';
+
+const mapStateToProps = ({ indexEditor }) => {
+  return {
+    database: indexEditor.database,
+    isNewView: indexEditor.isNewView,
+    viewName: indexEditor.viewName,
+    designDocs: indexEditor.designDocs,
+    designDocList: getDesignDocIds(indexEditor),
+    originalViewName: indexEditor.originalViewName,
+    originalDesignDocName: indexEditor.originalDesignDocName,
+    isNewDesignDoc: indexEditor.isNewDesignDoc,
+    designDocId: indexEditor.designDocId,
+    newDesignDocName: indexEditor.newDesignDocName,
+    saveDesignDoc: getSaveDesignDoc(indexEditor),
+    map: indexEditor.view.map,
+    isLoading: indexEditor.isLoading,
+    reduce: indexEditor.view.reduce,
+    reduceOptions: indexEditor.reduceOptions,
+    reduceSelectedOption: reduceSelectedOption(indexEditor),
+    hasCustomReduce: hasCustomReduce(indexEditor),
+    hasReduce: !!indexEditor.view.reduce
+  };
+};
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    saveView: (viewInfo) => {
+      dispatch(Actions.saveView(viewInfo));
+    },
+
+    changeViewName: (name) => {
+      dispatch(Actions.changeViewName(name));
+    },
+
+    updateMapCode: (code) => {
+      dispatch(Actions.updateMapCode(code));
+    },
+
+    selectDesignDoc: (designDoc) => {
+      dispatch(Actions.selectDesignDoc(designDoc));
+    },
+
+    updateNewDesignDocName: (designDocName) => {
+      dispatch(Actions.updateNewDesignDocName(designDocName));
+    },
+
+    updateReduceCode: (code) => {
+      dispatch(Actions.updateReduceCode(code));
+    },
+
+    selectReduceChanged: (reduceOption) => {
+      dispatch(Actions.selectReduceChanged(reduceOption));
+    }
+  };
+};
+
+const IndexEditorContainer = connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(IndexEditor);
+
+export default IndexEditorContainer;
diff --git a/app/addons/documents/index-editor/components/ReduceEditor.js b/app/addons/documents/index-editor/components/ReduceEditor.js
index 7e0b1815b..7f1df5255 100644
--- a/app/addons/documents/index-editor/components/ReduceEditor.js
+++ b/app/addons/documents/index-editor/components/ReduceEditor.js
@@ -10,59 +10,33 @@
 // 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";
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import app from '../../../../app';
+import ReactComponents from '../../../components/react-components';
 
 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, (reduce, i) => {
+    return this.props.reduceOptions.map((reduce, i) => {
       return <option key={i} value={reduce}>{reduce}</option>;
     });
   }
 
   getReduceValue() {
-    if (!this.state.hasReduce) {
+    if (!this.props.hasReduce) {
       return null;
     }
 
-    if (!this.state.hasCustomReduce) {
-      return this.state.reduce;
+    if (!this.props.hasCustomReduce) {
+      return this.props.reduce;
     }
 
     return this.reduceEditor.getValue();
@@ -73,23 +47,23 @@ export default class ReduceEditor extends Component {
   }
 
   updateReduceCode(code) {
-    Actions.updateReduceCode(code);
+    this.props.updateReduceCode(code);
   }
 
   selectChange(event) {
-    Actions.selectReduceChanged(event.target.value);
+    this.props.selectReduceChanged(event.target.value);
   }
 
   render() {
     const reduceOptions = this.getOptionsList();
     let customReduceSection;
 
-    if (this.state.hasCustomReduce) {
+    if (this.props.hasCustomReduce) {
       customReduceSection = <CodeEditorPanel
         ref={node => this.reduceEditor = node}
         id='reduce-function'
         title={'Custom Reduce function'}
-        defaultCode={this.state.reduce}
+        defaultCode={this.props.reduce}
         allowZenMode={false}
         blur={this.updateReduceCode.bind(this)}
       />;
@@ -114,10 +88,20 @@ export default class ReduceEditor extends Component {
             selectContent={reduceOptions}
             selectChange={this.selectChange.bind(this)}
             selectId="reduce-function-selector"
-            selectValue={this.state.reduceSelectedOption} />
+            selectValue={this.props.reduceSelectedOption} />
         </div>
         {customReduceSection}
       </div>
     );
   }
 }
+
+ReduceEditor.propTypes = {
+  reduceOptions: PropTypes.array.isRequired,
+  hasReduce: PropTypes.bool.isRequired,
+  hasCustomReduce: PropTypes.bool.isRequired,
+  reduce: PropTypes.string,
+  reduceSelectedOption: PropTypes.string.isRequired,
+  updateReduceCode: PropTypes.func.isRequired,
+  selectReduceChanged: PropTypes.func.isRequired
+};
diff --git a/app/addons/documents/index-editor/reducers.js b/app/addons/documents/index-editor/reducers.js
new file mode 100644
index 000000000..663818fca
--- /dev/null
+++ b/app/addons/documents/index-editor/reducers.js
@@ -0,0 +1,196 @@
+// 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 ActionTypes from './actiontypes';
+import Resources from "../resources";
+
+const defaultMap = 'function (doc) {\n  emit(doc._id, 1);\n}';
+const defaultReduce = 'function (keys, values, rereduce) {\n  if (rereduce) {\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}';
+const builtInReducers = ['_sum', '_count', '_stats'];
+
+const initialState = {
+  designDocs: new Backbone.Collection(),
+  isLoading: true,
+  view: { reduce: '', map: defaultMap },
+  database: { id: '0' },
+  designDocId: '',
+  isNewDesignDoc: false,
+  newDesignDocName: '',
+  isNewView: false,
+  viewName: '',
+  originalViewName: '',
+  originalDesignDocName: '',
+  reduceOptions: builtInReducers.concat(['CUSTOM', 'NONE'])
+};
+
+function editIndex(state, options) {
+  const newState = {
+    ...state,
+    isLoading: false,
+    newDesignDocName: '',
+    isNewView: options.isNewView,
+    viewName: options.viewName || 'viewName',
+    isNewDesignDoc: options.isNewDesignDoc || false,
+    designDocs: options.designDocs,
+    designDocId: options.designDocId,
+    originalDesignDocName: options.designDocId,
+    database: options.database
+  };
+  newState.originalViewName = newState.viewName;
+  newState.view = getView(newState);
+  return newState;
+}
+
+function getView(state) {
+  if (state.isNewView || state.isNewDesignDoc) {
+    return { reduce: '', map: defaultMap };
+  }
+
+  const designDoc = state.designDocs.find(ddoc => {
+    return state.designDocId == ddoc.id;
+  }).dDocModel();
+  return designDoc.get('views')[state.viewName];
+}
+
+export function reduceSelectedOption(state) {
+  if (!state.view.reduce) {
+    return 'NONE';
+  }
+  if (hasCustomReduce(state)) {
+    return 'CUSTOM';
+  }
+  return state.view.reduce;
+}
+
+export function hasCustomReduce(state) {
+  if (state.view.reduce) {
+    return !builtInReducers.includes(state.view.reduce);
+  }
+  return false;
+}
+
+export function getSaveDesignDoc(state) {
+  if (state.designDocId === 'new-doc') {
+    const doc = {
+      _id: '_design/' + state.newDesignDocName,
+      views: {},
+      language: 'javascript'
+    };
+    return new Resources.Doc(doc, { database: state.database });
+  }
+
+  if (!state.designDocs) {
+    return null;
+  }
+
+  const foundDoc = state.designDocs.find(ddoc => {
+    return ddoc.id === state.designDocId;
+  });
+
+  return foundDoc ? foundDoc.dDocModel() : null;
+}
+
+// returns a simple array of design doc IDs. Omits mango docs
+export function getDesignDocIds(state) {
+  if (!state.designDocs) {
+    return [];
+  }
+  return state.designDocs.filter(doc => {
+    return !doc.isMangoDoc();
+  }).map(doc => {
+    return doc.id;
+  });
+}
+
+export default function indexEditor(state = initialState, action) {
+  const { options } = action;
+  switch (action.type) {
+
+    case ActionTypes.CLEAR_INDEX:
+      return {
+        ...initialState
+      };
+
+    case ActionTypes.EDIT_INDEX:
+      return editIndex(state, options);
+
+    case ActionTypes.EDIT_NEW_INDEX:
+      return editIndex(state, options);
+
+    case ActionTypes.VIEW_NAME_CHANGE:
+      return {
+        ...state,
+        viewName: action.name
+      };
+
+    case ActionTypes.SELECT_REDUCE_CHANGE:
+      let newReduce = action.reduceSelectedOption;
+      if (newReduce === 'NONE') {
+        newReduce = '';
+      }
+      if (newReduce === 'CUSTOM') {
+        newReduce = defaultReduce;
+      }
+      return {
+        ...state,
+        view: {
+          ...state.view,
+          reduce: newReduce
+        }
+      };
+
+    case ActionTypes.DESIGN_DOC_CHANGE:
+      return {
+        ...state,
+        designDocId: options.value
+      };
+
+    case ActionTypes.VIEW_SAVED:
+      return state;
+
+    case ActionTypes.VIEW_CREATED:
+      return state;
+
+    case ActionTypes.VIEW_ADD_DESIGN_DOC:
+      return {
+        ...state,
+        designDocId: action.designDoc._id
+      };
+
+    case ActionTypes.VIEW_UPDATE_MAP_CODE:
+      return {
+        ...state,
+        view: {
+          ...state.view,
+          map: action.code
+        }
+      };
+
+    case ActionTypes.VIEW_UPDATE_REDUCE_CODE:
+      return {
+        ...state,
+        view: {
+          ...state.view,
+          reduce: action.code
+        }
+      };
+
+    case ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED:
+      return {
+        ...state,
+        newDesignDocName: options.value
+      };
+
+    default:
+      return state;
+  }
+}
diff --git a/app/addons/documents/index-editor/stores.js b/app/addons/documents/index-editor/stores.js
deleted file mode 100644
index c5b620554..000000000
--- a/app/addons/documents/index-editor/stores.js
+++ /dev/null
@@ -1,264 +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 Resources from "../resources";
-var Stores = {};
-
-Stores.IndexEditorStore = FauxtonAPI.Store.extend({
-
-  defaultMap: 'function (doc) {\n  emit(doc._id, 1);\n}',
-  defaultReduce: 'function (keys, values, rereduce) {\n  if (rereduce) {\n    return sum(values);\n  } else {\n    return values.length;\n  }\n}',
-
-  initialize: function () {
-    this.reset();
-  },
-
-  reset: function () {
-    this._designDocs = [];
-    this._isLoading = true;
-    this._view = { reduce: '', map: this.defaultMap };
-    this._database = { id: '0' };
-  },
-
-  editIndex: function (options) {
-    this._database = options.database;
-    this._newView = options.newView;
-    this._viewName = options.viewName || 'viewName';
-    this._newDesignDoc = options.newDesignDoc || false;
-    this._newDesignDocName = '';
-    this._designDocs = options.designDocs;
-    this._designDocId = options.designDocId;
-    this._originalViewName = this._viewName;
-    this._originalDesignDocName = options.designDocId;
-    this.setView();
-
-    this._isLoading = false;
-  },
-
-  isLoading: function () {
-    return this._isLoading;
-  },
-
-  setView: function () {
-    if (this._newView || this._newDesignDoc) {
-      this._view = { reduce: '', map: this.defaultMap };
-    } else {
-      this._view = this.getDesignDoc().get('views')[this._viewName];
-    }
-  },
-
-  getDatabase: function () {
-    return this._database;
-  },
-
-  getMap: function () {
-    return this._view.map;
-  },
-
-  setMap: function (map) {
-    this._view.map = map;
-  },
-
-  getReduce: function () {
-    return this._view.reduce;
-  },
-
-  setReduce: function (reduce) {
-    this._view.reduce = reduce;
-  },
-
-  getDesignDoc: function () {
-    return this._designDocs.find((ddoc) => {
-      return this._designDocId == ddoc.id;
-    }).dDocModel();
-  },
-
-  getDesignDocs: function () {
-    return this._designDocs;
-  },
-
-  // returns a simple array of design doc IDs. Omits mango docs
-  getAvailableDesignDocs: function () {
-    var availableDocs = this.getDesignDocs().filter(function (doc) {
-      return !doc.isMangoDoc();
-    });
-    return _.map(availableDocs, function (doc) {
-      return doc.id;
-    });
-  },
-
-  getDesignDocId: function () {
-    return this._designDocId;
-  },
-
-  setDesignDocId: function (designDocId) {
-    this._designDocId = designDocId;
-  },
-
-  isNewDesignDoc: function () {
-    return this._newDesignDoc;
-  },
-
-  isNewView: function () {
-    return this._newView;
-  },
-
-  getViewName: function () {
-    return this._viewName;
-  },
-
-  setViewName: function (name) {
-    this._viewName = name;
-  },
-
-  hasCustomReduce: function () {
-    if (!this.hasReduce()) {
-      return false;
-    }
-    return !_.includes(this.builtInReduces(), this.getReduce());
-  },
-
-  hasReduce: function () {
-    if (!this.getReduce()) {
-      return false;
-    }
-    return true;
-  },
-
-  getOriginalViewName: function () {
-    return this._originalViewName;
-  },
-
-  getOriginalDesignDocName: function () {
-    return this._originalDesignDocName;
-  },
-
-  builtInReduces: function () {
-    return ['_sum', '_count', '_stats'];
-  },
-
-  reduceSelectedOption: function () {
-    if (!this.hasReduce()) {
-      return 'NONE';
-    }
-    if (this.hasCustomReduce()) {
-      return 'CUSTOM';
-    }
-    return this.getReduce();
-  },
-
-  reduceOptions: function () {
-    return this.builtInReduces().concat(['CUSTOM', 'NONE']);
-  },
-
-  updateReduceFromSelect: function (selectedReduce) {
-    if (selectedReduce === 'NONE') {
-      this.setReduce(null);
-      return;
-    }
-    if (selectedReduce === 'CUSTOM') {
-      this.setReduce(this.defaultReduce);
-      return;
-    }
-    this.setReduce(selectedReduce);
-  },
-
-  addDesignDoc: function (designDoc) {
-    this._designDocs.add(designDoc, { merge: true });
-    this._designDocId = designDoc._id;
-  },
-
-  getNewDesignDocName: function () {
-    return this._newDesignDocName;
-  },
-
-  getSaveDesignDoc: function () {
-    if (this._designDocId === 'new-doc') {
-      var doc = {
-        _id: '_design/' + this._newDesignDocName,
-        views: {},
-        language: 'javascript'
-      };
-      return new Resources.Doc(doc, { database: this._database });
-    }
-
-    var foundDoc = this._designDocs.find(function (ddoc) {
-      return ddoc.id === this._designDocId;
-    }.bind(this));
-
-    return (!foundDoc) ? null : foundDoc.dDocModel();
-  },
-
-  dispatch: function (action) {
-    switch (action.type) {
-      case ActionTypes.CLEAR_INDEX:
-        this.reset();
-        break;
-
-      case ActionTypes.EDIT_INDEX:
-        this.editIndex(action.options);
-        break;
-
-      case ActionTypes.VIEW_NAME_CHANGE:
-        this.setViewName(action.name);
-        break;
-
-      case ActionTypes.EDIT_NEW_INDEX:
-        this.editIndex(action.options);
-        break;
-
-      case ActionTypes.SELECT_REDUCE_CHANGE:
-        this.updateReduceFromSelect(action.reduceSelectedOption);
-        break;
-
-      case ActionTypes.DESIGN_DOC_CHANGE:
-        this.setDesignDocId(action.options.value);
-        break;
-
-      case ActionTypes.VIEW_SAVED:
-        break;
-
-      case ActionTypes.VIEW_CREATED:
-        break;
-
-      case ActionTypes.VIEW_ADD_DESIGN_DOC:
-        this.addDesignDoc(action.designDoc);
-        this.setView();
-        break;
-
-      case ActionTypes.VIEW_UPDATE_MAP_CODE:
-        this.setMap(action.code);
-        break;
-
-      case ActionTypes.VIEW_UPDATE_REDUCE_CODE:
-        this.setReduce(action.code);
-        break;
-
-      case ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED:
-        this._newDesignDocName = action.options.value;
-        break;
-
-      default:
-        return;
-    }
-
-    this.triggerChange();
-  }
-
-});
-
-Stores.indexEditorStore = new Stores.IndexEditorStore();
-Stores.indexEditorStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.indexEditorStore.dispatch.bind(Stores.indexEditorStore));
-
-export default Stores;
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index 4be1d2072..7f91c8e12 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -247,7 +247,7 @@ export const ViewsTabsSidebarLayout = ({showEditView, database, docURL, endpoint
   dbName, dropDownLinks, selectedNavItem, designDocInfo, partitionKey }) => {
 
   const content = showEditView ?
-    <IndexEditorComponents.EditorController /> :
+    <IndexEditorComponents.IndexEditorContainer /> :
     <DesignDocInfoContainer
       designDocInfo={designDocInfo}
       designDocName={selectedNavItem.designDocName}/>;
diff --git a/app/addons/documents/routes-index-editor.js b/app/addons/documents/routes-index-editor.js
index 8d357ba7e..bfe9c42ba 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -74,10 +74,10 @@ const IndexEditorAndResults = BaseRoute.extend({
   showView: function (databaseName, partitionKey, ddoc, viewName) {
     viewName = viewName.replace(/\?.*$/, '');
 
-    ActionsIndexEditor.clearIndex();
-    ActionsIndexEditor.fetchDesignDocsBeforeEdit({
+    ActionsIndexEditor.dispatchClearIndex();
+    ActionsIndexEditor.dispatchFetchDesignDocsBeforeEdit({
       viewName: viewName,
-      newView: false,
+      isNewView: false,
       database: this.database,
       designDocs: this.designDocs,
       designDocId: '_design/' + ddoc
@@ -127,21 +127,21 @@ const IndexEditorAndResults = BaseRoute.extend({
   },
 
   createView: function (database, partitionKey, _designDoc) {
-    let newDesignDoc = true;
+    let isNewDesignDoc = true;
     let designDoc = 'new-doc';
 
     if (_designDoc) {
       designDoc = '_design/' + _designDoc;
-      newDesignDoc = false;
+      isNewDesignDoc = false;
     }
 
-    ActionsIndexEditor.fetchDesignDocsBeforeEdit({
+    ActionsIndexEditor.dispatchFetchDesignDocsBeforeEdit({
       viewName: 'new-view',
-      newView: true,
+      isNewView: true,
       database: this.database,
       designDocs: this.designDocs,
       designDocId: designDoc,
-      newDesignDoc: newDesignDoc
+      isNewDesignDoc: isNewDesignDoc
     });
 
     const selectedNavItem = new SidebarItemSelection('');
@@ -163,9 +163,9 @@ const IndexEditorAndResults = BaseRoute.extend({
   },
 
   editView: function (databaseName, partitionKey, ddocName, viewName) {
-    ActionsIndexEditor.fetchDesignDocsBeforeEdit({
+    ActionsIndexEditor.dispatchFetchDesignDocsBeforeEdit({
       viewName: viewName,
-      newView: false,
+      isNewView: false,
       database: this.database,
       designDocs: this.designDocs,
       designDocId: '_design/' + ddocName


 

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


With regards,
Apache Git Services