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:50 UTC
[44/51] [partial] Bring Fauxton directories together
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/config/templates/dashboard.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/templates/dashboard.html b/share/www/fauxton/src/app/addons/config/templates/dashboard.html
new file mode 100644
index 0000000..ffbeb37
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/config/templates/dashboard.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.
+-->
+
+<div class="row">
+ <div class="span2 offset10">
+ <button id="add-section" href="#" class="button button-margin">
+ <i class="icon-plus icon-white"> </i>
+ Add Section
+ </button>
+ </div>
+</div>
+<table class="config table table-striped table-bordered">
+ <thead>
+ <th id="config-section"> Section </th>
+ <th id="config-option"> Option </th>
+ <th id="config-value"> Value </th>
+ <th id="config-trash"></th>
+ </thead>
+ <tbody>
+ </tbody>
+</table>
+<div id="add-section-modal" class="modal hide fade">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h3>Create Config Option</h3>
+ </div>
+ <div class="modal-body">
+ <form id="add-section-form" class="form well">
+ <label>Section</label>
+ <input type="text" name="section" placeholder="Section">
+ <span class="help-block">Enter an existing section name to add to it.</span>
+ <input type="text" name="name" placeholder="Name">
+ <br/>
+ <input type="text" name="value" placeholder="Value">
+ <div class="modal-footer">
+ <button type="button" class="btn" data-dismiss="modal">Cancel</button>
+ <button type="submit" class="btn btn-primary"> Save </button>
+ </div>
+ </form>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/config/templates/item.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/config/templates/item.html b/share/www/fauxton/src/app/addons/config/templates/item.html
new file mode 100644
index 0000000..3e6e4ee
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/config/templates/item.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 (option.index === 0) {%>
+<th> <%= option.section %> </th>
+<% } else { %>
+<td></td>
+<% } %>
+<td> <%= option.name %> </td>
+<td>
+ <div id="show-value">
+ <%= option.value %> <button class="edit-button"> Edit </button>
+ </div>
+ <div id="edit-value-form" style="display:none">
+ <input class="value-input" type="text" value="<%= option.value %>" />
+ <button id="save-value" class="btn btn-success btn-small"> Save </button>
+ <button id="cancel-value" class="btn btn-danger btn-small"> Cancel </button>
+ </div>
+</td>
+<td id="delete-value"> <i class="icon-trash"> </i> </td>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/contribute/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/contribute/base.js b/share/www/fauxton/src/app/addons/contribute/base.js
new file mode 100644
index 0000000..8f622fe
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/contribute/base.js
@@ -0,0 +1,33 @@
+// 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([
+ // Libraries.
+ "jquery",
+ "lodash"
+],
+function($, _){
+ $.contribute = function(message, file){
+ /*
+ var JST = window.JST = window.JST || {};
+ var template = JST['app/addons/contribute/templates/modal.html'];
+ console.log(template);
+ var compiled = template({message: message, file: file});
+ */
+ console.log('contribute!contribute!monorail!contribute!');
+ /*
+ console.log(compiled);
+ var elem = $(compiled);
+ elem.modal('show');
+ */
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/exampleAuth/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/exampleAuth/base.js b/share/www/fauxton/src/app/addons/exampleAuth/base.js
new file mode 100644
index 0000000..aa99670
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/exampleAuth/base.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"
+],
+
+function(app, FauxtonAPI) {
+ // This is an example module of using the new auth module.
+
+ var noAccessView = FauxtonAPI.View.extend({
+ template: "addons/exampleAuth/templates/noAccess"
+
+ });
+
+ // To utilise the authentication - all that is required, is one callback
+ // that is registered with the auth api. This function can return an array
+ // of deferred objects.
+ // The roles argument that is passed in is the required roles for the current user
+ // to be allowed to access the current page.
+ // The layout is the main layout for use when you want to render a view onto the page
+ var auth = function (roles) {
+ var deferred = $.Deferred();
+
+ if (roles.indexOf('_admin') > -1) {
+ deferred.reject();
+ } else {
+ deferred.resolve();
+ }
+
+ return [deferred];
+ };
+
+ // If you would like to do something with when access is denied you can register this callback.
+ // It will be called is access has been denied on the previous page.
+ var authFail = function () {
+ app.masterLayout.setView('#dashboard', new noAccessView());
+ app.masterLayout.renderView('#dashboard');
+ };
+
+ // Register the auth call back. This will be called before new route rendered
+ FauxtonAPI.auth.registerAuth(auth);
+ // Register a failed route request callback. This is called if access is denied.
+ FauxtonAPI.auth.registerAuthDenied(authFail);
+
+
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/exampleAuth/templates/noAccess.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/exampleAuth/templates/noAccess.html b/share/www/fauxton/src/app/addons/exampleAuth/templates/noAccess.html
new file mode 100644
index 0000000..f1a9506
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/exampleAuth/templates/noAccess.html
@@ -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.
+-->
+
+<div class="row-fluid" >
+ <div class="span6 offset4">
+ <h3> You do not have permission to view this page </h3>
+</div>
+</div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/base.js b/share/www/fauxton/src/app/addons/logs/base.js
new file mode 100644
index 0000000..1aecbdf
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/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/logs/routes"
+],
+
+function(app, FauxtonAPI, Log) {
+ Log.initialize = function() {
+ FauxtonAPI.addHeaderLink({title: "Log", href: "#_log", icon: "fonticon-log", className: 'logs'});
+ };
+
+ return Log;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/resources.js b/share/www/fauxton/src/app/addons/logs/resources.js
new file mode 100644
index 0000000..3a47b92
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/resources.js
@@ -0,0 +1,225 @@
+// 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",
+ "backbone"
+],
+
+function (app, FauxtonAPI, Backbone) {
+
+ var Log = FauxtonAPI.addon();
+
+ Log.Model = Backbone.Model.extend({
+
+ date: function () {
+ var date = new Date(this.get('date'));
+
+ var formatted_time = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds();
+ var formatted_date = date.toDateString().slice(4, 10);
+
+ return formatted_date + ' ' + formatted_time;
+ },
+
+ logLevel: function () {
+ return this.get('log_level').replace(/ /g,'');
+ },
+
+ pid: function () {
+ return _.escape(this.get('pid'));
+ },
+
+ args: function () {
+ return _.escape(this.get('args'));
+ }
+
+ });
+
+ Log.Collection = Backbone.Collection.extend({
+ model: Log.Model,
+
+ initialize: function (options) {
+ this.params = {bytes: 5000};
+ },
+
+ documentation: "log",
+
+ url: function () {
+ query = "?" + $.param(this.params);
+ return app.host + '/_log' + query;
+ },
+
+ // override fetch because backbone expects json and couchdb sends text/html for logs,
+ // I think its more elegant to set the dataType here than where ever fetch is called
+ fetch: function (options) {
+ options = options ? options : {};
+
+ return Backbone.Collection.prototype.fetch.call(this, _.extend(options, {dataType: "html"}));
+ },
+
+ parse: function (resp) {
+ var lines = resp.split(/\n/);
+ return _.foldr(lines, function (acc, logLine) {
+ var match = logLine.match(/^\[(.*?)\]\s\[(.*?)\]\s\[(.*?)\]\s(.*)/);
+
+ if (!match) { return acc;}
+
+ acc.push({
+ date: match[1],
+ log_level: match[2],
+ pid: match[3],
+ args: match[4]
+ });
+
+ return acc;
+ }, []);
+ }
+ });
+
+ Log.events = {};
+ _.extend(Log.events, Backbone.Events);
+
+ Log.Views.View = FauxtonAPI.View.extend({
+ template: "addons/logs/templates/dashboard",
+
+ initialize: function (options) {
+ this.refreshTime = options.refreshTime || 5000;
+
+ Log.events.on("log:filter", this.filterLogs, this);
+ Log.events.on("log:remove", this.removeFilterLogs, this);
+
+ this.filters = [];
+
+ this.collection.on("add", function () {
+ this.render();
+ }, this);
+ },
+
+ establish: function () {
+ return [this.collection.fetch()];
+ },
+
+ serialize: function () {
+ return { logs: new Log.Collection(this.createFilteredCollection())};
+ },
+
+ afterRender: function () {
+ this.startRefreshInterval();
+ },
+
+ cleanup: function () {
+ this.stopRefreshInterval();
+ },
+
+ filterLogs: function (filter) {
+ this.filters.push(filter);
+ this.render();
+ },
+
+ createFilteredCollection: function () {
+ var that = this;
+
+ return _.reduce(this.filters, function (logs, filter) {
+
+ return _.filter(logs, function (log) {
+ var match = false;
+
+ _.each(log, function (value) {
+ if (value.toString().match(new RegExp(filter))) {
+ match = true;
+ }
+ });
+ return match;
+ });
+
+
+ }, this.collection.toJSON(), this);
+
+ },
+
+ removeFilterLogs: function (filter) {
+ this.filters.splice(this.filters.indexOf(filter), 1);
+ this.render();
+ },
+
+ startRefreshInterval: function () {
+ var collection = this.collection;
+
+ // Interval already set
+ if (this.intervalId) { return ; }
+
+ this.intervalId = setInterval(function () {
+ collection.fetch();
+ }, this.refreshTime);
+
+ },
+
+ stopRefreshInterval: function () {
+ clearInterval(this.intervalId);
+ }
+ });
+
+ Log.Views.FilterView = FauxtonAPI.View.extend({
+ template: "addons/logs/templates/sidebar",
+
+ events: {
+ "submit #log-filter-form": "filterLogs"
+ },
+
+ filterLogs: function (event) {
+ event.preventDefault();
+ var $filter = this.$('input[name="filter"]'),
+ filter = $filter.val();
+
+ Log.events.trigger("log:filter", filter);
+
+ this.insertView("#filter-list", new Log.Views.FilterItemView({
+ filter: filter
+ })).render();
+
+ $filter.val('');
+ }
+
+ });
+
+ Log.Views.FilterItemView = FauxtonAPI.View.extend({
+ template: "addons/logs/templates/filterItem",
+ tagName: "li",
+
+ initialize: function (options) {
+ this.filter = options.filter;
+ },
+
+ events: {
+ "click .remove-filter": "removeFilter"
+ },
+
+ serialize: function () {
+ return {
+ filter: this.filter
+ };
+ },
+
+ removeFilter: function (event) {
+ event.preventDefault();
+
+ Log.events.trigger("log:remove", this.filter);
+ this.remove();
+ }
+
+ });
+
+
+ return Log;
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/routes.js b/share/www/fauxton/src/app/addons/logs/routes.js
new file mode 100644
index 0000000..5c937af
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/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",
+
+ // Modules
+ "addons/logs/resources"
+],
+
+function(app, FauxtonAPI, Log) {
+
+ var LogRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: "with_sidebar",
+
+ crumbs: [
+ {"name": "Logs", "link": "_log"}
+ ],
+
+ routes: {
+ "_log": "showLog"
+ },
+
+ selectedHeader: "Log",
+
+ roles: ["_admin"],
+
+ apiUrl: function() {
+ return [this.logs.url(), this.logs.documentation];
+ },
+
+ initialize: function () {
+ this.logs = new Log.Collection();
+ this.setView("#sidebar-content", new Log.Views.FilterView({}));
+ },
+
+ showLog: function () {
+ this.setView("#dashboard-content", new Log.Views.View({collection: this.logs}));
+ }
+ });
+
+ Log.RouteObjects = [LogRouteObject];
+
+ return Log;
+
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/templates/dashboard.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/templates/dashboard.html b/share/www/fauxton/src/app/addons/logs/templates/dashboard.html
new file mode 100644
index 0000000..199794c
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/templates/dashboard.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.
+-->
+
+ <h2> CouchDB Logs </h2>
+ <table class="table table-bordered" >
+ <thead>
+ <tr>
+ <th class="Date">Date</th>
+ <th class="Log Level">Log Value</th>
+ <th class="Pid">Pid</th>
+ <th class="Args">Url</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ <% logs.each(function (log) { %>
+ <tr class="<%= log.logLevel() %>">
+ <td>
+ <!-- TODO: better format the date -->
+ <%= log.date() %>
+ </td>
+ <td>
+ <%= log.logLevel() %>
+ </td>
+ <td>
+ <%= log.pid() %>
+ </td>
+ <td>
+ <!-- TODO: split the line, maybe put method in it's own column -->
+ <%= log.args() %>
+ </td>
+ </tr>
+ <% }); %>
+ </tbody>
+</table>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/templates/filterItem.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/templates/filterItem.html b/share/www/fauxton/src/app/addons/logs/templates/filterItem.html
new file mode 100644
index 0000000..c4e885a
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/templates/filterItem.html
@@ -0,0 +1,16 @@
+<!--
+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.
+-->
+
+<span class="label label-info"> <%= filter %> </span>
+<a class="label label-info remove-filter" href="#">×</a>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/templates/sidebar.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/templates/sidebar.html b/share/www/fauxton/src/app/addons/logs/templates/sidebar.html
new file mode 100644
index 0000000..59b10ac
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/templates/sidebar.html
@@ -0,0 +1,27 @@
+<!--
+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="log-sidebar">
+ <header>Log Filter</header>
+ <form class="form-inline" id="log-filter-form">
+ <fieldset>
+ <input type="text" name="filter" placeholder="Type a filter to sort the logs by">
+ <!-- TODO: filter by method -->
+ <!-- TODO: correct removed filter behaviour -->
+ <button type="submit" class="btn">Filter</button>
+ <span class="help-block"> <h6> Eg. debug or <1.4.1> or any regex </h6> </span>
+ </fieldset>
+ </form>
+ <ul id="filter-list"></ul>
+</div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/logs/tests/logSpec.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/logs/tests/logSpec.js b/share/www/fauxton/src/app/addons/logs/tests/logSpec.js
new file mode 100644
index 0000000..621cc9b
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/logs/tests/logSpec.js
@@ -0,0 +1,38 @@
+// 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([
+ 'addons/logs/base',
+ 'chai'
+], function (Log, chai) {
+ var expect = chai.expect;
+
+ describe('Logs Addon', function(){
+
+ describe('Log Model', function () {
+ var log;
+
+ beforeEach(function () {
+ log = new Log.Model({
+ log_level: 'DEBUG',
+ pid: '1234',
+ args: 'testing 123',
+ date: (new Date()).toString()
+ });
+ });
+
+ it('should have a log level', function () {
+ expect(log.logLevel()).to.equal('DEBUG');
+ });
+
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/assets/less/permissions.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/assets/less/permissions.less b/share/www/fauxton/src/app/addons/permissions/assets/less/permissions.less
new file mode 100644
index 0000000..7ce4d10
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/assets/less/permissions.less
@@ -0,0 +1,44 @@
+// 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.
+
+.border-hdr {
+ border-bottom: 1px solid #E3E3E3;
+ margin-bottom: 10px;
+ .help{
+
+ }
+ h3{
+ text-transform: capitalize;
+ margin-bottom: 0;
+ }
+}
+
+
+.permission-items.unstyled{
+ margin-left: 0px;
+ li {
+ padding: 5px;
+ border-bottom: 1px solid #E3E3E3;
+ border-right: 1px solid #E3E3E3;
+ border-left: 3px solid #E3E3E3;
+ &:first-child{
+ border-top: 1px solid #E3E3E3;
+ }
+ &:nth-child(odd){
+ border-left: 3px solid red;
+ }
+ button {
+ float: right;
+ margin-bottom: 6px;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/base.js b/share/www/fauxton/src/app/addons/permissions/base.js
new file mode 100644
index 0000000..016ba1c
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/base.js
@@ -0,0 +1,25 @@
+// 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/permissions/routes"
+],
+
+function(app, FauxtonAPI, Permissions) {
+
+ Permissions.initialize = function() {};
+
+ return Permissions;
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/resources.js b/share/www/fauxton/src/app/addons/permissions/resources.js
new file mode 100644
index 0000000..66eaffd
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/resources.js
@@ -0,0 +1,70 @@
+// 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 Permissions = FauxtonAPI.addon();
+
+ Permissions.Security = Backbone.Model.extend({
+ defaults: {
+ admins: {
+ names: [],
+ roles: []
+ },
+
+ members: {
+ names: [],
+ roles: []
+ }
+ },
+
+ isNew: function () {
+ return false;
+ },
+
+ initialize: function (attrs, options) {
+ this.database = options.database;
+ },
+
+ url: function () {
+ return this.database.id + '/_security';
+ },
+
+ addItem: function (value, type, section) {
+ var sectionValues = this.get(section);
+
+ if (!sectionValues || !sectionValues[type]) {
+ return {
+ error: true,
+ msg: 'Section ' + section + 'does not exist'
+ };
+ }
+
+ if (sectionValues[type].indexOf(value) > -1) {
+ return {
+ error: true,
+ msg: 'Role/Name has already been added'
+ };
+ }
+
+ sectionValues[type].push(value);
+ return this.set(section, sectionValues);
+ }
+
+ });
+
+ return Permissions;
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/routes.js b/share/www/fauxton/src/app/addons/permissions/routes.js
new file mode 100644
index 0000000..89c2bd7
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/routes.js
@@ -0,0 +1,63 @@
+// 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/databases/base",
+ "addons/permissions/views"
+],
+function (app, FauxtonAPI, Databases, Permissions) {
+
+ var PermissionsRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: 'one_pane',
+ selectedHeader: 'Databases',
+
+ routes: {
+ 'database/:database/permissions': 'permissions'
+ },
+
+ initialize: function (route, masterLayout, options) {
+ var docOptions = app.getParams();
+ docOptions.include_docs = true;
+
+ this.databaseName = options[0];
+ this.database = new Databases.Model({id:this.databaseName});
+ this.security = new Permissions.Security(null, {
+ database: this.database
+ });
+ },
+
+ establish: function () {
+ return [this.database.fetch(), this.security.fetch()];
+ },
+
+ permissions: function () {
+ this.setView('#dashboard-content', new Permissions.Permissions({
+ database: this.database,
+ model: this.security
+ }));
+
+ },
+
+ crumbs: function () {
+ return [
+ {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
+ {"name": "Permissions", "link": "/permissions"}
+ ];
+ },
+
+ });
+
+ Permissions.RouteObjects = [PermissionsRouteObject];
+ return Permissions;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/templates/item.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/templates/item.html b/share/www/fauxton/src/app/addons/permissions/templates/item.html
new file mode 100644
index 0000000..616ffd6
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/templates/item.html
@@ -0,0 +1,17 @@
+<!--
+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.
+-->
+
+<span> <%= item %> </span>
+<button type="button" class="close">×</button>
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/templates/permissions.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/templates/permissions.html b/share/www/fauxton/src/app/addons/permissions/templates/permissions.html
new file mode 100644
index 0000000..99c9ff5
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/templates/permissions.html
@@ -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.
+-->
+
+<div id="sections"> </div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/templates/section.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/templates/section.html b/share/www/fauxton/src/app/addons/permissions/templates/section.html
new file mode 100644
index 0000000..3360308
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/templates/section.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.
+-->
+<header class="border-hdr">
+<h3> <%= (section) %> </h3>
+<p id="help"> <%= help %> <a href="<%=getDocUrl('database_permission')%>" target="_blank"><i class="icon-question-sign"> </i> </a></p>
+</header>
+
+<div class="row">
+ <div class="span6">
+ <header>
+ <h4> Users </h4>
+ <p>Specify users who will have <%= section %> access to this database.</p>
+ </header>
+ <form class="permission-item-form form-inline">
+ <input data-section="<%= section %>" data-type="names" type="text" class="item input-small" placeholder="Add Name">
+ <button type="submit" class="button btn green fonticon-circle-plus">Add Name</button>
+ </form>
+ <ul class="clearfix unstyled permission-items span10" id="<%= (section) %>-items-names">
+ </ul>
+ </div>
+ <div class="span6">
+ <header>
+ <h4> Roles </h4>
+ <p>All users under the following role(s) will have <%= section %> access.</p>
+ </header>
+
+
+ <form class="permission-item-form form-inline">
+ <input data-section="<%= section %>" data-type="roles" type="text" class="item input-small" placeholder="Add Role">
+ <button type="submit" class="button btn green fonticon-circle-plus">Add Role</button>
+ </form>
+ <ul class="unstyled permission-items span10" id="<%= (section) %>-items-roles">
+ </ul>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/tests/resourceSpec.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/tests/resourceSpec.js b/share/www/fauxton/src/app/addons/permissions/tests/resourceSpec.js
new file mode 100644
index 0000000..f73687a
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/tests/resourceSpec.js
@@ -0,0 +1,51 @@
+// 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/permissions/resources',
+ 'testUtils'
+], function (FauxtonAPI, Models, testUtils) {
+ var assert = testUtils.assert;
+
+ describe('Permissions', function () {
+
+ describe('#addItem', function () {
+ var security;
+
+ beforeEach(function () {
+ security = new Models.Security(null, {database: 'fakedb'});
+ });
+
+ it('Should add value to section', function () {
+
+ security.addItem('_user', 'names', 'admins');
+ assert.equal(security.get('admins').names[0], '_user');
+ });
+
+ it('Should handle incorrect type', function () {
+ security.addItem('_user', 'asdasd', 'admins');
+ });
+
+ it('Should handle incorrect section', function () {
+ security.addItem('_user', 'names', 'Asdasd');
+ });
+
+ it('Should reject duplicates', function () {
+ security.addItem('_user', 'names', 'admins');
+ security.addItem('_user', 'names', 'admins');
+ assert.equal(security.get('admins').names.length, 1);
+ });
+ });
+
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/tests/viewsSpec.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/tests/viewsSpec.js b/share/www/fauxton/src/app/addons/permissions/tests/viewsSpec.js
new file mode 100644
index 0000000..e5330c0
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/tests/viewsSpec.js
@@ -0,0 +1,159 @@
+// 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/permissions/views',
+ 'addons/permissions/resources',
+ 'testUtils'
+], function (FauxtonAPI, Views, Models, testUtils) {
+ var assert = testUtils.assert,
+ ViewSandbox = testUtils.ViewSandbox;
+
+ describe('Permission View', function () {
+
+ beforeEach(function () {
+ security = new Models.Security({'admins': {
+ 'names': ['_user'],
+ 'roles': []
+ }
+ }, {database: 'fakedb'});
+
+ section = new Views.Permissions({
+ database: 'fakedb',
+ model: security
+ });
+
+ viewSandbox = new ViewSandbox();
+ viewSandbox.renderView(section);
+ });
+
+ afterEach(function () {
+ viewSandbox.remove();
+ });
+
+ describe('itemRemoved', function () {
+
+ it('Should set model', function () {
+ var saveMock = sinon.spy(security, 'set');
+ Views.events.trigger('itemRemoved');
+
+ assert.ok(saveMock.calledOnce);
+ var args = saveMock.args;
+ assert.deepEqual(args[0][0], {"admins":{"names":["_user"],"roles":[]},"members":{"names":[],"roles":[]}});
+ });
+
+ it('Should save model', function () {
+ var saveMock = sinon.spy(security, 'save');
+ Views.events.trigger('itemRemoved');
+
+ assert.ok(saveMock.calledOnce);
+ });
+ });
+
+ });
+
+ describe('PermissionsSection', function () {
+ var section, security;
+
+ beforeEach(function () {
+ security = new Models.Security({'admins': {
+ 'names': ['_user'],
+ 'roles': []
+ }
+ }, {database: 'fakedb'});
+
+ section = new Views.PermissionSection({
+ section: 'admins',
+ model: security
+ });
+
+ viewSandbox = new ViewSandbox();
+ viewSandbox.renderView(section);
+ });
+
+ afterEach(function () {
+ viewSandbox.remove();
+ });
+
+ describe('#discardRemovedViews', function () {
+ it('Should not filter out active views', function () {
+ section.discardRemovedViews();
+
+ assert.equal(section.nameViews.length, 1);
+
+ });
+
+ it('Should filter out removed views', function () {
+ section.nameViews[0].removed = true;
+ section.discardRemovedViews();
+
+ assert.equal(section.nameViews.length, 0);
+
+ });
+
+ });
+
+ describe('#getItemFromView', function () {
+
+ it('Should return item list', function () {
+ var items = section.getItemFromView(section.nameViews);
+
+ assert.deepEqual(items, ['_user']);
+ });
+
+ });
+
+ describe('#addItems', function () {
+
+ it('Should add item to model', function () {
+ //todo add a test here
+
+ });
+
+ });
+
+ });
+
+ describe('PermissionItem', function () {
+ var item;
+
+ beforeEach(function () {
+ item = new Views.PermissionItem({
+ item: '_user'
+ });
+
+ viewSandbox = new ViewSandbox();
+ viewSandbox.renderView(item);
+ });
+
+ afterEach(function () {
+ viewSandbox.remove();
+ });
+
+ it('should trigger event on remove item', function () {
+ var eventSpy = sinon.spy();
+
+ Views.events.on('itemRemoved', eventSpy);
+
+ item.$('.close').click();
+
+ assert.ok(eventSpy.calledOnce);
+ });
+
+ it('should set removed to true', function () {
+ item.$('.close').click();
+
+ assert.ok(item.removed);
+ });
+ });
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/permissions/views.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/permissions/views.js b/share/www/fauxton/src/app/addons/permissions/views.js
new file mode 100644
index 0000000..eb5a378
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/permissions/views.js
@@ -0,0 +1,200 @@
+// 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/permissions/resources"
+],
+function (app, FauxtonAPI, Permissions ) {
+ var events = {};
+ Permissions.events = _.extend(events, Backbone.Events);
+
+ Permissions.Permissions = FauxtonAPI.View.extend({
+ template: "addons/permissions/templates/permissions",
+
+ initialize: function (options) {
+ this.database = options.database;
+ this.listenTo(Permissions.events, 'itemRemoved', this.itemRemoved);
+ },
+
+ itemRemoved: function (event) {
+ this.model.set({
+ admins: this.adminsView.items(),
+ members: this.membersView.items()
+ });
+
+ this.model.save().then(function () {
+ FauxtonAPI.addNotification({
+ msg: 'Database permissions has been updated.'
+ });
+ }, function (xhr) {
+ FauxtonAPI.addNotification({
+ msg: 'Could not update permissions - reason: ' + xhr.responseText,
+ type: 'error'
+ });
+ });
+ },
+
+ beforeRender: function () {
+ this.adminsView = this.insertView('#sections', new Permissions.PermissionSection({
+ model: this.model,
+ section: 'admins',
+ help: 'Database admins can update design documents and edit the admin and member lists.'
+ }));
+
+ this.membersView = this.insertView('#sections', new Permissions.PermissionSection({
+ model: this.model,
+ section: 'members',
+ help: 'Database members can access the database. If no members are defined, the database is public.'
+ }));
+ },
+
+ serialize: function () {
+ return {
+ databaseName: this.database.id,
+ };
+ }
+ });
+
+ Permissions.PermissionSection = FauxtonAPI.View.extend({
+ template: "addons/permissions/templates/section",
+ initialize: function (options) {
+ this.section = options.section;
+ this.help = options.help;
+ },
+
+ events: {
+ "submit .permission-item-form": "addItem",
+ 'click button.close': "removeItem"
+ },
+
+ beforeRender: function () {
+ var section = this.model.get(this.section);
+
+ this.nameViews = [];
+ this.roleViews = [];
+
+ _.each(section.names, function (name) {
+ var nameView = this.insertView('#'+this.section+'-items-names', new Permissions.PermissionItem({
+ item: name,
+ }));
+ this.nameViews.push(nameView);
+ }, this);
+
+ _.each(section.roles, function (role) {
+ var roleView = this.insertView('#'+this.section+'-items-roles', new Permissions.PermissionItem({
+ item: role,
+ }));
+ this.roleViews.push(roleView);
+ }, this);
+ },
+
+ getItemFromView: function (viewList) {
+ return _.map(viewList, function (view) {
+ return view.item;
+ });
+ },
+
+ discardRemovedViews: function () {
+ this.nameViews = _.filter(this.nameViews, function (view) {
+ return !view.removed;
+ });
+
+ this.roleViews = _.filter(this.roleViews, function (view) {
+ return !view.removed;
+ });
+ },
+
+ items: function () {
+ this.discardRemovedViews();
+
+ return {
+ names: this.getItemFromView(this.nameViews),
+ roles: this.getItemFromView(this.roleViews)
+ };
+ },
+
+ addItem: function (event) {
+ event.preventDefault();
+ var $item = this.$(event.currentTarget).find('.item'),
+ value = $item.val(),
+ section = $item.data('section'),
+ type = $item.data('type'),
+ that = this;
+
+ var resp = this.model.addItem(value, type, section);
+
+ if (resp && resp.error) {
+ return FauxtonAPI.addNotification({
+ msg: resp.msg,
+ type: 'error'
+ });
+ }
+
+ this.model.save().then(function () {
+ that.render();
+ FauxtonAPI.addNotification({
+ msg: 'Database permissions has been updated.'
+ });
+ }, function (xhr) {
+ FauxtonAPI.addNotification({
+ msg: 'Could not update permissions - reason: ' + xhr.responseText,
+ type: 'error'
+ });
+ });
+ },
+
+ serialize: function () {
+ return {
+ section: this.section,
+ help: this.help
+ };
+ }
+
+ });
+
+ Permissions.PermissionItem = FauxtonAPI.View.extend({
+ tagName: "li",
+ template: "addons/permissions/templates/item",
+ initialize: function (options) {
+ this.item = options.item;
+ this.viewsList = options.viewsList;
+ },
+
+ events: {
+ 'click .close': "removeItem"
+ },
+
+ removeItem: function (event) {
+ var that = this;
+ event.preventDefault();
+
+ this.removed = true;
+ Permissions.events.trigger('itemRemoved');
+
+ this.$el.hide('fast', function () {
+ that.remove();
+ });
+ },
+
+
+ serialize: function () {
+ return {
+ item: this.item
+ };
+ }
+
+ });
+
+ return Permissions;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/plugins/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/plugins/base.js b/share/www/fauxton/src/app/addons/plugins/base.js
new file mode 100644
index 0000000..0798fbd
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/plugins/base.js
@@ -0,0 +1,24 @@
+// 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/plugins/routes"
+],
+
+function(app, FauxtonAPI, plugins) {
+ plugins.initialize = function() {
+ //FauxtonAPI.addHeaderLink({title: "Plugins", href: "#_plugins", icon: "fonticon-plugins", className: 'plugins'});
+ };
+ return plugins;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/plugins/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/plugins/resources.js b/share/www/fauxton/src/app/addons/plugins/resources.js
new file mode 100644
index 0000000..d00fada
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/plugins/resources.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"
+],
+
+function (app, FauxtonAPI) {
+ var plugins = FauxtonAPI.addon();
+
+ plugins.Hello = FauxtonAPI.View.extend({
+ template: "addons/plugins/templates/plugins"
+ });
+
+ return plugins;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/plugins/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/plugins/routes.js b/share/www/fauxton/src/app/addons/plugins/routes.js
new file mode 100644
index 0000000..24d47f0
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/plugins/routes.js
@@ -0,0 +1,47 @@
+// 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/plugins/resources"
+],
+function(app, FauxtonAPI, plugins) {
+ var PluginsRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: "one_pane",
+
+ crumbs: [
+ {"name": "Plugins","link": "_plugins"}
+ ],
+
+ routes: {
+ "_plugins": "pluginsRoute"
+ },
+
+ selectedHeader: "Plugins",
+
+ roles: ["_admin"],
+
+ apiUrl:'plugins',
+
+ initialize: function () {
+ //put common views used on all your routes here (eg: sidebars )
+ },
+
+ pluginsRoute: function () {
+ this.setView("#dashboard-content", new plugins.Hello({}));
+ }
+ });
+
+ plugins.RouteObjects = [PluginsRouteObject];
+ return plugins;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/plugins/templates/plugins.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/plugins/templates/plugins.html b/share/www/fauxton/src/app/addons/plugins/templates/plugins.html
new file mode 100644
index 0000000..3002247
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/plugins/templates/plugins.html
@@ -0,0 +1,102 @@
+<!--
+
+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="content">
+ <div class="row">
+ <h2>GeoCouch</h2>
+ <p>Version: <strong>couchdb1.2.x_v0.3.0-11-g66e6219</strong></p>
+ <p>Author: Volker Mische</p>
+ <p>
+ Available Erlang Versions:
+ <ul>
+ <li>CouchDB 1.4.0-XXX R15B01</li>
+ </ul>
+ </p>
+ <p>
+ <button href="#" class="install-plugin" data-url="http://people.apache.org/~jan" data-checksums='{"1.4.0": {"R15B03":"D5QPhrJTAifM42DXqAj4RxzfEtI="}}' data-name="geocouch" data-version="couchdb1.2.x_v0.3.0-16-g66e6219">Install GeoCouch Now</button>
+ </p>
+ </div>
+ <div class="row">
+ <h2>CouchPerUser</h2>
+ <p>Version: <strong>1.0.0</strong></p>
+ <p>Author: Bob Ippolito</p>
+ <p>
+ Available Erlang Versions:
+ <ul>
+ <li>CouchDB 1.4.0-XXX R15B01</li>
+ </ul>
+ </p>
+ <p>
+ <button href="#" class="install-plugin" data-url="http://people.apache.org/~jan" data-checksums='{"1.4.0": {"R15B03":"Aj3mjC6M75NA62q5/xkP0tl8Hws="}}' data-name="couchperuser" data-version="1.0.0">Install CouchPerUser Now</button>
+ </p>
+ </div>
+ </div>
+ </div></body>
+ <script>
+ $('.install-plugin').each(function() {
+ var button = $(this);
+ var name = button.data('name');
+ var version = button.data('version');
+ $.get("/_config/plugins/" + name + "/", function(body, textStatus) {
+ body = JSON.parse(body);
+ if(body == version) {
+ button.html('Already Installed. Click to Uninstall');
+ button.data('delete', true);
+ } else {
+ button.html('Other Version Installed: ' + body);
+ button.attr('disabled', true);
+ }
+ });
+ });
+
+ $('.install-plugin').click(function(event) {
+ var button = $(this);
+ var delete_plugin = button.data('delete') || false;
+ var plugin_spec = JSON.stringify({
+ name: button.data('name'),
+ url: button.data('url'),
+ version: button.data('version'),
+ checksums: button.data('checksums'),
+ "delete": delete_plugin
+ });
+ var url = '/_plugins'
+ $.ajax({
+ url: url,
+ type: 'POST',
+ data: plugin_spec,
+ contentType: 'application/json', // what we send to the server
+ dataType: 'json', // expected from the server
+ processData: false, // keep our precious JSON
+ success: function(data, textStatus, jqXhr) {
+ if(textStatus == "success") {
+ var action = delete_plugin ? 'Uninstalled' : 'Installed';
+ button.html('Sucessfully ' + action);
+ button.attr('disabled', true);
+ } else {
+ button.html(textStatus);
+ }
+ },
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('Accept', 'application/json');
+ },
+ });
+ });
+ </script>
+ <style type="text/css">
+ .row {
+ background-color: #FFF;
+ padding:1em;
+ margin-bottom:1em;
+ }
+ </style>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/assets/less/replication.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/assets/less/replication.less b/share/www/fauxton/src/app/addons/replication/assets/less/replication.less
new file mode 100644
index 0000000..a301966
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/assets/less/replication.less
@@ -0,0 +1,196 @@
+// 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.
+
+
+@brown: #3A2C2B;
+@red: #E33F3B;
+@darkRed: #AF2D24;
+@linkRed: #DA4F49;
+@greyBrown: #A59D9D;
+@fontGrey: #808080;
+@secondarySidebar: #E4DFDC;
+
+
+form#replication {
+ position: relative;
+ max-width: none;
+ width: auto;
+
+ .form_set{
+ width: 350px;
+ display: inline-block;
+ border: 1px solid @greyBrown;
+ padding: 15px 10px 0;
+ margin-bottom: 20px;
+ &.middle{
+ width: 100px;
+ border: none;
+ position: relative;
+ height: 100px;
+ margin: 0;
+ }
+ input, select {
+ margin: 0 0 16px 5px;
+ height: 40px;
+ width: 318px;
+ }
+ .btn-group{
+ margin: 0 0 16px 5px;
+ .btn {
+ padding: 10px 57px;
+ }
+ }
+ &.local{
+ .local_option{
+ display: block;
+ }
+ .remote_option{
+ display: none;
+ }
+ .local-btn{
+ background-color: @red;
+ color: #fff;
+ }
+ .remote-btn{
+ background-color: #f5f5f5;
+ color: @fontGrey;
+ }
+ }
+ .local_option{
+ display: none;
+ }
+ .remote-btn{
+ background-color: @red;
+ color: #fff;
+ }
+ }
+
+
+ .options {
+ position: relative;
+ &:after{
+ content: '';
+ display: block;
+ position: absolute;
+ right: -16px;
+ top: 9px;
+ width: 0;
+ height: 0;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: 5px solid black;
+ border-top: none;
+ }
+ &.off {
+ &:after{
+ content: '';
+ display: block;
+ position: absolute;
+ right: -16px;
+ top: 9px;
+ width: 0;
+ height: 0;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: none;
+ border-top: 5px solid black;
+ }
+ }
+ }
+ .control-group{
+ label{
+ float: left;
+ min-height: 30px;
+ vertical-align: top;
+ padding-right: 5px;
+ min-width: 130px;
+ padding-left: 0px;
+ }
+ input[type=radio],
+ input[type=checkbox]{
+ margin: 0 0 2px 0;
+ }
+ }
+
+ .circle{
+ z-index: 0;
+ position: absolute;
+ top: 20px;
+ left: 15px;
+
+ &:after {
+ width: 70px;
+ height: 70px;
+ content: '';
+ display: block;
+ position: relative;
+ margin: 0 auto;
+ border: 1px solid @greyBrown;
+ -webkit-border-radius: 40px;
+ -moz-border-radius: 40px;
+ border-radius:40px;
+ }
+ }
+ .swap {
+ text-decoration: none;
+ z-index: 30;
+ cursor: pointer;
+ position: absolute;
+ font-size: 40px;
+ width: 27px;
+ height: 12px;
+ top: 31px;
+ left: 30px;
+ &:hover {
+ color: @greyBrown;
+ }
+ }
+
+}
+#replicationStatus{
+ &.showHeader{
+ li.header{
+ display: block;
+ border: none;
+ }
+ ul {
+ border:1px solid @greyBrown;
+ }
+ }
+ li.header{
+ display: none;
+ }
+ ul{
+ margin: 0;
+ li{
+ .progress,
+ p{
+ margin: 0px;
+ vertical-align: bottom;
+ &.break {
+ -ms-word-break: break-all;
+ word-break: break-all;
+
+ /* Non standard for webkit */
+ word-break: break-word;
+ -webkit-hyphens: auto;
+ -moz-hyphens: auto;
+ hyphens: auto;
+ }
+ }
+ padding: 10px 10px;
+ margin: 0;
+ list-style: none;
+ border-top: 1px solid @greyBrown;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/base.js b/share/www/fauxton/src/app/addons/replication/base.js
new file mode 100644
index 0000000..93965c1
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/base.js
@@ -0,0 +1,24 @@
+// 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/replication/route"
+],
+
+function(app, FauxtonAPI, replication) {
+ replication.initialize = function() {
+ FauxtonAPI.addHeaderLink({title: "Replication", href: "#/replication", icon: "fonticon-replicate",});
+ };
+ return replication;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/resources.js b/share/www/fauxton/src/app/addons/replication/resources.js
new file mode 100644
index 0000000..14f255a
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/resources.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/activetasks/resources'
+],
+
+function (app, FauxtonAPI, ActiveTasks) {
+ var Replication = {};
+
+ //these are probably dupes from the database modules. I'm going to keep them seperate for now.
+ Replication.DBModel = Backbone.Model.extend({
+ label: function () {
+ //for autocomplete
+ return this.get("name");
+ }
+ });
+
+ Replication.DBList = Backbone.Collection.extend({
+ model: Replication.DBModel,
+ url: function() {
+ return app.host + "/_all_dbs";
+ },
+ parse: function(resp) {
+ // TODO: pagination!
+ return _.map(resp, function(database) {
+ return {
+ id: database,
+ name: database
+ };
+ });
+ }
+ });
+
+ Replication.Task = Backbone.Model.extend({});
+
+ Replication.Tasks = Backbone.Collection.extend({
+ model: Replication.Task,
+ url: function () {
+ return app.host + '/_active_tasks';
+ },
+ parse: function(resp){
+ //only want replication tasks to return
+ return _.filter(resp, function(task){
+ return task.type === "replication";
+ });
+ }
+ });
+
+ Replication.Replicate = Backbone.Model.extend({
+ documentation: "replication_doc",
+ url: function(){
+ return app.host + "/_replicate";
+ }
+ });
+
+ return Replication;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/route.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/route.js b/share/www/fauxton/src/app/addons/replication/route.js
new file mode 100644
index 0000000..17368f8
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/route.js
@@ -0,0 +1,50 @@
+// 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/replication/resources",
+ "addons/replication/views"
+],
+function(app, FauxtonAPI, Replication, Views) {
+ var RepRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: "one_pane",
+ roles: ["_admin"],
+ routes: {
+ "replication": "defaultView",
+ "replication/:dbname": "defaultView"
+ },
+ selectedHeader: "Replication",
+ apiUrl: function() {
+ return [this.replication.url(), this.replication.documentation];
+ },
+ crumbs: [
+ {"name": "Replicate changes from: ", "link": "replication"}
+ ],
+ defaultView: function(dbname){
+ this.databases = new Replication.DBList({});
+ this.tasks = new Replication.Tasks({id: "ReplicationTasks"});
+ this.replication = new Replication.Replicate({});
+ this.setView("#dashboard-content", new Views.ReplicationForm({
+ selectedDB: dbname ||"",
+ collection: this.databases,
+ status: this.tasks
+ }));
+ }
+ });
+
+
+ Replication.RouteObjects = [RepRouteObject];
+
+ return Replication;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/templates/form.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/templates/form.html b/share/www/fauxton/src/app/addons/replication/templates/form.html
new file mode 100644
index 0000000..32a87dc
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/templates/form.html
@@ -0,0 +1,74 @@
+<!--
+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.
+-->
+
+<form id="replication" class="form-horizontal">
+ <div class="from form_set local">
+ <div class="btn-group">
+ <button class="btn local-btn" type="button" value="local">Local</button>
+ <button class="btn remote-btn" type="button" value="remote">Remote</button>
+ </div>
+
+ <div class="from_local local_option">
+ <select id="from_name" name="source">
+ <% _.each( databases, function( db, i ){ %>
+ <option value="<%=db.name%>" <% if(selectedDB == db.name){%>selected<%}%> ><%=db.name%></option>
+ <% }); %>
+ </select>
+ </div>
+ <div class="from_to_remote remote_option">
+ <input type="text" id="from_url" name="source" size="30" value="http://">
+ </div>
+ </div>
+
+ <div class="form_set middle">
+ <span class="circle "></span>
+ <a href="#" title="Switch Target and Source" class="swap">
+ <span class="fonticon-swap-arrows"></span>
+ </a>
+ </span>
+ </div>
+
+ <div class="to form_set local">
+ <div class="btn-group">
+ <button class="btn local-btn" type="button" value="local">Local</button>
+ <button class="btn remote-btn" type="button" value="remote">Remote</button>
+ </div>
+ <div class="to_local local_option">
+ <input type="text" id="to_name" name="target" size="30" placeholder="database name">
+ </div>
+
+ <div class="to_remote remote_option">
+ <input type="text" id="to_url" name="target" size="30" value="http://">
+ </div>
+ </div>
+
+
+ <div class="actions">
+ <div class="control-group">
+ <label for="continuous">
+ <input type="checkbox" name="continuous" value="true" id="continuous">
+ Continuous
+ </label>
+
+ <label for="createTarget">
+ <input type="checkbox" name="create_target" value="true" id="createTarget">
+ Create Target <a href="<%=getDocUrl('replication_doc')%>" target="_blank"><i class="icon-question-sign" rel="tooltip" title="Create the target database"></i></a>
+ </label>
+ </div>
+
+ <button class="btn btn-success btn-large save" type="submit">Replicate</button>
+ </div>
+</form>
+
+<div id="replicationStatus"></div>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/templates/progress.html
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/templates/progress.html b/share/www/fauxton/src/app/addons/replication/templates/progress.html
new file mode 100644
index 0000000..1e6ef90
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/templates/progress.html
@@ -0,0 +1,22 @@
+<!--
+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.
+-->
+<p class="span6 break">Replicating <strong><%=source%></strong> to <strong><%=target%></strong></p>
+
+<div class="span4 progress progress-striped active">
+ <div class="bar" style="width: <%=progress || 0%>%;"><%=progress || "0"%>%</div>
+</div>
+
+<span class="span1">
+ <button class="cancel btn btn-danger btn-large delete" data-source="<%=source%>" data-rep-id="<%=repid%>" data-continuous="<%=continuous%>" data-target="<%=target%>">Cancel</a>
+</span>
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/tests/replicationSpec.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/tests/replicationSpec.js b/share/www/fauxton/src/app/addons/replication/tests/replicationSpec.js
new file mode 100644
index 0000000..788b082
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/tests/replicationSpec.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([
+ 'addons/replication/base',
+ 'chai'
+], function (Replication, chai) {
+ var expect = chai.expect;
+
+ describe('Replication Addon', function(){
+
+ describe('Replication DBList Collection', function () {
+ var rep;
+
+ beforeEach(function () {
+ rep = new rep.DBList(["foo","bar","baz","bo"]);
+ });
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/replication/views.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/replication/views.js b/share/www/fauxton/src/app/addons/replication/views.js
new file mode 100644
index 0000000..f4b96fd
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/replication/views.js
@@ -0,0 +1,295 @@
+// 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/fauxton/components",
+ "addons/replication/resources"
+],
+function(app, FauxtonAPI, Components, replication) {
+ var View = {},
+ Events ={},
+ pollingInfo ={
+ rate: 5,
+ intervalId: null
+ };
+
+ _.extend(Events, Backbone.Events);
+
+ // NOTES: http://wiki.apache.org/couchdb/Replication
+
+ // Replication form view is huge
+ // -----------------------------------
+ // afterRender: autocomplete on the target input field
+ // beforeRender: add the status table
+ // disableFields: disable non active fields on submit
+ // enableFields: enable field when radio btns are clicked
+ // establish: get the DB list for autocomplete
+ // formValidation: make sure fields aren't empty
+ // showProgress: make a call to active_tasks model and show only replication types. Poll every 5 seconds. (make this it's own view)
+ // startReplication: saves to the model, starts replication
+ // submit: form submit handler
+ // swapFields: change to and from target
+ // toggleAdvancedOptions: toggle advanced
+
+ View.ReplicationForm = FauxtonAPI.View.extend({
+ template: "addons/replication/templates/form",
+ events: {
+ "submit #replication": "validate",
+ "click .btn-group .btn": "showFields",
+ "click .swap": "swapFields",
+ "click .options": "toggleAdvancedOptions"
+ },
+ initialize: function(options){
+ this.status = options.status;
+ this.selectedDB = options.selectedDB;
+ this.newRepModel = new replication.Replicate({});
+ },
+ afterRender: function(){
+ this.dbSearchTypeahead = new Components.DbSearchTypeahead({
+ dbLimit: 30,
+ el: "input#to_name"
+ });
+
+ this.dbSearchTypeahead.render();
+
+ },
+
+ beforeRender: function(){
+ this.insertView("#replicationStatus", new View.ReplicationList({
+ collection: this.status
+ }));
+ },
+ cleanup: function(){
+ clearInterval(pollingInfo.intervalId);
+ },
+ enableFields: function(){
+ this.$el.find('input','select').attr('disabled',false);
+ },
+ disableFields: function(){
+ this.$el.find('input:hidden','select:hidden').attr('disabled',true);
+ },
+ showFields: function(e){
+ var $currentTarget = this.$(e.currentTarget),
+ targetVal = $currentTarget.val();
+
+ if (targetVal === "local"){
+ $currentTarget.parents('.form_set').addClass('local');
+ }else{
+ $currentTarget.parents('.form_set').removeClass('local');
+ }
+ },
+ establish: function(){
+ return [ this.collection.fetch(), this.status.fetch()];
+ },
+ validate: function(e){
+ e.preventDefault();
+ var notification;
+ if (this.formValidation()){
+ notification = FauxtonAPI.addNotification({
+ msg: "Please enter every field.",
+ type: "error",
+ clear: true
+ });
+ }else if (this.$('input#to_name').is(':visible') && !this.$('input[name=create_target]').is(':checked')){
+ var alreadyExists = this.collection.where({"name":this.$('input#to_name').val()});
+ if (alreadyExists.length === 0){
+ notification = FauxtonAPI.addNotification({
+ msg: "This database doesn't exist. Check create target if you want to create it.",
+ type: "error",
+ clear: true
+ });
+ }
+ }else{
+ this.submit(e);
+ }
+ },
+ formValidation: function(e){
+ var $remote = this.$el.find('input:visible'),
+ error = false;
+ for(var i=0; i<$remote.length; i++){
+ if ($remote[i].value =="http://" || $remote[i].value ===""){
+ error = true;
+ }
+ }
+ return error;
+ },
+ serialize: function(){
+ return {
+ databases: this.collection.toJSON(),
+ selectedDB: this.selectedDB
+ };
+ },
+ startReplication: function(json){
+ var that = this;
+ this.newRepModel.save(json,{
+ success: function(resp){
+ var notification = FauxtonAPI.addNotification({
+ msg: "Replication from "+resp.get('source')+" to "+ resp.get('target')+" has begun.",
+ type: "success",
+ clear: true
+ });
+ that.updateButtonText(false);
+ Events.trigger('update:tasks');
+ },
+ error: function(model, xhr, options){
+ var errorMessage = JSON.parse(xhr.responseText);
+ var notification = FauxtonAPI.addNotification({
+ msg: errorMessage.reason,
+ type: "error",
+ clear: true
+ });
+ that.updateButtonText(false);
+ }
+ });
+ this.enableFields();
+ },
+ updateButtonText: function(wait){
+ var $button = this.$('#replication button[type=submit]');
+ if(wait){
+ $button.text('Starting replication...').attr('disabled', true);
+ } else {
+ $button.text('Replication').attr('disabled', false);
+ }
+ },
+ submit: function(e){
+ this.disableFields();
+ var formJSON = {};
+ _.map(this.$(e.currentTarget).serializeArray(), function(formData){
+ if(formData.value !== ''){
+ formJSON[formData.name] = (formData.value ==="true"? true: formData.value.replace(/\s/g, '').toLowerCase());
+ }
+ });
+
+ this.updateButtonText(true);
+ this.startReplication(formJSON);
+ },
+ swapFields: function(e){
+ e.preventDefault();
+ //WALL O' VARIABLES
+ var $fromSelect = this.$('#from_name'),
+ $toSelect = this.$('#to_name'),
+ $toInput = this.$('#to_url'),
+ $fromInput = this.$('#from_url'),
+ fromSelectVal = $fromSelect.val(),
+ fromInputVal = $fromInput.val(),
+ toSelectVal = $toSelect.val(),
+ toInputVal = $toInput.val();
+
+ $fromSelect.val(toSelectVal);
+ $toSelect.val(fromSelectVal);
+
+ $fromInput.val(toInputVal);
+ $toInput.val(fromInputVal);
+ }
+ });
+
+
+ View.ReplicationList = FauxtonAPI.View.extend({
+ tagName: "ul",
+ initialize: function(){
+ Events.bind('update:tasks', this.establish, this);
+ this.listenTo(this.collection, "reset", this.render);
+ this.$el.prepend("<li class='header'><h4>Active Replication Tasks</h4></li>");
+ },
+ establish: function(){
+ return [this.collection.fetch({reset: true})];
+ },
+ setPolling: function(){
+ var that = this;
+ this.cleanup();
+ pollingInfo.intervalId = setInterval(function() {
+ that.establish();
+ }, pollingInfo.rate*1000);
+ },
+ cleanup: function(){
+ clearInterval(pollingInfo.intervalId);
+ },
+ beforeRender: function(){
+ this.collection.forEach(function(item) {
+ this.insertView(new View.replicationItem({
+ model: item
+ }));
+ }, this);
+ },
+ showHeader: function(){
+ if (this.collection.length > 0){
+ this.$el.parent().addClass('showHeader');
+ } else {
+ this.$el.parent().removeClass('showHeader');
+ }
+ },
+ afterRender: function(){
+ this.showHeader();
+ this.setPolling();
+ }
+ });
+
+ //make this a table row item.
+ View.replicationItem = FauxtonAPI.View.extend({
+ tagName: "li",
+ className: "row",
+ template: "addons/replication/templates/progress",
+ events: {
+ "click .cancel": "cancelReplication"
+ },
+ initialize: function(){
+ this.newRepModel = new replication.Replicate({});
+ },
+ establish: function(){
+ return [this.model.fetch()];
+ },
+ cancelReplication: function(e){
+ //need to pass "cancel": true with source & target
+ var $currentTarget = this.$(e.currentTarget),
+ repID = $currentTarget.attr('data-rep-id');
+ this.newRepModel.save({
+ "replication_id": repID,
+ "cancel": true
+ },
+ {
+ success: function(model, xhr, options){
+ var notification = FauxtonAPI.addNotification({
+ msg: "Replication stopped.",
+ type: "success",
+ clear: true
+ });
+ },
+ error: function(model, xhr, options){
+ var errorMessage = JSON.parse(xhr.responseText);
+ var notification = FauxtonAPI.addNotification({
+ msg: errorMessage.reason,
+ type: "error",
+ clear: true
+ });
+ }
+ });
+ },
+ afterRender: function(){
+ if (this.model.get('continuous')){
+ this.$el.addClass('continuous');
+ }
+ },
+ serialize: function(){
+ return {
+ progress: this.model.get('progress'),
+ target: this.model.get('target'),
+ source: this.model.get('source'),
+ continuous: this.model.get('continuous'),
+ repid: this.model.get('replication_id')
+ };
+ }
+ });
+
+ return View;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/stats/assets/less/stats.less
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/stats/assets/less/stats.less b/share/www/fauxton/src/app/addons/stats/assets/less/stats.less
new file mode 100644
index 0000000..cfa7679
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/stats/assets/less/stats.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.
+
+.datatypes {
+ border: #d3d3d3 1px solid;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ padding: 15px;
+}
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/stats/base.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/stats/base.js b/share/www/fauxton/src/app/addons/stats/base.js
new file mode 100644
index 0000000..1b44b8b
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/stats/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/stats/routes"
+],
+
+function(app, FauxtonAPI, Stats) {
+
+ Stats.initialize = function() {
+ FauxtonAPI.addHeaderLink({title: "Statistics", href: "#stats", icon: "fonticon-stats", className: 'stats'});
+ };
+
+ return Stats;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/stats/resources.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/stats/resources.js b/share/www/fauxton/src/app/addons/stats/resources.js
new file mode 100644
index 0000000..a761e6b
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/stats/resources.js
@@ -0,0 +1,38 @@
+// 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",
+ "backbone",
+ "lodash",
+ "modules/fauxton/base"
+],
+
+function (app, FauxtonAPI, backbone, _, Fauxton) {
+ var Stats = new FauxtonAPI.addon();
+
+ Stats.Collection = Backbone.Collection.extend({
+ model: Backbone.Model,
+ documentation: "stats",
+ url: app.host+"/_stats",
+ parse: function(resp) {
+ return _.flatten(_.map(resp, function(doc, key) {
+ return _.map(doc, function(v, k){
+ return _.extend({id: k, type: key}, v);
+ });
+ }), true);
+ }
+ });
+
+ return Stats;
+});
http://git-wip-us.apache.org/repos/asf/couchdb/blob/c14b2991/share/www/fauxton/src/app/addons/stats/routes.js
----------------------------------------------------------------------
diff --git a/share/www/fauxton/src/app/addons/stats/routes.js b/share/www/fauxton/src/app/addons/stats/routes.js
new file mode 100644
index 0000000..971c111
--- /dev/null
+++ b/share/www/fauxton/src/app/addons/stats/routes.js
@@ -0,0 +1,63 @@
+// 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/stats/views"
+],
+
+function(app, FauxtonAPI, Stats) {
+
+ var StatsRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: "with_sidebar",
+
+ routes: {
+ "stats":"showStats",
+ "_stats": "showStats"
+ },
+
+
+ crumbs: [
+ {"name": "Statistics", "link": "_stats"}
+ ],
+
+ selectedHeader: "Statistics",
+
+ initialize: function () {
+ this.stats = new Stats.Collection();
+
+ this.setView("#sidebar-content", new Views.StatSelect({
+ collection: this.stats
+ }));
+
+ },
+
+ showStats: function () {
+ this.setView("#dashboard-content", new Views.Statistics({
+ collection: this.stats
+ }));
+ },
+
+ establish: function() {
+ return [this.stats.fetch()];
+ },
+
+ apiUrl: function(){
+ return [ this.stats.url, this.stats.documentation];
+ }
+ });
+
+ Stats.RouteObjects = [StatsRouteObject];
+
+ return Stats;
+});