Return-Path: X-Original-To: apmail-ambari-commits-archive@www.apache.org Delivered-To: apmail-ambari-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 5C9B210644 for ; Tue, 14 Jan 2014 12:02:39 +0000 (UTC) Received: (qmail 60771 invoked by uid 500); 14 Jan 2014 12:02:38 -0000 Delivered-To: apmail-ambari-commits-archive@ambari.apache.org Received: (qmail 60710 invoked by uid 500); 14 Jan 2014 12:02:38 -0000 Mailing-List: contact commits-help@ambari.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: ambari-dev@ambari.apache.org Delivered-To: mailing list commits@ambari.apache.org Received: (qmail 60703 invoked by uid 99); 14 Jan 2014 12:02:38 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 14 Jan 2014 12:02:38 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 015808BC90D; Tue, 14 Jan 2014 12:02:37 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: onechiporenko@apache.org To: commits@ambari.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: git commit: AMBARI-4284. Alerts, Restart, Maintenance elements in the Hosts filters. (onechiporenko) Date: Tue, 14 Jan 2014 12:02:37 +0000 (UTC) Updated Branches: refs/heads/trunk b1d187fb2 -> 122dc8397 AMBARI-4284. Alerts, Restart, Maintenance elements in the Hosts filters. (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/122dc839 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/122dc839 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/122dc839 Branch: refs/heads/trunk Commit: 122dc8397cf8d91aae315e64dbda5067825a1139 Parents: b1d187f Author: Oleg Nechiporenko Authored: Tue Jan 14 14:00:19 2014 +0200 Committer: Oleg Nechiporenko Committed: Tue Jan 14 14:00:19 2014 +0200 ---------------------------------------------------------------------- ambari-web/app/data/host/categories.js | 98 ++++++++++++ ambari-web/app/styles/application.less | 6 + ambari-web/app/templates/main/host.hbs | 20 +-- ambari-web/app/views/main/host.js | 221 ++++++++++++++++++---------- 4 files changed, 250 insertions(+), 95 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/122dc839/ambari-web/app/data/host/categories.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/host/categories.js b/ambari-web/app/data/host/categories.js new file mode 100644 index 0000000..857304d --- /dev/null +++ b/ambari-web/app/data/host/categories.js @@ -0,0 +1,98 @@ +/** + * 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. + */ + +module.exports = [ + { + value: Em.I18n.t('common.all'), + isHealthStatus: true, + healthStatusValue: '', + isActive: true, + isVisible: false + }, + { + value: Em.I18n.t('hosts.host.healthStatusCategory.green'), + isHealthStatus: true, + healthStatusValue: 'health-status-LIVE', + observes: 'view.content.@each.healthClass' + }, + { + value: Em.I18n.t('hosts.host.healthStatusCategory.red'), + isHealthStatus: true, + healthStatusValue: 'health-status-DEAD-RED', + observes: 'view.content.@each.healthClass' + }, + { + value: Em.I18n.t('hosts.host.healthStatusCategory.orange'), + isHealthStatus: true, + healthStatusValue: 'health-status-DEAD-ORANGE', + observes: 'view.content.@each.healthClass' + }, + { + value: Em.I18n.t('hosts.host.healthStatusCategory.yellow'), + isHealthStatus: true, + healthStatusValue: 'health-status-DEAD-YELLOW', + observes: 'view.content.@each.healthClass' + }, + { + value: Em.I18n.t('hosts.host.alerts.label'), + hostProperty: 'criticalAlertsCount', + class: 'label label-important alerts-status', + isHealthStatus: false, + healthStatusValue: 'health-status-WITH-ALERTS', + column: 7, + separator: true, + type: 'number', + filterValue: '>0', + observes: 'view.content.@each.criticalAlertsCount' + }, + { + value: Em.I18n.t('common.restart'), + hostProperty: 'componentsWithStaleConfigsCount', + class: 'icon-refresh', + isHealthStatus: false, + healthStatusValue: 'health-status-RESTART', + column: 8, + type: 'number', + filterValue: '>0', + observes: 'view.content.@each.componentsWithStaleConfigsCount' + }, + { + value: Em.I18n.t('common.selected'), + hostProperty: 'selected', + class: '', + isHealthStatus: false, + healthStatusValue: 'health-status-SELECTED', + selected: true, + column: 10, + type: 'boolean', + filterValue: true, + isVisible: false, + observes: 'view.content.@each.selected' + }, + { + value: Em.I18n.t('common.maintenance'), + hostProperty: 'componentsInMaintenanceCount', + class: 'maintenance icon-medkit', + isHealthStatus: false, + healthStatusValue: 'health-status-MAINTENANCE', + column: 9, + type: 'number', + filterValue: '>0', + observes: 'view.content.@each.componentsInMaintenanceCount' + } +]; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/122dc839/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index e919a43..006ab4e 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -2694,6 +2694,12 @@ table.graphs { .maintenance { color: #000; } + .alerts-status { + padding: 1px 6px !important; + &:before { + content: "!"; + } + } .host-name-search { position: relative; top: 0px; http://git-wip-us.apache.org/repos/asf/ambari/blob/122dc839/ambari-web/app/templates/main/host.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/host.hbs b/ambari-web/app/templates/main/host.hbs index 07002aa..37ed6d9 100644 --- a/ambari-web/app/templates/main/host.hbs +++ b/ambari-web/app/templates/main/host.hbs @@ -27,25 +27,17 @@ {{#view view.statusFilter categoriesBinding="view.categories"}} {{#each category in view.categories}} {{#if category.isVisible}} - {{#if category.alerts}} -

+ {{#if category.separator}} +

{{else}} - | + | {{/if}} - {{#if category.alerts}} - {{t hosts.host.alerts.st}} + {{#if category.isHealthStatus}} +     {{else}} - {{#if category.restart}} - - {{else}} - {{#if category.maintenance}} - - {{else}} -     - {{/if}} - {{/if}} + {{/if}} {{category.label}} http://git-wip-us.apache.org/repos/asf/ambari/blob/122dc839/ambari-web/app/views/main/host.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/host.js b/ambari-web/app/views/main/host.js index 1096f87..d52f9aa 100644 --- a/ambari-web/app/views/main/host.js +++ b/ambari-web/app/views/main/host.js @@ -23,6 +23,10 @@ var date = require('utils/date'); App.MainHostView = App.TableView.extend({ templateName:require('templates/main/host'), + /** + * List of hosts in cluster + * @type {Array} + */ content:function () { return this.get('controller.content'); }.property('controller.content.length'), @@ -53,7 +57,7 @@ App.MainHostView = App.TableView.extend({ /** * Select/deselect all visible hosts flag - * @property {bool} + * @property {Boolean} */ selectAllHosts: false, @@ -242,69 +246,139 @@ App.MainHostView = App.TableView.extend({ /** * Category view for all hosts + * @type {Object} */ + //@TODO maybe should be separated to two types (basing on isHealthStatus) categoryObject: Em.Object.extend({ - hostsCount: function () { + /** + * Text used with hostsCount in category label + * @type {String} + */ + value: null, + /** + * Is category based on host health status + * @type {Boolean} + */ + isHealthStatus: true, + /** + * host health status (used if isHealthStatus is true) + * @type {String} + */ + healthStatusValue: '', + /** + * Should category be displayed on the top of the hosts table + * @type {Boolean} + */ + isVisible: true, + /** + * Is category selected now + * @type {Boolean} + */ + isActive: false, + /** + * String with path that category should observe + * @type {String} + */ + observes: null, + /** + * CSS-class for span in the category-link (used if isHealthStatus is false) + * @type {String} + */ + class: null, + /** + * Associated column number + * @type {Number} + */ + column: null, + /** + * Type of filter value (string, number, boolean) + * @type {String} + */ + type: null, + /** + * @type {String|Number|Boolean} + */ + filterValue: null, + /** + * Should new line be inserted after this category + * @type {Boolean} + */ + separator: false, + + /** + * App.Host property that should be used to calculate hostsCount (used if isHealthStatus is false) + * @type {String} + */ + hostProperty: null, + + /** + * Number of host in current category + * @type {Number} + */ + hostsCount: 0, + + /** + * Add "active" class for category span-wrapper if current category is selected + * @type {String} + */ + itemClass: function() { + return this.get('isActive') ? 'active' : ''; + }.property('isActive'), + + /** + * Trigger updating hostsCount only 1 time + */ + updateHostsCount: function() { + Em.run.once(this, 'updateOnce'); + }, + /** + * Update hostsCount in current category + */ + updateOnce: function() { var statusString = this.get('healthStatusValue'); - var alerts = this.get('alerts'); - var restart = this.get('restart'); - var maintenance = this.get('maintenance'); - var selected = this.get('selected'); - if(alerts) { - return this.get('view.content').filterProperty('criticalAlertsCount').get('length'); - } - else { - if (restart) { - return this.get('view.content').filterProperty('componentsWithStaleConfigsCount').get('length'); + if (this.get('isHealthStatus')) { + if (statusString == "") { + this.set('hostsCount', this.get('view.content').get('length')); } else { - if (maintenance) { - return this.get('view.content').filterProperty('componentsInMaintenanceCount').get('length'); - } - else { - if (selected) { - return this.get('view.content').filterProperty('selected').get('length'); - } - else { - if (statusString == "") { - return this.get('view.content').get('length'); - } - else { - return this.get('view.content').filterProperty('healthClass', statusString ).get('length'); - } - } - } + this.set('hostsCount', this.get('view.content').filterProperty('healthClass', statusString).get('length')); } } - }.property('view.content.@each.selected', 'view.content.@each.healthClass', 'view.content.@each.criticalAlertsCount', 'view.content.@each.componentsInMaintenanceCount', 'view.content.@each.componentsWithStaleConfigsCount'), + else { + this.set('hostsCount', this.get('view.content').filterProperty(this.get('hostProperty')).get('length')); + } + }, + /** + * Text shown on the right of category icon + * @type {String} + */ label: function () { return "%@ (%@)".fmt(this.get('value'), this.get('hostsCount')); }.property('hostsCount') }), + /** + * List of categories used to filter hosts + * @type {Array} + */ categories: function () { var self = this; self.categoryObject.reopen({ - view: self, - isActive: false, - itemClass: function() { - return this.get('isActive') ? 'active' : ''; - }.property('isActive') + view: self }); - return [ - self.categoryObject.create({value: Em.I18n.t('common.all'), healthStatusValue: '', isActive: true, isVisible: false}), - self.categoryObject.create({value: Em.I18n.t('hosts.host.healthStatusCategory.green'), healthStatusValue: 'health-status-LIVE', isVisible: true}), - self.categoryObject.create({value: Em.I18n.t('hosts.host.healthStatusCategory.red'), healthStatusValue: 'health-status-DEAD-RED', isVisible: true}), - self.categoryObject.create({value: Em.I18n.t('hosts.host.healthStatusCategory.orange'), healthStatusValue: 'health-status-DEAD-ORANGE', isVisible: true}), - self.categoryObject.create({value: Em.I18n.t('hosts.host.healthStatusCategory.yellow'), healthStatusValue: 'health-status-DEAD-YELLOW', isVisible: true}), - self.categoryObject.create({value: Em.I18n.t('hosts.host.alerts.label'), healthStatusValue: 'health-status-WITH-ALERTS', alerts: true, isVisible: true }), - self.categoryObject.create({value: Em.I18n.t('common.restart'), healthStatusValue: 'health-status-RESTART', restart: true, isVisible: true }), - self.categoryObject.create({value: Em.I18n.t('common.selected'), healthStatusValue: 'health-status-SELECTED', selected: true, isVisible: false }), - self.categoryObject.create({value: Em.I18n.t('common.maintenance'), healthStatusValue: 'health-status-MAINTENANCE', maintenance: true, last: true, isVisible: true }) - ]; + var category_mocks = require('data/host/categories'); + + return category_mocks.map(function(category_mock) { + var c = self.categoryObject.create(category_mock); + if (c.get('observes')) { + c.addObserver(c.get('observes'), c, c.updateHostsCount); + c.updateHostsCount(); + } + return c; + }); }.property(), /** @@ -321,59 +395,40 @@ App.MainHostView = App.TableView.extend({ /** * switch active category label */ - onCategoryChange: function(){ + onCategoryChange: function() { this.get('categories').setEach('isActive', false); this.get('categories').findProperty('healthStatusValue', this.get('value')).set('isActive', true); }.observes('value'), + showClearFilter: function(){ var mockEvent = { context: this.get('categories').findProperty('healthStatusValue', this.get('value')) }; this.selectCategory(mockEvent); }, + /** + * Trigger on Category click + * @param {Object} event + */ selectCategory: function(event){ var category = event.context; + var self = this; this.set('value', category.get('healthStatusValue')); - if(category.get('alerts')) { - this.get('parentView').updateFilter(0, '', 'string'); - this.get('parentView').updateFilter(7, '>0', 'number'); - this.get('parentView').updateFilter(8, '', 'number'); - this.get('parentView').updateFilter(9, '', 'number'); - this.get('parentView').updateFilter(10, '', 'boolean'); + if (category.get('isHealthStatus')) { + this.get('parentView').updateFilter(0, category.get('healthStatusValue'), 'string'); + this.get('categories').filterProperty('isHealthStatus', false).forEach(function(c) { + self.get('parentView').updateFilter(c.get('column'), '', c.get('type')); + }); } else { - if(category.get('restart')) { - this.get('parentView').updateFilter(0, '', 'string'); - this.get('parentView').updateFilter(7, '', 'number'); - this.get('parentView').updateFilter(8, '>0', 'number'); - this.get('parentView').updateFilter(9, '', 'number'); - this.get('parentView').updateFilter(10, '', 'boolean'); - } - else { - if(category.get('maintenance')) { - this.get('parentView').updateFilter(0, '', 'string'); - this.get('parentView').updateFilter(7, '', 'number'); - this.get('parentView').updateFilter(8, '', 'number'); - this.get('parentView').updateFilter(9, '>0', 'number'); - this.get('parentView').updateFilter(10, '', 'boolean'); + this.get('categories').filterProperty('isHealthStatus', false).forEach(function(c) { + if (c.get('column') === category.get('column')) { + self.get('parentView').updateFilter(category.get('column'), category.get('filterValue'), category.get('type')); } else { - if(category.get('selected')) { - this.get('parentView').updateFilter(0, '', 'string'); - this.get('parentView').updateFilter(7, '', 'number'); - this.get('parentView').updateFilter(8, '', 'number'); - this.get('parentView').updateFilter(9, '', 'number'); - this.get('parentView').updateFilter(10, true, 'boolean'); - } - else { - this.get('parentView').updateFilter(0, category.get('healthStatusValue'), 'string'); - this.get('parentView').updateFilter(7, '', 'number'); - this.get('parentView').updateFilter(8, '', 'number'); - this.get('parentView').updateFilter(9, '', 'number'); - this.get('parentView').updateFilter(10, '', 'boolean'); - } + self.get('parentView').updateFilter(c.get('column'), '', c.get('type')); } - } + }); } }, clearFilter: function() { @@ -434,6 +489,9 @@ App.MainHostView = App.TableView.extend({ } }), + /** + * view of the "selected" filter implemented as a category of host statuses + */ selectedFilter: Em.View.extend({ column: 10, value: null, @@ -631,6 +689,7 @@ App.MainHostView = App.TableView.extend({ /** * associations between host property and column index + * @type {Array} */ colPropAssoc: function(){ var associations = [];