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 2015/08/21 12:10:15 UTC

[2/2] ambari git commit: AMBARI-12845. Alert Instances overriding issue (onehiporenko)

AMBARI-12845. Alert Instances overriding issue (onehiporenko)


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

Branch: refs/heads/trunk
Commit: 66d0b6e2c136335841fb99a47d5122ebde18d046
Parents: 9953433
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Fri Aug 21 13:07:57 2015 +0300
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Fri Aug 21 13:07:57 2015 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   6 +-
 .../main/alerts/alert_instances_controller.js   |  13 +-
 .../alerts/definition_details_controller.js     |   2 +-
 .../main/host/host_alerts_controller.js         |   2 +-
 .../app/mappers/alert_instances_mapper.js       |  14 +-
 ambari-web/app/models.js                        |  11 +-
 ambari-web/app/models/alert_config.js           | 619 -------------------
 ambari-web/app/models/alert_definition.js       | 344 -----------
 ambari-web/app/models/alert_group.js            |  79 ---
 ambari-web/app/models/alert_instance.js         | 165 -----
 ambari-web/app/models/alert_notification.js     |  33 -
 ambari-web/app/models/alerts/alert_config.js    | 619 +++++++++++++++++++
 .../app/models/alerts/alert_definition.js       | 344 +++++++++++
 ambari-web/app/models/alerts/alert_group.js     |  79 +++
 ambari-web/app/models/alerts/alert_instance.js  | 165 +++++
 .../app/models/alerts/alert_instance_local.js   |  30 +
 .../app/models/alerts/alert_notification.js     |  33 +
 .../main/alerts/definition_details_view.js      |   2 +-
 .../app/views/main/host/host_alerts_view.js     |  13 +-
 ambari-web/test/models/alert_config_test.js     | 332 ----------
 ambari-web/test/models/alert_definition_test.js | 212 -------
 ambari-web/test/models/alert_instance_test.js   |  94 ---
 .../test/models/alerts/alert_config_test.js     | 332 ++++++++++
 .../test/models/alerts/alert_definition_test.js | 212 +++++++
 .../test/models/alerts/alert_instance_test.js   |  94 +++
 25 files changed, 1944 insertions(+), 1905 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/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 56f9444..1888690 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -275,9 +275,9 @@ var files = ['test/init_model_test',
   'test/models/service/flume_test',
   'test/models/service/hdfs_test',
   'test/models/service/yarn_test',
-  'test/models/alert_config_test',
-  'test/models/alert_definition_test',
-  'test/models/alert_instance_test',
+  'test/models/alerts/alert_config_test',
+  'test/models/alerts/alert_definition_test',
+  'test/models/alerts/alert_instance_test',
   'test/models/authentication_test',
   'test/models/cluster_states_test',
   'test/models/config_group_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alerts/alert_instances_controller.js b/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
index 9e07726..234fba0 100644
--- a/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
+++ b/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
@@ -182,7 +182,7 @@ App.MainAlertInstancesController = Em.Controller.extend({
    * @method getAlertInstancesSuccessCallback
    */
   getAlertInstancesSuccessCallback: function (json) {
-    App.alertInstanceMapper.map(json);
+    App.alertInstanceMapper.mapLocal(json);
     this.set('isLoaded', true);
     this.toggleProperty('reload');
   },
@@ -309,15 +309,6 @@ App.MainAlertInstancesController = Em.Controller.extend({
           this.set('filteredContent', this.get('content'));
         }.observes('content.length'),
 
-        refreshTooltips: function () {
-          this.ensureTooltip();
-        }.observes('contents.[]', 'filteringComplete'),
-
-        ensureTooltip: function () {
-          Em.run.next(this, function () {
-            App.tooltip($(".timeago"));
-          });
-        },
         /**
          * Router transition to alert definition details page
          * @param event
@@ -354,8 +345,6 @@ App.MainAlertInstancesController = Em.Controller.extend({
 
         didInsertElement: function () {
           this.filter();
-          this.addObserver('filteringComplete', this, this.overlayObserver);
-          this.overlayObserver();
           return this._super();
         }
       })

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/controllers/main/alerts/definition_details_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alerts/definition_details_controller.js b/ambari-web/app/controllers/main/alerts/definition_details_controller.js
index 27e6a4a..336033e 100644
--- a/ambari-web/app/controllers/main/alerts/definition_details_controller.js
+++ b/ambari-web/app/controllers/main/alerts/definition_details_controller.js
@@ -21,7 +21,7 @@ App.MainAlertDefinitionDetailsController = Em.Controller.extend({
   name: 'mainAlertDefinitionDetailsController',
 
   alerts: function () {
-    return App.AlertInstance.find().toArray()
+    return App.AlertInstanceLocal.find().toArray()
         .filterProperty('definitionId', this.get('content.id'));
   }.property('App.router.mainAlertInstancesController.isLoaded', 'App.router.mainAlertInstancesController.reload'),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/controllers/main/host/host_alerts_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/host_alerts_controller.js b/ambari-web/app/controllers/main/host/host_alerts_controller.js
index 2a47914..a44aa26 100644
--- a/ambari-web/app/controllers/main/host/host_alerts_controller.js
+++ b/ambari-web/app/controllers/main/host/host_alerts_controller.js
@@ -30,7 +30,7 @@ App.MainHostAlertsController = Em.ArrayController.extend({
    * @type {App.AlertInstance[]}
    */
   content: function () {
-    return App.AlertInstance.find().toArray().filterProperty('host', this.get('selectedHost'));
+    return App.AlertInstanceLocal.find().toArray().filterProperty('host', this.get('selectedHost'));
   }.property('App.router.mainAlertInstancesController.isLoaded', 'selectedHost'),
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/mappers/alert_instances_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/alert_instances_mapper.js b/ambari-web/app/mappers/alert_instances_mapper.js
index af6804f..cd1f8bd 100644
--- a/ambari-web/app/mappers/alert_instances_mapper.js
+++ b/ambari-web/app/mappers/alert_instances_mapper.js
@@ -21,6 +21,8 @@ App.alertInstanceMapper = App.QuickDataMapper.create({
 
   model : App.AlertInstance,
 
+  modelLocal: App.AlertInstanceLocal,
+
   config : {
     id: 'Alert.id',
     label: 'Alert.label',
@@ -41,10 +43,17 @@ App.alertInstanceMapper = App.QuickDataMapper.create({
   },
 
   map: function(json) {
+    return this.parse(json, this.get('model'));
+  },
+
+  mapLocal: function(json) {
+    return this.parse(json, this.get('modelLocal'));
+  },
+
+  parse: function(json, model) {
     console.time('App.alertInstanceMapper execution time');
     if (json.items) {
       var alertInstances = [];
-      var model = this.get('model');
       var alertsToDelete = model.find().mapProperty('id');
 
       json.items.forEach(function (item) {
@@ -57,8 +66,9 @@ App.alertInstanceMapper = App.QuickDataMapper.create({
         model.find().clear();
       }
 
-      App.store.loadMany(this.get('model'), alertInstances);
+      App.store.loadMany(model, alertInstances);
       console.timeEnd('App.alertInstanceMapper execution time');
     }
   }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models.js b/ambari-web/app/models.js
index 64860ea..6bffb95 100644
--- a/ambari-web/app/models.js
+++ b/ambari-web/app/models.js
@@ -42,11 +42,12 @@ require('models/service/mapreduce2');
 require('models/service/hbase');
 require('models/service/flume');
 require('models/service/storm');
-require('models/alert_definition');
-require('models/alert_instance');
-require('models/alert_notification');
-require('models/alert_config');
-require('models/alert_group');
+require('models/alerts/alert_definition');
+require('models/alerts/alert_instance');
+require('models/alerts/alert_instance_local');
+require('models/alerts/alert_notification');
+require('models/alerts/alert_config');
+require('models/alerts/alert_group');
 require('models/user');
 require('models/host');
 require('models/rack');

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/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
deleted file mode 100644
index df2e579..0000000
--- a/ambari-web/app/models/alert_config.js
+++ /dev/null
@@ -1,619 +0,0 @@
-/**
- * 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');
-var validator = require('utils/validator');
-var numericUtils = require('utils/number_utils');
-
-App.AlertConfigProperty = Ember.Object.extend({
-
-  /**
-   * label to be shown for config property
-   * @type {String}
-   */
-  label: '',
-
-  /**
-   * PORT|METRIC|AGGREGATE
-   * @type {String}
-   */
-  type: '',
-
-  /**
-   * config property value
-   * @type {*}
-   */
-  value: null,
-
-  /**
-   * property value cache to realise undo function
-   * @type {*}
-   */
-  previousValue: null,
-
-  /**
-   * define either input is disabled or enabled
-   * @type {Boolean}
-   */
-  isDisabled: false,
-
-  /**
-   * options that Select list will have
-   * @type {Array}
-   */
-  options: [],
-
-  /**
-   * input displayType
-   * one of 'textFields', 'textArea', 'select' or 'threshold'
-   * @type {String}
-   */
-  displayType: '',
-
-  /**
-   * unit to be shown with value
-   * @type {String}
-   */
-  unit: null,
-
-  /**
-   * space separated list of css class names to use
-   * @type {String}
-   */
-  classNames: '',
-
-  /**
-   * define whether row with property should be shifted right
-   * @type {Boolean}
-   */
-  isShifted: false,
-
-  /**
-   * name or names of properties related to config
-   * may be either string for one property or array of strings for multiple properties
-   * if this property is array, then <code>apiFormattedValue</code> should also be an array
-   * example: <code>apiProperty[0]</code> relates to <code>apiFormattedValue[0]</code>
-   * @type {String|Array}
-   */
-  apiProperty: '',
-
-  /**
-   * for some metrics properties may be set true or false
-   * depending on what property is related to (JMX or Ganglia)
-   */
-  isJMXMetric: null,
-
-  /**
-   * define place to show label
-   * if true - label is shown before input
-   * if false - label is shown after input
-   * @type {Boolean}
-   */
-  isPreLabeled: function () {
-    var afterLabeledTypes = ['radioButton'];
-    return !afterLabeledTypes.contains(this.get('displayType'));
-  }.property('displayType'),
-
-  /**
-   * value converted to appropriate format for sending to server
-   * should be computed property
-   * should be defined in child class
-   * @type {*}
-   */
-  apiFormattedValue: function () {
-    return this.get('value');
-  }.property('value'),
-
-  /**
-   * define if property was changed by user
-   * @type {Boolean}
-   */
-  wasChanged: function () {
-    return this.get('previousValue') !== null && this.get('value') !== this.get('previousValue');
-  }.property('value', 'previousValue'),
-
-  /**
-   * view class according to <code>displayType</code>
-   * @type {Em.View}
-   */
-  viewClass: function () {
-    var displayType = this.get('displayType');
-    switch (displayType) {
-      case 'textField':
-        return App.AlertConfigTextFieldView;
-      case 'textArea':
-        return App.AlertConfigTextAreaView;
-      case 'select':
-        return App.AlertConfigSelectView;
-      case 'threshold':
-        return App.AlertConfigThresholdView;
-      case 'radioButton':
-        return App.AlertConfigRadioButtonView;
-      default:
-        console.error('Unable to find viewClass for displayType ', displayType);
-    }
-  }.property('displayType'),
-
-  /**
-   * Define whether property is valid
-   * Computed property
-   * Should be defined in child class
-   * @type {Boolean}
-   */
-  isValid: function () {
-    return true;
-  }.property()
-
-});
-
-App.AlertConfigProperties = {
-
-  AlertName: App.AlertConfigProperty.extend({
-    name: 'alert_name',
-    label: 'Alert Name',
-    displayType: 'textField',
-    classNames: 'alert-text-input',
-    apiProperty: 'name'
-  }),
-
-  AlertNameSelected: App.AlertConfigProperty.extend({
-    name: 'alert_name',
-    label: 'Alert Name',
-    displayType: 'select',
-    apiProperty: 'name'
-  }),
-
-  ServiceAlertType: App.AlertConfigProperty.extend({
-    name: 'alert_type_service',
-    label: 'Service Alert Definition',
-    displayType: 'radioButton',
-    group: 'alert_type'
-  }),
-
-  HostAlertType: App.AlertConfigProperty.extend({
-    name: 'alert_type_host',
-    label: 'Host Alert Definition',
-    displayType: 'radioButton',
-    group: 'alert_type'
-  }),
-
-  Service: App.AlertConfigProperty.extend({
-    name: 'service',
-    label: 'Service',
-    displayType: 'select',
-    apiProperty: 'service_name',
-    apiFormattedValue: function () {
-      return App.StackService.find().findProperty('displayName', this.get('value')).get('serviceName');
-    }.property('value')
-  }),
-
-  Component: App.AlertConfigProperty.extend({
-    name: 'component',
-    label: 'Component',
-    displayType: 'select',
-    apiProperty: 'component_name',
-    apiFormattedValue: function () {
-      return App.StackServiceComponent.find().findProperty('displayName', this.get('value')).get('componentName');
-    }.property('value')
-  }),
-
-  Scope: App.AlertConfigProperty.extend({
-    name: 'scope',
-    label: 'Scope',
-    displayType: 'select',
-    apiProperty: 'scope',
-    apiFormattedValue: function () {
-      return this.get('value').toUpperCase();
-    }.property('value')
-  }),
-
-  Description: App.AlertConfigProperty.extend({
-    name: 'description',
-    label: 'Description',
-    displayType: 'textArea',
-    classNames: 'alert-config-text-area',
-    // todo: check value after API will be provided
-    apiProperty: 'description'
-  }),
-
-  Interval: App.AlertConfigProperty.extend({
-    name: 'interval',
-    label: 'Check Interval',
-    displayType: 'textField',
-    unit: 'Minute',
-    classNames: 'alert-interval-input',
-    apiProperty: 'interval',
-    isValid: function () {
-      var value = this.get('value');
-      if (!value) return false;
-      return String(value) === String(parseInt(value, 10)) && value >= 1;
-    }.property('value')
-  }),
-
-  /**
-   * 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: '',
-
-    /**
-     * Type of value. This will be a fixed set of types (like %).
-     */
-    valueMetric: null,
-
-    /**
-     * Value actually displayed to the user. This value is transformed
-     * based on the limited types of 'valueMetric's. Mappings from
-     * 'value' to 'displayValue' is handled by observers.
-     */
-    displayValue: '',
-
-    /**
-     * threshold-text
-     * @type {string}
-     */
-    text: '',
-
-    displayType: 'threshold',
-
-    classNames: 'alert-thresholds-input',
-
-    apiProperty: [],
-
-    init: function () {
-      this.set('displayValue', this.getNewValue());
-      this._super();
-    },
-
-    /**
-     * @type {string[]}
-     */
-    apiFormattedValue: function () {
-      var ret = [];
-      if (this.get('showInputForValue')) {
-        ret.push(this.get('value'));
-      }
-      if (this.get('showInputForText')) {
-        ret.push(this.get('text'));
-      }
-      return ret;
-    }.property('value', 'text', 'showInputForValue', 'showInputForText'),
-
-    /**
-     * 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'),
-
-    /**
-     * May be redefined in child-models, mixins etc
-     * @method getValue
-     * @returns {string}
-     */
-    getNewValue: function () {
-      return this.get('value');
-    },
-
-    valueWasChanged: function () {
-      var displayValue = this.get('displayValue');
-      var newDisplayValue = this.getNewValue();
-      if (newDisplayValue !== displayValue && !(isNaN(newDisplayValue) ||isNaN(displayValue))) {
-        this.set('displayValue', newDisplayValue);
-      }
-    }.observes('value'),
-
-    /**
-     * May be redefined in child-models, mixins etc
-     * @method getDisplayValue
-     * @returns {string}
-     */
-    getNewDisplayValue: function () {
-      return this.get('displayValue');
-    },
-
-    displayValueWasChanged: function () {
-      var value = this.get('value');
-      var newValue = this.getNewDisplayValue();
-      if (newValue !== value && !(isNaN(newValue) ||isNaN(value))) {
-        this.set('value', newValue);
-      }
-    }.observes('displayValue'),
-
-    /**
-     * Check if <code>displayValue</code> is valid float number
-     * If this value isn't shown (see <code>showInputForValue</code>), result is always true
-     * @return {boolean}
-     */
-    isValid: function () {
-      if (!this.get('showInputForValue')) {
-        return true;
-      }
-
-      var value = this.get('displayValue');
-
-      if (Em.isNone(value)) {
-        return false;
-      }
-
-      value = ('' + value).trim();
-
-      //only allow 1/10th of a second
-      if (numericUtils.getFloatDecimals(value) > 1) {
-        return false;
-      }
-
-      return validator.isValidFloat(value);
-    }.property('displayValue', 'showInputForValue')
-
-  }),
-
-  URI: App.AlertConfigProperty.extend({
-    name: 'uri',
-    label: 'URI',
-    displayType: 'textField',
-    classNames: 'alert-text-input',
-    apiProperty: 'source.uri'
-  }),
-
-  URIExtended: App.AlertConfigProperty.extend({
-    name: 'uri',
-    label: 'URI',
-    displayType: 'textArea',
-    classNames: 'alert-config-text-area',
-    apiProperty: 'source.uri',
-    apiFormattedValue: function () {
-      var result = {};
-      try {
-        result = JSON.parse(this.get('value'));
-      } catch (e) {
-        console.error('Wrong format of URI');
-      }
-      return result;
-    }.property('value')
-  }),
-
-  DefaultPort: App.AlertConfigProperty.extend({
-    name: 'default_port',
-    label: 'Default Port',
-    displayType: 'textField',
-    classNames: 'alert-port-input',
-    apiProperty: 'source.default_port'
-  }),
-
-  Path: App.AlertConfigProperty.extend({
-    name: 'path',
-    label: 'Path',
-    displayType: 'textField',
-    classNames: 'alert-text-input',
-    apiProperty: 'source.path'
-  }),
-
-  Metrics: App.AlertConfigProperty.extend({
-    name: 'metrics',
-    label: 'JMX/Ganglia Metrics',
-    displayType: 'textArea',
-    classNames: 'alert-config-text-area',
-    apiProperty: function () {
-      return this.get('isJMXMetric') ? 'source.jmx.property_list' : 'source.ganglia.property_list'
-    }.property('isJMXMetric'),
-    apiFormattedValue: function () {
-      return this.get('value').split(',\n');
-    }.property('value')
-  }),
-
-  FormatString: App.AlertConfigProperty.extend({
-    name: 'metrics_string',
-    label: 'Format String',
-    displayType: 'textArea',
-    classNames: 'alert-config-text-area',
-    apiProperty: function () {
-      return this.get('isJMXMetric') ? 'source.jmx.value' : 'source.ganglia.value'
-    }.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')
-
-  }),
-
-  /**
-   * Mixin for <code>App.AlertConfigProperties.Threshold</code>
-   * Used to validate values in percentage range (0..1]
-   * @type {Em.Mixin}
-   */
-  PercentageMixin: Em.Mixin.create({
-
-    isValid: function () {
-      var value = this.get('displayValue');
-
-      if (!value) {
-        return false;
-      }
-
-      value = ('' + value).trim();
-      if (numericUtils.getFloatDecimals(value)) {
-        return false;
-      }
-
-      value = parseFloat(value);
-
-      //do not allow float values
-      if (parseInt(value, 10) !== value) {
-        return false;
-      }
-
-      return this.get('showInputForValue') ? !isNaN(value) && value > 0 && value <= 100 : true;
-    }.property('displayValue', 'showInputForValue'),
-
-    /**
-     * Return <code>value * 100</code>
-     * @returns {string}
-     */
-    getNewValue: function () {
-      var value = this.get('value');
-      return (value && !isNaN(value)) ? (Number(value) * 100) + '' : value;
-    },
-
-    /**
-     * Return <code>displayValue / 100</code>
-     * @returns {string}
-     */
-    getNewDisplayValue: function () {
-      var displayValue = this.get('displayValue');
-      return (displayValue && !isNaN(displayValue)) ? (Number(displayValue) / 100) + '' : displayValue;
-    }
-
-  }),
-
-  /**
-   * Mixin for <code>App.AlertConfigProperties.Threshold</code>
-   * Used to validate values that should be greater than 0
-   * @type {Em.Mixin}
-   */
-  PositiveMixin: Em.Mixin.create({
-
-    isValid: function () {
-      if (!this.get('showInputForValue')) {
-        return true;
-      }
-      var value = this.get('displayValue');
-
-      if (!value) {
-        return false;
-      }
-
-      //only allow 1/10th of a second
-      if (numericUtils.getFloatDecimals(value) > 1) {
-        return false;
-      }
-
-      value = ('' + value).trim();
-      value = parseFloat(value);
-
-      return !isNaN(value) && value > 0;
-    }.property('displayValue', 'showInputForValue')
-
-  })
-
-};

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alert_definition.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert_definition.js b/ambari-web/app/models/alert_definition.js
deleted file mode 100644
index d1310ff..0000000
--- a/ambari-web/app/models/alert_definition.js
+++ /dev/null
@@ -1,344 +0,0 @@
-/**
- * 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');
-var dateUtils = require('utils/date');
-
-App.AlertDefinition = DS.Model.extend({
-
-  name: DS.attr('string'),
-  label: DS.attr('string'),
-  description: DS.attr('string'),
-  service: DS.belongsTo('App.Service'),
-  serviceName: DS.attr('string'),
-  componentName: DS.attr('string'),
-  enabled: DS.attr('boolean'),
-  scope: DS.attr('string'),
-  interval: DS.attr('number'),
-  type: DS.attr('string'),
-  groups: DS.hasMany('App.AlertGroup'),
-  reporting: DS.hasMany('App.AlertReportDefinition'),
-  lastTriggered: DS.attr('number'),
-
-  //relates only to SCRIPT-type alert definition
-  location: DS.attr('string'),
-  //relates only to AGGREGATE-type alert definition
-  alertName: DS.attr('string'),
-  //relates only to WEB and METRIC types of alert definition
-  uri: DS.belongsTo('App.AlertMetricsUriDefinition'),
-  //relates only METRIC-type alert definition
-  jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
-  ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
-  //relates only PORT-type alert definition
-  defaultPort: DS.attr('number'),
-  portUri: DS.attr('string'),
-
-  /**
-   * Raw data from AlertDefinition/source
-   * used to format request content for updating alert definition
-   * @type {Object}
-   */
-  rawSourceData: {},
-
-  /**
-   * Counts of alert grouped by their status
-   * Format:
-   * <code>
-   *   {
-   *    "CRITICAL": {
-   *      count: 1,
-   *      maintenanceCount: 0
-   *    },
-   *    "OK": {
-   *      count: 0,
-   *      maintenanceCount: 1
-   *    },
-   *    "UNKNOWN": {
-   *      count: 0,
-   *      maintenanceCount: 0
-   *    },
-   *    "WARNING": {
-   *      count: 1,
-   *      maintenanceCount: 1
-   *    }
-   *   }
-   * </code>
-   * @type {object}
-   */
-  summary: {},
-
-  /**
-   * Formatted timestamp for latest alert triggering for current alertDefinition
-   * @type {string}
-   */
-  lastTriggeredFormatted: function () {
-    return dateUtils.dateFormat(this.get('lastTriggered'));
-  }.property('lastTriggered'),
-
-  /**
-   * Formatted timestamp with <code>$.timeago</code>
-   * @type {string}
-   */
-  lastTriggeredAgoFormatted: function () {
-    var lastTriggered = this.get('lastTriggered');
-    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
-  }.property('lastTriggered'),
-
-  lastTriggeredVerboseDisplay: function () {
-    var lastTriggered = this.get('lastTriggered');
-    return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
-  }.property('lastTriggered'),
-
-  /**
-   * Formatted timestamp in format: for 4 days
-   * @type {string}
-   */
-  lastTriggeredForFormatted: function () {
-    var lastTriggered = this.get('lastTriggered');
-    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
-    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
-    $.timeago.settings.strings.suffixAgo = null;
-    $.timeago.settings.strings.prefixAgo = 'for';
-    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
-    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
-    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
-    return triggeredFor;
-  }.property('lastTriggered'),
-
-  /**
-   * Formatted displayName for <code>componentName</code>
-   * @type {String}
-   */
-  componentNameFormatted: function () {
-    return App.format.role(this.get('componentName'));
-  }.property('componentName'),
-
-  /**
-   * Status generates from child-alerts
-   * Format: OK(1)  WARN(2)  CRIT(1)  UNKN(1)
-   * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
-   * If some there are no alerts with some state, this state isn't shown
-   * If no OK/WARN/CRIT/UNKN state, then show PENDING
-   * Order is equal to example
-   * @type {string}
-   */
-  status: function () {
-    var order = this.get('order'),
-        summary = this.get('summary'),
-        hostCnt = 0,
-        self = this;
-    order.forEach(function (state) {
-      hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
-    });
-    if (hostCnt > 1) {
-      // multiple hosts
-      return order.map(function (state) {
-        var shortState = self.get('shortState')[state];
-        var result = '';
-        result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + ' (' + summary[state].count + ')</span>' : '';
-        // add status with maintenance mode icon
-        result += summary[state].maintenanceCount ?
-        '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + ' (' + summary[state].maintenanceCount + ')</span>' : '';
-        return result;
-      }).without('').join(' ');
-    } else if (hostCnt == 1) {
-      // single host, single status
-      return order.map(function (state) {
-        var shortState = self.get('shortState')[state];
-        var result = '';
-        result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + '</span>' : '';
-        // add status with maintenance mode icon
-        result += summary[state].maintenanceCount ?
-        '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + '</span>' : '';
-        return result;
-      }).without('').join(' ');
-    } else if (hostCnt == 0) {
-      // none
-      return '<span class="alert-state-single-host label alert-state-PENDING">NONE</span>';
-    }
-    return '';
-  }.property('summary'),
-
-  latestText: function () {
-    var order = this.get('order'), summary = this.get('summary'), text = '';
-    order.forEach(function (state) {
-      var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
-      if (cnt > 0) {
-        text = summary[state].latestText;
-      }
-    });
-    return text;
-  }.property('summary'),
-
-  isHostAlertDefinition: function () {
-    var serviceID = (this.get('service')._id === "AMBARI"),
-        component = (this.get('componentName') === "AMBARI_AGENT");
-    return serviceID && component;
-  }.property('service', 'componentName'),
-
-  typeIconClass: function () {
-    var typeIcons = this.get('typeIcons'),
-        type = this.get('type');
-    return typeIcons[type];
-  }.property('type'),
-
-  /**
-   * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
-   * instances with maintenance mode ON are ignored
-   * @type {boolean}
-   */
-  isCriticalOrWarning: function () {
-    return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
-  }.property('summary'),
-
-  /**
-   * if this definition is in state: CRIT
-   * @type {boolean}
-   */
-  isCritical: function () {
-    var summary = this.get('summary');
-    var state = 'CRITICAL';
-    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
-  }.property('summary'),
-
-  /**
-   * if this definition is in state: WARNING
-   * @type {boolean}
-   */
-  isWarning: function () {
-    var summary = this.get('summary');
-    var state = 'WARNING';
-    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
-  }.property('summary'),
-
-  /**
-   * if this definition is in state: OK
-   * @type {boolean}
-   */
-  isOK: function () {
-    var summary = this.get('summary');
-    var state = 'OK';
-    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
-  }.property('summary'),
-
-  /**
-   * if this definition is in state: OK
-   * @type {boolean}
-   */
-  isUnknown: function () {
-    var summary = this.get('summary');
-    var state = 'UNKNOWN';
-    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
-  }.property('summary'),
-
-  /**
-   * For alerts we will have processes which are not typical
-   * cluster services - like Ambari-Server. This method unifies
-   * cluster services and other services into a common display-name.
-   * @see App.AlertInstance#serviceDisplayName()
-   */
-  serviceDisplayName: function () {
-    var serviceName = this.get('service.displayName');
-    if (!serviceName) {
-      serviceName = this.get('serviceName');
-      if (serviceName) {
-        serviceName = serviceName.toCapital();
-      }
-    }
-    return serviceName;
-  }.property('serviceName', 'service.displayName'),
-
-  /**
-   * List of css-classes for alert types
-   * @type {object}
-   */
-  typeIcons: {
-    'METRIC': 'icon-bolt',
-    'SCRIPT': 'icon-file-text',
-    'WEB': 'icon-globe',
-    'PORT': 'icon-signin',
-    'AGGREGATE': 'icon-plus',
-    'SERVER': 'icon-desktop'
-  },
-
-  /**
-   * Sort on load definitions by this severity order
-   */
-  severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
-  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
-
-  shortState: {
-    'CRITICAL': 'CRIT',
-    'WARNING': 'WARN',
-    'OK': 'OK',
-    'UNKNOWN': 'UNKWN',
-    'PENDING': 'NONE'
-  }
-});
-
-App.AlertDefinition.reopenClass({
-
-  /**
-   * Return function to sort list of AlertDefinitions by their status
-   * It sorts according to <code>severityOrder</code>
-   * @param {boolean} order true - DESC, false - ASC
-   * @returns {Function}
-   * @method getSortDefinitionsByStatus
-   */
-  getSortDefinitionsByStatus: function (order) {
-    return function (a, b) {
-      var a_summary = a.get('summary'),
-        b_summary = b.get('summary'),
-        st_order = a.get('severityOrder'),
-        ret = 0;
-      for (var i = 0; i < st_order.length; i++) {
-        var a_v = Em.isNone(a_summary[st_order[i]]) ? 0 : a_summary[st_order[i]].count + a_summary[st_order[i]].maintenanceCount,
-          b_v = Em.isNone(b_summary[st_order[i]]) ? 0 : b_summary[st_order[i]].count + b_summary[st_order[i]].maintenanceCount;
-        ret = b_v - a_v;
-        if (ret !== 0) {
-          break;
-        }
-      }
-      return order ? ret : -ret;
-    };
-  }
-
-});
-
-App.AlertReportDefinition = DS.Model.extend({
-  type: DS.attr('string'),
-  text: DS.attr('string'),
-  value: DS.attr('number')
-});
-
-App.AlertMetricsSourceDefinition = DS.Model.extend({
-  propertyList: [],
-  value: DS.attr('string')
-});
-
-App.AlertMetricsUriDefinition = DS.Model.extend({
-  http: DS.attr('string'),
-  https: DS.attr('string'),
-  httpsProperty: DS.attr('string'),
-  httpsPropertyValue: DS.attr('string')
-});
-
-App.AlertDefinition.FIXTURES = [];
-App.AlertReportDefinition.FIXTURES = [];
-App.AlertMetricsSourceDefinition.FIXTURES = [];
-App.AlertMetricsUriDefinition.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alert_group.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert_group.js b/ambari-web/app/models/alert_group.js
deleted file mode 100644
index e914ed5..0000000
--- a/ambari-web/app/models/alert_group.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * 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');
-
-/**
- * Represents an alert-group on the cluster.
- * A alert group is a collection of alert definitions
- *
- * Alert group hierarchy is at 2 levels. For
- * each service there is a 'Default' alert group
- * containing all definitions , this group is read-only
- *
- * User can create new alert group containing alert definitions from
- * any service.
- */
-App.AlertGroup = DS.Model.extend({
-
-  name: DS.attr('string'),
-
-  description: DS.attr('string'),
-
-  /**
-   * Is this group default for some service
-   * @type {boolean}
-   */
-  default: DS.attr('boolean'),
-
-  /**
-   * @type {App.AlertDefinition[]}
-   */
-  definitions: DS.hasMany('App.AlertDefinition'),
-
-  /**
-   * @type {App.AlertNotification[]}
-   */
-  targets: DS.hasMany('App.AlertNotification'),
-
-  /**
-   * @type {string}
-   */
-  displayName: function () {
-    var name = this.get('name');
-    if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
-      var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
-      name = name.substring(0, middle) + "..." + name.substring(name.length - middle);
-    }
-    return this.get('default') ? (name + ' Default') : name;
-  }.property('name', 'default'),
-
-  /**
-   * @type {string}
-   */
-  displayNameDefinitions: function () {
-    return this.get('displayName') + ' (' + this.get('definitions.length') + ')';
-  }.property('displayName', 'definitions.length'),
-
-  isAddDefinitionsDisabled: function () {
-    return this.get('default');
-  }.property('default')
-});
-App.AlertGroup.FIXTURES = [];
-
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alert_instance.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert_instance.js b/ambari-web/app/models/alert_instance.js
deleted file mode 100644
index 33df293..0000000
--- a/ambari-web/app/models/alert_instance.js
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * 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');
-var dateUtils = require('utils/date');
-
-App.AlertInstance = DS.Model.extend({
-  id: DS.attr('number'),
-  label: DS.attr('string'),
-  definitionName: DS.attr('string'),
-  definitionId: DS.attr('number'),
-  service: DS.belongsTo('App.Service'),
-  serviceName: DS.attr('string'),
-  componentName: DS.attr('string'),
-  host: DS.belongsTo('App.Host'),
-  hostName: DS.attr('string'),
-  scope: DS.attr('string'),
-  originalTimestamp: DS.attr('number'),
-  latestTimestamp: DS.attr('number'),
-  maintenanceState: DS.attr('string'),
-  instance: DS.attr('string'),
-  state: DS.attr('string'),
-  text: DS.attr('string'),
-  notification: DS.hasMany('App.AlertNotification'),
-
-  /**
-   * Status icon markup
-   * @type {string}
-   */
-  status: function () {
-    var isMaintenanceStateOn = this.get('maintenanceState') === 'ON';
-    var state = this.get('state');
-    var stateClass = isMaintenanceStateOn ? 'PENDING' : state;
-    var shortState = this.get('shortState')[state];
-    var maintenanceIcon = isMaintenanceStateOn ? '<span class="icon-medkit"></span> ' : '';
-    return '<div class="label alert-state-single-host alert-state-' + stateClass + '">' + maintenanceIcon + shortState + '</div>';
-  }.property('state'),
-
-  /**
-   * For alerts we will have processes which are not typical
-   * cluster services - like Ambari-Server. This method unifies
-   * cluster services and other services into a common display-name.
-   * @see App.AlertDefinition#serviceDisplayName()
-   */
-  serviceDisplayName: function () {
-    var serviceName = this.get('service.displayName');
-    if (!serviceName) {
-      serviceName = this.get('serviceName');
-      if (serviceName) {
-        serviceName = serviceName.toCapital();
-      }
-    }
-    return serviceName;
-  }.property('serviceName', 'service.displayName'),
-
-  /**
-   * Formatted timestamp for latest instance triggering
-   * @type {string}
-   */
-  lastCheckedFormatted: function () {
-    return dateUtils.dateFormat(this.get('latestTimestamp'));
-  }.property('latestTimestamp'),
-
-  /**
-   * Formatted timestamp for latest instance triggering
-   * @type {string}
-   */
-  lastTriggeredFormatted: function () {
-    return dateUtils.dateFormat(this.get('originalTimestamp'));
-  }.property('originalTimestamp'),
-
-  /**
-   * Formatted timestamp with <code>$.timeago</code>
-   * @type {string}
-   */
-  lastTriggeredAgoFormatted: function () {
-    var lastTriggered = this.get('originalTimestamp');
-    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
-  }.property('originalTimestamp'),
-
-  lastTriggeredVerboseDisplay: function () {
-    var originalTimestamp = this.get('originalTimestamp');
-    var latestTimestamp = this.get('latestTimestamp');
-    return Em.I18n.t('models.alert_instance.tiggered.verbose').format(
-        dateUtils.dateFormat(originalTimestamp),
-        dateUtils.dateFormat(latestTimestamp));
-  }.property('originalTimestamp', 'latestTimestamp'),
-
-  /**
-   * Formatted timestamp with <code>$.timeago</code>
-   * @type {string}
-   */
-  lastTriggeredForFormatted: function () {
-    var lastTriggered = this.get('originalTimestamp');
-    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
-    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
-    $.timeago.settings.strings.suffixAgo = null;
-    $.timeago.settings.strings.prefixAgo = 'for';
-    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
-    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
-    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
-    return triggeredFor;
-  }.property('originalTimestamp'),
-
-  /**
-  * escaped '<' and '>' special characters.
-  * @type {string}
-  */  
-  escapeSpecialCharactersFromTooltip: function () {
-    var displayedText = this.get('text');
-    return  displayedText.replace(/[<>]/g, '');
-  }.property('text'),
-
-  /**
-   * Formatted lastChecked and lastTriggered timestamp
-   * @returns {string}
-   */
-  statusChangedAndLastCheckedFormatted: function () {
-    var lastCheckedFormatted = this.get('lastCheckedFormatted');
-    var lastTriggeredFormatted = this.get('lastTriggeredFormatted');
-    return Em.I18n.t('models.alert_definition.triggered.checked').format(lastTriggeredFormatted, lastCheckedFormatted);
-  }.property('lastCheckedFormatted', 'lastTriggeredFormatted'),
-
-  /**
-   * List of css-classes for alert instance status
-   * @type {object}
-   */
-  typeIcons: {
-    'DISABLED': 'icon-off'
-  },
-
-  /**
-   * Define if definition serviceName is Ambari
-   * Used in some logic in templates to distinguish definitions with Ambari serviceName
-   * @returns {boolean}
-   */
-  isAmbariServiceName: function () {
-    return this.get('serviceName') === 'AMBARI';
-  }.property('serviceName'),
-
-  shortState: {
-    'CRITICAL': 'CRIT',
-    'WARNING': 'WARN',
-    'OK': 'OK',
-    'UNKNOWN': 'UNKWN',
-    'PENDING': 'NONE'
-  }
-});
-
-App.AlertInstance.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alert_notification.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alert_notification.js b/ambari-web/app/models/alert_notification.js
deleted file mode 100644
index c2d7570..0000000
--- a/ambari-web/app/models/alert_notification.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * 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.AlertNotification = DS.Model.extend({
-  id: DS.attr('number'),
-  name: DS.attr('string'),
-  type: DS.attr('string'),
-  description: DS.attr('string'),
-  groups: DS.hasMany('App.AlertGroup'),
-  global: DS.attr('boolean'),
-
-  properties: {},
-  alertStates: []
-});
-
-App.AlertNotification.FIXTURES = [];
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alerts/alert_config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alerts/alert_config.js b/ambari-web/app/models/alerts/alert_config.js
new file mode 100644
index 0000000..df2e579
--- /dev/null
+++ b/ambari-web/app/models/alerts/alert_config.js
@@ -0,0 +1,619 @@
+/**
+ * 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');
+var validator = require('utils/validator');
+var numericUtils = require('utils/number_utils');
+
+App.AlertConfigProperty = Ember.Object.extend({
+
+  /**
+   * label to be shown for config property
+   * @type {String}
+   */
+  label: '',
+
+  /**
+   * PORT|METRIC|AGGREGATE
+   * @type {String}
+   */
+  type: '',
+
+  /**
+   * config property value
+   * @type {*}
+   */
+  value: null,
+
+  /**
+   * property value cache to realise undo function
+   * @type {*}
+   */
+  previousValue: null,
+
+  /**
+   * define either input is disabled or enabled
+   * @type {Boolean}
+   */
+  isDisabled: false,
+
+  /**
+   * options that Select list will have
+   * @type {Array}
+   */
+  options: [],
+
+  /**
+   * input displayType
+   * one of 'textFields', 'textArea', 'select' or 'threshold'
+   * @type {String}
+   */
+  displayType: '',
+
+  /**
+   * unit to be shown with value
+   * @type {String}
+   */
+  unit: null,
+
+  /**
+   * space separated list of css class names to use
+   * @type {String}
+   */
+  classNames: '',
+
+  /**
+   * define whether row with property should be shifted right
+   * @type {Boolean}
+   */
+  isShifted: false,
+
+  /**
+   * name or names of properties related to config
+   * may be either string for one property or array of strings for multiple properties
+   * if this property is array, then <code>apiFormattedValue</code> should also be an array
+   * example: <code>apiProperty[0]</code> relates to <code>apiFormattedValue[0]</code>
+   * @type {String|Array}
+   */
+  apiProperty: '',
+
+  /**
+   * for some metrics properties may be set true or false
+   * depending on what property is related to (JMX or Ganglia)
+   */
+  isJMXMetric: null,
+
+  /**
+   * define place to show label
+   * if true - label is shown before input
+   * if false - label is shown after input
+   * @type {Boolean}
+   */
+  isPreLabeled: function () {
+    var afterLabeledTypes = ['radioButton'];
+    return !afterLabeledTypes.contains(this.get('displayType'));
+  }.property('displayType'),
+
+  /**
+   * value converted to appropriate format for sending to server
+   * should be computed property
+   * should be defined in child class
+   * @type {*}
+   */
+  apiFormattedValue: function () {
+    return this.get('value');
+  }.property('value'),
+
+  /**
+   * define if property was changed by user
+   * @type {Boolean}
+   */
+  wasChanged: function () {
+    return this.get('previousValue') !== null && this.get('value') !== this.get('previousValue');
+  }.property('value', 'previousValue'),
+
+  /**
+   * view class according to <code>displayType</code>
+   * @type {Em.View}
+   */
+  viewClass: function () {
+    var displayType = this.get('displayType');
+    switch (displayType) {
+      case 'textField':
+        return App.AlertConfigTextFieldView;
+      case 'textArea':
+        return App.AlertConfigTextAreaView;
+      case 'select':
+        return App.AlertConfigSelectView;
+      case 'threshold':
+        return App.AlertConfigThresholdView;
+      case 'radioButton':
+        return App.AlertConfigRadioButtonView;
+      default:
+        console.error('Unable to find viewClass for displayType ', displayType);
+    }
+  }.property('displayType'),
+
+  /**
+   * Define whether property is valid
+   * Computed property
+   * Should be defined in child class
+   * @type {Boolean}
+   */
+  isValid: function () {
+    return true;
+  }.property()
+
+});
+
+App.AlertConfigProperties = {
+
+  AlertName: App.AlertConfigProperty.extend({
+    name: 'alert_name',
+    label: 'Alert Name',
+    displayType: 'textField',
+    classNames: 'alert-text-input',
+    apiProperty: 'name'
+  }),
+
+  AlertNameSelected: App.AlertConfigProperty.extend({
+    name: 'alert_name',
+    label: 'Alert Name',
+    displayType: 'select',
+    apiProperty: 'name'
+  }),
+
+  ServiceAlertType: App.AlertConfigProperty.extend({
+    name: 'alert_type_service',
+    label: 'Service Alert Definition',
+    displayType: 'radioButton',
+    group: 'alert_type'
+  }),
+
+  HostAlertType: App.AlertConfigProperty.extend({
+    name: 'alert_type_host',
+    label: 'Host Alert Definition',
+    displayType: 'radioButton',
+    group: 'alert_type'
+  }),
+
+  Service: App.AlertConfigProperty.extend({
+    name: 'service',
+    label: 'Service',
+    displayType: 'select',
+    apiProperty: 'service_name',
+    apiFormattedValue: function () {
+      return App.StackService.find().findProperty('displayName', this.get('value')).get('serviceName');
+    }.property('value')
+  }),
+
+  Component: App.AlertConfigProperty.extend({
+    name: 'component',
+    label: 'Component',
+    displayType: 'select',
+    apiProperty: 'component_name',
+    apiFormattedValue: function () {
+      return App.StackServiceComponent.find().findProperty('displayName', this.get('value')).get('componentName');
+    }.property('value')
+  }),
+
+  Scope: App.AlertConfigProperty.extend({
+    name: 'scope',
+    label: 'Scope',
+    displayType: 'select',
+    apiProperty: 'scope',
+    apiFormattedValue: function () {
+      return this.get('value').toUpperCase();
+    }.property('value')
+  }),
+
+  Description: App.AlertConfigProperty.extend({
+    name: 'description',
+    label: 'Description',
+    displayType: 'textArea',
+    classNames: 'alert-config-text-area',
+    // todo: check value after API will be provided
+    apiProperty: 'description'
+  }),
+
+  Interval: App.AlertConfigProperty.extend({
+    name: 'interval',
+    label: 'Check Interval',
+    displayType: 'textField',
+    unit: 'Minute',
+    classNames: 'alert-interval-input',
+    apiProperty: 'interval',
+    isValid: function () {
+      var value = this.get('value');
+      if (!value) return false;
+      return String(value) === String(parseInt(value, 10)) && value >= 1;
+    }.property('value')
+  }),
+
+  /**
+   * 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: '',
+
+    /**
+     * Type of value. This will be a fixed set of types (like %).
+     */
+    valueMetric: null,
+
+    /**
+     * Value actually displayed to the user. This value is transformed
+     * based on the limited types of 'valueMetric's. Mappings from
+     * 'value' to 'displayValue' is handled by observers.
+     */
+    displayValue: '',
+
+    /**
+     * threshold-text
+     * @type {string}
+     */
+    text: '',
+
+    displayType: 'threshold',
+
+    classNames: 'alert-thresholds-input',
+
+    apiProperty: [],
+
+    init: function () {
+      this.set('displayValue', this.getNewValue());
+      this._super();
+    },
+
+    /**
+     * @type {string[]}
+     */
+    apiFormattedValue: function () {
+      var ret = [];
+      if (this.get('showInputForValue')) {
+        ret.push(this.get('value'));
+      }
+      if (this.get('showInputForText')) {
+        ret.push(this.get('text'));
+      }
+      return ret;
+    }.property('value', 'text', 'showInputForValue', 'showInputForText'),
+
+    /**
+     * 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'),
+
+    /**
+     * May be redefined in child-models, mixins etc
+     * @method getValue
+     * @returns {string}
+     */
+    getNewValue: function () {
+      return this.get('value');
+    },
+
+    valueWasChanged: function () {
+      var displayValue = this.get('displayValue');
+      var newDisplayValue = this.getNewValue();
+      if (newDisplayValue !== displayValue && !(isNaN(newDisplayValue) ||isNaN(displayValue))) {
+        this.set('displayValue', newDisplayValue);
+      }
+    }.observes('value'),
+
+    /**
+     * May be redefined in child-models, mixins etc
+     * @method getDisplayValue
+     * @returns {string}
+     */
+    getNewDisplayValue: function () {
+      return this.get('displayValue');
+    },
+
+    displayValueWasChanged: function () {
+      var value = this.get('value');
+      var newValue = this.getNewDisplayValue();
+      if (newValue !== value && !(isNaN(newValue) ||isNaN(value))) {
+        this.set('value', newValue);
+      }
+    }.observes('displayValue'),
+
+    /**
+     * Check if <code>displayValue</code> is valid float number
+     * If this value isn't shown (see <code>showInputForValue</code>), result is always true
+     * @return {boolean}
+     */
+    isValid: function () {
+      if (!this.get('showInputForValue')) {
+        return true;
+      }
+
+      var value = this.get('displayValue');
+
+      if (Em.isNone(value)) {
+        return false;
+      }
+
+      value = ('' + value).trim();
+
+      //only allow 1/10th of a second
+      if (numericUtils.getFloatDecimals(value) > 1) {
+        return false;
+      }
+
+      return validator.isValidFloat(value);
+    }.property('displayValue', 'showInputForValue')
+
+  }),
+
+  URI: App.AlertConfigProperty.extend({
+    name: 'uri',
+    label: 'URI',
+    displayType: 'textField',
+    classNames: 'alert-text-input',
+    apiProperty: 'source.uri'
+  }),
+
+  URIExtended: App.AlertConfigProperty.extend({
+    name: 'uri',
+    label: 'URI',
+    displayType: 'textArea',
+    classNames: 'alert-config-text-area',
+    apiProperty: 'source.uri',
+    apiFormattedValue: function () {
+      var result = {};
+      try {
+        result = JSON.parse(this.get('value'));
+      } catch (e) {
+        console.error('Wrong format of URI');
+      }
+      return result;
+    }.property('value')
+  }),
+
+  DefaultPort: App.AlertConfigProperty.extend({
+    name: 'default_port',
+    label: 'Default Port',
+    displayType: 'textField',
+    classNames: 'alert-port-input',
+    apiProperty: 'source.default_port'
+  }),
+
+  Path: App.AlertConfigProperty.extend({
+    name: 'path',
+    label: 'Path',
+    displayType: 'textField',
+    classNames: 'alert-text-input',
+    apiProperty: 'source.path'
+  }),
+
+  Metrics: App.AlertConfigProperty.extend({
+    name: 'metrics',
+    label: 'JMX/Ganglia Metrics',
+    displayType: 'textArea',
+    classNames: 'alert-config-text-area',
+    apiProperty: function () {
+      return this.get('isJMXMetric') ? 'source.jmx.property_list' : 'source.ganglia.property_list'
+    }.property('isJMXMetric'),
+    apiFormattedValue: function () {
+      return this.get('value').split(',\n');
+    }.property('value')
+  }),
+
+  FormatString: App.AlertConfigProperty.extend({
+    name: 'metrics_string',
+    label: 'Format String',
+    displayType: 'textArea',
+    classNames: 'alert-config-text-area',
+    apiProperty: function () {
+      return this.get('isJMXMetric') ? 'source.jmx.value' : 'source.ganglia.value'
+    }.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')
+
+  }),
+
+  /**
+   * Mixin for <code>App.AlertConfigProperties.Threshold</code>
+   * Used to validate values in percentage range (0..1]
+   * @type {Em.Mixin}
+   */
+  PercentageMixin: Em.Mixin.create({
+
+    isValid: function () {
+      var value = this.get('displayValue');
+
+      if (!value) {
+        return false;
+      }
+
+      value = ('' + value).trim();
+      if (numericUtils.getFloatDecimals(value)) {
+        return false;
+      }
+
+      value = parseFloat(value);
+
+      //do not allow float values
+      if (parseInt(value, 10) !== value) {
+        return false;
+      }
+
+      return this.get('showInputForValue') ? !isNaN(value) && value > 0 && value <= 100 : true;
+    }.property('displayValue', 'showInputForValue'),
+
+    /**
+     * Return <code>value * 100</code>
+     * @returns {string}
+     */
+    getNewValue: function () {
+      var value = this.get('value');
+      return (value && !isNaN(value)) ? (Number(value) * 100) + '' : value;
+    },
+
+    /**
+     * Return <code>displayValue / 100</code>
+     * @returns {string}
+     */
+    getNewDisplayValue: function () {
+      var displayValue = this.get('displayValue');
+      return (displayValue && !isNaN(displayValue)) ? (Number(displayValue) / 100) + '' : displayValue;
+    }
+
+  }),
+
+  /**
+   * Mixin for <code>App.AlertConfigProperties.Threshold</code>
+   * Used to validate values that should be greater than 0
+   * @type {Em.Mixin}
+   */
+  PositiveMixin: Em.Mixin.create({
+
+    isValid: function () {
+      if (!this.get('showInputForValue')) {
+        return true;
+      }
+      var value = this.get('displayValue');
+
+      if (!value) {
+        return false;
+      }
+
+      //only allow 1/10th of a second
+      if (numericUtils.getFloatDecimals(value) > 1) {
+        return false;
+      }
+
+      value = ('' + value).trim();
+      value = parseFloat(value);
+
+      return !isNaN(value) && value > 0;
+    }.property('displayValue', 'showInputForValue')
+
+  })
+
+};

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alerts/alert_definition.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alerts/alert_definition.js b/ambari-web/app/models/alerts/alert_definition.js
new file mode 100644
index 0000000..d1310ff
--- /dev/null
+++ b/ambari-web/app/models/alerts/alert_definition.js
@@ -0,0 +1,344 @@
+/**
+ * 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');
+var dateUtils = require('utils/date');
+
+App.AlertDefinition = DS.Model.extend({
+
+  name: DS.attr('string'),
+  label: DS.attr('string'),
+  description: DS.attr('string'),
+  service: DS.belongsTo('App.Service'),
+  serviceName: DS.attr('string'),
+  componentName: DS.attr('string'),
+  enabled: DS.attr('boolean'),
+  scope: DS.attr('string'),
+  interval: DS.attr('number'),
+  type: DS.attr('string'),
+  groups: DS.hasMany('App.AlertGroup'),
+  reporting: DS.hasMany('App.AlertReportDefinition'),
+  lastTriggered: DS.attr('number'),
+
+  //relates only to SCRIPT-type alert definition
+  location: DS.attr('string'),
+  //relates only to AGGREGATE-type alert definition
+  alertName: DS.attr('string'),
+  //relates only to WEB and METRIC types of alert definition
+  uri: DS.belongsTo('App.AlertMetricsUriDefinition'),
+  //relates only METRIC-type alert definition
+  jmx: DS.belongsTo('App.AlertMetricsSourceDefinition'),
+  ganglia: DS.belongsTo('App.AlertMetricsSourceDefinition'),
+  //relates only PORT-type alert definition
+  defaultPort: DS.attr('number'),
+  portUri: DS.attr('string'),
+
+  /**
+   * Raw data from AlertDefinition/source
+   * used to format request content for updating alert definition
+   * @type {Object}
+   */
+  rawSourceData: {},
+
+  /**
+   * Counts of alert grouped by their status
+   * Format:
+   * <code>
+   *   {
+   *    "CRITICAL": {
+   *      count: 1,
+   *      maintenanceCount: 0
+   *    },
+   *    "OK": {
+   *      count: 0,
+   *      maintenanceCount: 1
+   *    },
+   *    "UNKNOWN": {
+   *      count: 0,
+   *      maintenanceCount: 0
+   *    },
+   *    "WARNING": {
+   *      count: 1,
+   *      maintenanceCount: 1
+   *    }
+   *   }
+   * </code>
+   * @type {object}
+   */
+  summary: {},
+
+  /**
+   * Formatted timestamp for latest alert triggering for current alertDefinition
+   * @type {string}
+   */
+  lastTriggeredFormatted: function () {
+    return dateUtils.dateFormat(this.get('lastTriggered'));
+  }.property('lastTriggered'),
+
+  /**
+   * Formatted timestamp with <code>$.timeago</code>
+   * @type {string}
+   */
+  lastTriggeredAgoFormatted: function () {
+    var lastTriggered = this.get('lastTriggered');
+    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
+  }.property('lastTriggered'),
+
+  lastTriggeredVerboseDisplay: function () {
+    var lastTriggered = this.get('lastTriggered');
+    return Em.I18n.t('models.alert_definition.triggered.verbose').format(dateUtils.dateFormat(lastTriggered));
+  }.property('lastTriggered'),
+
+  /**
+   * Formatted timestamp in format: for 4 days
+   * @type {string}
+   */
+  lastTriggeredForFormatted: function () {
+    var lastTriggered = this.get('lastTriggered');
+    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
+    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
+    $.timeago.settings.strings.suffixAgo = null;
+    $.timeago.settings.strings.prefixAgo = 'for';
+    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
+    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
+    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
+    return triggeredFor;
+  }.property('lastTriggered'),
+
+  /**
+   * Formatted displayName for <code>componentName</code>
+   * @type {String}
+   */
+  componentNameFormatted: function () {
+    return App.format.role(this.get('componentName'));
+  }.property('componentName'),
+
+  /**
+   * Status generates from child-alerts
+   * Format: OK(1)  WARN(2)  CRIT(1)  UNKN(1)
+   * If single host: show: OK/WARNING/CRITICAL/UNKNOWN
+   * If some there are no alerts with some state, this state isn't shown
+   * If no OK/WARN/CRIT/UNKN state, then show PENDING
+   * Order is equal to example
+   * @type {string}
+   */
+  status: function () {
+    var order = this.get('order'),
+        summary = this.get('summary'),
+        hostCnt = 0,
+        self = this;
+    order.forEach(function (state) {
+      hostCnt += summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
+    });
+    if (hostCnt > 1) {
+      // multiple hosts
+      return order.map(function (state) {
+        var shortState = self.get('shortState')[state];
+        var result = '';
+        result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + ' (' + summary[state].count + ')</span>' : '';
+        // add status with maintenance mode icon
+        result += summary[state].maintenanceCount ?
+        '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + ' (' + summary[state].maintenanceCount + ')</span>' : '';
+        return result;
+      }).without('').join(' ');
+    } else if (hostCnt == 1) {
+      // single host, single status
+      return order.map(function (state) {
+        var shortState = self.get('shortState')[state];
+        var result = '';
+        result += summary[state].count ? '<span class="alert-state-single-host label alert-state-' + state + '">' + shortState + '</span>' : '';
+        // add status with maintenance mode icon
+        result += summary[state].maintenanceCount ?
+        '<span class="alert-state-single-host label alert-state-PENDING"><span class="icon-medkit"></span> ' + shortState + '</span>' : '';
+        return result;
+      }).without('').join(' ');
+    } else if (hostCnt == 0) {
+      // none
+      return '<span class="alert-state-single-host label alert-state-PENDING">NONE</span>';
+    }
+    return '';
+  }.property('summary'),
+
+  latestText: function () {
+    var order = this.get('order'), summary = this.get('summary'), text = '';
+    order.forEach(function (state) {
+      var cnt = summary[state] ? summary[state].count + summary[state].maintenanceCount : 0;
+      if (cnt > 0) {
+        text = summary[state].latestText;
+      }
+    });
+    return text;
+  }.property('summary'),
+
+  isHostAlertDefinition: function () {
+    var serviceID = (this.get('service')._id === "AMBARI"),
+        component = (this.get('componentName') === "AMBARI_AGENT");
+    return serviceID && component;
+  }.property('service', 'componentName'),
+
+  typeIconClass: function () {
+    var typeIcons = this.get('typeIcons'),
+        type = this.get('type');
+    return typeIcons[type];
+  }.property('type'),
+
+  /**
+   * if this definition is in state: CRITICAL / WARNING, if true, will show up in alerts fast access popup
+   * instances with maintenance mode ON are ignored
+   * @type {boolean}
+   */
+  isCriticalOrWarning: function () {
+    return !!(this.get('summary.CRITICAL.count') || this.get('summary.WARNING.count'));
+  }.property('summary'),
+
+  /**
+   * if this definition is in state: CRIT
+   * @type {boolean}
+   */
+  isCritical: function () {
+    var summary = this.get('summary');
+    var state = 'CRITICAL';
+    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
+  }.property('summary'),
+
+  /**
+   * if this definition is in state: WARNING
+   * @type {boolean}
+   */
+  isWarning: function () {
+    var summary = this.get('summary');
+    var state = 'WARNING';
+    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
+  }.property('summary'),
+
+  /**
+   * if this definition is in state: OK
+   * @type {boolean}
+   */
+  isOK: function () {
+    var summary = this.get('summary');
+    var state = 'OK';
+    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
+  }.property('summary'),
+
+  /**
+   * if this definition is in state: OK
+   * @type {boolean}
+   */
+  isUnknown: function () {
+    var summary = this.get('summary');
+    var state = 'UNKNOWN';
+    return !!summary[state] && !!(summary[state].count || summary[state].maintenanceCount);
+  }.property('summary'),
+
+  /**
+   * For alerts we will have processes which are not typical
+   * cluster services - like Ambari-Server. This method unifies
+   * cluster services and other services into a common display-name.
+   * @see App.AlertInstance#serviceDisplayName()
+   */
+  serviceDisplayName: function () {
+    var serviceName = this.get('service.displayName');
+    if (!serviceName) {
+      serviceName = this.get('serviceName');
+      if (serviceName) {
+        serviceName = serviceName.toCapital();
+      }
+    }
+    return serviceName;
+  }.property('serviceName', 'service.displayName'),
+
+  /**
+   * List of css-classes for alert types
+   * @type {object}
+   */
+  typeIcons: {
+    'METRIC': 'icon-bolt',
+    'SCRIPT': 'icon-file-text',
+    'WEB': 'icon-globe',
+    'PORT': 'icon-signin',
+    'AGGREGATE': 'icon-plus',
+    'SERVER': 'icon-desktop'
+  },
+
+  /**
+   * Sort on load definitions by this severity order
+   */
+  severityOrder: ['CRITICAL', 'WARNING', 'OK', 'UNKNOWN', 'PENDING'],
+  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
+
+  shortState: {
+    'CRITICAL': 'CRIT',
+    'WARNING': 'WARN',
+    'OK': 'OK',
+    'UNKNOWN': 'UNKWN',
+    'PENDING': 'NONE'
+  }
+});
+
+App.AlertDefinition.reopenClass({
+
+  /**
+   * Return function to sort list of AlertDefinitions by their status
+   * It sorts according to <code>severityOrder</code>
+   * @param {boolean} order true - DESC, false - ASC
+   * @returns {Function}
+   * @method getSortDefinitionsByStatus
+   */
+  getSortDefinitionsByStatus: function (order) {
+    return function (a, b) {
+      var a_summary = a.get('summary'),
+        b_summary = b.get('summary'),
+        st_order = a.get('severityOrder'),
+        ret = 0;
+      for (var i = 0; i < st_order.length; i++) {
+        var a_v = Em.isNone(a_summary[st_order[i]]) ? 0 : a_summary[st_order[i]].count + a_summary[st_order[i]].maintenanceCount,
+          b_v = Em.isNone(b_summary[st_order[i]]) ? 0 : b_summary[st_order[i]].count + b_summary[st_order[i]].maintenanceCount;
+        ret = b_v - a_v;
+        if (ret !== 0) {
+          break;
+        }
+      }
+      return order ? ret : -ret;
+    };
+  }
+
+});
+
+App.AlertReportDefinition = DS.Model.extend({
+  type: DS.attr('string'),
+  text: DS.attr('string'),
+  value: DS.attr('number')
+});
+
+App.AlertMetricsSourceDefinition = DS.Model.extend({
+  propertyList: [],
+  value: DS.attr('string')
+});
+
+App.AlertMetricsUriDefinition = DS.Model.extend({
+  http: DS.attr('string'),
+  https: DS.attr('string'),
+  httpsProperty: DS.attr('string'),
+  httpsPropertyValue: DS.attr('string')
+});
+
+App.AlertDefinition.FIXTURES = [];
+App.AlertReportDefinition.FIXTURES = [];
+App.AlertMetricsSourceDefinition.FIXTURES = [];
+App.AlertMetricsUriDefinition.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alerts/alert_group.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alerts/alert_group.js b/ambari-web/app/models/alerts/alert_group.js
new file mode 100644
index 0000000..e914ed5
--- /dev/null
+++ b/ambari-web/app/models/alerts/alert_group.js
@@ -0,0 +1,79 @@
+/**
+ * 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');
+
+/**
+ * Represents an alert-group on the cluster.
+ * A alert group is a collection of alert definitions
+ *
+ * Alert group hierarchy is at 2 levels. For
+ * each service there is a 'Default' alert group
+ * containing all definitions , this group is read-only
+ *
+ * User can create new alert group containing alert definitions from
+ * any service.
+ */
+App.AlertGroup = DS.Model.extend({
+
+  name: DS.attr('string'),
+
+  description: DS.attr('string'),
+
+  /**
+   * Is this group default for some service
+   * @type {boolean}
+   */
+  default: DS.attr('boolean'),
+
+  /**
+   * @type {App.AlertDefinition[]}
+   */
+  definitions: DS.hasMany('App.AlertDefinition'),
+
+  /**
+   * @type {App.AlertNotification[]}
+   */
+  targets: DS.hasMany('App.AlertNotification'),
+
+  /**
+   * @type {string}
+   */
+  displayName: function () {
+    var name = this.get('name');
+    if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
+      var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
+      name = name.substring(0, middle) + "..." + name.substring(name.length - middle);
+    }
+    return this.get('default') ? (name + ' Default') : name;
+  }.property('name', 'default'),
+
+  /**
+   * @type {string}
+   */
+  displayNameDefinitions: function () {
+    return this.get('displayName') + ' (' + this.get('definitions.length') + ')';
+  }.property('displayName', 'definitions.length'),
+
+  isAddDefinitionsDisabled: function () {
+    return this.get('default');
+  }.property('default')
+});
+App.AlertGroup.FIXTURES = [];
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alerts/alert_instance.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alerts/alert_instance.js b/ambari-web/app/models/alerts/alert_instance.js
new file mode 100644
index 0000000..33df293
--- /dev/null
+++ b/ambari-web/app/models/alerts/alert_instance.js
@@ -0,0 +1,165 @@
+/**
+ * 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');
+var dateUtils = require('utils/date');
+
+App.AlertInstance = DS.Model.extend({
+  id: DS.attr('number'),
+  label: DS.attr('string'),
+  definitionName: DS.attr('string'),
+  definitionId: DS.attr('number'),
+  service: DS.belongsTo('App.Service'),
+  serviceName: DS.attr('string'),
+  componentName: DS.attr('string'),
+  host: DS.belongsTo('App.Host'),
+  hostName: DS.attr('string'),
+  scope: DS.attr('string'),
+  originalTimestamp: DS.attr('number'),
+  latestTimestamp: DS.attr('number'),
+  maintenanceState: DS.attr('string'),
+  instance: DS.attr('string'),
+  state: DS.attr('string'),
+  text: DS.attr('string'),
+  notification: DS.hasMany('App.AlertNotification'),
+
+  /**
+   * Status icon markup
+   * @type {string}
+   */
+  status: function () {
+    var isMaintenanceStateOn = this.get('maintenanceState') === 'ON';
+    var state = this.get('state');
+    var stateClass = isMaintenanceStateOn ? 'PENDING' : state;
+    var shortState = this.get('shortState')[state];
+    var maintenanceIcon = isMaintenanceStateOn ? '<span class="icon-medkit"></span> ' : '';
+    return '<div class="label alert-state-single-host alert-state-' + stateClass + '">' + maintenanceIcon + shortState + '</div>';
+  }.property('state'),
+
+  /**
+   * For alerts we will have processes which are not typical
+   * cluster services - like Ambari-Server. This method unifies
+   * cluster services and other services into a common display-name.
+   * @see App.AlertDefinition#serviceDisplayName()
+   */
+  serviceDisplayName: function () {
+    var serviceName = this.get('service.displayName');
+    if (!serviceName) {
+      serviceName = this.get('serviceName');
+      if (serviceName) {
+        serviceName = serviceName.toCapital();
+      }
+    }
+    return serviceName;
+  }.property('serviceName', 'service.displayName'),
+
+  /**
+   * Formatted timestamp for latest instance triggering
+   * @type {string}
+   */
+  lastCheckedFormatted: function () {
+    return dateUtils.dateFormat(this.get('latestTimestamp'));
+  }.property('latestTimestamp'),
+
+  /**
+   * Formatted timestamp for latest instance triggering
+   * @type {string}
+   */
+  lastTriggeredFormatted: function () {
+    return dateUtils.dateFormat(this.get('originalTimestamp'));
+  }.property('originalTimestamp'),
+
+  /**
+   * Formatted timestamp with <code>$.timeago</code>
+   * @type {string}
+   */
+  lastTriggeredAgoFormatted: function () {
+    var lastTriggered = this.get('originalTimestamp');
+    return lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
+  }.property('originalTimestamp'),
+
+  lastTriggeredVerboseDisplay: function () {
+    var originalTimestamp = this.get('originalTimestamp');
+    var latestTimestamp = this.get('latestTimestamp');
+    return Em.I18n.t('models.alert_instance.tiggered.verbose').format(
+        dateUtils.dateFormat(originalTimestamp),
+        dateUtils.dateFormat(latestTimestamp));
+  }.property('originalTimestamp', 'latestTimestamp'),
+
+  /**
+   * Formatted timestamp with <code>$.timeago</code>
+   * @type {string}
+   */
+  lastTriggeredForFormatted: function () {
+    var lastTriggered = this.get('originalTimestamp');
+    var previousSuffixAgo = $.timeago.settings.strings.suffixAgo;
+    var previousPrefixAgo = $.timeago.settings.strings.prefixAgo;
+    $.timeago.settings.strings.suffixAgo = null;
+    $.timeago.settings.strings.prefixAgo = 'for';
+    var triggeredFor = lastTriggered ? $.timeago(new Date(lastTriggered)) : '';
+    $.timeago.settings.strings.suffixAgo = previousSuffixAgo;
+    $.timeago.settings.strings.prefixAgo = previousPrefixAgo;
+    return triggeredFor;
+  }.property('originalTimestamp'),
+
+  /**
+  * escaped '<' and '>' special characters.
+  * @type {string}
+  */  
+  escapeSpecialCharactersFromTooltip: function () {
+    var displayedText = this.get('text');
+    return  displayedText.replace(/[<>]/g, '');
+  }.property('text'),
+
+  /**
+   * Formatted lastChecked and lastTriggered timestamp
+   * @returns {string}
+   */
+  statusChangedAndLastCheckedFormatted: function () {
+    var lastCheckedFormatted = this.get('lastCheckedFormatted');
+    var lastTriggeredFormatted = this.get('lastTriggeredFormatted');
+    return Em.I18n.t('models.alert_definition.triggered.checked').format(lastTriggeredFormatted, lastCheckedFormatted);
+  }.property('lastCheckedFormatted', 'lastTriggeredFormatted'),
+
+  /**
+   * List of css-classes for alert instance status
+   * @type {object}
+   */
+  typeIcons: {
+    'DISABLED': 'icon-off'
+  },
+
+  /**
+   * Define if definition serviceName is Ambari
+   * Used in some logic in templates to distinguish definitions with Ambari serviceName
+   * @returns {boolean}
+   */
+  isAmbariServiceName: function () {
+    return this.get('serviceName') === 'AMBARI';
+  }.property('serviceName'),
+
+  shortState: {
+    'CRITICAL': 'CRIT',
+    'WARNING': 'WARN',
+    'OK': 'OK',
+    'UNKNOWN': 'UNKWN',
+    'PENDING': 'NONE'
+  }
+});
+
+App.AlertInstance.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/66d0b6e2/ambari-web/app/models/alerts/alert_instance_local.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/alerts/alert_instance_local.js b/ambari-web/app/models/alerts/alert_instance_local.js
new file mode 100644
index 0000000..be34565
--- /dev/null
+++ b/ambari-web/app/models/alerts/alert_instance_local.js
@@ -0,0 +1,30 @@
+/**
+ * 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');
+
+/**
+ * Just a copy of <code>App.AlertInstance</code>, used to save separately alert instances for host and definition
+ * Sometimes alert instances can't be stored in the one model. Example: user is in the definition details page and open
+ * alerts popup. Different lists of instances should be shown and loaded. Also it's pretty hard to determine, which
+ * models should be removed from store, when user navigates in the popup or just leave the page
+ * @type {DS.Model}
+ */
+App.AlertInstanceLocal = App.AlertInstance.extend({});
+
+App.AlertInstanceLocal.FIXTURES = [];
\ No newline at end of file