You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/07/22 14:17:07 UTC
[1/3] fauxton commit: updated refs/heads/master to 5de1fe6
Repository: couchdb-fauxton
Updated Branches:
refs/heads/master c754c6cac -> 5de1fe668
Admin: Fix style issues
PR: #480
PR-URL: https://github.com/apache/couchdb-fauxton/pull/480
Reviewed-By: garren smith <ga...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/3896d202
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/3896d202
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/3896d202
Branch: refs/heads/master
Commit: 3896d202d368de90b2565cf16feb6fb3898a4376
Parents: 919a7f8
Author: Robert Kowalski <ro...@apache.org>
Authored: Tue Jul 14 15:14:51 2015 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Wed Jul 22 14:17:08 2015 +0200
----------------------------------------------------------------------
app/addons/auth/resources.js | 43 +++++++++++++++++----------------------
1 file changed, 19 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/3896d202/app/addons/auth/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/resources.js b/app/addons/auth/resources.js
index c3deed7..175a314 100644
--- a/app/addons/auth/resources.js
+++ b/app/addons/auth/resources.js
@@ -55,7 +55,6 @@ function (app, FauxtonAPI, CouchdbSession) {
this.messages = _.extend({}, {
missingCredentials: 'Username or password cannot be blank.',
- passwordsNotMatch: 'Passwords do not match.',
loggedIn: 'You have been logged in.',
adminCreated: 'CouchDB admin created',
changePassword: 'Your password has been updated.',
@@ -132,10 +131,9 @@ function (app, FauxtonAPI, CouchdbSession) {
},
createAdmin: function (username, password, login) {
- var that = this,
- error_promise = this.validateUser(username, password, this.messages.missingCredentials);
+ var errorPromise = this.validateUser(username, password, this.messages.missingCredentials);
- if (error_promise) { return error_promise; }
+ if (errorPromise) { return errorPromise; }
var admin = new Admin({
name: username,
@@ -144,19 +142,18 @@ function (app, FauxtonAPI, CouchdbSession) {
return admin.save().then(function () {
if (login) {
- return that.login(username, password);
- } else {
- return that.fetchUser({forceFetch: true});
+ return this.login(username, password);
}
- });
+
+ return this.fetchUser({forceFetch: true});
+
+ }.bind(this));
},
login: function (username, password) {
- var error_promise = this.validateUser(username, password, this.messages.missingCredentials);
-
- if (error_promise) { return error_promise; }
+ var errorPromise = this.validateUser(username, password, this.messages.missingCredentials);
- var that = this;
+ if (errorPromise) { return errorPromise; }
return $.ajax({
cache: false,
@@ -165,8 +162,8 @@ function (app, FauxtonAPI, CouchdbSession) {
dataType: "json",
data: {name: username, password: password}
}).then(function () {
- return that.fetchUser({forceFetch: true});
- });
+ return this.fetchUser({forceFetch: true});
+ }.bind(this));
},
logout: function () {
@@ -183,23 +180,21 @@ function (app, FauxtonAPI, CouchdbSession) {
});
},
- changePassword: function (password, password_confirm) {
- var error_promise = this.validatePasswords(password, password_confirm, this.messages.passwordsNotMatch);
+ changePassword: function (password, confirmedPassword) {
+ var errorMessage = 'Passwords do not match.';
+ var errorPromise = this.validatePasswords(password, confirmedPassword, errorMessage);
- if (error_promise) { return error_promise; }
-
- var that = this,
- info = this.get('info'),
- userCtx = this.get('userCtx');
+ if (errorPromise) { return errorPromise; }
+ var userName = this.get('userCtx').name;
var admin = new Admin({
- name: userCtx.name,
+ name: userName,
value: password
});
return admin.save().then(function () {
- return that.login(userCtx.name, password);
- });
+ return this.login(userName, password);
+ }.bind(this));
}
});
[2/3] fauxton commit: updated refs/heads/master to 5de1fe6
Posted by ro...@apache.org.
Revert "Detect if we run on a backdoor port"
This reverts commit 9ab1292d4e926ecba7c15291a04feb0342b40b21.
PR: #480
PR-URL: https://github.com/apache/couchdb-fauxton/pull/480
Reviewed-By: garren smith <ga...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/919a7f8e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/919a7f8e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/919a7f8e
Branch: refs/heads/master
Commit: 919a7f8e98c354f3646f12ce16d58e144a98635a
Parents: c754c6c
Author: Robert Kowalski <ro...@apache.org>
Authored: Tue Jun 23 13:44:49 2015 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Wed Jul 22 14:17:08 2015 +0200
----------------------------------------------------------------------
Gruntfile.js | 2 +-
app/addons/auth/base.js | 12 ++---
app/addons/auth/test/baseSpec.js | 57 ++++++---------------
app/app.js | 24 ---------
app/tests/appSpec.js | 96 -----------------------------------
5 files changed, 19 insertions(+), 172 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/919a7f8e/Gruntfile.js
----------------------------------------------------------------------
diff --git a/Gruntfile.js b/Gruntfile.js
index 570a40f..7955f1a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -373,7 +373,7 @@ module.exports = function (grunt) {
mochaSetup: {
default: {
files: {
- src: initHelper.watchFiles(['[Ss]pec.js'], ['./app/addons/**/*[Ss]pec.js', './app/addons/**/*[Ss]pec.react.js', './app/core/**/*[Ss]pec.js', './app/**/*[Ss]pec.js'])
+ src: initHelper.watchFiles(['[Ss]pec.js'], ['./app/addons/**/*[Ss]pec.js', './app/addons/**/*[Ss]pec.react.js', './app/core/**/*[Ss]pec.js'])
},
template: 'test/test.config.underscore',
config: './app/config.js'
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/919a7f8e/app/addons/auth/base.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/base.js b/app/addons/auth/base.js
index 4d0bb0c..8f4b1b3 100644
--- a/app/addons/auth/base.js
+++ b/app/addons/auth/base.js
@@ -13,13 +13,11 @@
define([
"app",
"api",
- 'addons/auth/routes'
+ "addons/auth/routes"
],
function (app, FauxtonAPI, Auth) {
- var isRunningOnBackdoorPort = null;
-
Auth.session = new Auth.Session();
FauxtonAPI.setSession(Auth.session);
app.session = Auth.session;
@@ -39,7 +37,6 @@ function (app, FauxtonAPI, Auth) {
var link = {};
if (session.isAdminParty()) {
-
link = {
id: "auth",
title: "Admin Party!",
@@ -78,11 +75,8 @@ function (app, FauxtonAPI, Auth) {
});
- FauxtonAPI.isRunningOnBackdoorPort().then(function (res) {
- isRunningOnBackdoorPort = res.runsOnBackportPort;
- Auth.session.fetchUser().then(function () {
- Auth.session.trigger('change');
- });
+ Auth.session.fetchUser().then(function () {
+ Auth.session.trigger('change');
});
var auth = function (session, roles) {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/919a7f8e/app/addons/auth/test/baseSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/test/baseSpec.js b/app/addons/auth/test/baseSpec.js
index d22f710..cc5e83f 100644
--- a/app/addons/auth/test/baseSpec.js
+++ b/app/addons/auth/test/baseSpec.js
@@ -21,25 +21,12 @@ define([
describe("failed login", function () {
- after(function () {
- FauxtonAPI.session.off('change');
- testUtils.restore(FauxtonAPI.session.isAdminParty);
- testUtils.restore(FauxtonAPI.isRunningOnBackdoorPort);
- testUtils.restore(FauxtonAPI.navigate);
- });
-
it("redirects with replace: true set", function () {
var navigateSpy = sinon.spy(FauxtonAPI, 'navigate');
-
- var stub = sinon.stub(FauxtonAPI.session, 'isAdminParty').returns(true);
- var deferred = FauxtonAPI.Deferred();
- sinon.stub(FauxtonAPI, 'isRunningOnBackdoorPort').returns(deferred);
+ FauxtonAPI.auth = new Auth();
+ FauxtonAPI.session.isLoggedIn = function () { return false; };
Base.initialize();
-
- deferred.resolve({runsOnBackportPort: false});
-
FauxtonAPI.auth.authDeniedCb();
-
assert.ok(navigateSpy.withArgs('/login?urlback=', {replace: true}).calledOnce);
});
});
@@ -48,28 +35,20 @@ define([
describe('auth session change', function () {
afterEach(function () {
- testUtils.restore(FauxtonAPI.updateHeaderLink);
- testUtils.restore(FauxtonAPI.session.isAdminParty);
- testUtils.restore(FauxtonAPI.isRunningOnBackdoorPort);
- testUtils.restore(FauxtonAPI.session.isLoggedIn);
- testUtils.restore(FauxtonAPI.session.user);
- FauxtonAPI.session.off('change');
+ FauxtonAPI.updateHeaderLink.restore && FauxtonAPI.updateHeaderLink.restore();
+ FauxtonAPI.session.isAdminParty.restore && FauxtonAPI.session.isAdminParty.restore();
});
it('for admin party changes title to admin party', function () {
var spy = sinon.spy(FauxtonAPI, 'updateHeaderLink');
var stub = sinon.stub(FauxtonAPI.session, 'isAdminParty').returns(true);
- var deferred = FauxtonAPI.Deferred();
- sinon.stub(FauxtonAPI, 'isRunningOnBackdoorPort').returns(deferred);
- Base.initialize();
- deferred.resolve({runsOnBackportPort: true});
-
FauxtonAPI.session.trigger('change');
assert.ok(spy.calledOnce);
var args = spy.getCall(0).args[0];
assert.ok(args.title.match(/Admin Party/));
+ FauxtonAPI.session.isAdminParty.restore();
});
it('for login changes title to login', function () {
@@ -77,53 +56,47 @@ define([
var stub = sinon.stub(FauxtonAPI.session, 'isAdminParty').returns(false);
sinon.stub(FauxtonAPI.session, 'user').returns({name: 'test-user'});
sinon.stub(FauxtonAPI.session, 'isLoggedIn').returns(true);
- var deferred = FauxtonAPI.Deferred();
- sinon.stub(FauxtonAPI, 'isRunningOnBackdoorPort').returns(deferred);
- Base.initialize();
- deferred.resolve({runsOnBackportPort: true});
-
FauxtonAPI.session.trigger('change');
assert.ok(spy.calledOnce);
var args = spy.getCall(0).args[0];
assert.equal(args.title, 'test-user');
-
+ FauxtonAPI.session.isLoggedIn.restore();
+ FauxtonAPI.session.user.restore();
+ FauxtonAPI.session.isAdminParty.restore();
});
it('for login adds logout link', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addHeaderLink');
var stub = sinon.stub(FauxtonAPI.session, 'isAdminParty').returns(false);
sinon.stub(FauxtonAPI.session, 'user').returns({name: 'test-user'});
sinon.stub(FauxtonAPI.session, 'isLoggedIn').returns(true);
- var deferred = FauxtonAPI.Deferred();
- sinon.stub(FauxtonAPI, 'isRunningOnBackdoorPort').returns(deferred);
- Base.initialize();
- deferred.resolve({runsOnBackportPort: false});
- var spy = sinon.spy(FauxtonAPI, 'addHeaderLink');
FauxtonAPI.session.trigger('change');
assert.ok(spy.calledOnce);
var args = spy.getCall(0).args[0];
assert.equal(args.title, 'Logout');
+ FauxtonAPI.session.isLoggedIn.restore();
+ FauxtonAPI.session.user.restore();
+ FauxtonAPI.session.isAdminParty.restore();
});
it('for logout, removes logout link', function () {
var spy = sinon.spy(FauxtonAPI, 'removeHeaderLink');
var stub = sinon.stub(FauxtonAPI.session, 'isAdminParty').returns(false);
sinon.stub(FauxtonAPI.session, 'isLoggedIn').returns(false);
- var deferred = FauxtonAPI.Deferred();
- sinon.stub(FauxtonAPI, 'isRunningOnBackdoorPort').returns(deferred);
- Base.initialize();
- deferred.resolve({runsOnBackportPort: true});
-
FauxtonAPI.session.trigger('change');
assert.ok(spy.calledOnce);
var args = spy.getCall(0).args[0];
assert.equal(args.id, 'logout');
+ FauxtonAPI.session.isLoggedIn.restore();
+ FauxtonAPI.session.isAdminParty.restore();
});
+
});
});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/919a7f8e/app/app.js
----------------------------------------------------------------------
diff --git a/app/app.js b/app/app.js
index a75949d..6483e5a 100644
--- a/app/app.js
+++ b/app/app.js
@@ -126,31 +126,7 @@ function (app, $, _, Backbone, Bootstrap, Helpers, Utils, FauxtonAPI, Couchdb) {
type: 'REMOVE_NAVBAR_LINK',
link: link
});
- },
-
- isRunningOnBackdoorPort: function () {
- if (this._backdoorDeferred) {
- return this._backdoorDeferred;
- }
-
- this._backdoorDeferred = FauxtonAPI.Deferred();
-
- $.ajax({
- type: 'GET',
- url: app.host + '/_cluster_setup'
- })
- .then(function () {
- this._backdoorDeferred.resolve({runsOnBackportPort: false});
- }.bind(this))
- .fail(function (res) {
- this._backdoorDeferred.resolve({
- runsOnBackportPort: res.status === 400
- });
- }.bind(this));
-
- return this._backdoorDeferred;
}
-
});
return app;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/919a7f8e/app/tests/appSpec.js
----------------------------------------------------------------------
diff --git a/app/tests/appSpec.js b/app/tests/appSpec.js
deleted file mode 100644
index bf38f87..0000000
--- a/app/tests/appSpec.js
+++ /dev/null
@@ -1,96 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-define([
- 'app',
- 'api',
- 'testUtils',
-], function (app, FauxtonAPI, testUtils) {
- var assert = testUtils.assert;
-
- describe('app', function () {
-
- describe('isRunningOnBackdoorPort', function () {
- var server, appHost;
- beforeEach(function () {
- appHost = app.host;
- app.host = 'http://example.com';
- server = sinon.fakeServer.create();
- });
- afterEach(function () {
- app.host = appHost;
- testUtils.restore(server);
- testUtils.restore($.ajax);
- FauxtonAPI._backdoorDeferred = null;
- });
-
- it('caches content', function (done) {
- server.respondWith('GET', 'http://example.com/_cluster_setup',
- [200, { "Content-Type": "application/json" },
- '[{ "id": 12, "comment": "Hey there" }]']);
-
- var spyAjax = sinon.spy($, 'ajax');
- var promise = FauxtonAPI.isRunningOnBackdoorPort();
- server.respond();
-
- promise.then(function (res) {
- var promise2 = FauxtonAPI.isRunningOnBackdoorPort();
- promise2.then(function (res) {
-
- assert.ok(spyAjax.calledOnce);
- done();
- });
- });
- });
-
- it('returns false on a 401', function (done) {
- server.respondWith('GET', 'http://example.com/_cluster_setup',
- [401, { "Content-Type": "application/json" }, '']);
-
- var promise = FauxtonAPI.isRunningOnBackdoorPort();
- server.respond();
-
- promise.then(function (res) {
- assert.deepEqual({runsOnBackportPort: false}, res);
- done();
- });
- });
-
- it('returns false on a 200', function (done) {
- server.respondWith('GET', 'http://example.com/_cluster_setup',
- [200, { "Content-Type": "application/json" }, '']);
-
- var promise = FauxtonAPI.isRunningOnBackdoorPort();
- server.respond();
-
- promise.then(function (res) {
- assert.deepEqual({runsOnBackportPort: false}, res);
- done();
- });
- });
-
-
- it('returns true on a 400', function (done) {
- server.respondWith('GET', 'http://example.com/_cluster_setup',
- [400, {'Content-Type': 'application/json' },
- '[{ "id": 12, "comment": "Hey there" }]']);
-
- var promise = FauxtonAPI.isRunningOnBackdoorPort();
- server.respond();
-
- promise.then(function (res) {
- assert.deepEqual({runsOnBackportPort: true}, res);
- done();
- });
- });
- });
- });
-});
[3/3] fauxton commit: updated refs/heads/master to 5de1fe6
Posted by ro...@apache.org.
Just enable config for a "cluster-of-one"
Warn users if they run multi node setups.
Testing instructions for single node setups, given you usually run
a cluster of three nodes:
1. stop couchdb, connect fauxton to a single node, change
```
exports.couch = 'http://localhost:15984/';
```
in `tasks/helper.js`
2. get rid of `dev/lib/` in the couchdb folder, so the cluster does
not know about the other nodes any more, caution: you will lose
your current dbs.
3. boot couchdb with one node:
```
./dev/run --with-admin-party-please -n1
```
4. PROFIT!
COUCHDB-2601 COUCHDB-2599 COUCHDB-2390
PR: #480
PR-URL: https://github.com/apache/couchdb-fauxton/pull/480
Reviewed-By: garren smith <ga...@gmail.com>
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/5de1fe66
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/5de1fe66
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/5de1fe66
Branch: refs/heads/master
Commit: 5de1fe6682fc5a9dee44022498357febd73c3600
Parents: 3896d20
Author: Robert Kowalski <ro...@apache.org>
Authored: Mon Jul 13 16:31:18 2015 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Wed Jul 22 14:17:34 2015 +0200
----------------------------------------------------------------------
.gitignore | 1 +
app/addons/auth/actions.js | 13 ++--
app/addons/auth/resources.js | 20 +++--
app/addons/auth/routes.js | 40 +++++++---
.../auth/test/auth.componentsSpec.react.jsx | 9 ++-
app/addons/cluster/base.js | 25 ++++++
app/addons/cluster/cluster.actions.js | 51 +++++++++++++
app/addons/cluster/cluster.actiontypes.js | 17 +++++
app/addons/cluster/cluster.react.jsx | 80 ++++++++++++++++++++
app/addons/cluster/cluster.stores.js | 60 +++++++++++++++
app/addons/cluster/resources.js | 42 ++++++++++
app/addons/cluster/routes.js | 52 +++++++++++++
app/addons/cluster/tests/clusterSpec.react.jsx | 57 ++++++++++++++
app/addons/cluster/tests/resourcesSpec.js | 60 +++++++++++++++
app/addons/config/assets/less/config.less | 18 +++++
app/addons/config/resources.js | 23 +++++-
app/addons/config/routes.js | 77 +++++++++++--------
app/addons/config/tests/configSpec.js | 6 +-
app/addons/config/views.js | 5 +-
app/addons/cors/actions.js | 45 ++++++-----
app/addons/cors/components.react.jsx | 8 +-
app/addons/cors/resources.js | 19 ++++-
app/addons/cors/stores.js | 5 ++
app/addons/cors/tests/componentsSpec.react.jsx | 1 +
app/addons/cors/tests/resourcesSpec.js | 2 +-
app/addons/documents/assets/less/sidenav.less | 3 +-
app/addons/fauxton/base.js | 1 +
.../tests/nightwatch/highlightsidebar.js | 6 +-
settings.json.default | 1 +
29 files changed, 654 insertions(+), 93 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b3517fa..a5db49e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ app/load_addons.js
app/addons/*
!app/addons/activetasks
!app/addons/config
+!app/addons/cluster
!app/addons/components
!app/addons/replication
!app/addons/auth
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/auth/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/actions.js b/app/addons/auth/actions.js
index ab3f50e..e7b468b 100644
--- a/app/addons/auth/actions.js
+++ b/app/addons/auth/actions.js
@@ -11,10 +11,12 @@
// the License.
define([
'api',
- 'addons/auth/actiontypes'
+ 'addons/auth/actiontypes',
+ 'addons/cluster/cluster.stores'
],
-function (FauxtonAPI, ActionTypes) {
+function (FauxtonAPI, ActionTypes, ClusterStore) {
+ var nodesStore = ClusterStore.nodesStore;
var errorHandler = function (xhr, type, msg) {
msg = xhr;
@@ -45,7 +47,8 @@ function (FauxtonAPI, ActionTypes) {
},
changePassword: function (password, passwordConfirm) {
- var promise = FauxtonAPI.session.changePassword(password, passwordConfirm);
+ var nodes = nodesStore.getNodes();
+ var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
promise.done(function () {
FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.changePassword });
@@ -70,7 +73,8 @@ function (FauxtonAPI, ActionTypes) {
},
createAdmin: function (username, password, loginAfter) {
- var promise = FauxtonAPI.session.createAdmin(username, password, loginAfter);
+ var nodes = nodesStore.getNodes();
+ var promise = FauxtonAPI.session.createAdmin(username, password, loginAfter, nodes[0].node);
promise.then(function () {
FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.adminCreated });
@@ -84,7 +88,6 @@ function (FauxtonAPI, ActionTypes) {
promise.fail(function (xhr, type, msg) {
msg = xhr;
if (arguments.length === 3) {
- console.log("here...", xhr.responseJSON);
msg = xhr.responseJSON.reason;
}
errorHandler(FauxtonAPI.session.messages.adminCreationFailedPrefix + ' ' + msg);
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/auth/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/resources.js b/app/addons/auth/resources.js
index 175a314..438cdb4 100644
--- a/app/addons/auth/resources.js
+++ b/app/addons/auth/resources.js
@@ -22,9 +22,19 @@ function (app, FauxtonAPI, CouchdbSession) {
var Admin = Backbone.Model.extend({
+
+ initialize: function (props, options) {
+ this.node = options.node;
+ },
+
url: function () {
- return app.host + '/_config/admins/' + this.get("name");
+ if (!this.node) {
+ throw new Error('no node set');
+ }
+
+ return app.host + '/_node/' + this.node + '/_config/admins/' + this.get('name');
},
+
isNew: function () { return false; },
sync: function (method, model, options) {
@@ -130,7 +140,7 @@ function (app, FauxtonAPI, CouchdbSession) {
}
},
- createAdmin: function (username, password, login) {
+ createAdmin: function (username, password, login, node) {
var errorPromise = this.validateUser(username, password, this.messages.missingCredentials);
if (errorPromise) { return errorPromise; }
@@ -138,7 +148,7 @@ function (app, FauxtonAPI, CouchdbSession) {
var admin = new Admin({
name: username,
value: password
- });
+ }, {node: node});
return admin.save().then(function () {
if (login) {
@@ -180,7 +190,7 @@ function (app, FauxtonAPI, CouchdbSession) {
});
},
- changePassword: function (password, confirmedPassword) {
+ changePassword: function (password, confirmedPassword, node) {
var errorMessage = 'Passwords do not match.';
var errorPromise = this.validatePasswords(password, confirmedPassword, errorMessage);
@@ -190,7 +200,7 @@ function (app, FauxtonAPI, CouchdbSession) {
var admin = new Admin({
name: userName,
value: password
- });
+ }, {node: node});
return admin.save().then(function () {
return this.login(userName, password);
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/auth/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/auth/routes.js b/app/addons/auth/routes.js
index 2632773..e7945d5 100644
--- a/app/addons/auth/routes.js
+++ b/app/addons/auth/routes.js
@@ -15,10 +15,11 @@ define([
"api",
'addons/auth/resources',
'addons/auth/actions',
- 'addons/auth/components.react'
+ 'addons/auth/components.react',
+ 'addons/cluster/cluster.actions'
],
-function (app, FauxtonAPI, Auth, AuthActions, Components) {
+function (app, FauxtonAPI, Auth, AuthActions, Components, ClusterActions) {
var AuthRouteObject = FauxtonAPI.RouteObject.extend({
layout: 'one_pane',
@@ -27,7 +28,12 @@ function (app, FauxtonAPI, Auth, AuthActions, Components) {
'login?*extra': 'login',
'login': 'login',
'logout': 'logout',
- 'createAdmin': 'createAdmin'
+ 'createAdmin': 'checkNodes',
+ 'createAdmin/:node': 'createAdminForNode',
+ },
+
+ checkNodes: function () {
+ ClusterActions.navigateToNodeBasedOnNodeCount('/createAdmin/');
},
login: function () {
@@ -43,13 +49,9 @@ function (app, FauxtonAPI, Auth, AuthActions, Components) {
});
},
- changePassword: function () {
- this.crumbs = [{name: 'Change Password', link: "#" }];
- this.setComponent('#dashboard-content', Components.ChangePasswordForm);
- },
-
- createAdmin: function () {
- this.crumbs = [{name: 'Create Admin', link:"#"}];
+ createAdminForNode: function () {
+ ClusterActions.fetchNodes();
+ this.crumbs = [{name: 'Create Admin', link: '#'}];
this.setComponent('#dashboard-content', Components.CreateAdminForm, { loginAfter: true });
}
});
@@ -60,15 +62,31 @@ function (app, FauxtonAPI, Auth, AuthActions, Components) {
routes: {
'changePassword': {
+ route: 'checkNodesForPasswordChange',
+ roles: ['fx_loggedIn']
+ },
+ 'changePassword/:node': {
route: 'changePassword',
roles: ['fx_loggedIn']
},
'addAdmin': {
+ route: 'checkNodesForAddAdmin',
+ roles: ['_admin']
+ },
+ 'addAdmin/:node': {
route: 'addAdmin',
roles: ['_admin']
}
},
+ checkNodesForPasswordChange: function () {
+ ClusterActions.navigateToNodeBasedOnNodeCount('/changePassword/');
+ },
+
+ checkNodesForAddAdmin: function () {
+ ClusterActions.navigateToNodeBasedOnNodeCount('/addAdmin/');
+ },
+
selectedHeader: function () {
return FauxtonAPI.session.user().name;
},
@@ -78,11 +96,13 @@ function (app, FauxtonAPI, Auth, AuthActions, Components) {
},
changePassword: function () {
+ ClusterActions.fetchNodes();
AuthActions.selectPage('changePassword');
this.setComponent('#dashboard-content', Components.ChangePasswordForm);
},
addAdmin: function () {
+ ClusterActions.fetchNodes();
AuthActions.selectPage('addAdmin');
this.setComponent('#dashboard-content', Components.CreateAdminForm, { loginAfter: false });
},
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/auth/test/auth.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/auth/test/auth.componentsSpec.react.jsx b/app/addons/auth/test/auth.componentsSpec.react.jsx
index cdafb83..937ea78 100644
--- a/app/addons/auth/test/auth.componentsSpec.react.jsx
+++ b/app/addons/auth/test/auth.componentsSpec.react.jsx
@@ -16,8 +16,8 @@ define([
'addons/auth/components.react',
'addons/auth/stores',
'addons/auth/actions'
-], function (FauxtonAPI, React, testUtils, Components, Stores, Actions) {
- var assert = testUtils.assert;
+], function (FauxtonAPI, React, utils, Components, Stores, Actions) {
+ var assert = utils.assert;
var TestUtils = React.addons.TestUtils;
var createAdminSidebarStore = Stores.createAdminSidebarStore;
@@ -50,6 +50,7 @@ define([
beforeEach(function () {
container = document.createElement('div');
changePasswordForm = TestUtils.renderIntoDocument(<Components.ChangePasswordForm />, container);
+ utils.restore(Actions.changePassword);
});
afterEach(function () {
@@ -69,9 +70,9 @@ define([
});
it('should call action to submit form', function () {
- var spy = sinon.spy(Actions, 'changePassword');
+ var stub = sinon.stub(Actions, 'changePassword', function () {});
TestUtils.Simulate.submit($(changePasswordForm.getDOMNode()).find('#change-password')[0]);
- assert.ok(spy.calledOnce);
+ assert.ok(stub.calledOnce);
});
});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/base.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/base.js b/app/addons/cluster/base.js
new file mode 100644
index 0000000..7e2892b
--- /dev/null
+++ b/app/addons/cluster/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/cluster/routes'
+],
+
+function (app, FauxtonAPI, Cluster) {
+
+ Cluster.initialize = function () {};
+
+ return Cluster;
+});
+
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/cluster.actions.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/cluster.actions.js b/app/addons/cluster/cluster.actions.js
new file mode 100644
index 0000000..1da30f9
--- /dev/null
+++ b/app/addons/cluster/cluster.actions.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/cluster/resources',
+ 'addons/cluster/cluster.actiontypes'
+],
+function (FauxtonAPI, ClusterResources, ActionTypes) {
+ return {
+ fetchNodes: function () {
+ var memberships = new ClusterResources.ClusterNodes();
+
+ memberships.fetch().then(function () {
+ this.updateNodes({
+ nodes: memberships.get('nodes_mapped')
+ });
+ }.bind(this));
+ },
+
+ updateNodes: function (options) {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.CLUSTER_FETCH_NODES,
+ options: options
+ });
+ },
+
+ navigateToNodeBasedOnNodeCount: function (successtarget) {
+ var memberships = new ClusterResources.ClusterNodes();
+
+ memberships.fetch().then(function () {
+ var nodes = memberships.get('all_nodes');
+
+ if (nodes.length === 1) {
+ return FauxtonAPI.navigate(successtarget + nodes[0]);
+ }
+ return FauxtonAPI.navigate('/cluster/disabled', {trigger: true});
+ });
+ }
+
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/cluster.actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/cluster.actiontypes.js b/app/addons/cluster/cluster.actiontypes.js
new file mode 100644
index 0000000..8fd521e
--- /dev/null
+++ b/app/addons/cluster/cluster.actiontypes.js
@@ -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.
+
+define([], function () {
+ return {
+ CLUSTER_FETCH_NODES: 'CLUSTER_FETCH_NODES'
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/cluster.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cluster/cluster.react.jsx b/app/addons/cluster/cluster.react.jsx
new file mode 100644
index 0000000..a53f695
--- /dev/null
+++ b/app/addons/cluster/cluster.react.jsx
@@ -0,0 +1,80 @@
+// 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',
+ 'react',
+ 'addons/cluster/cluster.stores'
+
+],
+
+function (app, FauxtonAPI, React, ClusterStore) {
+
+ var nodesStore = ClusterStore.nodesStore;
+
+
+ var DisabledConfigController = React.createClass({
+
+ getStoreState: function () {
+ return {
+ nodes: nodesStore.getNodes()
+ };
+ },
+
+ getInitialState: function () {
+ return this.getStoreState();
+ },
+
+ componentDidMount: function () {
+ nodesStore.on('change', this.onChange, this);
+ },
+
+ componentWillUnmount: function () {
+ nodesStore.off('change', this.onChange);
+ },
+
+ onChange: function () {
+ this.setState(this.getStoreState());
+ },
+
+ render: function () {
+ return (
+ <div className="config-warning-cluster-wrapper">
+ <div className="config-warning-cluster-container">
+ <div>
+ <div className="config-warning-icon-container pull-left">
+ <i className="fonticon-attention-circled"></i>
+ </div>
+ It seems that you are running a cluster with {this.state.nodes.length} nodes. For CouchDB 2.0
+ we recommend using a configuration management tools like Chef, Ansible,
+ Puppet or Salt (in no particular order) to configure your nodes in a cluster.
+ <br/>
+ <br/>
+ <div className="config-warning-other-text">
+ We highly recommend against configuring nodes in your cluster using the HTTP API and
+ suggest using a configuration management tool for all configurations.
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+ });
+
+ var Views = {
+ DisabledConfigController: DisabledConfigController
+ };
+
+ return Views;
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/cluster.stores.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/cluster.stores.js b/app/addons/cluster/cluster.stores.js
new file mode 100644
index 0000000..14388b3
--- /dev/null
+++ b/app/addons/cluster/cluster.stores.js
@@ -0,0 +1,60 @@
+// 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/cluster/cluster.actiontypes'
+], function (FauxtonAPI, ActionTypes) {
+
+ var NodesStore = FauxtonAPI.Store.extend({
+
+ initialize: function () {
+ this.reset();
+ },
+
+ reset: function () {
+ this._nodes = [];
+ },
+
+ setNodes: function (options) {
+ this._nodes = options.nodes;
+ },
+
+ getNodes: function () {
+ return this._nodes;
+ },
+
+ dispatch: function (action) {
+
+ switch (action.type) {
+ case ActionTypes.CLUSTER_FETCH_NODES:
+ this.setNodes(action.options);
+ break;
+
+ default:
+ return;
+ }
+
+ this.triggerChange();
+ }
+
+ });
+
+
+ var nodesStore = new NodesStore();
+
+ nodesStore.dispatchToken = FauxtonAPI.dispatcher.register(nodesStore.dispatch.bind(nodesStore));
+
+ return {
+ nodesStore: nodesStore
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/resources.js b/app/addons/cluster/resources.js
new file mode 100644
index 0000000..de9b8df
--- /dev/null
+++ b/app/addons/cluster/resources.js
@@ -0,0 +1,42 @@
+// 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 Cluster = FauxtonAPI.addon();
+
+ Cluster.ClusterNodes = Backbone.Model.extend({
+ url: function () {
+ return app.host + '/_membership';
+ },
+
+ parse: function (res) {
+ var list;
+
+ list = res.all_nodes.reduce(function (acc, node) {
+ var isInCluster = res.cluster_nodes.indexOf(node) !== -1;
+
+ acc.push({node: node, isInCluster: isInCluster});
+ return acc;
+ }, []);
+
+ res.nodes_mapped = list;
+ return res;
+ }
+ });
+
+ return Cluster;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/routes.js b/app/addons/cluster/routes.js
new file mode 100644
index 0000000..0b36832
--- /dev/null
+++ b/app/addons/cluster/routes.js
@@ -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.
+
+define([
+ 'app',
+ 'api',
+ 'addons/cluster/resources',
+ 'addons/cluster/cluster.react',
+ 'addons/cluster/cluster.actions',
+],
+
+function (app, FauxtonAPI, Cluster, ClusterComponents, ClusterActions) {
+
+
+ var ConfigDisabledRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: 'one_pane',
+
+ routes: {
+ 'cluster/disabled': 'showDisabledFeatureScreen',
+ },
+
+ crumbs: [
+ { name: 'Config disabled', link: '_config' }
+ ],
+
+ apiUrl: function () {
+ return [this.memberships.url(), this.memberships.documentation];
+ },
+
+ initialize: function () {
+ this.memberships = new Cluster.ClusterNodes();
+ },
+
+ showDisabledFeatureScreen: function () {
+ ClusterActions.fetchNodes();
+ this.warning = this.setComponent('#dashboard-content', ClusterComponents.DisabledConfigController);
+ }
+ });
+
+ Cluster.RouteObjects = [ConfigDisabledRouteObject];
+
+ return Cluster;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/tests/clusterSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cluster/tests/clusterSpec.react.jsx b/app/addons/cluster/tests/clusterSpec.react.jsx
new file mode 100644
index 0000000..9a6c3b5
--- /dev/null
+++ b/app/addons/cluster/tests/clusterSpec.react.jsx
@@ -0,0 +1,57 @@
+// 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/cluster/cluster.react',
+ 'addons/cluster/cluster.actions',
+ 'addons/cluster/cluster.stores',
+
+ 'testUtils',
+ 'react'
+], function (FauxtonAPI, ClusterComponent, ClusterActions, ClusterStores, utils, React) {
+
+ var assert = utils.assert;
+ var TestUtils = React.addons.TestUtils;
+
+ describe('Cluster Controller', function () {
+ var container, controller;
+
+ beforeEach(function () {
+
+ var nodeList = [
+ {'node': 'node1@127.0.0.1', 'isInCluster': true},
+ {'node': 'node2@127.0.0.1', 'isInCluster': true},
+ {'node': 'node3@127.0.0.1', 'isInCluster': false},
+ {'node': 'node3@127.0.0.1', 'isInCluster': false},
+ {'node': 'node3@127.0.0.1', 'isInCluster': false},
+ {'node': 'node3@127.0.0.1', 'isInCluster': false}
+ ];
+
+ ClusterActions.updateNodes({nodes: nodeList});
+
+ container = document.createElement('div');
+ controller = TestUtils.renderIntoDocument(
+ <ClusterComponent.DisabledConfigController />,
+ container
+ );
+ });
+
+ afterEach(function () {
+ ClusterStores.nodesStore.reset();
+ React.unmountComponentAtNode(container);
+ });
+
+ it('renders the amount of nodes', function () {
+ assert.ok(/6 nodes/.test($(controller.getDOMNode()).text()), 'finds 6 nodes');
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cluster/tests/resourcesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/cluster/tests/resourcesSpec.js b/app/addons/cluster/tests/resourcesSpec.js
new file mode 100644
index 0000000..03a30c8
--- /dev/null
+++ b/app/addons/cluster/tests/resourcesSpec.js
@@ -0,0 +1,60 @@
+// 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([
+ 'testUtils',
+ 'api',
+ 'addons/cluster/resources',
+], function (testUtils, FauxtonAPI, Resources) {
+ var assert = testUtils.assert;
+
+
+ describe('Membership Model', function () {
+ var data = {
+ 'all_nodes': ['node1@127.0.0.1', 'node2@127.0.0.1', 'node3@127.0.0.1', 'notpartofclusternode'],
+ 'cluster_nodes': ['node1@127.0.0.1', 'node2@127.0.0.1', 'node3@127.0.0.1']
+ };
+
+ it('reorders the data', function () {
+ var memberships = new Resources.ClusterNodes();
+ var res = memberships.parse(data);
+
+ assert.deepEqual([
+ {node: 'node1@127.0.0.1', isInCluster: true},
+ {node: 'node2@127.0.0.1', isInCluster: true},
+ {node: 'node3@127.0.0.1', isInCluster: true},
+ {node: 'notpartofclusternode', isInCluster: false}
+ ],
+ res.nodes_mapped);
+ });
+
+ it('keeps the exiting data', function () {
+ var memberships = new Resources.ClusterNodes();
+ var res = memberships.parse(data);
+
+ assert.deepEqual([
+ 'node1@127.0.0.1',
+ 'node2@127.0.0.1',
+ 'node3@127.0.0.1',
+ 'notpartofclusternode'
+ ],
+ res.all_nodes);
+
+ assert.deepEqual([
+ 'node1@127.0.0.1',
+ 'node2@127.0.0.1',
+ 'node3@127.0.0.1'
+ ],
+ res.cluster_nodes);
+ });
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/config/assets/less/config.less
----------------------------------------------------------------------
diff --git a/app/addons/config/assets/less/config.less b/app/addons/config/assets/less/config.less
index d7d6db4..6363d80 100644
--- a/app/addons/config/assets/less/config.less
+++ b/app/addons/config/assets/less/config.less
@@ -111,3 +111,21 @@ table.config {
}
}
}
+
+.config-warning-cluster-wrapper {
+ .config-warning-cluster-container {
+ margin-left: -50px;
+ }
+ margin: 40px auto;
+ width: 70%;
+ .fonticon-attention-circled {
+ font-size: 40px;
+ }
+ .config-warning-icon-container {
+ width: 50px;
+ margin-top: -5px;
+ }
+ .config-warning-other-text {
+ margin-left: 50px;
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/config/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/config/resources.js b/app/addons/config/resources.js
index 468860c..5c3ed3f 100644
--- a/app/addons/config/resources.js
+++ b/app/addons/config/resources.js
@@ -21,12 +21,20 @@ function (app, FauxtonAPI) {
var Config = FauxtonAPI.addon();
- Config.Model = Backbone.Model.extend({});
Config.OptionModel = Backbone.Model.extend({
documentation: FauxtonAPI.constants.DOC_URLS.CONFIG,
+ initialize: function (_, options) {
+ this.node = options.node;
+ },
+
url: function () {
- return app.host + '/_config/' + this.get('section') + '/' + encodeURIComponent(this.get('name'));
+ if (!this.node) {
+ throw new Error('no node set');
+ }
+
+ return app.host + '/_node/' + this.node + '/_config/' +
+ this.get('section') + '/' + encodeURIComponent(this.get('name'));
},
isNew: function () { return false; },
@@ -49,11 +57,16 @@ function (app, FauxtonAPI) {
}
});
+ Config.Model = Backbone.Model.extend({});
Config.Collection = Backbone.Collection.extend({
model: Config.Model,
documentation: FauxtonAPI.constants.DOC_URLS.CONFIG,
+ initialize: function (_, options) {
+ this.node = options.node;
+ },
+
comparator: function (OptionModel) {
if (OptionModel.get('section')) {
return OptionModel.get('section');
@@ -61,7 +74,11 @@ function (app, FauxtonAPI) {
},
url: function () {
- return window.location.origin + '/_config';
+ if (!this.node) {
+ throw new Error('no node set');
+ }
+
+ return app.host + '/_node/' + this.node + '/_config';
},
findEntryInSection: function (sectionName, entry) {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/config/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/config/routes.js b/app/addons/config/routes.js
index 77d46da..38fd32c 100644
--- a/app/addons/config/routes.js
+++ b/app/addons/config/routes.js
@@ -16,33 +16,33 @@ define([
'addons/config/resources',
'addons/config/views',
'addons/cors/components.react',
- 'addons/cors/actions'
+ 'addons/cors/actions',
+ 'addons/cluster/cluster.actions'
],
-function (app, FauxtonAPI, Config, Views, CORSComponents, CORSActions) {
+function (app, FauxtonAPI, Config, Views, CORSComponents, CORSActions, ClusterActions) {
- var ConfigRouteObject = FauxtonAPI.RouteObject.extend({
- layout: 'with_tabs_sidebar_scroll',
- initialize: function () {
- this.configs = new Config.Collection();
+ var ConfigDisabledRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: 'one_pane',
- this.sidebar = this.setView('#sidebar-content', new Views.Tabs({
- sidebarItems: [
- {
- title: 'Main config',
- typeSelect: 'main',
- link: '_config'
- },
- {
- title: 'CORS',
- typeSelect: 'cors',
- link: '_config/cors'
- }
- ]
- }));
+ routes: {
+ '_config': 'checkNodes',
},
+ crumbs: [
+ { name: 'Config disabled', link: '_config' }
+ ],
+
+ checkNodes: function () {
+ ClusterActions.navigateToNodeBasedOnNodeCount('/_config/');
+ }
+ });
+
+
+ var ConfigPerNodeRouteObject = FauxtonAPI.RouteObject.extend({
+ layout: 'with_tabs_sidebar_scroll',
+
roles: ['_admin'],
selectedHeader: 'Config',
@@ -55,29 +55,46 @@ function (app, FauxtonAPI, Config, Views, CORSComponents, CORSActions) {
},
routes: {
- '_config': 'config',
- '_config/cors':'configCORS'
+ '_config/:node': 'configForNode',
+ '_config/:node/cors': 'configCorsForNode'
+ },
+
+ initialize: function (_a, _b, options) {
+ var node = options[0];
+
+ this.configs = new Config.Collection(null, {node: node});
+
+ this.sidebar = this.setView('#sidebar-content', new Views.Tabs({
+ sidebarItems: [
+ {
+ title: 'Main config',
+ typeSelect: 'main',
+ link: '_config/' + node
+ },
+ {
+ title: 'CORS',
+ typeSelect: 'cors',
+ link: '_config/' + node + '/cors'
+ }
+ ]
+ }));
},
- config: function () {
+ configForNode: function () {
this.newSection = this.setView('#right-header', new Views.ConfigHeader({ collection: this.configs }));
this.setView('#dashboard-content', new Views.Table({ collection: this.configs }));
this.sidebar.setSelectedTab('main');
},
- configCORS: function () {
+ configCorsForNode: function (node) {
this.removeView('#right-header');
this.newSection = this.setComponent('#dashboard-content', CORSComponents.CORSController);
- CORSActions.FetchAndEditCors();
+ CORSActions.fetchAndEditCors(node);
this.sidebar.setSelectedTab('cors');
- },
-
- establish: function () {
- return [this.configs.fetch()];
}
});
- Config.RouteObjects = [ConfigRouteObject];
+ Config.RouteObjects = [ConfigPerNodeRouteObject, ConfigDisabledRouteObject];
return Config;
});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/config/tests/configSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/config/tests/configSpec.js b/app/addons/config/tests/configSpec.js
index aefce92..cd5a03c 100644
--- a/app/addons/config/tests/configSpec.js
+++ b/app/addons/config/tests/configSpec.js
@@ -30,12 +30,12 @@ define([
options: [{
name: "testname"
}]
- });
+ }, {node: 'foo'});
optionModels.push(model);
});
- collection = new Resources.Collection(optionModels);
+ collection = new Resources.Collection(optionModels, {node: 'foo'}, "foo");
});
describe("Config: Add Option Tray", function () {
@@ -93,7 +93,7 @@ define([
optionModel = new Resources.OptionModel({
section: "foo",
name: "bar"
- });
+ }, {node: 'foo'});
tabMenu = new Views.TableRow({
model: optionModel,
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/config/views.js
----------------------------------------------------------------------
diff --git a/app/addons/config/views.js b/app/addons/config/views.js
index 35318e3..5f14942 100644
--- a/app/addons/config/views.js
+++ b/app/addons/config/views.js
@@ -128,7 +128,7 @@ function (app, FauxtonAPI, Config, Components) {
name: option.name,
value: option.value,
index: index
- })
+ }, {node: this.collection.node})
}));
}, this);
}, this);
@@ -204,11 +204,12 @@ function (app, FauxtonAPI, Config, Components) {
},
submitForm: function () {
+
var option = new Config.OptionModel({
section: this.$('input[name="section"]').val(),
name: this.$('input[name="name"]').val(),
value: this.$('input[name="value"]').val()
- });
+ }, {node: this.collection.node});
option.save();
var section = this.collection.find(function (section) {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/actions.js b/app/addons/cors/actions.js
index cce1518..1a35f78 100644
--- a/app/addons/cors/actions.js
+++ b/app/addons/cors/actions.js
@@ -15,14 +15,15 @@ define([
'addons/cors/resources'
], function (FauxtonAPI, ActionTypes, Resources) {
return {
- FetchAndEditCors: function () {
- var cors = new Resources.Config();
- var httpd = new Resources.Httpd();
+ fetchAndEditCors: function (node) {
+ var cors = new Resources.Config({node: node});
+ var httpd = new Resources.Httpd({node: node});
FauxtonAPI.when([cors.fetch(), httpd.fetch()]).then(function () {
this.editCors({
origins: cors.get('origins'),
- isEnabled: httpd.corsEnabled()
+ isEnabled: httpd.corsEnabled(),
+ node: node
});
}.bind(this));
},
@@ -68,6 +69,7 @@ define([
originalOrigin: originalOrigin
});
},
+
methodChange: function (httpMethod) {
FauxtonAPI.dispatch({
type: ActionTypes.CORS_METHOD_CHANGE,
@@ -75,51 +77,56 @@ define([
});
},
- saveEnableCorsToHttpd: function (enableCors) {
+ saveEnableCorsToHttpd: function (enableCors, node) {
var enableOption = new Resources.ConfigModel({
section: 'httpd',
attribute: 'enable_cors',
- value: enableCors.toString()
+ value: enableCors.toString(),
+ node: node
});
return enableOption.save();
},
- saveCorsOrigins: function (origins) {
+ saveCorsOrigins: function (origins, node) {
var allowOrigins = new Resources.ConfigModel({
section: 'cors',
attribute: 'origins',
- value: origins
+ value: origins,
+ node: node
});
return allowOrigins.save();
},
- saveCorsCredentials: function () {
+ saveCorsCredentials: function (node) {
var allowCredentials = new Resources.ConfigModel({
section: 'cors',
attribute: 'credentials',
- value: "true"
+ value: 'true',
+ node: node
});
return allowCredentials.save();
},
- saveCorsHeaders: function () {
+ saveCorsHeaders: function (node) {
var corsHeaders = new Resources.ConfigModel({
section: 'cors',
attribute: 'headers',
- value: 'accept, authorization, content-type, origin, referer'
+ value: 'accept, authorization, content-type, origin, referer',
+ node: node
});
return corsHeaders.save();
},
- saveCorsMethods: function () {
+ saveCorsMethods: function (node) {
var corsMethods = new Resources.ConfigModel({
section: 'cors',
attribute: 'methods',
- value: 'GET, PUT, POST, HEAD, DELETE'
+ value: 'GET, PUT, POST, HEAD, DELETE',
+ node: node
});
return corsMethods.save();
@@ -135,13 +142,13 @@ define([
saveCors: function (options) {
var promises = [];
- promises.push(this.saveEnableCorsToHttpd(options.enableCors));
+ promises.push(this.saveEnableCorsToHttpd(options.enableCors, options.node));
if (options.enableCors) {
- promises.push(this.saveCorsOrigins(this.sanitizeOrigins(options.origins)));
- promises.push(this.saveCorsCredentials());
- promises.push(this.saveCorsHeaders());
- promises.push(this.saveCorsMethods());
+ promises.push(this.saveCorsOrigins(this.sanitizeOrigins(options.origins), options.node));
+ promises.push(this.saveCorsCredentials(options.node));
+ promises.push(this.saveCorsHeaders(options.node));
+ promises.push(this.saveCorsMethods(options.node));
}
FauxtonAPI.when(promises).then(function () {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cors/components.react.jsx b/app/addons/cors/components.react.jsx
index 1bf330a..fb9f655 100644
--- a/app/addons/cors/components.react.jsx
+++ b/app/addons/cors/components.react.jsx
@@ -228,7 +228,8 @@ define([
origins: corsStore.getOrigins(),
isAllOrigins: corsStore.isAllOrigins(),
configChanged: corsStore.hasConfigChanged(),
- shouldSaveChange: corsStore.shouldSaveChange()
+ shouldSaveChange: corsStore.shouldSaveChange(),
+ node: corsStore.getNode()
};
},
@@ -270,10 +271,11 @@ define([
Actions.toggleEnableCors();
},
- save: function (event) {
+ save: function () {
Actions.saveCors({
enableCors: this.state.corsEnabled,
- origins: this.state.origins
+ origins: this.state.origins,
+ node: this.state.node
});
},
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/resources.js b/app/addons/cors/resources.js
index 3f42232..a22cfc8 100644
--- a/app/addons/cors/resources.js
+++ b/app/addons/cors/resources.js
@@ -21,7 +21,11 @@ function (app, FauxtonAPI) {
CORS.Config = FauxtonAPI.Model.extend({
url: function () {
- return app.host + '/_config/cors';
+ if (!this.get('node')) {
+ throw new Error('node not set');
+ }
+
+ return window.location.origin + '/_node/' + this.get('node') + '/_config/cors';
},
parse: function (resp) {
@@ -38,7 +42,11 @@ function (app, FauxtonAPI) {
CORS.Httpd = FauxtonAPI.Model.extend({
url: function () {
- return app.host + '/_config/httpd';
+ if (!this.get('node')) {
+ throw new Error('node not set');
+ }
+
+ return window.location.origin + '/_node/' + this.get('node') + '/_config/httpd';
},
corsEnabled: function () {
@@ -57,7 +65,12 @@ function (app, FauxtonAPI) {
documentation: 'cors',
url: function () {
- return app.host + '/_config/' + encodeURIComponent(this.get('section')) + '/' + encodeURIComponent(this.get('attribute'));
+ if (!this.get('node')) {
+ throw new Error('node not set');
+ }
+
+ return app.host + '/_node/' + this.get('node') + '/_config/' +
+ encodeURIComponent(this.get('section')) + '/' + encodeURIComponent(this.get('attribute'));
},
isNew: function () { return false; },
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/stores.js b/app/addons/cors/stores.js
index 1200053..bd36093 100644
--- a/app/addons/cors/stores.js
+++ b/app/addons/cors/stores.js
@@ -22,6 +22,7 @@ define([
this._origins = options.origins;
this._configChanged = false;
this._shouldSaveChange = false;
+ this._node = options.node;
},
shouldSaveChange: function () {
@@ -69,6 +70,10 @@ define([
return this._origins;
},
+ getNode: function () {
+ return this._node;
+ },
+
isAllOrigins: function () {
var origins = this.getOrigins();
if (_.include(origins, '*')) {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cors/tests/componentsSpec.react.jsx b/app/addons/cors/tests/componentsSpec.react.jsx
index dedbef0..b725085 100644
--- a/app/addons/cors/tests/componentsSpec.react.jsx
+++ b/app/addons/cors/tests/componentsSpec.react.jsx
@@ -33,6 +33,7 @@ define([
beforeEach(function () {
container = document.createElement('div');
corsStore._origins = ['http://hello.com'];
+ corsStore._node = 'node2@127.0.0.1';
corsStore._isEnabled = true;
corsStore._configChanged = true;
corsEl = TestUtils.renderIntoDocument(<Views.CORSController />, container);
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/cors/tests/resourcesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/tests/resourcesSpec.js b/app/addons/cors/tests/resourcesSpec.js
index 29c30e2..175a1fc 100644
--- a/app/addons/cors/tests/resourcesSpec.js
+++ b/app/addons/cors/tests/resourcesSpec.js
@@ -20,7 +20,7 @@ define([
var cors;
beforeEach(function () {
- cors = new CORS.Config({});
+ cors = new CORS.Config(null, {node: 'node2@127.0.0.1'});
});
it('Splits up origins into array', function () {
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/documents/assets/less/sidenav.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/sidenav.less b/app/addons/documents/assets/less/sidenav.less
index 27aa406..11df376 100644
--- a/app/addons/documents/assets/less/sidenav.less
+++ b/app/addons/documents/assets/less/sidenav.less
@@ -46,8 +46,7 @@
text-shadow: none;
background-color: rgba(0, 0, 0, 0.05);
}
- .nav-list > .active > a:hover,
- .nav-list > .active > a:focus{
+ .nav-list > .active > a:hover {
color: white;
}
.nav-list > li > a:hover + div.add-dropdown .dropdown-toggle{
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/fauxton/base.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/base.js b/app/addons/fauxton/base.js
index c570f20..db82062 100644
--- a/app/addons/fauxton/base.js
+++ b/app/addons/fauxton/base.js
@@ -49,6 +49,7 @@ function (app, FauxtonAPI, Components, NavbarReactComponents, NavigationActions,
}
});
+
Fauxton.initialize = function () {
app.apiBar = new Components.ApiBar();
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/tests/nightwatch/highlightsidebar.js b/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
index 445e1e5..7171887 100644
--- a/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
+++ b/app/addons/fauxton/tests/nightwatch/highlightsidebar.js
@@ -19,10 +19,10 @@ module.exports = {
.loginToGUI()
.url(baseUrl)
.waitForElementPresent('#add-new-database', waitTime, false)
- .click('a[href="#changePassword"]')
+ .click('a[href="#/replication"]')
.pause(1000)
- .waitForElementVisible('.auth-page', waitTime, false)
- .assert.cssClassPresent('li[data-nav-name="' + client.globals.test_settings.fauxton_username + '"]', "active")
+ .waitForElementVisible('#replication', waitTime, false)
+ .assert.cssClassPresent('li[data-nav-name="Replication"]', 'active')
.end();
}
};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/5de1fe66/settings.json.default
----------------------------------------------------------------------
diff --git a/settings.json.default b/settings.json.default
index cdddf6c..b44c98b 100644
--- a/settings.json.default
+++ b/settings.json.default
@@ -5,6 +5,7 @@
{ "name": "databases" },
{ "name": "documents" },
{ "name": "activetasks" },
+ { "name": "cluster" },
{ "name": "config" },
{ "name": "replication" },
{ "name": "cors" },