Implement a filter for databases Uses a new model to manage the state of the different search filters to filter the view.
Nice feature: the filter for the database (upper input) and the filters for the type (buttons) work nicely together, so you can filter out all replications for that database (let's name it registry) without the compaction, if you choose replication as type and enter "registry" in the top input. Closes COUCHDB-2125 Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/2adfaf93 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/2adfaf93 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/2adfaf93 Branch: refs/heads/secondary-indexes Commit: 2adfaf932a26a601fea0fc8cf316b6feb9023f99 Parents: b7c32c2 Author: Robert Kowalski <[email protected]> Authored: Fri Aug 1 20:10:13 2014 +0200 Committer: Robert Kowalski <[email protected]> Committed: Wed Aug 20 19:15:22 2014 +0200 ---------------------------------------------------------------------- .../activetasks/assets/less/activetasks.less | 30 ++++++++++ app/addons/activetasks/resources.js | 4 ++ app/addons/activetasks/routes.js | 20 ++++++- .../activetasks/templates/tab_header.html | 33 +++++++++++ app/addons/activetasks/templates/table.html | 24 ++------ app/addons/activetasks/tests/viewsSpec.js | 36 +++++++----- app/addons/activetasks/views.js | 59 +++++++++++++++----- 7 files changed, 155 insertions(+), 51 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/assets/less/activetasks.less ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/assets/less/activetasks.less b/app/addons/activetasks/assets/less/activetasks.less index b06f550..0f92a77 100644 --- a/app/addons/activetasks/assets/less/activetasks.less +++ b/app/addons/activetasks/assets/less/activetasks.less @@ -14,3 +14,33 @@ .active-tasks th { cursor: pointer; } + +.activetasks-header .task-search-database { + margin: 20px; +} + +.active-tasks th { + &.type { + width: 10%; + } + + &.database { + width: 23%; + } + + &.started { + width: 17%; + } + + &.updated { + width: 17%; + } + + &.pid { + width: 10%; + } + + &.status { + width: 23%; + } +} http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/resources.js ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/resources.js b/app/addons/activetasks/resources.js index 92165dc..0872d41 100644 --- a/app/addons/activetasks/resources.js +++ b/app/addons/activetasks/resources.js @@ -63,6 +63,10 @@ function (app, Fauxton) { } }); + Active.Search = Backbone.Model.extend({ + filterDatabase: null, + filterType: "all" + }); return Active; }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/routes.js ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/routes.js b/app/addons/activetasks/routes.js index cdc5a01..1805d3f 100644 --- a/app/addons/activetasks/routes.js +++ b/app/addons/activetasks/routes.js @@ -20,13 +20,17 @@ define([ function (app, FauxtonAPI, Activetasks, Views) { var ActiveTasksRouteObject = FauxtonAPI.RouteObject.extend({ - layout: "with_sidebar", + layout: "with_tabs_sidebar", routes: { "activetasks/:id": "defaultView", "activetasks": "defaultView" }, + events: { + "route:changeFilter": "changeFilter", + }, + selectedHeader: 'Active Tasks', crumbs: [ @@ -41,15 +45,25 @@ function (app, FauxtonAPI, Activetasks, Views) { initialize: function () { this.allTasks = new Activetasks.AllTasks(); + this.search = new Activetasks.Search(); }, defaultView: function () { - this.setView("#dashboard-content", new Views.View({ + this.setView("#dashboard-lower-content", new Views.View({ collection: this.allTasks, - currentView: "all" + currentView: "all", + searchModel: this.search })); this.setView("#sidebar-content", new Views.TabMenu({})); + + this.headerView = this.setView("#dashboard-upper-content", new Views.TabHeader({ + searchModel: this.search + })); + }, + + changeFilter: function (filterType) { + this.search.set('filterType', filterType); } }); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/templates/tab_header.html ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/templates/tab_header.html b/app/addons/activetasks/templates/tab_header.html new file mode 100644 index 0000000..d613c7d --- /dev/null +++ b/app/addons/activetasks/templates/tab_header.html @@ -0,0 +1,33 @@ +<!-- +Licensed under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. +--> + +<div class="dashboard-upper-menu"> + <ul class="nav nav-tabs window-resizeable" id="db-views-tabs-nav"> + <li> + <a class="js-toggle-filter" href="#filter" data-bypass="true" data-toggle="tab"> + <i class="fonticon fonticon-plus"></i>Filter + </a> + </li> + </ul> +</div> + +<div class="tab-content"> + <div class="tab-pane" id="query"> + <div class="activetasks-header"> + <div class="pull-right"> + <input class="task-search-database" type="text" name="search" placeholder="Search for databases..."> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/templates/table.html ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/templates/table.html b/app/addons/activetasks/templates/table.html index a8cbd52..2268927 100644 --- a/app/addons/activetasks/templates/table.html +++ b/app/addons/activetasks/templates/table.html @@ -12,19 +12,7 @@ License for the specific language governing permissions and limitations under the License. --> -<!-- -Licensed under the Apache License, Version 2.0 (the "License"); you may not -use this file except in compliance with the License. You may obtain a copy of -the License at - - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -License for the specific language governing permissions and limitations under -the License. ---> <% if (collection.length === 0){%> <tr> @@ -36,12 +24,12 @@ the License. <thead> <tr> - <th data-type="type">Type</th> - <th data-type="source,target,database">Object</th> - <th data-type="started_on">Started on</th> - <th data-type="updated_on">Last updated on</th> - <th data-type="pid">PID</th> - <th data-type="progress" width="200">Status</th> + <th class="type" data-type="type">Type</th> + <th class="database" data-type="source,target,database">Database</th> + <th class="started" data-type="started_on">Started on</th> + <th class="updated" data-type="updated_on">Last updated on</th> + <th class="pid" data-type="pid">PID</th> + <th class="status" data-type="progress">Status</th> </tr> </thead> http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/tests/viewsSpec.js ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/tests/viewsSpec.js b/app/addons/activetasks/tests/viewsSpec.js index 8731200..e02dfb1 100644 --- a/app/addons/activetasks/tests/viewsSpec.js +++ b/app/addons/activetasks/tests/viewsSpec.js @@ -13,8 +13,9 @@ define([ 'api', 'addons/activetasks/views', 'addons/activetasks/resources', + 'addons/activetasks/routes', 'testUtils' -], function (FauxtonAPI, Views, Activetasks, testUtils) { +], function (FauxtonAPI, Views, Activetasks, RouteObject, testUtils) { var assert = testUtils.assert, ViewSandbox = testUtils.ViewSandbox; @@ -62,19 +63,30 @@ define([ assert.ok(spy.calledOnce); }); + it("should set the correct active tab", function () { + var $rep = tabMenu.$('li[data-type="replication"]'); + $rep.click(); + assert.ok($rep.hasClass('active')); + }); }); describe('on request by type', function () { - var viewSandbox, mainView; + var viewSandbox, mainView, tabHeader, searchModel; + beforeEach(function (done) { + searchModel = new Activetasks.Search(); + tabHeader = new Views.TabHeader({ + searchModel: searchModel + }); mainView = new Views.View({ collection: new Activetasks.AllTasks(), - currentView: "all" + currentView: "all", + searchModel: searchModel }); viewSandbox = new ViewSandbox(); - viewSandbox.renderView(tabMenu).promise().then(function () { + viewSandbox.renderView(tabHeader, function () { viewSandbox.renderView(mainView, done); }); }); @@ -83,16 +95,9 @@ define([ viewSandbox.remove(); }); - it("should set the filter the main-view", function () { - var $rep = tabMenu.$('li[data-type="replication"]'); - $rep.click(); - assert.equal("replication", mainView.filter); - }); - - it("should set correct active tab", function () { - var $rep = tabMenu.$('li[data-type="replication"]'); - $rep.click(); - assert.ok($rep.hasClass('active')); + it("should set the filter 'database' for the main-view", function () { + var $rep = tabHeader.$("input").val("registry").trigger("keyup"); + assert.equal("registry", mainView.searchModel.get('filterDatabase')); }); }); @@ -103,7 +108,8 @@ define([ beforeEach(function (done) { mainView = new Views.View({ collection: new Activetasks.AllTasks(), - currentView: "all" + currentView: "all", + searchModel: new Activetasks.Search() }); viewSandbox = new ViewSandbox(); http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/2adfaf93/app/addons/activetasks/views.js ---------------------------------------------------------------------- diff --git a/app/addons/activetasks/views.js b/app/addons/activetasks/views.js index 54d8215..28efa36 100644 --- a/app/addons/activetasks/views.js +++ b/app/addons/activetasks/views.js @@ -39,30 +39,36 @@ function (app, FauxtonAPI, ActiveTasks) { "click th": "sortByType" }, - filter: "all", - initialize: function (options) { - this.listenTo(ActiveTasks.events, "tasks:filter", this.filterAndRender); + this.listenTo(this.searchModel, "change", this.render); this.listenTo(this.collection, "reset", this.render); }, beforeRender: function () { - this.filterAndInsertView(this.filter); - }, - - filterAndRender: function (view) { - this.filter = view; - this.render(); + this.filterAndInsertView(); }, filterAndInsertView: function () { - var that = this; + var that = this, + database = this.searchModel.get("filterDatabase"), + filter = this.searchModel.get("filterType"), + databaseRegex = new RegExp(database, "g"); + this.removeView(".js-tasks-go-here"); this.collection.forEach(function (item) { - if (that.filter !== "all" && item.get("type") !== that.filter) { + + if (filter && filter !== "all" && item.get("type") !== filter) { return; } + + if (database && + !databaseRegex.test(item.get("source")) && + !databaseRegex.test(item.get("target")) && + !databaseRegex.test(item.get("database"))) { + return; + } + var view = new Views.TableDetail({ model: item }); @@ -148,12 +154,12 @@ function (app, FauxtonAPI, ActiveTasks) { requestByType: function(e){ var currentTarget = e.currentTarget, - datatype = this.$(currentTarget).attr("data-type"); + filter = this.$(currentTarget).attr("data-type"); this.$('.task-tabs').find('li').removeClass('active'); this.$(currentTarget).addClass('active'); - ActiveTasks.events.trigger("tasks:filter", datatype); + FauxtonAPI.triggerRouteEvent('changeFilter', filter); } }); @@ -171,7 +177,7 @@ function (app, FauxtonAPI, ActiveTasks) { if (this.type === "replication"){ objectField = this.model.get('source') + " to " + this.model.get('target'); } else if (this.type === "indexer") { - objectField = this.model.get("database") + " / " + this.model.get("design_document"); + objectField = this.model.get("database") + " (View: " + this.model.get("design_document") + ")"; } return objectField; }, @@ -179,7 +185,7 @@ function (app, FauxtonAPI, ActiveTasks) { getProgress: function(){ var progress = ""; if (this.type === "indexer"){ - progress = "Processed " +this.model.get('changes_done')+ " of "+this.model.get('total_changes')+ ' changes.'; + progress = "Processed " +this.model.get('changes_done')+ " of "+this.model.get('total_changes')+ ' changes. '; } else if (this.type === "replication"){ progress = this.model.get('docs_written')+ " docs written. "; if (this.model.get('changes_pending') !== undefined) { @@ -208,5 +214,28 @@ function (app, FauxtonAPI, ActiveTasks) { } }); + Views.TabHeader = FauxtonAPI.View.extend({ + template: "addons/activetasks/templates/tab_header", + + events: { + "keyup input": "searchDb", + "click .js-toggle-filter": "toggleQuery" + }, + + toggleQuery: function (event) { + $('#dashboard-content').scrollTop(0); + this.$('#query').toggle('slow'); + }, + + searchDb: function (event) { + event.preventDefault(); + + var $search = this.$('input[name="search"]'), + database = $search.val(); + + this.searchModel.set('filterDatabase', database); + } + }); + return Views; });
