couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From beno...@apache.org
Subject [35/57] [abbrv] [partial] inital move to rebar compilation
Date Tue, 07 Jan 2014 00:36:55 GMT
http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/Gruntfile.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/Gruntfile.js b/apps/fauxton/Gruntfile.js
new file mode 100644
index 0000000..3afaa1f
--- /dev/null
+++ b/apps/fauxton/Gruntfile.js
@@ -0,0 +1,441 @@
+// 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.
+
+
+// This is the main application configuration file.  It is a Grunt
+// configuration file, which you can learn more about here:
+// https://github.com/cowboy/grunt/blob/master/docs/configuring.md
+
+module.exports = function(grunt) {
+  var helper = require('./tasks/helper').init(grunt),
+  _ = grunt.util._,
+  path = require('path');
+
+  var couch_config = function () {
+
+    var default_couch_config = {
+      fauxton: {
+        db: 'http://localhost:5984/fauxton',
+        app: './couchapp.js',
+        options: {
+          okay_if_missing: true
+        }
+      }
+    };
+
+    var settings_couch_config = helper.readSettingsFile().couch_config;
+    return settings_couch_config || default_couch_config;
+  }();
+
+  var cleanableAddons =  function () {
+    var theListToClean = [];
+    helper.processAddons(function(addon){
+      // Only clean addons that are included from a local dir
+      if (addon.path){
+        theListToClean.push("app/addons/" + addon.name);
+      }
+    });
+
+    return theListToClean;
+  }();
+
+  var cleanable = function(){
+    // Whitelist files and directories to be cleaned
+    // You'll always want to clean these two directories
+    // Now find the external addons you have and add them for cleaning up
+    return _.union(["dist/", "app/load_addons.js"], cleanableAddons);
+  }();
+
+  var assets = function(){
+    // Base assets
+    var theAssets = {
+      less:{
+        paths: ["assets/less"],
+        files: {
+          "dist/debug/css/fauxton.css": "assets/less/fauxton.less"
+        }
+      },
+      img: ["assets/img/**"]
+    };
+    helper.processAddons(function(addon){
+      // Less files from addons
+      var root = addon.path || "app/addons/" + addon.name;
+      var lessPath = root + "/assets/less";
+      if(path.existsSync(lessPath)){
+        // .less files exist for this addon
+        theAssets.less.paths.push(lessPath);
+        theAssets.less.files["dist/debug/css/" + addon.name + ".css"] =
+          lessPath + "/" + addon.name + ".less";
+      }
+      // Images
+      root = addon.path || "app/addons/" + addon.name;
+      var imgPath = root + "/assets/img";
+      if(path.existsSync(imgPath)){
+        theAssets.img.push(imgPath + "/**");
+      }
+    });
+    return theAssets;
+  }();
+
+  var templateSettings = function(){
+    var defaultSettings = {
+     "development": {
+        "src": "assets/index.underscore",
+        "dest": "dist/debug/index.html",
+        "variables": {
+          "requirejs": "/assets/js/libs/require.js",
+          "css": "./css/index.css",
+          "base": null
+        }
+      },
+      "release": {
+        "src": "assets/index.underscore",
+        "dest": "dist/debug/index.html",
+        "variables": {
+          "requirejs": "./js/require.js",
+          "css": "./css/index.css",
+          "base": null
+        }
+      }
+    };
+
+    var settings = helper.readSettingsFile();
+    return settings.template || defaultSettings;
+  }();
+
+  grunt.initConfig({
+
+    // The clean task ensures all files are removed from the dist/ directory so
+    // that no files linger from previous builds.
+    clean: {
+      release:  cleanable,
+      watch: cleanableAddons
+    },
+
+    // The lint task will run the build configuration and the application
+    // JavaScript through JSHint and report any errors.  You can change the
+    // options for this task, by reading this:
+    // https://github.com/cowboy/grunt/blob/master/docs/task_lint.md
+    lint: {
+      files: [
+        "build/config.js", "app/**/*.js" 
+      ]
+    },
+
+    less: {
+      compile: {
+        options: {
+          paths: assets.less.paths
+        },
+        files: assets.less.files
+      }
+    },
+
+    // The jshint option for scripturl is set to lax, because the anchor
+    // override inside main.js needs to test for them so as to not accidentally
+    // route. Settings expr true so we can do `migtBeNullObject && mightBeNullObject.coolFunction()`
+    jshint: {
+      all: ['app/**/*.js', 'Gruntfile.js', "test/core/*.js"],
+      options: {
+        scripturl: true,
+        evil: true,
+        expr: true
+      }
+    },
+
+    // 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: {
+      "dist/debug/templates.js": [
+        "app/templates/**/*.html",
+        "app/addons/**/templates/**/*.html"
+      ]
+    },
+
+    template: templateSettings,
+
+    // The concatenate task is used here to merge the almond require/define
+    // shim and the templates into the application code.  It's named
+    // dist/debug/require.js, because we want to only load one script file in
+    // index.html.
+    concat: {
+      requirejs: {
+        src: [ "assets/js/libs/require.js", "dist/debug/templates.js", "dist/debug/require.js"],
+        dest: "dist/debug/js/require.js"
+      },
+
+      index_css: {
+        src: ["dist/debug/css/*.css", 'assets/css/*.css'],
+        dest: 'dist/debug/css/index.css'
+      },
+
+      test_config_js: {
+        src: ["dist/debug/templates.js", "test/test.config.js"],
+        dest: 'test/test.config.js'
+      },
+    },
+
+    cssmin: {
+      compress: {
+        files: {
+          "dist/release/css/index.css": [
+            "dist/debug/css/index.css", 'assets/css/*.css',
+            "app/addons/**/assets/css/*.css"
+          ]
+        },
+        options: {
+          report: 'min'
+        }
+      }
+    },
+
+    uglify: {
+      release: {
+        files: {
+          "dist/release/js/require.js": [
+            "dist/debug/js/require.js"
+          ]
+        }
+      }
+    },
+
+    // Runs a proxy server for easier development, no need to keep deploying to couchdb
+    couchserver: {
+      dist: './dist/debug/',
+      port: 8000,
+      proxy: {
+        target: {
+          host: 'localhost',
+          port: 5984,
+          https: false
+        },
+        // This sets the Host header in the proxy so that you can use external
+        // CouchDB instances and not have the Host set to 'localhost'
+        changeOrigin: true
+      }
+    },
+
+    watch: {
+      js: { 
+        files: helper.watchFiles(['.js'], ["./app/**/*.js", '!./app/load_addons.js',"./assets/**/*.js", "./test/**/*.js"]),
+        tasks: ['watchRun'],
+      },
+      style: {
+        files: helper.watchFiles(['.less','.css'],["./app/**/*.css","./app/**/*.less","./assets/**/*.css", "./assets/**/*.less"]),
+        tasks: ['clean:watch', 'dependencies','less', 'concat:index_css'],
+      },
+      html: {
+        // the index.html is added in as a dummy file incase there is no
+        // html dependancies this will break. So we need one include pattern
+        files: helper.watchFiles(['.html'], ['./index.html']),
+        tasks: ['clean:watch', 'dependencies']
+      },
+      options: {
+        nospawn: true,
+        debounceDelay: 500
+      }
+    },
+
+    requirejs: {
+      compile: {
+        options: {
+          baseUrl: 'app',
+          // Include the main configuration file.
+          mainConfigFile: "app/config.js",
+
+          // Output file.
+          out: "dist/debug/require.js",
+
+          // Root application module.
+          name: "config",
+
+          // Do not wrap everything in an IIFE.
+          wrap: false,
+          optimize: "none",
+          findNestedDependencies: true
+        }
+      }
+    },
+
+    // Copy build artifacts and library code into the distribution
+    // see - http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
+    copy: {
+      couchdb: {
+        files: [
+          // this gets built in the template task
+          {src: "dist/release/index.html", dest: "../../share/www/fauxton/index.html"},
+          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/release/js/',  expand: true},
+          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/release/img/', expand: true},
+          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/release/css/", expand: true}
+        ]
+      },
+      couchdebug: {
+        files: [
+          // this gets built in the template task
+          {src: "dist/debug/index.html", dest: "../../share/www/fauxton/index.html"},
+          {src: ["**"], dest: "../../share/www/fauxton/js/", cwd:'dist/debug/js/',  expand: true},
+          {src: ["**"], dest: "../../share/www/fauxton/img/", cwd:'dist/debug/img/', expand: true},
+          {src: ["**"], dest: "../../share/www/fauxton/css/", cwd:"dist/debug/css/", expand: true}
+        ]
+      },
+      ace: {
+        files: [
+          {src: "assets/js/libs/ace/worker-json.js", dest: "dist/release/js/ace/worker-json.js"},
+          {src: "assets/js/libs/ace/mode-json.js", dest: "dist/release/js/ace/mode-json.js"},
+          {src: "assets/js/libs/ace/theme-crimson_editor.js", dest: "dist/release/js/ace/theme-crimson_editor.js"},
+          {src: "assets/js/libs/ace/mode-javascript.js", dest: "dist/release/js/ace/mode-javascript.js"},
+          {src: "assets/js/libs/ace/worker-javascript.js", dest: "dist/release/js/ace/worker-javascript.js"},
+        ]
+      },
+
+      dist:{
+        files:[
+          {src: "dist/debug/index.html", dest: "dist/release/index.html"},
+          {src: assets.img, dest: "dist/release/img/", flatten: true, expand: true}
+        ]
+      },
+      debug:{
+        files:[
+          {src: assets.img, dest: "dist/debug/img/", flatten: true, expand: true}
+        ]
+      }
+    },
+
+    get_deps: {
+      "default": {
+        src: "settings.json"
+      }
+    },
+
+    gen_load_addons: {
+      "default": {
+        src: "settings.json"
+      }
+    },
+    gen_initialize: templateSettings,
+    /*gen_initialize: {
+      "default": {
+        src: "settings.json"
+      }
+    },*/
+
+    mkcouchdb: couch_config,
+    rmcouchdb: couch_config,
+    couchapp: couch_config,
+
+    mochaSetup: {
+      default: {
+        files: { src: helper.watchFiles(['[Ss]pec.js'], ['./test/core/**/*[Ss]pec.js', './app/**/*[Ss]pec.js'])},
+        template: 'test/test.config.underscore',
+        config: './app/config.js'
+      }
+    },
+
+    mocha_phantomjs: {
+      all: ['test/runner.html']
+    }
+
+  });
+
+  // on watch events configure jshint:all to only run on changed file
+  grunt.event.on('watch', function(action, filepath) {
+    if (!!filepath.match(/.js$/) && filepath.indexOf('test.config.js') === -1) {
+      grunt.config(['jshint', 'all'], filepath);
+    }
+
+    if (!!filepath.match(/[Ss]pec.js$/)) {
+      //grunt.task.run(['mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
+    }
+  });
+
+  /*
+   * Load Grunt plugins
+   */
+  // Load fauxton specific tasks
+  grunt.loadTasks('tasks');
+  // Load the couchapp task
+  grunt.loadNpmTasks('grunt-couchapp');
+  // Load the copy task
+  grunt.loadNpmTasks('grunt-contrib-watch');
+  // Load the exec task
+  grunt.loadNpmTasks('grunt-exec');
+  // Load Require.js task
+  grunt.loadNpmTasks('grunt-contrib-requirejs');
+  // Load Copy task
+  grunt.loadNpmTasks('grunt-contrib-copy');
+  // Load Clean task
+  grunt.loadNpmTasks('grunt-contrib-clean');
+  // Load jshint task
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  // Load jst task
+  grunt.loadNpmTasks('grunt-contrib-jst');
+  // Load less task
+  grunt.loadNpmTasks('grunt-contrib-less');
+  // Load concat task
+  grunt.loadNpmTasks('grunt-contrib-concat');
+  // Load UglifyJS task
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  // Load CSSMin task
+  grunt.loadNpmTasks('grunt-contrib-cssmin');
+  grunt.loadNpmTasks('grunt-mocha-phantomjs');
+
+  /*
+   * Default task
+   */
+  // defult task - install minified app to local CouchDB
+  grunt.registerTask('default', 'couchdb');
+
+  /*
+   * Transformation tasks
+   */
+  // clean out previous build artefactsa and lint
+  grunt.registerTask('lint', ['clean', 'jshint']);
+  grunt.registerTask('test', ['lint', 'mochaSetup','jst', 'concat:test_config_js', 'mocha_phantomjs']);
+  // Fetch dependencies (from git or local dir), lint them and make load_addons
+  grunt.registerTask('dependencies', ['get_deps', 'gen_load_addons:default']);
+  // build templates, js and css
+  grunt.registerTask('build', ['less', 'concat:index_css', 'jst', 'requirejs', 'concat:requirejs', 'template:release']);
+  // minify code and css, ready for release.
+  grunt.registerTask('minify', ['uglify', 'cssmin:compress']);
+
+  /*
+   * Build the app in either dev, debug, or release mode
+   */
+  // dev server
+  grunt.registerTask('dev', ['debugDev', 'couchserver']);
+  // build a debug release
+  grunt.registerTask('debug', ['lint', 'dependencies', "gen_initialize:development", 'concat:requirejs','less', 'concat:index_css', 'template:development', 'copy:debug']);
+  grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development",'jshint','less', 'concat:index_css', 'template:development', 'copy:debug']);
+
+  grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'jshint']);
+  // build a release
+  grunt.registerTask('release', ['clean' ,'dependencies', "gen_initialize:release", 'jshint', 'build', 'minify', 'copy:dist', 'copy:ace']);
+
+  /*
+   * Install into CouchDB in either debug, release, or couchapp mode
+   */
+  // make a development install that is server by mochiweb under _utils
+  grunt.registerTask('couchdebug', ['debug', 'copy:couchdebug']);
+  // make a minimized install that is server by mochiweb under _utils
+  grunt.registerTask('couchdb', ['release', 'copy:couchdb']);
+  // make an install that can be deployed as a couchapp
+  grunt.registerTask('couchapp_setup', ['release']);
+  // install fauxton as couchapp
+  grunt.registerTask('couchapp_install', ['rmcouchdb:fauxton', 'mkcouchdb:fauxton', 'couchapp:fauxton']);
+  // setup and install fauxton as couchapp
+  grunt.registerTask('couchapp_deploy', ['couchapp_setup', 'couchapp_install']);
+};

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/TODO.md
----------------------------------------------------------------------
diff --git a/apps/fauxton/TODO.md b/apps/fauxton/TODO.md
new file mode 100644
index 0000000..b929e05
--- /dev/null
+++ b/apps/fauxton/TODO.md
@@ -0,0 +1,26 @@
+# Fauxton todo
+In no particular order
+
+- [ ] docco docs
+- [ ] user management
+- [ ] view options
+- [ ] view editor
+- [ ] visual view builder
+- [ ] new db as modal
+- [ ] new view button
+- [ ] show design docs only
+- [ ] fix delete doc button UI bug
+- [ ] delete multiple docs via _bulk_docs
+- [x] show change events in database view
+- [ ] pouchdb addon
+- [ ] bespoke bootstrap style
+- [ ] responsive interface
+- [ ] sticky subnav for some UI components on _all_docs
+- [ ] "show me" button in API bar doesn't
+- [ ] edit index button doesn't
+- [ ] replicate UI
+- [x] delete database
+- [x] format dates better (e.g. in logs plugin)
+- [ ] format log entry better
+- [ ] filter logs by method
+- [ ] restore unfiltered data in logs UI

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/assets/less/activetasks.less
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/assets/less/activetasks.less b/apps/fauxton/app/addons/activetasks/assets/less/activetasks.less
new file mode 100644
index 0000000..743917d
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/assets/less/activetasks.less
@@ -0,0 +1,18 @@
+// 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.
+
+.task-tabs li {
+  cursor: pointer;
+}
+table.active-tasks{
+	font-size: 16px;
+}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/base.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/base.js b/apps/fauxton/app/addons/activetasks/base.js
new file mode 100644
index 0000000..647add0
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/base.js
@@ -0,0 +1,26 @@
+// 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.
+
+define([
+  "app",
+  "api",
+  "addons/activetasks/routes"
+],
+
+function (app, FauxtonAPI, Activetasks) {
+
+  Activetasks.initialize = function() {
+    FauxtonAPI.addHeaderLink({title: "Active Tasks", icon: "fonticon-activetasks", href: "#/activetasks"});
+  };
+ 
+  return Activetasks;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/resources.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/resources.js b/apps/fauxton/app/addons/activetasks/resources.js
new file mode 100644
index 0000000..ca732fb
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/resources.js
@@ -0,0 +1,118 @@
+// 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.
+
+define([
+  "app",
+  "backbone",
+  "modules/fauxton/base",
+  "d3"
+],
+
+function (app, backbone, Fauxton) {
+  var Active = {},
+      apiv = app.versionAPI;
+      app.taskSortBy = 'type';
+
+  Active.Task = Backbone.Model.extend({
+    initialize: function() { 
+      this.set({"id": this.get('pid')});
+    }
+  });
+
+// ALL THE TASKS
+  Active.Tasks = Backbone.Model.extend({
+    alltypes: {
+      "all": "All tasks",
+      "replication": "Replication",
+      "database_compaction":" Database Compaction",
+      "indexer": "Indexer",
+      "view_compaction": "View Compaction"
+    },
+    documentation: "_active_tasks",
+    url: function (context) {
+      if (context === "apiurl"){
+        return window.location.origin + '/_active_tasks';
+      } else {
+        return app.host + '/_active_tasks';
+      }
+    },
+    fetch: function (options) {
+     var fetchoptions = options || {};
+     fetchoptions.cache = false;
+     return Backbone.Model.prototype.fetch.call(this, fetchoptions);
+    },
+    parse: function(resp){
+      var types = this.getUniqueTypes(resp),
+          that = this;
+
+      var typeCollections = _.reduce(types, function (collection, val, key) {
+          collection[key] = new Active.AllTasks(that.sortThis(resp, key));
+          return collection;
+        }, {});
+
+      typeCollections.all = new Active.AllTasks(resp);
+
+      this.set(typeCollections);  //now set them all to the model
+    },
+    getUniqueTypes: function(resp){
+      var types = this.alltypes;
+
+      _.each(resp, function(type){
+        if( typeof(types[type.type]) === "undefined"){
+          types[type.type] = type.type.replace(/_/g,' ');
+        }
+      },this);
+
+      this.alltypes = types;
+      return types;
+    },
+    sortThis: function(resp, type){
+      return _.filter(resp, function(item) { return item.type === type; });
+    },
+    changeView: function (view){
+      this.set({
+        "currentView": view
+      });
+    },
+    getCurrentViewData: function(){
+      var currentView = this.get('currentView');
+      return this.get(currentView);
+    },
+    getDatabaseCompactions: function(){
+      return this.get('databaseCompactions');
+    },
+    getIndexes: function(){
+      return this.get('indexes');
+    },
+    getViewCompactions: function(){
+      return this.get('viewCompactions');
+    }
+  });
+
+//ALL TASKS
+
+//NEW IDEA. Lets make this extremely generic, so if there are new weird tasks, they get sorted and collected.
+
+  Active.AllTasks = Backbone.Collection.extend({
+    model: Active.Task,
+    sortByColumn: function(colName) {
+      app.taskSortBy = colName;
+      this.sort();
+    },
+    comparator: function(item) {
+      return item.get(app.taskSortBy);
+    }
+  });
+
+
+  return Active;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/routes.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/routes.js b/apps/fauxton/app/addons/activetasks/routes.js
new file mode 100644
index 0000000..89bcfcc
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/routes.js
@@ -0,0 +1,58 @@
+// 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.
+
+define([
+  "app",
+  "api",
+  "addons/activetasks/resources",
+  "addons/activetasks/views"
+],
+
+function (app, FauxtonAPI, Activetasks, Views) {
+
+  var  ActiveTasksRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: "with_sidebar",
+    routes: {
+      "activetasks/:id": "defaultView",
+      "activetasks": "defaultView"
+    },
+    selectedHeader: 'Active Tasks',
+    crumbs: [
+    {"name": "Active tasks", "link": "activetasks"}
+    ],
+    apiUrl: function(){
+      return [this.newtasks.url("apiurl"), this.newtasks.documentation];
+    }, 
+
+    roles: ["_admin"],
+
+    defaultView: function(id){
+     this.newtasks = new Activetasks.Tasks({
+        currentView: "all", 
+        id:'activeTasks'
+      });
+      this.setView("#sidebar-content", new Views.TabMenu({
+        currentView: "all",
+        model: this.newtasks
+      })); 
+
+      this.setView("#dashboard-content", new Views.DataSection({
+        model: this.newtasks,
+        currentView: "all"
+      })); 
+    }
+  });
+
+  Activetasks.RouteObjects = [ActiveTasksRouteObject];
+
+  return Activetasks;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/templates/detail.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/templates/detail.html b/apps/fauxton/app/addons/activetasks/templates/detail.html
new file mode 100644
index 0000000..5e53129
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/templates/detail.html
@@ -0,0 +1,21 @@
+<!--
+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.
+-->
+
+<div class="progress progress-striped active">
+  <div class="bar" style="width: <%=model.get("progress")%>%;"><%=model.get("progress")%>%</div>
+</div>
+<p>
+	<%= model.get("type").replace('_',' ')%> on
+	<%= model.get("node")%>
+</p>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/templates/table.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/templates/table.html b/apps/fauxton/app/addons/activetasks/templates/table.html
new file mode 100644
index 0000000..885cb47
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/templates/table.html
@@ -0,0 +1,52 @@
+<!--
+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.
+-->
+
+<!--
+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.
+-->
+
+<% if (collection.length === 0){%>
+   <tr> 
+    <td>
+      <p>No tasks.</p>
+    </td>
+  </tr>
+<%}else{%>
+
+  <thead>
+    <tr>
+      <th data-type="type">Type</th>
+      <th data-type="node">Object</th>
+      <th data-type="started_on">Started on</th>
+      <th data-type="updated_on">Last updated on</th>
+      <th data-type="pid">PID</th>
+      <th data-type="progress" width="200">Status</th>
+    </tr>
+  </thead>
+
+  <tbody id="tasks_go_here">
+
+  </tbody>
+
+<% } %>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/templates/tabledetail.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/templates/tabledetail.html b/apps/fauxton/app/addons/activetasks/templates/tabledetail.html
new file mode 100644
index 0000000..67c0dc8
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/templates/tabledetail.html
@@ -0,0 +1,36 @@
+<!--
+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.
+-->
+
+<td>
+  <%= model.get("type")%>
+</td>
+<td>
+  <%= objectField %>
+</td>
+<td>
+  <%= formatDate(model.get("started_on")) %>
+</td>
+<td>
+  <%= formatDate(model.get("updated_on")) %>
+</td>
+<td>
+  <%= model.get("pid")%>
+</td>
+<td>
+	<div class="progress progress-striped active">
+	  <div class="bar" style="width: <%=model.get("progress")%>%;"><%=model.get("progress")%>%</div>
+
+	</div>
+	<p><%=progress%> </p>
+</td>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/templates/tabs.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/templates/tabs.html b/apps/fauxton/app/addons/activetasks/templates/tabs.html
new file mode 100644
index 0000000..5869748
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/templates/tabs.html
@@ -0,0 +1,46 @@
+<!--
+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.
+-->
+
+
+
+
+
+<div id="sidenav">
+  <header class="row-fluid">
+    <h3>Filter by: </h3>
+  </header>
+
+  <nav>
+		<ul class="task-tabs nav nav-list">
+		  <% for (var filter in filters) { %>
+		      <li data-type="<%=filter%>">
+			      <a>
+			      		<%=filters[filter]%>
+			      </a>
+		    </li>
+		  <% } %>
+		</ul>
+		<ul class="nav nav-list views">
+			<li class="nav-header">Polling interval</li>
+			<li>
+				<input id="pollingRange" type="range"
+				       min="1"
+				       max="30"
+				       step="1"
+				       value="5"/>
+				<label for="pollingRange"><span>5</span> second(s)</label>
+			</li>
+		</ul>
+  </nav>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/tests/viewsSpec.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/tests/viewsSpec.js b/apps/fauxton/app/addons/activetasks/tests/viewsSpec.js
new file mode 100644
index 0000000..395b60a
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/tests/viewsSpec.js
@@ -0,0 +1,139 @@
+// 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.
+define([
+       'api',
+       'addons/activetasks/views',
+       'addons/activetasks/resources',
+      'testUtils'
+], function (FauxtonAPI, Views, Models, testUtils) {
+  var assert = testUtils.assert,
+      ViewSandbox = testUtils.ViewSandbox;
+  
+  describe("TabMenu", function () {
+    var tabMenu;
+
+    beforeEach(function () {
+      var newtasks = new Models.Tasks({
+        currentView: "all", 
+        id:'activeTasks'
+      });
+
+      tabMenu = new Views.TabMenu({
+        currentView: "all",
+        model: newtasks
+      });
+    });
+
+    describe("on change polling rate", function () {
+      var viewSandbox;
+      beforeEach(function () {
+        viewSandbox = new ViewSandbox();
+        viewSandbox.renderView(tabMenu); 
+      });
+
+      afterEach(function () {
+        viewSandbox.remove();
+      });
+
+      it("Should set polling rate", function () {
+        $range = tabMenu.$('#pollingRange');
+        $range.val(15);
+        $range.trigger('change');
+
+        assert.equal(tabMenu.$('span').text(), 15);
+      });
+
+      it("Should clearInterval", function () {
+        $range = tabMenu.$('#pollingRange');
+        clearIntervalMock = sinon.spy(window,'clearInterval');
+        $range.trigger('change');
+
+        assert.ok(clearIntervalMock.calledOnce);
+
+      });
+
+      it("Should trigger update:poll event", function () {
+        var spy = sinon.spy();
+        Views.Events.on('update:poll', spy);
+        $range = tabMenu.$('#pollingRange');
+        $range.trigger('change');
+
+        assert.ok(spy.calledOnce);
+      });
+
+    });
+
+    describe('on request by type', function () {
+      var viewSandbox;
+      beforeEach(function () {
+        viewSandbox = new ViewSandbox();
+        viewSandbox.renderView(tabMenu); 
+      });
+
+      afterEach(function () {
+        viewSandbox.remove();
+      });
+
+      it("should change model view", function () {
+        var spy = sinon.spy(tabMenu.model, 'changeView');
+        var $rep = tabMenu.$('li[data-type="replication"]');
+        $rep.click();
+        assert.ok(spy.calledOnce);
+      });
+
+      it("should set correct active tab", function () {
+        var spy = sinon.spy(tabMenu.model, 'changeView');
+        var $rep = tabMenu.$('li[data-type="replication"]');
+        $rep.click();
+        assert.ok($rep.hasClass('active'));
+      });
+
+    });
+
+  });
+
+  describe('DataSection', function () {
+    var viewSandbox, dataSection;
+    beforeEach(function () {
+      var newtasks = new Models.Tasks({
+        currentView: "all", 
+        id:'activeTasks'
+      });
+      newtasks.parse([]);
+
+      dataSection = new Views.DataSection({
+        currentView: "all",
+        model: newtasks
+      });
+
+      viewSandbox = new ViewSandbox();
+      viewSandbox.renderView(dataSection); 
+    });
+
+    afterEach(function () {
+      viewSandbox.remove();
+    });
+
+    describe('#setPolling', function () {
+
+      it('Should set polling interval', function () {
+        var spy = sinon.spy(window, 'setInterval');
+        dataSection.setPolling();
+        assert.ok(spy.calledOnce);
+      });
+
+    });
+
+
+
+  });
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/activetasks/views.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/activetasks/views.js b/apps/fauxton/app/addons/activetasks/views.js
new file mode 100644
index 0000000..005d487
--- /dev/null
+++ b/apps/fauxton/app/addons/activetasks/views.js
@@ -0,0 +1,181 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/activetasks/resources"
+],
+
+function (app, FauxtonAPI, activetasks) {
+
+  var Views = {},
+      Events = {},
+      pollingInfo ={
+        rate: "5",
+        intervalId: null
+      };
+
+
+  Views.Events = _.extend(Events, Backbone.Events);
+
+  Views.TabMenu = FauxtonAPI.View.extend({
+    template: "addons/activetasks/templates/tabs",
+    events: {
+      "click .task-tabs li": "requestByType",
+      "change #pollingRange": "changePollInterval"
+    },
+    establish: function(){
+      return [this.model.fetch({reset: true})];
+    },
+    serialize: function(){
+      return {
+        filters: this.model.alltypes
+      };
+    },
+    afterRender: function(){
+      this.$('.task-tabs').find('li').eq(0).addClass('active');
+    },
+    changePollInterval: function(e){
+      var range = this.$(e.currentTarget).val();
+      this.$('label[for="pollingRange"] span').text(range);
+      pollingInfo.rate = range;
+      clearInterval(pollingInfo.intervalId);
+      Events.trigger('update:poll');
+    },
+
+    cleanup: function () {
+      clearInterval(pollingInfo.intervalId);
+    },
+
+    requestByType: function(e){
+      var currentTarget = e.currentTarget;
+      datatype = this.$(currentTarget).attr("data-type");
+
+      this.$('.task-tabs').find('li').removeClass('active');
+      this.$(currentTarget).addClass('active');
+      this.model.changeView(datatype);
+    }
+  });
+
+  Views.DataSection = FauxtonAPI.View.extend({
+    showData: function(){
+      var currentData = this.model.getCurrentViewData();
+
+      if (this.dataView) {
+       this.dataView.update(currentData, this.model.get('currentView').replace('_',' '));
+      } else {
+        this.dataView = this.insertView( new Views.TableData({ 
+          collection: currentData,
+          currentView: this.model.get('currentView').replace('_',' ')
+        }));
+      }
+    },
+    showDataAndRender: function () {
+      this.showData();
+      this.dataView.render();
+    },
+
+    beforeRender: function () {
+      this.showData();
+    },
+    establish: function(){
+      return [this.model.fetch()];
+    },
+    setPolling: function(){
+      var that = this;
+      clearInterval(pollingInfo.intervalId);
+      pollingInfo.intervalId = setInterval(function() {
+        that.establish();
+      }, pollingInfo.rate*1000);
+    },
+    cleanup: function(){
+      clearInterval(pollingInfo.intervalId);
+    },
+    afterRender: function(){
+      this.listenTo(this.model, "change", this.showDataAndRender);
+      Events.bind('update:poll', this.setPolling, this);
+      this.setPolling();
+    }
+  });
+
+  Views.TableData = FauxtonAPI.View.extend({
+    tagName: "table",
+    className: "table table-bordered table-striped active-tasks",
+    template: "addons/activetasks/templates/table",
+    events: {
+      "click th": "sortByType"
+    },
+    initialize: function(){
+      currentView = this.options.currentView;
+    },
+    sortByType:  function(e){
+      var currentTarget = e.currentTarget;
+      datatype = $(currentTarget).attr("data-type");
+      this.collection.sortByColumn(datatype);
+      this.render();
+    },
+    serialize: function(){
+      return {
+        currentView: currentView,
+        collection: this.collection
+      };
+    },
+
+    update: function (collection, currentView) {
+      this.collection = collection;
+      this.currentView = currentView;
+    },
+
+    beforeRender: function(){
+      //iterate over the collection to add each
+      this.collection.forEach(function(item) {
+        this.insertView("#tasks_go_here", new Views.TableDetail({ 
+          model: item
+        }));
+      }, this);
+    }
+  });
+
+  Views.TableDetail = FauxtonAPI.View.extend({
+    tagName: 'tr',
+    template: "addons/activetasks/templates/tabledetail",
+    initialize: function(){
+      this.type = this.model.get('type');
+    },
+    getObject: function(){
+      var objectField = this.model.get('database');
+      if (this.type === "replication"){
+        objectField = this.model.get('source') + " to " + this.model.get('target');
+      }
+      return objectField;
+    },
+    getProgress:  function(){
+      var progress = "";
+      if (this.type === "indexer"){
+        progress = "Processed " +this.model.get('changes_done')+ " of "+this.model.get('total_changes')+ ' changes';
+      }
+      return progress;
+    },
+    serialize: function(){
+      return {
+        model: this.model,
+        objectField: this.getObject(),
+        progress: this.getProgress()
+      };
+    }
+  });
+
+
+
+  return Views;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/assets/less/auth.less
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/assets/less/auth.less b/apps/fauxton/app/addons/auth/assets/less/auth.less
new file mode 100644
index 0000000..598da10
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/assets/less/auth.less
@@ -0,0 +1,15 @@
+// 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.
+
+.menuDropdown {
+  display: none;
+}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/base.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/base.js b/apps/fauxton/app/addons/auth/base.js
new file mode 100644
index 0000000..9f9a332
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/base.js
@@ -0,0 +1,69 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/auth/routes"
+],
+
+function(app, FauxtonAPI, Auth) {
+
+  Auth.session = new Auth.Session();
+  FauxtonAPI.setSession(Auth.session);
+
+  Auth.initialize = function() {
+    Auth.navLink = new Auth.NavLink({model: Auth.session});
+
+    FauxtonAPI.addHeaderLink({
+      title: "Auth", 
+      href: "#_auth",
+      view: Auth.navLink,
+      icon: "fonticon-user",
+      bottomNav: true,
+      establish: [FauxtonAPI.session.fetchUser()]
+    });
+      
+
+    var auth = function (session, roles) {
+      var deferred = $.Deferred();
+
+      if (session.isAdminParty()) {
+        deferred.resolve();
+      } else if(session.matchesRoles(roles)) {
+        deferred.resolve();
+      } else {
+        deferred.reject();
+      }
+
+      return [deferred];
+    };
+
+    var authDenied = function () {
+      FauxtonAPI.navigate('/noAccess');
+    };
+
+    FauxtonAPI.auth.registerAuth(auth);
+    FauxtonAPI.auth.registerAuthDenied(authDenied);
+
+    FauxtonAPI.session.on('change', function () {
+      if (FauxtonAPI.session.isLoggedIn()) {
+        FauxtonAPI.addHeaderLink({footerNav: true, href:"#logout", title:"Logout", icon: "", className: 'logout'});
+      } else {
+        FauxtonAPI.removeHeaderLink({title: "Logout", footerNav: true});
+      }
+    });
+  };
+
+
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/resources.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/resources.js b/apps/fauxton/app/addons/auth/resources.js
new file mode 100644
index 0000000..b1d40cc
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/resources.js
@@ -0,0 +1,364 @@
+// 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.
+
+define([
+       "app",
+       "api"
+],
+
+function (app, FauxtonAPI) {
+
+  var Auth = new FauxtonAPI.addon();
+
+  var Admin = Backbone.Model.extend({
+
+    url: function () {
+      return app.host + '/_config/admins/' + this.get("name");
+    },
+
+    isNew: function () { return false; },
+
+    sync: function (method, model, options) {
+
+      var params = {
+        url: model.url(),
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(model.get('value'))
+      };
+
+      if (method === 'delete') {
+        params.type = 'DELETE';
+      } else {
+        params.type = 'PUT';
+      }
+
+      return $.ajax(params);
+    }
+  });
+
+  Auth.Session = FauxtonAPI.Session.extend({
+    url: '/_session',
+
+    initialize: function (options) {
+      if (!options) { options = {}; }
+
+      this.messages = _.extend({},  { 
+          missingCredentials: 'Username or password cannot be blank.',
+          passwordsNotMatch:  'Passwords do not match.',
+          incorrectCredentials: 'Incorrect username or password.',
+          loggedIn: 'You have been logged in.',
+          adminCreated: 'Couchdb admin created',
+          changePassword: 'Your password has been updated.'
+        }, options.messages);
+    },
+
+    isAdminParty: function () {
+      var userCtx = this.get('userCtx');
+
+      if (!userCtx.name && userCtx.roles.indexOf("_admin") > -1) {
+        return true;
+      }
+
+      return false;
+    },
+
+    isLoggedIn: function () {
+      var userCtx = this.get('userCtx');
+
+      if (userCtx.name) {
+        return true;
+      }
+
+      return false;
+    },
+
+    userRoles: function () {
+      var user = this.user();
+
+      if (user && user.roles) { 
+        return user.roles;
+      }
+
+      return [];
+    },
+
+    matchesRoles: function (roles) {
+      if (roles.length === 0) {
+        return true;
+      }
+
+      var numberMatchingRoles = _.intersection(this.userRoles(), roles).length;
+
+      if (numberMatchingRoles > 0) {
+        return true;
+      }
+
+      return false;
+    },
+
+    validateUser: function (username, password, msg) {
+      if (_.isEmpty(username) || _.isEmpty(password)) {
+        var deferred = FauxtonAPI.Deferred();
+
+        deferred.rejectWith(this, [msg]);
+        return deferred;
+      }
+    },
+
+    validatePasswords: function (password, password_confirm, msg) {
+      if (_.isEmpty(password) || _.isEmpty(password_confirm) || (password !== password_confirm)) {
+        var deferred = FauxtonAPI.Deferred();
+
+        deferred.rejectWith(this, [msg]);
+        return deferred;
+      }
+
+    },
+
+    createAdmin: function (username, password, login) {
+      var that = this,
+          error_promise =  this.validateUser(username, password, this.messages.missingCredentials);
+
+      if (error_promise) { return error_promise; }
+
+      var admin = new Admin({
+        name: username,
+        value: password
+      });
+
+      return admin.save().then(function () {
+        if (login) {
+          return that.login(username, password);
+        } else {
+         return that.fetchUser({forceFetch: true});
+        }
+      });
+    },
+
+    login: function (username, password) {
+      var error_promise =  this.validateUser(username, password, this.messages.missingCredentials);
+
+      if (error_promise) { return error_promise; }
+
+      var that = this;
+
+      return $.ajax({
+        cache: false,
+        type: "POST", 
+        url: "/_session", 
+        dataType: "json",
+        data: {name: username, password: password}
+      }).then(function () {
+         return that.fetchUser({forceFetch: true});
+      });
+    },
+
+    logout: function () {
+      var that = this;
+
+      return $.ajax({
+        type: "DELETE", 
+        url: "/_session", 
+        dataType: "json",
+        username : "_", 
+        password : "_"
+      }).then(function () {
+       return that.fetchUser({forceFetch: true });
+      });
+    },
+
+    changePassword: function (password, password_confirm) {
+      var error_promise =  this.validatePasswords(password, password_confirm, this.messages.passwordsNotMatch);
+
+      if (error_promise) { return error_promise; }
+
+      var  that = this,
+           info = this.get('info'),
+           userCtx = this.get('userCtx');
+
+       var admin = new Admin({
+        name: userCtx.name,
+        value: password
+      });
+
+      return admin.save().then(function () {
+        return that.login(userCtx.name, password);
+      });
+    }
+  });
+
+  Auth.CreateAdminView = FauxtonAPI.View.extend({
+    template: 'addons/auth/templates/create_admin',
+
+    initialize: function (options) {
+      options = options || {};
+      this.login_after = options.login_after === false ? false : true;
+    },
+
+    events: {
+      "submit #create-admin-form": "createAdmin"
+    },
+
+    createAdmin: function (event) {
+      event.preventDefault();
+
+      var that = this,
+          username = this.$('#username').val(),
+          password = this.$('#password').val();
+
+      var promise = this.model.createAdmin(username, password, this.login_after);
+
+      promise.then(function () {
+        FauxtonAPI.addNotification({
+          msg: FauxtonAPI.session.messages.adminCreated,
+        });
+
+        if (that.login_after) {
+          FauxtonAPI.navigate('/');
+        } else {
+          that.$('#username').val('');
+          that.$('#password').val('');
+        }
+      });
+
+      promise.fail(function (rsp) {
+        FauxtonAPI.addNotification({
+          msg: 'Could not create admin. Reason' + rsp + '.',
+          type: 'error'
+        });
+      });
+    }
+
+  });
+
+  Auth.LoginView = FauxtonAPI.View.extend({
+    template: 'addons/auth/templates/login',
+
+    events: {
+      "submit #login": "login"
+    },
+
+    login: function (event) {
+      event.preventDefault();
+
+      var that = this,
+          username = this.$('#username').val(),
+          password = this.$('#password').val(),
+          promise = this.model.login(username, password);
+
+      promise.then(function () {
+        FauxtonAPI.addNotification({msg:  FauxtonAPI.session.messages.loggedIn });
+        FauxtonAPI.navigate('/');
+      });
+
+      promise.fail(function (xhr, type, msg) {
+        if (arguments.length === 3) {
+          msg = FauxtonAPI.session.messages.incorrectCredentials;
+        } else {
+          msg = xhr;
+        }
+
+        FauxtonAPI.addNotification({
+          msg: msg,
+          type: 'error'
+        });
+      });
+    }
+
+  });
+
+  Auth.ChangePassword = FauxtonAPI.View.extend({
+    template: 'addons/auth/templates/change_password',
+
+    events: {
+      "submit #change-password": "changePassword"
+    },
+
+    changePassword: function () {
+      event.preventDefault();
+
+      var that = this,
+          new_password = this.$('#password').val(),
+          password_confirm = this.$('#password-confirm').val();
+
+      var promise = this.model.changePassword(new_password, password_confirm);
+
+      promise.done(function () {
+        FauxtonAPI.addNotification({msg: FauxtonAPI.session.messages.changePassword});
+        that.$('#password').val('');
+        that.$('#password-confirm').val('');
+      });
+
+      promise.fail(function (xhr, error, msg) {
+        if (arguments.length < 3) {
+          msg = xhr;
+        }
+
+        FauxtonAPI.addNotification({
+          msg: xhr,
+          type: 'error'
+        });
+      });
+    }
+  });
+
+  Auth.NavLink = FauxtonAPI.View.extend({ 
+    template: 'addons/auth/templates/nav_link_title',
+    tagName: 'li',
+
+    beforeRender: function () {
+      this.listenTo(this.model, 'change', this.render);
+    },
+
+    serialize: function () {
+      return {
+        admin_party: this.model.isAdminParty(),
+        user: this.model.user()
+      };
+    }
+  });
+
+  Auth.NavDropDown = FauxtonAPI.View.extend({ 
+    template: 'addons/auth/templates/nav_dropdown',
+
+    beforeRender: function () {
+      this.listenTo(this.model, 'change', this.render);
+    },
+
+    setTab: function (selectedTab) {
+      this.selectedTab = selectedTab;
+      this.$('.active').removeClass('active');
+      var $tab = this.$('a[data-select="' + selectedTab +'"]');
+      $tab.parent().addClass('active');
+    },
+
+    afterRender: function () {
+      if (this.selectedTab) {
+        this.setTab(this.selectedTab);
+      }
+    },
+
+    serialize: function () {
+      return {
+        admin_party: this.model.isAdminParty(),
+        user: this.model.user()
+      };
+    }
+  });
+
+  Auth.NoAccessView = FauxtonAPI.View.extend({
+    template: "addons/auth/templates/noAccess"
+  });
+
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/routes.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/routes.js b/apps/fauxton/app/addons/auth/routes.js
new file mode 100644
index 0000000..fe40a77
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/routes.js
@@ -0,0 +1,93 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/auth/resources"
+],
+
+function(app, FauxtonAPI, Auth) {
+  var authRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: 'one_pane',
+
+    routes: {
+      'login': 'login',
+      'logout': 'logout',
+      'createAdmin': 'createAdmin',
+      'noAccess': 'noAccess'
+    },
+
+    login: function () {
+      this.crumbs = [{name: 'Login', link:"#"}];
+      this.setView('#dashboard-content', new Auth.LoginView({model: FauxtonAPI.session}));
+    },
+
+    logout: function () {
+      FauxtonAPI.addNotification({msg: 'You have been logged out.'});
+      FauxtonAPI.session.logout().then(function () {
+        FauxtonAPI.navigate('/');
+      });
+    },
+
+    changePassword: function () {
+      this.crumbs = [{name: 'Change Password', link:"#"}];
+      this.setView('#dashboard-content', new Auth.ChangePassword({model: FauxtonAPI.session}));
+    },
+
+    createAdmin: function () {
+      this.crumbs = [{name: 'Create Admin', link:"#"}];
+      this.setView('#dashboard-content', new Auth.CreateAdminView({model: FauxtonAPI.session}));
+    },
+
+    noAccess: function () {
+      this.crumbs = [{name: 'Access Denied', link:"#"}];
+      this.setView('#dashboard-content', new Auth.NoAccessView());
+      this.apiUrl = 'noAccess';
+    },
+  });
+
+  var userRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: 'with_sidebar',
+
+    routes: {
+      'changePassword': {
+        route: 'changePassword',
+        roles: ['_admin', '_reader', '_replicator']
+      },
+      'addAdmin': {
+        roles: ['_admin'],
+        route: 'addAdmin',
+      },
+    },
+    
+    initialize: function () {
+     this.navDrop = this.setView('#sidebar-content', new Auth.NavDropDown({model: FauxtonAPI.session}));
+    },
+
+    changePassword: function () {
+      this.navDrop.setTab('change-password');
+      this.setView('#dashboard-content', new Auth.ChangePassword({model: FauxtonAPI.session}));
+    },
+
+    addAdmin: function () {
+      this.navDrop.setTab('add-admin');
+      this.setView('#dashboard-content', new Auth.CreateAdminView({login_after: false, model: FauxtonAPI.session}));
+    },
+
+    crumbs: [{name: 'User Management', link: '#'}]
+  });
+
+  Auth.RouteObjects = [authRouteObject, userRouteObject];
+  
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/change_password.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/change_password.html b/apps/fauxton/app/addons/auth/templates/change_password.html
new file mode 100644
index 0000000..64b7d1f
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/change_password.html
@@ -0,0 +1,26 @@
+<!--
+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.
+-->
+
+<div class="span12">
+  <h2> Change Password </h2>
+  <form id="change-password">
+    <p class="help-block">
+    Enter your new password.
+    </p>
+    <input id="password" type="password" name="password" placeholder= "New Password:" size="24">
+    <br/>
+    <input id="password-confirm" type="password" name="password_confirm" placeholder= "Verify New Password" size="24">
+    <button type="submit" class="btn btn-primary">Change</button>
+  </form>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/create_admin.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/create_admin.html b/apps/fauxton/app/addons/auth/templates/create_admin.html
new file mode 100644
index 0000000..4715be5
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/create_admin.html
@@ -0,0 +1,37 @@
+<!--
+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.
+-->
+
+<div class="span12">
+  <h2> Add Admin </h2>
+  <form id="create-admin-form">
+    <input id="username" type="text" name="name" placeholder= "Username:" size="24">
+    <br/>
+    <input id="password" type="password" name="password" placeholder= "Password" size="24">
+    <p class="help-block">
+    Before a server admin is configured, all clients have admin privileges.
+    This is fine when HTTP access is restricted 
+    to trusted users. <strong>If end-users will be accessing this CouchDB, you must
+      create an admin account to prevent accidental (or malicious) data loss.</strong>
+    </p>
+    <p class="help-block">Server admins can create and destroy databases, install 
+    and update _design documents, run the test suite, and edit all aspects of CouchDB 
+    configuration.
+    </p>
+    <p class="help-block">Non-admin users have read and write access to all databases, which
+    are controlled by validation functions. CouchDB can be configured to block all
+    access to anonymous users.
+    </p>
+    <button type="submit" href="#" id="create-admin" class="btn btn-primary">Create Admin</button>
+  </form>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/login.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/login.html b/apps/fauxton/app/addons/auth/templates/login.html
new file mode 100644
index 0000000..a57f3f0
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/login.html
@@ -0,0 +1,26 @@
+<!--
+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.
+-->
+<div class="span12">
+  <form id="login">
+    <p class="help-block">
+      Login to CouchDB with your name and password.
+    </p>
+    <input id="username" type="text" name="name" placeholder= "Username:" size="24">
+    <br/>
+    <input id="password" type="password" name="password" placeholder= "Password" size="24">
+    <br/>
+    <button id="submit" class="btn" type="submit"> Login </button>
+  </form>
+</div>
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/nav_dropdown.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/nav_dropdown.html b/apps/fauxton/app/addons/auth/templates/nav_dropdown.html
new file mode 100644
index 0000000..d61c24a
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/nav_dropdown.html
@@ -0,0 +1,26 @@
+<!--
+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.
+-->
+
+<div id="sidenav">
+<header class="row-fluid">
+  <h3> <%= user.name %> </h3>
+</header>
+<nav>
+<ul class="nav nav-list">
+  <li class="active" ><a data-select="change-password" id="user-change-password" href="#changePassword"> Change Password </a></li>
+  <li ><a data-select="add-admin" href="#addAdmin"> Create Admins </a></li>
+</ul>
+</nav>
+</div>
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/nav_link_title.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/nav_link_title.html b/apps/fauxton/app/addons/auth/templates/nav_link_title.html
new file mode 100644
index 0000000..b23157e
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/nav_link_title.html
@@ -0,0 +1,31 @@
+<!--
+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.
+-->
+<% if (admin_party) { %>
+  <a id="user-create-admin" href="#createAdmin"> 
+  	<span class="fonticon-user fonticon"></span>
+  	Admin Party! 
+  </a>
+<% } else if (user) { %>
+  <a  href="#changePassword" >
+  	<span class="fonticon-user fonticon"></span> 
+  	<%= user.name %> 
+	</a>
+<% } else { %>
+  <a  href="#login" >  
+  	<span class="fonticon-user fonticon"></span> 
+  	Login 
+  </a>
+<% } %>
+
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/auth/templates/noAccess.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/auth/templates/noAccess.html b/apps/fauxton/app/addons/auth/templates/noAccess.html
new file mode 100644
index 0000000..ceff992
--- /dev/null
+++ b/apps/fauxton/app/addons/auth/templates/noAccess.html
@@ -0,0 +1,20 @@
+<!--
+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.
+-->
+
+
+<div class="span12">
+  <h2> Access Denied </h2>
+  <p> You do not have permission to view this page. <br/> You might need to <a href="#login"> login </a> to view this page/ </p>
+  
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/assets/less/compaction.less
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/assets/less/compaction.less b/apps/fauxton/app/addons/compaction/assets/less/compaction.less
new file mode 100644
index 0000000..70b034b
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/assets/less/compaction.less
@@ -0,0 +1,19 @@
+// 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.
+
+.compaction-option {
+  background-color: #F7F7F7;
+  border: 1px solid #DDD;
+  margin-bottom: 30px;
+  padding: 10px;
+
+}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/base.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/base.js b/apps/fauxton/app/addons/compaction/base.js
new file mode 100644
index 0000000..de0f124
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/base.js
@@ -0,0 +1,31 @@
+// 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.
+
+define([
+  "app",
+  "api",
+  "addons/compaction/routes"
+],
+
+function(app, FauxtonAPI, Compaction) {
+  Compaction.initialize = function() {
+    FauxtonAPI.registerExtension('docLinks', {
+      title: "Compact & Clean", 
+      url: "compact", 
+      icon: "icon-cogs"
+    });
+
+    FauxtonAPI.registerExtension('advancedOptions:ViewButton', new Compaction.CompactView({}));
+  };
+
+  return Compaction;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/resources.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/resources.js b/apps/fauxton/app/addons/compaction/resources.js
new file mode 100644
index 0000000..6633677
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/resources.js
@@ -0,0 +1,48 @@
+// 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.
+
+define([
+  "app",
+  "api"
+],
+
+function (app, FauxtonAPI) {
+  var Compaction = FauxtonAPI.addon();
+
+  Compaction.compactDB = function (db) {
+    return $.ajax({
+      url: db.url() + '/_compact',
+      contentType: 'application/json',
+      type: 'POST'
+    });
+  };
+
+  Compaction.cleanupViews = function (db) {
+    return $.ajax({
+      url: db.url() + '/_view_cleanup',
+      contentType: 'application/json',
+      type: 'POST'
+    });
+  };
+
+
+  Compaction.compactView = function (db, designDoc) {
+    // /some_database/_compact/designname
+    return $.ajax({
+      url: db.url() + '/_compact/' + designDoc.replace('_design/','') ,
+      contentType: 'application/json',
+      type: 'POST'
+    });
+  };
+
+  return Compaction;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/routes.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/routes.js b/apps/fauxton/app/addons/compaction/routes.js
new file mode 100644
index 0000000..2a33e07
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/routes.js
@@ -0,0 +1,65 @@
+// 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.
+
+define([
+       "app",
+
+       "api",
+
+       // Modules
+       "addons/compaction/views",
+       "modules/databases/resources"
+],
+
+function(app, FauxtonAPI, Compaction, Databases) {
+
+  var  CompactionRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: "one_pane",
+
+    crumbs: function () {
+      return [
+        {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
+        {"name": "Compact & Clean", "link": "compact"}
+      ];
+    },
+
+    routes: {
+      "database/:database/compact": "compaction"
+    },
+
+    initialize: function(route, masterLayout, options) {
+      var databaseName = options[0];
+
+      this.database = this.database || new Databases.Model({id: databaseName});
+    },
+
+    compaction: function () {
+      this.setView('#dashboard-content', new Compaction.Layout({model: this.database}));
+    },
+
+    establish: function () {
+      return this.database.fetch();
+    }
+
+    /*apiUrl: function() {
+      return [this.compactions.url(), this.compactions.documentation];
+    },*/
+
+  });
+
+  Compaction.RouteObjects = [CompactionRouteObject];
+
+  return Compaction;
+
+});
+
+

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/templates/compact_view.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/templates/compact_view.html b/apps/fauxton/app/addons/compaction/templates/compact_view.html
new file mode 100644
index 0000000..8a0b7ec
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/templates/compact_view.html
@@ -0,0 +1,14 @@
+<!--
+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.
+-->
+Compact View

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/templates/layout.html
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/templates/layout.html b/apps/fauxton/app/addons/compaction/templates/layout.html
new file mode 100644
index 0000000..5125892
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/templates/layout.html
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<div class="row">
+  <div class="span12 compaction-option">
+    <h3> Compact Database </h3>
+    <p>Compacting a database removes deleted documents and previous revisions. It is an irreversible operation and may take a while to complete for large databases.</p>
+    <button id="compact-db" class="btn btn-large btn-primary"> Run </button>
+  </div>
+</div>
+
+<div class="row">
+  <div class="span12 compaction-option">
+    <h3> Cleanup Views </h3>
+    <p>Cleaning up views in a database removes old view files still stored on the filesystem. It is an irreversible operation.</p>
+    <button id="cleanup-views" class="btn btn-large btn-primary"> Run </button>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/compaction/views.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/compaction/views.js b/apps/fauxton/app/addons/compaction/views.js
new file mode 100644
index 0000000..06a1300
--- /dev/null
+++ b/apps/fauxton/app/addons/compaction/views.js
@@ -0,0 +1,140 @@
+// 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.
+
+define([
+       "app",
+
+       "api",
+       // Modules
+       "addons/compaction/resources"
+],
+function (app, FauxtonAPI, Compaction) {
+
+  Compaction.Layout = FauxtonAPI.View.extend({
+    template: 'addons/compaction/templates/layout',
+
+    initialize: function () {
+      _.bindAll(this);
+    },
+
+    events: {
+      "click #compact-db": "compactDB",
+      "click #compact-view": "compactDB",
+      "click #cleanup-views": "cleanupViews"
+    },
+
+    disableButton: function (selector, text) {
+      this.$(selector).attr('disabled', 'disabled').text(text);
+    },
+
+    enableButton: function (selector, text) {
+      this.$(selector).removeAttr('disabled').text(text);
+    },
+
+    compactDB: function (event) {
+      var enableButton = this.enableButton;
+      event.preventDefault();
+
+      this.disableButton('#compact-db', 'Compacting...');
+
+      Compaction.compactDB(this.model).then(function () {
+        FauxtonAPI.addNotification({
+          type: 'success',
+          msg: 'Database compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view the compaction progress.',
+        });
+      }, function (xhr, error, reason) {
+        console.log(arguments);
+        FauxtonAPI.addNotification({
+          type: 'error',
+          msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+        });
+      }).always(function () {
+        enableButton('#compact-db', 'Run');
+      });
+    },
+
+    cleanupViews: function (event) {
+      var enableButton = this.enableButton;
+      event.preventDefault();
+
+      this.disableButton('#cleanup-view', 'Cleaning...');
+
+      Compaction.cleanupViews(this.model).then(function () {
+        FauxtonAPI.addNotification({
+          type: 'success',
+          msg: 'View cleanup has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.'
+        });
+      }, function (xhr, error, reason) {
+        FauxtonAPI.addNotification({
+          type: 'error',
+          msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+        });
+      }).always(function () {
+        enableButton('#cleanup-views', 'Run');
+      });
+    }
+  });
+
+  Compaction.CompactView = FauxtonAPI.View.extend({
+    template: 'addons/compaction/templates/compact_view',
+    className: 'btn btn-info btn-large pull-right',
+    tagName: 'button',
+
+    initialize: function () {
+      _.bindAll(this);
+    },
+
+    events: {
+      "click": "compact"
+    },
+
+    disableButton: function () {
+      this.$el.attr('disabled', 'disabled').text('Compacting...');
+    },
+
+    enableButton: function () {
+      this.$el.removeAttr('disabled').text('Compact View');
+    },
+
+
+    update: function (database, designDoc, viewName) {
+      this.database = database;
+      this.designDoc = designDoc;
+      this.viewName = viewName;
+    },
+
+    compact: function (event) {
+      event.preventDefault();
+      var enableButton = this.enableButton;
+
+      this.disableButton();
+
+      Compaction.compactView(this.database, this.designDoc).then(function () {
+        FauxtonAPI.addNotification({
+          type: 'success',
+          msg: 'View compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.'
+        });
+      }, function (xhr, error, reason) {
+        FauxtonAPI.addNotification({
+          type: 'error',
+          msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+        });
+      }).always(function () {
+        enableButton();
+      });
+
+    }
+
+  });
+
+  return Compaction;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/config/assets/less/config.less
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/config/assets/less/config.less b/apps/fauxton/app/addons/config/assets/less/config.less
new file mode 100644
index 0000000..86d9bf1
--- /dev/null
+++ b/apps/fauxton/app/addons/config/assets/less/config.less
@@ -0,0 +1,13 @@
+table.config {
+  #config-trash {
+    width: 5%;
+  }
+  
+  #delete-value {
+    text-align: center;
+  } 
+}
+
+button#add-section {
+  float: right;
+}

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/config/base.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/config/base.js b/apps/fauxton/app/addons/config/base.js
new file mode 100644
index 0000000..8362cb5
--- /dev/null
+++ b/apps/fauxton/app/addons/config/base.js
@@ -0,0 +1,28 @@
+// 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.
+
+define([
+  "app",
+
+  "api",
+
+  // Modules
+  "addons/config/routes"
+],
+
+function(app, FauxtonAPI, Config) {
+  Config.initialize = function() {
+    FauxtonAPI.addHeaderLink({title: "Config", href: "#_config", icon:"fonticon-cog", className: 'config'});
+  };
+
+  return Config;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/config/resources.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/config/resources.js b/apps/fauxton/app/addons/config/resources.js
new file mode 100644
index 0000000..14d2474
--- /dev/null
+++ b/apps/fauxton/app/addons/config/resources.js
@@ -0,0 +1,176 @@
+// 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.
+
+define([
+  "app",
+  "api"
+],
+
+function (app, FauxtonAPI) {
+
+  var Config = FauxtonAPI.addon();
+
+  Config.Model = Backbone.Model.extend({});
+  Config.OptionModel = Backbone.Model.extend({
+    documentation: "config",
+    
+    url: function () {
+      return app.host + '/_config/' + this.get("section") + '/' + this.get("name");
+    },
+
+    isNew: function () { return false; },
+
+    sync: function (method, model, options) {
+
+      var params = {
+        url: model.url(),
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(model.get('value'))
+      };
+
+      if (method === 'delete') {
+        params.type = 'DELETE';
+      } else {
+        params.type = 'PUT';
+      }
+
+      return $.ajax(params);
+    }
+  });
+
+  Config.Collection = Backbone.Collection.extend({
+    model: Config.Model,
+    documentation: "config",
+    url: function () {
+      return app.host + '/_config';
+    },
+
+    parse: function (resp) {
+      return _.map(resp, function (section, section_name) {
+        return {
+          section: section_name,
+          options: _.map(section, function (option, option_name) {
+            return {
+              name: option_name,
+              value: option
+            };
+          })
+        };
+      });
+    }
+  });
+
+  Config.ViewItem = FauxtonAPI.View.extend({
+    tagName: "tr",
+    className: "config-item",
+    template: "addons/config/templates/item",
+
+    events: {
+      "click .edit-button": "editValue",
+      "click #delete-value": "deleteValue",
+      "click #cancel-value": "cancelEdit",
+      "click #save-value": "saveValue"
+    },
+
+    deleteValue: function (event) {
+      var result = confirm("Are you sure you want to delete this configuration value?");
+
+      if (!result) { return; }
+
+      this.model.destroy();
+      this.remove();
+    },
+
+    editValue: function (event) {
+      this.$("#show-value").hide();
+      this.$("#edit-value-form").show();
+    },
+
+    saveValue: function (event) {
+      this.model.save({value: this.$(".value-input").val()});
+      this.render();
+    },
+
+    cancelEdit: function (event) {
+      this.$("#edit-value-form").hide();
+      this.$("#show-value").show();
+    },
+
+    serialize: function () {
+      return {option: this.model.toJSON()};
+    }
+
+  });
+
+  Config.View = FauxtonAPI.View.extend({
+    template: "addons/config/templates/dashboard",
+
+    events: {
+      "click #add-section": "addSection",
+      "submit #add-section-form": "submitForm"
+    },
+
+    submitForm: function (event) {
+      event.preventDefault();
+      var option = new Config.OptionModel({
+        section: this.$('input[name="section"]').val(),
+        name: this.$('input[name="name"]').val(),
+        value: this.$('input[name="value"]').val()
+      });
+
+      option.save();
+
+      var section = this.collection.find(function (section) {
+        return section.get("section") === option.get("section");
+      });
+
+      if (section) {
+        section.get("options").push(option.attributes);
+      } else {
+        this.collection.add({
+          section: option.get("section"),
+          options: [option.attributes]
+        });
+      }
+
+      this.$("#add-section-modal").modal('hide');
+      this.render();
+    },
+
+    addSection: function (event) {
+      event.preventDefault();
+      this.$("#add-section-modal").modal({show:true});
+    },
+
+    beforeRender: function() {
+      this.collection.each(function(config) {
+        _.each(config.get("options"), function (option, index) {
+          this.insertView("table.config tbody", new Config.ViewItem({
+            model: new Config.OptionModel({
+              section: config.get("section"),
+              name: option.name,
+              value: option.value,
+              index: index
+            })
+          }));
+        }, this);
+      }, this);
+    },
+
+    establish: function() {
+      return [this.collection.fetch()];
+    }
+  });
+
+  return Config;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/add91738/apps/fauxton/app/addons/config/routes.js
----------------------------------------------------------------------
diff --git a/apps/fauxton/app/addons/config/routes.js b/apps/fauxton/app/addons/config/routes.js
new file mode 100644
index 0000000..6af8157
--- /dev/null
+++ b/apps/fauxton/app/addons/config/routes.js
@@ -0,0 +1,59 @@
+// 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.
+
+define([
+       "app",
+
+       "api",
+
+       // Modules
+       "addons/config/resources"
+],
+
+function(app, FauxtonAPI, Config) {
+
+  var ConfigRouteObject = FauxtonAPI.RouteObject.extend({
+    layout: "one_pane",
+
+    initialize: function () {
+      this.configs = new Config.Collection();
+    },
+
+    roles: ["_admin"],
+
+    selectedHeader: "Config",
+
+    crumbs: [
+      {"name": "Config","link": "_config"}
+    ],
+
+    apiUrl: function () {
+      return [this.configs.url(), this.configs.documentation];
+    },
+
+    routes: {
+      "_config": "config"
+    },
+
+    config: function () {
+      this.setView("#dashboard-content", new Config.View({collection: this.configs}));
+    },
+
+    establish: function () {
+      return [this.configs.fetch()];
+    }
+  });
+
+
+  Config.RouteObjects = [ConfigRouteObject];
+  return Config;
+});


Mime
View raw message