Repository: ambari Updated Branches: refs/heads/branch-2.2 87604be7f -> 492d47278
AMBARI-14683 .Add Filter in Alert instances table (onechiporenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/492d4727 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/492d4727 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/492d4727 Branch: refs/heads/branch-2.2 Commit: 492d47278cb1242d061bff39655add67dc4bdfe4 Parents: 87604be Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Fri Jan 15 12:34:53 2016 +0200 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Fri Jan 29 12:28:26 2016 +0200 ---------------------------------------------------------------------- ambari-web/app/styles/alerts.less | 14 +- .../main/alerts/definition_details.hbs | 30 ++- ambari-web/app/views/common/filter_view.js | 224 ++++++++----------- .../app/views/main/alert_definitions_view.js | 26 +-- .../main/alerts/definition_details_view.js | 101 ++++++++- .../test/views/common/filter_view_test.js | 76 +++++++ 6 files changed, 310 insertions(+), 161 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/app/styles/alerts.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/alerts.less b/ambari-web/app/styles/alerts.less index 727df04..2eabbe2 100644 --- a/ambari-web/app/styles/alerts.less +++ b/ambari-web/app/styles/alerts.less @@ -155,24 +155,30 @@ .col0, td:first-child, th:first-child { - width: 30%; + width: 10%; } .col1, td:first-child + td, th:first-child + th { - width: 23%; + width: 20%; } .col2, td:first-child + td + td, th:first-child + th + th { - width: 7% + width: 23%; } .col3, td:first-child + td + td + td, th:first-child + th + th + th { + width: 7%; + } + + .col4, + td:first-child + td + td + td + td, + th:first-child + th + th + th + th { width: 40%; } @@ -195,7 +201,7 @@ margin: 5px; } } - margin-bottom: 0px; + margin-bottom: 0; } .definition-details-block { margin-top: 30px; http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/app/templates/main/alerts/definition_details.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/alerts/definition_details.hbs b/ambari-web/app/templates/main/alerts/definition_details.hbs index 1c2605d..a56890c 100644 --- a/ambari-web/app/templates/main/alerts/definition_details.hbs +++ b/ambari-web/app/templates/main/alerts/definition_details.hbs @@ -181,11 +181,19 @@ <table class="table advanced-header-table table-bordered table-striped alerts-table" id="alert-instances-table"> <thead> - <tr> - <th class="first">{{t alerts.definition.details.serviceHost}}</th> - <th>{{t common.status}}</th> + {{#view view.sortView classNames="label-row" contentBinding="view.filteredContent"}} + {{view view.parentView.serviceSort class="first service-sorting"}} + {{view view.parentView.hostNameSort class="host-sorting"}} + {{view view.parentView.stateSort class="state-sorting"}} <th>{{t alerts.definition.details.24-hour}}</th> <th>{{t alerts.table.header.check.response}}</th> + {{/view}} + <tr class="filter-row"> + <th class="first">{{view view.serviceFilterView}}</th> + <th>{{view view.hostNameFilterView}}</th> + <th>{{view view.stateFilterView }}</th> + <th>{{!}}</th> + <th>{{!}}</th> </tr> </thead> <tbody> @@ -193,7 +201,21 @@ {{#each instance in view.pageContent}} {{#view view.instanceTableRow}} <td class="first"> - {{view App.AlertInstanceServiceHostView instanceBinding="instance"}} + {{#if instance.serviceDisplayName}} + {{#if instance.service.isLoaded}} + <a {{action goToService instance.service target="view"}} + href="#">{{instance.serviceDisplayName}}</a> + {{else}} + {{instance.serviceDisplayName}} + {{/if}} + {{/if}} + </td> + <td> + {{#if instance.hostName}} + <a {{action goToHostAlerts instance.host target="view"}} href="#"> + {{instance.hostName}} + </a> + {{/if}} </td> <td>{{{instance.status}}} <time class="timeago" http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/app/views/common/filter_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/filter_view.js b/ambari-web/app/views/common/filter_view.js index f1f18d8..21c8c0e 100644 --- a/ambari-web/app/views/common/filter_view.js +++ b/ambari-web/app/views/common/filter_view.js @@ -186,7 +186,7 @@ var wrapperView = Ember.View.extend({ $optionEl.text(triggeredValue.displayAs); // the second one option should be hidden // as the result, on init stage we show only one option that could be selected - if (index == 1) { + if (index === 1) { $optionEl.css('display', 'none'); } }, this); @@ -207,7 +207,7 @@ var wrapperView = Ember.View.extend({ var currentValueIndex = values.indexOf(this.get('value')); if (currentValueIndex < 0) return; // value assigned to hidden option - hiddenValue = values[Number(currentValueIndex == 0)]; + hiddenValue = values[Number(currentValueIndex === 0)]; }, this); if (hiddenValue) { // our select @@ -282,7 +282,7 @@ var componentFieldView = Ember.View.extend({ var dropDown = this.$('.filter-components'); var firstClick = true; $(document).bind('click', function (e) { - if (!firstClick && $(e.target).closest(dropDown).length == 0) { + if (!firstClick && !$(e.target).closest(dropDown).length) { self.set('isFilterOpen', false); $(document).unbind('click'); } @@ -382,194 +382,148 @@ module.exports = { return function (rowValue, rangeExp) { var compareChar = isNaN(rangeExp.charAt(0)) ? rangeExp.charAt(0) : false; var compareScale = rangeExp.charAt(rangeExp.length - 1); - var compareValue = compareChar ? parseFloat(rangeExp.substr(1, rangeExp.length)) : parseFloat(rangeExp.substr(0, rangeExp.length)); - var match = false; - if (rangeExp.length == 1 && compareChar !== false) { + var compareValue = parseFloat(rangeExp.substr(compareChar ? 1 : 0)); + if (rangeExp.length === 1 && compareChar !== false) { // User types only '=' or '>' or '<', so don't filter column values - match = true; - return match; - } - switch (compareScale) { - case 'g': - compareValue *= 1073741824; - break; - case 'm': - compareValue *= 1048576; - break; - case 'k': - compareValue *= 1024; - break; - default: - //default value in GB - compareValue *= 1073741824; + return true; } - rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue; + var oneSymbolScales = { + k: 1024, + m: 1048576, + g: 1073741824 + }; + var twoSymbolsScales = { + KB: 1024, + MB: 1048576, + GB: 1073741824 + }; + + compareValue *= oneSymbolScales[compareScale] ? oneSymbolScales[compareScale] : oneSymbolScales.g; // default value in GB + rowValue = jQuery(rowValue).text() ? jQuery(rowValue).text() : rowValue; var convertedRowValue; if (rowValue === '<1KB') { convertedRowValue = 1; } else { var rowValueScale = rowValue.substr(rowValue.length - 2, 2); - switch (rowValueScale) { - case 'KB': - convertedRowValue = parseFloat(rowValue) * 1024; - break; - case 'MB': - convertedRowValue = parseFloat(rowValue) * 1048576; - break; - case 'GB': - convertedRowValue = parseFloat(rowValue) * 1073741824; - break; + if (twoSymbolsScales[rowValueScale]) { + convertedRowValue = parseFloat(rowValue) * twoSymbolsScales[rowValueScale]; } } switch (compareChar) { case '<': - if (compareValue > convertedRowValue) match = true; - break; + return compareValue > convertedRowValue; case '>': - if (compareValue < convertedRowValue) match = true; - break; + return compareValue < convertedRowValue; case false: case '=': - if (compareValue == convertedRowValue) match = true; - break; + return compareValue === convertedRowValue; + default: + return false; } - return match; }; - break; case 'duration': return function (rowValue, rangeExp) { var compareChar = isNaN(rangeExp.charAt(0)) ? rangeExp.charAt(0) : false; var compareScale = rangeExp.charAt(rangeExp.length - 1); - var compareValue = compareChar ? parseFloat(rangeExp.substr(1, rangeExp.length)) : parseFloat(rangeExp.substr(0, rangeExp.length)); - var match = false; - if (rangeExp.length == 1 && compareChar !== false) { + var compareValue = parseFloat(rangeExp.substr(compareChar ? 1 : 0)); + if (rangeExp.length === 1 && compareChar !== false) { // User types only '=' or '>' or '<', so don't filter column values - match = true; - return match; - } - switch (compareScale) { - case 's': - compareValue *= 1000; - break; - case 'm': - compareValue *= 60000; - break; - case 'h': - compareValue *= 3600000; - break; - default: - compareValue *= 1000; + return true; } - rowValue = (jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue; + var oneSymbolsScales = { + s: 1000, + m: 60000, + h: 3600000 + }; + compareValue *= oneSymbolsScales[compareScale] ? oneSymbolsScales[compareScale] : oneSymbolsScales.s; + rowValue = jQuery(rowValue).text() ? jQuery(rowValue).text() : rowValue; switch (compareChar) { case '<': - if (compareValue > rowValue) match = true; - break; + return compareValue > rowValue; case '>': - if (compareValue < rowValue) match = true; - break; + return compareValue < rowValue; case false: case '=': - if (compareValue == rowValue) match = true; - break; + return compareValue == rowValue; } - return match; + return false; }; - break; case 'date': return function (rowValue, rangeExp) { - var match = false; var timePassed = App.dateTime() - rowValue; switch (rangeExp) { case 'Past 1 hour': - match = timePassed <= 3600000; - break; + return timePassed <= 3600000; case 'Past 1 Day': - match = timePassed <= 86400000; - break; + return timePassed <= 86400000; case 'Past 2 Days': - match = timePassed <= 172800000; - break; + return timePassed <= 172800000; case 'Past 7 Days': - match = timePassed <= 604800000; - break; + return timePassed <= 604800000; case 'Past 14 Days': - match = timePassed <= 1209600000; - break; + return timePassed <= 1209600000; case 'Past 30 Days': - match = timePassed <= 2592000000; - break; + return timePassed <= 2592000000; case 'Any': - match = true; - break; + return true; + default: + return false; } - return match; + return false; }; - break; case 'number': return function (rowValue, rangeExp) { var compareChar = rangeExp.charAt(0); var compareValue; - var match = false; - if (rangeExp.length == 1) { - if (isNaN(parseInt(compareChar))) { + if (rangeExp.length === 1) { + if (isNaN(parseInt(compareChar, 10))) { // User types only '=' or '>' or '<', so don't filter column values - match = true; - return match; - } - else { - compareValue = parseFloat(parseFloat(rangeExp).toFixed(2)); + return true; } + compareValue = parseFloat(parseFloat(rangeExp).toFixed(2)); } else { - if (isNaN(parseInt(compareChar))) { + if (isNaN(parseInt(compareChar, 10))) { compareValue = parseFloat(parseFloat(rangeExp.substr(1, rangeExp.length)).toFixed(2)); } else { compareValue = parseFloat(parseFloat(rangeExp.substr(0, rangeExp.length)).toFixed(2)); } } - rowValue = parseFloat((jQuery(rowValue).text()) ? jQuery(rowValue).text() : rowValue); - match = false; + rowValue = parseFloat(jQuery(rowValue).text() ? jQuery(rowValue).text() : rowValue); switch (compareChar) { case '<': - if (compareValue > rowValue) match = true; - break; + return compareValue > rowValue; case '>': - if (compareValue < rowValue) match = true; - break; + return compareValue < rowValue case '=': - if (compareValue == rowValue) match = true; - break; default: - if (rangeExp == rowValue) match = true; + return compareValue === rowValue; } - return match; + return false; }; - break; case 'sub-resource': return function (origin, compareValue) { - if (!Array.isArray(compareValue) || compareValue.length === 0) return true; + if (!Array.isArray(compareValue) || !compareValue.length) { + return true; + } return origin.some(function (item) { for (var i = 0, l = compareValue.length; i < l; i++) { - if(item.get(compareValue[i].property) !== compareValue[i].value) return false + if(item.get(compareValue[i].property) !== compareValue[i].value) { + return false; + } } return true; }); }; - break; case 'multiple': return function (origin, compareValue) { var options = compareValue.split(','); - if (typeof (origin) === "string") { - var rowValue = origin; - } else { - var rowValue = origin.mapProperty('componentName').join(" "); - } + var rowValue = typeof origin === "string" ? origin : origin.mapProperty('componentName').join(" "); var str = new RegExp(compareValue, "i"); for (var i = 0; i < options.length; i++) { if (!isGlobal) { @@ -581,34 +535,28 @@ module.exports = { } return false; }; - break; case 'boolean': - return function (origin, compareValue) { - return origin === compareValue; - }; - break; case 'select': return function (origin, compareValue) { - return origin == compareValue; + return origin === compareValue; }; - break; case 'os': return function (origin, compareValue) { return origin.getEach('osType').contains(compareValue) }; - break; case 'range': return function (origin, compareValue) { if (compareValue[1] && compareValue[0]) { return origin >= compareValue[0] && origin <= compareValue[1]; - } else if (compareValue[0]) { + } + if (compareValue[0]) { return origin >= compareValue[0]; - } else if (compareValue[1]) { + } + if (compareValue[1]) { return origin <= compareValue[1] } return true; }; - break; case 'alert_status': /** * origin - alertDefinition.summary @@ -627,27 +575,43 @@ module.exports = { } return !!origin[compareValue] && (origin[compareValue].count > 0 || origin[compareValue].maintenanceCount > 0); }; - break; case 'alert_group': return function (origin, compareValue) { return origin.mapProperty('id').contains(compareValue); }; - break; case 'enable_disable': return function (origin, compareValue) { - return origin == (compareValue == 'enabled'); + return origin === (compareValue === 'enabled'); }; - break; case 'string': default: return function (origin, compareValue) { if (validator.isValidMatchesRegexp(compareValue)) { var regex = new RegExp(compareValue, "i"); return regex.test(origin); - } else { - return false; } + return false; } } + }, + + getComputedServicesList: function () { + return Em.computed('App.router.clusterController.isLoaded', function () { + return [ + { + value: '', + label: Em.I18n.t('common.all') + } + ].concat(App.Service.find().map(function (service) { + return { + value: service.get('serviceName'), + label: service.get('displayName') + } + })).concat({ + value: 'AMBARI', + label: Em.I18n.t('app.name') + }); + }); } + }; http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/app/views/main/alert_definitions_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/alert_definitions_view.js b/ambari-web/app/views/main/alert_definitions_view.js index 5db6352..8d27858 100644 --- a/ambari-web/app/views/main/alert_definitions_view.js +++ b/ambari-web/app/views/main/alert_definitions_view.js @@ -18,8 +18,7 @@ var App = require('app'); var filters = require('views/common/filter_view'), - sort = require('views/common/sort_view'), - date = require('utils/date/date'); + sort = require('views/common/sort_view'); App.MainAlertDefinitionsView = App.TableView.extend({ @@ -254,24 +253,7 @@ App.MainAlertDefinitionsView = App.TableView.extend({ serviceFilterView: filters.createSelectView({ column: 3, fieldType: 'filter-input-width', - content: function () { - return [ - { - value: '', - label: Em.I18n.t('common.all') - } - ].concat(App.Service.find().map(function (service) { - return { - value: service.get('serviceName'), - label: service.get('displayName') - } - }).concat([ - { - value: 'AMBARI', - label: Em.I18n.t('app.name') - } - ])); - }.property('App.router.clusterController.isLoaded'), + content: filters.getComputedServicesList(), onChangeValue: function () { this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select'); } @@ -464,7 +446,7 @@ App.MainAlertDefinitionsView = App.TableView.extend({ onValueChange: function () { var value = this.get('value'); - if (value != undefined) { + if (value !== undefined) { this.get('content').setEach('selected', false); this.set('selected', this.get('content').findProperty('value', value)); var selectEntry = this.get('content').findProperty('value', value); @@ -503,7 +485,7 @@ App.MainAlertDefinitionsView = App.TableView.extend({ * @type {string} */ paginationRightClass: function () { - if ((this.get("endIndex")) < this.get("filteredCount")) { + if (this.get("endIndex") < this.get("filteredCount")) { return "paginate_next"; } return "paginate_disabled_next"; http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/app/views/main/alerts/definition_details_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/alerts/definition_details_view.js b/ambari-web/app/views/main/alerts/definition_details_view.js index cb8f309..3ca2abc 100644 --- a/ambari-web/app/views/main/alerts/definition_details_view.js +++ b/ambari-web/app/views/main/alerts/definition_details_view.js @@ -17,6 +17,8 @@ */ var App = require('app'); +var filters = require('views/common/filter_view'); +var sort = require('views/common/sort_view'); App.MainAlertDefinitionDetailsView = App.TableView.extend({ @@ -38,6 +40,8 @@ App.MainAlertDefinitionDetailsView = App.TableView.extend({ */ disabledDisplay: Em.I18n.t('alerts.table.state.disabled'), + colPropAssoc: ['serviceName', 'hostName', 'state'], + content: function () { return this.get('controller.alerts'); }.property('controller.alerts.@each'), @@ -81,6 +85,101 @@ App.MainAlertDefinitionDetailsView = App.TableView.extend({ }); }.observes('controller.content.enabled'), + sortView: sort.wrapperView.extend({}), + + /** + * Sorting header for <label>alertDefinition.label</label> + * @type {Em.View} + */ + serviceSort: sort.fieldView.extend({ + column: 0, + name: 'serviceName', + displayName: Em.I18n.t('common.service') + }), + + /** + * Sorting header for <label>alertDefinition.status</label> + * @type {Em.View} + */ + hostNameSort: sort.fieldView.extend({ + column: 1, + name: 'hostName', + displayName: Em.I18n.t('common.host') + }), + + /** + * Sorting header for <label>alertDefinition.service.serviceName</label> + * @type {Em.View} + */ + stateSort: sort.fieldView.extend({ + column: 2, + name: 'state', + displayName: Em.I18n.t('common.status') + }), + + /** + * Filtering header for <label>alertInstance.hostName</label> + * @type {Em.View} + */ + hostNameFilterView: filters.createTextView({ + column: 1, + fieldType: 'input-medium', + onChangeValue: function(){ + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string'); + } + }), + + /** + * Filtering header for <label>alertInstance.serviceName</label> + * @type {Em.View} + */ + serviceFilterView: filters.createSelectView({ + column: 0, + fieldType: 'input-small', + content: filters.getComputedServicesList(), + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select'); + } + }), + + /** + * Filtering header for <label>alertInstance.state</label> + * @type {Em.View} + */ + stateFilterView: filters.createSelectView({ + column: 2, + fieldType: 'filter-input-width', + content: [ + { + value: '', + label: Em.I18n.t('common.all') + }, + { + value: 'OK', + label: 'OK' + }, + { + value: 'WARNING', + label: 'WARNING' + }, + { + value: 'CRITICAL', + label: 'CRITICAL' + }, + { + value: 'UNKNOWN', + label: 'UNKNOWN' + }, + { + value: 'PENDING', + label: 'NONE' + } + ], + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select'); + } + }), + /** * View calculates and represents count of alerts on appropriate host during last day */ @@ -160,7 +259,7 @@ App.MainAlertDefinitionDetailsView = App.TableView.extend({ * @type {string} */ paginationRightClass: function () { - if ((this.get("endIndex")) < this.get("filteredCount")) { + if (this.get("endIndex") < this.get("filteredCount")) { return "paginate_next"; } return "paginate_disabled_next"; http://git-wip-us.apache.org/repos/asf/ambari/blob/492d4727/ambari-web/test/views/common/filter_view_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/common/filter_view_test.js b/ambari-web/test/views/common/filter_view_test.js index 1afd844..f47f35a 100644 --- a/ambari-web/test/views/common/filter_view_test.js +++ b/ambari-web/test/views/common/filter_view_test.js @@ -567,4 +567,80 @@ describe('filters.getFilterByType', function () { }); + describe('os', function () { + + var filter = filters.getFilterByType('os'); + + [ + { + origin: [{osType: 'os1'}, {osType: 'os2'}, {osType: 'os3'}], + compareValue: 'os1', + e: true + }, + { + origin: [{osType: 'os1'}, {osType: 'os2'}, {osType: 'os3'}], + compareValue: 'os2', + e: true + }, + { + origin: [{osType: 'os1'}, {osType: 'os2'}, {osType: 'os3'}], + compareValue: 'os3', + e: true + }, + { + origin: [], + compareValue: 'os1', + e: false + }, + { + origin: [{}, {}, {}], + compareValue: 'os1', + e: false + } + ].forEach(function (test, i) { + it('test #' + (i + 1), function () { + expect(filter(test.origin, test.compareValue)).to.be.equal(test.e); + }); + }); + + }); + + describe('range', function () { + + var filter = filters.getFilterByType('range'); + + [ + { + compareValue: [2], + origin: 1, + e: false + }, + { + compareValue: [0, 1], + origin: 1, + e: true + }, + { + compareValue: [1, 1], + origin: 1, + e: true + }, + { + compareValue: [2, 2], + origin: 1, + e: false + }, + { + compareValue: [4, 2], + origin: 1, + e: false + } + ].forEach(function (test, i) { + it('test #' + (i + 1), function () { + expect(filter(test.origin, test.compareValue)).to.be.equal(test.e); + }); + }); + + }); + });