瀏覽代碼

AMBARI-16461: PXF Agents Live Widget on Dashboard needs custom widget to display only single threshold i.e., Green/Red only (Goutam Tadi via mithmatt)

Matt 9 年之前
父節點
當前提交
297183521c

+ 1 - 0
ambari-web/app/assets/test/tests.js

@@ -255,6 +255,7 @@ var files = [
   'test/views/main/dashboard/widget_test',
   'test/views/main/dashboard/widgets_test',
   'test/views/main/dashboard/widgets/text_widget_test',
+  'test/views/main/dashboard/widgets/text_widget_single_threshold_test',
   'test/views/main/dashboard/widgets/uptime_text_widget_test',
   'test/views/main/dashboard/widgets/node_managers_live_test',
   'test/views/main/dashboard/widgets/datanode_live_test',

+ 4 - 3
ambari-web/app/messages.js

@@ -1796,7 +1796,6 @@ Em.I18n.translations = {
   // Node Manager custom command to refresh YARN Apps on Slider
   'services.service.actions.run.createYARNDirectories':'Create YARN Directories',
   'services.service.actions.run.createYARNDirectories.confirmation':'Please confirm. This will create necessary folders on the NodeManagers required for running YARN Apps on Slider, such as LLAP. This does not need to restart NodeManagers.',
-  
   'services.service.actions.run.immediateStopHawqService.context':'Stop HAWQ Service (Immediate Mode)',
   'services.service.actions.run.immediateStopHawqService.label':'Stop HAWQ Service (Immediate Mode)',
   'services.service.actions.run.immediateStopHawqSegment.label':'Stop (Immediate Mode)',
@@ -2654,7 +2653,8 @@ Em.I18n.translations = {
   'dashboard.widgets.error.invalid': 'Invalid! Enter a number between 0 - {0}',
   'dashboard.widgets.error.smaller': 'Threshold 1 should be smaller than threshold 2!',
   'dashboard.widgets.HawqSegmentUp': 'HAWQ Segments Live',
-  'dashboard.widgets.PxfUp': 'PXFs Live',
+  'dashboard.widgets.PxfUp': 'PXF Agents Live',
+  'dashboard.widgets.PXFAgents': 'PXF Agents',
 
   'dashboard': {
     'widgets': {
@@ -2663,7 +2663,8 @@ Em.I18n.translations = {
         'common': 'Edit the percentage thresholds to change the color of current pie chart. <br />Enter two numbers between 0 to {0}',
         'hint1': 'Edit the percentage of thresholds to change the color of current widget. <br />Assume all components UP is 100, and all DOWN is 0. <br /> So enter two numbers between 0 to {0}',
         'hint2': 'Edit the thresholds to change the color of current widget.<br /><br />So enter two numbers larger than 0.',
-        'hint3': 'Edit the thresholds to change the color of current widget.<br />The unit is milli-second. <br />So enter two numbers larger than 0. '
+        'hint3': 'Edit the thresholds to change the color of current widget.<br />The unit is milli-second. <br />So enter two numbers larger than 0. ',
+        'hint4': 'Edit the threshold value representing the number of {0} that are down to change the color of the widget. <br />If the number of {0} that are down is greater than the threshold, the widget will show warning in Red. <br />Choose a number between 0 and {1}. '
       }
     }
   },

+ 1 - 0
ambari-web/app/mixins.js

@@ -30,6 +30,7 @@ require('mixins/common/table_server_view_mixin');
 require('mixins/common/table_server_mixin');
 require('mixins/main/dashboard/widgets/editable');
 require('mixins/main/dashboard/widgets/editable_with_limit');
+require('mixins/main/dashboard/widgets/single_numeric_threshold');
 require('mixins/main/host/details/host_components/decommissionable');
 require('mixins/main/host/details/host_components/install_component');
 require('mixins/main/host/details/actions/install_new_version');

+ 1 - 1
ambari-web/app/mixins/main/dashboard/widgets/editable_with_limit.js

@@ -136,4 +136,4 @@ App.EditableWithLimitWidgetMixin = Em.Mixin.create({
     });
   }
 
-});
+});

+ 156 - 0
ambari-web/app/mixins/main/dashboard/widgets/single_numeric_threshold.js

@@ -0,0 +1,156 @@
+/**
+ * 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');
+
+/**
+ * @type {Em.Mixin}
+ */
+App.SingleNumericThresholdMixin = Em.Mixin.create({
+
+  /**
+   * @type {Em.Object}
+   * @class
+   */
+  widgetConfig: Ember.Object.extend({
+    thresh1: '',
+    hintInfo: '',
+    isThresh1Error: false,
+    errorMessage1: "",
+
+    maxValue: 0,
+    observeThresh1Value: function () {
+      var thresh1 = this.get('thresh1');
+      var maxValue = this.get('maxValue');
+
+      if (thresh1.trim() !== "") {
+        if (isNaN(thresh1) || thresh1 > maxValue || thresh1 < 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('thresh1', 'maxValue'),
+
+    updateSlider: function () {
+      var thresh1 = this.get('thresh1');
+      // update the slider handles and color
+      if (this.get('isThresh1Error') === false) {
+        $("#slider-range")
+          .slider('values', 0, parseFloat(thresh1))
+      }
+    }
+  }),
+
+  /**
+   * edit widget
+   * @param {object} event
+   */
+  editWidget: function () {
+    var parent = this;
+    var maxTmp = parseFloat(this.get('maxValue'));
+    var configObj = this.get('widgetConfig').create({
+      thresh1: this.get('thresh1') + '',
+      hintInfo: this.get('hintInfo') + '',
+      maxValue: parseFloat(this.get('maxValue'))
+    });
+
+    var browserVersion = this.getInternetExplorerVersion();
+    App.ModalPopup.show({
+        header: Em.I18n.t('dashboard.widgets.popupHeader'),
+        classNames: ['sixty-percent-width-modal-edit-widget'],
+        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) {
+            parent.set('thresh1', parseFloat(configObj.get('thresh1')));
+            if (!App.get('testMode')) {
+              // save to persist
+              var bigParent = parent.get('parentView');
+              bigParent.getUserPref(bigParent.get('persistKey')).complete(function () {
+                var oldValue = bigParent.get('currentPrefObject');
+                oldValue.threshold[parseInt(parent.id, 10)] = [configObj.get('thresh1')];
+                bigParent.postUserPref(parent.get('persistKey'), oldValue);
+              });
+            }
+            this.hide();
+          }
+        },
+        didInsertElement: function () {
+          this._super();
+          var handlers = [configObj.get('thresh1')];
+          var colors = [App.healthStatusGreen, App.healthStatusRed]; //color green,red
+
+          if (browserVersion === -1 || browserVersion > 9) {
+            configObj.set('isIE9', false);
+            configObj.set('isGreenRed', true);
+            $("#slider-range").slider({
+              range: false,
+              min: 0,
+              max: maxTmp,
+              values: handlers,
+              create: function () {
+              updateColors(handlers);
+              },
+              slide: function (event, ui) {
+              updateColors(ui.values);
+                configObj.set('thresh1', ui.values[0] + '');
+              },
+              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 / 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);
+
+              sliderElement.find('.ui-widget-header').css({'background-color': '#FF8E00', 'background-image': 'none'}); // change the  original ranger color
+            }
+          } else {
+            configObj.set('isIE9', true);
+            configObj.set('isGreenRed', true);
+          }
+        }
+
+      });
+
+  }
+
+});

+ 1 - 1
ambari-web/app/styles/modal_popups.less

@@ -618,4 +618,4 @@
       }
     }
   }
-}
+}

+ 53 - 0
ambari-web/app/templates/main/dashboard/edit_widget_popup_single_threshold.hbs

@@ -0,0 +1,53 @@
+{{!
+* 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.
+}}
+
+<form class="form-horizontal" autocomplete="off">
+  <div class="each-row">
+    <div class="alert alert-info">
+      {{{view.configPropertyObj.hintInfo}}}
+    </div>
+  </div>
+
+  <div class="row-fluid" id= "min-height-limit">
+    {{#if view.configPropertyObj.isIE9}}
+      {{#if view.configPropertyObj.isGreenRed}}
+        <div class="progress span9">
+          <div class="bar bar-success" style="width: 33%;"></div>
+          <div class="bar bar-danger" style="width: 34%;"></div>
+        </div>
+      {{else}}
+        <div class="progress span9">
+           <div class="bar bar-danger" style="width: 33%;"></div>
+           <div class="bar bar-success" style="width: 34%;"></div>
+        </div>
+      {{/if}}
+    {{else}}
+      <div class="span9" id="slider-range"></div>
+    {{/if}}
+  </div>
+
+  <div class="row-fluid">
+    <div id="slider-value1" class="value-on-slider span2" style="margin-left: 20px">0</div>
+      <div id="slider-value2" style="margin-left: 100px"{{bindAttr class="view.configPropertyObj.isThresh1Error:slider-error :value-on-slider :span4"}}>
+        {{view Ember.TextField valueBinding="view.configPropertyObj.thresh1"}}
+        <span class="help-inline">{{view.configPropertyObj.errorMessage1}}</span>
+      </div>
+    <div id="slider-value3" style="margin-left: 150px" class="value-on-slider span2">{{view.configPropertyObj.maxValue}}</div>
+  </div>
+
+</form>

+ 1 - 0
ambari-web/app/views.js

@@ -226,6 +226,7 @@ require('views/main/dashboard/cluster_metrics/network');
 require('views/main/dashboard/widget');
 require('views/main/dashboard/widgets');
 require('views/main/dashboard/widgets/text_widget');
+require('views/main/dashboard/widgets/text_widget_single_threshold');
 require('views/main/dashboard/widgets/uptime_text_widget');
 require('views/main/dashboard/widgets/links_widget');
 require('views/main/dashboard/widgets/pie_chart_widget');

+ 1 - 2
ambari-web/app/views/main/dashboard/widgets.js

@@ -491,7 +491,7 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap
     visible: [],
     hidden: [],
     threshold: {1: [80, 90], 2: [85, 95], 3: [90, 95], 4: [80, 90], 5: [1000, 3000], 6: [], 7: [], 8: [], 9: [], 10: [], 11: [], 12: [], 13: [70, 90], 14: [150, 250], 15: [3, 10], 16: [],
-      17: [70, 90], 18: [], 19: [50, 75], 20: [50, 75], 21: [85, 95], 22: [85, 95], 23: [], 24: [75, 90], 25: [75, 90]} // id:[thresh1, thresh2]
+      17: [70, 90], 18: [], 19: [50, 75], 20: [50, 75], 21: [85, 95], 22: [85, 95], 23: [], 24: [75, 90], 25: []} // id:[thresh1, thresh2]
   }),
 
   /**
@@ -540,4 +540,3 @@ App.MainDashboardWidgetsView = Em.View.extend(App.UserPref, App.LocalStorage, Ap
   showAlertsPopup: Em.K
 
 });
-

+ 5 - 6
ambari-web/app/views/main/dashboard/widgets/pxf_live.js

@@ -29,7 +29,7 @@ function counterOrNA(key) {
   });
 }
 
-App.PxfUpView = App.TextDashboardWidgetView.extend(App.EditableWithLimitWidgetMixin, {
+App.PxfUpView = App.TextDashboardSingleThresholdWidgetView.extend(App.SingleNumericThresholdMixin,{
 
   title: Em.I18n.t('dashboard.widgets.PxfUp'),
   id: '25',
@@ -46,9 +46,8 @@ App.PxfUpView = App.TextDashboardWidgetView.extend(App.EditableWithLimitWidgetMi
 
   hiddenInfoClass: "hidden-info-three-line",
 
-  thresh1: 75,
-  thresh2: 90,
-  maxValue: 100,
+  thresh1: 0,
+  maxValue: counterOrNA('pxfsTotal'),
 
   pxfsStarted: counterOrNA('pxfsStarted'),
 
@@ -63,7 +62,7 @@ App.PxfUpView = App.TextDashboardWidgetView.extend(App.EditableWithLimitWidgetMi
     if (this.get('someMetricsNA')) {
       return null;
     }
-    return (this.get('pxfsStarted') / this.get('model.pxfsTotal')).toFixed(2) * 100;
+    return (this.get('pxfsTotal') - this.get('pxfsStarted') );
   }.property('model.pxfsTotal', 'pxfsStarted', 'someMetricsNA'),
 
   /**
@@ -78,7 +77,7 @@ App.PxfUpView = App.TextDashboardWidgetView.extend(App.EditableWithLimitWidgetMi
 
   hintInfo: function () {
     var maxTmp = parseFloat(this.get('maxValue'));
-    return Em.I18n.t('dashboard.widgets.hintInfo.hint1').format(maxTmp);
+    return Em.I18n.t('dashboard.widgets.hintInfo.hint4').format(Em.I18n.t('dashboard.widgets.PXFAgents'),maxTmp);
   }.property('maxValue'),
 
   /**

+ 37 - 0
ambari-web/app/views/main/dashboard/widgets/text_widget_single_threshold.js

@@ -0,0 +1,37 @@
+/**
+ * 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');
+
+App.TextDashboardSingleThresholdWidgetView = App.DashboardWidgetView.extend({
+
+  templateName: require('templates/main/dashboard/widgets/simple_text'),
+
+  classNameBindings: ['isRed', 'isGreen', 'isNA'],
+  isGreen: Em.computed.lteProperties('data', 'thresh1'),
+  isRed: Em.computed.gtProperties('data', 'thresh1'),
+
+  isNA: function () {
+    return this.get('data') === null;
+  }.property('data'),
+
+  hiddenInfo: [],
+
+  maxValue: null,
+
+});

+ 1 - 1
ambari-web/test/aliases/computed/gtProperties.js

@@ -69,4 +69,4 @@ App.TestAliases.testAsComputedGtProperties = function (context, propertyName, de
 
   });
 
-};
+};

+ 57 - 0
ambari-web/test/views/main/dashboard/widgets/text_widget_single_threshold_test.js

@@ -0,0 +1,57 @@
+/**
+ * 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');
+
+require('views/main/dashboard/widget');
+require('views/main/dashboard/widgets/text_widget_single_threshold');
+
+function getView() {
+  return App.TextDashboardSingleThresholdWidgetView.create({thresh1:0});
+}
+
+describe('App.TextDashboardSingleThresholdWidgetView', function() {
+
+  var tests = [
+    {
+      data: 1,
+      e: {
+        isNA: false
+      }
+    },
+    {
+      data: null,
+      e: {
+        isNA: true
+      }
+    }
+  ];
+
+  tests.forEach(function(test) {
+    describe('data - ' + test.data + ' | thresh1 - 0', function() {
+      var textDashboardWidgetSingleThresholdView = App.TextDashboardSingleThresholdWidgetView.create({thresh1:0});
+      textDashboardWidgetSingleThresholdView.set('data', test.data);
+      it('isNA', function() {
+        expect(textDashboardWidgetSingleThresholdView.get('isNA')).to.equal(test.e.isNA);
+      });
+    });
+  });
+
+  App.TestAliases.testAsComputedGtProperties(getView(), 'isRed', 'data', 'thresh1');
+  App.TestAliases.testAsComputedLteProperties(getView(), 'isGreen', 'data', 'thresh1');
+});