You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2016/12/08 10:16:49 UTC

[2/2] fauxton commit: updated refs/heads/master to a231a4e

Move to all React

This removes the last parts of backbone.layout manager. We now have a
single React entry point.

PR: #820
PR-URL: https://github.com/apache/couchdb-fauxton/pull/820
Reviewed-By: Robert Kowalski <ro...@kowalski.gd>


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

Branch: refs/heads/master
Commit: a231a4e4a0b6f55daf49c45753ae1c59de24a4a2
Parents: 2cec2e4
Author: Garren Smith <ga...@gmail.com>
Authored: Mon Dec 5 11:57:08 2016 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Thu Dec 8 11:16:01 2016 +0100

----------------------------------------------------------------------
 .eslintrc                                       |   3 +-
 .travis.yml                                     |   1 +
 Gruntfile.js                                    |  58 +-
 app/addons/activetasks/routes.js                |   5 +-
 app/addons/auth/routes.js                       |  32 +-
 app/addons/cluster/routes.js                    |  18 +-
 app/addons/components/__tests__/polling.test.js | 107 ++++
 app/addons/components/tests/pollingSpec.js      | 108 ----
 app/addons/config/routes.js                     |  29 +-
 app/addons/databases/routes.js                  |   2 +-
 app/addons/documentation/routes.js              |  10 +-
 app/addons/documents/doc-editor/actions.js      |   2 +-
 .../documents/doc-editor/components.react.jsx   |   5 +-
 .../documents/index-editor/tests/actionsSpec.js |   1 -
 app/addons/documents/index-results/actions.js   |   8 +-
 .../index-results.components.react.jsx          |   6 +-
 .../tests/index-results.actionsSpec.js          |  24 +-
 app/addons/documents/layouts.js                 |   4 +-
 app/addons/documents/mangolayout.js             |   8 +-
 app/addons/documents/resources.js               |   4 -
 app/addons/documents/routes-doc-editor.js       |  38 +-
 app/addons/documents/routes-documents.js        |  63 +--
 app/addons/documents/routes-index-editor.js     |  57 +-
 app/addons/documents/routes-mango.js            |  46 +-
 app/addons/documents/sidebar/actions.js         |   9 +-
 app/addons/documents/sidebar/actiontypes.js     |   1 -
 app/addons/documents/sidebar/stores.react.jsx   |   4 +-
 .../documents/tests/nightwatch/cloneDoc.js      |   2 +-
 app/addons/fauxton/appwrapper.js                |  71 +++
 app/addons/fauxton/base.js                      |  14 -
 .../fauxton/navigation/components.react.jsx     |   5 +-
 .../navigation/tests/componentsSpec.react.jsx   |  24 +-
 .../notifications/notifications.react.jsx       |  16 +-
 app/addons/permissions/routes.js                |  18 +-
 .../replication/__tests__/helpers-tests.js      |  34 --
 .../replication/__tests__/helpers.tests.js      |  34 ++
 app/addons/replication/route.js                 |  33 +-
 app/addons/setup/route.js                       |  60 +--
 app/addons/styletests/assets/img/ripley.jpeg    | Bin 26384 -> 0 bytes
 app/addons/styletests/base.js                   |  29 -
 app/addons/styletests/routes.js                 |  36 --
 app/addons/styletests/styletests.react.jsx      | 525 -------------------
 app/addons/verifyinstall/routes.js              |  15 +-
 app/app.js                                      |  39 --
 app/core/api.js                                 |   8 +-
 app/core/auth.js                                |   1 +
 app/core/base.js                                |   2 +-
 app/core/couchdbSession.js                      |   2 +
 app/core/layout.js                              |  93 ----
 app/core/routeObject.js                         | 291 +---------
 app/core/router.js                              |  40 +-
 app/core/store.js                               |   1 +
 app/core/tests/layoutSpec.js                    | 126 -----
 app/core/tests/routeObjectSpec.js               | 244 ---------
 app/main.js                                     |   6 +
 app/templates/layouts/empty.html                |  15 -
 assets/index.underscore                         |  14 +-
 assets/less/templates.less                      |   2 +-
 package.json                                    |   3 +-
 tasks/addon/rename.json                         |   6 -
 tasks/addon/root/base.js.underscore             |  27 -
 .../addon/root/components.react.jsx.underscore  |  36 --
 tasks/addon/root/resources.js.underscore        |  21 -
 tasks/addon/root/routes.js.underscore           |  45 --
 tasks/addon/template.js                         |  68 ---
 test/dev.js                                     |   2 +-
 test/runner.html                                |   1 -
 writing_addons.md                               | 114 ----
 68 files changed, 523 insertions(+), 2253 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/.eslintrc
----------------------------------------------------------------------
diff --git a/.eslintrc b/.eslintrc
index c009736..0b5439d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -72,8 +72,7 @@
     "before": true,
     "after": true,
     "define": true,
-
-    "Spinner": true,
+    "expect": true,
     "prettyPrint": true
   }
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/.travis.yml
----------------------------------------------------------------------
diff --git a/.travis.yml b/.travis.yml
index 3330164..8187c65 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,6 +14,7 @@ before_script:
   - docker logs couchdb
   - docker logs selenium
   - curl http://127.0.0.1:5984
+  - npm run stylecheck
   - npm test
   - grunt debugDev
   - DIST=./dist/debug ./bin/fauxton &

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/Gruntfile.js
----------------------------------------------------------------------
diff --git a/Gruntfile.js b/Gruntfile.js
index a68c20c..639e81e 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -102,43 +102,8 @@ module.exports = function (grunt) {
       release:  cleanable
     },
 
-    // The jst task compiles all application templates into JavaScript
-    // functions with the underscore.js template function from 1.2.4.  You can
-    // change the namespace and the template options, by reading this:
-    // https://github.com/gruntjs/grunt-contrib/blob/master/docs/jst.md
-    //
-    // The concat task depends on this file to exist, so if you decide to
-    // remove this, ensure concat is updated accordingly.
-    jst: {
-      compile: {
-        options: {
-          processContent: function (src) {
-            return src.replace(/<!--[\s\S]*?-->/gm, '');
-          }
-        },
-        files: {
-          'dist/tmp-out/templates.js': [
-            "app/templates/**/*.html",
-            "app/addons/**/templates/**/*.html"
-          ]
-        }
-      }
-    },
-
     template: templateSettings,
 
-    concat: {
-      bundle_js: {
-        src: ['dist/tmp-out/templates.js', "dist/debug/bundle.js"],
-        dest: "dist/debug/bundle.js"
-      },
-
-      bundlerelease_js: {
-        src: ['dist/tmp-out/templates.js', "dist/release/bundle.js"],
-        dest: "dist/tmp-out/bundle.js"
-      }
-    },
-
     // Copy build artifacts and library code into the distribution
     // see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
     copy: {
@@ -174,17 +139,6 @@ module.exports = function (grunt) {
         ]
       },
 
-      testTemplates: {
-        files: [
-          {src: 'dist/tmp-out/templates.js', dest: 'test/templates.js'}
-       ]
-      },
-      devTemplates: {
-        files: [
-          {src: 'dist/tmp-out/templates.js', dest: 'dist/debug/templates.js'}
-       ]
-      },
-
       testfiles: {
         files:[
           {src: ['test/**'], dest: 'dist/debug/', flatten: false, expand: true},
@@ -262,7 +216,7 @@ module.exports = function (grunt) {
     // these rename the already-bundled, minified requireJS and CSS files to include their hash
     md5: {
       bundlejs: {
-        files: { 'dist/release/dashboard.assets/js/': 'dist/tmp-out/bundle.js' },
+        files: { 'dist/release/dashboard.assets/js/': 'dist/release/bundle.js' },
         options: {
           afterEach: function (fileChanges) {
             // replace the REQUIREJS_FILE placeholder with the actual filename
@@ -287,8 +241,6 @@ module.exports = function (grunt) {
   grunt.loadNpmTasks('grunt-exec');
   grunt.loadNpmTasks('grunt-contrib-copy');
   grunt.loadNpmTasks('grunt-contrib-clean');
-  grunt.loadNpmTasks('grunt-contrib-jst');
-  grunt.loadNpmTasks('grunt-contrib-concat');
   grunt.loadNpmTasks('grunt-shell');
   grunt.loadNpmTasks('grunt-md5');
   /*
@@ -303,12 +255,12 @@ module.exports = function (grunt) {
   grunt.registerTask('test', ['checkTestExists', 'clean:release', 'dependencies', 'copy:debug', 'gen_initialize:development', 'test_inline']);
 
   // lighter weight test task for use inside dev/watch
-  grunt.registerTask('test_inline', ['mochaSetup', 'shell:webpacktest', 'jst', 'copy:testTemplates', 'shell:phantomjs']);
+  grunt.registerTask('test_inline', ['mochaSetup', 'shell:webpacktest', 'shell:phantomjs']);
   // Fetch dependencies (from git or local dir)
   grunt.registerTask('dependencies', ['get_deps', 'gen_load_addons:default']);
 
   // minify code and css, ready for release.
-  grunt.registerTask('build', ['copy:distDepsRequire', 'jst', 'shell:webpackrelease', 'concat:bundlerelease_js',
+  grunt.registerTask('build', ['copy:distDepsRequire', 'shell:webpackrelease',
     'md5:bundlejs', 'template:release']);
   /*
    * Build the app in either dev, debug, or release mode
@@ -323,10 +275,10 @@ module.exports = function (grunt) {
     'template:development', 'copy:debug']);
 
   grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development",
-    'template:development', 'copy:debug', 'jst', 'shell:webpack', 'concat:bundle_js']);
+    'template:development', 'copy:debug', 'shell:webpack']);
 
   grunt.registerTask('devSetup', ['dependencies', "gen_initialize:development",
-    'template:development', 'copy:debug', 'jst', 'copy:devTemplates']);
+    'template:development', 'copy:debug']);
   grunt.registerTask('devSetupWithClean', ['clean', 'devSetup']);
 
   grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'shell:stylecheck']);

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/activetasks/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/routes.js b/app/addons/activetasks/routes.js
index efe3783..90796cd 100644
--- a/app/addons/activetasks/routes.js
+++ b/app/addons/activetasks/routes.js
@@ -19,9 +19,6 @@ import Layout from './layout';
 
 var ActiveTasksRouteObject = FauxtonAPI.RouteObject.extend({
   selectedHeader: 'Active Tasks',
-  layout: 'empty',
-  hideNotificationCenter: true,
-  hideApiBar: true,
 
   routes: {
     'activetasks/:id': 'showActiveTasks',
@@ -31,7 +28,7 @@ var ActiveTasksRouteObject = FauxtonAPI.RouteObject.extend({
   roles: ['_admin'],
 
   showActiveTasks: function () {
-    this.setComponent(".template", Layout);
+    return <Layout />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/auth/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/routes.js b/app/addons/auth/routes.js
index 8bfb9c0..4d40f98 100644
--- a/app/addons/auth/routes.js
+++ b/app/addons/auth/routes.js
@@ -38,10 +38,10 @@ var AuthRouteObject = FauxtonAPI.RouteObject.extend({
 
   login: function () {
     const crumbs = [{ name: 'Log In to CouchDB' }];
-    this.setComponent(".template", AuthLayout, {
-      crumbs: crumbs,
-      component: <LoginForm urlBack={app.getParams().urlback } />
-    });
+    return <AuthLayout
+      crumbs={crumbs}
+      component={<LoginForm urlBack={app.getParams().urlback } />}
+      />;
   },
 
   logout: function () {
@@ -54,10 +54,10 @@ var AuthRouteObject = FauxtonAPI.RouteObject.extend({
   createAdminForNode: function () {
     ClusterActions.fetchNodes();
     const crumbs = [{ name: 'Create Admin' }];
-    this.setComponent(".template", AuthLayout, {
-      crumbs: crumbs,
-      component: <CreateAdminForm loginAfter={true} />
-    });
+    return <AuthLayout
+      crumbs={crumbs}
+      component={<CreateAdminForm loginAfter={true} />}
+      />;
   }
 });
 
@@ -101,19 +101,19 @@ var UserRouteObject = FauxtonAPI.RouteObject.extend({
   changePassword: function () {
     ClusterActions.fetchNodes();
     AuthActions.selectPage('changePassword');
-    this.setComponent(".template", AdminLayout, {
-      crumbs: [{name: 'User Management'}],
-      changePassword: true
-    });
+    return <AdminLayout
+      crumbs={[{name: 'User Management'}]}
+      changePassword={true}
+      />;
   },
 
   addAdmin: function () {
     ClusterActions.fetchNodes();
     AuthActions.selectPage('addAdmin');
-    this.setComponent(".template", AdminLayout, {
-      crumbs: [{name: 'User Management'}],
-      changePassword: false
-    });
+    return <AdminLayout
+      crumbs={[{name: 'User Management'}]}
+      changePassword={false}
+      />;
   },
 
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/cluster/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/routes.js b/app/addons/cluster/routes.js
index ae9aacd..99ac615 100644
--- a/app/addons/cluster/routes.js
+++ b/app/addons/cluster/routes.js
@@ -20,10 +20,6 @@ import {OnePaneSimpleLayout} from '../components/layouts';
 
 
 var ConfigDisabledRouteObject = FauxtonAPI.RouteObject.extend({
-  layout: 'empty',
-  hideApiBar: true,
-  hideNotificationCenter: true,
-
   routes: {
     'cluster/disabled': 'showDisabledFeatureScreen'
   },
@@ -35,14 +31,14 @@ var ConfigDisabledRouteObject = FauxtonAPI.RouteObject.extend({
   showDisabledFeatureScreen: function () {
     const memberships = new Cluster.ClusterNodes();
     ClusterActions.fetchNodes();
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <ClusterComponents.DisabledConfigController/>,
-      endpoint: memberships.url('apiurl'),
-      docURL: memberships.documentation,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<ClusterComponents.DisabledConfigController/>}
+      endpoint={memberships.url('apiurl')}
+      docURL={memberships.documentation}
+      crumbs={[
         { name: 'Config disabled' }
-      ]
-    });
+      ]}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/components/__tests__/polling.test.js
----------------------------------------------------------------------
diff --git a/app/addons/components/__tests__/polling.test.js b/app/addons/components/__tests__/polling.test.js
new file mode 100644
index 0000000..c6a206a
--- /dev/null
+++ b/app/addons/components/__tests__/polling.test.js
@@ -0,0 +1,107 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+import {Polling, clearPollCounter, resetPollCounter} from "../components/polling";
+import utils from "../../../../test/mocha/testUtils";
+import {shallow, mount} from "enzyme";
+import sinon from "sinon";
+import React from "react";
+import ReactDOM from "react-dom";
+
+var assert = utils.assert;
+
+describe("Polling", () => {
+  describe('Counters', () => {
+
+    it('resetPollCounter calls cb after set time', done => {
+      let called = false;
+      resetPollCounter(100, () => {
+        called = true;
+        assert.ok(called);
+        done();
+      });
+    });
+
+    it('clearRefreshCounter stops counter', done => {
+      let called = false;
+      resetPollCounter(100, () => {
+        called = true;
+      });
+
+      clearPollCounter();
+      setTimeout(() => {
+        assert.notOk(called);
+        done();
+      }, 200);
+    });
+  });
+
+  describe('Component', () => {
+    var clock;
+    beforeEach(() => {
+      clock = sinon.useFakeTimers();
+    });
+
+    afterEach(() => {
+      clock.restore();
+    });
+
+    it('renders slider with correct info', () => {
+      const wrapper = shallow(<Polling
+        startValue={10}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={() => {}}
+                            />);
+
+      const props = wrapper.find('input').props();
+
+      assert.deepEqual(props.value, 10);
+      assert.deepEqual(props.step, 1);
+      assert.deepEqual(props.min, 1);
+      assert.deepEqual(props.max, 21);
+    });
+
+    it('turns polling off if value is max', () => {
+      const wrapper = mount(<Polling
+        startValue={10}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={() => {}}
+                            />);
+
+      wrapper.find('input').simulate('change', {target: {value: 21}});
+      const isOff = wrapper.find('.faux__polling-info-value--off').text();
+      assert.deepEqual(isOff.toLowerCase(), "off");
+    });
+
+    it('turns polling off if value is max', (done) => {
+      let pollCalled = false;
+      const onPoll = () => {
+        pollCalled = true;
+        assert.ok(pollCalled);
+        done();
+      };
+      const wrapper = mount(<Polling
+        startValue={1}
+        min={1}
+        max={20}
+        stepSize={1}
+        onPoll={onPoll}
+                        />);
+
+      clock.tick(1010);
+
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/components/tests/pollingSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/pollingSpec.js b/app/addons/components/tests/pollingSpec.js
deleted file mode 100644
index b311287..0000000
--- a/app/addons/components/tests/pollingSpec.js
+++ /dev/null
@@ -1,108 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-import FauxtonAPI from "../../../core/api";
-import {Polling, clearPollCounter, resetPollCounter} from "../components/polling";
-import utils from "../../../../test/mocha/testUtils";
-import {shallow, mount} from "enzyme";
-import sinon from "sinon";
-import React from "react";
-import ReactDOM from "react-dom";
-
-var assert = utils.assert;
-
-describe("Polling", () => {
-  describe('Counters', () => {
-
-    it('resetPollCounter calls cb after set time', done => {
-      let called = false;
-      resetPollCounter(100, () => {
-        called = true;
-        assert.ok(called);
-        done();
-      });
-    });
-
-    it('clearRefreshCounter stops counter', done => {
-      let called = false;
-      resetPollCounter(100, () => {
-        called = true;
-      });
-
-      clearPollCounter();
-      setTimeout(() => {
-        assert.notOk(called);
-        done();
-      }, 200);
-    });
-  });
-
-  describe('Component', () => {
-    var clock;
-    beforeEach(() => {
-      clock = sinon.useFakeTimers();
-    });
-
-    afterEach(() => {
-      clock.restore();
-    });
-
-    it('renders slider with correct info', () => {
-      const wrapper = shallow(<Polling
-        startValue={10}
-        min={1}
-        max={20}
-        stepSize={1}
-        onPoll={() => {}}
-                            />);
-
-      const props = wrapper.find('input').props();
-
-      assert.deepEqual(props.value, 10);
-      assert.deepEqual(props.step, 1);
-      assert.deepEqual(props.min, 1);
-      assert.deepEqual(props.max, 21);
-    });
-
-    it('turns polling off if value is max', () => {
-      const wrapper = mount(<Polling
-        startValue={10}
-        min={1}
-        max={20}
-        stepSize={1}
-        onPoll={() => {}}
-                            />);
-
-      wrapper.find('input').simulate('change', {target: {value: 21}});
-      const isOff = wrapper.find('.faux__polling-info-value--off').text();
-      assert.deepEqual(isOff.toLowerCase(), "off");
-    });
-
-    it('turns polling off if value is max', (done) => {
-      let pollCalled = false;
-      const onPoll = () => {
-        pollCalled = true;
-        assert.ok(pollCalled);
-        done();
-      };
-      const wrapper = mount(<Polling
-        startValue={1}
-        min={1}
-        max={20}
-        stepSize={1}
-        onPoll={onPoll}
-                        />);
-
-      clock.tick(1010);
-
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/config/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/config/routes.js b/app/addons/config/routes.js
index 8692379..a6d1599 100644
--- a/app/addons/config/routes.js
+++ b/app/addons/config/routes.js
@@ -22,7 +22,6 @@ import Layout from './layout';
 
 
 var ConfigDisabledRouteObject = FauxtonAPI.RouteObject.extend({
-  layout: 'empty',
 
   routes: {
     '_config': 'checkNodes',
@@ -61,24 +60,24 @@ var ConfigPerNodeRouteObject = FauxtonAPI.RouteObject.extend({
 
   configForNode: function (node) {
     ConfigActions.fetchAndEditConfig(node);
-    this.setComponent('.template', Layout, {
-      node: node,
-      docURL: this.configs.documentation,
-      endpoint: this.configs.url(),
-      crumbs: [{ name: 'Config' }],
-      showCors: false
-    });
+    return <Layout
+      node={node}
+      docURL={this.configs.documentation}
+      endpoint={this.configs.url()}
+      crumbs={[{ name: 'Config' }]}
+      showCors={false}
+    />;
   },
 
   configCorsForNode: function (node) {
     CORSActions.fetchAndEditCors(node);
-    this.setComponent('.template', Layout, {
-      node: node,
-      docURL: this.configs.documentation,
-      endpoint: this.configs.url(),
-      crumbs: [{ name: 'Config' }],
-      showCors: true
-    });
+    return <Layout
+      node={node}
+      docURL={this.configs.documentation}
+      endpoint={this.configs.url()}
+      crumbs={[{ name: 'Config' }]}
+      showCors={true}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/databases/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/routes.js b/app/addons/databases/routes.js
index a13c339..b86ed53 100644
--- a/app/addons/databases/routes.js
+++ b/app/addons/databases/routes.js
@@ -35,7 +35,7 @@ const AllDbsRouteObject = FauxtonAPI.RouteObject.extend({
 
   allDatabases: function () {
     Actions.init();
-    this.setComponent('.template', Layout);
+    return <Layout />;
   }
 });
 Databases.RouteObjects = [AllDbsRouteObject];

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documentation/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documentation/routes.js b/app/addons/documentation/routes.js
index d9d9898..0657be7 100644
--- a/app/addons/documentation/routes.js
+++ b/app/addons/documentation/routes.js
@@ -26,12 +26,12 @@ var DocumentationRouteObject = FauxtonAPI.RouteObject.extend({
   },
   roles: ['fx_loggedIn'],
   documentation: function () {
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <DocumentationComponents.DocumentationPage/>,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<DocumentationComponents.DocumentationPage/>}
+      crumbs={[
           {'name': 'Documentation'}
-      ]
-    });
+      ]}
+    />;
   }
 });
 DocumentationRouteObject.RouteObjects = [DocumentationRouteObject];

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/doc-editor/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/doc-editor/actions.js b/app/addons/documents/doc-editor/actions.js
index ddc9656..95a0ade 100644
--- a/app/addons/documents/doc-editor/actions.js
+++ b/app/addons/documents/doc-editor/actions.js
@@ -53,7 +53,7 @@ function saveDoc (doc, isValidDoc, onSave) {
 
     doc.save().then(function () {
       onSave(doc.prettyJSON());
-      FauxtonAPI.navigate('#/' + FauxtonAPI.urls('allDocs', 'app', url.encode(doc.database.id)), {trigger: true});
+      FauxtonAPI.navigate('#/' + FauxtonAPI.urls('allDocs', 'app',  FauxtonAPI.url.encode(doc.database.id)), {trigger: true});
     }).fail(function (xhr) {
       FauxtonAPI.addNotification({
         msg: 'Save failed: ' + JSON.parse(xhr.responseText).reason,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/doc-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/doc-editor/components.react.jsx b/app/addons/documents/doc-editor/components.react.jsx
index 7069f1b..0a614fd 100644
--- a/app/addons/documents/doc-editor/components.react.jsx
+++ b/app/addons/documents/doc-editor/components.react.jsx
@@ -84,10 +84,11 @@ var DocEditorController = React.createClass({
     store.off('change', this.onChange);
   },
 
-  // whenever a file is uploaded, reset the editor
+  // whenever a file is uploaded or a doc is cloned update the editor
   componentWillUpdate: function (nextProps, nextState) {
-    if (this.state.numFilesUploaded !== nextState.numFilesUploaded) {
+    if (this.state.numFilesUploaded !== nextState.numFilesUploaded || this.state.doc && this.state.doc.hasChanged()) {
       this.getEditor().setValue(JSON.stringify(nextState.doc.attributes, null, '  '));
+      this.onSaveComplete();
     }
   },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/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 be13898..797c9b6 100644
--- a/app/addons/documents/index-editor/tests/actionsSpec.js
+++ b/app/addons/documents/index-editor/tests/actionsSpec.js
@@ -57,7 +57,6 @@ describe('Index Editor Actions', function () {
 
     afterEach(function () {
       restore(FauxtonAPI.navigate);
-      restore(FauxtonAPI.triggerRouteEvent);
     });
 
     it('saves design doc if has other views', function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/index-results/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/actions.js b/app/addons/documents/index-results/actions.js
index 6a54834..c0a4ceb 100644
--- a/app/addons/documents/index-results/actions.js
+++ b/app/addons/documents/index-results/actions.js
@@ -165,7 +165,7 @@ export default {
     });
   },
 
-  deleteSelected: function (bulkDeleteCollection, itemsLength) {
+  deleteSelected: function (bulkDeleteCollection, itemsLength, designDocs) {
     var msg = (itemsLength === 1) ? 'Are you sure you want to delete this doc?' :
       'Are you sure you want to delete these ' + itemsLength + ' docs?';
 
@@ -180,6 +180,8 @@ export default {
 
     var reloadResultsList = _.bind(this.reloadResultsList, this);
     var selectedIds = [];
+    const hasDesignDocs = !!bulkDeleteCollection.map(d => d.id).find((id) => /_design/.test(id));
+
 
     bulkDeleteCollection
       .bulkDelete()
@@ -198,9 +200,11 @@ export default {
         selectedIds = ids;
       })
       .always(function (id) {
+        if (designDocs && hasDesignDocs) {
+          SidebarActions.updateDesignDocs(designDocs);
+        }
         reloadResultsList().then(function () {
           bulkDeleteCollection.reset(selectedIds);
-          SidebarActions.refresh();
         });
       });
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/index-results/index-results.components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/index-results.components.react.jsx b/app/addons/documents/index-results/index-results.components.react.jsx
index a40f3dc..b9e5feb 100644
--- a/app/addons/documents/index-results/index-results.components.react.jsx
+++ b/app/addons/documents/index-results/index-results.components.react.jsx
@@ -444,6 +444,10 @@ var ResultsScreen = React.createClass({
 
 
 var ViewResultListController = React.createClass({
+  propTypes: {
+    designDocs: React.PropTypes.object.isRequired
+  },
+
   getStoreState: function () {
     var selectedItemsLength = store.getSelectedItemsLength();
     return {
@@ -465,7 +469,7 @@ var ViewResultListController = React.createClass({
   },
 
   removeItem: function () {
-    Actions.deleteSelected(this.state.bulkDeleteCollection, this.state.selectedItemsLength);
+    Actions.deleteSelected(this.state.bulkDeleteCollection, this.state.selectedItemsLength, this.props.designDocs);
   },
 
   getInitialState: function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/index-results/tests/index-results.actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/tests/index-results.actionsSpec.js b/app/addons/documents/index-results/tests/index-results.actionsSpec.js
index dd64acf..ae64afc 100644
--- a/app/addons/documents/index-results/tests/index-results.actionsSpec.js
+++ b/app/addons/documents/index-results/tests/index-results.actionsSpec.js
@@ -51,8 +51,8 @@ describe('#deleteSelected', function () {
     restore(window.confirm);
     restore(FauxtonAPI.addNotification);
     restore(Actions.reloadResultsList);
-    restore(SidebarActions.refresh);
     restore(Actions.newResultsList);
+    restore(SidebarActions.updateDesignDocs);
   });
 
   it('doesn\'t delete if user denies confirmation', function () {
@@ -70,7 +70,7 @@ describe('#deleteSelected', function () {
 
   it('on success notifies all deleted', function (done) {
     var spy = sinon.spy(FauxtonAPI, 'addNotification');
-    var sidebarSpy = sinon.spy(SidebarActions, 'refresh');
+    const spy2 = sinon.spy(SidebarActions, 'updateDesignDocs');
     var promise = FauxtonAPI.Deferred();
     var ids = {
       errorIds: []
@@ -82,6 +82,21 @@ describe('#deleteSelected', function () {
       },
       reset: function () {
         done();
+      },
+      map () {
+        return {
+          find () {
+            return true;
+          }
+        };
+      }
+    };
+
+    const designDocs = {
+      fetch () {
+        const designDocPromise = FauxtonAPI.Deferred();
+        designDocPromise.reject();
+        return designDocPromise;
       }
     };
 
@@ -90,9 +105,8 @@ describe('#deleteSelected', function () {
     stubPromise.resolve();
     reloadResultsListStub.returns(stubPromise);
 
-    Actions.deleteSelected(bulkDelete, 1);
-
+    Actions.deleteSelected(bulkDelete, 1, designDocs);
     assert.ok(spy.calledOnce);
-    assert.ok(sidebarSpy.calledOnce);
+    assert.ok(spy2.calledOnce);
   });
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/layouts.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index 3f85a10..ba03d72 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -98,7 +98,7 @@ TabsSidebarContent.propTypes = {
   upperContent: React.PropTypes.object,
 };
 
-export const DocsTabsSidebarLayout = ({database, showIncludeAllDocs, docURL, endpoint, dbName, dropDownLinks}) => {
+export const DocsTabsSidebarLayout = ({database, designDocs, showIncludeAllDocs, docURL, endpoint, dbName, dropDownLinks}) => {
   return (
     <div id="dashboard" className="with-sidebar">
       <TabsSidebarHeader
@@ -110,7 +110,7 @@ export const DocsTabsSidebarLayout = ({database, showIncludeAllDocs, docURL, end
         database={database}
       />
       <TabsSidebarContent
-        lowerContent={<IndexResultsComponents.List />}
+        lowerContent={<IndexResultsComponents.List designDocs={designDocs} />}
       />
     </div>
   );

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/mangolayout.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/mangolayout.js b/app/addons/documents/mangolayout.js
index 3c75ed1..87aeecf 100644
--- a/app/addons/documents/mangolayout.js
+++ b/app/addons/documents/mangolayout.js
@@ -65,7 +65,7 @@ MangoHeader.defaultProps = {
   crumbs: []
 };
 
-const MangoContent = ({edit}) => {
+const MangoContent = ({edit, designDocs}) => {
   const leftContent = edit ?
     <MangoComponents.MangoIndexEditorController
       description={app.i18n.en_US['mango-descripton-index-editor']}
@@ -83,7 +83,7 @@ const MangoContent = ({edit}) => {
       </div>
       <div id="right-content" className="flex-body flex-layout flex-col">
         <div id="dashboard-lower-content" className="flex-body">
-          <IndexResultsComponents.List />
+          <IndexResultsComponents.List designDocs={designDocs} />
         </div>
         <MangoFooter  />
       </div>
@@ -92,7 +92,7 @@ const MangoContent = ({edit}) => {
 };
 
 
-export const MangoLayout = ({edit, showIncludeAllDocs, docURL, endpoint, crumbs}) => {
+export const MangoLayout = ({edit, showIncludeAllDocs, docURL, endpoint, crumbs, designDocs}) => {
   return (
     <div id="dashboard" className="two-pane flex-layout flex-col">
       <MangoHeader
@@ -101,7 +101,7 @@ export const MangoLayout = ({edit, showIncludeAllDocs, docURL, endpoint, crumbs}
         endpoint={endpoint}
         crumbs={crumbs}
       />
-    <MangoContent edit={edit} />
+    <MangoContent edit={edit} designDocs={designDocs}/>
     </div>
   );
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/resources.js b/app/addons/documents/resources.js
index 4c182cd..1714915 100644
--- a/app/addons/documents/resources.js
+++ b/app/addons/documents/resources.js
@@ -423,10 +423,6 @@ Documents.BulkDeleteDocCollection = FauxtonAPI.Collection.extend({
       this.remove(this.get(id));
     }, this);
 
-    if (reloadDesignDocs) {
-      FauxtonAPI.triggerRouteEvent('reloadDesignDocs');
-    }
-
     this.trigger('removed', ids);
   },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/routes-doc-editor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-doc-editor.js b/app/addons/documents/routes-doc-editor.js
index 8fcfaae..5ecf605 100644
--- a/app/addons/documents/routes-doc-editor.js
+++ b/app/addons/documents/routes-doc-editor.js
@@ -24,14 +24,11 @@ import {DocEditorLayout} from '../components/layouts';
 
 
 const DocEditorRouteObject = FauxtonAPI.RouteObject.extend({
-  layout: 'empty',
-  hideApiBar: true,
-  hideNotificationCenter: true,
   selectedHeader: 'Databases',
 
   roles: ['fx_loggedIn'],
 
-  initialize: function (route, masterLayout, options) {
+  initialize (route, options) {
     this.databaseName = options[0];
     this.docId = options[1];
     this.database = this.database || new Databases.Model({ id: this.databaseName });
@@ -58,12 +55,12 @@ const DocEditorRouteObject = FauxtonAPI.RouteObject.extend({
 
     RevBrowserActions.showConfirmModal(false, null);
     RevBrowserActions.initDiffEditor(databaseName, docId);
-    this.setComponent(".template", DocEditorLayout, {
-      crumbs,
-      endpoint: this.doc.url('apiurl'),
-      docURL,
-      component: <RevBrowserComponents.DiffyController />
-    });
+    return <DocEditorLayout
+      crumbs={crumbs}
+      endpoint={this.doc.url('apiurl')}
+      docURL={docURL}
+      component={<RevBrowserComponents.DiffyController />}
+      />;
   },
 
   codeEditor: function (databaseName, docId) {
@@ -81,19 +78,20 @@ const DocEditorRouteObject = FauxtonAPI.RouteObject.extend({
     }
 
     Actions.initDocEditor({ doc: this.doc, database: this.database });
-    this.setComponent(".template", DocEditorLayout, {
-      crumbs,
-      endpoint: this.doc.url('apiurl'),
-      docURL: this.doc.documentation(),
-      component: <ReactComponents.DocEditorController
-        database={this.database}
-        isNewDoc={docId ? false : true}
-      />
-    });
+
+    return <DocEditorLayout
+      crumbs={crumbs}
+      endpoint={this.doc.url('apiurl')}
+      docURL={this.doc.documentation()}
+      component={<ReactComponents.DocEditorController
+          database={this.database}
+          isNewDoc={docId ? false : true}
+        />}
+      />;
   },
 
   showDesignDoc: function (database, ddoc) {
-    this.codeEditor(database, '_design/' + ddoc);
+    return this.codeEditor(database, '_design/' + ddoc);
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 445a5fa..d8cb677 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -11,7 +11,7 @@
 // the License.
 
 import app from '../../app';
-
+import React from 'react';
 import FauxtonAPI from '../../core/api';
 import BaseRoute from './shared-routes';
 import Documents from './resources';
@@ -28,7 +28,6 @@ import QueryOptionsActions from './queryoptions/actions';
 import {DocsTabsSidebarLayout, ViewsTabsSidebarLayout, ChangesSidebarLayout} from './layouts';
 
 var DocumentsRouteObject = BaseRoute.extend({
-  layout: "empty",
   routes: {
     "database/:database/_all_docs(:extra)": {
       route: "allDocs",
@@ -41,11 +40,7 @@ var DocumentsRouteObject = BaseRoute.extend({
     'database/:database/_changes': 'changes'
   },
 
-  events: {
-    "route:reloadDesignDocs": "reloadDesignDocs"
-  },
-
-  initialize: function (route, masterLayout, options) {
+  initialize (route, options) {
     this.initViews(options[0]);
   },
 
@@ -73,14 +68,14 @@ var DocumentsRouteObject = BaseRoute.extend({
     QueryOptionsActions.hideQueryOptions();
 
     const dropDownLinks = this.getCrumbs(this.database);
-    this.setComponent('.template', ViewsTabsSidebarLayout, {
-      showEditView: false, //a bit of a hack but its fine for now.
-      docURL: designDocInfo.documentation(),
-      endpoint: designDocInfo.url('apiurl'),
-      dbName: this.database.id,
-      dropDownLinks,
-      database: this.database
-    });
+    return <ViewsTabsSidebarLayout
+      showEditView={false}
+      docURL={designDocInfo.documentation()}
+      endpoint={designDocInfo.url('apiurl')}
+      dbName={this.database.id}
+      dropDownLinks={dropDownLinks}
+      database={this.database}
+    />;
   },
 
   /*
@@ -136,21 +131,15 @@ var DocumentsRouteObject = BaseRoute.extend({
     QueryOptionsActions.showQueryOptions();
 
     const dropDownLinks = this.getCrumbs(this.database);
-    this.setComponent('.template', DocsTabsSidebarLayout, {
-      showIncludeAllDocs: true,
-      docURL,
-      endpoint,
-      dbName: this.database.id,
-      dropDownLinks,
-      database: this.database
-    });
-  },
-
-  reloadDesignDocs: function (event) {
-    this.addSidebar(); // this ensures the design docs get reloaded
-    if (event && event.selectedTab) {
-      SidebarActions.selectNavItem(event.selectedTab);
-    }
+    return <DocsTabsSidebarLayout
+      showIncludeAllDocs={true}
+      docURL={docURL}
+      endpoint={endpoint}
+      dbName={this.database.id}
+      dropDownLinks={dropDownLinks}
+      database={this.database}
+      designDocs={this.designDocs}
+    />;
   },
 
   changes: function () {
@@ -161,13 +150,13 @@ var DocumentsRouteObject = BaseRoute.extend({
 
     QueryOptionsActions.hideQueryOptions();
 
-    this.setComponent('.template', ChangesSidebarLayout, {
-      endpoint: FauxtonAPI.urls('changes', 'apiurl', this.database.id, ''),
-      docURL: this.database.documentation(),
-      dbName: this.database.id,
-      dropDownLinks: this.getCrumbs(this.database),
-      database: this.database
-    });
+    return <ChangesSidebarLayout
+      endpoint={FauxtonAPI.urls('changes', 'apiurl', this.database.id, '')}
+      docURL={this.database.documentation()}
+      dbName={this.database.id}
+      dropDownLinks={this.getCrumbs(this.database)}
+      database={this.database}
+    />;
   }
 
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/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 eb1e83a..9ef44bb 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -10,6 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+import React from 'react';
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
 import Helpers from "./helpers";
@@ -23,9 +24,7 @@ import ReactHeaderActions from "./header/header.actions";
 import SidebarActions from "./sidebar/actions";
 import {DocsTabsSidebarLayout, ViewsTabsSidebarLayout} from './layouts';
 
-
-var IndexEditorAndResults = BaseRoute.extend({
-  layout: 'empty',
+const IndexEditorAndResults = BaseRoute.extend({
   routes: {
     'database/:database/new_view': {
       route: 'createView',
@@ -45,7 +44,7 @@ var IndexEditorAndResults = BaseRoute.extend({
     }
   },
 
-  initialize: function (route, masterLayout, options) {
+  initialize (route, options) {
     var databaseName = options[0];
     this.databaseName = databaseName;
     this.database = new Databases.Model({id: databaseName});
@@ -97,14 +96,14 @@ var IndexEditorAndResults = BaseRoute.extend({
     const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
 
     const dropDownLinks = this.getCrumbs(this.database);
-    this.setComponent('.template', DocsTabsSidebarLayout, {
-      showIncludeAllDocs: true,
-      docURL,
-      endpoint,
-      dbName: this.database.id,
-      dropDownLinks,
-      database: this.database
-    });
+    return <DocsTabsSidebarLayout
+      showIncludeAllDocs={true}
+      docURL={docURL}
+      endpoint={endpoint}
+      dbName={this.database.id}
+      dropDownLinks={dropDownLinks}
+      database={this.database}
+      />;
   },
 
   createView: function (database, _designDoc) {
@@ -128,13 +127,14 @@ var IndexEditorAndResults = BaseRoute.extend({
     SidebarActions.selectNavItem('');
 
     const dropDownLinks = this.getCrumbs(this.database);
-    this.setComponent('.template', ViewsTabsSidebarLayout, {
-      showIncludeAllDocs: true,
-      docURL: FauxtonAPI.constants.DOC_URLS.GENERAL,
-      dbName: this.database.id,
-      database: this.database,
-      dropDownLinks
-    });
+
+    return <ViewsTabsSidebarLayout
+      showIncludeAllDocs={true}
+      docURL={FauxtonAPI.constants.DOC_URLS.GENERAL}
+      dbName={this.database.id}
+      dropDownLinks={dropDownLinks}
+      database={this.database}
+      />;
   },
 
   editView: function (databaseName, ddocName, viewName) {
@@ -154,17 +154,16 @@ var IndexEditorAndResults = BaseRoute.extend({
 
     const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
     const endpoint = FauxtonAPI.urls('view', 'apiurl', databaseName, ddocName, viewName);
-
-
     const dropDownLinks = this.getCrumbs(this.database);
-    this.setComponent('.template', ViewsTabsSidebarLayout, {
-      showIncludeAllDocs: true,
-      docURL,
-      endpoint,
-      dbName: this.database.id,
-      dropDownLinks,
-      database: this.database
-    });
+
+    return <ViewsTabsSidebarLayout
+      showIncludeAllDocs={true}
+      docURL={docURL}
+      endpoint={endpoint}
+      dbName={this.database.id}
+      dropDownLinks={dropDownLinks}
+      database={this.database}
+      />;
   }
 
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/routes-mango.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-mango.js b/app/addons/documents/routes-mango.js
index c63e5a3..15642c8 100644
--- a/app/addons/documents/routes-mango.js
+++ b/app/addons/documents/routes-mango.js
@@ -10,6 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+import React from 'react';
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
 import Helpers from "./helpers";
@@ -19,6 +20,7 @@ import Resources from "./resources";
 import IndexResultsActions from "./index-results/actions";
 import IndexResultStores from "./index-results/stores";
 import ReactHeader from "./header/header.react";
+import Documents from "./shared-resources";
 import ReactActions from "./header/header.actions";
 import MangoActions from "./mango/mango.actions";
 import MangoStores from "./mango/mango.stores";
@@ -40,7 +42,7 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
     },
   },
 
-  initialize: function (route, masterLayout, options) {
+  initialize: function (route, options) {
     var databaseName = options[0];
     this.databaseName = databaseName;
     this.database = new Databases.Model({id: databaseName});
@@ -87,16 +89,29 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
       {name: app.i18n.en_US['mango-title-editor']}
     ];
 
-    this.setComponent('.template', MangoLayout, {
-      showIncludeAllDocs: false,
-      crumbs: crumbs,
-      docURL: FauxtonAPI.constants.DOC_URLS.MANGO_SEARCH,
-      endpoint: mangoResultCollection.urlRef('query-apiurl', ''),
-      edit: false
-    });
+    return <MangoLayout
+      showIncludeAllDocs={false}
+      crumbs={crumbs}
+      docURL={FauxtonAPI.constants.DOC_URLS.MANGO_SEARCH}
+      endpoint={mangoResultCollection.urlRef('query-apiurl', '')}
+      edit={false}
+    />;
   },
 
   createIndex: function (database) {
+    const designDocs = new Documents.AllDocs(null, {
+      database: this.database,
+      paging: {
+        pageSize: 500
+      },
+      params: {
+        startkey: '_design/',
+        endkey: '_design0',
+        include_docs: true,
+        limit: 500
+      }
+    });
+
     const mangoIndexCollection = new Resources.MangoIndexCollection(null, {
       database: this.database,
       params: null,
@@ -120,13 +135,14 @@ const MangoIndexEditorAndQueryEditor = FauxtonAPI.RouteObject.extend({
       {name: app.i18n.en_US['mango-indexeditor-title']}
     ];
 
-    this.setComponent('.template', MangoLayout, {
-      showIncludeAllDocs: false,
-      crumbs: crumbs,
-      docURL: FauxtonAPI.constants.DOC_URLS.MANGO_INDEX,
-      endpoint: mangoIndexCollection.urlRef('index-apiurl', ''),
-      edit: true
-    });
+    return <MangoLayout
+      showIncludeAllDocs={false}
+      crumbs={crumbs}
+      docURL={FauxtonAPI.constants.DOC_URLS.MANGO_INDEX}
+      endpoint={mangoIndexCollection.urlRef('index-apiurl', '')}
+      edit={true}
+      designDocs={designDocs}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/sidebar/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/sidebar/actions.js b/app/addons/documents/sidebar/actions.js
index 1dc238e..573c807 100644
--- a/app/addons/documents/sidebar/actions.js
+++ b/app/addons/documents/sidebar/actions.js
@@ -32,6 +32,10 @@ function newOptions (options) {
 }
 
 function updateDesignDocs (designDocs) {
+  FauxtonAPI.dispatch({
+    type: ActionTypes.SIDEBAR_FETCHING
+  });
+
   designDocs.fetch().then(function () {
     FauxtonAPI.dispatch({
       type: ActionTypes.SIDEBAR_UPDATED_DESIGN_DOCS,
@@ -72,10 +76,6 @@ function selectNavItem (navItem, params) {
   });
 }
 
-function refresh () {
-  FauxtonAPI.dispatch({ type: ActionTypes.SIDEBAR_REFRESH });
-}
-
 function showDeleteIndexModal (indexName, designDocName, indexLabel, onDelete) {
   FauxtonAPI.dispatch({
     type: ActionTypes.SIDEBAR_SHOW_DELETE_INDEX_MODAL,
@@ -142,7 +142,6 @@ export default {
   updateDesignDocs: updateDesignDocs,
   toggleContent: toggleContent,
   selectNavItem: selectNavItem,
-  refresh: refresh,
   showDeleteIndexModal: showDeleteIndexModal,
   hideDeleteIndexModal: hideDeleteIndexModal,
   showCloneIndexModal: showCloneIndexModal,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/sidebar/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/sidebar/actiontypes.js b/app/addons/documents/sidebar/actiontypes.js
index 6a1ebd4..f08d4bc 100644
--- a/app/addons/documents/sidebar/actiontypes.js
+++ b/app/addons/documents/sidebar/actiontypes.js
@@ -15,7 +15,6 @@ export default {
   SIDEBAR_NEW_OPTIONS: 'SIDEBAR_NEW_OPTIONS',
   SIDEBAR_TOGGLE_CONTENT: 'SIDEBAR_TOGGLE_CONTENT',
   SIDEBAR_FETCHING: 'SIDEBAR_FETCHING',
-  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',

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/sidebar/stores.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/sidebar/stores.react.jsx b/app/addons/documents/sidebar/stores.react.jsx
index 787a338..adaeb0e 100644
--- a/app/addons/documents/sidebar/stores.react.jsx
+++ b/app/addons/documents/sidebar/stores.react.jsx
@@ -288,9 +288,6 @@ Stores.SidebarStore = FauxtonAPI.Store.extend({
         this._loading = true;
       break;
 
-      case ActionTypes.SIDEBAR_REFRESH:
-      break;
-
       case ActionTypes.SIDEBAR_SHOW_DELETE_INDEX_MODAL:
         this.showDeleteIndexModal(action.options);
       break;
@@ -321,6 +318,7 @@ Stores.SidebarStore = FauxtonAPI.Store.extend({
 
       case ActionTypes.SIDEBAR_UPDATED_DESIGN_DOCS:
         this.updatedDesignDocs(action.options.designDocs);
+        this._loading = false;
       break;
 
       default:

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/documents/tests/nightwatch/cloneDoc.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/cloneDoc.js b/app/addons/documents/tests/nightwatch/cloneDoc.js
index 674ccb6..0d000d5 100644
--- a/app/addons/documents/tests/nightwatch/cloneDoc.js
+++ b/app/addons/documents/tests/nightwatch/cloneDoc.js
@@ -50,7 +50,7 @@ module.exports = {
 
         this.verify.ok(
           isCreatedDocumentPresent,
-          'Checking if new document no longer shows up in _all_docs.'
+          'check that document is correctly reloaded'
         );
       })
     .end();

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/fauxton/appwrapper.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/appwrapper.js b/app/addons/fauxton/appwrapper.js
new file mode 100644
index 0000000..48961ef
--- /dev/null
+++ b/app/addons/fauxton/appwrapper.js
@@ -0,0 +1,71 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import React from 'react';
+import FauxtonAPI from '../../core/api';
+import ComponentActions from '../components/actions';
+import {NotificationController} from "./notifications/notifications.react";
+import {NavBar} from './navigation/components.react';
+import NavbarActions from './navigation/actions';
+
+class ContentWrapper extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = {
+      routerOptions: props.router.currentRouteOptions
+    };
+
+    if (props.router.currentRouteOptions && props.router.currentRouteOptions.selectedHeader) {
+      NavbarActions.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
+    }
+  }
+
+  componentDidMount () {
+    this.props.router.on('new-component', (routerOptions) => {
+      this.setState({routerOptions});
+      NavbarActions.setNavbarActiveLink(this.state.routerOptions.selectedHeader);
+    });
+  }
+
+  render () {
+    if (!this.state.routerOptions) {
+      return null;
+    }
+
+    const {component} = this.state.routerOptions;
+    return component;
+  }
+}
+
+const App = ({router}) => {
+  return (
+    <div>
+      <div id="notifications">
+        <NotificationController />
+      </div>
+      <div role="main" id="main">
+        <div id="app-container">
+          <div className="wrapper">
+            <div className="pusher">
+              <ContentWrapper router={router} />
+            </div>
+            <div id="primary-navbar">
+              <NavBar/>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default App;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/fauxton/base.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/base.js b/app/addons/fauxton/base.js
index 0811b89..0509717 100644
--- a/app/addons/fauxton/base.js
+++ b/app/addons/fauxton/base.js
@@ -27,20 +27,6 @@ const Fauxton = FauxtonAPI.addon();
 
 Fauxton.initialize = () => {
 
-  FauxtonAPI.RouteObject.on('beforeEstablish', function (routeObject) {
-    NavigationActions.setNavbarActiveLink(_.result(routeObject, 'selectedHeader'));
-  });
-
-  const primaryNavBarEl = $('#primary-navbar')[0];
-  if (primaryNavBarEl) {
-    NavbarReactComponents.renderNavBar(primaryNavBarEl);
-  }
-
-  const notificationEl = $('#notifications')[0];
-  if (notificationEl) {
-    NotificationComponents.renderNotificationController(notificationEl);
-  }
-
   const versionInfo = new Fauxton.VersionInfo();
   versionInfo.fetch().then(function () {
     NavigationActions.setNavbarVersionInfo(versionInfo.get("version"));

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/fauxton/navigation/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/navigation/components.react.jsx b/app/addons/fauxton/navigation/components.react.jsx
index ddf338d..6e61015 100644
--- a/app/addons/fauxton/navigation/components.react.jsx
+++ b/app/addons/fauxton/navigation/components.react.jsx
@@ -60,7 +60,7 @@ const NavLink = React.createClass({
   }
 });
 
-const NavBar = React.createClass({
+export const NavBar = React.createClass({
   getStoreState () {
     return {
       navLinks: navBarStore.getNavLinks(),
@@ -156,9 +156,6 @@ const NavBar = React.createClass({
 });
 
 export default {
-  renderNavBar (el) {
-    ReactDOM.render(<NavBar/>, el);
-  },
   NavBar: NavBar,
   Burger: Burger
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/fauxton/navigation/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/navigation/tests/componentsSpec.react.jsx b/app/addons/fauxton/navigation/tests/componentsSpec.react.jsx
index f14d960..fc8d349 100644
--- a/app/addons/fauxton/navigation/tests/componentsSpec.react.jsx
+++ b/app/addons/fauxton/navigation/tests/componentsSpec.react.jsx
@@ -19,26 +19,17 @@ import React from "react";
 import ReactDOM from "react-dom";
 import TestUtils from "react-addons-test-utils";
 import sinon from "sinon";
+import {mount} from 'enzyme';
 
 var assert = utils.assert;
 
 describe('NavBar', function () {
 
   describe('burger', function () {
-    var container, burgerEl, toggleMenu;
-
-    beforeEach(function () {
-      toggleMenu = sinon.spy();
-      container = document.createElement('div');
-      burgerEl = TestUtils.renderIntoDocument(<Views.Burger toggleMenu={toggleMenu} />, container);
-    });
-
-    afterEach(function () {
-      ReactDOM.unmountComponentAtNode(container);
-    });
-
     it('dispatch TOGGLE_NAVBAR_MENU on click', function () {
-      TestUtils.Simulate.click(ReactDOM.findDOMNode(burgerEl));
+      const toggleMenu = sinon.spy();
+      const burgerEl = mount(<Views.Burger toggleMenu={toggleMenu} />);
+      burgerEl.simulate('click');
       assert.ok(toggleMenu.calledOnce);
     });
 
@@ -51,19 +42,18 @@ describe('NavBar', function () {
     sinon.stub(FauxtonAPI.session, 'user').returns({ name: 'test-user' });
     BaseAuth.initialize();
 
-    var container = document.createElement('div');
-    var el = TestUtils.renderIntoDocument(<Views.NavBar />, container);
+    const el = mount(<Views.NavBar />);
 
     FauxtonAPI.session.trigger('change');
 
     // confirm the logout link is present
-    var matches = ReactDOM.findDOMNode(el).outerHTML.match(/Logout/);
+    let matches = el.text().match(/Logout/);
     assert.equal(matches.length, 1);
 
     // now confirm there's still only a single logout link after publishing multiple
     FauxtonAPI.session.trigger('change');
     FauxtonAPI.session.trigger('change');
-    matches = ReactDOM.findDOMNode(el).outerHTML.match(/Logout/);
+    matches = el.text().match(/Logout/);
     assert.equal(matches.length, 1);
 
     FauxtonAPI.session.isLoggedIn.restore();

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/fauxton/notifications/notifications.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/notifications/notifications.react.jsx b/app/addons/fauxton/notifications/notifications.react.jsx
index 6ea3a00..a7ab3ae 100644
--- a/app/addons/fauxton/notifications/notifications.react.jsx
+++ b/app/addons/fauxton/notifications/notifications.react.jsx
@@ -28,7 +28,7 @@ var VelocityComponent = VelocityReact.VelocityComponent;
 
 // The one-stop-shop for Fauxton notifications. This controller handler the header notifications and the rightmost
 // notification center panel
-var NotificationController = React.createClass({
+export const NotificationController = React.createClass({
 
   getInitialState: function () {
     return this.getStoreState();
@@ -439,13 +439,9 @@ var NotificationPanelRow = React.createClass({
 
 
 export default {
-  NotificationController: NotificationController,
-  NotificationCenterButton: NotificationCenterButton,
-  NotificationCenterPanel: NotificationCenterPanel,
-  NotificationPanelRow: NotificationPanelRow,
-  Notification: Notification,
-
-  renderNotificationController: function (el) {
-    return ReactDOM.render(<NotificationController />, el);
-  }
+  NotificationController,
+  NotificationCenterButton,
+  NotificationCenterPanel,
+  NotificationPanelRow,
+  Notification
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/permissions/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/permissions/routes.js b/app/addons/permissions/routes.js
index 46ed6f9..bd87d59 100644
--- a/app/addons/permissions/routes.js
+++ b/app/addons/permissions/routes.js
@@ -17,15 +17,15 @@ import Resources from "./resources";
 import Actions from "./actions";
 import BaseRoute from "../documents/shared-routes";
 import Layout from './layout';
+import React from 'react';
 
 const PermissionsRouteObject = BaseRoute.extend({
-  layout: 'empty',
   roles: ['fx_loggedIn'],
   routes: {
     'database/:database/permissions': 'permissions'
   },
 
-  initialize: function (route, masterLayout, options) {
+  initialize: function (route, options) {
     var docOptions = app.getParams();
     docOptions.include_docs = true;
 
@@ -48,13 +48,13 @@ const PermissionsRouteObject = BaseRoute.extend({
       { name: this.database.id, link: Databases.databaseUrl(this.database)},
       { name: 'Permissions' }
     ];
-    this.setComponent('.template', Layout, {
-      docURL: this.security.documentation,
-      endpoint: this.security.url('apiurl'),
-      dbName: this.database.id,
-      dropDownLinks: crumbs,
-      database: this.database
-    });
+    return <Layout
+      docURL={this.security.documentation}
+      endpoint={this.security.url('apiurl')}
+      dbName={this.database.id}
+      dropDownLinks={crumbs}
+      database={this.database}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/replication/__tests__/helpers-tests.js
----------------------------------------------------------------------
diff --git a/app/addons/replication/__tests__/helpers-tests.js b/app/addons/replication/__tests__/helpers-tests.js
deleted file mode 100644
index 0703f39..0000000
--- a/app/addons/replication/__tests__/helpers-tests.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-import helpers from '../helpers';
-
-describe('Replication Helpers - getDatabaseLabel', () => {
-
-  it('returns database name for string', () => {
-    const db = 'http://tester:testerpass@127.0.0.1/fancy/db/name';
-
-    const res = helpers.getDatabaseLabel(db);
-
-    expect(res).toBe('fancy/db/name');
-  });
-
-  it('returns database name for object', () => {
-    const db = {
-      url: 'http://tester:testerpass@127.0.0.1/fancy'
-    };
-
-    const res = helpers.getDatabaseLabel(db);
-    expect(res).toBe('fancy');
-  });
-
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/replication/__tests__/helpers.tests.js
----------------------------------------------------------------------
diff --git a/app/addons/replication/__tests__/helpers.tests.js b/app/addons/replication/__tests__/helpers.tests.js
new file mode 100644
index 0000000..0703f39
--- /dev/null
+++ b/app/addons/replication/__tests__/helpers.tests.js
@@ -0,0 +1,34 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import helpers from '../helpers';
+
+describe('Replication Helpers - getDatabaseLabel', () => {
+
+  it('returns database name for string', () => {
+    const db = 'http://tester:testerpass@127.0.0.1/fancy/db/name';
+
+    const res = helpers.getDatabaseLabel(db);
+
+    expect(res).toBe('fancy/db/name');
+  });
+
+  it('returns database name for object', () => {
+    const db = {
+      url: 'http://tester:testerpass@127.0.0.1/fancy'
+    };
+
+    const res = helpers.getDatabaseLabel(db);
+    expect(res).toBe('fancy');
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/replication/route.js
----------------------------------------------------------------------
diff --git a/app/addons/replication/route.js b/app/addons/replication/route.js
index 6d4b726..5c0b16c 100644
--- a/app/addons/replication/route.js
+++ b/app/addons/replication/route.js
@@ -10,15 +10,12 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+import React from 'react';
 import FauxtonAPI from '../../core/api';
 import ReplicationController from './controller';
 import ComponentActions from '../components/actions';
 
 const ReplicationRouteObject = FauxtonAPI.RouteObject.extend({
-  layout: 'empty',
-  hideNotificationCenter: true,
-  hideApiBar: true,
-
   routes: {
     'replication/_create': 'defaultView',
     'replication/:dbname': 'defaultView',
@@ -43,31 +40,25 @@ const ReplicationRouteObject = FauxtonAPI.RouteObject.extend({
   },
 
   defaultView: function (databaseName) {
-    // ComponentActions.hideAPIBarButton();
-    // this.setCreateReplicationCrumbs();
     const localSource = databaseName || '';
-    this.setComponent('.template', ReplicationController, {
-      localSource: localSource,
-      section: 'new replication'
-    });
 
+    return <ReplicationController
+      localSource={localSource}
+      section={'new replication'}
+      />;
   },
 
   fromId: function (replicationId) {
-    // ComponentActions.hideAPIBarButton();
-    // this.setCreateReplicationCrumbs();
-    this.setComponent('.template', ReplicationController, {
-      replicationId: replicationId,
-      section: 'new replication'
-    });
+    return <ReplicationController
+      replicationId={replicationId}
+      section={'new replication'}
+    />;
   },
 
   activityView: function () {
-    // ComponentActions.hideAPIBarButton();
-    // this.setActivityCrumbs();
-    this.setComponent('.template', ReplicationController, {
-      section: 'activity'
-    });
+    return <ReplicationController
+      section={'activity'}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/setup/route.js
----------------------------------------------------------------------
diff --git a/app/addons/setup/route.js b/app/addons/setup/route.js
index a12102b..b601aba 100644
--- a/app/addons/setup/route.js
+++ b/app/addons/setup/route.js
@@ -20,10 +20,6 @@ import ClusterActions from "../cluster/cluster.actions";
 import {OnePaneSimpleLayout} from '../components/layouts';
 
 var RouteObject = FauxtonAPI.RouteObject.extend({
-  layout: 'empty',
-  hideApiBar: true,
-  hideNotificationCenter: true,
-
   roles: ['_admin'],
 
   routes: {
@@ -37,52 +33,52 @@ var RouteObject = FauxtonAPI.RouteObject.extend({
     const setup = new Setup.Model();
     ClusterActions.fetchNodes();
     SetupActions.getClusterStateFromCouch();
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <SetupComponents.SetupFirstStepController/>,
-      endpoint: setup.url('apiurl'),
-      docURL: setup.documentation,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<SetupComponents.SetupFirstStepController/>}
+      endpoint={setup.url('apiurl')}
+      docURL={setup.documentation}
+      crumbs={[
         { 'name': 'Setup ' + app.i18n.en_US['couchdb-productname'] }
-      ]
-    });
+      ]}
+    />;
   },
 
   setupSingleNode: function () {
     const setup = new Setup.Model();
     ClusterActions.fetchNodes();
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <SetupComponents.SetupSingleNodeController/>,
-      endpoint: setup.url('apiurl'),
-      docURL: setup.documentation,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<SetupComponents.SetupSingleNodeController/>}
+      endpoint={setup.url('apiurl')}
+      docURL={setup.documentation}
+      crumbs={[
         { 'name': 'Setup ' + app.i18n.en_US['couchdb-productname'] }
-      ]
-    });
+      ]}
+    />;
   },
 
   setupMultiNode: function () {
     const setup = new Setup.Model();
     ClusterActions.fetchNodes();
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <SetupComponents.SetupMultipleNodesController/>,
-      endpoint: setup.url('apiurl'),
-      docURL: setup.documentation,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<SetupComponents.SetupMultipleNodesController/>}
+      endpoint={setup.url('apiurl')}
+      docURL={setup.documentation}
+      crumbs={[
         { 'name': 'Setup ' + app.i18n.en_US['couchdb-productname'] }
-      ]
-    });
+      ]}
+    />;
   },
 
   finishView: function () {
     const setup = new Setup.Model();
-    this.setComponent('.template', OnePaneSimpleLayout, {
-      component: <SetupComponents.ClusterConfiguredScreen/>,
-      endpoint: setup.url('apiurl'),
-      docURL: setup.documentation,
-      crumbs: [
+    return <OnePaneSimpleLayout
+      component={<SetupComponents.ClusterConfiguredScreen/>}
+      endpoint={setup.url('apiurl')}
+      docURL={setup.documentation}
+      crumbs={[
         { 'name': 'Setup ' + app.i18n.en_US['couchdb-productname'] }
-      ]
-    });
+      ]}
+    />;
   }
 });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/styletests/assets/img/ripley.jpeg
----------------------------------------------------------------------
diff --git a/app/addons/styletests/assets/img/ripley.jpeg b/app/addons/styletests/assets/img/ripley.jpeg
deleted file mode 100644
index 66e89ab..0000000
Binary files a/app/addons/styletests/assets/img/ripley.jpeg and /dev/null differ

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/styletests/base.js
----------------------------------------------------------------------
diff --git a/app/addons/styletests/base.js b/app/addons/styletests/base.js
deleted file mode 100644
index dc57ef4..0000000
--- a/app/addons/styletests/base.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-import app from "../../app";
-import FauxtonAPI from "../../core/api";
-import tests from "./routes";
-import "./assets/less/styletests.less";
-
-tests.initialize = function () {
-
-  FauxtonAPI.addHeaderLink({
-    title: "Tests",
-    href: '#/tests',
-    bottomNav: true,
-    icon: "fonticon-wrench"
-  });
-
-};
-
-export default tests;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a231a4e4/app/addons/styletests/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/styletests/routes.js b/app/addons/styletests/routes.js
deleted file mode 100644
index c931317..0000000
--- a/app/addons/styletests/routes.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-import app from "app";
-import FauxtonAPI from "api";
-import StyleTests from "addons/styletests/styletests.react";
-
-var TestRouteObject = FauxtonAPI.RouteObject.extend({
-  layout: "one_pane",
-  routes: {
-    "tests": "initialize"
-  },
-
-  selectedHeader: 'theme tests',
-
-  crumbs:[],
-
-  apiUrl: function () {
-    return false;
-  },
-
-  initialize: function () {
-    this.setComponent('#dashboard-content', StyleTests.StyleTests);
-  }
-});
-
-export default {RouteObjects: [TestRouteObject]};