[partitioned dbs] Updates to index editor and index clone modal (#1158)

* Support creation of partitioned views

* Update tests

* Minor fixes

* Address comments
diff --git a/app/addons/documents/assets/less/sidenav.less b/app/addons/documents/assets/less/sidenav.less
index df2ab14..8ba51a5 100644
--- a/app/addons/documents/assets/less/sidenav.less
+++ b/app/addons/documents/assets/less/sidenav.less
@@ -257,4 +257,8 @@
       }
     }
   }
+  .ddoc-selector-partitioned {
+    padding-top: 0px;
+    padding-bottom: 16px;
+  }
 }
diff --git a/app/addons/documents/assets/less/view-editor.less b/app/addons/documents/assets/less/view-editor.less
index 163c244..5c23149 100644
--- a/app/addons/documents/assets/less/view-editor.less
+++ b/app/addons/documents/assets/less/view-editor.less
@@ -253,3 +253,16 @@
     cursor: pointer;
   }
 }
+
+.ddoc-selector-partitioned {
+  clear: both;
+  padding-top: 16px;
+
+  label.check--disabled {
+    cursor: default
+  }
+}
+
+.reduce-editor-warning {
+  padding-bottom: 1rem;
+}
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index 48be8e3..5fa6613 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -135,8 +135,8 @@
     return 'database/' + database + partitionUrlComponent(partitionKey) + '/_design/' + designDoc + '/_view/' + indexName + '/edit';
   },
 
-  showView: function (database, designDoc, viewName) {
-    return '/database/' + database + '/' + designDoc + '/_view/' + viewName;
+  showView: function (database, partitionKey, designDoc, viewName) {
+    return '/database/' + database + partitionUrlComponent(partitionKey) + '/' + designDoc + '/_view/' + viewName;
   },
 
   fragment: function (database, designDoc, viewName) {
diff --git a/app/addons/documents/helpers.js b/app/addons/documents/helpers.js
index 69347aa..a5c5921 100644
--- a/app/addons/documents/helpers.js
+++ b/app/addons/documents/helpers.js
@@ -128,11 +128,22 @@
     && selectedNavItem.indexName);
 };
 
+const isDDocPartitioned = (ddoc, isDbPartitioned) => {
+  // By default a design doc is partitioned if the database is partitioned
+  let isDDocPartitioned = isDbPartitioned;
+  // Check if ddoc is explictly set to not partitioned
+  if (isDbPartitioned && ddoc.options && ddoc.options.partitioned === false) {
+    isDDocPartitioned = false;
+  }
+  return isDDocPartitioned;
+};
+
 export default {
   getSeqNum,
   getNewButtonLinks,
   getModifyDatabaseLinks,
   getNewDocUrl,
+  isDDocPartitioned,
   parseJSON,
   truncateDoc,
   selectedViewContainsReduceFunction,
diff --git a/app/addons/documents/index-editor/__tests__/components.test.js b/app/addons/documents/index-editor/__tests__/components.test.js
index fde338c..a3d4c20 100644
--- a/app/addons/documents/index-editor/__tests__/components.test.js
+++ b/app/addons/documents/index-editor/__tests__/components.test.js
@@ -11,7 +11,7 @@
 // the License.
 
 import React from 'react';
-import {mount} from 'enzyme';
+import {mount, shallow} from 'enzyme';
 import sinon from 'sinon';
 import FauxtonAPI from '../../../../core/api';
 import Views from '../components';
@@ -27,19 +27,20 @@
       hasCustomReduce: false,
       reduce: null,
       reduceSelectedOption: 'NONE',
+      customReducerSupported: true,
       updateReduceCode: () => {},
       selectReduceChanged: () => {}
     };
 
     it('returns null for none', () => {
-      const reduceEl = mount(<Views.ReduceEditor
+      const reduceEl = shallow(<Views.ReduceEditor
         {...defaultProps}
       />);
       expect(reduceEl.instance().getReduceValue()).toBeNull();
     });
 
     it('returns built in for built in reduce', () => {
-      const reduceEl = mount(<Views.ReduceEditor
+      const reduceEl = shallow(<Views.ReduceEditor
         {...defaultProps}
         reduce='_sum'
         hasReduce={true}
@@ -47,20 +48,38 @@
       expect(reduceEl.instance().getReduceValue()).toBe('_sum');
     });
 
+    it('shows warning when custom reduce is not supported', () => {
+      const reduceEl = shallow(<Views.ReduceEditor
+        {...defaultProps}
+        reduce='function() {}'
+        hasReduce={true}
+        customReducerSupported={false}
+      />);
+      expect(reduceEl.find('div.reduce-editor-warning').exists()).toBe(true);
+    });
+
   });
 });
 
 describe('DesignDocSelector component', () => {
+  const defaultProps = {
+    designDocList: ['_design/test-doc', '_design/test-doc2'],
+    newDesignDocName: '',
+    selectedDesignDocPartitioned: false,
+    isDbPartitioned: false,
+    newDesignDocPartitioned: false,
+    onChangeNewDesignDocName: () => {},
+    onSelectDesignDoc: () => {}
+  };
   let selectorEl;
 
   it('calls onSelectDesignDoc on change', () => {
     const spy = sinon.spy();
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc', '_design/test-doc2']}
+        {...defaultProps}
         selectedDDocName={'new-doc'}
         onSelectDesignDoc={spy}
-        onChangeNewDesignDocName={() => {}}
       />);
 
     selectorEl.find('.styled-select select').first().simulate('change', {
@@ -74,10 +93,8 @@
   it('shows new design doc field when set to new-doc', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'new-doc'}
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
 
     expect(selectorEl.find('#new-ddoc-section').length).toBe(1);
@@ -86,10 +103,8 @@
   it('hides new design doc field when design doc selected', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'_design/test-doc'}
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
 
     expect(selectorEl.find('#new-ddoc-section').length).toBe(0);
@@ -98,10 +113,8 @@
   it('always passes validation when design doc selected', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'_design/test-doc'}
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
 
     expect(selectorEl.instance().validate()).toBe(true);
@@ -110,11 +123,9 @@
   it('fails validation if new doc name entered/not entered', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'new-doc'}
         newDesignDocName=''
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
 
     // it shouldn't validate at this point: no new design doc name has been entered
@@ -124,11 +135,9 @@
   it('passes validation if new doc name entered/not entered', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'new-doc'}
         newDesignDocName='new-doc-name'
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
     expect(selectorEl.instance().validate()).toBe(true);
   });
@@ -137,10 +146,8 @@
   it('omits doc URL when not supplied', () => {
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'new-doc'}
-        onSelectDesignDoc={() => { }}
-        onChangeNewDesignDocName={() => {}}
       />);
     expect(selectorEl.find('.help-link').length).toBe(0);
   });
@@ -149,15 +156,39 @@
     const docLink = 'http://docs.com';
     selectorEl = mount(
       <Views.DesignDocSelector
-        designDocList={['_design/test-doc']}
+        {...defaultProps}
         selectedDesignDocName={'new-doc'}
-        onSelectDesignDoc={() => { }}
         docLink={docLink}
-        onChangeNewDesignDocName={() => {}}
       />);
     expect(selectorEl.find('.help-link').length).toBe(1);
     expect(selectorEl.find('.help-link').prop('href')).toBe(docLink);
   });
+
+  it('shows Partitioned checkbox only when db is partitioned', () => {
+    selectorEl = mount(
+      <Views.DesignDocSelector
+        {...defaultProps}
+        selectedDesignDocName={'new-doc'}
+      />);
+
+    expect(selectorEl.find('div.ddoc-selector-partitioned').exists()).toBe(false);
+
+    selectorEl.setProps({isDbPartitioned: true});
+    expect(selectorEl.find('div.ddoc-selector-partitioned').exists()).toBe(true);
+  });
+
+  it('calls onChangeNewDesignDocPartitioned when partitioned option changes', () => {
+    const spy = sinon.stub();
+    selectorEl = mount(
+      <Views.DesignDocSelector
+        {...defaultProps}
+        selectedDesignDocName={'new-doc'}
+        isDbPartitioned={true}
+        onChangeNewDesignDocPartitioned={spy}
+      />);
+    selectorEl.find('input#js-ddoc-selector-partitioned').simulate('change');
+    sinon.assert.called(spy);
+  });
 });
 
 describe('IndexEditor', () => {
@@ -165,12 +196,16 @@
     isLoading: false,
     isNewView: false,
     isNewDesignDoc: false,
+    isDbPartitioned: false,
     viewName: '',
-    database: {},
+    database: { safeID: () => 'test_db' },
+    newDesignDocName: '',
+    newDesignDocPartitioned: false,
     originalViewName: '',
     originalDesignDocName: '',
     designDoc: {},
     designDocId: '',
+    designDocPartitioned: false,
     designDocList: [],
     map: '',
     reduce: '',
@@ -179,6 +214,7 @@
     updateMapCode: () => {},
     selectDesignDoc: () => {},
     onChangeNewDesignDocName: () => {},
+    changeViewName: () => {},
     reduceOptions: [],
     reduceSelectedOption: 'NONE',
     hasReduce: false,
@@ -187,6 +223,10 @@
     selectReduceChanged: () => {}
   };
 
+  afterEach(() => {
+    sinon.restore();
+  });
+
   it('calls changeViewName on view name change', () => {
     const spy = sinon.spy();
     const editorEl = mount(<Views.IndexEditor
@@ -202,4 +242,23 @@
     });
     sinon.assert.calledWith(spy, 'newViewName');
   });
+
+  it('shows warning when trying to save a partitioned view with custom reduce', () => {
+    sinon.stub(FauxtonAPI, 'addNotification');
+    const editorEl = mount(<Views.IndexEditor
+      {...defaultProps}
+      viewName='new-name'
+      designDocId='new-doc'
+      newDesignDocName='test_ddoc'
+      newDesignDocPartitioned={true}
+      isDbPartitioned={true}
+      reduce='function() { /*custom reduce*/ }'
+    />);
+
+    editorEl.find('form.view-query-save').simulate('submit', {
+      preventDefault: () => {}
+    });
+    sinon.assert.calledWithMatch(FauxtonAPI.addNotification, { msg: 'Partitioned views do not support custom reduce functions.' });
+  });
+
 });
diff --git a/app/addons/documents/index-editor/__tests__/reducers.test.js b/app/addons/documents/index-editor/__tests__/reducers.test.js
index ee60b4e..c579010 100644
--- a/app/addons/documents/index-editor/__tests__/reducers.test.js
+++ b/app/addons/documents/index-editor/__tests__/reducers.test.js
@@ -11,7 +11,8 @@
 // the License.
 
 import Documents from '../../../documents/resources';
-import reducer, { hasCustomReduce, getDesignDocIds } from '../reducers';
+import reducer, { hasCustomReduce, getDesignDocList, getSelectedDesignDocPartitioned,
+  getSaveDesignDoc } from '../reducers';
 import ActionTypes from '../actiontypes';
 import '../../base';
 
@@ -252,7 +253,7 @@
 
     it('only filters mango docs', () => {
       const newState = reducer(undefined, editAction);
-      const designDocs = getDesignDocIds(newState);
+      const designDocs = getDesignDocList(newState);
 
       expect(designDocs.length).toBe(1);
       expect(designDocs[0]).toBe('_design/test-doc');
@@ -296,4 +297,55 @@
       expect(newState.view.reduce).toBe('_sum');
     });
   });
+
+  describe('getSelectedDesignDocPartitioned', () => {
+    const designDocs = [
+      {id: '_design/docGlobal', get: () => { return {options: { partitioned: false }}; }},
+      {id: '_design/docPartitioned', get: () => { return {options: { partitioned: true }}; }},
+      {id: '_design/docNoOptions', get: () => { return {};}}
+    ];
+
+    it('returns true for ddocs without partitioned flag on partitioned dbs', () => {
+      const isDbPartitioned = true;
+      const state = { designDocs, designDocId: '_design/docNoOptions' };
+      expect(getSelectedDesignDocPartitioned(state, isDbPartitioned)).toBe(true);
+    });
+
+    it('returns false for ddocs where partitioned is false on partitioned dbs', () => {
+      const isDbPartitioned = true;
+      const state = { designDocs, designDocId: '_design/docGlobal' };
+      expect(getSelectedDesignDocPartitioned(state, isDbPartitioned)).toBe(false);
+    });
+
+    it('returns true for ddocs where partitioned is true on partitioned dbs', () => {
+      const isDbPartitioned = true;
+      const state = { designDocs, designDocId: '_design/docPartitioned' };
+      expect(getSelectedDesignDocPartitioned(state, isDbPartitioned)).toBe(true);
+    });
+
+    it('any ddoc is global on non-partitioned dbs', () => {
+      const isDbPartitioned = false;
+      const state = { designDocs, designDocId: '_design/docGlobal' };
+      expect(getSelectedDesignDocPartitioned(state, isDbPartitioned)).toBe(false);
+
+      const state2 = { designDocs, designDocId: '_design/docPartitioned' };
+      expect(getSelectedDesignDocPartitioned(state2, isDbPartitioned)).toBe(false);
+
+      const state3 = { designDocs, designDocId: '_design/docNoOptions' };
+      expect(getSelectedDesignDocPartitioned(state3, isDbPartitioned)).toBe(false);
+    });
+
+  });
+
+  describe('getSaveDesignDoc', () => {
+
+    it('only sets partitioned flag when db is partitioned', () => {
+      const state = { designDocId: 'new-doc', newDesignDocPartitioned: true, };
+      const ddoc = getSaveDesignDoc(state, true);
+      expect(ddoc.get('options')).toEqual({ partitioned: true });
+
+      const ddoc2 = getSaveDesignDoc(state, false);
+      expect(ddoc2.get('options')).toBeUndefined();
+    });
+  });
 });
diff --git a/app/addons/documents/index-editor/actions.js b/app/addons/documents/index-editor/actions.js
index ad261e0..a6cf7e7 100644
--- a/app/addons/documents/index-editor/actions.js
+++ b/app/addons/documents/index-editor/actions.js
@@ -10,7 +10,6 @@
 // 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';
@@ -65,7 +64,7 @@
           viewInfo.originalViewName !== viewInfo.viewName;
 };
 
-const saveView = (viewInfo) => (dispatch) => {
+const saveView = (viewInfo, navigateToURL) => (dispatch) => {
   const designDoc = viewInfo.designDoc;
   designDoc.setDdocView(viewInfo.viewName, viewInfo.map, viewInfo.reduce);
 
@@ -103,8 +102,7 @@
     }
     SidebarActions.dispatchUpdateDesignDocs(viewInfo.designDocs);
     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 });
+    FauxtonAPI.navigate(navigateToURL, { trigger: true });
   }, (xhr) => {
     FauxtonAPI.addNotification({
       msg: 'Save failed. ' + (xhr.responseJSON ? `Reason: ${xhr.responseJSON.reason}` : ''),
@@ -146,7 +144,8 @@
 };
 
 const cloneView = (params) => {
-  const targetDesignDoc = getDesignDoc(params.designDocs, params.targetDesignDocName, params.newDesignDocName, params.database);
+  const targetDesignDoc = getDesignDoc(params.designDocs, params.targetDesignDocName, params.newDesignDocName,
+    params.newDesignDocPartitioned, params.database, params.isDbPartitioned);
   let indexes = targetDesignDoc.get('views');
   if (indexes && _.has(indexes, params.newIndexName)) {
     FauxtonAPI.addNotification({
@@ -223,6 +222,15 @@
   });
 };
 
+const updateNewDesignDocPartitioned = (isPartitioned) => (dispatch) => {
+  dispatch({
+    type: ActionTypes.DESIGN_DOC_NEW_PARTITIONED_UPDATED,
+    options: {
+      value: isPartitioned
+    }
+  });
+};
+
 // 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
 const safeDeleteIndex = (designDoc, designDocs, indexPropName, indexName, options) => {
@@ -277,14 +285,18 @@
   }).dDocModel();
 };
 
-const getDesignDoc = (designDocs, targetDesignDocName, newDesignDocName, database) => {
+const getDesignDoc = (designDocs, targetDesignDocName, newDesignDocName, newDesignDocPartitioned, database, isDbPartitioned) => {
   if (targetDesignDocName === 'new-doc') {
     const doc = {
       "_id": "_design/" + newDesignDocName,
       "views": {},
       "language": "javascript"
     };
-    return new Documents.Doc(doc, { database: database });
+    const dDoc = new Documents.Doc(doc, { database: database });
+    if (isDbPartitioned) {
+      dDoc.setDDocPartitionedOption(newDesignDocPartitioned);
+    }
+    return dDoc;
   }
 
   const foundDoc = designDocs.find(function (ddoc) {
@@ -314,5 +326,6 @@
   updateMapCode,
   updateReduceCode,
   selectDesignDoc,
-  updateNewDesignDocName
+  updateNewDesignDocName,
+  updateNewDesignDocPartitioned
 };
diff --git a/app/addons/documents/index-editor/actiontypes.js b/app/addons/documents/index-editor/actiontypes.js
index 920bd9f..ef746df 100644
--- a/app/addons/documents/index-editor/actiontypes.js
+++ b/app/addons/documents/index-editor/actiontypes.js
@@ -19,6 +19,7 @@
   VIEW_CREATED: 'VIEW_CREATED',
   DESIGN_DOC_CHANGE: 'DESIGN_DOC_CHANGE',
   DESIGN_DOC_NEW_NAME_UPDATED: 'DESIGN_DOC_NEW_NAME_UPDATED',
+  DESIGN_DOC_NEW_PARTITIONED_UPDATED: 'DESIGN_DOC_NEW_PARTITIONED_UPDATED',
   NEW_DESIGN_DOC: 'NEW_DESIGN_DOC',
   VIEW_NAME_CHANGE: 'VIEW_NAME_CHANGE',
   VIEW_ADD_DESIGN_DOC: 'VIEW_ADD_DESIGN_DOC',
diff --git a/app/addons/documents/index-editor/components/DesignDocSelector.js b/app/addons/documents/index-editor/components/DesignDocSelector.js
index 57c6bbc..a524c32 100644
--- a/app/addons/documents/index-editor/components/DesignDocSelector.js
+++ b/app/addons/documents/index-editor/components/DesignDocSelector.js
@@ -21,6 +21,7 @@
 
   constructor(props) {
     super(props);
+    this.onTogglePartitioned = this.onTogglePartitioned.bind(this);
   }
 
   validate() {
@@ -80,6 +81,39 @@
     );
   }
 
+  onTogglePartitioned() {
+    this.props.onChangeNewDesignDocPartitioned(!this.props.newDesignDocPartitioned);
+  }
+
+  getPartitionedCheckbox() {
+    if (!this.props.isDbPartitioned) {
+      return null;
+    }
+    const isExistingDDoc = this.props.selectedDesignDocName !== 'new-doc';
+    const checked = isExistingDDoc ?
+      this.props.selectedDesignDocPartitioned :
+      this.props.newDesignDocPartitioned;
+    const labelClass = isExistingDDoc ? 'check--disabled' : '';
+    const inputTitle = isExistingDDoc ?
+      (this.props.selectedDesignDocPartitioned ? 'Design document is partitioned' : 'Design document is not partitioned') :
+      (this.props.newDesignDocPartitioned ? 'New document will be partitioned' : 'New document will not be partitioned');
+    return (
+      <div className="ddoc-selector-partitioned">
+        <label className={labelClass} title={inputTitle}>
+          <input
+            id="js-ddoc-selector-partitioned"
+            type="checkbox"
+            title={inputTitle}
+            checked={checked}
+            onChange={this.onTogglePartitioned}
+            style={{margin: '0px 10px 0px 0px'}}
+            disabled={isExistingDDoc}/>
+          Partitioned
+        </label>
+      </div>
+    );
+  }
+
   render() {
     const selectContent =
       <optgroup label="Select a document">
@@ -101,6 +135,7 @@
           />
         </div>
         {this.getNewDDocField()}
+        {this.getPartitionedCheckbox()}
       </div>
     );
   }
@@ -117,7 +152,9 @@
   onSelectDesignDoc: PropTypes.func.isRequired,
   onChangeNewDesignDocName: PropTypes.func.isRequired,
   selectedDesignDocName: PropTypes.string.isRequired,
+  selectedDesignDocPartitioned: PropTypes.bool.isRequired,
   newDesignDocName: PropTypes.string.isRequired,
+  newDesignDocPartitioned: PropTypes.bool.isRequired,
   designDocLabel: PropTypes.string,
   docURL: PropTypes.string
 };
diff --git a/app/addons/documents/index-editor/components/IndexEditor.js b/app/addons/documents/index-editor/components/IndexEditor.js
index 332b749..2d1a2cc 100644
--- a/app/addons/documents/index-editor/components/IndexEditor.js
+++ b/app/addons/documents/index-editor/components/IndexEditor.js
@@ -25,6 +25,9 @@
 
   constructor(props) {
     super(props);
+    this.saveView = this.saveView.bind(this);
+    this.viewChange = this.viewChange.bind(this);
+    this.updateMapCode = this.updateMapCode.bind(this);
   }
 
   // the code editor is a standalone component, so if the user goes from one edit view page to another, we need to
@@ -35,6 +38,21 @@
     }
   }
 
+  isPartitionedView() {
+    if (this.props.designDocId === 'new-doc') {
+      return this.props.newDesignDocPartitioned;
+    }
+    return this.props.designDocPartitioned;
+  }
+
+  isCustomReduceSupported() {
+    if (this.props.isDbPartitioned && this.props.reduce && !this.props.reduce.startsWith('_')) {
+      const isDDocPartitioned = this.props.designDocId === 'new-doc' ? this.props.newDesignDocPartitioned : this.props.designDocPartitioned;
+      return isDDocPartitioned ? false : true;
+    }
+    return true;
+  }
+
   saveView(el) {
     el.preventDefault();
 
@@ -42,6 +60,18 @@
       return;
     }
 
+    if (!this.isCustomReduceSupported()) {
+      FauxtonAPI.addNotification({
+        msg: 'Partitioned views do not support custom reduce functions.',
+        type: 'error',
+        clear: true
+      });
+      return;
+    }
+
+    const encodedPartKey = this.isPartitionedView() && this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
+    const url = FauxtonAPI.urls('view', 'showView', this.props.database.safeID(), encodedPartKey,
+      this.props.saveDesignDoc.safeID(), encodeURIComponent(this.props.viewName));
     this.props.saveView({
       database: this.props.database,
       isNewView: this.props.isNewView,
@@ -54,7 +84,7 @@
       map: this.mapEditor.getValue(),
       reduce: this.reduceEditor.getReduceValue(),
       designDocs: this.props.designDocs
-    });
+    }, url);
   }
 
   viewChange(el) {
@@ -65,6 +95,17 @@
     this.props.updateMapCode(code);
   }
 
+  getCancelLink() {
+    const encodedDatabase = encodeURIComponent(this.props.database.id);
+    const encodedPartitionKey = this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
+    const encodedDDoc = encodeURIComponent(this.props.designDocId);
+    const encodedView = encodeURIComponent(this.props.viewName);
+    if (this.props.designDocId === 'new-doc' || this.props.isNewView) {
+      return '#' + FauxtonAPI.urls('allDocs', 'app', encodedDatabase, encodedPartitionKey);
+    }
+    return '#' + FauxtonAPI.urls('view', 'showView', encodedDatabase, encodedPartitionKey, encodedDDoc, encodedView);
+  }
+
   render() {
     if (this.props.isLoading) {
       return (
@@ -76,20 +117,23 @@
 
     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)}>
+        <form className="form-horizontal view-query-save" onSubmit={this.saveView}>
           <h3 className="simple-header">{pageHeader}</h3>
 
           <div className="new-ddoc-section">
             <DesignDocSelector
               ref={(el) => { this.designDocSelector = el; }}
               designDocList={this.props.designDocList}
+              isDbPartitioned={this.props.isDbPartitioned}
               selectedDesignDocName={this.props.designDocId}
+              selectedDesignDocPartitioned={this.props.designDocPartitioned}
               newDesignDocName={this.props.newDesignDocName}
+              newDesignDocPartitioned={this.props.newDesignDocPartitioned}
               onSelectDesignDoc={this.props.selectDesignDoc}
               onChangeNewDesignDocName={this.props.updateNewDesignDocName}
+              onChangeNewDesignDocPartitioned={this.props.updateNewDesignDocPartitioned}
               docLink={getDocUrl('DESIGN_DOCS')} />
           </div>
 
@@ -109,7 +153,7 @@
               type="text"
               id="index-name"
               value={this.props.viewName}
-              onChange={this.viewChange.bind(this)}
+              onChange={this.viewChange}
               placeholder="Index name" />
           </div>
           <CodeEditorPanel
@@ -117,14 +161,17 @@
             ref={(el) => { this.mapEditor = el; }}
             title={"Map function"}
             docLink={getDocUrl('MAP_FUNCS')}
-            blur={this.updateMapCode.bind(this)}
+            blur={this.updateMapCode}
             allowZenMode={false}
             defaultCode={this.props.map} />
-          <ReduceEditor ref={(el) => { this.reduceEditor = el; }} {...this.props} />
+          <ReduceEditor
+            ref={(el) => { this.reduceEditor = el; }}
+            customReducerSupported={this.isCustomReduceSupported()}
+            {...this.props} />
           <div className="padded-box">
             <div className="control-group">
               <ConfirmButton id="save-view" text={btnLabel} />
-              <a href={cancelLink} className="index-cancel-link">Cancel</a>
+              <a href={this.getCancelLink()} className="index-cancel-link">Cancel</a>
             </div>
           </div>
         </form>
@@ -137,13 +184,16 @@
   isLoading:PropTypes.bool.isRequired,
   isNewView: PropTypes.bool.isRequired,
   database: PropTypes.object.isRequired,
+  isDbPartitioned: PropTypes.bool.isRequired,
   designDocId: PropTypes.string.isRequired,
+  newDesignDocName: PropTypes.string.isRequired,
   viewName: PropTypes.string.isRequired,
   isNewDesignDoc: PropTypes.bool.isRequired,
   originalViewName: PropTypes.string,
   originalDesignDocName: PropTypes.string,
   designDocs: PropTypes.object,
   saveDesignDoc: PropTypes.object,
+  partitionKey: PropTypes.string,
   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
index 445b029..2e7a136 100644
--- a/app/addons/documents/index-editor/components/IndexEditorContainer.js
+++ b/app/addons/documents/index-editor/components/IndexEditorContainer.js
@@ -13,35 +13,41 @@
 import { connect } from 'react-redux';
 import IndexEditor from './IndexEditor';
 import Actions from '../actions';
-import { getSaveDesignDoc, getDesignDocIds, reduceSelectedOption, hasCustomReduce } from '../reducers';
+import { getSaveDesignDoc, getDesignDocList, reduceSelectedOption, hasCustomReduce,
+  getSelectedDesignDocPartitioned } from '../reducers';
 
-const mapStateToProps = ({ indexEditor }) => {
+const mapStateToProps = ({ indexEditor, databases }, ownProps) => {
+  const isSelectedDDocPartitioned = getSelectedDesignDocPartitioned(indexEditor, databases.isDbPartitioned);
   return {
     database: indexEditor.database,
     isNewView: indexEditor.isNewView,
     viewName: indexEditor.viewName,
     designDocs: indexEditor.designDocs,
-    designDocList: getDesignDocIds(indexEditor),
+    designDocList: getDesignDocList(indexEditor),
     originalViewName: indexEditor.originalViewName,
     originalDesignDocName: indexEditor.originalDesignDocName,
     isNewDesignDoc: indexEditor.isNewDesignDoc,
     designDocId: indexEditor.designDocId,
+    designDocPartitioned: isSelectedDDocPartitioned,
     newDesignDocName: indexEditor.newDesignDocName,
-    saveDesignDoc: getSaveDesignDoc(indexEditor),
+    newDesignDocPartitioned: indexEditor.newDesignDocPartitioned,
+    saveDesignDoc: getSaveDesignDoc(indexEditor, databases.isDbPartitioned),
     map: indexEditor.view.map,
     isLoading: indexEditor.isLoading,
     reduce: indexEditor.view.reduce,
     reduceOptions: indexEditor.reduceOptions,
     reduceSelectedOption: reduceSelectedOption(indexEditor),
     hasCustomReduce: hasCustomReduce(indexEditor),
-    hasReduce: !!indexEditor.view.reduce
+    hasReduce: !!indexEditor.view.reduce,
+    isDbPartitioned: databases.isDbPartitioned,
+    partitionKey: ownProps.partitionKey
   };
 };
 
 const mapDispatchToProps = (dispatch) => {
   return {
-    saveView: (viewInfo) => {
-      dispatch(Actions.saveView(viewInfo));
+    saveView: (viewInfo, navigateToURL) => {
+      dispatch(Actions.saveView(viewInfo, navigateToURL));
     },
 
     changeViewName: (name) => {
@@ -60,6 +66,10 @@
       dispatch(Actions.updateNewDesignDocName(designDocName));
     },
 
+    updateNewDesignDocPartitioned: (isPartitioned) => {
+      dispatch(Actions.updateNewDesignDocPartitioned(isPartitioned));
+    },
+
     updateReduceCode: (code) => {
       dispatch(Actions.updateReduceCode(code));
     },
diff --git a/app/addons/documents/index-editor/components/ReduceEditor.js b/app/addons/documents/index-editor/components/ReduceEditor.js
index 7f1df52..2520576 100644
--- a/app/addons/documents/index-editor/components/ReduceEditor.js
+++ b/app/addons/documents/index-editor/components/ReduceEditor.js
@@ -58,7 +58,7 @@
     const reduceOptions = this.getOptionsList();
     let customReduceSection;
 
-    if (this.props.hasCustomReduce) {
+    if (this.props.hasCustomReduce && this.props.customReducerSupported) {
       customReduceSection = <CodeEditorPanel
         ref={node => this.reduceEditor = node}
         id='reduce-function'
@@ -67,6 +67,12 @@
         allowZenMode={false}
         blur={this.updateReduceCode.bind(this)}
       />;
+    } else if (!this.props.customReducerSupported) {
+      customReduceSection = (
+        <div className="reduce-editor-warning">
+          <label>Partitioned views do not support custom reduce functions.</label>
+        </div>
+      );
     }
 
     return (
@@ -96,10 +102,15 @@
   }
 }
 
+ReduceEditor.defaultProps = {
+  customReducerSupported: true
+};
+
 ReduceEditor.propTypes = {
   reduceOptions: PropTypes.array.isRequired,
   hasReduce: PropTypes.bool.isRequired,
   hasCustomReduce: PropTypes.bool.isRequired,
+  customReducerSupported: PropTypes.bool,
   reduce: PropTypes.string,
   reduceSelectedOption: PropTypes.string.isRequired,
   updateReduceCode: PropTypes.func.isRequired,
diff --git a/app/addons/documents/index-editor/reducers.js b/app/addons/documents/index-editor/reducers.js
index 663818f..51988f6 100644
--- a/app/addons/documents/index-editor/reducers.js
+++ b/app/addons/documents/index-editor/reducers.js
@@ -11,11 +11,13 @@
 // the License.
 
 import ActionTypes from './actiontypes';
-import Resources from "../resources";
+import Resources from '../resources';
+import Helpers from '../helpers';
 
 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 builtInReducers = ['_sum', '_count', '_stats', '_approx_count_distinct'];
+const allReducers = builtInReducers.concat(['CUSTOM', 'NONE']);
 
 const initialState = {
   designDocs: new Backbone.Collection(),
@@ -25,11 +27,12 @@
   designDocId: '',
   isNewDesignDoc: false,
   newDesignDocName: '',
+  newDesignDocPartitioned: true,
   isNewView: false,
   viewName: '',
   originalViewName: '',
   originalDesignDocName: '',
-  reduceOptions: builtInReducers.concat(['CUSTOM', 'NONE'])
+  reduceOptions: allReducers
 };
 
 function editIndex(state, options) {
@@ -61,6 +64,16 @@
   return designDoc.get('views')[state.viewName];
 }
 
+export function getSelectedDesignDocPartitioned(state, isDbPartitioned) {
+  const designDoc = state.designDocs.find(ddoc => {
+    return state.designDocId === ddoc.id;
+  });
+  if (designDoc) {
+    return Helpers.isDDocPartitioned(designDoc.get('doc'), isDbPartitioned);
+  }
+  return false;
+}
+
 export function reduceSelectedOption(state) {
   if (!state.view.reduce) {
     return 'NONE';
@@ -78,14 +91,18 @@
   return false;
 }
 
-export function getSaveDesignDoc(state) {
+export function getSaveDesignDoc(state, isDbPartitioned) {
   if (state.designDocId === 'new-doc') {
     const doc = {
       _id: '_design/' + state.newDesignDocName,
       views: {},
       language: 'javascript'
     };
-    return new Resources.Doc(doc, { database: state.database });
+    const dDoc = new Resources.Doc(doc, { database: state.database });
+    if (isDbPartitioned) {
+      dDoc.setDDocPartitionedOption(state.newDesignDocPartitioned);
+    }
+    return dDoc;
   }
 
   if (!state.designDocs) {
@@ -100,7 +117,7 @@
 }
 
 // returns a simple array of design doc IDs. Omits mango docs
-export function getDesignDocIds(state) {
+export function getDesignDocList(state) {
   if (!state.designDocs) {
     return [];
   }
@@ -190,6 +207,12 @@
         newDesignDocName: options.value
       };
 
+    case ActionTypes.DESIGN_DOC_NEW_PARTITIONED_UPDATED:
+      return {
+        ...state,
+        newDesignDocPartitioned: options.value
+      };
+
     default:
       return state;
   }
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index 0d59329..9c39f13 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -249,7 +249,7 @@
   dbName, dropDownLinks, selectedNavItem, designDocInfo, partitionKey }) => {
 
   const content = showEditView ?
-    <IndexEditorComponents.IndexEditorContainer /> :
+    <IndexEditorComponents.IndexEditorContainer partitionKey={partitionKey}/> :
     <DesignDocInfoContainer
       designDocInfo={designDocInfo}
       designDocName={selectedNavItem.designDocName}/>;
diff --git a/app/addons/documents/mango/components/MangoQueryEditor.js b/app/addons/documents/mango/components/MangoQueryEditor.js
index ecbfea0..a702955 100644
--- a/app/addons/documents/mango/components/MangoQueryEditor.js
+++ b/app/addons/documents/mango/components/MangoQueryEditor.js
@@ -145,8 +145,9 @@
 
     this.props.manageIndexes();
 
+    const encodedPartKey = this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
     const manageIndexURL = '#' + FauxtonAPI.urls('mango', 'index-app',
-      encodeURIComponent(this.props.databaseName), encodeURIComponent(this.props.partitionKey));
+      encodeURIComponent(this.props.databaseName), encodedPartKey);
     FauxtonAPI.navigate(manageIndexURL);
   }
 
diff --git a/app/addons/documents/mango/mango.api.js b/app/addons/documents/mango/mango.api.js
index 9655592..59cbebf 100644
--- a/app/addons/documents/mango/mango.api.js
+++ b/app/addons/documents/mango/mango.api.js
@@ -16,7 +16,8 @@
 import Constants from '../constants';
 
 export const fetchQueryExplain = (databaseName, partitionKey, queryCode) => {
-  const url = FauxtonAPI.urls('mango', 'explain-server', encodeURIComponent(databaseName), encodeURIComponent(partitionKey));
+  const encodedPartKey = partitionKey ? encodeURIComponent(partitionKey) : '';
+  const url = FauxtonAPI.urls('mango', 'explain-server', encodeURIComponent(databaseName), encodedPartKey);
 
   return post(url, queryCode, {rawBody: true}).then((json) => {
     if (json.error) {
diff --git a/app/addons/documents/mangolayout.js b/app/addons/documents/mangolayout.js
index 504b7df..70b3e93 100644
--- a/app/addons/documents/mangolayout.js
+++ b/app/addons/documents/mangolayout.js
@@ -165,7 +165,8 @@
     let endpoint = this.props.endpoint;
 
     if (this.props.explainPlan) {
-      endpoint = FauxtonAPI.urls('mango', 'explain-apiurl', encodeURIComponent(database), encodeURIComponent(partitionKey));
+      const encodedPartKey = partitionKey ? encodeURIComponent(partitionKey) : '';
+      endpoint = FauxtonAPI.urls('mango', 'explain-apiurl', encodeURIComponent(database), encodedPartKey);
     }
     let queryFunction = (params) => { return MangoAPI.mangoQueryDocs(databaseName, partitionKey, queryFindCode, params); };
     let docType = Constants.INDEX_RESULTS_DOC_TYPE.MANGO_QUERY;
diff --git a/app/addons/documents/routes-mango.js b/app/addons/documents/routes-mango.js
index 4e555d6..b4981f0 100644
--- a/app/addons/documents/routes-mango.js
+++ b/app/addons/documents/routes-mango.js
@@ -57,7 +57,7 @@
       'allDocs', 'app', encodeURIComponent(this.databaseName), encodedPartitionKey
     );
 
-    const partKeyUrlComponent = partitionKey ? `/${encodeURIComponent(partitionKey)}` : '';
+    const partKeyUrlComponent = partitionKey ? `/${encodedPartitionKey}` : '';
     const fetchUrl = '/' + encodeURIComponent(this.databaseName) + partKeyUrlComponent + '/_find';
 
     const crumbs = [
diff --git a/app/addons/documents/shared-resources.js b/app/addons/documents/shared-resources.js
index ac5c0e0..d0ff692 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -100,6 +100,20 @@
     return this.docType() === "design doc";
   },
 
+  setDDocPartitionedOption: function (isPartitioned) {
+    if (!this.isDdoc()) {
+      return false;
+    }
+    let options = this.get('options');
+    if (!options) {
+      options = {};
+    }
+    options.partitioned = isPartitioned;
+    this.set({ options });
+
+    return true;
+  },
+
   setDdocView: function (view, map, reduce) {
     if (!this.isDdoc()) {
       return false;
diff --git a/app/addons/documents/sidebar/SidebarControllerContainer.js b/app/addons/documents/sidebar/SidebarControllerContainer.js
index 550f3b7..9b85a26 100644
--- a/app/addons/documents/sidebar/SidebarControllerContainer.js
+++ b/app/addons/documents/sidebar/SidebarControllerContainer.js
@@ -13,7 +13,7 @@
 import { connect } from 'react-redux';
 import SidebarComponents from './sidebar';
 import Action from './actions';
-import { getDatabase } from './reducers';
+import { getDatabase, getDesignDocPartitioned } from './reducers';
 
 
 // returns a simple array of design doc IDs
@@ -69,7 +69,9 @@
     cloneIndexModalVisible: sidebar.cloneIndexModalVisible,
     cloneIndexModalTitle: sidebar.cloneIndexModalTitle,
     cloneIndexModalSelectedDesignDoc: sidebar.cloneIndexModalSelectedDesignDoc,
+    cloneIndexModalSelectedDesignDocPartitioned: getDesignDocPartitioned(sidebar, databases.isDbPartitioned),
     cloneIndexModalNewDesignDocName: sidebar.cloneIndexModalNewDesignDocName,
+    cloneIndexModalNewDesignDocPartitioned: sidebar.cloneIndexModalNewDesignDocPartitioned,
     cloneIndexModalOnSubmit: sidebar.cloneIndexModalOnSubmit,
     cloneIndexDesignDocProp: sidebar.cloneIndexDesignDocProp,
     cloneIndexModalNewIndexName: sidebar.cloneIndexModalNewIndexName,
@@ -102,6 +104,9 @@
     updateNewDesignDocName: (designDocName) => {
       dispatch(Action.updateNewDesignDocName(designDocName));
     },
+    updateNewDesignDocPartitioned: (isPartitioned) => {
+      dispatch(Action.updateNewDesignDocPartitioned(isPartitioned));
+    },
     setNewCloneIndexName: (indexName) => {
       dispatch(Action.setNewCloneIndexName(indexName));
     }
diff --git a/app/addons/documents/sidebar/actions.js b/app/addons/documents/sidebar/actions.js
index 7564b3c..d8ba4cd 100644
--- a/app/addons/documents/sidebar/actions.js
+++ b/app/addons/documents/sidebar/actions.js
@@ -131,6 +131,15 @@
   });
 };
 
+const updateNewDesignDocPartitioned = (isPartitioned) => (dispatch) => {
+  dispatch({
+    type: ActionTypes.SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_PARTITIONED_UPDATED,
+    options: {
+      value: isPartitioned
+    }
+  });
+};
+
 const selectDesignDoc = (designDoc) => (dispatch) => {
   dispatch({
     type: ActionTypes.SIDEBAR_CLONE_MODAL_DESIGN_DOC_CHANGE,
@@ -159,6 +168,7 @@
   showCloneIndexModal,
   hideCloneIndexModal,
   updateNewDesignDocName,
+  updateNewDesignDocPartitioned,
   selectDesignDoc,
   setNewCloneIndexName,
   dispatchExpandSelectedItem
diff --git a/app/addons/documents/sidebar/actiontypes.js b/app/addons/documents/sidebar/actiontypes.js
index 666b8a9..28c84fc 100644
--- a/app/addons/documents/sidebar/actiontypes.js
+++ b/app/addons/documents/sidebar/actiontypes.js
@@ -21,6 +21,7 @@
   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_DESIGN_DOC_NEW_PARTITIONED_UPDATED: 'SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_PARTITIONED_UPDATED',
   SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME: 'SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME',
   SIDEBAR_UPDATED_DESIGN_DOCS: 'SIDEBAR_UPDATED_DESIGN_DOCS'
 };
diff --git a/app/addons/documents/sidebar/components/CloneIndexModal.js b/app/addons/documents/sidebar/components/CloneIndexModal.js
index 220e8ab..ca83562 100644
--- a/app/addons/documents/sidebar/components/CloneIndexModal.js
+++ b/app/addons/documents/sidebar/components/CloneIndexModal.js
@@ -89,10 +89,14 @@
               <DesignDocSelector
                 ref={node => this.designDocSelector = node}
                 designDocList={this.props.designDocArray}
+                isDbPartitioned={this.props.isDbPartitioned}
                 selectedDesignDocName={this.props.selectedDesignDoc}
+                selectedDesignDocPartitioned={this.props.selectedDesignDocPartitioned}
                 newDesignDocName={this.props.newDesignDocName}
+                newDesignDocPartitioned={this.props.newDesignDocPartitioned}
                 onSelectDesignDoc={this.props.selectDesignDoc}
-                onChangeNewDesignDocName={this.props.updateNewDesignDocName} />
+                onChangeNewDesignDocName={this.props.updateNewDesignDocName}
+                onChangeNewDesignDocPartitioned={this.props.updateNewDesignDocPartitioned} />
             </div>
 
             <div className="clone-index-name-row">
diff --git a/app/addons/documents/sidebar/components/DesignDocList.js b/app/addons/documents/sidebar/components/DesignDocList.js
index 2113470..c520659 100644
--- a/app/addons/documents/sidebar/components/DesignDocList.js
+++ b/app/addons/documents/sidebar/components/DesignDocList.js
@@ -12,8 +12,8 @@
 
 import PropTypes from 'prop-types';
 import React from 'react';
-import ReactDOM from 'react-dom';
 import FauxtonAPI from '../../../../core/api';
+import DocHelpers from '../../helpers';
 import DesignDoc from './DesignDoc';
 
 export default class DesignDocList extends React.Component {
@@ -43,12 +43,7 @@
   designDocList = () => {
     return _.map(this.props.designDocs, (designDoc, key) => {
       const ddName = decodeURIComponent(designDoc.safeId);
-      // By default a design doc is partitioned if the database is partitioned
-      let isDDocPartitioned = this.props.isDbPartitioned;
-      // Check if it is explictly set to not partitioned
-      if (this.props.isDbPartitioned && designDoc.options && designDoc.options.partitioned === false) {
-        isDDocPartitioned = false;
-      }
+      const isDDocPartitioned = DocHelpers.isDDocPartitioned(designDoc, this.props.isDbPartitioned);
 
       // only pass down the selected nav info and toggle info if they're relevant for this particular design doc
       let expanded = false,
diff --git a/app/addons/documents/sidebar/components/SidebarController.js b/app/addons/documents/sidebar/components/SidebarController.js
index b37c8ac..bda4bfa 100644
--- a/app/addons/documents/sidebar/components/SidebarController.js
+++ b/app/addons/documents/sidebar/components/SidebarController.js
@@ -12,7 +12,6 @@
 
 import PropTypes from 'prop-types';
 import React from 'react';
-import ReactDOM from 'react-dom';
 import ComponentsActions from "../../../components/actions";
 import Components from '../../../components/react-components';
 import ComponentsStore from '../../../components/stores';
@@ -91,6 +90,8 @@
       sourceDesignDocName: this.props.cloneIndexSourceDesignDocName,
       targetDesignDocName: this.props.cloneIndexModalSelectedDesignDoc,
       newDesignDocName: this.props.cloneIndexModalNewDesignDocName,
+      newDesignDocPartitioned: this.props.cloneIndexModalNewDesignDocPartitioned,
+      isDbPartitioned: this.props.isDbPartitioned,
       newIndexName: this.props.cloneIndexModalNewIndexName,
       designDocs: this.props.designDocs,
       database: this.props.database,
@@ -137,12 +138,16 @@
           submit={this.cloneIndex}
           designDocArray={this.props.availableDesignDocIds}
           selectedDesignDoc={this.props.cloneIndexModalSelectedDesignDoc}
+          selectedDesignDocPartitioned={this.props.cloneIndexModalSelectedDesignDocPartitioned}
           newDesignDocName={this.props.cloneIndexModalNewDesignDocName}
+          newDesignDocPartitioned={this.props.cloneIndexModalNewDesignDocPartitioned}
           newIndexName={this.props.cloneIndexModalNewIndexName}
           indexLabel={this.props.cloneIndexModalIndexLabel}
           selectDesignDoc={this.props.selectDesignDoc}
           updateNewDesignDocName={this.props.updateNewDesignDocName}
-          setNewCloneIndexName={this.props.setNewCloneIndexName} />
+          updateNewDesignDocPartitioned={this.props.updateNewDesignDocPartitioned}
+          setNewCloneIndexName={this.props.setNewCloneIndexName}
+          isDbPartitioned={this.props.isDbPartitioned} />
       </nav>
     );
   }
diff --git a/app/addons/documents/sidebar/reducers.js b/app/addons/documents/sidebar/reducers.js
index f1fa140..a5491d8 100644
--- a/app/addons/documents/sidebar/reducers.js
+++ b/app/addons/documents/sidebar/reducers.js
@@ -10,9 +10,10 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-import React from "react";
-import app from "../../../app";
-import ActionTypes from "./actiontypes";
+import React from 'react';
+import app from '../../../app';
+import Helpers from '../helpers';
+import ActionTypes from './actiontypes';
 
 const initialState = {
   designDocs: new Backbone.Collection(),
@@ -37,6 +38,7 @@
   cloneIndexModalTitle: '',
   cloneIndexModalSelectedDesignDoc: '',
   cloneIndexModalNewDesignDocName: '',
+  cloneIndexModalNewDesignDocPartitioned: true,
   cloneIndexModalNewIndexName: '',
   cloneIndexModalSourceIndexName: '',
   cloneIndexModalSourceDesignDocName: '',
@@ -136,6 +138,16 @@
   return ddocsList;
 }
 
+export function getDesignDocPartitioned(state, isDbPartitioned) {
+  const designDoc = state.designDocs.find(ddoc => {
+    return state.cloneIndexModalSelectedDesignDoc == ddoc.id;
+  });
+  if (designDoc) {
+    return Helpers.isDDocPartitioned(designDoc.get('doc'), isDbPartitioned);
+  }
+  return false;
+}
+
 export const getDatabase = (state) => {
   if (state.loading) {
     return {};
@@ -214,6 +226,12 @@
         cloneIndexModalNewDesignDocName: options.value
       };
 
+    case ActionTypes.SIDEBAR_CLONE_MODAL_DESIGN_DOC_NEW_PARTITIONED_UPDATED:
+      return {
+        ...state,
+        cloneIndexModalNewDesignDocPartitioned: options.value
+      };
+
     case ActionTypes.SIDEBAR_CLONE_MODAL_UPDATE_INDEX_NAME:
       return {
         ...state,
diff --git a/app/addons/documents/tests/nightwatch/viewCreateBadView.js b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
index 66eb74a..7405ed0 100644
--- a/app/addons/documents/tests/nightwatch/viewCreateBadView.js
+++ b/app/addons/documents/tests/nightwatch/viewCreateBadView.js
@@ -31,7 +31,7 @@
       .clearValue('#index-name')
       .setValue('#index-name', 'hasenindex')
       .clickWhenVisible('#reduce-function-selector')
-      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
+      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
       .execute('\
         var editor = ace.edit("map-function");\
         editor.getSession().setValue("function (doc) { emit(\'boom\', doc._id); }");\
diff --git a/app/addons/documents/tests/nightwatch/viewEdit.js b/app/addons/documents/tests/nightwatch/viewEdit.js
index 6214a8e..6a1dd41 100644
--- a/app/addons/documents/tests/nightwatch/viewEdit.js
+++ b/app/addons/documents/tests/nightwatch/viewEdit.js
@@ -128,7 +128,7 @@
       .clearValue('#index-name')
       .setValue('#index-name', 'view1')
       .clickWhenVisible('#reduce-function-selector')
-      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
+      .keys(['\uE013', '\uE013', '\uE013', '\uE013', '\uE013', '\uE006'])
       .execute('\
         var editor = ace.edit("map-function");\
         editor.getSession().setValue("function (doc) { emit(doc._id, 100); }");\