You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by at...@apache.org on 2016/12/09 11:33:29 UTC

ambari git commit: AMBARI-19146 Refactor widget instance view on Dashboard. (atkach)

Repository: ambari
Updated Branches:
  refs/heads/trunk 6a55220d1 -> 66c6d5607


AMBARI-19146 Refactor widget instance view on Dashboard. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/66c6d560
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/66c6d560
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/66c6d560

Branch: refs/heads/trunk
Commit: 66c6d5607867a95d29deee00407ef8b7ef22ee03
Parents: 6a55220
Author: Andrii Tkach <at...@apache.org>
Authored: Fri Dec 9 12:38:35 2016 +0200
Committer: Andrii Tkach <at...@apache.org>
Committed: Fri Dec 9 13:18:30 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/styles/dashboard.less            |  15 -
 .../main/dashboard/edit_widget_popup.hbs        |  22 +-
 .../main/dashboard/widgets/pie_chart.hbs        |   2 +-
 .../main/dashboard/widgets/simple_text.hbs      |   2 +-
 ambari-web/app/views/main/dashboard/widget.js   | 218 +++-----
 .../test/views/main/dashboard/widget_test.js    | 506 ++++++++-----------
 6 files changed, 315 insertions(+), 450 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/ambari-web/app/styles/dashboard.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/dashboard.less b/ambari-web/app/styles/dashboard.less
index c170894..9e1213e 100644
--- a/ambari-web/app/styles/dashboard.less
+++ b/ambari-web/app/styles/dashboard.less
@@ -183,21 +183,6 @@
       .slots-content-isNA{
         top: -82px;
       }
-      .content-hidden-two-line{
-        .content-mx(-105px);
-      }
-      .content-hidden-three-line{
-        .content-mx(-116px);
-      }
-      .content-hidden-four-line{
-        .content-mx(-126px);
-      }
-      .content-hidden-five-line{
-        .content-mx(-140px);
-      }
-      .content-hidden-six-line{
-        .content-mx(-143px);
-      }
     }
 
     .cluster-metrics {

http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/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 3802e29..7caf085 100644
--- a/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs
+++ b/ambari-web/app/templates/main/dashboard/edit_widget_popup.hbs
@@ -24,15 +24,7 @@
 
     <div class="row" id= "min-height-limit">
       <div class="col-md-12">
-       {{#if view.configPropertyObj.isIE9}}
-         <div class="progress">
-           <div {{bindAttr class=":bar view.configPropertyObj.isGreenOrangeRed:bar-success:bar-danger"}} style="width: 33%;"></div>
-           <div class="bar bar-warning" style="width: 33%;"></div>
-           <div {{bindAttr class=":bar view.configPropertyObj.isGreenOrangeRed:bar-danger:bar-success"}} style="width: 34%;"></div>
-         </div>
-       {{else}}
-         <div id="slider-range"></div>
-       {{/if}}
+        <div id="slider-range"></div>
       </div>
     </div>
 
@@ -40,16 +32,16 @@
         <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 view.configPropertyObj.isThresh1Error:has-error"}}>
+        <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.errorMessage1}}
-            <span class="help-block validation-block">{{view.configPropertyObj.errorMessage1}}</span>
+          {{#if view.configPropertyObj.thresholdMinErrorMessage}}
+            <span class="help-block validation-block">{{view.configPropertyObj.thresholdMinErrorMessage}}</span>
           {{/if}}
         </div>
-        <div id="slider-value3" {{bindAttr class="view.configPropertyObj.isThresh2Error:slider-error :value-on-slider :col-md-4 view.configPropertyObj.isThresh2Error:has-error"}}>
+        <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.errorMessage1}}
-            <span class="help-block validation-block">{{view.configPropertyObj.errorMessage2}}</span>
+          {{#if view.configPropertyObj.thresholdMaxErrorMessage}}
+            <span class="help-block validation-block">{{view.configPropertyObj.thresholdMaxErrorMessage}}</span>
           {{/if}}
         </div>
         <div id="slider-value4" class="value-on-slider col-md-2">

http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/ambari-web/app/templates/main/dashboard/widgets/pie_chart.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/widgets/pie_chart.hbs b/ambari-web/app/templates/main/dashboard/widgets/pie_chart.hbs
index 1b14503..d13ddb4 100644
--- a/ambari-web/app/templates/main/dashboard/widgets/pie_chart.hbs
+++ b/ambari-web/app/templates/main/dashboard/widgets/pie_chart.hbs
@@ -41,7 +41,7 @@
         </div>
 
         {{#if view.isPieExist}}
-          <div {{bindAttr class=":widget-content view.hoverContentTopClass"}}>
+          <div class="widget-content">
             {{view view.content
                 modelBinding="view.model"
                 thresholdMinBinding="view.thresholdMin"

http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/ambari-web/app/templates/main/dashboard/widgets/simple_text.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/widgets/simple_text.hbs b/ambari-web/app/templates/main/dashboard/widgets/simple_text.hbs
index 80967b9..f10ca19 100644
--- a/ambari-web/app/templates/main/dashboard/widgets/simple_text.hbs
+++ b/ambari-web/app/templates/main/dashboard/widgets/simple_text.hbs
@@ -39,7 +39,7 @@
             {{/each}}
           </table>
         </div>
-        <div {{bindAttr class=":widget-content view.hoverContentTopClass"}}>{{view.content}}</div>
+        <div class="widget-content">{{view.content}}</div>
       {{else}}
         {{view App.SpinnerView}}
       {{/if}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/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 495db2e..563e31d 100644
--- a/ambari-web/app/views/main/dashboard/widget.js
+++ b/ambari-web/app/views/main/dashboard/widget.js
@@ -35,7 +35,7 @@ App.DashboardWidgetView = Em.View.extend({
   /**
    * @type {object} - record from model that serve as data source
    */
-  model : function () {
+  model: function () {
     var model = Em.Object.create();
     if (Em.isNone(this.get('sourceName'))) {
       return model;
@@ -108,59 +108,49 @@ App.DashboardWidgetView = Em.View.extend({
     thresholdMin: '',
     thresholdMax: '',
     hintInfo: Em.computed.i18nFormat('dashboard.widgets.hintInfo.common', 'maxValue'),
-    isThresh1Error: false,
-    isThresh2Error: false,
-    errorMessage1: "",
-    errorMessage2: "",
+    thresholdMinError: false,
+    thresholdMaxError: false,
+    thresholdMinErrorMessage: "",
+    thresholdMaxErrorMessage: "",
     maxValue: 0,
-    observeThresh1Value: function () {
-      var thresholdMin = this.get('thresholdMin');
-      var thresholdMax = this.get('thresholdMax');
-      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 if (this.get('isThresh2Error') === false && parseFloat(thresholdMax) <= parseFloat(thresholdMin)) {
-          this.set('isThresh1Error', true);
-          this.set('errorMessage1', Em.I18n.t('dashboard.widgets.error.smaller'));
+    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 {
-          this.set('isThresh1Error', false);
-          this.set('errorMessage1', '');
+          isError = false;
+          errorMessage = '';
         }
       } else {
-        this.set('isThresh1Error', true);
-        this.set('errorMessage1', Em.I18n.t('admin.users.editError.requiredField'));
+        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'),
-    observeThresh2Value: function () {
-      var thresholdMax = this.get('thresholdMax');
-      var maxValue = this.get('maxValue');
-
-      if (thresholdMax.trim() !== "") {
-        if (isNaN(thresholdMax) || thresholdMax > maxValue || thresholdMax < 0) {
-          this.set('isThresh2Error', true);
-          this.set('errorMessage2', Em.I18n.t('dashboard.widgets.error.invalid').format(maxValue));
-        } else {
-          this.set('isThresh2Error', false);
-          this.set('errorMessage2', '');
-        }
-      } else {
-        this.set('isThresh2Error', true);
-        this.set('errorMessage2', Em.I18n.t('admin.users.editError.requiredField'));
-      }
-      this.updateSlider();
+    observeThreshMaxValue: function () {
+      this.validateThreshold('thresholdMax');
     }.observes('thresholdMax', 'maxValue'),
     updateSlider: function () {
-      var thresholdMin = this.get('thresholdMin');
-      var thresholdMax = this.get('thresholdMax');
-      // update the slider handles and color
-      if (this.get('isThresh1Error') === false && this.get('isThresh2Error') === false) {
+      if (this.get('thresholdMinError') === false && this.get('thresholdMaxError') === false) {
         $("#slider-range")
-          .slider('values', 0, parseFloat(thresholdMin))
-          .slider('values', 1, parseFloat(thresholdMax));
+          .slider('values', 0, parseFloat(this.get('thresholdMin')))
+          .slider('values', 1, parseFloat(this.get('thresholdMax')));
       }
     }
   }),
@@ -172,6 +162,11 @@ App.DashboardWidgetView = Em.View.extend({
     });
   },
 
+  /**
+   *
+   * @param {string} source
+   * @returns {App.Service}
+   */
   findModelBySource: function (source) {
     if (source === 'HOST_METRICS' && App.get('services.hostMetrics').length > 0) {
       return App.get('services.hostMetrics');
@@ -214,7 +209,7 @@ App.DashboardWidgetView = Em.View.extend({
       thresholdMax: this.get('thresholdMax') + '',
       maxValue: parseFloat(this.get('maxValue'))
     });
-    this.showEditDialog(configObj)
+    this.showEditDialog(configObj);
   },
 
   /**
@@ -234,11 +229,13 @@ App.DashboardWidgetView = Em.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.observeThresh1Value();
-        configObj.observeThresh2Value();
-        if (!configObj.isThresh1Error && !configObj.isThresh2Error) {
+        configObj.observeThreshMinValue();
+        configObj.observeThreshMaxValue();
+        if (!configObj.thresholdMinError && !configObj.thresholdMaxError) {
           self.set('thresholdMin', parseFloat(configObj.get('thresholdMin')));
           self.set('thresholdMax', parseFloat(configObj.get('thresholdMax')));
 
@@ -254,96 +251,47 @@ App.DashboardWidgetView = Em.View.extend({
 
       didInsertElement: function () {
         this._super();
-        var browserVersion = self.getInternetExplorerVersion();
+        var self = this;
         var handlers = [configObj.get('thresholdMin'), configObj.get('thresholdMax')];
-        var colors = [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed]; //color green, orange ,red
-
-        if (browserVersion === -1 || browserVersion > 9) {
-          configObj.set('isIE9', false);
-          configObj.set('isGreenOrangeRed', true);
-          $("#slider-range").slider({
-            range: true,
-            min: 0,
-            max: maxValue,
-            values: handlers,
-            create: function () {
-              updateColors(handlers);
-            },
-            slide: function (event, ui) {
-              updateColors(ui.values);
-              configObj.set('thresholdMin', ui.values[0] + '');
-              configObj.set('thresholdMax', ui.values[1] + '');
-            },
-            change: function (event, ui) {
-              updateColors(ui.values);
-            }
-          });
-
-          function updateColors(handlers) {
-            var colorstops = colors[0] + ", "; // start with the first color
-            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 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);
-            //$('#slider-range').css('filter', 'progid:DXImageTransform.Microsoft.gradient( startColorStr= ' + colors[0] + ', endColorStr= ' + colors[2] +',  GradientType=1 )' ); // IE 10-
-            var css3 = '-moz-linear-gradient(left,' + colorstops + ')'; // Firefox
-            sliderElement.css('background-image', css3);
-
-            sliderElement.find('.ui-widget-header').css({'background-color': '#FF8E00', 'background-image': 'none'}); // change the  original ranger color
+
+        $("#slider-range").slider({
+          range: true,
+          min: 0,
+          max: maxValue,
+          values: handlers,
+          create: function () {
+            self.updateColors(handlers);
+          },
+          slide: function (event, ui) {
+            self.updateColors(ui.values);
+            configObj.set('thresholdMin', ui.values[0] + '');
+            configObj.set('thresholdMax', ui.values[1] + '');
+          },
+          change: function (event, ui) {
+            self.updateColors(ui.values);
           }
-        } else {
-          configObj.set('isIE9', true);
-          configObj.set('isGreenOrangeRed', true);
+        });
+      },
+      updateColors: function (handlers) {
+        var colors = [App.healthStatusGreen, App.healthStatusOrange, App.healthStatusRed];
+        var colorStops = colors[0] + ", ";
+
+        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 + ')';
+
+        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'
+        });
       }
     });
-  },
-
-  /**
-   * @returns {number}
-   */
-  getInternetExplorerVersion: function () {
-    var rv = -1; //return -1 for other browsers
-    if (navigator.appName === 'Microsoft Internet Explorer') {
-      var ua = navigator.userAgent;
-      var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
-      if (re.exec(ua) != null) {
-        rv = parseFloat(RegExp.$1); // IE version 1-10
-      }
-    }
-    return rv;
-  },
-
-  /**
-   * for widgets has hidden info(hover info),
-   * calculate the hover content top number
-   * based on how long the hiddenInfo is
-   * @returns {string}
-   */
-  hoverContentTopClass: function () {
-    var lineNum = this.get('hiddenInfo.length');
-    if (lineNum === 2) {
-      return "content-hidden-two-line";
-    }
-    if (lineNum === 3) {
-      return "content-hidden-three-line";
-    }
-    if (lineNum === 4) {
-      return "content-hidden-four-line";
-    }
-    if (lineNum === 5) {
-      return "content-hidden-five-line";
-    }
-    if (lineNum === 6) {
-      return "content-hidden-six-line";
-    }
-    return '';
-  }.property('hiddenInfo.length')
-
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/66c6d560/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 63da712..8582ad0 100644
--- a/ambari-web/test/views/main/dashboard/widget_test.js
+++ b/ambari-web/test/views/main/dashboard/widget_test.js
@@ -21,329 +21,269 @@ require('views/main/dashboard/widget');
 
 describe('App.DashboardWidgetView', function () {
 
-  var dashboardWidgetView;
-
-  dashboardWidgetView = App.DashboardWidgetView.create({
-    parentView: Em.Object.create({
-      widgetsMapper: Em.K,
-      getUserPref: function () {
-        return {complete: Em.K}
-      },
-      postUserPref: Em.K,
-      translateToReal: Em.K,
-      visibleWidgets: [],
-      hiddenWidgets: []
-    }),
-    widget: Em.Object.create({
-      id: 5,
-      sourceName: 'HDFS',
-      title: 'Widget'
-    })
-  });
+  var view;
 
-  describe('#viewID', function () {
-    it('viewID is computed with id', function () {
-      expect(dashboardWidgetView.get('viewID')).to.equal('widget-5');
+  beforeEach(function() {
+    view = App.DashboardWidgetView.create({
+      widget: Em.Object.create(),
+      parentView: Em.Object.create({
+        userPreferences: {},
+        saveWidgetsSettings: Em.K,
+        renderWidgets: Em.K
+      })
     });
   });
 
-  describe('#model', function () {
+  describe('#model', function() {
 
     beforeEach(function() {
-      sinon.stub(dashboardWidgetView, 'findModelBySource').returns(Em.Object.create({serviceName: 'HDFS'}));
+      sinon.stub(view, 'findModelBySource').returns(Em.Object.create({
+        serviceName: 'S1'
+      }));
     });
 
     afterEach(function() {
-      dashboardWidgetView.findModelBySource.restore();
+      view.findModelBySource.restore();
     });
 
-    it('sourceName is null', function () {
-      dashboardWidgetView.set('widget.sourceName', null);
-      dashboardWidgetView.propertyDidChange('model');
-      expect(dashboardWidgetView.get('model')).to.be.an.object;
+    it('sourceName is null', function() {
+      view.set('widget.sourceName', null);
+      view.propertyDidChange('model');
+      expect(view.get('model')).to.be.empty;
     });
-    it('sourceName is valid', function () {
-      dashboardWidgetView.set('widget.sourceName', 'HDFS');
-      dashboardWidgetView.propertyDidChange('model');
-      expect(dashboardWidgetView.get('model')).to.eql(Em.Object.create({serviceName: 'HDFS'}));
+
+    it('sourceName is S1', function() {
+      view.set('widget.sourceName', 'S1');
+      view.propertyDidChange('model');
+      expect(view.get('model')).to.not.be.empty;
     });
   });
 
-  describe("#didInsertElement()", function () {
+  describe('#thresholdMin', function() {
 
-    beforeEach(function () {
-      sinon.stub(App, 'tooltip', Em.K);
-    });
-    afterEach(function () {
-      App.tooltip.restore();
+    it('threshold is empty', function() {
+      view.set('widget.threshold', null);
+      expect(view.get('thresholdMin')).to.be.equal(0);
     });
 
-    it("call App.tooltip", function () {
-      dashboardWidgetView.didInsertElement();
-      expect(App.tooltip.calledOnce).to.be.true;
+    it('threshold is set', function() {
+      view.set('widget.threshold', [1, 2]);
+      expect(view.get('thresholdMin')).to.be.equal(1);
     });
   });
 
-  describe("#editWidget()", function () {
+  describe('#thresholdMax', function() {
 
-    beforeEach(function () {
-      sinon.stub(dashboardWidgetView, 'showEditDialog', Em.K);
-    });
-    afterEach(function () {
-      dashboardWidgetView.showEditDialog.restore();
+    it('threshold is empty', function() {
+      view.set('widget.threshold', null);
+      expect(view.get('thresholdMax')).to.be.equal(0);
     });
 
-    it("call showEditDialog", function () {
-      dashboardWidgetView.editWidget();
-      expect(dashboardWidgetView.showEditDialog.calledOnce).to.be.true;
+    it('threshold is set', function() {
+      view.set('widget.threshold', [1, 2]);
+      expect(view.get('thresholdMax')).to.be.equal(2);
     });
   });
 
-  describe('#hoverContentTopClass', function () {
-    var tests = [
-      {
-        h: ['', ''],
-        e: 'content-hidden-two-line',
-        m: '2 lines'
-      },
-      {
-        h: ['', '', ''],
-        e: 'content-hidden-three-line',
-        m: '3 lines'
-      },
-      {
-        h: [''],
-        e: '',
-        m: '1 line'
-      },
-      {
-        h: [],
-        e: '',
-        m: '0 lines'
-      },
-      {
-        h: ['', '', '', '', ''],
-        e: 'content-hidden-five-line',
-        m: '5 lines'
-      },
-      {
-        h: ['', '', '', ''],
-        e: 'content-hidden-four-line',
-        m: '4 lines'
-      },
-      {
-        h: ['', '', '', '', '', ''],
-        e: 'content-hidden-six-line',
-        m: '6 lines'
-      }
-    ];
-    tests.forEach(function (test) {
-      it(test.m, function () {
-        dashboardWidgetView.set('hiddenInfo', test.h);
-        expect(dashboardWidgetView.get('hoverContentTopClass')).to.equal(test.e);
+  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("#widgetConfig", function() {
-    var widget = dashboardWidgetView.get('widgetConfig').create();
-    describe("#hintInfo", function() {
-      it("is formatted with maxValue", function() {
-        widget.set('maxValue', 1);
-        widget.propertyDidChange('hintInfo');
-        expect(widget.get('hintInfo')).to.equal(Em.I18n.t('dashboard.widgets.hintInfo.common').format(1));
+    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("#observeThresh1Value", function() {
-      beforeEach(function () {
-        sinon.stub(widget, 'updateSlider', Em.K);
+
+    describe('#observeThreshMaxValue()', function() {
+
+      beforeEach(function() {
+        sinon.stub(widgetConfig, 'validateThreshold');
       });
-      afterEach(function () {
-        widget.updateSlider.restore();
+      afterEach(function() {
+        widgetConfig.validateThreshold.restore();
       });
-      var testCases = [
-        {
-          data: {
-            thresholdMin: '',
-            maxValue: 0
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('admin.users.editError.requiredField')
-          }
-        },
-        {
-          data: {
-            thresholdMin: 'NaN',
-            maxValue: 0
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('dashboard.widgets.error.invalid').format(0)
-          }
-        },
-        {
-          data: {
-            thresholdMin: '-1',
-            maxValue: 0
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('dashboard.widgets.error.invalid').format(0)
-          }
-        },
-        {
-          data: {
-            thresholdMin: '2',
-            maxValue: 1
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('dashboard.widgets.error.invalid').format(1)
-          }
-        },
-        {
-          data: {
-            thresholdMin: '1',
-            thresholdMax: '1',
-            maxValue: 2
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('dashboard.widgets.error.smaller')
-          }
-        },
-        {
-          data: {
-            thresholdMin: '1',
-            thresholdMax: '0',
-            maxValue: 2
-          },
-          result: {
-            isThresh1Error: true,
-            errorMessage1: Em.I18n.t('dashboard.widgets.error.smaller')
-          }
-        },
-        {
-          data: {
-            thresholdMin: '1',
-            thresholdMax: '2',
-            maxValue: 2
-          },
-          result: {
-            isThresh1Error: false,
-            errorMessage1: ''
-          }
-        }
-      ];
-      testCases.forEach(function (test) {
-        describe("thresholdMin - " + test.data.thresholdMin + ', maxValue - ' + test.data.maxValue, function () {
-
-          beforeEach(function () {
-            widget.set('isThresh2Error', false);
-            widget.set('thresholdMax', test.data.thresholdMax || "");
-            widget.set('thresholdMin', test.data.thresholdMin);
-            widget.set('maxValue', test.data.maxValue);
-            widget.observeThresh1Value();
-          });
-
-          it('isThresh1Error is ' + test.result.isThresh1Error, function () {
-            expect(widget.get('isThresh1Error')).to.equal(test.result.isThresh1Error);
-          });
-
-          it('errorMessage1 is ' + test.result.errorMessage1, function () {
-            expect(widget.get('errorMessage1')).to.equal(test.result.errorMessage1);
-          });
-
-          it('updateSlider is called', function () {
-            expect(widget.updateSlider.called).to.be.true;
-          });
-
-        });
+
+      it('validateThreshold should be called', function() {
+        widgetConfig.observeThreshMaxValue();
+        expect(widgetConfig.validateThreshold.calledWith('thresholdMax')).to.be.true;
       });
     });
+  });
 
-    describe("#observeThresh2Value", function() {
-      beforeEach(function () {
-        sinon.stub(widget, 'updateSlider', Em.K);
+  describe('#didInsertElement()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App, 'tooltip');
+    });
+
+    afterEach(function() {
+      App.tooltip.restore();
+    });
+
+    it('App.tooltip should be called', function() {
+      view.didInsertElement();
+      expect(App.tooltip).to.be.calledOnce;
+    });
+  });
+
+  describe('#findModelBySource()', function() {
+
+    beforeEach(function() {
+      sinon.stub(App.Service, 'find').returns(Em.Object.create({serviceName: 'S1'}));
+      sinon.stub(App.HDFSService, 'find').returns(Em.Object.create({serviceName: 'HDFS'}));
+      this.mockGet = sinon.stub(App, 'get');
+    });
+
+    afterEach(function() {
+      App.Service.find.restore();
+      App.HDFSService.find.restore();
+      this.mockGet.restore();
+    });
+
+    it('source = HOST_METRICS', function() {
+      this.mockGet.returns([{}]);
+      expect(view.findModelBySource('HOST_METRICS')).to.be.eql([{}]);
+    });
+
+    it('source = S1', function() {
+      expect(view.findModelBySource('S1')).to.be.eql(Em.Object.create({serviceName: 'S1'}));
+    });
+
+    it('source = HDFS', function() {
+      expect(view.findModelBySource('HDFS')).to.be.eql(Em.Object.create({serviceName: 'HDFS'}));
+    });
+  });
+
+  describe('#deleteWidget()', function() {
+
+    beforeEach(function() {
+      sinon.stub(view.get('parentView'), 'saveWidgetsSettings');
+      sinon.stub(view.get('parentView'), 'renderWidgets');
+      view.set('widget.id', 1);
+      view.set('parentView.userPreferences', {
+        visible: [1],
+        hidden: [],
+        threshold: []
       });
-      afterEach(function () {
-        widget.updateSlider.restore();
+      view.deleteWidget();
+    });
+
+    afterEach(function() {
+      view.get('parentView').saveWidgetsSettings.restore();
+      view.get('parentView').renderWidgets.restore();
+    });
+
+    it('saveWidgetsSettings should be called', function() {
+      expect(view.get('parentView').saveWidgetsSettings.getCall(0).args[0]).to.be.eql({
+        visible: [],
+        hidden: [1],
+        threshold: []
       });
-      var testCases = [
-        {
-          data: {
-            thresholdMax: '',
-            maxValue: 0
-          },
-          result: {
-            isThresh2Error: true,
-            errorMessage2: Em.I18n.t('admin.users.editError.requiredField')
-          }
-        },
-        {
-          data: {
-            thresholdMax: 'NaN',
-            maxValue: 0
-          },
-          result: {
-            isThresh2Error: true,
-            errorMessage2: Em.I18n.t('dashboard.widgets.error.invalid').format(0)
-          }
-        },
-        {
-          data: {
-            thresholdMax: '-1',
-            maxValue: 0
-          },
-          result: {
-            isThresh2Error: true,
-            errorMessage2: Em.I18n.t('dashboard.widgets.error.invalid').format(0)
-          }
-        },
-        {
-          data: {
-            thresholdMax: '2',
-            maxValue: 1
-          },
-          result: {
-            isThresh2Error: true,
-            errorMessage2: Em.I18n.t('dashboard.widgets.error.invalid').format(1)
-          }
-        },
-        {
-          data: {
-            thresholdMax: '2',
-            maxValue: 2
-          },
-          result: {
-            isThresh2Error: false,
-            errorMessage2: ''
-          }
-        }
-      ];
-      testCases.forEach(function (test) {
-        describe("thresholdMax - " + test.data.thresholdMax + ', maxValue - ' + test.data.maxValue, function () {
-
-          beforeEach(function () {
-            widget.set('thresholdMax', test.data.thresholdMax || "");
-            widget.set('maxValue', test.data.maxValue);
-            widget.observeThresh2Value();
-          });
-
-          it('isThresh2Error is ' + test.result.isThresh2Error, function () {
-            expect(widget.get('isThresh2Error')).to.equal(test.result.isThresh2Error);
-          });
-
-          it('errorMessage2 is ' + JSON.stringify(test.result.errorMessage2), function () {
-            expect(widget.get('errorMessage2')).to.equal(test.result.errorMessage2);
-          });
-
-          it('updateSlider is called', function () {
-            expect(widget.updateSlider.called).to.be.true;
-          });
-        });
+    });
+
+    it('renderWidgets should be called', function() {
+      expect(view.get('parentView').renderWidgets).to.be.calledOnce;
+    });
+  });
+
+  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');
+    });
+
+    afterEach(function() {
+      App.ModalPopup.show.restore();
+    });
+
+    it('App.ModalPopup.show should be called', function() {
+      view.showEditDialog();
+      expect(App.ModalPopup.show).to.be.calledOnce;
     });
   });