AMBARI-20043. Don't rerender all widgets when one of them is changed (onechiporenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/05c76ed6 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/05c76ed6 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/05c76ed6 Branch: refs/heads/branch-feature-AMBARI-12556 Commit: 05c76ed609dfcf75e0ff211aa8032834ef8e9f73 Parents: 984b35e Author: Oleg Nechiporenko <[email protected]> Authored: Thu Feb 16 15:25:48 2017 +0200 Committer: Oleg Nechiporenko <[email protected]> Committed: Fri Feb 17 10:26:47 2017 +0200 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 1 + ambari-web/app/data/dashboard_widgets.js | 196 +++++++++ ambari-web/app/messages.js | 2 +- .../app/mixins/common/track_request_mixin.js | 6 +- .../mixins/main/dashboard/widgets/editable.js | 91 +--- .../dashboard/widgets/editable_with_limit.js | 106 +---- .../widgets/single_numeric_threshold.js | 127 +----- .../main/dashboard/edit_widget_popup.hbs | 20 +- .../edit_widget_popup_single_threshold.hbs | 12 +- ambari-web/app/views.js | 1 + .../modal_popups/edit_dashboard_widget_popup.js | 436 +++++++++++++++++++ ambari-web/app/views/main/dashboard/widget.js | 173 ++------ ambari-web/app/views/main/dashboard/widgets.js | 266 ++--------- .../views/main/dashboard/widgets/text_widget.js | 23 +- .../edit_dashboard_widget_popup_test.js | 214 +++++++++ .../test/views/main/dashboard/widget_test.js | 112 +---- .../test/views/main/dashboard/widgets_test.js | 10 +- 17 files changed, 968 insertions(+), 828 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index d47d558..05c1657 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -253,6 +253,7 @@ var files = [ 'test/views/common/widget/template_widget_view_test', 'test/views/common/widget/heatmap_widget_view_test', 'test/views/common/modal_popups/cluster_check_popup_test', + 'test/views/common/modal_popups/edit_dashboard_widget_popup_test', 'test/views/common/modal_popups/hosts_table_list_popup_test', 'test/views/common/modal_popups/dependent_configs_list_popup_test', 'test/views/main/admin_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/data/dashboard_widgets.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/data/dashboard_widgets.js b/ambari-web/app/data/dashboard_widgets.js new file mode 100644 index 0000000..d58b0e2 --- /dev/null +++ b/ambari-web/app/data/dashboard_widgets.js @@ -0,0 +1,196 @@ +/** + * 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 = [ + { + id: 1, + viewName: 'NameNodeHeapPieChartView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.NameNodeHeap'), + threshold: [80, 90] + }, + { + id: 2, + viewName: 'NameNodeCapacityPieChartView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.HDFSDiskUsage'), + threshold: [85, 95] + }, + { + id: 3, + viewName: 'NameNodeCpuPieChartView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.NameNodeCpu'), + threshold: [90, 95] + }, + { + id: 4, + viewName: 'DataNodeUpView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.DataNodeUp'), + threshold: [80, 90] + }, + { + id: 5, + viewName: 'NameNodeRpcView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.NameNodeRpc'), + threshold: [1000, 3000] + }, + { + id: 6, + viewName: 'ChartClusterMetricsMemoryWidgetView', + sourceName: 'HOST_METRICS', + title: Em.I18n.t('dashboard.clusterMetrics.memory'), + threshold: [] + }, + { + id: 7, + viewName: 'ChartClusterMetricsNetworkWidgetView', + sourceName: 'HOST_METRICS', + title: Em.I18n.t('dashboard.clusterMetrics.network'), + threshold: [] + }, + { + id: 8, + viewName: 'ChartClusterMetricsCPUWidgetView', + sourceName: 'HOST_METRICS', + title: Em.I18n.t('dashboard.clusterMetrics.cpu'), + threshold: [] + }, + { + id: 9, + viewName: 'ChartClusterMetricsLoadWidgetView', + sourceName: 'HOST_METRICS', + title: Em.I18n.t('dashboard.clusterMetrics.load'), + threshold: [] + }, + { + id: 10, + viewName: 'NameNodeUptimeView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.NameNodeUptime'), + threshold: [] + }, + { + id: 11, + viewName: 'HDFSLinksView', + sourceName: 'HDFS', + title: Em.I18n.t('dashboard.widgets.HDFSLinks'), + threshold: [] + }, + { + id: 12, + viewName: 'HBaseLinksView', + sourceName: 'HBASE', + title: Em.I18n.t('dashboard.widgets.HBaseLinks'), + threshold: [] + }, + { + id: 13, + viewName: 'HBaseMasterHeapPieChartView', + sourceName: 'HBASE', + title: Em.I18n.t('dashboard.widgets.HBaseMasterHeap'), + threshold: [70, 90] + }, + { + id: 14, + viewName: 'HBaseAverageLoadView', + sourceName: 'HBASE', + title: Em.I18n.t('dashboard.widgets.HBaseAverageLoad'), + threshold: [150, 250] + }, + { + id: 15, + viewName: 'HBaseRegionsInTransitionView', + sourceName: 'HBASE', + title: Em.I18n.t('dashboard.widgets.HBaseRegionsInTransition'), + threshold: [3, 10], + isHiddenByDefault: true + }, + { + id: 16, + viewName: 'HBaseMasterUptimeView', + sourceName: 'HBASE', + title: Em.I18n.t('dashboard.widgets.HBaseMasterUptime'), + threshold: [] + }, + { + id: 17, + viewName: 'ResourceManagerHeapPieChartView', + sourceName: 'YARN', + title: Em.I18n.t('dashboard.widgets.ResourceManagerHeap'), + threshold: [70, 90] + }, + { + id: 18, + viewName: 'ResourceManagerUptimeView', + sourceName: 'YARN', + title: Em.I18n.t('dashboard.widgets.ResourceManagerUptime'), + threshold: [] + }, + { + id: 19, + viewName: 'NodeManagersLiveView', + sourceName: 'YARN', + title: Em.I18n.t('dashboard.widgets.NodeManagersLive'), + threshold: [50, 75] + }, + { + id: 20, + viewName: 'YARNMemoryPieChartView', + sourceName: 'YARN', + title: Em.I18n.t('dashboard.widgets.YARNMemory'), + threshold: [50, 75] + }, + { + id: 21, + viewName: 'SuperVisorUpView', + sourceName: 'STORM', + title: Em.I18n.t('dashboard.widgets.SuperVisorUp'), + threshold: [85, 95] + }, + { + id: 22, + viewName: 'FlumeAgentUpView', + sourceName: 'FLUME', + title: Em.I18n.t('dashboard.widgets.FlumeAgentUp'), + threshold: [85, 95] + }, + { + id: 23, + viewName: 'YARNLinksView', + sourceName: 'YARN', + title: Em.I18n.t('dashboard.widgets.YARNLinks'), + threshold: [] + }, + { + id: 24, + viewName: 'HawqSegmentUpView', + sourceName: 'HAWQ', + title: Em.I18n.t('dashboard.widgets.HawqSegmentUp'), + threshold: [75, 90] + }, + { + id: 25, + viewName: 'PxfUpView', + sourceName: 'PXF', + title: Em.I18n.t('dashboard.widgets.PxfUp'), + threshold: [] + } +]; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 81833f3..5d69b53 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -2860,7 +2860,7 @@ Em.I18n.translations = { 'dashboard.widgets.NodeManagersLive': 'NodeManagers Live', 'dashboard.widgets.YARNMemory': 'YARN Memory', 'dashboard.widgets.YARNLinks': 'YARN Links', - 'dashboard.widgets.error.invalid': 'Invalid! Enter a number between 0 - {0}', + 'dashboard.widgets.error.invalid': 'Invalid! Enter a number between {0} - {1}', 'dashboard.widgets.error.smaller': 'Threshold 1 should be smaller than threshold 2!', 'dashboard.widgets.HawqSegmentUp': 'HAWQ Segments Live', 'dashboard.widgets.PxfUp': 'PXF Agents Live', http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/mixins/common/track_request_mixin.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/common/track_request_mixin.js b/ambari-web/app/mixins/common/track_request_mixin.js index c665253..dd97b97 100644 --- a/ambari-web/app/mixins/common/track_request_mixin.js +++ b/ambari-web/app/mixins/common/track_request_mixin.js @@ -38,14 +38,14 @@ App.TrackRequestMixin = Em.Mixin.create({ this.get('requestsInProgress').pushObject({ request: request, id: requestId, - status: request.state(), - completed: ['resolved', 'rejected'].contains(request.state()) + status: Em.tryInvoke(request, 'state'), + completed: ['resolved', 'rejected'].contains(Em.tryInvoke(request, 'state')) }); request.always(function() { var requestInProgress = self.get('requestsInProgress').findProperty('id', requestId) || {}; Em.setProperties(requestInProgress, { completed: true, - status: request.state() + status: Em.tryInvoke(request, 'state') }); }); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/mixins/main/dashboard/widgets/editable.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/dashboard/widgets/editable.js b/ambari-web/app/mixins/main/dashboard/widgets/editable.js index fcb6bfb..482ff6a 100644 --- a/ambari-web/app/mixins/main/dashboard/widgets/editable.js +++ b/ambari-web/app/mixins/main/dashboard/widgets/editable.js @@ -20,93 +20,22 @@ var App = require('app'); App.EditableWidgetMixin = Em.Mixin.create({ - hintInfo: '', - editWidget: function () { - var self = this; - var configObj = Ember.Object.create({ - thresholdMin: self.get('thresholdMin') + '', - thresholdMax: self.get('thresholdMax') + '', - hintInfo: self.get('hintInfo'), - isThresh1Error: false, - isThresh2Error: false, - errorMessage1: "", - errorMessage2: "", - maxValue: 'infinity', - observeNewThresholdValue: function () { - var thresholdMin = this.get('thresholdMin'); - var thresholdMax = this.get('thresholdMax'); - if (thresholdMin.trim() !== "") { - if (isNaN(thresholdMin) || thresholdMin < 0) { - this.set('isThresh1Error', true); - this.set('errorMessage1', 'Invalid! Enter a number larger than 0'); - } else if ( this.get('isThresh2Error') === false && parseFloat(thresholdMax)<= parseFloat(thresholdMin)){ - this.set('isThresh1Error', true); - this.set('errorMessage1', 'Threshold 1 should be smaller than threshold 2 !'); - } else { - this.set('isThresh1Error', false); - this.set('errorMessage1', ''); - } - } else { - this.set('isThresh1Error', true); - this.set('errorMessage1', 'This is required'); - } - - if (thresholdMax.trim() !== "") { - if (isNaN(thresholdMax) || thresholdMax < 0) { - this.set('isThresh2Error', true); - this.set('errorMessage2', 'Invalid! Enter a number larger than 0'); - } else { - this.set('isThresh2Error', false); - this.set('errorMessage2', ''); - } - } else { - this.set('isThresh2Error', true); - this.set('errorMessage2', 'This is required'); - } + return App.EditDashboardWidgetPopup.show({ - }.observes('thresholdMin', 'thresholdMax') + widgetView: this, - }); - - App.ModalPopup.show({ - header: Em.I18n.t('dashboard.widgets.popupHeader'), - classNames: [ 'modal-edit-widget'], - modalDialogClasses: ['modal-lg'], - bodyClass: Ember.View.extend({ - templateName: require('templates/main/dashboard/edit_widget_popup'), - configPropertyObj: configObj + sliderHandlersManager: App.EditDashboardWidgetPopup.DoubleHandlers.create({ + maxValue: 'infinity', + thresholdMin: this.get('thresholdMin'), + thresholdMax: this.get('thresholdMax') }), - primary: Em.I18n.t('common.apply'), - onPrimary: function () { - configObj.observeNewThresholdValue(); - if (!configObj.isThresh1Error && !configObj.isThresh2Error) { - - var parent = self.get('parentView'); - var userPreferences = parent.get('userPreferences'); - userPreferences.threshold[Number(self.get('id'))] = [configObj.get('thresholdMin'), configObj.get('thresholdMax')]; - parent.saveWidgetsSettings(userPreferences); - parent.renderWidgets(); - this.hide(); - } - }, - didInsertElement: function () { - this._super(); - var colors = [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed]; //color green, orange ,red - var handlers = [33, 66]; //fixed value + sliderDisabled: true, + sliderHandlers: [33, 66], + sliderMaxValue: 100, + sliderColors: [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed] - $("#slider-range").slider({ - range: true, - disabled: true, //handlers cannot move - min: 0, - max: 100, - values: handlers, - create: function (event, ui) { - self.updateColors(handlers, colors); - } - }); - } }); } http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js b/ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js index ddf2a26..1cb96df 100644 --- a/ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js +++ b/ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js @@ -23,110 +23,18 @@ var App = require('app'); */ App.EditableWithLimitWidgetMixin = Em.Mixin.create({ - hintInfo: '', - editWidget: function () { - var parent = this; - var maxTmp = parseFloat(parent.get('maxValue')); - var configObj = Ember.Object.create({ - thresholdMin: parent.get('thresholdMin') + '', - thresholdMax: parent.get('thresholdMax') + '', - hintInfo: parent.get('hintInfo'), - thresholdMinError: false, - thresholdMaxError: false, - thresholdMinErrorMessage: '', - thresholdMaxErrorMessage: '', - maxValue: maxTmp, - observeNewThresholdValue: function () { - var thresholdMin = this.get('thresholdMin'); - var thresholdMax = this.get('thresholdMax'); - if (thresholdMin.trim() !== '') { - if (isNaN(thresholdMin) || thresholdMin > maxTmp || thresholdMin < 0){ - this.set('thresholdMinError', true); - this.set('thresholdMinErrorMessage', 'Invalid! Enter a number between 0 - ' + maxTmp); - } else if ( this.get('thresholdMaxError') === false && parseFloat(thresholdMax)<= parseFloat(thresholdMin)) { - this.set('thresholdMinError', true); - this.set('thresholdMinErrorMessage', 'Threshold 1 should be smaller than threshold 2 !'); - } else { - this.set('thresholdMinError', false); - this.set('thresholdMinErrorMessage', ''); - } - } else { - this.set('thresholdMinError', true); - this.set('thresholdMinErrorMessage', 'This is required'); - } - - if (thresholdMax.trim() !== '') { - if (isNaN(thresholdMax) || thresholdMax > maxTmp || thresholdMax < 0) { - this.set('thresholdMaxError', true); - this.set('thresholdMaxErrorMessage', 'Invalid! Enter a number between 0 - ' + maxTmp); - } else { - this.set('thresholdMaxError', false); - this.set('thresholdMaxErrorMessage', ''); - } - } else { - this.set('thresholdMaxError', true); - this.set('thresholdMaxErrorMessage', 'This is required'); - } - - // update the slider handles and color - if (!this.get('thresholdMinError') && !this.get('thresholdMaxError')) { - $("#slider-range").slider('values', 0 , parseFloat(thresholdMin)); - $("#slider-range").slider('values', 1 , parseFloat(thresholdMax)); - } - }.observes('thresholdMin', 'thresholdMax') - - }); - App.ModalPopup.show({ - header: Em.I18n.t('dashboard.widgets.popupHeader'), - classNames: ['modal-edit-widget'], - modalDialogClasses: ['modal-lg'], - bodyClass: Ember.View.extend({ - templateName: require('templates/main/dashboard/edit_widget_popup'), - configPropertyObj: configObj - }), - primary: Em.I18n.t('common.apply'), - onPrimary: function () { - configObj.observeNewThresholdValue(); - if (!configObj.thresholdMinError && !configObj.thresholdMaxError) { - parent.set('thresholdMin', parseFloat(configObj.get('thresholdMin')) ); - parent.set('thresholdMax', parseFloat(configObj.get('thresholdMax')) ); - if (!App.get('testMode')) { - var bigParent = parent.get('parentView'); - bigParent.getUserPref(bigParent.get('persistKey')); - var oldValue = bigParent.get('currentPrefObject'); - oldValue.threshold[parseInt(parent.id, 10)] = [configObj.get('thresholdMin'), configObj.get('thresholdMax')]; - bigParent.postUserPref(bigParent.get('persistKey'),oldValue); - } - this.hide(); - } - }, + return App.EditDashboardWidgetPopup.show({ - didInsertElement: function () { - this._super(); - var handlers = [configObj.get('thresholdMin'), configObj.get('thresholdMax')]; - var colors = [App.healthStatusRed, App.healthStatusOrange, App.healthStatusGreen]; //color red, orange, green + widgetView: this, - $("#slider-range").slider({ - range: true, - min: 0, - max: maxTmp, - values: handlers, - create: function () { - parent.updateColors(handlers, colors); - }, - slide: function (event, ui) { - parent.updateColors(ui.values, colors); - configObj.set('thresholdMin', ui.values[0] + ''); - configObj.set('thresholdMax', ui.values[1] + ''); - }, - change: function (event, ui) { - parent.updateColors(ui.values, colors); - } - }); + sliderHandlersManager: App.EditDashboardWidgetPopup.DoubleHandlers.create({ + maxValue: parseFloat(this.get('maxValue')), + thresholdMin: this.get('thresholdMin'), + thresholdMax: this.get('thresholdMax') + }) - } }); } http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js b/ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js index 06bcffe..36172b7 100644 --- a/ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js +++ b/ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js @@ -23,126 +23,25 @@ var App = require('app'); */ App.SingleNumericThresholdMixin = Em.Mixin.create({ - /** - * @type {Em.Object} - * @class - */ - widgetConfig: Ember.Object.extend({ - thresholdMin: '', - hintInfo: '', - isThresh1Error: false, - errorMessage1: "", - - maxValue: 0, - observeThresh1Value: function () { - var thresholdMin = this.get('thresholdMin'); - var maxValue = this.get('maxValue'); - - if (thresholdMin.trim() !== "") { - if (isNaN(thresholdMin) || thresholdMin > maxValue || thresholdMin < 0) { - this.set('isThresh1Error', true); - this.set('errorMessage1', Em.I18n.t('dashboard.widgets.error.invalid').format(maxValue)); - } else { - this.set('isThresh1Error', false); - this.set('errorMessage1', ''); - } - } else { - this.set('isThresh1Error', true); - this.set('errorMessage1', Em.I18n.t('admin.users.editError.requiredField')); - } - this.updateSlider(); - }.observes('thresholdMin', 'maxValue'), - - updateSlider: function () { - var thresholdMin = this.get('thresholdMin'); - // update the slider handles and color - if (this.get('isThresh1Error') === false) { - $("#slider-range") - .slider('values', 0, parseFloat(thresholdMin)) - } - } - }), - - /** - * edit widget - * @param {object} event - */ editWidget: function () { - var parent = this; - var maxTmp = parseFloat(this.get('maxValue')); - var configObj = this.get('widgetConfig').create({ - thresholdMin: this.get('thresholdMin') + '', - hintInfo: this.get('hintInfo') + '', - maxValue: parseFloat(this.get('maxValue')) - }); + return App.EditDashboardWidgetPopup.show({ + + widgetView: this, - App.ModalPopup.show({ - header: Em.I18n.t('dashboard.widgets.popupHeader'), - classNames: ['modal-edit-widget'], - modalDialogClasses: ['modal-lg'], - bodyClass: Ember.View.extend({ - templateName: require('templates/main/dashboard/edit_widget_popup_single_threshold'), - configPropertyObj: configObj - }), - primary: Em.I18n.t('common.apply'), - onPrimary: function () { - configObj.observeThresh1Value(); - if (!configObj.isThresh1Error) { - var bigParent = parent.get('parentView'); - parent.set('thresholdMin', parseFloat(configObj.get('thresholdMin'))); - if (!App.get('testMode')) { - // save to persist - var userPreferences = bigParent.get('userPreferences'); - userPreferences.threshold[parseInt(parent.get('id'), 10)] = [configObj.get('thresholdMin')]; - bigParent.saveWidgetsSettings(userPreferences); - bigParent.renderWidgets(); - } - this.hide(); - } - }, - didInsertElement: function () { - this._super(); - var handlers = [configObj.get('thresholdMin')]; - var _this = this; + sliderHandlersManager: App.EditDashboardWidgetPopup.SingleHandler.create({ + thresholdMin: this.get('thresholdMin'), + maxValue: parseFloat(this.get('maxValue')) + }), - $("#slider-range").slider({ - range: false, - min: 0, - max: maxTmp, - values: handlers, - create: function () { - _this.updateColors(handlers); - }, - slide: function (event, ui) { - _this.updateColors(ui.values); - configObj.set('thresholdMin', ui.values[0] + ''); - }, - change: function (event, ui) { - _this.updateColors(ui.values); - } - }); - }, + bodyClass: App.EditDashboardWidgetPopup.EditDashboardWidgetPopupBody.extend({ + templateName: require('templates/main/dashboard/edit_widget_popup_single_threshold') + }), - updateColors: function (handlers) { - var colors = [App.healthStatusGreen, App.healthStatusRed]; //color green,red - var colorstops = colors[0] + ", "; // start with the first color - for (var i = 0; i < handlers.length; i++) { - colorstops += colors[i] + " " + handlers[i] * 100 / maxTmp + "%,"; - colorstops += colors[i + 1] + " " + handlers[i] * 100 / maxTmp + "%,"; - } - colorstops += colors[colors.length - 1]; - var sliderElement = $('#slider-range'); - var css1 = '-webkit-linear-gradient(left,' + colorstops + ')'; // chrome & safari - sliderElement.css('background-image', css1); - var css2 = '-ms-linear-gradient(left,' + colorstops + ')'; // IE 10+ - sliderElement.css('background-image', css2); - var css3 = '-moz-linear-gradient(left,' + colorstops + ')'; // Firefox - sliderElement.css('background-image', css3); + sliderIsRange: false, - sliderElement.find('.ui-widget-header').css({'background-color': '#FF8E00', 'background-image': 'none'}); // change the original ranger color - } + sliderColors: [App.healthStatusGreen, App.healthStatusRed] - }); + }); } http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs b/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs index 7caf085..60c9741 100644 --- a/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs +++ b/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs @@ -18,7 +18,7 @@ <form class="form-horizontal" autocomplete="off"> <div class="each-row"> <div class="alert alert-info"> - {{{view.configPropertyObj.hintInfo}}} + {{{view.parentView.widgetView.hintInfo}}} </div> </div> @@ -32,20 +32,20 @@ <div id="slider-value1" class="value-on-slider col-md-2"> <input type="text" value="0" disabled="disabled" class="form-control" /> </div> - <div id="slider-value2" {{bindAttr class="view.configPropertyObj.thresholdMinError:slider-error :value-on-slider :col-md-4 view.configPropertyObj.thresholdMinError:has-error"}}> - {{view Ember.TextField class="form-control" valueBinding="view.configPropertyObj.thresholdMin"}} - {{#if view.configPropertyObj.thresholdMinErrorMessage}} - <span class="help-block validation-block">{{view.configPropertyObj.thresholdMinErrorMessage}}</span> + <div id="slider-value2" {{bindAttr class="view.parentView.sliderHandlersManager.thresholdMinError:slider-error :value-on-slider :col-md-4 view.parentView.sliderHandlersManager.thresholdMinError:has-error"}}> + {{view Ember.TextField class="form-control" valueBinding="view.parentView.sliderHandlersManager.thresholdMin"}} + {{#if view.parentView.sliderHandlersManager.thresholdMinError}} + <span class="help-block validation-block">{{view.parentView.sliderHandlersManager.thresholdMinErrorMessage}}</span> {{/if}} </div> - <div id="slider-value3" {{bindAttr class="view.configPropertyObj.thresholdMaxError:slider-error :value-on-slider :col-md-4 view.configPropertyObj.thresholdMaxError:has-error"}}> - {{view Ember.TextField class="form-control" valueBinding="view.configPropertyObj.thresholdMax"}} - {{#if view.configPropertyObj.thresholdMaxErrorMessage}} - <span class="help-block validation-block">{{view.configPropertyObj.thresholdMaxErrorMessage}}</span> + <div id="slider-value3" {{bindAttr class="view.parentView.sliderHandlersManager.thresholdMaxError:slider-error :value-on-slider :col-md-4 view.parentView.sliderHandlersManager.thresholdMaxError:has-error"}}> + {{view Ember.TextField class="form-control" valueBinding="view.parentView.sliderHandlersManager.thresholdMax"}} + {{#if view.parentView.sliderHandlersManager.thresholdMaxError}} + <span class="help-block validation-block">{{view.parentView.sliderHandlersManager.thresholdMaxErrorMessage}}</span> {{/if}} </div> <div id="slider-value4" class="value-on-slider col-md-2"> - {{view Em.TextField valueBinding="view.configPropertyObj.maxValue" classNames="form-control" disabled="disabled"}} + {{view Em.TextField valueBinding="view.parentView.sliderHandlersManager.maxValue" classNames="form-control" disabled="disabled"}} </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs b/ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs index 86ffb47..416852e 100644 --- a/ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs +++ b/ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs @@ -19,7 +19,7 @@ <form class="form-horizontal" autocomplete="off"> <div class="each-row"> <div class="alert alert-info"> - {{{view.configPropertyObj.hintInfo}}} + {{{view.parentView.widgetView.hintInfo}}} </div> </div> @@ -33,14 +33,14 @@ <div id="slider-value1" class="value-on-slider col-md-2"> <input type="text" value="0" disabled="disabled" class="form-control" /> </div> - <div id="slider-value2" {{bindAttr class="view.configPropertyObj.isThresh1Error:slider-error :value-on-slider :col-md-4 :col-md-offset-2 :col-sm-offset-2 view.configPropertyObj.isThresh1Error:has-error"}}> - {{view Ember.TextField valueBinding="view.configPropertyObj.thresholdMin" class="form-control"}} - {{#if view.configPropertyObj.errorMessage1}} - <span class="help-block validation-block">{{view.configPropertyObj.errorMessage1}}</span> + <div id="slider-value2" {{bindAttr class="view.parentView.sliderHandlersManager.thresholdMinError:slider-error :value-on-slider :col-md-4 :col-md-offset-2 :col-sm-offset-2 view.parentView.sliderHandlersManager.thresholdMinError:has-error"}}> + {{view Ember.TextField valueBinding="view.parentView.sliderHandlersManager.thresholdMin" class="form-control"}} + {{#if view.parentView.sliderHandlersManager.thresholdMinErrorMessage}} + <span class="help-block validation-block">{{view.parentView.sliderHandlersManager.thresholdMinErrorMessage}}</span> {{/if}} </div> <div id="slider-value3" class="value-on-slider col-md-2 col-md-offset-2 col-sm-offset-2"> - {{view Em.TextField valueBinding="view.configPropertyObj.maxValue" classNames="form-control" disabled="disabled"}} + {{view Em.TextField valueBinding="view.parentView.sliderHandlersManager.maxValue" classNames="form-control" disabled="disabled"}} </div> </div> http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index 77b5d5a..6972d2a 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -33,6 +33,7 @@ require('views/common/chart/linear'); require('views/common/chart/linear_time'); require('views/common/modal_popup'); require('views/common/modal_popups/alert_popup'); +require('views/common/modal_popups/edit_dashboard_widget_popup'); require('views/common/modal_popups/manage_kdc_credentials_popup'); require('views/common/modal_popups/confirmation_feedback_popup'); require('views/common/modal_popups/confirmation_popup'); http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/views/common/modal_popups/edit_dashboard_widget_popup.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/modal_popups/edit_dashboard_widget_popup.js b/ambari-web/app/views/common/modal_popups/edit_dashboard_widget_popup.js new file mode 100644 index 0000000..7ea1b32 --- /dev/null +++ b/ambari-web/app/views/common/modal_popups/edit_dashboard_widget_popup.js @@ -0,0 +1,436 @@ +/** + * 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. + */ + +var App = require('app'); +const {isValidFloat} = require('utils/validator'); + +/** + * Thresholds manager for sliders with single value + * Usage: + * <pre> + * SingleHandler.create({ + * thresholdMin: 12, + * minValue: 10, + * maxValue: 100 + * }); + * </pre> + * + * @class SingleHandler + */ +const SingleHandler = Em.Object.extend({ + + /** + * @type {number} + */ + thresholdMin: null, + + /** + * @type {number} + * @default 0 + */ + minValue: 0, + + /** + * @type {number} + */ + maxValue: null, + + /** + * Is <code>thresholdMin</code> invalid + * true - invalid + * false - valid + * + * @type {boolean} + */ + thresholdMinError: Em.computed.bool('thresholdMinErrorMessage'), + + /** + * Alias for <code>thresholdMinError</code> + * + * @type {boolean} + */ + hasErrors: Em.computed.alias('thresholdMinError'), + + /** + * Error message for <code>thresholdMin</code> + * <ul> + * <li>Value is not a number</li> + * <li>Value is out of range <code>(minValue - maxValue)</code></li> + * </ul> + * Empty message means that <code>thresholdMin</code> has valid value + * + * @type {string} + */ + thresholdMinErrorMessage: function () { + var thresholdMin = this.get('thresholdMin'); + var maxValue = this.get('maxValue'); + var minValue = this.get('minValue'); + if (!isValidFloat(thresholdMin) || thresholdMin > maxValue || thresholdMin < minValue) { + return Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + } + return ''; + }.property('thresholdMin', 'maxValue'), + + /** + * Formatted threshold value + * + * @type {number[]} + */ + preparedThresholds: function () { + return [parseFloat(this.get('thresholdMin'))]; + }.property('thresholdMin'), + + /** + * Force set new values for threshold + * + * @param {number[]} newValues + */ + updateThresholds(newValues) { + this.set('thresholdMin', newValues[0]); + } + +}); + +/** + * Thresholds manager for sliders with double values + * Usage: + * <pre> + * SingleHandler.create({ + * thresholdMin: 12, + * thresholdMax: 40, + * minValue: 10, + * maxValue: 100 + * }); + * </pre> + * + * @class DoubleHandlers + */ +const DoubleHandlers = SingleHandler.extend({ + + /** + * @type {number} + */ + thresholdMax: null, + + /** + * Is <code>thresholdMax</code> invalid + * true - invalid + * false - valid + * + * @type {boolean} + */ + thresholdMaxError: Em.computed.bool('thresholdMaxErrorMessage'), + + /** + * Is some threshold invalid + * true - some one is invalid + * false - thresholds are valid + * + * @type {boolean} + */ + hasErrors: Em.computed.or('thresholdMinError', 'thresholdMaxError'), + + /** + * Error message for <code>thresholdMin</code> + * <ul> + * <li>Value is not a number</li> + * <li>Value is out of range <code>(minValue - maxValue)</code></li> + * <li><code>thresholdMin</code>-value greater than <code>thresholdMax</code>-value</li> + * </ul> + * Empty message means that <code>thresholdMin</code> has valid value + * + * @type {string} + */ + thresholdMinErrorMessage: function () { + var thresholdMin = this.get('thresholdMin'); + var thresholdMax = this.get('thresholdMax'); + var maxValue = this.get('maxValue'); + var minValue = this.get('minValue'); + if (!isValidFloat(thresholdMin) || thresholdMin > maxValue || thresholdMin < minValue) { + return Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + } + if (this.get('thresholdMaxError') === false && thresholdMax <= thresholdMin) { + return Em.I18n.t('dashboard.widgets.error.smaller'); + } + return ''; + }.property('thresholdMin', 'thresholdMax'), + + /** + * Error message for <code>thresholdMax</code> + * <ul> + * <li>Value is not a number</li> + * <li>Value is out of range <code>(minValue - maxValue)</code></li> + * </ul> + * Empty message means that <code>thresholdMax</code> has valid value + * + * @type {string} + */ + thresholdMaxErrorMessage: function () { + var thresholdMax = this.get('thresholdMax'); + var maxValue = this.get('maxValue'); + var minValue = this.get('minValue'); + if (!isValidFloat(thresholdMax) || thresholdMax > maxValue || thresholdMax < minValue) { + return Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + } + return ''; + }.property('thresholdMax'), + + /** + * Threshold values ready to save + * + * @type {number[]} + */ + preparedThresholds: function () { + return [parseFloat(this.get('thresholdMin')), parseFloat(this.get('thresholdMax'))]; + }.property('thresholdMin', 'thresholdMax'), + + /** + * Force set new values for threshold + * + * @param {number[]} newValues + */ + updateThresholds(newValues) { + this.set('thresholdMin', newValues[0]); + this.set('thresholdMax', newValues[1]); + } + +}); + +/** + * Common body-view for popup with sliders + * + * @class EditDashboardWidgetPopupBody + */ +const EditDashboardWidgetPopupBody = Em.View.extend({ + templateName: require('templates/main/dashboard/edit_widget_popup') +}); + +/** + * Popup with slider to edit dashboard widget + * Usage: + * <pre> + * App.EditDashboardWidgetPopup.show({ + * widgetView: this, + * sliderHandlersManager: App.EditDashboardWidgetPopup.DoubleHandlers.create({ + * maxValue: 100, + * thresholdMin: this.get('thresholdMin'), + * thresholdMax: this.get('thresholdMax') + * }) + * }); + * </pre> + * + * <code>widgetView</code> should be set to view with widget. + * Usually you will use <code>App.EditDashboardWidgetPopup</code> inside of some <code>App.DashboardWidgetView</code> instance, + * so <code>widgetView</code> may be set to <code>this</code> + * <code>sliderHandlersManager</code> should be set to some of the <code>App.EditDashboardWidgetPopup.SingleHandler</code> + * or <code>App.EditDashboardWidgetPopup.DoubleHandler</code> + * + * You can't use <code>App.EditDashboardWidgetPopup</code> without setting this two properties! + * + * @class App.EditDashboardWidgetPopup + */ +App.EditDashboardWidgetPopup = App.ModalPopup.extend({ + + header: Em.I18n.t('dashboard.widgets.popupHeader'), + classNames: ['modal-edit-widget'], + modalDialogClasses: ['modal-lg'], + primary: Em.I18n.t('common.apply'), + disablePrimary: Em.computed.alias('sliderHandlersManager.hasErrors'), + + /** + * Can't be null or undefined + * + * @type {SingleHandler|DoubleHandlers} + */ + sliderHandlersManager: null, + + /** + * Widget view + * Can't be not a view. Used to save Thresholds. Normally it's an instance of <code>App.DashboardWidgetView</code> + * + * @type {Em.View} + */ + widgetView: null, + + /** + * Determines if slider is enabled for slide + * true - don't enabled + * false - enabled + * + * Determines if slider handlers should be updated with Threshold values + * true - don't update + * false - update + * + * Used as option <code>disabled</code> for $.ui.slider + * + * @type {boolean} + */ + sliderDisabled: false, + + /** + * Slider "ticks" + * Used as option <code>values</code> for $.ui.slider + * + * @type {number[]} + */ + sliderHandlers: function () { + return this.get('sliderHandlersManager.preparedThresholds'); + }.property('sliderHandlersManager.preparedThresholds.[]'), + + /** + * Colors used for slider ranges + * @type {string[]} + */ + sliderColors: [App.healthStatusRed, App.healthStatusOrange, App.healthStatusGreen], + + /** + * Maximum value for slider + * Used as option <code>max</code> for $.ui.slider + * + * @type {number} + */ + sliderMaxValue: Em.computed.alias('sliderHandlersManager.maxValue'), + + /** + * Minimum value for slider + * Used as option <code>min</code> for $.ui.slider + * + * @type {number} + */ + sliderMinValue: 0, + + /** + * Check how many handlers has slider + * true - 2 handlers + * false - 1 handler + * + * Used as option <code>range</code> for $.ui.slider + * + * @type {boolean} + */ + sliderIsRange: true, + + bodyClass: EditDashboardWidgetPopupBody, + + init() { + Em.assert('`widgetView` should be valid view', this.get('widgetView.isView')); + Em.assert('`sliderHandlersManager` should be set', !!this.get('sliderHandlersManager')); + return this._super(...arguments); + }, + + /** + * Save new threshold value on popup-close (means Primary click) + * Use <code>widgetView</code> to get <code>widgetsView</code> and save new values + * Current widget is updated too (without redrawing) + */ + saveThreshold () { + let preparedThresholds = this.get('sliderHandlersManager.preparedThresholds'); + this.get('widgetView').saveWidgetThresholds(preparedThresholds); + }, + + /** + * Update slider values when new threshold values are provided + * Don't do anything if some value is invalid or slider is disabled + * + * @private + */ + _updateSliderValues: function() { + var sliderHandlersManager = this.get('sliderHandlersManager'); + if (!sliderHandlersManager.get('hasErrors') && !this.get('sliderDisabled')) { + $('#slider-range').slider('values', sliderHandlersManager.get('preparedThresholds')); + } + }.observes('sliderDisabled', 'sliderHandlersManager.preparedThresholds.[]', 'sliderHandlersManager.hasErrors'), + + onPrimary () { + let sliderHandlersManager = this.get('sliderHandlersManager'); + if (!sliderHandlersManager.get('hasErrors')) { + this.saveThreshold(); + this.hide(); + } + }, + + /** + * Create slider in the popup when it's opened + */ + createSlider() { + var self = this; + let sliderHandlersManager = this.get('sliderHandlersManager'); + var handlers = this.get('sliderHandlers'); + + $('#slider-range').slider({ + range: this.get('sliderIsRange'), + min: this.get('sliderMinValue'), + max: this.get('sliderMaxValue'), + disabled: this.get('sliderDisabled'), + values: handlers, + create: function () { + self.updateSliderColors(handlers); + }, + slide: function (event, ui) { + self.updateSliderColors(ui.values); + sliderHandlersManager.updateThresholds(ui.values); + }, + change: function (event, ui) { + self.updateSliderColors(ui.values); + } + }); + }, + + didInsertElement: function () { + this._super(); + this.createSlider(); + }, + + /** + * Update colors on slider using <code>sliderColors</code> theme when user interacts with it + * + * @param {number[]} handlers + */ + updateSliderColors(handlers) { + let gradient = this._getGradientStr(handlers); + $('#slider-range') + .css('background-image', '-webkit-' + gradient) + .css('background-image', '-ms-' + gradient) + .css('background-image', '-moz-' + gradient) + .find('.ui-widget-header').css({ + 'background-color': App.healthStatusOrange, + 'background-image': 'none' + }); + }, + + /** + * @param {number[]} handlers + * @returns {string} + * @private + */ + _getGradientStr(handlers) { + let maxValue = this.get('sliderMaxValue'); + let colors = this.get('sliderColors'); + let gradient = colors[0] + ', ' + handlers.map((handler, i) => { + return `${colors[i]} ${handlers[i] * 100 / maxValue}%, ${colors[i + 1]} ${handlers[i] * 100 / maxValue}%,`; + }).join('') + colors[colors.length - 1]; + return `linear-gradient(left,${gradient})`; + } + +}); + +App.EditDashboardWidgetPopup.reopenClass({ + SingleHandler, + DoubleHandlers, + EditDashboardWidgetPopupBody +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/views/main/dashboard/widget.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widget.js b/ambari-web/app/views/main/dashboard/widget.js index e7a626c..9fba906 100644 --- a/ambari-web/app/views/main/dashboard/widget.js +++ b/ambari-web/app/views/main/dashboard/widget.js @@ -30,9 +30,19 @@ App.DashboardWidgetView = Em.View.extend({ sourceName: Em.computed.alias('widget.sourceName'), + /** + * Bound from template + * + * @type {object} + */ widget: null, /** + * @type {Em.View} + */ + widgetsView: Em.computed.alias('parentView'), + + /** * @type {object} - record from model that serve as data source */ model: function () { @@ -79,6 +89,11 @@ App.DashboardWidgetView = Em.View.extend({ hiddenInfoClass: "hidden-info-two-line", /** + * @type {string} + */ + hintInfo: Em.computed.i18nFormat('dashboard.widgets.hintInfo.common', 'maxValue'), + + /** * @type {number} * @default 0 */ @@ -100,61 +115,6 @@ App.DashboardWidgetView = Em.View.extend({ */ isDataLoadedBinding: 'App.router.clusterController.isServiceContentFullyLoaded', - /** - * @type {Em.Object} - * @class - */ - widgetConfig: Ember.Object.extend({ - thresholdMin: '', - thresholdMax: '', - hintInfo: Em.computed.i18nFormat('dashboard.widgets.hintInfo.common', 'maxValue'), - thresholdMinError: false, - thresholdMaxError: false, - thresholdMinErrorMessage: "", - thresholdMaxErrorMessage: "", - maxValue: 0, - validateThreshold: function(thresholdName) { - var thresholdMin = this.get('thresholdMin'), - thresholdMax = this.get('thresholdMax'), - maxValue = this.get('maxValue'), - currentThreshold = this.get(thresholdName), - isError = false, - errorMessage = ''; - - if (currentThreshold.trim() !== "") { - if (isNaN(currentThreshold) || currentThreshold > maxValue || currentThreshold < 0) { - isError = true; - errorMessage = Em.I18n.t('dashboard.widgets.error.invalid').format(maxValue); - } else if (parseFloat(thresholdMax) <= parseFloat(thresholdMin)) { - isError = true; - errorMessage = Em.I18n.t('dashboard.widgets.error.smaller'); - } else { - isError = false; - errorMessage = ''; - } - } else { - isError = true; - errorMessage = Em.I18n.t('admin.users.editError.requiredField'); - } - this.set(thresholdName + 'ErrorMessage', errorMessage); - this.set(thresholdName + 'Error', isError); - this.updateSlider(); - }, - observeThreshMinValue: function () { - this.validateThreshold('thresholdMin'); - }.observes('thresholdMin', 'maxValue'), - observeThreshMaxValue: function () { - this.validateThreshold('thresholdMax'); - }.observes('thresholdMax', 'maxValue'), - updateSlider: function () { - if (this.get('thresholdMinError') === false && this.get('thresholdMaxError') === false) { - $("#slider-range") - .slider('values', 0, parseFloat(this.get('thresholdMin'))) - .slider('values', 1, parseFloat(this.get('thresholdMax'))); - } - } - }), - didInsertElement: function () { App.tooltip(this.$("[rel='ZoomInTooltip']"), { placement: 'left', @@ -190,97 +150,36 @@ App.DashboardWidgetView = Em.View.extend({ }, /** - * edit widget + * Update thresholds for widget and save this them to persist + * + * @param {number[]} preparedThresholds */ - editWidget: function () { - var configObj = this.get('widgetConfig').create({ - thresholdMin: this.get('thresholdMin') + '', - thresholdMax: this.get('thresholdMax') + '', - maxValue: parseFloat(this.get('maxValue')) - }); - this.showEditDialog(configObj); + saveWidgetThresholds(preparedThresholds) { + const widgetsView = this.get('widgetsView'); + const userPreferences = widgetsView.get('userPreferences'); + const widgetId = Number(this.get('id')); + userPreferences.threshold[widgetId] = preparedThresholds; + this.set('widget.threshold', userPreferences.threshold[widgetId]); + widgetsView.saveWidgetsSettings(userPreferences); }, /** - * show edit dialog - * @param {Em.Object} configObj - * @returns {App.ModalPopup} + * edit widget */ - showEditDialog: function (configObj) { - var self = this; - var maxValue = this.get('maxValue'); - - return App.ModalPopup.show({ - header: Em.I18n.t('dashboard.widgets.popupHeader'), - classNames: ['modal-edit-widget'], - modalDialogClasses: ['modal-lg'], - bodyClass: Ember.View.extend({ - templateName: require('templates/main/dashboard/edit_widget_popup'), - configPropertyObj: configObj - }), - configObj: configObj, - disablePrimary: Em.computed.or('configObj.thresholdMinError', 'configObj.thresholdMaxError'), - primary: Em.I18n.t('common.apply'), - onPrimary: function () { - configObj.observeThreshMinValue(); - configObj.observeThreshMaxValue(); - if (!configObj.thresholdMinError && !configObj.thresholdMaxError) { - self.set('thresholdMin', parseFloat(configObj.get('thresholdMin'))); - self.set('thresholdMax', parseFloat(configObj.get('thresholdMax'))); - - var parent = self.get('parentView'); - var userPreferences = parent.get('userPreferences'); - userPreferences.threshold[Number(self.get('id'))] = [configObj.get('thresholdMin'), configObj.get('thresholdMax')]; - parent.saveWidgetsSettings(userPreferences); - parent.renderWidgets(); - - this.hide(); - } - }, + editWidget: function () { + return App.EditDashboardWidgetPopup.show({ - didInsertElement: function () { - this._super(); - var _this = this; - var handlers = [configObj.get('thresholdMin'), configObj.get('thresholdMax')]; + widgetView: this, - $("#slider-range").slider({ - range: true, - min: 0, - max: maxValue, - values: handlers, - create: function () { - _this.updateColors(handlers); - }, - slide: function (event, ui) { - _this.updateColors(ui.values); - configObj.set('thresholdMin', ui.values[0] + ''); - configObj.set('thresholdMax', ui.values[1] + ''); - }, - change: function (event, ui) { - _this.updateColors(ui.values); - } - }); - }, - updateColors: function (handlers) { - var colors = [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed]; - var colorStops = colors[0] + ", "; + sliderHandlersManager: App.EditDashboardWidgetPopup.DoubleHandlers.create({ + thresholdMin: this.get('thresholdMin'), + thresholdMax: this.get('thresholdMax'), + maxValue: parseFloat(this.get('maxValue')) + }), - for (var i = 0; i < handlers.length; i++) { - colorStops += colors[i] + " " + handlers[i] * 100 / maxValue + "%,"; - colorStops += colors[i + 1] + " " + handlers[i] * 100 / maxValue + "%,"; - } - colorStops += colors[colors.length - 1]; - var sliderElement = $('#slider-range'); - var gradient = 'linear-gradient(left,' + colorStops + ')'; + sliderColors: [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed] - sliderElement.css('background-image', '-webkit-' + gradient); - sliderElement.css('background-image', '-ms-' + gradient); - sliderElement.css('background-image', '-moz-' + gradient); - sliderElement.find('.ui-widget-header').css({ - 'background-color': '#FF8E00', - 'background-image': 'none' - }); - } }); } + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/views/main/dashboard/widgets.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widgets.js b/ambari-web/app/views/main/dashboard/widgets.js index 572625d..16840a5 100644 --- a/ambari-web/app/views/main/dashboard/widgets.js +++ b/ambari-web/app/views/main/dashboard/widgets.js @@ -32,184 +32,7 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap name: 'mainDashboardWidgetsView', templateName: require('templates/main/dashboard/widgets'), - widgetsDefinition: [ - { - id: 1, - viewName: 'NameNodeHeapPieChartView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.NameNodeHeap'), - threshold: [80, 90] - }, - { - id: 2, - viewName: 'NameNodeCapacityPieChartView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.HDFSDiskUsage'), - threshold: [85, 95] - }, - { - id: 3, - viewName: 'NameNodeCpuPieChartView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.NameNodeCpu'), - threshold: [90, 95] - }, - { - id: 4, - viewName: 'DataNodeUpView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.DataNodeUp'), - threshold: [80, 90] - }, - { - id: 5, - viewName: 'NameNodeRpcView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.NameNodeRpc'), - threshold: [1000, 3000] - }, - { - id: 6, - viewName: 'ChartClusterMetricsMemoryWidgetView', - sourceName: 'HOST_METRICS', - title: Em.I18n.t('dashboard.clusterMetrics.memory'), - threshold: [] - }, - { - id: 7, - viewName: 'ChartClusterMetricsNetworkWidgetView', - sourceName: 'HOST_METRICS', - title: Em.I18n.t('dashboard.clusterMetrics.network'), - threshold: [] - }, - { - id: 8, - viewName: 'ChartClusterMetricsCPUWidgetView', - sourceName: 'HOST_METRICS', - title: Em.I18n.t('dashboard.clusterMetrics.cpu'), - threshold: [] - }, - { - id: 9, - viewName: 'ChartClusterMetricsLoadWidgetView', - sourceName: 'HOST_METRICS', - title: Em.I18n.t('dashboard.clusterMetrics.load'), - threshold: [] - }, - { - id: 10, - viewName: 'NameNodeUptimeView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.NameNodeUptime'), - threshold: [] - }, - { - id: 11, - viewName: 'HDFSLinksView', - sourceName: 'HDFS', - title: Em.I18n.t('dashboard.widgets.HDFSLinks'), - threshold: [] - }, - { - id: 12, - viewName: 'HBaseLinksView', - sourceName: 'HBASE', - title: Em.I18n.t('dashboard.widgets.HBaseLinks'), - threshold: [] - }, - { - id: 13, - viewName: 'HBaseMasterHeapPieChartView', - sourceName: 'HBASE', - title: Em.I18n.t('dashboard.widgets.HBaseMasterHeap'), - threshold: [70, 90] - }, - { - id: 14, - viewName: 'HBaseAverageLoadView', - sourceName: 'HBASE', - title: Em.I18n.t('dashboard.widgets.HBaseAverageLoad'), - threshold: [150, 250] - }, - { - id: 15, - viewName: 'HBaseRegionsInTransitionView', - sourceName: 'HBASE', - title: Em.I18n.t('dashboard.widgets.HBaseRegionsInTransition'), - threshold: [3, 10], - isHiddenByDefault: true - }, - { - id: 16, - viewName: 'HBaseMasterUptimeView', - sourceName: 'HBASE', - title: Em.I18n.t('dashboard.widgets.HBaseMasterUptime'), - threshold: [] - }, - { - id: 17, - viewName: 'ResourceManagerHeapPieChartView', - sourceName: 'YARN', - title: Em.I18n.t('dashboard.widgets.ResourceManagerHeap'), - threshold: [70, 90] - }, - { - id: 18, - viewName: 'ResourceManagerUptimeView', - sourceName: 'YARN', - title: Em.I18n.t('dashboard.widgets.ResourceManagerUptime'), - threshold: [] - }, - { - id: 19, - viewName: 'NodeManagersLiveView', - sourceName: 'YARN', - title: Em.I18n.t('dashboard.widgets.NodeManagersLive'), - threshold: [50, 75] - }, - { - id: 20, - viewName: 'YARNMemoryPieChartView', - sourceName: 'YARN', - title: Em.I18n.t('dashboard.widgets.YARNMemory'), - threshold: [50, 75] - }, - { - id: 21, - viewName: 'SuperVisorUpView', - sourceName: 'STORM', - title: Em.I18n.t('dashboard.widgets.SuperVisorUp'), - threshold: [85, 95] - }, - { - id: 22, - viewName: 'FlumeAgentUpView', - sourceName: 'FLUME', - title: Em.I18n.t('dashboard.widgets.FlumeAgentUp'), - threshold: [85, 95] - }, - { - id: 23, - viewName: 'YARNLinksView', - sourceName: 'YARN', - title: Em.I18n.t('dashboard.widgets.YARNLinks'), - threshold: [] - }, - { - id: 24, - viewName: 'HawqSegmentUpView', - sourceName: 'HAWQ', - title: Em.I18n.t('dashboard.widgets.HawqSegmentUp'), - threshold: [75, 90] - }, - { - id: 25, - viewName: 'PxfUpView', - sourceName: 'PXF', - title: Em.I18n.t('dashboard.widgets.PxfUp'), - threshold: [] - } - ], + widgetsDefinition: require('data/dashboard_widgets'), widgetsDefinitionMap: function () { return this.get('widgetsDefinition').toMapByProperty('id'); @@ -275,15 +98,13 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap userPreferences: null, didInsertElement: function () { - var self = this; - this._super(); - this.loadWidgetsSettings().complete(function() { - self.checkServicesChange(); - self.renderWidgets(); - self.set('isDataLoaded', true); + this.loadWidgetsSettings().complete(() => { + this.checkServicesChange(); + this.renderWidgets(); + this.set('isDataLoaded', true); App.loadTimer.finish('Dashboard Metrics Page'); - Em.run.next(self, 'makeSortable'); + Em.run.next(this, 'makeSortable'); }); }, @@ -337,11 +158,10 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap resolveConfigDependencies: function(widgetsDefinition) { var clusterEnv = App.router.get('clusterController.clusterEnv').properties; - var yarnMemoryWidget = widgetsDefinition.findProperty('id', 20); - if (clusterEnv.hide_yarn_memory_widget === 'true') { - yarnMemoryWidget.isHiddenByDefault = true; + widgetsDefinition.findProperty('id', 20).isHiddenByDefault = true; } + return widgetsDefinition; }, generateDefaultUserPreferences: function() { @@ -353,14 +173,10 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap }; this.resolveConfigDependencies(widgetsDefinition); - widgetsDefinition.forEach(function(widget) { if (App.Service.find(widget.sourceName).get('isLoaded') || widget.sourceName === 'HOST_METRICS') { - if (widget.isHiddenByDefault) { - preferences.hidden.push(widget.id); - } else { - preferences.visible.push(widget.id); - } + let state = widget.isHiddenByDefault ? 'hidden' : 'visible'; + preferences[state].push(widget.id); } preferences.threshold[widget.id] = widget.threshold; }); @@ -421,18 +237,13 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap }; var isChanged = false; - defaultPreferences.visible.forEach(function(id) { - if (!userPreferences.visible.contains(id) && !userPreferences.hidden.contains(id)) { - isChanged = true; - newValue.visible.push(id); - } - }); - - defaultPreferences.hidden.forEach(function(id) { - if (!userPreferences.visible.contains(id) && !userPreferences.hidden.contains(id)) { - isChanged = true; - newValue.hidden.push(id); - } + ['visible', 'hidden'].forEach(state => { + defaultPreferences[state].forEach(id => { + if (!userPreferences.visible.contains(id) && !userPreferences.hidden.contains(id)) { + isChanged = true; + newValue[state].push(id); + } + }); }); if (isChanged) { this.saveWidgetsSettings(newValue); @@ -443,15 +254,14 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap * Reset widgets visibility-status */ resetAllWidgets: function () { - var self = this; - App.showConfirmationPopup(function () { - self.saveWidgetsSettings(self.generateDefaultUserPreferences()); - self.setProperties({ + App.showConfirmationPopup(() => { + this.saveWidgetsSettings(this.generateDefaultUserPreferences()); + this.setProperties({ currentTimeRangeIndex: 0, customStartTime: null, customEndTime: null }); - self.renderWidgets(); + this.renderWidgets(); }); }, @@ -469,23 +279,21 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap var widgetsArray = $('div[viewid]'); var userPreferences = self.get('userPreferences') || self.getDBProperty(self.get('persistKey')); - var newValue = Em.Object.create({ + var newValue = { visible: [], hidden: userPreferences.hidden, threshold: userPreferences.threshold + }; + newValue.visible = userPreferences.visible.map((item, index) => { + var viewID = widgetsArray.get(index).getAttribute('viewid'); + return Number(viewID.split('-')[1]); }); - var size = userPreferences.visible.length; - for (var j = 0; j <= size - 1; j++) { - var viewID = widgetsArray.get(j).getAttribute('viewid'); - var id = Number(viewID.split("-").get(1)); - newValue.visible.push(id); - } self.saveWidgetsSettings(newValue); }, - activate: function (event, ui) { + activate: function () { self.set('isMoving', true); }, - deactivate: function (event, ui) { + deactivate: function () { self.set('isMoving', false); } }).disableSelection(); @@ -511,21 +319,9 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap }), applyFilter: function () { var parent = this.get('parentView'), - hiddenWidgets = this.get('hiddenWidgets'), - userPreferences = parent.get('userPreferences'), - newValue = { - visible: userPreferences.visible.slice(0), - hidden: userPreferences.hidden.slice(0), - threshold: userPreferences.threshold - }; - - hiddenWidgets.filterProperty('checked').forEach(function (item) { - newValue.visible.push(item.id); - newValue.hidden = newValue.hidden.without(item.id); - hiddenWidgets.removeObject(item); - }, this); - parent.saveWidgetsSettings(newValue); - parent.renderWidgets(); + hiddenWidgets = this.get('hiddenWidgets'); + hiddenWidgets.filterProperty('checked').setEach('isVisible', true); + parent.saveWidgetsSettings(); } }), http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/app/views/main/dashboard/widgets/text_widget.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/dashboard/widgets/text_widget.js b/ambari-web/app/views/main/dashboard/widgets/text_widget.js index daa354c..79f0573 100644 --- a/ambari-web/app/views/main/dashboard/widgets/text_widget.js +++ b/ambari-web/app/views/main/dashboard/widgets/text_widget.js @@ -32,26 +32,5 @@ App.TextDashboardWidgetView = App.DashboardWidgetView.extend({ return this.get('data') === null; }.property('data'), - hiddenInfo: [], - - maxValue: null, - - updateColors: function (handlers, colors) { - var colorstops = colors[0] + ", "; // start with the first color - for (var i = 0; i < handlers.length; i++) { - colorstops += colors[i] + " " + handlers[i] + "%,"; - colorstops += colors[i + 1] + " " + handlers[i] + "%,"; - } - colorstops += colors[colors.length - 1]; - var cssForChromeAndSafari = '-webkit-linear-gradient(left,' + colorstops + ')'; // chrome & safari - var slider = $('#slider-range'); - slider.css('background-image', cssForChromeAndSafari); - var cssForIE = '-ms-linear-gradient(left,' + colorstops + ')'; // IE 10+ - slider.css('background-image', cssForIE); - //$('#slider-range').css('filter', 'progid:DXImageTransform.Microsoft.gradient( startColorStr= ' + colors[0] + ', endColorStr= ' + colors[2] +', GradientType=1 )' ); // IE 10- - var cssForFireFox = '-moz-linear-gradient(left,' + colorstops + ')'; // Firefox - slider.css('background-image', cssForFireFox); - - slider.find('.ui-widget-header').css({'background-color': '#FF8E00', 'background-image': 'none'}); // change the original ranger color - } + hiddenInfo: [] }); http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/test/views/common/modal_popups/edit_dashboard_widget_popup_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/common/modal_popups/edit_dashboard_widget_popup_test.js b/ambari-web/test/views/common/modal_popups/edit_dashboard_widget_popup_test.js new file mode 100644 index 0000000..3335cf3 --- /dev/null +++ b/ambari-web/test/views/common/modal_popups/edit_dashboard_widget_popup_test.js @@ -0,0 +1,214 @@ +/** + * 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. + */ + + +var App = require('app'); + +function getView() { + return App.EditDashboardWidgetPopup.create({ + widgetView: Em.View.create(), + sliderHandlersManager: {} + }); +} + +describe('App.EditDashboardWidgetPopup', function () { + + App.TestAliases.testAsComputedAlias(getView(), 'disablePrimary', 'sliderHandlersManager.hasErrors'); + + App.TestAliases.testAsComputedAlias(getView(), 'sliderMaxValue', 'sliderHandlersManager.maxValue'); + + describe('#init', function () { + + it('should throw an Error if no `widgetView` provided', function () { + expect(function () { + App.EditDashboardWidgetPopup.create({ + sliderHandlersManager: {} + }); + }).to.throw(/`widgetView` should be valid view/); + }); + + it('should throw an Error if no `sliderHandlersManager` provided', function () { + expect(function () { + App.EditDashboardWidgetPopup.create({ + widgetView: Em.View.create(), + }); + }).to.throw(/`sliderHandlersManager` should be set/); + }); + + }); + +}); + +describe('App.EditDashboardWidgetPopup.SingleHandler', function () { + + var handler; + + function getSingleHandler() { + return App.EditDashboardWidgetPopup.SingleHandler.create(); + } + + beforeEach(function () { + handler = getSingleHandler(); + }); + + App.TestAliases.testAsComputedAlias(getSingleHandler(), 'hasErrors', 'thresholdMinError'); + + describe('#updateThresholds', function () { + + it('should update `thresholdMin`', function () { + handler.set('thresholdMin', -1); + handler.updateThresholds([100500]); + expect(handler.get('thresholdMin')).to.be.equal(100500); + }); + + }); + + describe('#thresholdMinErrorMessage', function() { + + var minValue = 0; + var maxValue = 100; + var msg = Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + + beforeEach(function() { + handler.setProperties({ + minValue: minValue, + maxValue: maxValue + }); + }); + + [ + {thresholdMin: -1, e: msg}, + {thresholdMin: 101, e: msg}, + {thresholdMin: 'abc', e: msg}, + {thresholdMin: 60, e: ''} + ].forEach(function(test) { + it('thresholdMin: ' + JSON.stringify(test.thresholdMin), function () { + handler.set('thresholdMin', test.thresholdMin); + expect(handler.get('thresholdMinErrorMessage')).to.be.equal(test.e); + }); + }); + + }); + + describe('#preparedThresholds', function () { + + it('mapped to array threshold values', function () { + handler.setProperties({ + thresholdMin: 1 + }); + expect(handler.get('preparedThresholds')).to.be.eql([1]); + }); + + }); + +}); + +describe('App.EditDashboardWidgetPopup.DoubleHandlers', function () { + + var handler; + + function getDoubleHandlers() { + return App.EditDashboardWidgetPopup.DoubleHandlers.create(); + } + + beforeEach(function () { + handler = getDoubleHandlers(); + }); + + App.TestAliases.testAsComputedOr(getDoubleHandlers(), 'hasErrors', ['thresholdMinError', 'thresholdMaxError']); + + describe('#updateThresholds', function () { + + it('should update `thresholdMin` and `thresholdMax`', function () { + handler.set('thresholdMin', -1); + handler.set('thresholdMax', 1); + handler.updateThresholds([1234, 4321]); + expect(handler.get('thresholdMin')).to.be.equal(1234); + expect(handler.get('thresholdMax')).to.be.equal(4321); + }); + + }); + + describe('#thresholdMinErrorMessage', function() { + + var minValue = 0; + var maxValue = 100; + var msg = Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + var msg2 = Em.I18n.t('dashboard.widgets.error.smaller'); + + beforeEach(function() { + handler.setProperties({ + minValue: minValue, + maxValue: maxValue + }); + }); + + [ + {thresholdMin: -1, e: msg}, + {thresholdMin: 101, e: msg}, + {thresholdMin: 'abc', e: msg}, + {thresholdMin: 60, e: ''}, + {thresholdMin: 99, e: msg2} + ].forEach(function(test) { + it('thresholdMin: ' + JSON.stringify(test.thresholdMin), function () { + handler.set('thresholdMin', test.thresholdMin); + handler.set('thresholdMax', 98); + expect(handler.get('thresholdMinErrorMessage')).to.be.equal(test.e); + }); + }); + + }); + + describe('#thresholdMaxErrorMessage', function () { + var minValue = 0; + var maxValue = 100; + var msg = Em.I18n.t('dashboard.widgets.error.invalid').format(minValue, maxValue); + + beforeEach(function() { + handler.setProperties({ + minValue: minValue, + maxValue: maxValue + }); + }); + + [ + {thresholdMax: -1, e: msg}, + {thresholdMax: 101, e: msg}, + {thresholdMax: 'abc', e: msg}, + {thresholdMax: 60, e: ''} + ].forEach(function(test) { + it('thresholdMax: ' + JSON.stringify(test.thresholdMax), function () { + handler.set('thresholdMax', test.thresholdMax); + expect(handler.get('thresholdMaxErrorMessage')).to.be.equal(test.e); + }); + }); + }); + + describe('#preparedThresholds', function () { + + it('mapped to array threshold values', function () { + handler.setProperties({ + thresholdMin: 1, + thresholdMax: 2 + }); + expect(handler.get('preparedThresholds')).to.be.eql([1, 2]); + }); + + }); + +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/test/views/main/dashboard/widget_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/dashboard/widget_test.js b/ambari-web/test/views/main/dashboard/widget_test.js index a504c6d..8e10cef 100644 --- a/ambari-web/test/views/main/dashboard/widget_test.js +++ b/ambari-web/test/views/main/dashboard/widget_test.js @@ -89,97 +89,6 @@ describe('App.DashboardWidgetView', function () { }); }); - describe('#widgetConfig', function () { - var widgetConfig; - - beforeEach(function() { - widgetConfig = view.get('widgetConfig').create(); - }); - - describe('#validateThreshold()', function () { - - beforeEach(function () { - sinon.stub(widgetConfig, 'updateSlider'); - }); - - afterEach(function () { - widgetConfig.updateSlider.restore(); - }); - - it('updateSlider should be called', function () { - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.updateSlider).to.be.called; - }); - - it('thresholdMin is empty', function () { - widgetConfig.set('thresholdMin', ''); - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.get('thresholdMinError')).to.be.true; - expect(widgetConfig.get('thresholdMinErrorMessage')).to.be.equal(Em.I18n.t('admin.users.editError.requiredField')); - }); - - it('thresholdMin is NaN', function () { - widgetConfig.set('thresholdMin', 'a'); - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.get('thresholdMinError')).to.be.true; - expect(widgetConfig.get('thresholdMinErrorMessage')).to.be.equal(Em.I18n.t('dashboard.widgets.error.invalid').format(0)); - }); - - it('thresholdMin bigger than maxValue', function () { - widgetConfig.set('thresholdMin', '1'); - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.get('thresholdMinError')).to.be.true; - expect(widgetConfig.get('thresholdMinErrorMessage')).to.be.equal(Em.I18n.t('dashboard.widgets.error.invalid').format(0)); - }); - - it('thresholdMin less than 0', function () { - widgetConfig.set('thresholdMin', '-1'); - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.get('thresholdMinError')).to.be.true; - expect(widgetConfig.get('thresholdMinErrorMessage')).to.be.equal(Em.I18n.t('dashboard.widgets.error.invalid').format(0)); - }); - - it('thresholdMin bigger than thresholdMax', function () { - widgetConfig.set('thresholdMin', '2'); - widgetConfig.set('thresholdMax', '1'); - widgetConfig.set('maxValue', 100); - widgetConfig.validateThreshold('thresholdMin'); - expect(widgetConfig.get('thresholdMinError')).to.be.true; - expect(widgetConfig.get('thresholdMinErrorMessage')).to.be.equal(Em.I18n.t('dashboard.widgets.error.smaller')); - }); - }); - - describe('#observeThreshMinValue()', function() { - - beforeEach(function() { - sinon.stub(widgetConfig, 'validateThreshold'); - }); - afterEach(function() { - widgetConfig.validateThreshold.restore(); - }); - - it('validateThreshold should be called', function() { - widgetConfig.observeThreshMinValue(); - expect(widgetConfig.validateThreshold.calledWith('thresholdMin')).to.be.true; - }); - }); - - describe('#observeThreshMaxValue()', function() { - - beforeEach(function() { - sinon.stub(widgetConfig, 'validateThreshold'); - }); - afterEach(function() { - widgetConfig.validateThreshold.restore(); - }); - - it('validateThreshold should be called', function() { - widgetConfig.observeThreshMaxValue(); - expect(widgetConfig.validateThreshold.calledWith('thresholdMax')).to.be.true; - }); - }); - }); - describe('#didInsertElement()', function() { beforeEach(function() { @@ -250,25 +159,6 @@ describe('App.DashboardWidgetView', function () { describe('#editWidget()', function() { beforeEach(function() { - sinon.stub(view, 'showEditDialog'); - }); - - afterEach(function() { - view.showEditDialog.restore(); - }); - - it('showEditDialog should be called', function() { - view.reopen({ - widgetConfig: Em.Object.extend() - }); - view.editWidget(); - expect(view.showEditDialog).to.be.calledOnce; - }); - }); - - describe('#showEditDialog()', function() { - - beforeEach(function() { sinon.stub(App.ModalPopup, 'show'); }); @@ -277,7 +167,7 @@ describe('App.DashboardWidgetView', function () { }); it('App.ModalPopup.show should be called', function() { - view.showEditDialog(); + view.editWidget(); expect(App.ModalPopup.show).to.be.calledOnce; }); }); http://git-wip-us.apache.org/repos/asf/ambari/blob/05c76ed6/ambari-web/test/views/main/dashboard/widgets_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/dashboard/widgets_test.js b/ambari-web/test/views/main/dashboard/widgets_test.js index 5d1ddb2..4700ac8 100644 --- a/ambari-web/test/views/main/dashboard/widgets_test.js +++ b/ambari-web/test/views/main/dashboard/widgets_test.js @@ -426,15 +426,7 @@ describe('App.MainDashboardWidgetsView', function () { }); it('saveWidgetsSettings should be called', function() { - expect(plusButtonFilterView.get('parentView').saveWidgetsSettings.getCall(0).args[0]).to.be.eql({ - visible: [2, 1], - hidden: [3], - threshold: {} - }); - }); - - it('renderWidgets should be called', function() { - expect(plusButtonFilterView.get('parentView').renderWidgets).to.be.calledOnce; + expect(plusButtonFilterView.get('parentView').saveWidgetsSettings.calledOnce).to.be.true; }); }); });
