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 <[email protected]> Authored: Mon May 11 14:32:32 2015 +0200 Committer: Garren Smith <[email protected]> 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>
