Update Views

This is a big update to the Views pages.
- now uses standard 2 panel layout for adding/editing/viewing
Views (includes the sidebar)
- New menu added to all Views, containing [Edit, Clone, Delete]
options. Clone and Delete are their own modals. This modal is
extensible, so can be used for different types of indexes added
via extensions.
- sidebar now properly selects views and highlights them to
show current location + view.
- Renaming a view no longer creates a second view, just renames
it. The clone feature lets you copy/clone a View. It also properly
removes the old view from the old location, be it a separate
design doc or the current one. If it removes it from another
design doc, it deletes the old design doc if it's empty.
- Auto-deleting logic of design docs has been rewritten. Before,
we were overloading the hasViews() method on the backbone object
to determine if the design doc was now empty (this didn't
actually work, btw). Now any code that extends Fauxton's index
types, registers the design doc properly name for the index
groups. That is then used in the deletion code to properly
identify an empty design doc.

N.B. the new menu uses React Bootstrap so it's very similar
but not identical to our current menu dropdowns. The latter
will be replaced in subsquent PRs.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/3ff6ff62
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/3ff6ff62
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/3ff6ff62

Branch: refs/heads/master
Commit: 3ff6ff622bf22bc019a585b8285e03af94ec0650
Parents: c1ea1b6
Author: Ben Keen <ben.k...@gmail.com>
Authored: Wed Feb 17 17:10:42 2016 -0800
Committer: Ben Keen <ben.k...@gmail.com>
Committed: Fri Mar 18 11:51:44 2016 -0700

----------------------------------------------------------------------
 app/addons/components/assets/less/docs.less     |   4 +
 .../components/react-components.react.jsx       |   2 +-
 app/addons/components/stores.js                 |   1 -
 app/addons/documents/assets/less/documents.less |   1 +
 app/addons/documents/assets/less/sidenav.less   |  95 ++++-
 .../documents/assets/less/view-editor.less      |  52 +--
 app/addons/documents/base.js                    |  20 +-
 app/addons/documents/index-editor/actions.js    | 354 +++++++++++++------
 .../documents/index-editor/actiontypes.js       |   2 +-
 .../documents/index-editor/components.react.jsx | 222 +++++-------
 app/addons/documents/index-editor/stores.js     |  52 +--
 .../documents/index-editor/tests/actionsSpec.js |  93 +++--
 .../documents/index-editor/tests/storesSpec.js  |   4 +-
 .../tests/viewIndex.componentsSpec.react.jsx    |   3 +-
 app/addons/documents/index-results/stores.js    |   2 +-
 .../index-results.componentsSpec.react.jsx      |   2 +-
 .../documents/mango/mango.components.react.jsx  |   4 +-
 app/addons/documents/routes-documents.js        |   4 +-
 app/addons/documents/routes-index-editor.js     |  88 +++--
 app/addons/documents/shared-resources.js        |  32 --
 app/addons/documents/sidebar/actions.js         | 170 ++++++---
 app/addons/documents/sidebar/actiontypes.js     |  10 +-
 app/addons/documents/sidebar/sidebar.react.jsx  | 302 ++++++++++++++--
 app/addons/documents/sidebar/stores.js          | 191 ----------
 app/addons/documents/sidebar/stores.react.jsx   | 345 ++++++++++++++++++
 .../tests/sidebar.componentsSpec.react.jsx      |  55 ++-
 .../sidebar/tests/sidebar.storesSpec.js         |   2 +-
 .../tests/nightwatch/deletesDocuments.js        |   2 +-
 .../tests/nightwatch/doubleEmitResults.js       |   2 +-
 .../tests/nightwatch/previousButton.js          |  20 +-
 .../documents/tests/nightwatch/viewClone.js     |  37 ++
 .../documents/tests/nightwatch/viewCreate.js    |  17 +-
 .../documents/tests/nightwatch/viewDelete.js    |  40 +++
 .../documents/tests/nightwatch/viewEdit.js      | 159 ++++++---
 .../tests/nightwatch/viewQueryOptions.js        |  14 +-
 app/addons/fauxton/components.react.jsx         |  13 +-
 app/addons/permissions/routes.js                |   7 +-
 app/core/api.js                                 |   8 +
 assets/less/fauxton.less                        |   8 +
 39 files changed, 1605 insertions(+), 834 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/components/assets/less/docs.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/docs.less 
b/app/addons/components/assets/less/docs.less
index 04b79f8..d5020c6 100644
--- a/app/addons/components/assets/less/docs.less
+++ b/app/addons/components/assets/less/docs.less
@@ -61,6 +61,10 @@
   }
 }
 
+.view #doc-list {
+  padding-top: 12px;
+}
+
 .show-select {
   #doc-list {
     padding: 0px 0 30px 0;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx 
b/app/addons/components/react-components.react.jsx
index 6ff8c97..f43f0c1 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -369,7 +369,7 @@ function (app, FauxtonAPI, React, ReactDOM, Actions, 
Stores, FauxtonComponents,
       return (
         <div className={classes}>
           <label>
-            <strong>{this.props.title + ' '}</strong>
+            <span>{this.props.title}</span>
             {this.getDocIcon()}
             {this.getZenModeIcon()}
           </label>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/components/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/components/stores.js b/app/addons/components/stores.js
index 6da96af..fafb76c 100644
--- a/app/addons/components/stores.js
+++ b/app/addons/components/stores.js
@@ -19,7 +19,6 @@ define([
 function (FauxtonAPI, app, ActionTypes) {
   var Stores = {};
 
-
   Stores.ComponentStore = FauxtonAPI.Store.extend({
     initialize: function () {
       this.reset();

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/assets/less/documents.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/documents.less 
b/app/addons/documents/assets/less/documents.less
index 77ab9d2..e068946 100644
--- a/app/addons/documents/assets/less/documents.less
+++ b/app/addons/documents/assets/less/documents.less
@@ -71,6 +71,7 @@ button.beautify {
   }
   #new-ddoc-section {
     margin-top: 10px;
+    width: 325px;
     label {
       width: 100px
     }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/assets/less/sidenav.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/sidenav.less 
b/app/addons/documents/assets/less/sidenav.less
index 9c6fb35..fb46c22 100644
--- a/app/addons/documents/assets/less/sidenav.less
+++ b/app/addons/documents/assets/less/sidenav.less
@@ -10,6 +10,8 @@
 // License for the specific language governing permissions and limitations 
under
 // the License.
 @import "../../../../../assets/less/variables.less";
+@import "../../../../../assets/less/mixins.less";
+
 
 #sidebar-content {
   .loading-lines {
@@ -39,7 +41,8 @@
   // ugly! This styles the (+) icon to make it white when a user hovers over a 
row. Better solution would be to move the
   // active class to the <li> instead of the child <a>
   .accordion-list-item:hover, .nav-list > li a:hover {
-    & + div.add-dropdown .dropdown-toggle {
+    & + div.add-dropdown .dropdown-toggle,
+    & + span.index-menu-toggle {
       color: white;
     }
   }
@@ -160,4 +163,94 @@
   .index-group-header {
     font-weight: bold;
   }
+
+  li.nav-header .index-menu-toggle.fonticon {
+    position: absolute;
+    top: 0;
+    right: 0;
+    color: #767f89;
+    height: 30px;
+    width: 40px;
+    padding-top: 2px;
+    padding-left: 4px;
+    .transition(all 0.25s linear);
+    &:hover {
+      color: @linkColor;
+    }
+    &:before {
+      font-size: 17px;
+      margin-right: 0;
+    }
+  }
+}
+
+#index-menu-component-popover {
+  .border-radius(0);
+  .box-shadow(2px 2px rgba(0, 0, 0, 0.2));
+  background-color: black;
+  color: #dddddd;
+  font-size: 12px;
+  padding: 0;
+  margin-left: -7px;
+  margin-top: 5px;
+  ul {
+    list-style-type: none;
+    margin: 0;
+  }
+  li {
+    padding: 10px;
+    background-color: #202326;
+    margin-bottom: 2px;
+    cursor: pointer;
+    .transition(all 0.25s linear);
+    &:hover {
+      background-color: @brandPrimaryDark;
+    }
+    &:last-child {
+      margin-bottom: 0;
+    }
+  }
+  .arrow {
+    &:after {
+      border-bottom-color: black;
+      border-top-color: black;
+    }
+  }
+  .fonticon {
+    margin-right: 7px;
+  }
+  .popover-content {
+    padding: 0;
+  }
+}
+
+.clone-index-modal {
+  .modal-body {
+    padding: 20px;
+  }
+  /* the index label ("view" / "search index", etc.) is passed dynamically to 
the clone index modal. This fixes the text case */
+  .modal-title, .btn-success, .new-index-title-label {
+    text-transform: capitalize;
+  }
+  .styled-select, select {
+    width: 230px;
+  }
+  .row {
+    margin: 0;
+    padding-top: 10px;
+    #new-ddoc-section {
+      width: 262px;
+
+      label {
+        width: 40px;
+        margin-top: 27px;
+        float: left;
+      }
+      div.controls {
+        margin-left: 0;
+        float: right;
+        margin-top: 15px;
+      }
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/assets/less/view-editor.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/view-editor.less 
b/app/addons/documents/assets/less/view-editor.less
index 51bca44..de76655 100644
--- a/app/addons/documents/assets/less/view-editor.less
+++ b/app/addons/documents/assets/less/view-editor.less
@@ -12,18 +12,24 @@
 
 @import "../../../../../assets/less/variables.less";
 
-.editor-wrapper {
-  .define-view {
-    padding-bottom: 70px;
+.define-view {
+  padding: 15px;
+  .help-link {
+    margin-left: 4px;
   }
-  .define-view {
-    .help-link {
-      margin-left: 3px;
+  .design-doc-group #new-ddoc-section {
+    margin-top: 24px;
+    label {
+      padding-top: 12px;
     }
   }
+}
+
+/* to remove once Mango has moved to the standard 2-panel layout */
+.mango-editor-wrapper {
   label {
     font-size: 16px;
-    margin-right: 0px;
+    margin-right: 0;
   }
   .bordered-box {
     border-bottom: 1px solid #ccc;
@@ -52,13 +58,11 @@
   a.edit-link {
     float: right;
   }
+  .help-link {
+    margin-left: 4px;
+  }
 }
 
-body .view-query-save .control-group {
-  margin-bottom: 0;
-}
-
-
 // 940px grid without margin
 // -------------------------
 @gridColumnWidthNoMargin:         60px;
@@ -218,25 +222,7 @@ body .view-query-save .control-group {
   }
 }
 
-
-/* temporary CSS overrides. This will be removed once the Views is moved to 
the standard 2-panel layout */
-.define-view .new-ddoc-section {
-  .span5 {
-    .label {
-      display: none;
-    }
-    .control-label {
-      display: none;
-    }
-  }
-  .span3 span {
-    font-weight: bold;
-  }
-  #new-ddoc-section {
-    margin: 16px 0 0;
-    .controls {
-      margin-left: 0;
-    }
-  }
+.index-cancel-link {
+  margin-left: 10px;
+  font-size: 14px;
 }
-/* end temporary override */

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/base.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index 75620e5..7734c17 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -55,24 +55,28 @@ function (app, FauxtonAPI, Documents) {
   });
 
   FauxtonAPI.registerUrls( 'view', {
-    server: function (id, designDoc, viewName) {
-      return app.host + '/' + id + '/_design/' + designDoc + '/_view/' + 
viewName;
+    server: function (database, designDoc, viewName) {
+      return app.host + '/' + database + '/_design/' + designDoc + '/_view/' + 
viewName;
     },
 
-    app: function (id, designDoc) {
-      return 'database/' + id + '/_design/' + designDoc + '/_view/';
+    app: function (database, designDoc) {
+      return 'database/' + database + '/_design/' + designDoc + '/_view/';
     },
 
     apiurl: function (id, designDoc, viewName) {
       return window.location.origin + '/' + id + '/_design/' + designDoc + 
'/_view/' + viewName;
     },
 
-    showNewlySavedView: function (database, designDocs, viewName) {
-      return '/database/' + database + '/' + designDocs + '/_view/' + viewName;
+    edit: function (database, designDoc, indexName) {
+      return 'database/' + database + '/_design/' + designDoc + '/_view/' + 
indexName + '/edit';
+    },
+
+    showView: function (database, designDoc, viewName) {
+      return '/database/' + database + '/' + designDoc + '/_view/' + viewName;
     },
 
-    fragment: function (database, designDocs, viewName) {
-      return 'database/' + database + designDocs + '/_view/' + viewName;
+    fragment: function (database, designDoc, viewName) {
+      return 'database/' + database + designDoc + '/_view/' + viewName;
     }
   });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/actions.js 
b/app/addons/documents/index-editor/actions.js
index 552ca6f..f81bd00 100644
--- a/app/addons/documents/index-editor/actions.js
+++ b/app/addons/documents/index-editor/actions.js
@@ -15,142 +15,286 @@ define([
   'api',
   'addons/documents/resources',
   'addons/documents/index-editor/actiontypes',
-  'addons/documents/index-results/actions'
+  'addons/documents/index-results/actions',
+  'addons/documents/sidebar/actions',
+  'addons/documents/sidebar/actiontypes'
 ],
-function (app, FauxtonAPI, Documents, ActionTypes, IndexResultsActions) {
+function (app, FauxtonAPI, Documents, ActionTypes, IndexResultsActions, 
SidebarActions, SidebarActionTypes) {
 
-  var ActionHelpers = {
-    findDesignDoc: function (designDocs, designDocId) {
-      return _.find(designDocs, function (doc) {
-        return doc.id === designDocId;
-      }).dDocModel();
-    }
-  };
 
+  function selectReduceChanged (reduceOption) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SELECT_REDUCE_CHANGE,
+      reduceSelectedOption: reduceOption
+    });
+  }
 
-  return {
-    //helpers are added here for use in testing actions
-    helpers: ActionHelpers,
+  function changeViewName (name) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.VIEW_NAME_CHANGE,
+      name: name
+    });
+  }
 
-    selectReduceChanged: function (reduceOption) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.SELECT_REDUCE_CHANGE,
-        reduceSelectedOption: reduceOption
-      });
-    },
+  function editIndex (options) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.EDIT_INDEX,
+      options: options
+    });
+  }
 
-    changeViewName: function (name) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.VIEW_NAME_CHANGE,
-        name: name
-      });
-    },
+  function clearIndex () {
+    FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX });
+  }
 
-    editIndex: function (options) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.EDIT_INDEX,
-        options: options
-      });
-    },
+  function fetchDesignDocsBeforeEdit (options) {
+    options.designDocs.fetch({reset: true}).then(function () {
+      this.editIndex(options);
+    }.bind(this));
+  }
 
-    clearIndex: function () {
-      FauxtonAPI.dispatch({ type: ActionTypes.CLEAR_INDEX });
-    },
+  function saveView (viewInfo) {
+    var designDoc = viewInfo.designDoc;
+    designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce);
 
-    fetchDesignDocsBeforeEdit: function (options) {
-      options.designDocs.fetch({reset: true}).then(function () {
-        this.editIndex(options);
-      }.bind(this));
-    },
+    FauxtonAPI.addNotification({
+      msg: 'Saving View...',
+      type: 'info',
+      clear: true
+    });
 
-    saveView: function (viewInfo) {
-      var designDoc = viewInfo.designDoc;
-      designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce);
+    // if the view name just changed and it's in the SAME design doc, remove 
the old one before saving the doc
+    if (viewInfo.originalDesignDocName === viewInfo.designDocId && 
viewInfo.originalViewName !== viewInfo.viewName) {
+      designDoc.removeDdocView(viewInfo.originalViewName);
+    }
 
+    designDoc.save().then(function () {
       FauxtonAPI.addNotification({
-        msg:  "Saving View...",
-        type: "info",
+        msg: 'View Saved.',
+        type: 'success',
         clear: true
       });
 
-      designDoc.save().then(function () {
-        FauxtonAPI.addNotification({
-          msg:  "View Saved.",
-          type: "success",
-          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) {
+        var oldDesignDoc = findDesignDoc(viewInfo.designDocs, 
viewInfo.originalDesignDocName);
+        safeDeleteIndex(oldDesignDoc, viewInfo.designDocs, 'views', 
viewInfo.originalViewName, {
+          onSuccess: function () {
+            SidebarActions.updateDesignDocs(viewInfo.designDocs);
+          }
         });
+      }
 
-        if (_.any([viewInfo.designDocChanged, viewInfo.hasViewNameChanged, 
viewInfo.newDesignDoc, viewInfo.newView])) {
-          FauxtonAPI.dispatch({ type: ActionTypes.VIEW_SAVED });
-          var fragment = FauxtonAPI.urls('view', 'showNewlySavedView', 
viewInfo.database.safeID(), designDoc.safeID(), 
app.utils.safeURLName(viewInfo.viewName));
-          FauxtonAPI.navigate(fragment, { trigger: true });
-        } else {
-          this.updateDesignDoc(designDoc);
-        }
-
-        // this can be removed after the Views are on their own page
-        IndexResultsActions.reloadResultsList();
-      }.bind(this));
-    },
+      if (viewInfo.designDocId === 'new-doc') {
+        addDesignDoc(designDoc);
+      }
 
-    updateDesignDoc: function (designDoc) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.VIEW_UPDATE_DESIGN_DOC,
-        designDoc: designDoc.toJSON()
-      });
-    },
+      FauxtonAPI.dispatch({ type: ActionTypes.VIEW_SAVED });
+      var fragment = FauxtonAPI.urls('view', 'showView', 
viewInfo.database.safeID(), designDoc.safeID(), 
app.utils.safeURLName(viewInfo.viewName));
+      FauxtonAPI.navigate(fragment, { trigger: true });
+    });
+  }
 
-    deleteView: function (options) {
-      var viewName = options.viewName;
-      var database = options.database;
-      var designDoc = ActionHelpers.findDesignDoc(options.designDocs, 
options.designDocId);
-      var promise;
+  function addDesignDoc (designDoc) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.VIEW_ADD_DESIGN_DOC,
+      designDoc: designDoc.toJSON()
+    });
+  }
 
-      designDoc.removeDdocView(viewName);
+  function deleteView (options) {
 
-      if (designDoc.hasViews()) {
-        promise = designDoc.save();
-      } else {
-        promise = designDoc.destroy();
-      }
+    function onSuccess () {
 
-      promise.then(function () {
-        var url = FauxtonAPI.urls('allDocs', 'app', database.safeID(), 
'?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT);
+      // if the user was on the index that was just deleted, redirect them 
back to all docs
+      if (options.isOnIndex) {
+        var url = FauxtonAPI.urls('allDocs', 'app', options.database.safeID(), 
'?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT);
         FauxtonAPI.navigate(url);
-        FauxtonAPI.triggerRouteEvent('reloadDesignDocs');
-      });
-    },
+      }
+
+      SidebarActions.updateDesignDocs(options.designDocs);
 
-    updateMapCode: function (code) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.VIEW_UPDATE_MAP_CODE,
-        code: code
+      FauxtonAPI.addNotification({
+        msg: 'The <code>' + _.escape(options.indexName) + '</code> view has 
been deleted.',
+        type: 'info',
+        escape: false,
+        clear: true
       });
-    },
+      FauxtonAPI.dispatch({ type: 
SidebarActionTypes.SIDEBAR_HIDE_DELETE_INDEX_MODAL });
+    }
 
-    updateReduceCode: function (code) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.VIEW_UPDATE_REDUCE_CODE,
-        code: code
+    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');
+    if (indexes && _.has(indexes, params.newIndexName)) {
+      FauxtonAPI.addNotification({
+        msg: 'That index name is already used in this design doc. Please enter 
a new name.',
+        type: 'error',
+        clear: true
       });
-    },
+      return;
+    }
+    if (!indexes) {
+      indexes = {};
+    }
+    var sourceDesignDoc = findDesignDoc(params.designDocs, '_design/' + 
params.sourceDesignDocName);
+    var sourceDesignDocJSON = sourceDesignDoc.toJSON();
 
-    selectDesignDoc: function (designDoc) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.DESIGN_DOC_CHANGE,
-        options: {
-          value: designDoc
-        }
+    // 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 () {
+      params.onComplete();
+      FauxtonAPI.addNotification({
+        msg: 'The index has been cloned.',
+        type: 'success',
+        clear: true
       });
+      SidebarActions.updateDesignDocs(params.designDocs);
     },
-
-    updateNewDesignDocName: function (designDocName) {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.DESIGN_DOC_NEW_NAME_UPDATED,
-        options: {
-          value: designDocName
-        }
+    function (xhr) {
+      params.onComplete();
+      var responseText = JSON.parse(xhr.responseText).reason;
+      FauxtonAPI.addNotification({
+        msg: 'Clone failed: ' + responseText,
+        type: 'error',
+        clear: true
       });
+    });
+  }
+
+  function gotoEditViewPage (databaseName, designDocName, indexName) {
+    FauxtonAPI.navigate('#' + FauxtonAPI.urls('view', 'edit', databaseName, 
designDocName, indexName));
+  }
+
+  function updateMapCode (code) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.VIEW_UPDATE_MAP_CODE,
+      code: code
+    });
+  }
+
+  function updateReduceCode (code) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.VIEW_UPDATE_REDUCE_CODE,
+      code: code
+    });
+  }
+
+  function selectDesignDoc (designDoc) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.DESIGN_DOC_CHANGE,
+      options: {
+        value: designDoc
+      }
+    });
+  }
+
+  function updateNewDesignDocName (designDocName) {
+    FauxtonAPI.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({
+      onSuccess: function () { },
+      onError: function (xhr) {
+        var responseText = JSON.parse(xhr.responseText).reason;
+        FauxtonAPI.addNotification({
+          msg: 'Delete failed: ' + responseText,
+          type: 'error',
+          clear: true
+        });
+      }
+    }, options);
+
+    var indexes = designDoc.get(indexPropName) || {};
+    delete indexes[indexName];
+    var 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) {
+      return designDoc.get(propName) && _.keys(designDoc.get(propName)).length 
> 0;
+    });
+
+    var promise;
+    var deleteDesignDoc = false;
+    if (hasRemainingIndex) {
+      promise = designDoc.save();
+    } else {
+      promise = designDoc.destroy();
+      deleteDesignDoc = true;
     }
+    promise.then(function () {
+      if (deleteDesignDoc) {
+        designDocs.remove(designDoc.id);
+      }
+      opts.onSuccess();
+    }, opts.onError);
+  }
+
+
+
+  // ---- helpers ----
+
+  function findDesignDoc (designDocs, designDocName) {
+    return designDocs.find(function (doc) {
+      return doc.id === designDocName;
+    }).dDocModel();
+  }
+
+  function getDesignDoc (designDocs, targetDesignDocName, newDesignDocName, 
database) {
+    if (targetDesignDocName === 'new-doc') {
+      var doc = {
+        "_id": "_design/" + newDesignDocName,
+        "views": {},
+        "language": "javascript"
+      };
+      return new Documents.Doc(doc, { database: database });
+    }
+
+    var foundDoc = designDocs.find(function (ddoc) {
+      return ddoc.id === targetDesignDocName;
+    });
+    return (!foundDoc) ? null : foundDoc.dDocModel();
+  }
+
+
+  return {
+    helpers: {
+      findDesignDoc: findDesignDoc,
+      getDesignDoc: getDesignDoc
+    },
+    safeDeleteIndex: safeDeleteIndex,
+    selectReduceChanged: selectReduceChanged,
+    changeViewName: changeViewName,
+    editIndex: editIndex,
+    clearIndex: clearIndex,
+    fetchDesignDocsBeforeEdit: fetchDesignDocsBeforeEdit,
+    saveView: saveView,
+    addDesignDoc: addDesignDoc,
+    deleteView: deleteView,
+    cloneView: cloneView,
+    gotoEditViewPage: gotoEditViewPage,
+    updateMapCode: updateMapCode,
+    updateReduceCode: updateReduceCode,
+    selectDesignDoc: selectDesignDoc,
+    updateNewDesignDocName: updateNewDesignDocName
   };
+
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/actiontypes.js 
b/app/addons/documents/index-editor/actiontypes.js
index 7104d31..d4c1fa1 100644
--- a/app/addons/documents/index-editor/actiontypes.js
+++ b/app/addons/documents/index-editor/actiontypes.js
@@ -22,7 +22,7 @@ define([], function () {
     DESIGN_DOC_NEW_NAME_UPDATED: 'DESIGN_DOC_NEW_NAME_UPDATED',
     NEW_DESIGN_DOC: 'NEW_DESIGN_DOC',
     VIEW_NAME_CHANGE: 'VIEW_NAME_CHANGE',
-    VIEW_UPDATE_DESIGN_DOC: 'VIEW_UPDATE_DESIGN_DOC',
+    VIEW_ADD_DESIGN_DOC: 'VIEW_ADD_DESIGN_DOC',
     VIEW_UPDATE_MAP_CODE: 'VIEW_UPDATE_MAP_CODE',
     VIEW_UPDATE_REDUCE_CODE: 'VIEW_UPDATE_REDUCE_CODE'
   };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/components.react.jsx 
b/app/addons/documents/index-editor/components.react.jsx
index 7c40570..092bcc3 100644
--- a/app/addons/documents/index-editor/components.react.jsx
+++ b/app/addons/documents/index-editor/components.react.jsx
@@ -22,11 +22,11 @@ define([
 ],
 
 function (app, FauxtonAPI, React, ReactDOM, Stores, Actions, Components, 
ReactComponents) {
-  var indexEditorStore = Stores.indexEditorStore;
+
+  var store = Stores.indexEditorStore;
   var getDocUrl = app.helpers.getDocUrl;
   var StyledSelect = ReactComponents.StyledSelect;
   var CodeEditorPanel = ReactComponents.CodeEditorPanel;
-  var PaddedBorderedBox = ReactComponents.PaddedBorderedBox;
   var ConfirmButton = ReactComponents.ConfirmButton;
   var LoadLines = ReactComponents.LoadLines;
 
@@ -130,11 +130,11 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
 
     getStoreState: function () {
       return {
-        reduce: indexEditorStore.getReduce(),
-        reduceOptions: indexEditorStore.reduceOptions(),
-        reduceSelectedOption: indexEditorStore.reduceSelectedOption(),
-        hasCustomReduce: indexEditorStore.hasCustomReduce(),
-        hasReduce: indexEditorStore.hasReduce()
+        reduce: store.getReduce(),
+        reduceOptions: store.reduceOptions(),
+        reduceSelectedOption: store.reduceSelectedOption(),
+        hasCustomReduce: store.hasCustomReduce(),
+        hasReduce: store.hasReduce()
       };
     },
 
@@ -174,6 +174,7 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
           id='reduce-function'
           title={'Custom Reduce function'}
           defaultCode={this.state.reduce}
+          allowZenMode={false}
           blur={this.updateReduceCode}
         />;
       }
@@ -182,7 +183,7 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
         <div>
           <div className="control-group">
             <label htmlFor="reduce-function-selector">
-              <strong>Reduce (optional)</strong>
+              <span>Reduce (optional)</span>
               <a
                 className="help-link"
                 data-bypass="true"
@@ -213,78 +214,38 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
     },
 
     onChange: function () {
-      this.setState(this.getStoreState());
+      if (this.isMounted()) {
+        this.setState(this.getStoreState());
+      }
     },
 
     componentDidMount: function () {
-      indexEditorStore.on('change', this.onChange, this);
+      store.on('change', this.onChange, this);
     },
 
     componentWillUnmount: function () {
-      indexEditorStore.off('change', this.onChange);
+      store.off('change', this.onChange);
     }
   });
 
-  var DeleteView = React.createClass({
-    getStoreState: function () {
-      return {
-        isNewView: indexEditorStore.isNewView(),
-        designDocs: indexEditorStore.getDesignDocs(),
-        viewName: indexEditorStore.getViewName(),
-        designDocId: indexEditorStore.getDesignDocId(),
-        database: indexEditorStore.getDatabase()
-      };
-    },
-
-    getInitialState: function () {
-      return this.getStoreState();
-    },
 
-    render: function () {
-      if (this.state.isNewView) {
-        return null;
-      }
-
-      return (
-        <button onClick={this.deleteView} className="btn btn-danger delete">
-          <i className="icon fonticon-cancel-circled"></i>
-          Delete
-        </button>
-      );
-    },
-
-    deleteView: function (event) {
-      event.preventDefault();
-
-      if (!confirm('Are you sure you want to delete this view?')) {return;}
-
-      Actions.deleteView({
-        designDocs: this.state.designDocs,
-        viewName: this.state.viewName,
-        designDocId: this.state.designDocId,
-        database: this.state.database
-      });
-    }
-
-  });
-
-  var Editor = React.createClass({
+  var EditorController = React.createClass({
 
     getStoreState: function () {
       return {
-        hasViewNameChanged: indexEditorStore.hasViewNameChanged(),
-        database: indexEditorStore.getDatabase(),
-        isNewView: indexEditorStore.isNewView(),
-        viewName: indexEditorStore.getViewName(),
-        designDocs: indexEditorStore.getDesignDocs(),
-        designDocList: indexEditorStore.getAvailableDesignDocs(),
-        hasDesignDocChanged: indexEditorStore.hasDesignDocChanged(),
-        newDesignDoc: indexEditorStore.isNewDesignDoc(),
-        designDocId: indexEditorStore.getDesignDocId(),
-        newDesignDocName: indexEditorStore.getNewDesignDocName(),
-        saveDesignDoc: indexEditorStore.getSaveDesignDoc(),
-        map: indexEditorStore.getMap(),
-        isLoading: indexEditorStore.isLoading()
+        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()
       };
     },
 
@@ -299,16 +260,24 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
     },
 
     componentDidMount: function () {
-      indexEditorStore.on('change', this.onChange, this);
+      store.on('change', this.onChange, this);
     },
 
     componentWillUnmount: function () {
-      indexEditorStore.off('change', this.onChange);
+      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();
+      }
     },
 
     hasErrors: function () {
       var mapEditorErrors = this.refs.mapEditor.getEditor().hasErrors();
-      var customReduceErrors = (indexEditorStore.hasCustomReduce()) ? 
this.refs.reduceEditor.getEditor().hasErrors() : false;
+      var customReduceErrors = (store.hasCustomReduce()) ? 
this.refs.reduceEditor.getEditor().hasErrors() : false;
       return mapEditorErrors || customReduceErrors;
     },
 
@@ -321,7 +290,7 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
 
       if (this.hasErrors()) {
         FauxtonAPI.addNotification({
-          msg:  'Please fix the Javascript errors and try again.',
+          msg: 'Please fix the Javascript errors and try again.',
           type: 'error',
           clear: true
         });
@@ -335,8 +304,8 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
         designDoc: this.state.saveDesignDoc,
         designDocId: this.state.designDocId,
         newDesignDoc: this.state.newDesignDoc,
-        designDocChanged: this.state.hasDesignDocChanged,
-        hasViewNameChanged: this.state.hasViewNameChanged,
+        originalViewName: this.state.originalViewName,
+        originalDesignDocName: this.state.originalDesignDocName,
         map: this.refs.mapEditor.getValue(),
         reduce: this.refs.reduceEditor.getReduceValue(),
         designDocs: this.state.designDocs
@@ -360,71 +329,57 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
         );
       }
 
-      var url = '#/' + FauxtonAPI.urls('allDocs', 'app', 
this.state.database.id, '');
+      var pageHeader = (this.state.isNewView) ? 'New View' : 'Edit View';
+      var btnLabel = (this.state.isNewView) ? 'Create Document and Build 
Index' : 'Save Document and Build Index';
+
+      var cancelLink = '#' + FauxtonAPI.urls('view', 'showView', 
this.state.database.id, this.state.designDocId, this.state.viewName);
       return (
         <div className="define-view">
-          <PaddedBorderedBox>
-            Views are the primary tools for querying and reporting.
-          </PaddedBorderedBox>
-          <PaddedBorderedBox>
-            <strong>Database</strong>
-            <div className="db-title">
-              <a href={url}>{this.state.database.id}</a>
-            </div>
-          </PaddedBorderedBox>
           <form className="form-horizontal view-query-save" 
onSubmit={this.saveView}>
+            <h3 className="simple-header">{pageHeader}</h3>
 
             <div className="new-ddoc-section">
-              <PaddedBorderedBox>
-                <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')} />
-              </PaddedBorderedBox>
+              <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">
-              <PaddedBorderedBox>
-                <label htmlFor="index-name">
-                  <strong>Index name</strong>
-                  <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" />
-              </PaddedBorderedBox>
-            </div>
-            <div className="control-group">
-              <PaddedBorderedBox>
-                <CodeEditorPanel
-                  id={'map-function'}
-                  ref="mapEditor"
-                  title={"Map function"}
-                  docLink={getDocUrl('MAP_FUNCS')}
-                  blur={this.updateMapCode}
-                  defaultCode={this.state.map} />
-              </PaddedBorderedBox>
+              <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>
-            <PaddedBorderedBox>
-              <ReduceEditor ref="reduceEditor" />
-            </PaddedBorderedBox>
+            <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="Save Document and Build 
Index" />
-                <DeleteView />
+                <ConfirmButton id="save-view" text={btnLabel} />
+                <a href={cancelLink} className="index-cancel-link">Cancel</a>
               </div>
             </div>
           </form>
@@ -433,23 +388,12 @@ function (app, FauxtonAPI, React, ReactDOM, Stores, 
Actions, Components, ReactCo
     }
   });
 
-  var EditorController = React.createClass({
-    render: function () {
-      return (
-        <div className="editor-wrapper">
-          <Editor />
-        </div>
-      );
-    }
-  });
 
-  var Views = {
+  return {
     EditorController: EditorController,
     ReduceEditor: ReduceEditor,
-    Editor: Editor,
     DesignDocSelector: DesignDocSelector,
     StyledSelect: StyledSelect
   };
 
-  return Views;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/stores.js 
b/app/addons/documents/index-editor/stores.js
index ebc37ae..1ea67c0 100644
--- a/app/addons/documents/index-editor/stores.js
+++ b/app/addons/documents/index-editor/stores.js
@@ -43,9 +43,10 @@ function (FauxtonAPI, ActionTypes, Resources) {
       this._newDesignDocName = '';
       this._designDocs = options.designDocs;
       this._designDocId = options.designDocId;
-      this._designDocChanged = false;
-      this._viewNameChanged = false;
+      this._originalViewName = this._viewName;
+      this._originalDesignDocName = options.designDocId;
       this.setView();
+
       this._isLoading = false;
     },
 
@@ -88,14 +89,15 @@ function (FauxtonAPI, ActionTypes, Resources) {
     },
 
     getDesignDocs: function () {
-      return this._designDocs.filter(function (ddoc) {
-        return !ddoc.isMangoDoc();
-      });
+      return this._designDocs;
     },
 
-    // returns a simple array of design doc IDs
+    // returns a simple array of design doc IDs. Omits mango docs
     getAvailableDesignDocs: function () {
-      return _.map(this.getDesignDocs(), function (doc) {
+      var availableDocs = this.getDesignDocs().filter(function (doc) {
+        return !doc.isMangoDoc();
+      });
+      return _.map(availableDocs, function (doc) {
         return doc.id;
       });
     },
@@ -108,10 +110,6 @@ function (FauxtonAPI, ActionTypes, Resources) {
       this._designDocId = designDocId;
     },
 
-    hasDesignDocChanged: function () {
-      return this._designDocChanged;
-    },
-
     isNewDesignDoc: function () {
       return this._newDesignDoc;
     },
@@ -126,23 +124,28 @@ function (FauxtonAPI, ActionTypes, Resources) {
 
     setViewName: function (name) {
       this._viewName = name;
-      this._viewNameChanged = true;
     },
 
     hasCustomReduce: function () {
-      if (!this.hasReduce()) { return false; }
-
+      if (!this.hasReduce()) {
+        return false;
+      }
       return !_.contains(this.builtInReduces(), this.getReduce());
     },
 
     hasReduce: function () {
-      if (!this.getReduce()) { return false; }
-
+      if (!this.getReduce()) {
+        return false;
+      }
       return true;
     },
 
-    hasViewNameChanged: function () {
-      return this._viewNameChanged;
+    getOriginalViewName: function () {
+      return this._originalViewName;
+    },
+
+    getOriginalDesignDocName: function () {
+      return this._originalDesignDocName;
     },
 
     builtInReduces: function () {
@@ -153,11 +156,9 @@ function (FauxtonAPI, ActionTypes, Resources) {
       if (!this.hasReduce()) {
         return 'NONE';
       }
-
       if (this.hasCustomReduce()) {
         return 'CUSTOM';
       }
-
       return this.getReduce();
     },
 
@@ -170,17 +171,16 @@ function (FauxtonAPI, ActionTypes, Resources) {
         this.setReduce(null);
         return;
       }
-
       if (selectedReduce === 'CUSTOM') {
         this.setReduce(this.defaultReduce);
         return;
       }
-
       this.setReduce(selectedReduce);
     },
 
-    updateDesignDoc: function (designDoc) {
-      this._designDocs.add(designDoc, {merge: true});
+    addDesignDoc: function (designDoc) {
+      this._designDocs.add(designDoc, { merge: true });
+      this._designDocId = designDoc._id;
     },
 
     getNewDesignDocName: function () {
@@ -236,8 +236,8 @@ function (FauxtonAPI, ActionTypes, Resources) {
         case ActionTypes.VIEW_CREATED:
         break;
 
-        case ActionTypes.VIEW_UPDATE_DESIGN_DOC:
-          this.updateDesignDoc(action.designDoc);
+        case ActionTypes.VIEW_ADD_DESIGN_DOC:
+          this.addDesignDoc(action.designDoc);
           this.setView();
         break;
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/tests/actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/tests/actionsSpec.js 
b/app/addons/documents/index-editor/tests/actionsSpec.js
index 8064962..eef6781 100644
--- a/app/addons/documents/index-editor/tests/actionsSpec.js
+++ b/app/addons/documents/index-editor/tests/actionsSpec.js
@@ -27,13 +27,9 @@ define([
 
 
   describe('Index Editor Actions', function () {
-    var database = {
-      safeID: function () { return 'id'; }
-    };
-
 
     describe('delete view', function () {
-      var designDocs, database, designDoc, designDocId, viewName;
+      var designDocs, database, designDoc, designDocCollection, designDocId, 
viewName;
       beforeEach(function () {
         database = {
           safeID: function () { return 'safeid';}
@@ -41,7 +37,7 @@ define([
 
         viewName = 'test-view';
         designDocId = '_design/test-doc';
-        designDocs = new Documents.AllDocs([{
+        designDocCollection = new Documents.AllDocs([{
           _id: designDocId,
           _rev: '1-231',
           views: {
@@ -56,7 +52,7 @@ define([
           params: { limit: 10 },
           database: database
         });
-        designDocs = designDocs.models;
+        designDocs = designDocCollection.models;
         designDoc = _.first(designDocs);
       });
 
@@ -65,83 +61,78 @@ define([
         restore(FauxtonAPI.triggerRouteEvent);
       });
 
-      it('removes view from design doc', function () {
-
-        Actions.deleteView({
-          viewName: viewName,
-          designDocId: designDocId,
-          database: database,
-          designDocs: designDocs
-        });
-
-        assert.ok(_.isUndefined(designDoc.getDdocView(viewName)));
-      });
-
       it('saves design doc if has other views', function () {
-        var spy = sinon.spy(designDoc, 'save');
+        designDoc.save = function () {
+          var promise = $.Deferred();
+          promise.resolve();
+          return promise;
+        };
+        var saveSpy = sinon.spy(designDoc, 'save');
+        designDocs.fetch = function () {
+          var promise = $.Deferred();
+          promise.resolve();
+          return promise;
+        };
 
         Actions.deleteView({
-          viewName: viewName,
-          designDocId: designDocId,
+          indexName: viewName,
           database: database,
-          designDocs: designDocs
+          designDocs: designDocs,
+          designDoc: designDoc
         });
 
-        assert.ok(spy.calledOnce);
+        assert.ok(saveSpy.calledOnce);
       });
 
       it('deletes design doc if has no other views', function () {
-        var spy = sinon.spy(designDoc, 'destroy');
         designDoc.removeDdocView('test-view2');
 
-        Actions.deleteView({
-          viewName: viewName,
-          designDocId: designDocId,
-          database: database,
-          designDocs: designDocs
-        });
-
-        assert.ok(spy.calledOnce);
-      });
-
-      it('navigates to all docs', function () {
-        var spy = sinon.spy(FauxtonAPI, 'navigate');
-
-        designDoc.save = function () {
+        designDoc.destroy = function () {
+          var promise = $.Deferred();
+          promise.resolve();
+          return promise;
+        };
+        var destroySpy = sinon.spy(designDoc, 'destroy');
+        designDocs.remove = function () {};
+        designDocs.fetch = function () {
           var promise = $.Deferred();
           promise.resolve();
           return promise;
         };
 
         Actions.deleteView({
-          viewName: viewName,
-          designDocId: designDocId,
+          indexName: viewName,
           database: database,
-          designDocs: designDocs
+          designDocs: designDocs,
+          designDoc: designDoc
         });
 
-        assert.ok(spy.getCall(0).args[0].match(/_all_docs/));
-        assert.ok(spy.calledOnce);
+        assert.ok(destroySpy.calledOnce);
       });
 
-      it('triggers design doc reload', function () {
-        var spy = sinon.spy(FauxtonAPI, 'triggerRouteEvent');
+      it('navigates to all docs if was on view', function () {
+        var spy = sinon.spy(FauxtonAPI, 'navigate');
 
         designDoc.save = function () {
           var promise = $.Deferred();
           promise.resolve();
           return promise;
         };
-
+        designDocs.fetch = function () {
+          var promise = $.Deferred();
+          promise.resolve();
+          return promise;
+        };
         Actions.deleteView({
-          viewName: viewName,
-          designDocId: designDocId,
+          indexName: viewName,
           database: database,
-          designDocs: designDocs
+          designDocs: designDocs,
+          designDoc: designDoc,
+          isOnIndex: true
         });
 
+        assert.ok(spy.getCall(0).args[0].match(/_all_docs/));
         assert.ok(spy.calledOnce);
-        assert.equal(spy.getCall(0).args[0], 'reloadDesignDocs');
       });
 
     });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/tests/storesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/tests/storesSpec.js 
b/app/addons/documents/index-editor/tests/storesSpec.js
index db098a6..07fbadb 100644
--- a/app/addons/documents/index-editor/tests/storesSpec.js
+++ b/app/addons/documents/index-editor/tests/storesSpec.js
@@ -289,9 +289,9 @@ define([
       });
 
       it('only filters mango docs', function () {
-        var designDocs = store.getDesignDocs();
+        var designDocs = store.getAvailableDesignDocs();
         assert.equal(designDocs.length, 1);
-        assert.equal(designDocs[0].id, '_design/test-doc');
+        assert.equal(designDocs[0], '_design/test-doc');
       });
     });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git 
a/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.react.jsx 
b/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.react.jsx
index 51ed2a2..288a999 100644
--- a/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.react.jsx
+++ b/app/addons/documents/index-editor/tests/viewIndex.componentsSpec.react.jsx
@@ -106,7 +106,6 @@ define([
 
   describe('DesignDocSelector component', function () {
     var container, selectorEl;
-    var database = { id: 'db' };
     var designDoc = {
       "id": "_design/test-doc",
       "key": "_design/test-doc",
@@ -251,7 +250,7 @@ define([
       container = document.createElement('div');
       $('body').append('<div id="map-function"></div>');
       $('body').append('<div id="editor"></div>');
-      editorEl = TestUtils.renderIntoDocument(<Views.Editor/>, container);
+      editorEl = TestUtils.renderIntoDocument(<Views.EditorController />, 
container);
       sandbox = sinon.sandbox.create();
     });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-results/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/stores.js 
b/app/addons/documents/index-results/stores.js
index 38f0a23..a744a4a 100644
--- a/app/addons/documents/index-results/stores.js
+++ b/app/addons/documents/index-results/stores.js
@@ -47,7 +47,7 @@ function (app, FauxtonAPI, ActionTypes, HeaderActionTypes, 
PaginationActionTypes
 
       this.clearSelectedItems();
       this._isLoading = false;
-      this._textEmptyIndex = 'No Index Created Yet!';
+      this._textEmptyIndex = 'No Documents Found';
       this._typeOfIndex = 'view';
 
       this._tableViewSelectedFields = [];

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git 
a/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
 
b/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
index 7bde20b..012b1fb 100644
--- 
a/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
+++ 
b/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
@@ -52,7 +52,7 @@ define([
 
         instance = TestUtils.renderIntoDocument(<Views.List />, container);
         var $el = $(ReactDOM.findDOMNode(instance));
-        assert.equal($el.text(), 'No Index Created Yet!');
+        assert.equal($el.text(), 'No Documents Found');
       });
 
       it('you can change the default text', function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/mango/mango.components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/mango/mango.components.react.jsx 
b/app/addons/documents/mango/mango.components.react.jsx
index c7e949b..d92f340 100644
--- a/app/addons/documents/mango/mango.components.react.jsx
+++ b/app/addons/documents/mango/mango.components.react.jsx
@@ -74,7 +74,7 @@ function (app, FauxtonAPI, React, Stores, Actions,
       var loadLines;
       if (this.state.isLoading) {
         return (
-          <div className="editor-wrapper">
+          <div className="mango-editor-wrapper">
             <ReactComponents.LoadLines />
           </div>
         );
@@ -130,7 +130,7 @@ function (app, FauxtonAPI, React, Stores, Actions,
       var url = '#/' + FauxtonAPI.urls('allDocs', 'app', this.props.dbName, 
'');
 
       return (
-        <div className="editor-wrapper">
+        <div className="mango-editor-wrapper">
           <PaddedBorderedBox>
             <div
               dangerouslySetInnerHTML={{__html: this.props.description}}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js 
b/app/addons/documents/routes-documents.js
index e6bd8b1..f9542f0 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -63,7 +63,7 @@ function (app, FauxtonAPI, BaseRoute, Documents, Changes, 
ChangesActions, Databa
 
       establish: function () {
         return [
-          this.designDocs.fetch({reset: true}),
+          this.designDocs.fetch({ reset: true }),
           this.allDatabases.fetchOnce()
         ];
       },
@@ -170,8 +170,8 @@ function (app, FauxtonAPI, BaseRoute, Documents, Changes, 
ChangesActions, Databa
         this.rightHeader.showQueryOptions();
       },
 
-      //TODO: REMOVE
       reloadDesignDocs: function (event) {
+        this.addSidebar(); // this ensures the design docs get reloaded
         if (event && event.selectedTab) {
           SidebarActions.selectNavItem(event.selectedTab);
         }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/routes-index-editor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-index-editor.js 
b/app/addons/documents/routes-index-editor.js
index 3a66cbd..7e21daa 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -28,40 +28,53 @@ define([
   'addons/documents/pagination/pagination.react',
   'addons/documents/header/header.react',
   'addons/documents/header/header.actions',
+  'addons/documents/sidebar/actions'
 ],
 
 function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents, ActionsIndexEditor,
           Databases, Components, IndexResultsStores, IndexResultsActions,
-          IndexResultsComponents, ReactPagination, ReactHeader, 
ReactHeaderActions) {
+          IndexResultsComponents, ReactPagination, ReactHeader, 
ReactHeaderActions, SidebarActions) {
 
 
   var IndexEditorAndResults = BaseRoute.extend({
-    layout: 'two_pane',
+    layout: 'with_tabs_sidebar',
     routes: {
-      'database/:database/new_view': 'newViewEditor',
-      'database/:database/new_view/:designDoc': 'newViewEditor',
+      'database/:database/new_view': {
+        route: 'createView',
+        roles: ['fx_loggedIn']
+      },
+      'database/:database/new_view/:designDoc': {
+        route: 'createView',
+        roles: ['fx_loggedIn']
+      },
       'database/:database/_design/:ddoc/_view/:view': {
-        route: 'viewFn',
+        route: 'showView',
+        roles: ['fx_loggedIn']
+      },
+      'database/:database/_design/:ddoc/_view/:view/edit': {
+        route: 'editView',
         roles: ['fx_loggedIn']
       }
     },
 
     initialize: function (route, masterLayout, options) {
       var databaseName = options[0];
-
       this.databaseName = databaseName;
       this.database = new Databases.Model({id: databaseName});
       this.allDatabases = new Databases.List();
       this.createDesignDocsCollection();
+      this.addLeftHeader();
+      this.addSidebar();
     },
 
     establish: function () {
       return [
+        this.designDocs.fetch({ reset: true }),
         this.allDatabases.fetchOnce()
       ];
     },
 
-    viewFn: function (databaseName, ddoc, viewName) {
+    showView: function (databaseName, ddoc, viewName) {
       var params = this.createParams(),
           urlParams = params.urlParams,
           docParams = params.docParams,
@@ -71,17 +84,7 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents,
         database: this.database
       }));
 
-      var url = FauxtonAPI.urls('allDocs', 'app', this.database.safeID(), 
'?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT);
-      this.breadcrumbs = this.setView('#breadcrumbs', new 
Components.Breadcrumbs({
-        toggleDisabled: true,
-        crumbs: [
-          {'type': 'back', 'link': Helpers.getPreviousPage(this.database)},
-          {'name': this.database.id, 'link': url }
-        ]
-      }));
-
       viewName = viewName.replace(/\?.*$/, '');
-
       this.setComponent('#footer', ReactPagination.Footer);
 
       this.indexedDocs = new Documents.IndexCollection(null, {
@@ -109,9 +112,13 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents,
         designDocId: '_design/' + decodeDdoc
       });
 
-      this.setComponent('#react-headerbar', 
ReactHeader.BulkDocumentHeaderController, {showIncludeAllDocs: true});
+      SidebarActions.selectNavItem('designDoc', {
+        designDocName: ddoc,
+        designDocSection: 'Views',
+        indexName: viewName
+      });
 
-      this.setComponent('#left-content', 
IndexEditorComponents.EditorController);
+      this.setComponent('#react-headerbar', 
ReactHeader.BulkDocumentHeaderController, {showIncludeAllDocs: true});
       this.setComponent('#dashboard-lower-content', 
IndexResultsComponents.List);
 
       this.apiUrl = function () {
@@ -121,7 +128,7 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents,
       this.showQueryOptions(urlParams, ddoc, viewName);
     },
 
-    newViewEditor: function (database, _designDoc) {
+    createView: function (database, _designDoc) {
       var newDesignDoc = true;
       var designDoc = 'new-doc';
 
@@ -130,15 +137,6 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents,
         newDesignDoc = false;
       }
 
-      var url = FauxtonAPI.urls('allDocs', 'app', this.database.safeID(), 
'?limit=' + FauxtonAPI.constants.DATABASES.DOCUMENT_LIMIT);
-      this.breadcrumbs = this.setView('#breadcrumbs', new 
Components.Breadcrumbs({
-        toggleDisabled: true,
-        crumbs: [
-          { type: 'back', link: Helpers.getPreviousPage(this.database) },
-          { name: 'Create Index', link: url }
-        ]
-      }));
-
       ActionsIndexEditor.fetchDesignDocsBeforeEdit({
         viewName: 'new-view',
         newView: true,
@@ -148,11 +146,35 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, 
IndexEditorComponents,
         newDesignDoc: newDesignDoc
       });
 
-      this.setComponent('#left-content', 
IndexEditorComponents.EditorController);
-      this.setComponent('#dashboard-lower-content', 
IndexResultsComponents.List);
+      this.removeComponent('#react-headerbar');
+      this.removeComponent('#footer');
+      this.setComponent('#dashboard-lower-content', 
IndexEditorComponents.EditorController);
+      SidebarActions.selectNavItem('');
+    },
+
+    editView: function (databaseName, ddocName, viewName) {
+      ActionsIndexEditor.fetchDesignDocsBeforeEdit({
+        viewName: viewName,
+        newView: false,
+        database: this.database,
+        designDocs: this.designDocs,
+        designDocId: '_design/' + ddocName
+      });
+
+      SidebarActions.selectNavItem('designDoc', {
+        designDocName: ddocName,
+        designDocSection: 'Views',
+        indexName: viewName
+      });
+
+      this.apiUrl = function () {
+        return [FauxtonAPI.urls('view', 'apiurl', databaseName, ddocName, 
viewName), FauxtonAPI.constants.DOC_URLS.GENERAL];
+      };
 
-      IndexResultsActions.clearResults();
-      IndexResultsActions.resultsListReset();
+      this.removeView('#right-header');
+      this.removeComponent('#react-headerbar');
+      this.removeComponent('#footer');
+      this.setComponent('#dashboard-lower-content', 
IndexEditorComponents.EditorController);
     }
 
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/shared-resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-resources.js 
b/app/addons/documents/shared-resources.js
index 1b0c1c0..eefa545 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -84,42 +84,10 @@ define([
       return false;
     },
 
-    isReducedShown : function () {
-      if (this.collection) {
-        return this.collection.params.reduce;
-      } else {
-        return false;
-      }
-    },
-
     isDdoc: function () {
       return this.docType() === "design doc";
     },
 
-    hasViews: function () {
-      if (!this.isDdoc()) return false;
-      var doc = this.get('doc');
-      if (doc) {
-        return doc && doc.views && _.keys(doc.views).length > 0;
-      }
-
-      var views = this.get('views');
-      return views && _.keys(views).length > 0;
-    },
-
-    getDdocView: function (view) {
-      if (!this.isDdoc() || !this.hasViews()) {
-        return false;
-      }
-
-      var doc = this.get('doc');
-      if (doc) {
-        return doc.views[view];
-      }
-
-      return this.get('views')[view];
-    },
-
     setDdocView: function (view, map, reduce) {
       if (!this.isDdoc()) {
         return false;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/sidebar/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/sidebar/actions.js 
b/app/addons/documents/sidebar/actions.js
index 3419da0..da1d177 100644
--- a/app/addons/documents/sidebar/actions.js
+++ b/app/addons/documents/sidebar/actions.js
@@ -14,59 +14,145 @@ define([
   'app',
   'api',
   'addons/documents/sidebar/actiontypes',
-  'addons/documents/sidebar/stores'
+  'addons/documents/sidebar/stores.react'
 ],
 function (app, FauxtonAPI, ActionTypes, Stores) {
   var store = Stores.sidebarStore;
 
-  return {
-    newOptions: function (options) {
-      if (options.database.safeID() !== store.getDatabaseName()) {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SIDEBAR_FETCHING
-        });
-      }
-
-      options.designDocs.fetch().then(function () {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.SIDEBAR_NEW_OPTIONS,
-          options: options
-        });
+  function newOptions (options) {
+    if (options.database.safeID() !== store.getDatabaseName()) {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.SIDEBAR_FETCHING
       });
-    },
+    }
 
-    toggleContent: function (designDoc, indexGroup) {
+    options.designDocs.fetch().then(function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.SIDEBAR_TOGGLE_CONTENT,
-        designDoc: designDoc,
-        indexGroup: indexGroup
+        type: ActionTypes.SIDEBAR_NEW_OPTIONS,
+        options: options
       });
-    },
-
-    // This selects any item in the sidebar, including nested nav items to 
ensure the appropriate item is visible
-    // and highlighted. Params:
-    // - `navItem`: 'permissions', 'changes', 'all-docs', 'compact', 
'mango-query', 'designDoc' (or anything thats been
-    //    extended)
-    // - `params`: optional object if you passed designDoc as the first param. 
This lets you specify which sub-page
-    //    should be selected, e.g.
-    //       Actions.selectNavItem('designDoc', { designDocName: 
'my-design-doc', section: 'metadata' });
-    //       Actions.selectNavItem('designDoc', { designDocName: 
'my-design-doc', section: 'Views', indexName: 'my-view' });
-    selectNavItem: function (navItem, params) {
-      var settings = $.extend(true, {}, {
-        designDocName: '',
-        designDocSection: '',
-        indexName: ''
-      }, params);
-      settings.navItem = navItem;
+    });
+  }
 
+  function updateDesignDocs (designDocs) {
+    designDocs.fetch().then(function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.SIDEBAR_SET_SELECTED_NAV_ITEM,
-        options: settings
+        type: ActionTypes.SIDEBAR_UPDATED_DESIGN_DOCS,
+        options: {
+          designDocs: designDocs
+        }
       });
-    },
+    });
+  }
 
-    refresh: function () {
-      FauxtonAPI.dispatch({ type: ActionTypes.SIDEBAR_REFRESH });
-    }
+  function toggleContent (designDoc, indexGroup) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_TOGGLE_CONTENT,
+      designDoc: designDoc,
+      indexGroup: indexGroup
+    });
+  }
+
+  // This selects any item in the sidebar, including nested nav items to 
ensure the appropriate item is visible
+  // and highlighted. Params:
+  // - `navItem`: 'permissions', 'changes', 'all-docs', 'compact', 
'mango-query', 'designDoc' (or anything thats been
+  //    extended)
+  // - `params`: optional object if you passed designDoc as the first param. 
This lets you specify which sub-page
+  //    should be selected, e.g.
+  //       Actions.selectNavItem('designDoc', { designDocName: 
'my-design-doc', section: 'metadata' });
+  //       Actions.selectNavItem('designDoc', { designDocName: 
'my-design-doc', section: 'Views', indexName: 'my-view' });
+  function selectNavItem (navItem, params) {
+    var settings = $.extend(true, {}, {
+      designDocName: '',
+      designDocSection: '',
+      indexName: ''
+    }, params);
+    settings.navItem = navItem;
+
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_SET_SELECTED_NAV_ITEM,
+      options: settings
+    });
+  }
+
+  function refresh () {
+    FauxtonAPI.dispatch({ type: ActionTypes.SIDEBAR_REFRESH });
+  }
+
+  function showDeleteIndexModal (indexName, designDocName, indexLabel, 
onDelete) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_SHOW_DELETE_INDEX_MODAL,
+      options: {
+        indexName: indexName,
+        indexLabel: indexLabel,
+        designDocName: designDocName,
+        onDelete: onDelete
+      }
+    });
+  }
+
+  function hideDeleteIndexModal () {
+    FauxtonAPI.dispatch({ type: ActionTypes.SIDEBAR_HIDE_DELETE_INDEX_MODAL });
+  }
+
+  function showCloneIndexModal (indexName, designDocName, indexLabel, 
onSubmit) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_SHOW_CLONE_INDEX_MODAL,
+      options: {
+        sourceIndexName: indexName,
+        sourceDesignDocName: designDocName,
+        onSubmit: onSubmit,
+        indexLabel: indexLabel,
+        cloneIndexModalTitle: 'Clone ' + indexLabel
+      }
+    });
+  }
+
+  function hideCloneIndexModal () {
+    FauxtonAPI.dispatch({ type: ActionTypes.SIDEBAR_HIDE_CLONE_INDEX_MODAL });
+  }
+
+  function updateNewDesignDocName (designDocName) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_NAME_UPDATED,
+      options: {
+        value: designDocName
+      }
+    });
+  }
+
+  function selectDesignDoc (designDoc) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_CLONE_MODAL_DESIGN_DOC_CHANGE,
+      options: {
+        value: designDoc
+      }
+    });
+  }
+
+  function setNewCloneIndexName (indexName) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME,
+      options: {
+        value: indexName
+      }
+    });
+  }
+
+
+  return {
+    newOptions: newOptions,
+    updateDesignDocs: updateDesignDocs,
+    toggleContent: toggleContent,
+    selectNavItem: selectNavItem,
+    refresh: refresh,
+    showDeleteIndexModal: showDeleteIndexModal,
+    hideDeleteIndexModal: hideDeleteIndexModal,
+    showCloneIndexModal: showCloneIndexModal,
+    hideCloneIndexModal: hideCloneIndexModal,
+    updateNewDesignDocName: updateNewDesignDocName,
+    selectDesignDoc: selectDesignDoc,
+    setNewCloneIndexName: setNewCloneIndexName
   };
+
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3ff6ff62/app/addons/documents/sidebar/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/sidebar/actiontypes.js 
b/app/addons/documents/sidebar/actiontypes.js
index 70a5547..b05e3e1 100644
--- a/app/addons/documents/sidebar/actiontypes.js
+++ b/app/addons/documents/sidebar/actiontypes.js
@@ -16,6 +16,14 @@ define([], function () {
     SIDEBAR_NEW_OPTIONS: 'SIDEBAR_NEW_OPTIONS',
     SIDEBAR_TOGGLE_CONTENT: 'SIDEBAR_TOGGLE_CONTENT',
     SIDEBAR_FETCHING: 'SIDEBAR_FETCHING',
-    SIDEBAR_REFRESH: 'SIDEBAR_REFRESH'
+    SIDEBAR_REFRESH: 'SIDEBAR_REFRESH',
+    SIDEBAR_SHOW_DELETE_INDEX_MODAL: 'SIDEBAR_SHOW_DELETE_INDEX_MODAL',
+    SIDEBAR_HIDE_DELETE_INDEX_MODAL: 'SIDEBAR_HIDE_DELETE_INDEX_MODAL',
+    SIDEBAR_SHOW_CLONE_INDEX_MODAL: 'SIDEBAR_SHOW_CLONE_INDEX_MODAL',
+    SIDEBAR_HIDE_CLONE_INDEX_MODAL: 'SIDEBAR_HIDE_CLONE_INDEX_MODAL',
+    SIDEBAR_CLONE_MODAL_DESIGN_DOC_CHANGE: 
'SIDEBAR_CLONE_MODAL_DESIGN_DOC_CHANGE',
+    SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_NAME_UPDATED: 
'SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_NAME_UPDATED',
+    SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME: 
'SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME',
+    SIDEBAR_UPDATED_DESIGN_DOCS: 'SIDEBAR_UPDATED_DESIGN_DOCS'
   };
 });

Reply via email to