You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2015/05/14 11:39:38 UTC
fauxton commit: updated refs/heads/master to 77ba12f
Repository: couchdb-fauxton
Updated Branches:
refs/heads/master fbd7df2ba -> 77ba12fb7
Convert Compaction to use React.js
This converts all backbone.js views to React and Flux.
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/77ba12fb
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/77ba12fb
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/77ba12fb
Branch: refs/heads/master
Commit: 77ba12fb75a0fa329735d1fcef17f8c19b567970
Parents: fbd7df2
Author: Garren Smith <ga...@gmail.com>
Authored: Mon May 11 14:32:32 2015 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Thu May 14 11:39:06 2015 +0200
----------------------------------------------------------------------
app/addons/compaction/actions.js | 123 +++++++++
app/addons/compaction/actiontypes.js | 23 ++
app/addons/compaction/base.js | 2 +-
app/addons/compaction/components.react.jsx | 169 +++++++++++++
app/addons/compaction/routes.js | 10 +-
app/addons/compaction/stores.js | 93 +++++++
.../compaction/templates/compact_view.html | 14 --
app/addons/compaction/templates/layout.html | 28 ---
app/addons/compaction/tests/actionsSpec.js | 247 +++++++++++++++++++
.../compaction/tests/componentsSpec.react.jsx | 110 +++++++++
app/addons/compaction/views.js | 142 -----------
.../documents/index-editor/components.react.jsx | 13 +
12 files changed, 784 insertions(+), 190 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/actions.js b/app/addons/compaction/actions.js
new file mode 100644
index 0000000..15c50c2
--- /dev/null
+++ b/app/addons/compaction/actions.js
@@ -0,0 +1,123 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+ 'app',
+ 'api',
+ 'addons/compaction/actiontypes',
+ 'addons/compaction/resources'
+],
+function (app, FauxtonAPI, ActionTypes, Compaction) {
+
+ return {
+ setCompactionFor: function (database) {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_SET_UP,
+ database: database
+ });
+
+ },
+
+ compactionStarted: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_COMPACTION_STARTING
+ });
+ },
+
+ compactionFinished: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_COMPACTION_FINISHED
+ });
+ },
+
+ cleaningViewsStarted: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_CLEANUP_STARTED
+ });
+ },
+
+ cleaningViewsFinished: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_CLEANUP_FINISHED
+ });
+ },
+
+ compactViewStarted: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_VIEW_STARTED
+ });
+ },
+
+ compactViewFinished: function () {
+ FauxtonAPI.dispatch({
+ type: ActionTypes.COMPACTION_VIEW_FINISHED
+ });
+ },
+
+ compactDatabase: function (database) {
+ this.compactionStarted();
+ Compaction.compactDB(database).then(function () {
+ FauxtonAPI.addNotification({
+ type: 'success',
+ msg: 'Database compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view the compaction progress.',
+ escape: false // beware of possible XSS when the message changes
+ });
+ }, function (xhr, error, reason) {
+ FauxtonAPI.addNotification({
+ type: 'error',
+ msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+ });
+ }).always(function () {
+ this.compactionFinished();
+ }.bind(this));
+ },
+
+ cleanupViews: function (database) {
+ this.cleaningViewsStarted();
+ Compaction.cleanupViews(database).then(function () {
+ FauxtonAPI.addNotification({
+ type: 'success',
+ msg: 'View cleanup has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.',
+ escape: false // beware of possible XSS when the message changes
+ });
+ }, function (xhr, error, reason) {
+ FauxtonAPI.addNotification({
+ type: 'error',
+ msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+ });
+ }).always(function () {
+ this.cleaningViewsFinished();
+ }.bind(this));
+ },
+
+ compactView: function (database, designDoc) {
+ this.compactViewStarted();
+
+ Compaction.compactView(database, designDoc).then(function () {
+ FauxtonAPI.addNotification({
+ type: 'success',
+ msg: 'View compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.',
+ escape: false // beware of possible XSS when the message changes
+ });
+ }, function (xhr, error, reason) {
+ FauxtonAPI.addNotification({
+ type: 'error',
+ msg: 'Error: ' + JSON.parse(xhr.responseText).reason
+ });
+ }).always(function () {
+ this.compactViewFinished();
+ }.bind(this));
+ }
+
+ };
+
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/actiontypes.js b/app/addons/compaction/actiontypes.js
new file mode 100644
index 0000000..e164f7c
--- /dev/null
+++ b/app/addons/compaction/actiontypes.js
@@ -0,0 +1,23 @@
+// 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 {
+ COMPACTION_SET_UP: 'COMPACTION_SET_UP',
+ COMPACTION_COMPACTION_STARTING: 'COMPACTION_COMPACTION_STARTING',
+ COMPACTION_COMPACTION_FINISHED: 'COMPACTION_COMPACTION_FINISHED',
+ COMPACTION_CLEANUP_STARTED: 'COMPACTION_CLEANUP_STARTED',
+ COMPACTION_CLEANUP_FINISHED: 'COMPACTION_CLEANUP_FINISHED',
+ COMPACTION_VIEW_STARTED: 'COMPACTION_VIEW_STARTED',
+ COMPACTION_VIEW_FINISHED: 'COMPACTION_VIEW_FINISHED'
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/base.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/base.js b/app/addons/compaction/base.js
index b82852a..187391c 100644
--- a/app/addons/compaction/base.js
+++ b/app/addons/compaction/base.js
@@ -25,7 +25,7 @@ function (app, FauxtonAPI, Compaction) {
icon: "icon-cogs"
});
- FauxtonAPI.registerExtension('ViewEditor:ButtonRow', new Compaction.CompactView({}));
+ FauxtonAPI.registerExtension('view-editor:compaction-button', Compaction.ViewCompactionButton);
};
return Compaction;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/compaction/components.react.jsx b/app/addons/compaction/components.react.jsx
new file mode 100644
index 0000000..1aa2c0c
--- /dev/null
+++ b/app/addons/compaction/components.react.jsx
@@ -0,0 +1,169 @@
+// 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/compaction/stores',
+ 'addons/compaction/actions',
+ 'addons/components/react-components.react'
+],
+
+function (app, FauxtonAPI, React, Stores, Actions, Components, ReactComponents) {
+ var compactionStore = Stores.compactionStore;
+
+ var CompactDatabase = React.createClass({
+
+ run: function (e) {
+ this.props.compactDatabase();
+ },
+
+ render: function () {
+ var btnText = 'Run';
+
+ if (this.props.isCompacting) {
+ btnText = 'Compacting...';
+ }
+
+ return (
+ <div className="row-fluid">
+ <div className="span12 compaction-option">
+ <h3>Compact Database</h3>
+ <p>Compacting a database removes deleted documents and previous revisions. It is an irreversible operation and may take a while to complete for large databases.</p>
+ <button id="compact-db" disabled={this.props.isCompacting} onClick={this.run} className="btn btn-large btn-primary">{btnText}</button>
+ </div>
+ </div>
+ );
+ }
+
+ });
+
+ var CleanView = React.createClass({
+
+ run: function (e) {
+ this.props.cleanupView();
+ },
+
+ render: function () {
+ var btnText = 'Run';
+
+ if (this.props.isCleaningView) {
+ btnText = 'Cleaning Views...';
+ }
+ return (
+ <div className="row-fluid">
+ <div className="span12 compaction-option">
+ <h3>Cleanup Views</h3>
+ <p>Cleaning up views in a database removes old view files still stored on the filesystem. It is an irreversible operation.</p>
+ <button id="cleanup-views" onClick={this.run} className="btn btn-large btn-primary">{btnText}</button>
+ </div>
+ </div>
+ );
+ }
+
+ });
+
+ var CompactionController = React.createClass({
+ getStoreState: function () {
+ return {
+ database: compactionStore.getDatabase(),
+ isCompacting: compactionStore.isCompacting(),
+ isCleaningViews: compactionStore.isCleaningViews()
+ };
+ },
+
+ getInitialState: function () {
+ return this.getStoreState();
+ },
+
+ componentDidMount: function () {
+ compactionStore.on('change', this.onChange, this);
+ },
+
+ componentWillUnmount: function () {
+ compactionStore.off('change', this.onChange);
+ },
+
+ onChange: function () {
+ this.setState(this.getStoreState());
+ },
+
+ compactDatabase: function () {
+ Actions.compactDatabase(this.state.database);
+ },
+
+ cleanupView: function () {
+ Actions.cleanupViews(this.state.database);
+ },
+
+ render: function () {
+ return (
+ <div>
+ <CompactDatabase isCompacting={this.state.isCompacting} compactDatabase={this.compactDatabase} />
+ <CleanView isCleaningView={this.state.isCleaningViews} cleanupView={this.cleanupView}/>
+ </div>
+ );
+ }
+ });
+
+ var ViewCompactionButton = React.createClass({
+ onClick: function (e) {
+ e.preventDefault();
+ Actions.compactView(this.props.database, this.props.designDoc);
+ },
+
+ getStoreState: function () {
+ return {
+ isCompactingView: compactionStore.isCompactingView()
+ };
+ },
+
+ getInitialState: function () {
+ return this.getStoreState();
+ },
+
+ componentDidMount: function () {
+ compactionStore.on('change', this.onChange, this);
+ },
+
+ componentWillUnmount: function () {
+ compactionStore.off('change', this.onChange);
+ },
+
+ onChange: function () {
+ this.setState(this.getStoreState());
+ },
+
+ render: function () {
+ var btnMsg = 'Compact View';
+
+ if (this.state.isCompactingView) {
+ btnMsg = 'Compacting View';
+ }
+
+ return (
+ <button disabled={this.state.isCompactingView}
+ className="btn btn-info pull-right"
+ onClick={this.onClick}>{btnMsg}</button>
+ );
+ }
+
+ });
+
+ return {
+ CompactDatabase: CompactDatabase,
+ CleanView: CleanView,
+ CompactionController: CompactionController,
+ ViewCompactionButton: ViewCompactionButton
+ };
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/routes.js b/app/addons/compaction/routes.js
index 295765e..ea6d54f 100644
--- a/app/addons/compaction/routes.js
+++ b/app/addons/compaction/routes.js
@@ -15,12 +15,13 @@ define([
'api',
// Modules
- 'addons/compaction/views',
+ 'addons/compaction/components.react',
+ 'addons/compaction/actions',
'addons/databases/resources',
'addons/documents/shared-routes'
],
-function (app, FauxtonAPI, Compaction, Databases, BaseRoute) {
+function (app, FauxtonAPI, Compaction, Actions, Databases, BaseRoute) {
var CompactionRouteObject = BaseRoute.extend({
routes: {
@@ -55,7 +56,8 @@ function (app, FauxtonAPI, Compaction, Databases, BaseRoute) {
},
compaction: function () {
- this.pageContent = this.setView('#dashboard-content', new Compaction.Layout({model: this.database}));
+ Actions.setCompactionFor(this.database);
+ this.pageContent = this.setComponent('#dashboard-content', Compaction.CompactionController);
},
establish: function () {
@@ -86,5 +88,3 @@ function (app, FauxtonAPI, Compaction, Databases, BaseRoute) {
return Compaction;
});
-
-
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/stores.js b/app/addons/compaction/stores.js
new file mode 100644
index 0000000..d2c5410
--- /dev/null
+++ b/app/addons/compaction/stores.js
@@ -0,0 +1,93 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+define([
+ 'api',
+ 'addons/compaction/actiontypes'
+],
+
+function (FauxtonAPI, ActionTypes) {
+ var Stores = {};
+
+ Stores.CompactionStore = FauxtonAPI.Store.extend({
+
+ initialize: function () {
+ this._isCompacting = false;
+ this._isCleaningView = false;
+ this._isCompactingView = false;
+ },
+
+ isCompacting: function () {
+ return this._isCompacting;
+ },
+
+ isCleaningViews: function () {
+ return this._isCleaningViews;
+ },
+
+ isCompactingView: function () {
+ return this._isCompactingView;
+ },
+
+ setDatabase: function (database) {
+ this._database = database;
+ },
+
+ getDatabase: function () {
+ return this._database;
+ },
+
+ dispatch: function (action) {
+ switch (action.type) {
+ case ActionTypes.COMPACTION_SET_UP:
+ this.setDatabase(action.database);
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_COMPACTION_STARTING:
+ this._isCompacting = true;
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_COMPACTION_FINISHED:
+ this._isCompacting = false;
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_CLEANUP_STARTED:
+ this._isCleaningViews = true;
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_CLEANUP_FINISHED:
+ this._isCleaningViews = false;
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_VIEW_STARTED:
+ this._isCompactingView = true;
+ this.triggerChange();
+ break;
+ case ActionTypes.COMPACTION_VIEW_FINISHED:
+ this._isCompactingView = false;
+ this.triggerChange();
+ break;
+
+ default:
+ return;
+ // do nothing
+ }
+ }
+
+ });
+
+ Stores.compactionStore = new Stores.CompactionStore();
+
+ Stores.compactionStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.compactionStore.dispatch);
+
+ return Stores;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/templates/compact_view.html
----------------------------------------------------------------------
diff --git a/app/addons/compaction/templates/compact_view.html b/app/addons/compaction/templates/compact_view.html
deleted file mode 100644
index 8a0b7ec..0000000
--- a/app/addons/compaction/templates/compact_view.html
+++ /dev/null
@@ -1,14 +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.
--->
-Compact View
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/templates/layout.html
----------------------------------------------------------------------
diff --git a/app/addons/compaction/templates/layout.html b/app/addons/compaction/templates/layout.html
deleted file mode 100644
index f63b7de..0000000
--- a/app/addons/compaction/templates/layout.html
+++ /dev/null
@@ -1,28 +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.
--->
-<div class="row-fluid">
- <div class="span12 compaction-option">
- <h3> Compact Database </h3>
- <p>Compacting a database removes deleted documents and previous revisions. It is an irreversible operation and may take a while to complete for large databases.</p>
- <button id="compact-db" class="btn btn-large btn-primary"> Run </button>
- </div>
-</div>
-
-<div class="row-fluid">
- <div class="span12 compaction-option">
- <h3> Cleanup Views </h3>
- <p>Cleaning up views in a database removes old view files still stored on the filesystem. It is an irreversible operation.</p>
- <button id="cleanup-views" class="btn btn-large btn-primary"> Run </button>
- </div>
-</div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/tests/actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/tests/actionsSpec.js b/app/addons/compaction/tests/actionsSpec.js
new file mode 100644
index 0000000..1aff431
--- /dev/null
+++ b/app/addons/compaction/tests/actionsSpec.js
@@ -0,0 +1,247 @@
+// 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/compaction/stores',
+ 'addons/compaction/resources',
+ 'addons/compaction/actions',
+ 'testUtils'
+], function (FauxtonAPI, Stores, Compaction, Actions, testUtils) {
+ var assert = testUtils.assert;
+ var restore = testUtils.restore;
+ var store = Stores.compactionStore;
+
+ describe('Compaction Actions', function () {
+
+ describe('Compact Database', function () {
+ var database = {};
+
+ afterEach(function () {
+ restore(FauxtonAPI.addNotification);
+ });
+
+ it('compacts database', function () {
+ var spy = false;
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.compactDB = function () {
+ spy = true;
+ return promise;
+ };
+
+ Actions.compactDatabase(database);
+ assert.ok(spy);
+ });
+
+ it('notifies on success', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.compactDB = function () {
+ return promise;
+ };
+
+ Actions.compactDatabase(database);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('notifies on failure', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.reject({
+ responseText: JSON.stringify({reason: 'testing'})
+ });
+
+ Compaction.compactDB = function () {
+ return promise;
+ };
+
+ Actions.compactDatabase(database);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('sets compacting view to true on start', function () {
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.compactDB = function () {
+ return promise;
+ };
+
+ Actions.compactDatabase(database);
+ assert.ok(store.isCompacting());
+ });
+
+ it('sets compacting view to false on completion of request', function () {
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.compactDB = function () {
+ return promise;
+ };
+
+ Actions.compactDatabase(database);
+ assert.notOk(store.isCompacting());
+ });
+
+ });
+
+ describe('Clean Views', function () {
+ var database = {};
+
+ afterEach(function () {
+ restore(FauxtonAPI.addNotification);
+ });
+
+ it('cleans views', function () {
+ var spy = false;
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.cleanupViews = function () {
+ spy = true;
+ return promise;
+ };
+
+ Actions.cleanupViews(database);
+ assert.ok(spy);
+ });
+
+ it('notifies on success', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.cleanupViews = function () {
+ return promise;
+ };
+
+ Actions.cleanupViews(database);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('notifies on failure', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.reject({
+ responseText: JSON.stringify({reason: 'testing'})
+ });
+
+ Compaction.cleanupViews = function () {
+ return promise;
+ };
+
+ Actions.cleanupViews(database);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('sets compacting view to true on start', function () {
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.cleanupViews = function () {
+ return promise;
+ };
+
+ Actions.cleanupViews(database);
+ assert.ok(store.isCleaningViews());
+ });
+
+ it('sets compacting view to false on completion of request', function () {
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.cleanupViews = function () {
+ return promise;
+ };
+
+ Actions.cleanupViews(database);
+ assert.notOk(store.isCleaningViews());
+ });
+
+ });
+
+ describe('Compact View', function () {
+ var database = {};
+ var designDoc = '_design/test-doc';
+
+ afterEach(function () {
+ restore(FauxtonAPI.addNotification);
+ });
+
+ it('compacts database', function () {
+ var spy = false;
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.compactView = function () {
+ spy = true;
+ return promise;
+ };
+
+ Actions.compactView(database, designDoc);
+ assert.ok(spy);
+ });
+
+ it('notifies on success', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.compactView = function () {
+ return promise;
+ };
+
+ Actions.compactView(database, designDoc);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('notifies on failure', function () {
+ var spy = sinon.spy(FauxtonAPI, 'addNotification');
+ var promise = FauxtonAPI.Deferred();
+ promise.reject({
+ responseText: JSON.stringify({reason: 'testing'})
+ });
+
+ Compaction.compactView = function () {
+ return promise;
+ };
+
+ Actions.compactView(database, designDoc);
+ assert.ok(spy.calledOnce);
+ });
+
+ it('sets compacting view to true on start', function () {
+ var promise = FauxtonAPI.Deferred();
+
+ Compaction.compactView = function () {
+ return promise;
+ };
+
+ Actions.compactView(database, designDoc);
+ assert.ok(store.isCompactingView());
+ });
+
+ it('sets compacting view to false on completion of request', function () {
+ var promise = FauxtonAPI.Deferred();
+ promise.resolve();
+
+ Compaction.compactView = function () {
+ return promise;
+ };
+
+ Actions.compactView(database, designDoc);
+ assert.notOk(store.isCompactingView());
+ });
+
+ });
+
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/compaction/tests/componentsSpec.react.jsx b/app/addons/compaction/tests/componentsSpec.react.jsx
new file mode 100644
index 0000000..5c6a18a
--- /dev/null
+++ b/app/addons/compaction/tests/componentsSpec.react.jsx
@@ -0,0 +1,110 @@
+// 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/compaction/components.react',
+ 'addons/compaction/actions',
+ 'testUtils',
+ "react"
+], function (FauxtonAPI, Views, Actions, utils, React) {
+ FauxtonAPI.router = new FauxtonAPI.Router([]);
+
+ var assert = utils.assert;
+ var TestUtils = React.addons.TestUtils;
+
+ describe('Compaction Controller', function () {
+ var container, controllerEl;
+
+ beforeEach(function () {
+ Actions.setCompactionFor({
+ id: 'my-database'
+ });
+
+ container = document.createElement('div');
+ controllerEl = TestUtils.renderIntoDocument(
+ <Views.CompactionController />,
+ container
+ );
+ });
+
+ afterEach(function () {
+ React.unmountComponentAtNode(container);
+ });
+
+ it('triggers compact database action', function () {
+ var spy = sinon.spy(Actions, 'compactDatabase');
+
+ controllerEl.compactDatabase();
+ assert.ok(spy.calledOnce);
+ });
+
+ it('triggers clean up view action', function () {
+ var spy = sinon.spy(Actions, 'cleanupViews');
+
+ controllerEl.cleanupView();
+ assert.ok(spy.calledOnce);
+ });
+
+ });
+
+ describe('CleanView', function () {
+ var spy, container, cleanupViewEl;
+
+ beforeEach(function () {
+ spy = sinon.spy();
+ container = document.createElement('div');
+ cleanupViewEl = TestUtils.renderIntoDocument(
+ <Views.CleanView cleanupView={spy} />,
+ container
+ );
+ });
+
+ afterEach(function () {
+ React.unmountComponentAtNode(container);
+ });
+
+ it('calls cleanupView on button click', function () {
+ var el = $(cleanupViewEl.getDOMNode()).find('button')[0];
+ TestUtils.Simulate.click(el, {});
+
+ assert.ok(spy.calledOnce);
+
+ });
+
+ });
+
+ describe('CompactDatabase', function () {
+ var spy, container, compactViewEl;
+
+ beforeEach(function () {
+ spy = sinon.spy();
+ container = document.createElement('div');
+ compactViewEl = TestUtils.renderIntoDocument(
+ <Views.CompactDatabase compactDatabase={spy} />,
+ container
+ );
+ });
+
+ afterEach(function () {
+ React.unmountComponentAtNode(container);
+ });
+
+ it('calls compact database on button click', function () {
+ var el = $(compactViewEl.getDOMNode()).find('button')[0];
+ TestUtils.Simulate.click(el, {});
+
+ assert.ok(spy.calledOnce);
+
+ });
+
+ });
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/compaction/views.js
----------------------------------------------------------------------
diff --git a/app/addons/compaction/views.js b/app/addons/compaction/views.js
deleted file mode 100644
index be3f129..0000000
--- a/app/addons/compaction/views.js
+++ /dev/null
@@ -1,142 +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",
- // Modules
- "addons/compaction/resources"
-],
-function (app, FauxtonAPI, Compaction) {
-
- Compaction.Layout = FauxtonAPI.View.extend({
- template: 'addons/compaction/templates/layout',
-
- initialize: function () {
- _.bindAll(this);
- },
-
- events: {
- "click #compact-db": "compactDB",
- "click #compact-view": "compactDB",
- "click #cleanup-views": "cleanupViews"
- },
-
- disableButton: function (selector, text) {
- this.$(selector).attr('disabled', 'disabled').text(text);
- },
-
- enableButton: function (selector, text) {
- this.$(selector).removeAttr('disabled').text(text);
- },
-
- compactDB: function (event) {
- var enableButton = this.enableButton;
- event.preventDefault();
-
- this.disableButton('#compact-db', 'Compacting...');
-
- Compaction.compactDB(this.model).then(function () {
- FauxtonAPI.addNotification({
- type: 'success',
- msg: 'Database compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view the compaction progress.',
- escape: false // beware of possible XSS when the message changes
- });
- }, function (xhr, error, reason) {
- FauxtonAPI.addNotification({
- type: 'error',
- msg: 'Error: ' + JSON.parse(xhr.responseText).reason
- });
- }).always(function () {
- enableButton('#compact-db', 'Run');
- });
- },
-
- cleanupViews: function (event) {
- var enableButton = this.enableButton;
- event.preventDefault();
-
- this.disableButton('#cleanup-view', 'Cleaning...');
-
- Compaction.cleanupViews(this.model).then(function () {
- FauxtonAPI.addNotification({
- type: 'success',
- msg: 'View cleanup has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.',
- escape: false // beware of possible XSS when the message changes
- });
- }, function (xhr, error, reason) {
- FauxtonAPI.addNotification({
- type: 'error',
- msg: 'Error: ' + JSON.parse(xhr.responseText).reason
- });
- }).always(function () {
- enableButton('#cleanup-views', 'Run');
- });
- }
- });
-
- Compaction.CompactView = FauxtonAPI.View.extend({
- template: 'addons/compaction/templates/compact_view',
- className: 'btn btn-info pull-right',
- tagName: 'button',
-
- initialize: function () {
- _.bindAll(this);
- },
-
- events: {
- "click": "compact"
- },
-
- disableButton: function () {
- this.$el.attr('disabled', 'disabled').text('Compacting...');
- },
-
- enableButton: function () {
- this.$el.removeAttr('disabled').text('Compact View');
- },
-
-
- update: function (database, designDoc, viewName) {
- this.database = database;
- this.designDoc = designDoc;
- this.viewName = viewName;
- },
-
- compact: function (event) {
- event.preventDefault();
- var enableButton = this.enableButton;
-
- this.disableButton();
-
- Compaction.compactView(this.database, this.designDoc).then(function () {
- FauxtonAPI.addNotification({
- type: 'success',
- msg: 'View compaction has started. Visit <a href="#activetasks">Active Tasks</a> to view progress.',
- escape: false // beware of possible XSS when the message changes
- });
- }, function (xhr, error, reason) {
- FauxtonAPI.addNotification({
- type: 'error',
- msg: 'Error: ' + JSON.parse(xhr.responseText).reason
- });
- }).always(function () {
- enableButton();
- });
-
- }
-
- });
-
- return Compaction;
-});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/77ba12fb/app/addons/documents/index-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/components.react.jsx b/app/addons/documents/index-editor/components.react.jsx
index 1ba8bc6..2f27464 100644
--- a/app/addons/documents/index-editor/components.react.jsx
+++ b/app/addons/documents/index-editor/components.react.jsx
@@ -365,6 +365,18 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, ReactComponents)
Actions.updateMapCode(code);
},
+ getCompactButton: function () {
+ var extension = FauxtonAPI.getExtensions('view-editor:compaction-button');
+
+ if (_.isEmpty(extension)) {
+ return null;
+ } else {
+ var CompactButton = extension[0];
+ return <CompactButton database={this.state.database}
+ designDoc={this.state.designDocId}/>;
+ }
+ },
+
render: function () {
if (this.state.isLoading) {
return (
@@ -423,6 +435,7 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, ReactComponents)
<div className="control-group">
<ConfirmButton text="Save & Build Index" />
<DeleteView />
+ {this.getCompactButton()}
</div>
</div>
</form>