You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ns...@apache.org on 2013/12/14 12:41:51 UTC
[45/51] [partial] Bring Fauxton directories together
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/Gruntfile.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/Gruntfile.js b/share/www/fauxton/src/Gruntfile.js
new file mode 100644
index 0000000..3afaa1f
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/TODO.md
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/TODO.md b/share/www/fauxton/src/TODO.md
new file mode 100644
index 0000000..b929e05
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/assets/less/activetasks.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/assets/less/activetasks.less b/share/www/fauxton/src/app/addons/activetasks/assets/less/activetasks.less
new file mode 100644
index 0000000..743917d
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/base.js b/share/www/fauxton/src/app/addons/activetasks/base.js
new file mode 100644
index 0000000..647add0
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/resources.js b/share/www/fauxton/src/app/addons/activetasks/resources.js
new file mode 100644
index 0000000..4625871
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/activetasks/resources.js
@@ -0,0 +1,114 @@
+// 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 () {
+ 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/c14b2991/share/www/fauxton/src/app/addons/activetasks/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/routes.js b/share/www/fauxton/src/app/addons/activetasks/routes.js
new file mode 100644
index 0000000..e0454b7
--- /dev/null
+++ b/share/www/fauxton/src/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(), 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/c14b2991/share/www/fauxton/src/app/addons/activetasks/templates/detail.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/templates/detail.html b/share/www/fauxton/src/app/addons/activetasks/templates/detail.html
new file mode 100644
index 0000000..5e53129
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/templates/table.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/templates/table.html b/share/www/fauxton/src/app/addons/activetasks/templates/table.html
new file mode 100644
index 0000000..885cb47
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/templates/tabledetail.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/templates/tabledetail.html b/share/www/fauxton/src/app/addons/activetasks/templates/tabledetail.html
new file mode 100644
index 0000000..67c0dc8
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/templates/tabs.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/templates/tabs.html b/share/www/fauxton/src/app/addons/activetasks/templates/tabs.html
new file mode 100644
index 0000000..5869748
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/tests/viewsSpec.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/tests/viewsSpec.js b/share/www/fauxton/src/app/addons/activetasks/tests/viewsSpec.js
new file mode 100644
index 0000000..395b60a
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/activetasks/views.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/activetasks/views.js b/share/www/fauxton/src/app/addons/activetasks/views.js
new file mode 100644
index 0000000..005d487
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/assets/less/auth.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/assets/less/auth.less b/share/www/fauxton/src/app/addons/auth/assets/less/auth.less
new file mode 100644
index 0000000..598da10
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/base.js b/share/www/fauxton/src/app/addons/auth/base.js
new file mode 100644
index 0000000..9f9a332
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/resources.js b/share/www/fauxton/src/app/addons/auth/resources.js
new file mode 100644
index 0000000..b1d40cc
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/routes.js b/share/www/fauxton/src/app/addons/auth/routes.js
new file mode 100644
index 0000000..fe40a77
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/change_password.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/change_password.html b/share/www/fauxton/src/app/addons/auth/templates/change_password.html
new file mode 100644
index 0000000..64b7d1f
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/create_admin.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/create_admin.html b/share/www/fauxton/src/app/addons/auth/templates/create_admin.html
new file mode 100644
index 0000000..4715be5
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/login.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/login.html b/share/www/fauxton/src/app/addons/auth/templates/login.html
new file mode 100644
index 0000000..a57f3f0
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/nav_dropdown.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/nav_dropdown.html b/share/www/fauxton/src/app/addons/auth/templates/nav_dropdown.html
new file mode 100644
index 0000000..d61c24a
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/nav_link_title.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/nav_link_title.html b/share/www/fauxton/src/app/addons/auth/templates/nav_link_title.html
new file mode 100644
index 0000000..b23157e
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/auth/templates/noAccess.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/auth/templates/noAccess.html b/share/www/fauxton/src/app/addons/auth/templates/noAccess.html
new file mode 100644
index 0000000..ceff992
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/assets/less/compaction.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/assets/less/compaction.less b/share/www/fauxton/src/app/addons/compaction/assets/less/compaction.less
new file mode 100644
index 0000000..70b034b
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/base.js b/share/www/fauxton/src/app/addons/compaction/base.js
new file mode 100644
index 0000000..de0f124
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/resources.js b/share/www/fauxton/src/app/addons/compaction/resources.js
new file mode 100644
index 0000000..6633677
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/routes.js b/share/www/fauxton/src/app/addons/compaction/routes.js
new file mode 100644
index 0000000..2a33e07
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/templates/compact_view.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/templates/compact_view.html b/share/www/fauxton/src/app/addons/compaction/templates/compact_view.html
new file mode 100644
index 0000000..8a0b7ec
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/templates/layout.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/templates/layout.html b/share/www/fauxton/src/app/addons/compaction/templates/layout.html
new file mode 100644
index 0000000..5125892
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/compaction/views.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/compaction/views.js b/share/www/fauxton/src/app/addons/compaction/views.js
new file mode 100644
index 0000000..06a1300
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/config/assets/less/config.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/assets/less/config.less b/share/www/fauxton/src/app/addons/config/assets/less/config.less
new file mode 100644
index 0000000..86d9bf1
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/config/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/base.js b/share/www/fauxton/src/app/addons/config/base.js
new file mode 100644
index 0000000..8362cb5
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/config/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/resources.js b/share/www/fauxton/src/app/addons/config/resources.js
new file mode 100644
index 0000000..14d2474
--- /dev/null
+++ b/share/www/fauxton/src/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/c14b2991/share/www/fauxton/src/app/addons/config/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/routes.js b/share/www/fauxton/src/app/addons/config/routes.js
new file mode 100644
index 0000000..6af8157
--- /dev/null
+++ b/share/www/fauxton/src/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;
+});