You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by xi...@apache.org on 2017/02/22 01:15:33 UTC

[06/14] ambari git commit: AMBARI-19974. Test and fix new Notifications/Alerts styles on Ambari.(xiwang)

AMBARI-19974. Test and fix new Notifications/Alerts styles on Ambari.(xiwang)


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

Branch: refs/heads/trunk
Commit: d8af6aba46fe3c62b9b5a4d42b2f716b649c20bd
Parents: c7164d8
Author: Xi Wang <xi...@apache.org>
Authored: Fri Feb 10 14:13:13 2017 -0800
Committer: Xi Wang <xi...@apache.org>
Committed: Wed Feb 15 10:39:41 2017 -0800

----------------------------------------------------------------------
 .../main/alert_definitions_controller.js        |  14 +-
 .../main/alerts/alert_instances_controller.js   | 151 ---------------
 ambari-web/app/messages.js                      |   5 +
 .../app/styles/theme/bootstrap-ambari.css       | 152 +++++++++++++++
 ambari-web/app/styles/top-nav.less              |  20 +-
 ambari-web/app/templates/application.hbs        |  57 +++---
 .../main/alerts/alert_notifications_popup.hbs   |  69 +++++++
 ambari-web/app/views.js                         |   1 +
 .../main/alerts/alert_instances_popup_view.js   | 190 +++++++++++++++++++
 .../alerts/alert_instances_controller_test.js   |  33 ----
 10 files changed, 480 insertions(+), 212 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/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 0cfff21..5488fbb 100644
--- a/ambari-web/app/controllers/main/alert_definitions_controller.js
+++ b/ambari-web/app/controllers/main/alert_definitions_controller.js
@@ -119,7 +119,7 @@ App.MainAlertDefinitionsController = Em.ArrayController.extend({
   },
 
   /**
-   *  ========================== alerts popup dialog =========================
+   *  ========================== alerts notifications dropdown dialog =========================
    */
 
   /**
@@ -128,8 +128,18 @@ App.MainAlertDefinitionsController = Em.ArrayController.extend({
    * @type {Number}
    */
   unhealthyAlertInstancesCount: function () {
+    return this.get('criticalAlertInstancesCount') + this.get('warningAlertInstancesCount');
+  }.property('criticalAlertInstancesCount', 'warningAlertInstancesCount'),
+
+  criticalAlertInstancesCount: function () {
+    return this.get('content').map(function (alertDefinition) {
+      return alertDefinition.getWithDefault('summary.CRITICAL.count', 0);
+    }).reduce(Em.sum, 0);
+  }.property('content.@each.summary'),
+
+  warningAlertInstancesCount: function () {
     return this.get('content').map(function (alertDefinition) {
-      return alertDefinition.getWithDefault('summary.CRITICAL.count', 0) + alertDefinition.getWithDefault('summary.WARNING.count', 0);
+      return alertDefinition.getWithDefault('summary.WARNING.count', 0);
     }).reduce(Em.sum, 0);
   }.property('content.@each.summary'),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/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 cbeb71a..30eb999 100644
--- a/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
+++ b/ambari-web/app/controllers/main/alerts/alert_instances_controller.js
@@ -193,157 +193,6 @@ App.MainAlertInstancesController = Em.Controller.extend({
    */
   getAlertInstancesErrorCallback: function () {
     this.set('isLoaded', true);
-  },
-
-  /**
-   * Onclick handler for alerts number located right to bg ops number (see application.hbs)
-   * @method showPopup
-   * @return {App.ModalPopup}
-   */
-  showPopup: function () {
-
-    var self = this;
-
-    return App.ModalPopup.show({
-
-      alertsNumberBinding: 'App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount',
-
-      header: Em.computed.i18nFormat('alerts.fastAccess.popup.header', 'alertsNumber'),
-
-      classNames: ['common-modal-wrapper', 'alerts-popup'],
-      modalDialogClasses: ['modal-lg'],
-
-      secondary: Em.I18n.t('alerts.fastAccess.popup.body.showmore'),
-
-      autoHeight: false,
-
-      isHideBodyScroll: true,
-
-      onSecondary: function () {
-        this._super();
-        App.router.transitionTo('main.alerts.index');
-      },
-
-      bodyClass: App.TableView.extend(App.TableServerViewMixin, {
-
-        updaterBinding: 'App.router.updateController',
-
-        templateName: require('templates/common/modal_popups/alerts_popup'),
-
-        controller: self,
-
-        isPaginate: true,
-
-        willInsertElement: function () {
-          this._super();
-          this.updateAlertInstances();
-        },
-
-        /**
-         * Number of all critical and warning alert instances
-         * @type {Boolean}
-         */
-        filteredCount: Em.computed.alias('App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount'),
-
-        content: function () {
-          return this.get('controller.unhealthyAlertInstances');
-        }.property('controller.unhealthyAlertInstances.@each.state'),
-
-        isLoaded: Em.computed.bool('controller.unhealthyAlertInstances'),
-
-        isAlertEmptyList: Em.computed.empty('content'),
-
-        /**
-         * Update list of shown alert instances
-         * @method updateAlertInstances
-         */
-        updateAlertInstances: function () {
-          var self = this,
-            displayLength = this.get('displayLength'),
-            startIndex = this.get('startIndex');
-          if (!displayLength) return; // wait while table-info is loaded
-          this.get('updater').set('queryParamsForUnhealthyAlertInstances', {
-            from: startIndex - 1,
-            page_size: displayLength
-          });
-          this.set('filteringComplete', false);
-          this.get('updater').updateUnhealthyAlertInstances(function() {
-            self.set('filteringComplete', true);
-          });
-        }.observes('displayLength', 'startIndex'),
-
-        /**
-         * Show spinner when filter/sorting request is in processing
-         * @method overlayObserver
-         */
-        overlayObserver: function() {
-          var $tbody = this.$('#alert-info'),
-            $overlay = this.$('.table-overlay'),
-            $spinner = $($overlay).find('.spinner');
-          if (!this.get('filteringComplete')) {
-            if (!$tbody) return;
-            var tbodyPos =  $tbody.position();
-            if (!tbodyPos) return;
-            $spinner.css('display', 'block');
-            $overlay.css({
-              top: tbodyPos.top + 1,
-              left: tbodyPos.left + 1,
-              width: $tbody.width() - 1,
-              height: $tbody.height() - 1
-            });
-          }
-        },
-
-        /**
-         * No filtering for alert definitions
-         * @method filter
-         */
-        filter: function() {
-          this.set('filteredContent', this.get('content'));
-        }.observes('content.length'),
-
-        /**
-         * Router transition to alert definition details page
-         * @param event
-         */
-        gotoAlertDetails: function (event) {
-          if (event && event.context) {
-            this.get('parentView').hide();
-            var definition = App.AlertDefinition.find().findProperty('id', event.context.get('definitionId'));
-            App.router.transitionTo('main.alerts.alertDetails', definition);
-          }
-        },
-
-        /**
-         * Router transition to service summary page
-         * @param event
-         */
-        goToService: function (event) {
-          if (event && event.context) {
-            this.get('parentView').hide();
-            App.router.transitionTo('main.services.service.summary', event.context);
-          }
-        },
-
-        /**
-         * Router transition to host level alerts page
-         * @param event
-         */
-        goToHostAlerts: function (event) {
-          if (event && event.context) {
-            this.get('parentView').hide();
-            App.router.transitionTo('main.hosts.hostDetails.alerts', event.context);
-          }
-        },
-
-        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/d8af6aba/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index cb88fda..6e58823 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1085,6 +1085,11 @@ Em.I18n.translations = {
   'form.validator.alertNotificationName':'Invalid Alert Notification Name. Only alphanumerics, hyphens, spaces and underscores are allowed.',
   'form.validator.configKey.specific':'"{0}" is invalid Key. Only alphanumerics, hyphens, underscores, asterisks and periods are allowed.',
 
+  'alerts.dropdown.dialog.title': 'Notifications',
+  'alerts.dropdown.dialog.filters.critical': 'Critical ({0})',
+  'alerts.dropdown.dialog.filters.warning': 'Warning ({0})',
+  'alerts.dropdown.dialog.filters.all': 'All ({0})',
+
   'alerts.add.header': 'Create Alert',
   'alerts.add.step1.header': 'Choose Alert Type',
   'alerts.add.step1.header.description': 'Select the type of alert you want to create',

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/styles/theme/bootstrap-ambari.css
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/theme/bootstrap-ambari.css b/ambari-web/app/styles/theme/bootstrap-ambari.css
index d17e423..36a63a3 100644
--- a/ambari-web/app/styles/theme/bootstrap-ambari.css
+++ b/ambari-web/app/styles/theme/bootstrap-ambari.css
@@ -1037,6 +1037,7 @@ input.radio:checked + label:after {
 .navigation-bar-container.collapsed ul.nav.side-nav-footer li.submenu-li.active > a {
   padding-left: 19px;
 }
+
 .navigation-bar-fit-height {
   position: fixed;
   top: 0;
@@ -1059,6 +1060,157 @@ input.radio:checked + label:after {
 .navigation-bar-fit-height .navigation-bar-container:not(.collapsed) .side-nav-menu {
   overflow-y: auto;
 }
+
+.notifications-group {
+  position: relative;
+  top: 1px;
+}
+#notifications-dropdown.dropdown-menu {
+  min-width: 300px;
+  max-width: 300px;
+  min-height: 150px;
+  padding: 0px;
+  z-index: 1000;
+  right: -50px;
+  left: auto;
+  top: 260%;
+  border: none;
+  -webkit-box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+  -moz-box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+  box-shadow: 0px 2px 10px 2px rgba(0, 0, 0, 0.29);
+}
+#notifications-dropdown.dropdown-menu .popup-arrow-up {
+  position: absolute;
+  right: 37px;
+  top: -40px;
+  width: 40px;
+  height: 40px;
+  overflow: hidden;
+}
+#notifications-dropdown.dropdown-menu .popup-arrow-up:after {
+  content: "";
+  position: absolute;
+  width: 20px;
+  height: 20px;
+  background: #fff;
+  transform: rotate(45deg);
+  top: 30px;
+  left: 10px;
+  box-shadow: -1px -1px 10px -2px rgba(0, 0, 0, 0.5);
+}
+#notifications-dropdown.dropdown-menu .notifications-header {
+  border-bottom: 1px solid #eee;
+  padding: 15px 20px;
+}
+#notifications-dropdown.dropdown-menu .notifications-header .notifications-title {
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 16px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body {
+  padding: 0px 15px;
+  overflow: auto;
+  max-height: 500px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .no-alert-text {
+  padding: 15px 5px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls {
+  padding: 10px 0px;
+  margin: 0px;
+  border-bottom: 1px solid #eee;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls .state-filter {
+  padding: 0px;
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  font-size: 12px;
+  color: #666;
+  position: relative;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table-controls .state-filter .form-control.filter-select {
+  font-size: 12px;
+  color: #666;
+  height: 25px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table {
+  margin-top: 0px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr {
+  cursor: pointer;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr.no-alert-tr:hover {
+  cursor: default;
+  border-color: transparent;
+  border-bottom-color: #eee;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody tr.no-alert-tr:hover > td {
+  border-color: transparent;
+  background-color: white;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status {
+  width: 9%;
+  padding: 15px 3px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status .alert-state-CRITICAL {
+  color: #EF6162;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.status .alert-state-WARNING {
+  color: #E98A41;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content {
+  width: 90%;
+  padding: 15px 3px 10px 3px;
+  font-family: 'Roboto', sans-serif;
+  font-weight: normal;
+  font-style: normal;
+  line-height: 1;
+  color: #333;
+  line-height: 1.3;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .name {
+  font-weight: bold;
+  font-size: 12px;
+  color: #666;
+  margin-bottom: 5px;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .description {
+  font-size: 12px;
+  color: #666;
+  margin-bottom: 4px;
+  display: block;
+  display: -webkit-box;
+  -webkit-line-clamp: 3;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  /* Break long urls*/
+  overflow-wrap: break-word;
+  word-wrap: break-word;
+  -ms-word-break: break-all;
+  word-break: break-all;
+  word-break: break-word;
+  /* Adds a hyphen where the word breaks*/
+  -ms-hyphens: auto;
+  -moz-hyphens: auto;
+  -webkit-hyphens: auto;
+  hyphens: auto;
+}
+#notifications-dropdown.dropdown-menu .notifications-body .table.alerts-table tbody td.content .timestamp {
+  text-align: right;
+  font-size: 11px;
+  color: #999;
+}
+#notifications-dropdown.dropdown-menu .notifications-footer {
+  border-top: 1px solid #eee;
+  padding: 15px;
+}
 h1,
 h2,
 h3,

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/styles/top-nav.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/top-nav.less b/ambari-web/app/styles/top-nav.less
index d1c723a..78c804f 100644
--- a/ambari-web/app/styles/top-nav.less
+++ b/ambari-web/app/styles/top-nav.less
@@ -38,7 +38,13 @@
       }
     }
 
+    .cluster-notifications {
+      margin-top: 12px;
+    }
     .navbar-text.brand-wrapper {
+      margin-top: 17px;
+    }
+    .navbar-text.brand-wrapper, .cluster-notifications {
       color: @top-nav-brand-color;
       font-size: 16px;
       font-weight: normal;
@@ -51,6 +57,11 @@
         position: relative;
       }
 
+      span.alerts-label {
+        line-height: 20px;
+        cursor: pointer;
+      }
+
       .numberCircle {
         border-radius: 50%;
         width: 20px;
@@ -94,9 +105,14 @@
     a:hover {
       text-decoration: none;
     }
+    .top-nav-user {
+      margin-top: 2px;
+    }
   }
 
-  .top-nav-user {
-    margin-top: 2px;
+  #notifications-dropdown.dropdown-menu {
+    .popup-arrow-up {
+      right: 75px;
+    }
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs b/ambari-web/app/templates/application.hbs
index 25c3311..94d8337 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -127,16 +127,8 @@
         {{/if}}
         {{! user dropdown end }}
 
-        <div class="navbar-nav navbar-text navbar-right brand-wrapper">
+        <div class="navbar-nav navbar-right cluster-notifications">
           {{#if enableLinks}}
-
-            {{! cluster name }}
-            <a href="#" {{bindAttr title="clusterName"}} {{action "showPopup" target="App.router.backgroundOperationsController"}} class="cluster-name">
-              {{#unless App.isClusterUser}}
-                <span>{{clusterDisplayName}}</span>
-              {{/unless}}
-            </a>
-            {{! cluster name end }}
             {{! bg label }}
             <a href="#" class="bg-label" {{action "showPopup" target="App.router.backgroundOperationsController"}}>
               {{#with App.router.backgroundOperationsController}}
@@ -147,27 +139,44 @@
               {{/with}}
             </a>
             {{! bg label end }}
-            {{! alerts label }}
+
+            {{! new alerts label }}
             {{#if App.router.clusterController.isAlertsLoaded}}
-              <a href="#" class="alerts-label" {{action "showPopup" target="App.router.mainAlertInstancesController"}}>
-                {{#if App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
+              <span class="notifications-group">
+                <span class="alerts-label dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                   <span class="glyphicon glyphicon-bell"></span>
-                {{! alerts exist }}
-                  <span {{bindAttr class=":numberCircle App.router.mainAlertDefinitionsController.isCriticalAlerts:alert-crit-count:alert-warn-count"}}>
-                    {{App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
-                  </span>
-                {{else}}
-                {{! no alerts }}
-                  <span {{translateAttr title="titlebar.alerts.noAlerts"}} class="numberCircle alerts-none-count">
-                    {{App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
-                  </span>
-                {{/if}}
-              </a>
+                  {{#if App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
+                    {{! alerts exist }}
+                    <span {{bindAttr class=":numberCircle App.router.mainAlertDefinitionsController.isCriticalAlerts:alert-crit-count:alert-warn-count"}}>
+                      {{App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
+                    </span>
+                  {{else}}
+                  {{! no alerts }}
+                    <span {{translateAttr title="titlebar.alerts.noAlerts"}} class="numberCircle alerts-none-count">
+                      {{App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount}}
+                    </span>
+                  {{/if}}
+                </span>
+                <div id="notifications-dropdown" class="dropdown-menu row">
+                  {{view App.AlertInstancesPopupView}}
+                </div>
+              </span>
             {{/if}}
-          {{! alerts label end }}
+            {{! alerts label end }}
           {{/if}}
         </div>
 
+        <div class="navbar-nav navbar-text navbar-right brand-wrapper">
+          {{#if enableLinks}}
+            {{! cluster name }}
+            <a href="#" {{bindAttr title="clusterName"}} {{action "showPopup" target="App.router.backgroundOperationsController"}} class="cluster-name">
+              {{#unless App.isClusterUser}}
+                <span>{{clusterDisplayName}}</span>
+              {{/unless}}
+            </a>
+            {{! cluster name end }}
+          {{/if}}
+        </div>
       </div>
     </nav>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/templates/main/alerts/alert_notifications_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/alerts/alert_notifications_popup.hbs b/ambari-web/app/templates/main/alerts/alert_notifications_popup.hbs
new file mode 100644
index 0000000..a5f2bf2
--- /dev/null
+++ b/ambari-web/app/templates/main/alerts/alert_notifications_popup.hbs
@@ -0,0 +1,69 @@
+{{!
+* 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.
+}}
+
+<div class="popup-arrow-up"></div>
+<div class="notifications-header col-sm-12">
+  <div class="notifications-title">{{t alerts.dropdown.dialog.title}} ({{view.alertsNumber}})</div>
+</div>
+
+<div class="notifications-body col-sm-12">
+  {{#if view.isLoaded}}
+    <div class="table-controls row">
+      <div class="state-filter pull-right">
+        <span>{{t common.show}}:&nbsp;</span>
+        <div class="btn-group">
+          {{view Ember.Select
+          contentBinding="view.categories"
+          optionValuePath="content.value"
+          optionLabelPath="content.label"
+          selectionBinding="view.selectedCategory"
+          classNames="filter-select form-control"
+          }}
+        </div>
+      </div>
+    </div>
+    <table class="alerts-table table table-hover">
+      <tbody>
+        {{#if view.isAlertEmptyList}}
+          <tr class="no-alert-tr">
+            <td class="no-alert-text">{{t alerts.fastAccess.popup.body.noalerts}}</td>
+          </tr>
+        {{else}}
+          {{#each instance in view.pageContent}}
+            <tr {{action "gotoAlertDetails" instance target="view"}} {{bindAttr class="instance.isVisible::hidden"}}>
+              <td class="status">
+                <span {{bindAttr class="instance.stateClass :icon-circle"}}></span>
+              </td>
+              <td class="content">
+                <div class="name">{{instance.label}}</div>
+                <div class="description">{{instance.text}}</div>
+                <div class="timestamp">{{instance.lastTriggeredAgoFormatted}}</div>
+              </td>
+            </tr>
+          {{/each}}
+        {{/if}}
+      </tbody>
+    </table>
+  {{else}}
+    {{view App.SpinnerView}}
+  {{/if}}
+</div>
+
+<div class="notifications-footer col-sm-12">
+  <button type="button" class="btn btn-primary pull-right" {{action "gotoAllAlerts" target="view"}}>View All</button>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 77b5d5a..1a2a887 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -129,6 +129,7 @@ require('views/main/alerts/add_alert_definition/step2_view');
 require('views/main/alerts/add_alert_definition/step3_view');
 require('views/main/alerts');
 require('views/main/alerts/manage_alert_groups_view');
+require('views/main/alerts/alert_instances_popup_view');
 require('views/main/alerts/manage_alert_notifications_view');
 require('views/main/charts');
 require('views/main/views/details');

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/app/views/main/alerts/alert_instances_popup_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/alerts/alert_instances_popup_view.js b/ambari-web/app/views/main/alerts/alert_instances_popup_view.js
new file mode 100644
index 0000000..6524f30
--- /dev/null
+++ b/ambari-web/app/views/main/alerts/alert_instances_popup_view.js
@@ -0,0 +1,190 @@
+/**
+ * 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');
+
+/**
+ * Option for "filter by state" drop down
+ * @typedef {object} categoryObject
+ * @property {string} value "all|warning|critical"
+ * @property {number} count number of items with <code>state</code> equal to <code>this.value</code>
+ * @property {string} labelPath key in the messages.js
+ * @property {string} label localized label
+ */
+var categoryObject = Em.Object.extend({
+  value: '',
+  count: 0,
+  labelPath: '',
+  label: function () {
+    return Em.I18n.t(this.get('labelPath')).format(this.get('count'));
+  }.property('count', 'labelPath')
+});
+
+App.AlertInstancesPopupView = App.TableView.extend(App.TableServerViewMixin, {
+
+  templateName: require('templates/main/alerts/alert_notifications_popup'),
+
+  updaterBinding: 'App.router.updateController',
+
+  controllerBinding: 'App.router.mainAlertInstancesController',
+
+  /**
+   * Number of all critical and warning alert instances
+   * @type {Boolean}
+   */
+  alertsNumberBinding: 'App.router.mainAlertDefinitionsController.unhealthyAlertInstancesCount',
+  criticalNumberBinding: 'App.router.mainAlertDefinitionsController.criticalAlertInstancesCount',
+  warningNumberBinding: 'App.router.mainAlertDefinitionsController.warningAlertInstancesCount',
+
+  isPaginate: false,
+
+  willInsertElement: function () {
+    this._super();
+    this.updateAlertInstances();
+  },
+
+  didInsertElement: function () {
+    this.filter();
+    this.addObserver('filteringComplete', this, this.overlayObserver);
+    this.overlayObserver();
+    $(".notifications-body .filter-select ").click(function(event){
+      event.stopPropagation();
+    });
+    return this._super();
+  },
+
+  content: function () {
+    return this.get('controller.unhealthyAlertInstances');
+  }.property('controller.unhealthyAlertInstances.@each.state'),
+
+  isLoaded: Em.computed.bool('controller.unhealthyAlertInstances'),
+
+  isAlertEmptyList: Em.computed.or('isAlertContentEmptyList', 'isAlertFilterdEmptyList'),
+  isAlertContentEmptyList: Em.computed.empty('content'),
+  isAlertFilterdEmptyList:  Em.computed.everyBy('content', 'isVisible', false),
+
+  displayLength: 100,
+
+  /**
+   * Update list of shown alert instances
+   * @method updateAlertInstances
+   */
+  updateAlertInstances: function () {
+    var self = this,
+      displayLength = this.get('displayLength'),
+      startIndex = this.get('startIndex');
+    if (!displayLength) return; // wait while table-info is loaded
+    this.get('updater').set('queryParamsForUnhealthyAlertInstances', {
+      from: startIndex - 1,
+      page_size: displayLength
+    });
+    this.set('filteringComplete', false);
+    this.get('updater').updateUnhealthyAlertInstances(function() {
+      self.set('filteringComplete', true);
+    });
+  }.observes('displayLength', 'startIndex', 'alertsNumber'),
+
+  /**
+   * Show spinner when filter/sorting request is in processing
+   * @method overlayObserver
+   */
+  overlayObserver: function() {
+    var $tbody = this.$('.table.alerts-table'),
+      $overlay = this.$('.table-overlay'),
+      $spinner = $($overlay).find('.spinner');
+    if (!this.get('filteringComplete')) {
+      if (!$tbody) return;
+      var tbodyPos =  $tbody.position();
+      if (!tbodyPos) return;
+      $spinner.css('display', 'block');
+      $overlay.css({
+        top: tbodyPos.top + 1,
+        left: tbodyPos.left + 1,
+        width: $tbody.width() - 1,
+        height: $tbody.height() - 1
+      });
+    }
+  },
+
+  categories: function () {
+    var allCnt = this.get('alertsNumber');
+    var criticalCnt = this.get('criticalNumber');
+    var warningCnt = this.get('warningNumber');
+    return [
+      categoryObject.create({
+        value: 'all',
+        labelPath: 'alerts.dropdown.dialog.filters.all',
+        count: allCnt
+      }),
+      categoryObject.create({
+        value: 'alert-state-CRITICAL',
+        labelPath: 'alerts.dropdown.dialog.filters.critical',
+        count: criticalCnt
+      }),
+      categoryObject.create({
+        value: 'alert-state-WARNING',
+        labelPath: 'alerts.dropdown.dialog.filters.warning',
+        count: warningCnt
+      })
+    ];
+  }.property('criticalNumber', 'warningNumber', 'alertsNumber'),
+
+  selectedCategory: null,
+
+  /**
+   * Filter notifications by state
+   * @method filter
+   */
+  filter: function() {
+    var selectedState = this.get('selectedCategory.value');
+    var content = this.get('content');
+    if (selectedState == 'all') {
+      content.setEach("isVisible", true);
+      this.set('filteredContent', content);
+    } else {
+      this.set('filteredContent', content.filter(function (item) {
+        if (item.get('stateClass') == selectedState) {
+          item.set('isVisible', true);
+          return true;
+        } else {
+          item.set('isVisible', false);
+          return false;
+        }
+      }));
+    }
+  }.observes('content.length', 'selectedCategory'),
+
+  /**
+   * Router transition to alert definition details page
+   * @param event
+   */
+  gotoAlertDetails: function (event) {
+    if (event && event.context) {
+      var definition = App.AlertDefinition.find().findProperty('id', event.context.get('definitionId'));
+      App.router.transitionTo('main.alerts.alertDetails', definition);
+    }
+  },
+
+  /**
+   * Router transition to alert definition page
+   */
+  gotoAllAlerts: function () {
+    App.router.transitionTo('main.alerts.index');
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/d8af6aba/ambari-web/test/controllers/main/alerts/alert_instances_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/alerts/alert_instances_controller_test.js b/ambari-web/test/controllers/main/alerts/alert_instances_controller_test.js
index 94653c7..5b53323 100644
--- a/ambari-web/test/controllers/main/alerts/alert_instances_controller_test.js
+++ b/ambari-web/test/controllers/main/alerts/alert_instances_controller_test.js
@@ -64,37 +64,4 @@ describe('App.MainAlertInstancesController', function () {
 
   });
 
-
-  describe('#showPopup', function () {
-
-    describe('#bodyClass', function () {
-
-      var bodyView;
-
-      beforeEach(function () {
-        controller.reopen({unhealthyAlertInstances: [
-          App.AlertInstance.createRecord({state: 'CRITICAL'}),
-          App.AlertInstance.createRecord({state: 'WARNING'}),
-          App.AlertInstance.createRecord({state: 'WARNING'}),
-          App.AlertInstance.createRecord({state: 'CRITICAL'})
-        ]});
-        bodyView = controller.showPopup().get('bodyClass').create();
-      });
-
-      it('#content', function () {
-        expect(bodyView.get('content.length')).to.equal(4);
-      });
-
-      it('#isLoaded', function () {
-        expect(bodyView.get('isLoaded')).to.be.true;
-      });
-
-      it('#isAlertEmptyList', function () {
-        expect(bodyView.get('isAlertEmptyList')).to.be.false;
-      });
-
-    });
-
-  });
-
 });
\ No newline at end of file