Repository: ambari
Updated Branches:
  refs/heads/trunk ab48cfbf0 -> 93b6119cf


AMBARI-8308. Alerts UI: Summary Page. Fill Status and Last Triggered columns 
(onechiporenko)


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

Branch: refs/heads/trunk
Commit: 93b6119cfb37253dfe5006bc61591dbd56354300
Parents: ab48cfb
Author: Oleg Nechiporenko <onechipore...@apache.org>
Authored: Thu Nov 13 16:03:34 2014 +0200
Committer: Oleg Nechiporenko <onechipore...@apache.org>
Committed: Thu Nov 13 16:03:34 2014 +0200

----------------------------------------------------------------------
 .../app/assets/data/alerts/alert_summary.json   |  93 ++++++++++++++
 ambari-web/app/assets/test/tests.js             |   3 +
 .../controllers/global/cluster_controller.js    |   4 +-
 .../app/controllers/global/update_controller.js |  12 ++
 .../main/alert_definitions_controller.js        |  51 --------
 ambari-web/app/mappers.js                       |   1 +
 .../mappers/alert_definition_summary_mapper.js  |  51 ++++++++
 .../app/mappers/alert_definitions_mapper.js     |  16 ++-
 ambari-web/app/models/alert_definition.js       |  40 ++++--
 ambari-web/app/templates/main/alerts.hbs        |   2 +-
 ambari-web/app/views/common/filter_view.js      |   9 ++
 ambari-web/app/views/common/sort_view.js        |  24 +++-
 .../app/views/main/alert_definitions_view.js    |  35 ++----
 .../global/update_controller_test.js            |   2 +-
 .../alert_definition_summary_mapper_test.js     | 125 +++++++++++++++++++
 ambari-web/test/models/alert_definition_test.js |  60 +++++++++
 .../test/views/common/filter_view_test.js       |  30 ++++-
 ambari-web/test/views/common/sort_view_test.js  |  68 ++++++++++
 18 files changed, 531 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/assets/data/alerts/alert_summary.json
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/data/alerts/alert_summary.json 
b/ambari-web/app/assets/data/alerts/alert_summary.json
new file mode 100644
index 0000000..b870999
--- /dev/null
+++ b/ambari-web/app/assets/data/alerts/alert_summary.json
@@ -0,0 +1,93 @@
+{
+  "href" : 
"http://localhost:8080/api/v1/clusters/c1/alerts?format=groupedSummary";,
+  "alerts_summary_grouped" : [
+    {
+      "definition_id" : 34,
+      "definition_name" : "yarn_resourcemanager_webui",
+      "summary" : {
+        "OK" : {
+          "count" : 1,
+          "original_timestamp" : 1415732283450
+        },
+        "WARNING" : {
+          "count" : 0,
+          "original_timestamp" : 0
+        },
+        "CRITICAL" : {
+          "count" : 0,
+          "original_timestamp" : 0
+        },
+        "UNKNOWN" : {
+          "count" : 0,
+          "original_timestamp" : 0
+        }
+      }
+    },
+    {
+      "definition_id" : 12,
+      "definition_name" : "ganglia_monitor_mapreduce_history_server",
+      "summary" : {
+        "OK" : {
+          "count" : 1,
+          "original_timestamp" : 1415735183450
+        },
+        "WARNING" : {
+          "count" : 3,
+          "original_timestamp" : 1415735183450
+        },
+        "CRITICAL" : {
+          "count" : 1,
+          "original_timestamp" : 1415755183450
+        },
+        "UNKNOWN" : {
+          "count" : 2,
+          "original_timestamp" : 1412335183450
+        }
+      }
+    },
+    {
+      "definition_id" : 1,
+      "definition_name" : "ganglia_monitor_hdfs_namenode",
+      "summary" : {
+        "OK" : {
+          "count" : 2,
+          "original_timestamp" : 1415735183450
+        },
+        "WARNING" : {
+          "count" : 1,
+          "original_timestamp" : 1415735183450
+        },
+        "CRITICAL" : {
+          "count" : 3,
+          "original_timestamp" : 1415855183450
+        },
+        "UNKNOWN" : {
+          "count" : 2,
+          "original_timestamp" : 1412335183450
+        }
+      }
+    },
+    {
+      "definition_id" : 1,
+      "definition_name" : "ganglia_monitor_hbase_master",
+      "summary" : {
+        "OK" : {
+          "count" : 2,
+          "original_timestamp" : 1415735183450
+        },
+        "WARNING" : {
+          "count" : 2,
+          "original_timestamp" : 1415735183450
+        },
+        "CRITICAL" : {
+          "count" : 3,
+          "original_timestamp" : 1415355183450
+        },
+        "UNKNOWN" : {
+          "count" : 2,
+          "original_timestamp" : 1412335183450
+        }
+      }
+    }
+  ]
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/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 aab4bf2..6e2a10c 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -103,6 +103,7 @@ var files = ['test/init_model_test',
   'test/controllers/wizard/stack_upgrade/step3_controller_test',
   'test/login_test',
   'test/router_test',
+  'test/mappers/alert_definition_summary_mapper_test',
   'test/mappers/server_data_mapper_test',
   'test/mappers/hosts_mapper_test',
   'test/mappers/service_mapper_test',
@@ -138,6 +139,7 @@ var files = ['test/init_model_test',
   'test/views/common/quick_link_view_test',
   'test/views/common/rolling_restart_view_test',
   'test/views/common/modal_popup_test',
+  'test/views/common/sort_view_test',
   'test/views/common/configs/config_history_flow_test',
   'test/views/main/dashboard_test',
   'test/views/main/menu_test',
@@ -192,6 +194,7 @@ var files = ['test/init_model_test',
   'test/models/service/hdfs_test',
   'test/models/service/yarn_test',
   'test/models/alert_test',
+  'test/models/alert_definition_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/93b6119c/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js 
b/ambari-web/app/controllers/global/cluster_controller.js
index 1cebb43..7469d5b 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -341,7 +341,9 @@ App.ClusterController = Em.Controller.extend({
           self.updateLoadStatus('serviceMetrics');
 
           updater.updateAlertDefinitions(function () {
-            self.updateLoadStatus('alertDefinitions');
+            updater.updateAlertDefinitionSummary(function() {
+              self.updateLoadStatus('alertDefinitions');
+            });
           });
         });
       });

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/controllers/global/update_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/update_controller.js 
b/ambari-web/app/controllers/global/update_controller.js
index bd67e01..711d994 100644
--- a/ambari-web/app/controllers/global/update_controller.js
+++ b/ambari-web/app/controllers/global/update_controller.js
@@ -129,6 +129,7 @@ App.UpdateController = Em.Controller.extend({
       App.updater.run(this, 'graphsUpdate', 'isWorking');
       App.updater.run(this, 'updateComponentConfig', 'isWorking');
       App.updater.run(this, 'updateAlertDefinitions', 'isWorking', 
App.alertDefinitionsUpdateInterval);
+      App.updater.run(this, 'updateAlertDefinitionSummary', 'isWorking', 
App.alertDefinitionsUpdateInterval);
     }
   }.observes('isWorking'),
   /**
@@ -453,5 +454,16 @@ App.UpdateController = Em.Controller.extend({
     App.HttpClient.get(url, App.alertDefinitionsMapper, {
       complete: callback
     });
+  },
+
+  updateAlertDefinitionSummary: function(callback) {
+    var testUrl = '/data/alerts/alert_summary.json';
+    var realUrl = '/alerts?format=groupedSummary';
+    var url = this.getUrl(testUrl, realUrl);
+
+    App.HttpClient.get(url, App.alertDefinitionSummaryMapper, {
+      complete: callback
+    });
   }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/controllers/main/alert_definitions_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/alert_definitions_controller.js 
b/ambari-web/app/controllers/main/alert_definitions_controller.js
index 94ce3df..64163f4 100644
--- a/ambari-web/app/controllers/main/alert_definitions_controller.js
+++ b/ambari-web/app/controllers/main/alert_definitions_controller.js
@@ -50,57 +50,6 @@ App.MainAlertDefinitionsController = 
Em.ArrayController.extend({
       App.ScriptAlertDefinition.find().toArray());
   }.property('mapperTimestamp'),
 
-  /**
-   * Object for lastTriggered-filter
-   * @type {Em.Object}
-   */
-  modifiedFilter: Em.Object.create({
-    optionValue: 'Any',
-    filterModified: function () {
-      var time = "";
-      var curTime = new Date().getTime();
-
-      switch (this.get('optionValue')) {
-        case 'Past 1 hour':
-          time = curTime - 3600000;
-          break;
-        case 'Past 1 Day':
-          time = curTime - 86400000;
-          break;
-        case 'Past 2 Days':
-          time = curTime - 172800000;
-          break;
-        case 'Past 7 Days':
-          time = curTime - 604800000;
-          break;
-        case 'Past 14 Days':
-          time = curTime - 1209600000;
-          break;
-        case 'Past 30 Days':
-          time = curTime - 2592000000;
-          break;
-        case 'Custom':
-        case 'Custom2':
-          customDatePopup.showCustomDatePopup(this, this.get('actualValues'));
-          break;
-        case 'Any':
-          time = "";
-          break;
-      }
-      if (this.get('modified') !== "Custom") {
-        this.set("actualValues.startTime", time);
-        this.set("actualValues.endTime", '');
-      }
-    }.observes('optionValue'),
-    cancel: function () {
-      this.set('optionValue', 'Any');
-    },
-    actualValues: Em.Object.create({
-      startTime: "",
-      endTime: ""
-    })
-  }),
-
   toggleState: Em.K
 
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/mappers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js
index 917dedf..9aec70f 100644
--- a/ambari-web/app/mappers.js
+++ b/ambari-web/app/mappers.js
@@ -35,5 +35,6 @@ require('mappers/component_config_mapper');
 require('mappers/components_state_mapper');
 require('mappers/service_config_version_mapper');
 require('mappers/alert_definitions_mapper');
+require('mappers/alert_definition_summary_mapper');
 require('mappers/alert_instances_mapper');
 require('mappers/root_service_mapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/mappers/alert_definition_summary_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/alert_definition_summary_mapper.js 
b/ambari-web/app/mappers/alert_definition_summary_mapper.js
new file mode 100644
index 0000000..8b9680d
--- /dev/null
+++ b/ambari-web/app/mappers/alert_definition_summary_mapper.js
@@ -0,0 +1,51 @@
+/**
+ * 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.alertDefinitionSummaryMapper = App.QuickDataMapper.create({
+
+  config: {},
+
+  map: function(data) {
+    if (!data.alerts_summary_grouped) return;
+    var alertDefinitions = Array.prototype.concat.call(
+      Array.prototype, App.PortAlertDefinition.find().toArray(),
+      App.MetricsAlertDefinition.find().toArray(),
+      App.WebAlertDefinition.find().toArray(),
+      App.AggregateAlertDefinition.find().toArray(),
+      App.ScriptAlertDefinition.find().toArray()
+    );
+    data.alerts_summary_grouped.forEach(function(alertDefinitionSummary) {
+      var alertDefinition = alertDefinitions.findProperty('id', 
alertDefinitionSummary.definition_id);
+      if (alertDefinition) {
+        var summary = {},
+          timestamp = 0;
+        Em.keys(alertDefinitionSummary.summary).forEach(function(status) {
+          summary[status] = alertDefinitionSummary.summary[status].count;
+          if (alertDefinitionSummary.summary[status].original_timestamp > 
timestamp) {
+            timestamp = 
alertDefinitionSummary.summary[status].original_timestamp;
+          }
+        });
+        alertDefinition.setProperties({
+          summary: summary,
+          lastTriggered: parseInt(timestamp)
+        });
+      }
+    });
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/mappers/alert_definitions_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/alert_definitions_mapper.js 
b/ambari-web/app/mappers/alert_definitions_mapper.js
index fa23cae..847cbd3 100644
--- a/ambari-web/app/mappers/alert_definitions_mapper.js
+++ b/ambari-web/app/mappers/alert_definitions_mapper.js
@@ -27,7 +27,7 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({
   metricsUriModel: App.AlertMetricsUriDefinition,
 
   config: {
-    id: 'AlertDefinition.name',
+    id: 'AlertDefinition.id',
     name: 'AlertDefinition.name',
     label: 'AlertDefinition.label',
     service_id: 'AlertDefinition.service_name',
@@ -75,6 +75,13 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({
       var alertReportDefinitions = [];
       var alertMetricsSourceDefinitions = [];
       var alertMetricsUriDefinitions = [];
+      var alertDefinitions = Array.prototype.concat.call(
+        Array.prototype, App.PortAlertDefinition.find().toArray(),
+        App.MetricsAlertDefinition.find().toArray(),
+        App.WebAlertDefinition.find().toArray(),
+        App.AggregateAlertDefinition.find().toArray(),
+        App.ScriptAlertDefinition.find().toArray()
+      );
 
       json.items.forEach(function (item) {
         var convertedReportDefinitions = [];
@@ -94,6 +101,13 @@ App.alertDefinitionsMapper = App.QuickDataMapper.create({
         item.reporting = convertedReportDefinitions;
         var alertDefinition = this.parseIt(item, this.get('config'));
 
+        var oldAlertDefinition = alertDefinitions.findProperty('id', 
alertDefinition.id);
+        if (oldAlertDefinition) {
+          // new values will be parsed in the another mapper, so for now just 
use old values
+          alertDefinition.summary = oldAlertDefinition.get('summary');
+          alertDefinition.last_triggered = 
oldAlertDefinition.get('lastTriggered');
+        }
+
         // map properties dependent on Alert Definition type
         switch (item.AlertDefinition.source.type) {
           case 'PORT':

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/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
index ea1f1c4..81e5e60 100644
--- a/ambari-web/app/models/alert_definition.js
+++ b/ambari-web/app/models/alert_definition.js
@@ -18,7 +18,6 @@
 
 var App = require('app');
 var dateUtils = require('utils/date');
-var dataUtils = require('utils/data_manipulation');
 
 App.AlertDefinition = DS.Model.extend({
 
@@ -31,34 +30,49 @@ App.AlertDefinition = DS.Model.extend({
   interval: DS.attr('number'),
   type: DS.attr('string'),
   reporting: DS.hasMany('App.AlertReportDefinition'),
-  alerts: DS.hasMany('App.AlertInstance'),
+  lastTriggered: DS.attr('number'),
+
+  /**
+   * Counts of alert grouped by their status
+   * Format:
+   * <code>
+   *   {
+   *    "CRITICAL": 1,
+   *    "OK": 1,
+   *    "UNKNOWN": 0,
+   *    "WARN": 0
+   *   }
+   * </code>
+   * @type {object}
+   */
+  summary: {},
 
   /**
    * Formatted timestamp for latest alert triggering for current 
alertDefinition
    * @type {string}
    */
-  lastTriggered: function () {
-    return dateUtils.dateFormat(Math.max.apply(Math, 
this.get('alerts').mapProperty('latestTimestamp')));
-  }.property('alerts.@each.latestTimestamp'),
+  lastTriggeredFormatted: function () {
+    return dateUtils.dateFormat(this.get('lastTriggered'));
+  }.property('lastTriggered'),
 
   /**
    * Status generates from child-alerts
-   * Format: 1 OK / 2 WARN / 1 CRIT / 1 DISABLED / 1 UNKNOWN
+   * Format: 1 OK / 2 WARN / 1 CRIT / 1 UNKNOWN
    * If some there are no alerts with some state, this state isn't shown
    * Order is equal to example
    * @type {string}
    */
   status: function () {
     var typeIcons = this.get('typeIcons'),
-        ordered = ['OK', 'WARNING', 'CRITICAL', 'DISABLED', 'UNKNOWN'],
-        grouped = dataUtils.groupPropertyValues(this.get('alerts'), 'state');
-    return ordered.map(function (state) {
-      if (grouped[state]) {
-        return grouped[state].length + ' <span class="' + typeIcons[state] + ' 
alert-state-' + state + '"></span>';
+        order = this.get('order'),
+        summary = this.get('summary');
+    return order.map(function (state) {
+      if (summary[state]) {
+        return summary[state] + ' <span class="' + typeIcons[state] + ' 
alert-state-' + state + '"></span>';
       }
       return null;
     }).compact().join(' / ');
-  }.property('alerts.@each.state'),
+  }.property('summary'),
 
   /**
    * List of css-classes for alert types
@@ -72,6 +86,8 @@ App.AlertDefinition = DS.Model.extend({
     'UNKNOWN': 'icon-question-sign'
   },
 
+  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN'],
+
   // todo: in future be mapped from server response
   description: 'Description for the Alert Definition.',
   // todo: in future be mapped from server response

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/templates/main/alerts.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/alerts.hbs 
b/ambari-web/app/templates/main/alerts.hbs
index 4ceb216..8faa8fe 100644
--- a/ambari-web/app/templates/main/alerts.hbs
+++ b/ambari-web/app/templates/main/alerts.hbs
@@ -49,7 +49,7 @@
           </td>
           <td>{{{alertDefinition.status}}}</td>
           <td>{{alertDefinition.service.serviceName}}</td>
-          <td>{{alertDefinition.lastTriggered}}</td>
+          <td>{{alertDefinition.lastTriggeredFormatted}}</td>
           <td class="last">
             <a href="#" {{action "toggleState" alertDefinition 
target="controller"}} {{bindAttr 
class="alertDefinition.enabled:enabled:disabled"}}>
               <span class="icon-off"></span>

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/views/common/filter_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/filter_view.js 
b/ambari-web/app/views/common/filter_view.js
index be5d069..3a818d8 100644
--- a/ambari-web/app/views/common/filter_view.js
+++ b/ambari-web/app/views/common/filter_view.js
@@ -593,6 +593,15 @@ module.exports = {
           return true;
         };
         break;
+      case 'alert_status':
+        /**
+         * origin - alertDefinition.summary
+         * compareValue - "OK|WARN..."
+         */
+        return function (origin, compareValue) {
+          return !!origin[compareValue] && origin[compareValue] > 0;
+        };
+        break;
       case 'string':
       default:
         return function (origin, compareValue) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/views/common/sort_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/sort_view.js 
b/ambari-web/app/views/common/sort_view.js
index 30edb5b..e66630c 100644
--- a/ambari-web/app/views/common/sort_view.js
+++ b/ambari-web/app/views/common/sort_view.js
@@ -168,6 +168,28 @@ var wrapperView = Em.View.extend({
           }
         };
         break;
+      case 'alert_status':
+        func = function(a, b) {
+          var a_summary = a.get('summary'),
+            b_summary = b.get('summary'),
+            st_order = a.get('order'),
+            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]],
+              b_v = Em.isNone(b_summary[st_order[i]]) ? 0 : 
b_summary[st_order[i]];
+            ret = b_v - a_v;
+            if (ret !== 0) {
+              break;
+            }
+          }
+          if (order) {
+            return ret;
+          }
+          else {
+            return -ret;
+          }
+        };
+        break;
       default:
         func = function (a, b) {
           if (order) {
@@ -183,7 +205,7 @@ var wrapperView = Em.View.extend({
               return 1;
             return 0;
           }
-        }
+        };
     }
     return func;
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/app/views/main/alert_definitions_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/alert_definitions_view.js 
b/ambari-web/app/views/main/alert_definitions_view.js
index b8e8ef4..6e9c276 100644
--- a/ambari-web/app/views/main/alert_definitions_view.js
+++ b/ambari-web/app/views/main/alert_definitions_view.js
@@ -36,7 +36,7 @@ App.MainAlertDefinitionsView = App.TableView.extend({
     return this.get('content.length');
   }.property('content.length'),
 
-  colPropAssoc: ['', 'label', 'state', 'service.serviceName', 'lastTriggered'],
+  colPropAssoc: ['', 'label', 'summary', 'service.serviceName', 
'lastTriggered'],
 
   sortView: sort.wrapperView,
 
@@ -56,9 +56,9 @@ App.MainAlertDefinitionsView = App.TableView.extend({
    */
   statusSort: sort.fieldView.extend({
     column: 2,
-    name: 'status',
+    name: 'summary',
     displayName: Em.I18n.t('common.status'),
-    type: 'string'
+    type: 'alert_status'
   }),
 
   /**
@@ -78,9 +78,9 @@ App.MainAlertDefinitionsView = App.TableView.extend({
    */
   lastTriggeredSort: sort.fieldView.extend({
     column: 4,
-    name: 'memory',
+    name: 'lastTriggered',
     displayName: Em.I18n.t('alerts.table.header.lastTriggered'),
-    type: 'date'
+    type: 'number'
   }),
 
   /**
@@ -129,7 +129,7 @@ App.MainAlertDefinitionsView = App.TableView.extend({
       }
     ],
     onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), 
this.get('value'), 'select');
+      this.get('parentView').updateFilter(this.get('column'), 
this.get('value'), 'alert_status');
     }
   }),
 
@@ -164,12 +164,6 @@ App.MainAlertDefinitionsView = App.TableView.extend({
    */
   triggeredFilterView: filters.createSelectView({
     column: 4,
-    triggeredOnSameValue: [
-      {
-        values: ['Custom', 'Custom2'],
-        displayAs: 'Custom'
-      }
-    ],
     appliedEmptyValue: ["", ""],
     fieldType: 'filter-input-width,modified-filter',
     content: [
@@ -200,23 +194,12 @@ App.MainAlertDefinitionsView = App.TableView.extend({
       {
         value: 'Past 30 Days',
         label: 'Past 30 Days'
-      },
-      {
-        value: 'Custom',
-        label: 'Custom'
-      },
-      {
-        value: 'Custom2',
-        label: 'Custom2'
       }
     ],
     emptyValue: 'Any',
-    valueBinding: "controller.modifiedFilter.optionValue",
-    startTimeBinding: "controller.modifiedFilter.actualValues.startTime",
-    endTimeBinding: "controller.modifiedFilter.actualValues.endTime",
-    onTimeChange: function () {
-      this.get('parentView').updateFilter(this.get('column'), 
[this.get('controller.modifiedFilter.actualValues.startTime'), 
this.get('controller.modifiedFilter.actualValues.endTime')], 'range');
-    }.observes('controller.modifiedFilter.actualValues.startTime', 
'controller.modifiedFilter.actualValues.endTime')
+    onChangeValue: function () {
+      this.get('parentView').updateFilter(this.get('column'), 
this.get('value'), 'date');
+    }
   }),
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/test/controllers/global/update_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/global/update_controller_test.js 
b/ambari-web/test/controllers/global/update_controller_test.js
index 960a83f..7b8c3a3 100644
--- a/ambari-web/test/controllers/global/update_controller_test.js
+++ b/ambari-web/test/controllers/global/update_controller_test.js
@@ -62,7 +62,7 @@ describe('App.UpdateController', function () {
 
     it('isWorking = true', function () {
       controller.set('isWorking', true);
-      expect(App.updater.run.callCount).to.equal(7);
+      expect(App.updater.run.callCount).to.equal(8);
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/test/mappers/alert_definition_summary_mapper_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mappers/alert_definition_summary_mapper_test.js 
b/ambari-web/test/mappers/alert_definition_summary_mapper_test.js
new file mode 100644
index 0000000..36e8d2d
--- /dev/null
+++ b/ambari-web/test/mappers/alert_definition_summary_mapper_test.js
@@ -0,0 +1,125 @@
+/**
+ * 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('mappers/alert_definition_summary_mapper');
+
+describe('App.alertDefinitionSummaryMapper', function () {
+
+  describe('#map', function() {
+
+    var testModels = [
+        App.PortAlertDefinition.createRecord({id: 1, type: 'PORT'}),
+        App.MetricsAlertDefinition.createRecord({id: 2, type: 'METRICS'}),
+        App.WebAlertDefinition.createRecord({id: 3, type: 'WEB'}),
+        App.AggregateAlertDefinition.createRecord({id: 4, type: 'AGGREGATE'}),
+        App.ScriptAlertDefinition.createRecord({id: 5, type: 'SCRIPT'})
+      ],
+      dataToMap = {
+        alerts_summary_grouped: [
+          {
+            definition_id: 1,
+            summary: {
+              OK: {count: 1, original_timestamp: 1},
+              WARNING: {count: 1, original_timestamp: 2},
+              CRITICAL: {count: 0, original_timestamp: 0},
+              UNKNOWN: {count: 0, original_timestamp: 0}
+            }
+          },
+          {
+            definition_id: 2,
+            summary: {
+              OK: {count: 1, original_timestamp: 1},
+              WARNING: {count: 5, original_timestamp: 2},
+              CRITICAL: {count: 1, original_timestamp: 1},
+              UNKNOWN: {count: 1, original_timestamp: 3}
+            }
+          },
+          {
+            definition_id: 3,
+            summary: {
+              OK: {count: 1, original_timestamp: 1},
+              WARNING: {count: 2, original_timestamp: 2},
+              CRITICAL: {count: 3, original_timestamp: 4},
+              UNKNOWN: {count: 4, original_timestamp: 3}
+            }
+          },
+          {
+            definition_id: 4,
+            summary: {
+              OK: {count: 4, original_timestamp: 1},
+              WARNING: {count: 3, original_timestamp: 2},
+              CRITICAL: {count: 2, original_timestamp: 1},
+              UNKNOWN: {count: 1, original_timestamp: 2}
+            }
+          },
+          {
+            definition_id: 5,
+            summary: {
+              OK: {count: 1, original_timestamp: 1},
+              WARNING: {count: 1, original_timestamp: 2},
+              CRITICAL: {count: 1, original_timestamp: 3},
+              UNKNOWN: {count: 1, original_timestamp: 4}
+            }
+          }
+        ]
+      };
+
+    beforeEach(function() {
+
+      sinon.stub(App.PortAlertDefinition, 'find', function() {return 
testModels.filterProperty('type', 'PORT');});
+      sinon.stub(App.MetricsAlertDefinition, 'find', function() {return 
testModels.filterProperty('type', 'METRICS');});
+      sinon.stub(App.WebAlertDefinition, 'find', function() {return 
testModels.filterProperty('type', 'WEB');});
+      sinon.stub(App.AggregateAlertDefinition, 'find', function() {return 
testModels.filterProperty('type', 'AGGREGATE');});
+      sinon.stub(App.ScriptAlertDefinition, 'find', function() {return 
testModels.filterProperty('type', 'SCRIPT');});
+
+    });
+
+    afterEach(function() {
+
+      App.PortAlertDefinition.find.restore();
+      App.MetricsAlertDefinition.find.restore();
+      App.WebAlertDefinition.find.restore();
+      App.AggregateAlertDefinition.find.restore();
+      App.ScriptAlertDefinition.find.restore();
+
+    });
+
+    it('should map summary info for each alert', function() {
+
+      App.alertDefinitionSummaryMapper.map(dataToMap);
+      expect(App.PortAlertDefinition.find().findProperty('id', 
1).get('lastTriggered')).to.equal(2);
+      expect(App.PortAlertDefinition.find().findProperty('id', 
1).get('summary')).to.eql({OK: 1, WARNING: 1, CRITICAL: 0, UNKNOWN: 0});
+
+      expect(App.MetricsAlertDefinition.find().findProperty('id', 
2).get('lastTriggered')).to.equal(3);
+      expect(App.MetricsAlertDefinition.find().findProperty('id', 
2).get('summary')).to.eql({OK: 1, WARNING: 5, CRITICAL: 1, UNKNOWN: 1});
+
+      expect(App.WebAlertDefinition.find().findProperty('id', 
3).get('lastTriggered')).to.equal(4);
+      expect(App.WebAlertDefinition.find().findProperty('id', 
3).get('summary')).to.eql({OK: 1, WARNING: 2, CRITICAL: 3, UNKNOWN: 4});
+
+      expect(App.AggregateAlertDefinition.find().findProperty('id', 
4).get('lastTriggered')).to.equal(2);
+      expect(App.AggregateAlertDefinition.find().findProperty('id', 
4).get('summary')).to.eql({OK: 4, WARNING: 3, CRITICAL: 2, UNKNOWN: 1});
+
+      expect(App.ScriptAlertDefinition.find().findProperty('id', 
5).get('lastTriggered')).to.equal(4);
+      expect(App.ScriptAlertDefinition.find().findProperty('id', 
5).get('summary')).to.eql({OK: 1, WARNING: 1, CRITICAL: 1, UNKNOWN: 1});
+
+    });
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/test/models/alert_definition_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/models/alert_definition_test.js 
b/ambari-web/test/models/alert_definition_test.js
new file mode 100644
index 0000000..04a9c8e
--- /dev/null
+++ b/ambari-web/test/models/alert_definition_test.js
@@ -0,0 +1,60 @@
+/**
+ * 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_definition');
+
+var model;
+
+describe('App.AlertDefinition', function() {
+
+  beforeEach(function() {
+
+    model = App.AlertDefinition.createRecord();
+
+  });
+
+  describe('#status', function() {
+
+    Em.A([
+      {
+        summary: {OK: 1, UNKNOWN: 1, WARNING: 2},
+        m: 'No CRITICAL',
+        e: '1 <span class="icon-ok-sign alert-state-OK"></span> / ' +
+          '2 <span class="icon-warning-sign alert-state-WARNING"></span> / ' +
+          '1 <span class="icon-question-sign alert-state-UNKNOWN"></span>'
+      },
+      {
+        summary: {WARNING: 2, CRITICAL: 3, UNKNOWN: 1, OK: 1},
+        m: 'All states exists',
+        e: '1 <span class="icon-ok-sign alert-state-OK"></span> / ' +
+          '2 <span class="icon-warning-sign alert-state-WARNING"></span> / ' +
+          '3 <span class="icon-remove alert-state-CRITICAL"></span> / ' +
+          '1 <span class="icon-question-sign alert-state-UNKNOWN"></span>'
+      }
+    ]).forEach(function(test) {
+        it(test.m, function() {
+          model.set('summary', test.summary);
+          expect(model.get('status')).to.equal(test.e);
+        });
+      });
+
+  });
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/test/views/common/filter_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/filter_view_test.js 
b/ambari-web/test/views/common/filter_view_test.js
index aa077bb..48ad66f 100644
--- a/ambari-web/test/views/common/filter_view_test.js
+++ b/ambari-web/test/views/common/filter_view_test.js
@@ -22,7 +22,6 @@ require('utils/helper');
 
 describe('filters.getFilterByType', function () {
 
-
   describe('ambari-bandwidth', function () {
 
     var filter = filters.getFilterByType('ambari-bandwidth');
@@ -465,4 +464,33 @@ describe('filters.getFilterByType', function () {
       })
     });
   });
+
+  describe('alert_status', function () {
+
+    var filter = filters.getFilterByType('alert_status');
+
+    Em.A([
+      {
+        origin: {OK: 1},
+        compareValue: 'OK',
+        e: true
+      },
+      {
+        origin: {WARN: 1},
+        compareValue: 'OK',
+        e: false
+      },
+      {
+        origin: {WARN: 0},
+        compareValue: 'WARN',
+        e: false
+      }
+    ]).forEach(function(test, i) {
+        it('test #' + (i + 1), function() {
+          expect(filter(test.origin, test.compareValue)).to.equal(test.e);
+        });
+      });
+
+  });
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/93b6119c/ambari-web/test/views/common/sort_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/sort_view_test.js 
b/ambari-web/test/views/common/sort_view_test.js
new file mode 100644
index 0000000..f7d5f27
--- /dev/null
+++ b/ambari-web/test/views/common/sort_view_test.js
@@ -0,0 +1,68 @@
+/**
+ * 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 sort = require('views/common/sort_view');
+require('utils/misc');
+require('utils/string_utils');
+
+describe('#wrapperView', function () {
+
+  describe('#getSortFunc', function () {
+
+    describe('alert_status', function () {
+
+      var property = Em.Object.create({type: 'alert_status'});
+
+      Em.A([
+        {
+          a: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 1}}),
+          b: App.AlertDefinition.createRecord({summary: {WARNING: 1}}),
+          order: true,
+          e: -1
+        },
+        {
+          a: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 2}}),
+          b: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 1}}),
+          order: true,
+          e: -1
+        },
+        {
+          a: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 1}}),
+          b: App.AlertDefinition.createRecord({summary: {WARNING: 1}}),
+          order: false,
+          e: 1
+        },
+        {
+          a: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 2}}),
+          b: App.AlertDefinition.createRecord({summary: {OK: 1, WARNING: 1}}),
+          order: false,
+          e: 1
+        }
+      ]).forEach(function(test, i) {
+          it('test #' + (i + 1), function () {
+            var func = sort.wrapperView.create().getSortFunc(property, 
test.order);
+            expect(func(test.a, test.b)).to.equal(test.e);
+          });
+        });
+
+    });
+
+  });
+
+});

Reply via email to