Repository: ambari Updated Branches: refs/heads/trunk a3d1d6732 -> 74ef96200
AMBARI-5237 Implement pagination on "Confirm Hosts" step. (atkach) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/74ef9620 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/74ef9620 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/74ef9620 Branch: refs/heads/trunk Commit: 74ef96200a8b8ba1bc761d5ad7d561d35721cc4a Parents: a3d1d67 Author: atkach <[email protected]> Authored: Thu Mar 27 14:08:14 2014 +0200 Committer: atkach <[email protected]> Committed: Thu Mar 27 14:08:14 2014 +0200 ---------------------------------------------------------------------- .../app/controllers/wizard/step2_controller.js | 4 +- .../app/controllers/wizard/step3_controller.js | 149 ++++------------- ambari-web/app/messages.js | 2 + ambari-web/app/styles/application.less | 19 +++ .../app/templates/common/items_list_popup.hbs | 21 +++ .../wizard/step2_host_name_pattern_popup.hbs | 21 --- ambari-web/app/templates/wizard/step3.hbs | 158 +++++++++++-------- ambari-web/app/views/common/table_view.js | 93 +++++++++-- ambari-web/app/views/wizard/step3_view.js | 133 +++++++++++++++- 9 files changed, 381 insertions(+), 219 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/controllers/wizard/step2_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step2_controller.js b/ambari-web/app/controllers/wizard/step2_controller.js index 4d7df4c..e2eec44 100644 --- a/ambari-web/app/controllers/wizard/step2_controller.js +++ b/ambari-web/app/controllers/wizard/step2_controller.js @@ -309,8 +309,8 @@ App.WizardStep2Controller = Em.Controller.extend({ this.hide(); }, bodyClass: Ember.View.extend({ - templateName: require('templates/wizard/step2_host_name_pattern_popup'), - hostNames: hostNames + templateName: require('templates/common/items_list_popup'), + items: hostNames }) }); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/controllers/wizard/step3_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step3_controller.js b/ambari-web/app/controllers/wizard/step3_controller.js index f5b2fa6..b3720a3 100644 --- a/ambari-web/app/controllers/wizard/step3_controller.js +++ b/ambari-web/app/controllers/wizard/step3_controller.js @@ -38,68 +38,6 @@ App.WizardStep3Controller = Em.Controller.extend({ stopBootstrap: false, isSubmitDisabled: true, - categoryObject: Em.Object.extend({ - hostsCount: function () { - var category = this; - var hosts = this.get('controller.hosts').filter(function(_host) { - if (_host.get('bootStatus') == category.get('hostsBootStatus')) { - return true; - } else { - return (_host.get('bootStatus') == 'DONE' && category.get('hostsBootStatus') == 'REGISTERING'); - } - }, this); - return hosts.get('length'); - }.property('[email protected]'), // '[email protected]' - label: function () { - return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount')); - }.property('value', 'hostsCount') - }), - getCategory: function(field, value){ - return this.get('categories').find(function(item){ - return item.get(field) == value; - }); - }, - - categories: function () { - var self = this; - self.categoryObject.reopen({ - controller: self, - isActive: function(){ - return this.get('controller.category') == this; - }.property('controller.category'), - itemClass: function(){ - return this.get('isActive') ? 'active' : ''; - }.property('isActive') - }); - - var categories = [ - self.categoryObject.create({value: Em.I18n.t('common.all'), hostsCount: function () { - return this.get('controller.hosts.length'); - }.property('controller.hosts.length') }), - self.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.installing'), hostsBootStatus: 'RUNNING'}), - self.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.registering'), hostsBootStatus: 'REGISTERING'}), - self.categoryObject.create({value: Em.I18n.t('common.success'), hostsBootStatus: 'REGISTERED' }), - self.categoryObject.create({value: Em.I18n.t('common.fail'), hostsBootStatus: 'FAILED', last: true }) - ]; - - this.set('category', categories.get('firstObject')); - - return categories; - }.property(), - - category: false, - - allChecked: false, - - onAllChecked: function () { - var hosts = this.get('visibleHosts'); - hosts.setEach('isChecked', this.get('allChecked')); - }.observes('allChecked'), - - noHostsSelected: function () { - return !(this.hosts.someProperty('isChecked', true)); - }.property('[email protected]'), - isRetryDisabled: true, isLoaded: false, @@ -160,20 +98,8 @@ App.WizardStep3Controller = Em.Controller.extend({ hosts.pushObject(hostInfo); } - - if(hosts.length > 200) { - lazyloading.run({ - destination: this.get('hosts'), - source: hosts, - context: this, - initSize: 100, - chunkSize: 150, - delay: 50 - }); - } else { - this.set('hosts', hosts); - this.set('isLoaded', true); - } + this.set('hosts', hosts); + this.set('isLoaded', true); }, /** @@ -195,22 +121,6 @@ App.WizardStep3Controller = Em.Controller.extend({ return this.get('bootHosts').length != 0 && this.get('bootHosts').someProperty('bootStatus', 'RUNNING'); }, - filterByCategory: function () { - var category = this.get('category.hostsBootStatus'); - if (category) { - this.get('hosts').forEach(function (host) { - host.set('isVisible', (category === host.get('bootStatus'))); - }); - } else { // if (this.get('category') === 'All Hosts') - this.get('hosts').setEach('isVisible', true); - } - }.observes('category', '[email protected]'), - - /* Returns the current set of visible hosts on view (All, Succeeded, Failed) */ - visibleHosts: function () { - return this.get('hosts').filterProperty('isVisible'); - }.property('[email protected]'), - removeHosts: function (hosts) { var self = this; App.showConfirmationPopup(function() { @@ -229,7 +139,7 @@ App.WizardStep3Controller = Em.Controller.extend({ removeSelectedHosts: function () { if (!this.get('noHostsSelected')) { - var selectedHosts = this.get('visibleHosts').filterProperty('isChecked', true); + var selectedHosts = this.get('hosts').filterProperty('isChecked', true); selectedHosts.forEach(function (_hostInfo) { console.log('Removing: ' + _hostInfo.name); }); @@ -237,6 +147,24 @@ App.WizardStep3Controller = Em.Controller.extend({ } }, + /** + * show popup with the list of hosts which are selected + */ + selectedHostsPopup: function () { + var selectedHosts = this.get('hosts').filterProperty('isChecked').mapProperty('name'); + App.ModalPopup.show({ + header: Em.I18n.t('installer.step3.selectedHosts.popup.header'), + onPrimary: function () { + this.hide(); + }, + secondary: null, + bodyClass: Ember.View.extend({ + items: selectedHosts, + templateName: require('templates/common/items_list_popup') + }) + }); + }, + retryHost: function (hostInfo) { this.retryHosts([hostInfo]); }, @@ -287,7 +215,7 @@ App.WizardStep3Controller = Em.Controller.extend({ setRegistrationInProgress: function () { var bootHosts = this.get('bootHosts'); //if hosts aren't loaded yet then registration should be in progress - var result = (bootHosts.length === 0); + var result = (bootHosts.length === 0 && !this.get('isLoaded')); for (var i = 0, l = bootHosts.length; i < l; i++) { if (bootHosts[i].get('bootStatus') !== 'REGISTERED' && bootHosts[i].get('bootStatus') !== 'FAILED') { result = true; @@ -679,20 +607,18 @@ App.WizardStep3Controller = Em.Controller.extend({ }, submit: function () { - if (!this.get('isSubmitDisabled')) { - if(this.get('isHostHaveWarnings')) { - var self = this; - App.showConfirmationPopup( - function(){ - self.set('content.hosts', self.get('bootHosts')); - App.router.send('next'); - }, - Em.I18n.t('installer.step3.hostWarningsPopup.hostHasWarnings')); - } - else { - this.set('content.hosts', this.get('bootHosts')); - App.router.send('next'); - } + if (this.get('isHostHaveWarnings')) { + var self = this; + App.showConfirmationPopup( + function () { + self.set('content.hosts', self.get('bootHosts')); + App.router.send('next'); + }, + Em.I18n.t('installer.step3.hostWarningsPopup.hostHasWarnings')); + } + else { + this.set('content.hosts', this.get('bootHosts')); + App.router.send('next'); } }, @@ -1369,13 +1295,6 @@ App.WizardStep3Controller = Em.Controller.extend({ registeredHosts: self.get('registeredHosts') }) }) - }, - - back: function () { - if (this.get('isRegistrationInProgress')) { - return; - } - App.router.send('back'); } }); http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index c4c1440..fbe3880 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -531,6 +531,8 @@ Em.I18n.translations = { 'installer.step3.hosts.bootLog.registering':'\nRegistering with the server...', 'installer.step3.hostLogPopup.highlight':'click to highlight', 'installer.step3.hostLogPopup.copy':'press CTRL+C', + 'installer.step3.hostsTable.selectAll':'Select All Hosts', + 'installer.step3.selectedHosts.popup.header':'Selected Hosts', 'installer.step4.header':'Choose Services', 'installer.step4.body':'Choose which services you want to install on your cluster.', http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 6087d93..ac93e5d 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -414,6 +414,19 @@ h1 { } } #confirm-hosts { + table { + margin-bottom: 0; + td { + input[type="checkbox"] { + margin-left: 15px; + } + } + th { + input[type="checkbox"] { + margin: 0; + } + } + } #host-filter { margin-top: 3px; ul { @@ -437,6 +450,12 @@ h1 { } } } + .page-bar { + padding: 5px; + .selected-hosts-info { + margin: 0; + } + } .progress { margin-bottom: 0; } http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/templates/common/items_list_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/items_list_popup.hbs b/ambari-web/app/templates/common/items_list_popup.hbs new file mode 100644 index 0000000..6544a1b --- /dev/null +++ b/ambari-web/app/templates/common/items_list_popup.hbs @@ -0,0 +1,21 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you 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. +}} + +{{#each item in view.items}} + <p>{{item}}</p> +{{/each}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/templates/wizard/step2_host_name_pattern_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/wizard/step2_host_name_pattern_popup.hbs b/ambari-web/app/templates/wizard/step2_host_name_pattern_popup.hbs deleted file mode 100644 index 66e7f48..0000000 --- a/ambari-web/app/templates/wizard/step2_host_name_pattern_popup.hbs +++ /dev/null @@ -1,21 +0,0 @@ -{{! -* Licensed to the Apache Software Foundation (ASF) under one -* or more contributor license agreements. See the NOTICE file -* distributed with this work for additional information -* regarding copyright ownership. The ASF licenses this file -* to you 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. -}} - -{{#each host in view.hostNames}} - <p>{{host}}</p> -{{/each}} http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/templates/wizard/step3.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/wizard/step3.hbs b/ambari-web/app/templates/wizard/step3.hbs index 2b6fb18..5b8bdad 100644 --- a/ambari-web/app/templates/wizard/step3.hbs +++ b/ambari-web/app/templates/wizard/step3.hbs @@ -23,11 +23,11 @@ <div class="box"> <div class="box-header"> <div class="button-section"> - <a class="btn btn-primary" {{bindAttr disabled="noHostsSelected"}} - href="#" {{action removeSelectedHosts target="controller" }}><i + <button class="btn btn-primary" {{bindAttr disabled="view.noHostsSelected"}} + {{action removeSelectedHosts target="controller" }}><i class="icon-trash icon-white"></i> {{t installer.step3.removeSelected}} - </a> + </button> {{#unless isRetryDisabled}} <a class="btn btn-primary decommission" href="#" {{action retrySelectedHosts target="controller"}}><i @@ -39,9 +39,9 @@ <div id="host-filter" class="pull-right"> <ul class="clearfix"> <li class="first">{{t common.show}}:</li> - {{#each category in controller.categories}} + {{#each category in view.categories}} <li {{bindAttr class="category.itemClass"}}> - <a {{action selectCategory category target="controller"}} href="#"> + <a {{action selectCategory category target="view"}} href="#"> {{category.label}} </a> </li> @@ -54,64 +54,96 @@ </div> </div> - <div class="pre-scrollable" style="max-height: 440px;"> - <table class="table table-bordered table-striped"> - <thead> - <tr> - <th class="span1">{{view Ember.Checkbox checkedBinding="allChecked"}}</th> - <th class="span3">{{t common.host}}</th> - <!-- retrieved from local storage initially --> - <th class="span3">{{t common.progress}}</th> - <th class="span2">{{t common.status}}</th> - <!-- given by the parsing function that parses data from bootstrap call, dynamically assign the color --> - <th class="span3">{{t common.action}}</th> - <!-- trash icon --> - <!-- retry icon --> - </tr> - </thead> - - <tbody> - {{#each host in hosts}} - {{#view App.WizardHostView categoryBinding="controller.category" hostInfoBinding="host"}} - <td> - {{view Ember.Checkbox checkedBinding="host.isChecked"}} - </td> - <td> - {{host.name}} - </td> - <td> - <div {{bindAttr class="host.bootBarColor host.isBootDone::progress-striped host.isBootDone::active :progress"}}> - <div class="bar" style="width:100%"> - </div> + <div class="pre-scrollable" style="max-height: 440px;"> + <table class="table table-bordered table-striped"> + <thead> + <tr> + <th class="span1"> + <div class="btn-group"> + <a class="btn"> + {{view Ember.Checkbox checkedBinding="view.pageChecked"}} + </a> + <button class="btn dropdown-toggle" data-toggle="dropdown"> + <span class="caret"></span> + </button> + <ul class="dropdown-menu"> + <li> + <a {{action selectAll target="view"}}>{{t installer.step3.hostsTable.selectAll}}</a> + </li> + </ul> + </div> + </th> + <th class="span3">{{t common.host}}</th> + <!-- retrieved from local storage initially --> + <th class="span3">{{t common.progress}}</th> + <th class="span2">{{t common.status}}</th> + <!-- given by the parsing function that parses data from bootstrap call, dynamically assign the color --> + <th class="span3">{{t common.action}}</th> + <!-- trash icon --> + <!-- retry icon --> + </tr> + </thead> + <tbody> + {{#if view.pageContent}} + {{#each host in view.pageContent}} + {{#view App.WizardHostView categoryBinding="controller.category" hostInfoBinding="host"}} + <td> + {{view Ember.Checkbox checkedBinding="host.isChecked"}} + </td> + <td> + {{host.name}} + </td> + <td> + <div {{bindAttr class="host.bootBarColor host.isBootDone::progress-striped host.isBootDone::active :progress"}}> + <div class="bar" style="width:100%"> + </div> + </div> + </td> + <td> + <a href="javascript:void(null)" + data-toggle="modal" {{action hostLogPopup host target="controller"}}><span {{bindAttr class="host.bootStatusColor"}}>{{host.bootStatusForDisplay}}</span></a> + </td> + <td> + {{#if view.isRemovable}}<a class="btn btn-mini" {{action remove target="view"}}><i + class="icon-trash"></i> + {{t common.remove}}</a>{{/if}} + {{#if view.isRetryable}}<a class="btn btn-mini" {{action retry target="view"}}><i + class="icon-repeat"></i> + {{t common.retry}}</a>{{/if}} + </td> + {{/view}} + {{/each}} + {{else}} + <tr> + <td colspan="5"> + {{t hosts.table.noHosts}} + </td> + </tr> + {{/if}} + </tbody> + </table> + </div> + <div id="hosts"> + <div class="page-bar"> + <div class="selected-hosts-info span6"> + {{#if view.selectedHostsCount}} + <a {{action selectedHostsPopup target="controller"}} href="#"> + {{view.selectedHostsCount}} + {{pluralize view.selectedHostsCount singular="t:hosts.filters.selectedHostInfo" plural="t:hosts.filters.selectedHostsInfo"}} + </a> + - + <a {{action unSelectAll target="view"}} href="#">{{t hosts.filters.clearSelection}}</a> + {{/if}} + </div> + <div class="info">{{view.paginationInfo}}</div> + <div class="paging_two_button"> + {{view view.paginationFirst}} + {{view view.paginationLeft}} + {{view view.paginationRight}} + {{view view.paginationLast}} + </div> </div> - </td> - <td> - <a href="javascript:void(null)" - data-toggle="modal" {{action hostLogPopup host target="controller"}}><span {{bindAttr class="host.bootStatusColor"}}>{{host.bootStatusForDisplay}}</span></a> - </td> - <td> - {{#if view.isRemovable}}<a class="btn btn-mini" {{action remove target="view"}}><i class="icon-trash"></i> - {{t common.remove}}</a>{{/if}} - {{#if view.isRetryable}}<a class="btn btn-mini" {{action retry target="view"}}><i class="icon-repeat"></i> - {{t common.retry}}</a>{{/if}} - </td> - {{/view}} - {{/each}} - {{#unless visibleHosts.length}} - <tr> - <td colspan="5"><p>{{t installer.step3.hosts.noHosts}}</p></td> - </tr> - {{/unless}} - - </tbody> - - </table> - </div> - <div class="box-footer"> - <hr/> - <div class="footer-pagination"> </div> - </div> </div> {{#if hasMoreRegisteredHosts}} <div {{bindAttr class=":alert alert-warn"}}> @@ -126,7 +158,7 @@ {{/unless}} </div> <div class="btn-area"> - <a class="btn pull-left" {{bindAttr disabled="isRegistrationInProgress"}} {{action back target="controller"}}>← {{t common.back}}</a> - <a class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} →</a> + <button class="btn pull-left" {{bindAttr disabled="isRegistrationInProgress"}} {{action back}}>← {{t common.back}}</button> + <button class="btn btn-success pull-right" {{bindAttr disabled="isSubmitDisabled"}} {{action submit target="controller"}}>{{t common.next}} →</button> </div> </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/views/common/table_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/table_view.js b/ambari-web/app/views/common/table_view.js index ffb73f7..ef65cca 100644 --- a/ambari-web/app/views/common/table_view.js +++ b/ambari-web/app/views/common/table_view.js @@ -47,6 +47,21 @@ App.TableView = Em.View.extend(App.UserPref, { displayLengthOnLoad: null, /** + * The number of rows to show on every page + * The value should be a number converted into string type in order to support select element API + * Example: "10", "25" + * @type {String} + */ + displayLength: null, + + /** + * default value of display length + * The value should be a number converted into string type in order to support select element API + * Example: "10", "25" + */ + defaultDisplayLength: "10", + + /** * Do filtering, using saved in the local storage filter conditions */ willInsertElement:function () { @@ -54,12 +69,14 @@ App.TableView = Em.View.extend(App.UserPref, { var name = this.get('controller.name'); this.set('startIndexOnLoad', App.db.getStartIndex(name)); - if (App.db.getDisplayLength(name)) { - this.set('displayLength', App.db.getDisplayLength(name)); - } else { - self.dataLoading().done(function (initValue) { - self.set('displayLength', initValue); - }); + if (!this.get('displayLength')) { + if (App.db.getDisplayLength(name)) { + this.set('displayLength', App.db.getDisplayLength(name)); + } else { + self.dataLoading().done(function (initValue) { + self.set('displayLength', initValue); + }); + } } var filterConditions = App.db.getFilterConditions(name); @@ -130,7 +147,7 @@ App.TableView = Em.View.extend(App.UserPref, { getUserPrefErrorCallback: function () { // this user is first time login console.log('Persist did NOT find the key'); - var displayLengthDefault = "10"; + var displayLengthDefault = this.get('defaultDisplayLength'); this.set('displayLengthOnLoad', displayLengthDefault); if (App.get('isAdmin')) { this.postUserPref(this.displayLengthKey(), displayLengthDefault); @@ -173,7 +190,9 @@ App.TableView = Em.View.extend(App.UserPref, { }.property("parentView.startIndex", 'filteredContent.length'), click: function () { - this.get('parentView').previousPage(); + if (this.get('class') === "paginate_previous") { + this.get('parentView').previousPage(); + } } }), @@ -189,7 +208,45 @@ App.TableView = Em.View.extend(App.UserPref, { }.property("parentView.endIndex", 'filteredContent.length'), click: function () { - this.get('parentView').nextPage(); + if (this.get('class') === "paginate_next") { + this.get('parentView').nextPage(); + } + } + }), + + paginationFirst: Ember.View.extend({ + tagName: 'a', + template: Ember.Handlebars.compile('<i class="icon-step-backward"></i>'), + classNameBindings: ['class'], + class: function () { + if ((this.get("parentView.endIndex")) > parseInt(this.get("parentView.displayLength"))) { + return "paginate_previous"; + } + return "paginate_disabled_previous"; + }.property("parentView.endIndex", 'filteredContent.length'), + + click: function () { + if (this.get('class') === "paginate_previous") { + this.get('parentView').firstPage(); + } + } + }), + + paginationLast: Ember.View.extend({ + tagName: 'a', + template: Ember.Handlebars.compile('<i class="icon-step-forward"></i>'), + classNameBindings: ['class'], + class: function () { + if (this.get("parentView.endIndex") !== this.get("parentView.filteredContent.length")) { + return "paginate_next"; + } + return "paginate_disabled_next"; + }.property("parentView.endIndex", 'filteredContent.length'), + + click: function () { + if (this.get('class') === "paginate_next") { + this.get('parentView').lastPage(); + } } }), @@ -233,12 +290,22 @@ App.TableView = Em.View.extend(App.UserPref, { this.set('startIndex', result); } }, - /** - * The number of rows to show on every page - * @type {Number} + * Onclick handler for first page button on the page */ - displayLength: null, + firstPage: function () { + this.set('startIndex', 1); + }, + /** + * Onclick handler for last page button on the page + */ + lastPage: function () { + var pagesCount = this.get('filteredContent.length') / parseInt(this.get('displayLength')); + var startIndex = (this.get('filteredContent.length') % parseInt(this.get('displayLength')) === 0) ? + (pagesCount - 1) * parseInt(this.get('displayLength')) : + Math.floor(pagesCount) * parseInt(this.get('displayLength')); + this.set('startIndex', ++startIndex); + }, /** * Calculates default value for startIndex property after applying filter or changing displayLength http://git-wip-us.apache.org/repos/asf/ambari/blob/74ef9620/ambari-web/app/views/wizard/step3_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/wizard/step3_view.js b/ambari-web/app/views/wizard/step3_view.js index 3211e6d..f953e68 100644 --- a/ambari-web/app/views/wizard/step3_view.js +++ b/ambari-web/app/views/wizard/step3_view.js @@ -19,25 +19,148 @@ var App = require('app'); -App.WizardStep3View = Em.View.extend({ +App.WizardStep3View = App.TableView.extend({ templateName: require('templates/wizard/step3'), - category: '', - didInsertElement: function () { - this.get('controller').loadStep(); - }, + content:function () { + return this.get('controller.hosts'); + }.property('controller.hosts.length'), message:'', linkText: '', status: '', + selectedCategory: function() { + return this.get('categories').findProperty('isActive'); + }.property('[email protected]'), + registeredHostsMessage: '', + displayLength: "20", + + didInsertElement: function () { + this.get('controller').loadStep(); + }, + + pageChecked: false, + + /** + * select checkboxes of hosts on page + */ + onPageChecked: function () { + if (this.get('selectionInProgress')) return; + this.get('pageContent').setEach('isChecked', this.get('pageChecked')); + }.observes('pageChecked'), + + /** + * select checkboxes of all hosts + */ + selectAll: function () { + this.get('content').setEach('isChecked', true); + }, + + /** + * reset checkbox of all hosts + */ + unSelectAll: function() { + this.get('content').setEach('isChecked', false); + }, + + watchSelectionOnce: function(){ + Em.run.once(this, 'watchSelection'); + }.observes('[email protected]'), + + /** + * watch selection and calculate flags as: + * - noHostsSelected + * - selectedHostsCount + * - pageChecked + */ + watchSelection: function() { + this.set('selectionInProgress', true); + this.set('pageChecked', !!this.get('pageContent.length') && this.get('pageContent').everyProperty('isChecked', true)); + this.set('selectionInProgress', false); + var noHostsSelected = true; + var selectedHostsCount = 0; + this.get('content').forEach(function(host){ + selectedHostsCount += ~~host.get('isChecked'); + noHostsSelected = (noHostsSelected) ? !host.get('isChecked') : noHostsSelected; + }); + this.set('noHostsSelected', noHostsSelected); + this.set('selectedHostsCount', selectedHostsCount); + }, + setRegisteredHosts: function(){ this.set('registeredHostsMessage',Em.I18n.t('installer.step3.warning.registeredHosts').format(this.get('controller.registeredHosts').length)); }.observes('controller.registeredHosts'), + categoryObject: Em.Object.extend({ + hostsCount: 0, + label: function () { + return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount')); + }.property('value', 'hostsCount'), + isActive: false, + itemClass: function () { + return this.get('isActive') ? 'active' : ''; + }.property('isActive') + }), + + categories: function () { + return [ + this.categoryObject.create({value: Em.I18n.t('common.all'), hostsBootStatus: 'ALL', isActive: true}), + this.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.installing'), hostsBootStatus: 'RUNNING'}), + this.categoryObject.create({value: Em.I18n.t('installer.step3.hosts.status.registering'), hostsBootStatus: 'REGISTERING'}), + this.categoryObject.create({value: Em.I18n.t('common.success'), hostsBootStatus: 'REGISTERED' }), + this.categoryObject.create({value: Em.I18n.t('common.fail'), hostsBootStatus: 'FAILED', last: true }) + ]; + }.property(), + + countCategoryHosts: function () { + var counters = { + "RUNNING": 0, + "REGISTERING": 0, + "REGISTERED": 0, + "FAILED": 0 + }; + this.get('content').forEach(function (host) { + if (counters[host.get('bootStatus')] !== undefined) { + counters[host.get('bootStatus')]++; + } + }, this); + counters["ALL"] = this.get('content.length'); + this.get('categories').forEach(function(category) { + category.set('hostsCount', counters[category.get('hostsBootStatus')]); + }, this); + }.observes('[email protected]'), + + + /** + * filter hosts by category + */ + filter: function () { + var result = []; + var selectedCategory = this.get('selectedCategory'); + if (!selectedCategory || selectedCategory.get('hostsBootStatus') === 'ALL') { + result = this.get('content'); + } else { + result = this.get('content').filterProperty('bootStatus', this.get('selectedCategory.hostsBootStatus')); + } + this.set('filteredContent', result); + }.observes('[email protected]', 'selectedCategory'), + /** + * Trigger on Category click + * @param {Object} event + */ + selectCategory: function (event) { + var categoryStatus = event.context.get('hostsBootStatus'); + var self = this; + this.get('categories').forEach(function (category) { + category.set('isActive', (category.get('hostsBootStatus') === categoryStatus)); + }); + this.watchSelection(); + }, + monitorStatuses: function() { var hosts = this.get('controller.bootHosts'); var failedHosts = hosts.filterProperty('bootStatus', 'FAILED').length;
