You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by on...@apache.org on 2014/12/05 18:43:29 UTC

ambari git commit: AMBARI-8563. Alerts UI: Simplify editing Alert-Definition. (onechiporenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 3c8e7ba78 -> cd07f8844


AMBARI-8563. Alerts UI: Simplify editing Alert-Definition. (onechiporenko)


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

Branch: refs/heads/trunk
Commit: cd07f8844180a352c88241f8ae80968d5139776d
Parents: 3c8e7ba
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Fri Dec 5 19:40:21 2014 +0200
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Fri Dec 5 19:40:21 2014 +0200

----------------------------------------------------------------------
 .../assets/data/alerts/alertDefinitions.json    |   1 +
 ambari-web/app/assets/test/tests.js             |   1 +
 .../alerts/definition_configs_controller.js     | 184 +++++++++--------
 ambari-web/app/models/alert_config.js           | 160 ++++++++++++---
 .../alerts/configs/alert_config_threshold.hbs   |  18 +-
 .../main/alerts/definition_details.hbs          |  33 +--
 .../definitions_configs_controller_test.js      |  50 +++--
 ambari-web/test/models/alert_config_test.js     | 204 +++++++++++++++++++
 8 files changed, 479 insertions(+), 172 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/app/assets/data/alerts/alertDefinitions.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/alerts/alertDefinitions.json b/ambari-web/app/assets/data/alerts/alertDefinitions.json
index c16b536..20d83bd 100644
--- a/ambari-web/app/assets/data/alerts/alertDefinitions.json
+++ b/ambari-web/app/assets/data/alerts/alertDefinitions.json
@@ -123,6 +123,7 @@
       "AlertDefinition" : {
         "cluster_name" : "tdk",
         "component_name" : null,
+        "description" : null,
         "enabled" : true,
         "id" : 4,
         "ignore_host" : false,

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/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 35a80cf..ca815b2 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -224,6 +224,7 @@ var files = ['test/init_model_test',
   'test/models/service/hdfs_test',
   'test/models/service/yarn_test',
   'test/models/alert_test',
+  'test/models/alert_config_test',
   'test/models/alert_definition_test',
   'test/models/authentication_test',
   'test/models/cluster_states_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/app/controllers/main/alerts/definition_configs_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alerts/definition_configs_controller.js b/ambari-web/app/controllers/main/alerts/definition_configs_controller.js
index 23af711..e283e16 100644
--- a/ambari-web/app/controllers/main/alerts/definition_configs_controller.js
+++ b/ambari-web/app/controllers/main/alerts/definition_configs_controller.js
@@ -70,32 +70,6 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   }.property(),
 
   /**
-   * Compute thresholds from value using <code>content.reporting</code>
-   * @type {Number|Null}
-   */
-  thresholdsFrom: function () {
-    var warning = this.get('content.reporting').findProperty('type', 'warning');
-    if (warning && warning.get('value')) {
-      return warning.get('value');
-    } else {
-      return null;
-    }
-  }.property('content.reporting.@each.value'),
-
-  /**
-   * Compute thresholds to value using <code>content.reporting</code>
-   * @type {Number|Null}
-   */
-  thresholdsTo: function () {
-    var critical = this.get('content.reporting').findProperty('type', 'critical');
-    if (critical && critical.get('value')) {
-      return critical.get('value');
-    } else {
-      return null;
-    }
-  }.property('content.reporting.@each.value'),
-
-  /**
    * Change options of "Component", after changing value of "Service" config
    * @method onServiceSelect
    */
@@ -124,6 +98,19 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   },
 
   /**
+   * @return {string|Null}
+   * @method getThresholdsProperty
+   */
+  getThresholdsProperty: function (type, property) {
+    var warning = this.get('content.reporting').findProperty('type', type);
+    if (warning && warning.get(property)) {
+      return warning.get(property);
+    } else {
+      return null;
+    }
+  },
+
+  /**
    * Render array of configs for appropriate alert definition type
    * @method renderConfigs
    */
@@ -158,7 +145,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   /**
    * Render config properties for port-type alert definition
    * @method renderPortConfigs
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderPortConfigs: function () {
     var result = [];
@@ -170,19 +157,20 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
     }
 
     result = result.concat([
+      App.AlertConfigProperties.Description.create({
+        value: isWizard ? '' : alertDefinition.get('description')
+      }),
       App.AlertConfigProperties.Interval.create({
         value: isWizard ? '' : alertDefinition.get('interval')
       }),
-      App.AlertConfigProperties.Thresholds.create({
-        value: isWizard ? '' : this.get('thresholdsFrom') + '-' + this.get('thresholdsTo'),
-        from: isWizard ? '' : this.get('thresholdsFrom'),
-        to: isWizard ? '' : this.get('thresholdsTo')
-      }),
-      App.AlertConfigProperties.URI.create({
-        value: isWizard ? '' : alertDefinition.get('uri')
+      App.AlertConfigProperties.Thresholds.OkThreshold.create({
+        label: 'Thresholds',
+        text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
       }),
-      App.AlertConfigProperties.DefaultPort.create({
-        value: isWizard ? '' : alertDefinition.get('defaultPort')
+      App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
       })
     ]);
 
@@ -192,7 +180,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   /**
    * Render config properties for metric-type alert definition
    * @method renderMetricConfigs
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderMetricConfigs: function () {
     var result = [];
@@ -204,29 +192,25 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
     }
 
     result = result.concat([
+      App.AlertConfigProperties.Description.create({
+        value: isWizard ? '' : alertDefinition.get('description')
+      }),
       App.AlertConfigProperties.Interval.create({
         value: isWizard ? '' : alertDefinition.get('interval')
       }),
-      App.AlertConfigProperties.Thresholds.create({
-        value: isWizard ? '' : this.get('thresholdsFrom') + '-' + this.get('thresholdsTo'),
-        from: isWizard ? '' : this.get('thresholdsFrom'),
-        to: isWizard ? '' : this.get('thresholdsTo')
-      }),
-      App.AlertConfigProperties.URIExtended.create({
-        value: isWizard ? '' : JSON.stringify({
-          http: alertDefinition.get('uri.http'),
-          https: alertDefinition.get('uri.https'),
-          https_property: alertDefinition.get('uri.httpsProperty'),
-          https_property_value: alertDefinition.get('uri.httpsPropertyValue')
-        })
+      App.AlertConfigProperties.Thresholds.OkThreshold.create({
+        label: 'Thresholds',
+        showInputForValue: false,
+        text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
       }),
-      App.AlertConfigProperties.Metrics.create({
-        value: isWizard ? '' : alertDefinition.get('jmx.propertyList') ? alertDefinition.get('jmx.propertyList').join(',\n') : alertDefinition.get('ganglia.propertyList').join(',\n'),
-        isJMXMetric: isWizard ? false : !!alertDefinition.get('jmx.propertyList')
+      App.AlertConfigProperties.Thresholds.WarningThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
       }),
-      App.AlertConfigProperties.FormatString.create({
-        value: isWizard ? '' : alertDefinition.get('jmx.value') ? alertDefinition.get('jmx.value') : alertDefinition.get('ganglia.value'),
-        isJMXMetric: isWizard ? false : !!alertDefinition.get('jmx.value')
+      App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
       })
     ]);
 
@@ -236,7 +220,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   /**
    * Render config properties for web-type alert definition
    * @method renderWebConfigs
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderWebConfigs: function () {
     var result = [];
@@ -248,21 +232,27 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
     }
 
     result = result.concat([
+      App.AlertConfigProperties.Description.create({
+        value: isWizard ? '' : alertDefinition.get('description')
+      }),
       App.AlertConfigProperties.Interval.create({
         value: isWizard ? '' : alertDefinition.get('interval')
       }),
-      App.AlertConfigProperties.Thresholds.create({
-        value: isWizard ? '' : this.get('thresholdsFrom') + '-' + this.get('thresholdsTo'),
-        from: isWizard ? '' : this.get('thresholdsFrom'),
-        to: isWizard ? '' : this.get('thresholdsTo')
+      App.AlertConfigProperties.Thresholds.OkThreshold.create({
+        label: 'Thresholds',
+        showInputForValue: false,
+        text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
+      }),
+      App.AlertConfigProperties.Thresholds.WarningThreshold.create({
+        showInputForValue: false,
+        text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
       }),
-      App.AlertConfigProperties.URIExtended.create({
-        value: isWizard ? '' : JSON.stringify({
-          http: alertDefinition.get('uri.http'),
-          https: alertDefinition.get('uri.https'),
-          https_property: alertDefinition.get('uri.httpsProperty'),
-          https_property_value: alertDefinition.get('uri.httpsPropertyValue')
-        })
+      App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
+        showInputForValue: false,
+        text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
       })
     ]);
 
@@ -272,7 +262,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   /**
    * Render config properties for script-type alert definition
    * @method renderScriptConfigs
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderScriptConfigs: function () {
     var result = [];
@@ -284,16 +274,24 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
     }
 
     result = result.concat([
+      App.AlertConfigProperties.Description.create({
+        value: isWizard ? '' : alertDefinition.get('description')
+      }),
       App.AlertConfigProperties.Interval.create({
         value: isWizard ? '' : alertDefinition.get('interval')
       }),
-      App.AlertConfigProperties.Thresholds.create({
-        value: isWizard ? '' : this.get('thresholdsFrom') + '-' + this.get('thresholdsTo'),
-        from: isWizard ? '' : this.get('thresholdsFrom'),
-        to: isWizard ? '' : this.get('thresholdsTo')
+      App.AlertConfigProperties.Thresholds.OkThreshold.create({
+        label: 'Thresholds',
+        text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
+      }),
+      App.AlertConfigProperties.Thresholds.WarningThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
       }),
-      App.AlertConfigProperties.Path.create({
-        value: isWizard ? '' : alertDefinition.get('location')
+      App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
       })
     ]);
 
@@ -303,25 +301,35 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   /**
    * Render config properties for aggregate-type alert definition
    * @method renderAggregateConfigs
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderAggregateConfigs: function () {
     var isWizard = this.get('isWizard');
     var alertDefinition = this.get('content');
     return [
-      App.AlertConfigProperties.AlertNameSelected.create({
-        value: isWizard ? this.get('aggregateAlertNames')[0] : alertDefinition.get('name'),
-        options: this.get('aggregateAlertNames')
-      }),
       App.AlertConfigProperties.Description.create({
         value: isWizard ? '' : alertDefinition.get('description')
+      }),
+      App.AlertConfigProperties.Thresholds.OkThreshold.create({
+        label: 'Thresholds',
+        showInputForValue: false,
+        text: isWizard ? '' : this.getThresholdsProperty('ok', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('ok', 'value')
+      }),
+      App.AlertConfigProperties.Thresholds.WarningThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('warning', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('warning', 'value')
+      }),
+      App.AlertConfigProperties.Thresholds.CriticalThreshold.create({
+        text: isWizard ? '' : this.getThresholdsProperty('critical', 'text'),
+        value: isWizard ? '' : this.getThresholdsProperty('critical', 'value')
       })
     ];
   },
 
   /**
    * Render common list of configs used in almost all alert types in wizard
-   * @returns {Array}
+   * @returns {App.AlertConfigProperty[]}
    */
   renderCommonWizardConfigs: function () {
     return [
@@ -347,9 +355,6 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
       }),
       App.AlertConfigProperties.HostAlertType.create({
         value: false
-      }),
-      App.AlertConfigProperties.Description.create({
-        value: ''
       })
     ];
   },
@@ -361,6 +366,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   editConfigs: function () {
     this.get('configs').forEach(function (property) {
       property.set('previousValue', property.get('value'));
+      property.set('previousText', property.get('text'));
     });
     this.get('configs').setEach('isDisabled', false);
     this.set('canEdit', true);
@@ -373,6 +379,7 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
   cancelEditConfigs: function () {
     this.get('configs').forEach(function (property) {
       property.set('value', property.get('previousValue'));
+      property.set('text', property.get('previousText'));
     });
     this.get('configs').setEach('isDisabled', true);
     this.set('canEdit', false);
@@ -393,11 +400,20 @@ App.MainAlertDefinitionConfigsController = Em.Controller.extend({
       data: {
         id: this.get('content.id'),
         data: this.getPropertiesToUpdate(true)
-      }
+      },
+      success: 'saveConfigsSuccessCallback'
     });
   },
 
   /**
+   * Success-callback for saveConfigs-request
+   * @method saveConfigsSuccessCallback
+   */
+  saveConfigsSuccessCallback: function () {
+    App.router.get('updateController').updateAlertDefinitions(Em.K);
+  },
+
+  /**
    * Create object with new values to put it on server
    * @param {boolean} onlyChanged
    * @method getPropertiesToUpdate

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/app/models/alert_config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert_config.js b/ambari-web/app/models/alert_config.js
index ed337f0..948a38a 100644
--- a/ambari-web/app/models/alert_config.js
+++ b/ambari-web/app/models/alert_config.js
@@ -213,42 +213,97 @@ App.AlertConfigProperties = {
     classNames: 'alert-interval-input',
     apiProperty: 'interval'
   }),
-  Thresholds: App.AlertConfigProperty.extend({
-    name: 'thresholds',
-    label: 'Thresholds',
+
+  /**
+   * Implements threshold
+   * Main difference from other alertConfigProperties:
+   * it has two editable parts - <code>value</code> and <code>text</code>
+   * User may configure it to edit only one of them (use flags <code>showInputForValue</code> and <code>showInputForText</code>)
+   * This flags also determines update value and text in the API-request or not (see <code>App.AlertConfigProperties.Thresholds</code> for more examples)
+   *
+   * @type {App.AlertConfigProperty.Threshold}
+   */
+  Threshold: App.AlertConfigProperty.extend({
+
+    name: 'threshold',
+
+    /**
+     * Property text cache to realise undo function
+     * @type {*}
+     */
+    previousText: null,
+
+    label: '',
+
+    /**
+     * OK|WARNING|CRITICAL
+     * @type {string}
+     */
+    badge: '',
+
+    /**
+     * threshold-value
+     * @type {string}
+     */
+    value: '',
+
+    /**
+     * threshold-text
+     * @type {string}
+     */
+    text: '',
+
     displayType: 'threshold',
+
     classNames: 'alert-thresholds-input',
-    from: '',
-    to: '',
-    value: '',
 
-    setFromTo: function () {
-      this.set('doNotChangeValue', true);
-      this.set('from', this.get('value').split('-')[0]);
-      this.set('to', this.get('value').split('-')[1]);
-      this.set('doNotChangeValue', false);
-    }.observes('value'),
+    apiProperty: [],
 
-    setValue: function () {
-      if (!this.get('doNotChangeValue')) {
-        this.set('value', this.get('from') + '-' + this.get('to'));
+    /**
+     * @type {string[]}
+     */
+    apiFormattedValue: function () {
+      var ret = [];
+      if (this.get('showInputForValue')) {
+        ret.push(this.get('value'));
+      }
+      if (this.get('showInputForText')) {
+        ret.push(this.get('text'));
       }
-    }.observes('from', 'to'),
+      return ret;
+    }.property('value', 'text', 'showInputForValue', 'showInputForText'),
 
-    // flag for providing correct from, to and value recomputing
-    doNotChangeValue: false,
+    /**
+     * Determines if <code>value</code> should be visible and editable (if not - won't update API-value)
+     * @type {bool}
+     */
+    showInputForValue: true,
+
+    /**
+     * Determines if <code>text</code> should be visible and editable (if not - won't update API-text)
+     * @type {bool}
+     */
+    showInputForText: true,
+
+    /**
+     * Custom css-class for different badges
+     * type {string}
+     */
+    badgeCssClass: function () {
+      return 'alert-state-' + this.get('badge');
+    }.property('badge'),
+
+    /**
+     * Determines if <code>value</code> or <code>text</code> were changed
+     * @type {bool}
+     */
+    wasChanged: function () {
+      return (this.get('previousValue') !== null && this.get('value') !== this.get('previousValue')) ||
+        (this.get('previousText') !== null && this.get('text') !== this.get('previousText'));
+    }.property('value', 'text', 'previousValue', 'previousText')
 
-    apiProperty: [
-      'source.reporting.warning.value',
-      'source.reporting.critical.value'
-    ],
-    apiFormattedValue: function () {
-      return [
-          +this.get('from'),
-          +this.get('to')
-      ]
-    }.property('from', 'to')
   }),
+
   URI: App.AlertConfigProperty.extend({
     name: 'uri',
     label: 'URI',
@@ -308,4 +363,53 @@ App.AlertConfigProperties = {
     }.property('isJMXMetric')
   })
 
+};
+
+App.AlertConfigProperties.Thresholds = {
+
+  OkThreshold: App.AlertConfigProperties.Threshold.extend({
+    badge: 'OK',
+    name: 'ok_threshold',
+    apiProperty: function () {
+      var ret = [];
+      if (this.get('showInputForValue')) {
+        ret.push('source.reporting.ok.value');
+      }
+      if (this.get('showInputForText')) {
+        ret.push('source.reporting.ok.text');
+      }
+      return ret;
+    }.property('showInputForValue', 'showInputForText')
+  }),
+
+  WarningThreshold: App.AlertConfigProperties.Threshold.extend({
+    badge: 'WARNING',
+    name: 'warning_threshold',
+    apiProperty: function () {
+      var ret = [];
+      if (this.get('showInputForValue')) {
+        ret.push('source.reporting.warning.value');
+      }
+      if (this.get('showInputForText')) {
+        ret.push('source.reporting.warning.text');
+      }
+      return ret;
+    }.property('showInputForValue', 'showInputForText')
+  }),
+
+  CriticalThreshold: App.AlertConfigProperties.Threshold.extend({
+    badge: 'CRITICAL',
+    name: 'critical_threshold',
+    apiProperty: function () {
+      var ret = [];
+      if (this.get('showInputForValue')) {
+        ret.push('source.reporting.critical.value');
+      }
+      if (this.get('showInputForText')) {
+        ret.push('source.reporting.critical.text');
+      }
+      return ret;
+    }.property('showInputForValue', 'showInputForText')
+  })
+
 };
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/app/templates/main/alerts/configs/alert_config_threshold.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/alerts/configs/alert_config_threshold.hbs b/ambari-web/app/templates/main/alerts/configs/alert_config_threshold.hbs
index 9fe72ed..79e88b6 100644
--- a/ambari-web/app/templates/main/alerts/configs/alert_config_threshold.hbs
+++ b/ambari-web/app/templates/main/alerts/configs/alert_config_threshold.hbs
@@ -17,13 +17,17 @@
 }}
 
 <div class="control-group">
- <span class="alert-state-single-host label alert-state-WARNING">WARNING</span>&nbsp;
- {{view Em.TextField valueBinding="view.property.from" disabledBinding="view.property.isDisabled" class="span2"}}
-</div>
-
-<div>
- <span class="alert-state-single-host label alert-state-CRITICAL">CRITICAL</span>&nbsp;
- {{view Em.TextField valueBinding="view.property.to" disabledBinding="view.property.isDisabled" class="span2"}}
+  <div class="span3"><span {{bindAttr class="view.property.badgeCssClass :alert-state-single-host :label"}}>{{view.property.badge}}</span>&nbsp;</div>
+  <div class="span2">
+    {{#if view.property.showInputForValue}}
+      {{view Em.TextField valueBinding="view.property.value" disabledBinding="view.property.isDisabled" class="span11"}}
+    {{/if}}
+  </div>
+  <div class="span7">
+    {{#if view.property.showInputForText}}
+      {{view Em.TextField valueBinding="view.property.text" disabledBinding="view.property.isDisabled"}}
+    {{/if}}
+  </div>
 </div>
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/app/templates/main/alerts/definition_details.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/alerts/definition_details.hbs b/ambari-web/app/templates/main/alerts/definition_details.hbs
index 1bbb5a8..6969162 100644
--- a/ambari-web/app/templates/main/alerts/definition_details.hbs
+++ b/ambari-web/app/templates/main/alerts/definition_details.hbs
@@ -23,6 +23,7 @@
 
     {{! Left column }}
     <div class="span9">
+      {{! Alert Definition Name }}
       <div class="definition-name row-fluid">
         {{#if controller.editing.label.isEditing}}
           <div {{bindAttr class="controller.editing.label.isError:error :span5 :name-text-field :control-group"}}>
@@ -45,33 +46,11 @@
           {{/isAccessible}}
         {{/unless}}
       </div>
+      {{! Alert Definition Name end }}
+
       <div><a href="javascript:void(null)" data-toggle="modal" {{action back}}><i class="icon-arrow-left"></i>&nbsp;{{t common.back}}</a></div>
-      <div class="definition-details-block">
-        <strong>{{t common.description}}</strong>
-        {{#unless controller.editing.description.isEditing}}
-          {{#isAccessible ADMIN}}
-            <a {{action edit controller.editing.description target="controller"}} class="pull-right edit-link">
-              <strong>{{t common.edit}}</strong>
-            </a>
-          {{/isAccessible}}
-        {{/unless}}
-        <hr>
-        {{#if controller.editing.description.isEditing}}
-          <div {{bindAttr class="controller.editing.description.isError:error :control-group :text-area-edit"}}>
-            {{view Em.TextArea valueBinding="controller.editing.description.value"}}
-          </div>
-          <div class="edit-buttons">
-            <button {{action cancelEdit controller.editing.description target="controller"}} class="btn">{{t common.cancel}}</button>
-            <button {{bindAttr disabled="controller.editing.description.isError"}} {{action saveEdit controller.editing.description target="controller"}}
-                class="btn btn-primary">{{t common.save}}
-            </button>
-          </div>
-        {{else}}
-          <div class="multiline-text">
-            {{controller.content.description}}
-          </div>
-        {{/if}}
-      </div>
+
+      {{! Alert Definition Configs }}
       <div class="definition-details-block">
         <strong>{{t common.configuration}}</strong>
           {{#isAccessible ADMIN}}
@@ -92,6 +71,8 @@
           </div>
         {{/if}}
       </div>
+      {{! Alert Definition Configs end }}
+
     </div>
     {{! Left column end }}
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/test/controllers/main/alerts/definitions_configs_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/alerts/definitions_configs_controller_test.js b/ambari-web/test/controllers/main/alerts/definitions_configs_controller_test.js
index 2022370..f24e7fd 100644
--- a/ambari-web/test/controllers/main/alerts/definitions_configs_controller_test.js
+++ b/ambari-web/test/controllers/main/alerts/definitions_configs_controller_test.js
@@ -123,16 +123,12 @@ describe('App.MainAlertDefinitionConfigsController', function () {
       controller.set('isWizard', true);
       var result = controller.renderPortConfigs();
 
-      expect(result.length).to.equal(11);
+      expect(result.length).to.equal(10);
 
       controller.set('isWizard', false);
       result = controller.renderPortConfigs();
 
       expect(result.length).to.equal(4);
-      expect(result.someProperty('value', 60)).to.be.true;
-      expect(result.someProperty('value', '10-20')).to.be.true;
-      expect(result.someProperty('value', 'alertDefinitionUri')).to.be.true;
-      expect(result.someProperty('value', '777')).to.be.true;
     });
 
   });
@@ -182,17 +178,12 @@ describe('App.MainAlertDefinitionConfigsController', function () {
       controller.set('isWizard', true);
       var result = controller.renderMetricConfigs();
 
-      expect(result.length).to.equal(12);
+      expect(result.length).to.equal(11);
 
       controller.set('isWizard', false);
       result = controller.renderMetricConfigs();
 
       expect(result.length).to.equal(5);
-      expect(result.someProperty('value', 60)).to.be.true;
-      expect(result.someProperty('value', '10-20')).to.be.true;
-      expect(result.someProperty('value', '{\"http\":\"{{mapred-site/mapreduce.jobhistory.webapp.address}}\",\"https\":\"{{mapred-site/mapreduce.jobhistory.webapp.https.address}}\"}')).to.be.true;
-      expect(result.someProperty('value', 'property1,\nproperty2')).to.be.true;
-      expect(result.someProperty('value', 'jmxValue')).to.be.true;
     });
 
   });
@@ -234,15 +225,12 @@ describe('App.MainAlertDefinitionConfigsController', function () {
       controller.set('isWizard', true);
       var result = controller.renderWebConfigs();
 
-      expect(result.length).to.equal(10);
+      expect(result.length).to.equal(11);
 
       controller.set('isWizard', false);
       result = controller.renderWebConfigs();
 
-      expect(result.length).to.equal(3);
-      expect(result.someProperty('value', 60)).to.be.true;
-      expect(result.someProperty('value', '10-20')).to.be.true;
-      expect(result.someProperty('value', '{\"http\":\"{{mapred-site/mapreduce.jobhistory.webapp.address}}\",\"https\":\"{{mapred-site/mapreduce.jobhistory.webapp.https.address}}\"}')).to.be.true;
+      expect(result.length).to.equal(5);
     });
 
   });
@@ -278,15 +266,12 @@ describe('App.MainAlertDefinitionConfigsController', function () {
       controller.set('isWizard', true);
       var result = controller.renderScriptConfigs();
 
-      expect(result.length).to.equal(10);
+      expect(result.length).to.equal(11);
 
       controller.set('isWizard', false);
       result = controller.renderScriptConfigs();
 
-      expect(result.length).to.equal(3);
-      expect(result.someProperty('value', 60)).to.be.true;
-      expect(result.someProperty('value', '10-20')).to.be.true;
-      expect(result.someProperty('value', 'path to script')).to.be.true;
+      expect(result.length).to.equal(5);
     });
 
   });
@@ -297,14 +282,26 @@ describe('App.MainAlertDefinitionConfigsController', function () {
 
       controller.set('content', Em.Object.create({
         name: 'alertDefinitionName',
-        description: 'alertDefinitionDescription'
+        description: 'alertDefinitionDescription',
+        reporting: [
+          Em.Object.create({
+            type: 'warning',
+            value: 10
+          }),
+          Em.Object.create({
+            type: 'critical',
+            value: 20
+          }),
+          Em.Object.create({
+            type: 'ok',
+            value: 30
+          })
+        ]
       }));
 
       var result = controller.renderAggregateConfigs();
 
-      expect(result.length).to.equal(2);
-      expect(result.someProperty('value', 'alertDefinitionName')).to.be.true;
-      expect(result.someProperty('value', 'alertDefinitionDescription')).to.be.true;
+      expect(result.length).to.equal(4);
     });
 
   });
@@ -515,7 +512,7 @@ describe('App.MainAlertDefinitionConfigsController', function () {
 
       var result = controller.renderCommonWizardConfigs();
 
-      expect(result.length).to.equal(7);
+      expect(result.length).to.equal(6);
 
     });
 
@@ -543,5 +540,4 @@ describe('App.MainAlertDefinitionConfigsController', function () {
 
   });
 
-
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/cd07f884/ambari-web/test/models/alert_config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/alert_config_test.js b/ambari-web/test/models/alert_config_test.js
new file mode 100644
index 0000000..6d13e66
--- /dev/null
+++ b/ambari-web/test/models/alert_config_test.js
@@ -0,0 +1,204 @@
+/**
+ * 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('models/alert_config');
+
+var model;
+
+describe('App.AlertConfigProperties', function () {
+
+  describe('Threshold', function () {
+
+    beforeEach(function () {
+      model = App.AlertConfigProperties.Threshold.create({});
+    });
+
+    describe('#apiFormattedValue', function () {
+
+      it('should be based on showInputForValue and showInputForText', function () {
+
+        model.setProperties({
+          value: 'value',
+          text: 'text',
+          showInputForValue: false,
+          showInputForText: false
+        });
+        expect(model.get('apiFormattedValue')).to.eql([]);
+
+        model.set('showInputForValue', true);
+        expect(model.get('apiFormattedValue')).to.eql(['value']);
+
+        model.set('showInputForText', true);
+        expect(model.get('apiFormattedValue')).to.eql(['value', 'text']);
+
+      });
+
+    });
+
+    describe('#badgeCssClass', function () {
+
+      it ('should be based on badge', function () {
+
+        model.set('badge', 'OK');
+        expect(model.get('badgeCssClass')).to.equal('alert-state-OK');
+
+      });
+
+    });
+
+    describe('#wasChanged', function () {
+
+      Em.A([
+          {
+            p: {
+              previousValue: null,
+              previousText: null,
+              value: '',
+              text: ''
+            },
+            e: false
+          },
+          {
+            p: {
+              previousValue: 'not null',
+              previousText: null,
+              value: '',
+              text: ''
+            },
+            e: true
+          },
+          {
+            p: {
+              previousValue: null,
+              previousText: 'not null',
+              value: '',
+              text: ''
+            },
+            e: true
+          },
+          {
+            p: {
+              previousValue: 'not null',
+              previousText: 'not null',
+              value: '',
+              text: ''
+            },
+            e: true
+          }
+        ]).forEach(function (test, i) {
+        it('test #' + (i + 1), function () {
+          model.setProperties(test.p);
+          expect(model.get('wasChanged')).to.equal(test.e);
+        });
+      });
+
+    });
+
+  });
+
+  describe('App.AlertConfigProperties.Thresholds', function () {
+
+    describe('OkThreshold', function () {
+
+      beforeEach(function () {
+        model = App.AlertConfigProperties.Thresholds.OkThreshold.create();
+      });
+
+      describe('#apiProperty', function () {
+
+        it('should be based on showInputForValue and showInputForText', function () {
+
+          model.setProperties({
+            showInputForValue: false,
+            showInputForText: false
+          });
+          expect(model.get('apiProperty')).to.eql([]);
+
+          model.set('showInputForValue', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.ok.value']);
+
+          model.set('showInputForText', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.ok.value', 'source.reporting.ok.text']);
+
+        });
+
+      });
+
+    });
+
+    describe('WarningThreshold', function () {
+
+      beforeEach(function () {
+        model = App.AlertConfigProperties.Thresholds.WarningThreshold.create();
+      });
+
+      describe('#apiProperty', function () {
+
+        it('should be based on showInputForValue and showInputForText', function () {
+
+          model.setProperties({
+            showInputForValue: false,
+            showInputForText: false
+          });
+          expect(model.get('apiProperty')).to.eql([]);
+
+          model.set('showInputForValue', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.warning.value']);
+
+          model.set('showInputForText', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.warning.value', 'source.reporting.warning.text']);
+
+        });
+
+      });
+
+    });
+
+    describe('CriticalThreshold', function () {
+
+      beforeEach(function () {
+        model = App.AlertConfigProperties.Thresholds.CriticalThreshold.create();
+      });
+
+      describe('#apiProperty', function () {
+
+        it('should be based on showInputForValue and showInputForText', function () {
+
+          model.setProperties({
+            showInputForValue: false,
+            showInputForText: false
+          });
+          expect(model.get('apiProperty')).to.eql([]);
+
+          model.set('showInputForValue', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.critical.value']);
+
+          model.set('showInputForText', true);
+          expect(model.get('apiProperty')).to.eql(['source.reporting.critical.value', 'source.reporting.critical.text']);
+
+        });
+
+      });
+
+    });
+
+  });
+
+});