You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/10/23 15:20:55 UTC

[47/50] [abbrv] ambari git commit: AMBARI-22287 Hosts and Alerts filter table re-implementation. (atkach)

AMBARI-22287 Hosts and Alerts filter table re-implementation. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-20859
Commit: daac7df8aa9cf412bf22de82cc2fc21b9ffaa699
Parents: cf5c068
Author: Andrii Tkach <at...@apache.org>
Authored: Mon Oct 23 14:56:45 2017 +0300
Committer: Andrii Tkach <at...@apache.org>
Committed: Mon Oct 23 14:56:45 2017 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   1 +
 .../app/models/alerts/alert_definition.js       |  18 +-
 ambari-web/app/routes/main.js                   |   1 +
 ambari-web/app/styles/hosts.less                |  89 +++---
 ambari-web/app/styles/visualsearch.less         | 100 ++++++
 ambari-web/app/templates/main/alerts.hbs        |  19 +-
 .../alert_definition_summary.hbs                |   2 +-
 ambari-web/app/templates/main/host.hbs          |  26 +-
 .../templates/main/host/combo_search_box.hbs    |   9 +-
 ambari-web/app/views.js                         |   1 +
 ambari-web/app/views/common/table_view.js       |  11 +
 .../app/views/main/alert_definitions_view.js    | 264 ---------------
 .../alert_definition_summary.js                 |   2 +-
 .../app/views/main/alerts/alert_search_box.js   | 318 +++++++++++++++++++
 .../app/views/main/host/combo_search_box.js     |   8 +
 ambari-web/test/init_test.js                    |   8 +
 .../views/main/alert_definitions_view_test.js   | 152 ---------
 .../views/main/alerts/alert_search_box_test.js  | 232 ++++++++++++++
 18 files changed, 764 insertions(+), 497 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/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 7c636d4..fe0dd17 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -277,6 +277,7 @@ var files = [
   'test/views/main/alerts/manage_alert_notifications_view_test',
   'test/views/main/alerts/definition_details_view_test',
   'test/views/main/alerts/definition_configs_view_test',
+  'test/views/main/alerts/alert_search_box_test',
   'test/views/main/alerts/add_alert_definition/step1_view_test',
   'test/views/main/alerts/add_alert_definition/step3_view_test',
   'test/views/main/alerts/manage_alert_groups/select_definitions_popup_body_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/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
index 09089e6..236a40f 100644
--- a/ambari-web/app/models/alerts/alert_definition.js
+++ b/ambari-web/app/models/alerts/alert_definition.js
@@ -254,17 +254,17 @@ App.AlertDefinition = DS.Model.extend({
    * 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'
-  }
+  order: ['OK', 'WARNING', 'CRITICAL', 'UNKNOWN']
 });
 
+App.AlertDefinition.shortState = {
+  'CRITICAL': 'CRIT',
+  'WARNING': 'WARN',
+  'OK': 'OK',
+  'UNKNOWN': 'UNKWN',
+  'PENDING': 'NONE'
+};
+
 App.AlertDefinition.reopenClass({
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index d1f9012..5ba7c3d 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -375,6 +375,7 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       route: '/',
       connectOutlets: function (router, context) {
         router.get('mainController').connectOutlet('mainAlertDefinitions');
+        router.get('mainAlertDefinitionsController').connectOutlet('MainAlertDefinitionSearchBox');
       }
     }),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/styles/hosts.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/hosts.less b/ambari-web/app/styles/hosts.less
index 9a7ce24..9f0da8b 100644
--- a/ambari-web/app/styles/hosts.less
+++ b/ambari-web/app/styles/hosts.less
@@ -100,17 +100,20 @@
     }
   }
   .table {
-    input[type="checkbox"] {
-      margin: -2px 0 0 0;
+    input[type="checkbox"] + label {
+      top: 1px;
     }
     th {
       padding-left: 6px;
     }
-    .col0,.col1,
+    .col1,
+    .col0,
     td:first-child,
     th:first-child,
     td:last-child,
-    th:last-child {
+    th:last-child,
+    td:first-child + td,
+    th:first-child + th {
       padding-left: 4px!important;
       padding-right: 1px!important;
       padding-right: 10px\9!important;
@@ -121,70 +124,64 @@
       }
     }
     .col2,
-    td:first-child + td,
-    th:first-child + th{
+    td:first-child + td + td,
+    th:first-child + th + th {
       width: 20%;
       padding-right: 1px;
     }
     .col3, .col4,
-    td:first-child + td + td,
-    th:first-child + th + th,
     td:first-child + td + td + td,
-    th:first-child + th + th + th{
+    th:first-child + th + th + th,
+    td:first-child + td + td + td + td,
+    th:first-child + th + th + th + th {
       padding-left: 1px!important;
       padding-right: 1px!important;
       width: 1.5%;
       width: 13px\9!important;
     }
     .col5,
-    td:first-child + td + td + td + td,
-    th:first-child + th + th + th + th {
+    td:first-child + td + td + td + td + td,
+    th:first-child + th + th + th + th + th {
       width: 10%!important;
     }
     .col6,
-    td:first-child + td + td + td + td + td,
-    th:first-child + th + th + th + th + th {
+    td:first-child + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th {
       width: 13%!important;
     }
     .col7,
-    td:first-child + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th{
+    td:first-child + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th {
       width: 5%!important;
     }
 
     .col8,
-    td:first-child + td + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th + th{
+    td:first-child + td + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th + th {
       width: 6%!important;
     }
 
     .col9,
-    td:first-child + td + td + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th + th + th{
+    td:first-child + td + td + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th + th + th {
       width: 9%!important;
     }
 
     .col10,
-    td:first-child + td + td + td + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th + th + th + th{
+    td:first-child + td + td + td + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th + th + th + th {
       width: 9%!important;
     }
 
     .col11,
-    td:first-child + td + td + td + td + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th + th + th + th +th{
+    td:first-child + td + td + td + td + td + td + td + td + td + td + td,
+    th:first-child + th + th + th + th + th + th + th + th + th + th + th {
       width: 11%!important;
       a {
         word-wrap: break-word;
       }
     }
 
-    .col12,
-    td:first-child + td + td + td + td + td + td + td + td + td + td + td,
-    th:first-child + th + th + th + th + th + th + th + th + th + th +th{
-      width: 11%!important;
-    }
-
     td.name {
       overflow: inherit;
       overflow-wrap: break-word;
@@ -432,8 +429,8 @@
   #hosts {
     .table {
       .col2,
-      td:first-child + td,
-      th:first-child + th {
+      td:first-child + td + td,
+      th:first-child + th + th {
         width: 15% !important;
 
         .filter-input-width {
@@ -442,45 +439,45 @@
       }
 
       .col4,
-      td:first-child + td + td + td,
-      th:first-child + th + th + th {
-        width: 1.4%;
-      }
-
-      .col5,
       td:first-child + td + td + td + td,
       th:first-child + th + th + th + th {
-        width: 11.7% !important;
+        width: 1.4%;
       }
 
-      .col6,
+      .col5,
       td:first-child + td + td + td + td + td,
       th:first-child + th + th + th + th + th {
-        width: 9% !important;
+        width: 11.7% !important;
       }
 
-      .col7,
+      .col6,
       td:first-child + td + td + td + td + td + td,
       th:first-child + th + th + th + th + th + th {
         width: 9% !important;
       }
 
-      .col8,
+      .col7,
       td:first-child + td + td + td + td + td + td + td,
       th:first-child + th + th + th + th + th + th + th {
         width: 9% !important;
       }
-      .col9,
+
+      .col8,
       td:first-child + td + td + td + td + td + td + td + td,
       th:first-child + th + th + th + th + th + th + th + th {
         width: 9% !important;
       }
+      .col9,
+      td:first-child + td + td + td + td + td + td + td + td + td,
+      th:first-child + th + th + th + th + th + th + th + th + th {
+        width: 9% !important;
+      }
       .col11,
       .col12,
-      td:first-child + td + td + td + td + td + td + td + td + td + td,
-      th:first-child + th + th + th + th + th + th + th + th + th + th,
       td:first-child + td + td + td + td + td + td + td + td + td + td + td,
-      th:first-child + th + th + th + th + th + th + th + th + th + th + th {
+      th:first-child + th + th + th + th + th + th + th + th + th + th + th,
+      td:first-child + td + td + td + td + td + td + td + td + td + td + td + td,
+      th:first-child + th + th + th + th + th + th + th + th + th + th + th + th {
         width: 11.2% !important;
       }
       td.name .trim_hostname {

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/styles/visualsearch.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/visualsearch.less b/ambari-web/app/styles/visualsearch.less
new file mode 100644
index 0000000..f07d319
--- /dev/null
+++ b/ambari-web/app/styles/visualsearch.less
@@ -0,0 +1,100 @@
+/**
+ * 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.
+ */
+
+@import 'common.less';
+
+@background-color: #ddd;
+
+#combo_search_box {
+  .VS-icon-search {
+    display: none;
+  }
+  .VS-placeholder,
+  .VS-search-inner {
+    margin-left: 5px;
+  }
+  .VS-search-box {
+    background: none;
+  }
+  .VS-search {
+    .search_facet.not_selected {
+      height: 24px;
+      padding: 1px 0 0 14px;
+      background-image: none;
+      background-color: @background-color;
+      margin-top: 4px;
+      .search_facet_remove {
+        top: 5px;
+      }
+      .category,
+      .VS-interface {
+        text-transform: none;
+        color: #666;
+        font-size: 10px;
+        font-family: 'Roboto', sans-serif !important;
+      }
+    }
+  }
+}
+
+.VS-interface.ui-autocomplete {
+  max-width: 300px;
+  width: auto !important;
+  margin-top: 15px;
+  .ui-menu-item a {
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    background: none;
+    border: none;
+    padding: 3px 10px 5px 5px;
+  }
+  .ui-menu-item .ui-state-hover {
+    color: initial;
+    background: @background-color;
+    border: none;
+  }
+}
+
+.VS-open-box {
+  position: relative;
+  margin-right: 5px;
+  button {
+    padding: 10px !important;
+  }
+  .popup-arrow-up {
+    background: inherit;
+    z-index: 1;
+    left: 6px;
+    position: absolute;
+    width: 24px;
+    height: 16px;
+    overflow: hidden;
+  }
+  .popup-arrow-up:after {
+    content: "";
+    position: absolute;
+    width: 20px;
+    height: 20px;
+    background: #fff;
+    transform: rotate(45deg);
+    top: 10px;
+    left: 2px;
+    box-shadow: -2px -2px 10px -3px rgba(0, 0, 0, 0.5);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/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 0f85e27..1ce2c91 100644
--- a/ambari-web/app/templates/main/alerts.hbs
+++ b/ambari-web/app/templates/main/alerts.hbs
@@ -24,12 +24,18 @@
         {{#isAuthorized "SERVICE.TOGGLE_ALERTS"}}
           {{view App.MainAlertDefinitionActionsView controllerBinding="App.router.mainAlertDefinitionActionsController"}}
         {{/isAuthorized}}
-        {{#if App.router.clusterController.isAlertsLoaded}}
-          {{view view.alertGroupFilterView}}
-        {{/if}}
+        <div class="VS-open-box pull-right">
+          <button class="btn btn-default">
+            <i class="icon-search"></i>
+          </button>
+          <div class="popup-arrow-up hide"></div>
+        </div>
       </div>
     </div>
   </div>
+  <div class="row search-box-row hide">
+    {{outlet}}
+  </div>
   <table class="table advanced-header-table table-hover alerts-table" id="alert-definitions-table">
     <thead>
     {{#view view.sortView classNames="label-row" contentBinding="view.filteredContent"}}
@@ -39,13 +45,6 @@
       {{view view.parentView.lastTriggeredSort class="last-triggred-sorting"}}
       {{view view.parentView.enabledSort class="enabled-sorting"}}
     {{/view}}
-    <tr class="filter-row">
-      <th class="first">{{view view.stateFilterView class="status-filter"}}</th>
-      <th>{{view view.nameFilterView class="name-filter"}}</th>
-      <th>{{view view.serviceFilterView class="service-filter"}}</th>
-      <th>{{view view.triggeredFilterView class="last-triggered-filter"}}</th>
-      <th>{{view view.enabledFilterView class="enabled-filter"}}</th>
-    </tr>
     </thead>
     <tbody>
     {{#if App.router.clusterController.isAlertsLoaded}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/templates/main/alerts/alert_definition/alert_definition_summary.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/alerts/alert_definition/alert_definition_summary.hbs b/ambari-web/app/templates/main/alerts/alert_definition/alert_definition_summary.hbs
index 411c8be..5947711 100644
--- a/ambari-web/app/templates/main/alerts/alert_definition/alert_definition_summary.hbs
+++ b/ambari-web/app/templates/main/alerts/alert_definition/alert_definition_summary.hbs
@@ -27,5 +27,5 @@
     {{/if}}
   {{/each}}
 {{else}}
-  <span class="alert-state-single-host label alert-state-PENDING">{{view.content.shortState.PENDING}}</span>
+  <span class="alert-state-single-host label alert-state-PENDING">{{App.AlertDefinition.shortState.PENDING}}</span>
 {{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/templates/main/host.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host.hbs b/ambari-web/app/templates/main/host.hbs
index 07a9e7f..992c6b1 100644
--- a/ambari-web/app/templates/main/host.hbs
+++ b/ambari-web/app/templates/main/host.hbs
@@ -25,15 +25,26 @@
         {{#havePermissions "HOST.ADD_DELETE_COMPONENTS, HOST.TOGGLE_MAINTENANCE, HOST.ADD_DELETE_HOSTS"}}
           {{view App.HostTableMenuView}}
         {{/havePermissions}}
-        <div class="col-sm-10 pull-right">
-          {{outlet}}
+        <div class="VS-open-box pull-right">
+          <button class="btn btn-default">
+            <i class="icon-search"></i>
+          </button>
+          <div class="popup-arrow-up hide"></div>
         </div>
       </div>
     </div>
   </div>
+  <div class="row search-box-row hide">
+    {{outlet}}
+  </div>
   <table class="table advanced-header-table table-hover" id="hosts-table">
     <thead>
-    {{#view view.sortView classNames="label-row" contentBinding="view.filteredContent"}}
+      {{#view view.sortView classNames="label-row" contentBinding="view.filteredContent"}}
+        <th>
+          <div class="ember-view view-wrapper">
+            {{view App.CheckboxView classNames="host-select-all" checkedBinding="view.parentView.selectAllHosts"}}
+          </div>
+        </th>
         <th> </th>
         {{view view.parentView.nameSort}}
         <th> </th>
@@ -48,17 +59,14 @@
           {{t hosts.host.menu.stackVersions}}
         </th>
         <th class="sort-view-6">{{t common.components}}</th>
-        <th>
-          <div class="ember-view view-wrapper">
-            {{view App.CheckboxView classNames="host-select-all" checkedBinding="view.parentView.selectAllHosts"}}
-          </div>
-        </th>
+
       {{/view}}
     </thead>
     <tbody>
     {{#if view.pageContent}}
       {{#each host in view.pageContent}}
         {{#view view.HostView contentBinding="host"}}
+          <td>{{view App.CheckboxView checkedBinding="host.selected"}}</td>
 
           <td class="health">
             <span rel="HealthTooltip" {{bindAttr class="host.healthClass host.healthIconClass"}} {{bindAttr data-original-title="host.healthToolTip" }}></span>
@@ -108,8 +116,6 @@
               {{view.content.hostComponents.length}} {{pluralize view.content.hostComponents.length singular="t:common.component" plural="t:common.components"}}
             </a>
           </td>
-
-          <td>{{view App.CheckboxView checkedBinding="host.selected"}}</td>
         {{/view}}
       {{/each}}
     {{else}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/templates/main/host/combo_search_box.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/combo_search_box.hbs b/ambari-web/app/templates/main/host/combo_search_box.hbs
index 6de6774..6c1a23b 100644
--- a/ambari-web/app/templates/main/host/combo_search_box.hbs
+++ b/ambari-web/app/templates/main/host/combo_search_box.hbs
@@ -15,10 +15,11 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
+
+<div id="combo_search_box"></div>
 {{#if view.errMsg}}
-<div class="alert alert-danger">
-  {{view.errMsg}}
-</div>
+  <div class="alert alert-danger">
+    {{view.errMsg}}
+  </div>
 {{/if}}
-<div id="combo_search_box"></div>
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 50729a7..8ffa8f5 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -125,6 +125,7 @@ require('views/main/alert_definitions_view');
 require('views/main/alerts/alert_definition/alert_definition_summary');
 require('views/main/alerts/alert_definition/alert_definition_state');
 require('views/main/alerts/definition_details_view');
+require('views/main/alerts/alert_search_box');
 require('views/main/alerts/alert_definitions_actions_view');
 require('views/main/alerts/definition_configs_view');
 require('views/main/alerts/manage_alert_groups/select_definitions_popup_body_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/views/common/table_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/table_view.js b/ambari-web/app/views/common/table_view.js
index e14d283..fa30c81 100644
--- a/ambari-web/app/views/common/table_view.js
+++ b/ambari-web/app/views/common/table_view.js
@@ -273,6 +273,17 @@ App.TableView = Em.View.extend(App.Persist, {
   },
 
   /**
+   *
+   * @param {Array} filterConditions
+   */
+  updateComboFilter: function(filterConditions) {
+    this.set('controller.resetStartIndex', true);
+    this.set('filterConditions', filterConditions);
+    this.saveAllFilterConditions();
+    this.filter();
+  },
+
+  /**
    * save filter conditions to local storage
    * @param iColumn {Number}
    * @param value {String|Array}

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/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 f7515bc..3502ad1 100644
--- a/ambari-web/app/views/main/alert_definitions_view.js
+++ b/ambari-web/app/views/main/alert_definitions_view.js
@@ -167,270 +167,6 @@ App.MainAlertDefinitionsView = App.TableView.extend({
   }),
 
   /**
-   * Filtering header for <label>alertDefinition.label</label>
-   * @type {Em.View}
-   */
-  nameFilterView: filters.createTextView({
-    column: 1,
-    fieldType: 'filter-input-width',
-    onChangeValue: function(){
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition.status</label>
-   * @type {Em.View}
-   */
-  stateFilterView: filters.createSelectView({
-    column: 2,
-    fieldType: 'filter-input-width',
-    content: [
-      {
-        value: '',
-        label: Em.I18n.t('common.all')
-      },
-      {
-        value: 'OK',
-        label: 'OK'
-      },
-      {
-        value: 'WARNING',
-        label: 'WARNING'
-      },
-      {
-        value: 'CRITICAL',
-        label: 'CRITICAL'
-      },
-      {
-        value: 'UNKNOWN',
-        label: 'UNKNOWN'
-      },
-      {
-        value: 'PENDING',
-        label: 'NONE'
-      }
-    ],
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'alert_status');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition.service.serviceName</label>
-   * @type {Em.View}
-   */
-  serviceFilterView: filters.createSelectView({
-    column: 3,
-    fieldType: 'filter-input-width',
-    content: filters.getComputedServicesList(),
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition.type</label>
-   * @type {Em.View}
-   */
-  typeFilterView: filters.createSelectView({
-    column: 4,
-    fieldType: 'filter-input-width',
-    content: [
-      {
-        value: '',
-        label: Em.I18n.t('common.all')
-      },
-      {
-        value: 'SCRIPT',
-        label: 'SCRIPT'
-      },
-      {
-        value: 'WEB',
-        label: 'WEB'
-      },
-      {
-        value: 'PORT',
-        label: 'PORT'
-      },
-      {
-        value: 'METRIC',
-        label: 'METRIC'
-      },
-      {
-        value: 'AGGREGATE',
-        label: 'AGGREGATE'
-      },
-      {
-        value: 'SERVER',
-        label: 'SERVER'
-      },
-      {
-        value: 'RECOVERY',
-        label: 'RECOVERY'
-      }
-    ],
-    onChangeValue: function(){
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition.lastTriggered</label>
-   * @type {Em.View}
-   */
-  triggeredFilterView: filters.createSelectView({
-    column: 5,
-    appliedEmptyValue: ["", ""],
-    fieldType: 'filter-input-width,modified-filter',
-    content: [
-      {
-        value: 'Any',
-        label: Em.I18n.t('any')
-      },
-      {
-        value: 'Past 1 hour',
-        label: 'Past 1 hour'
-      },
-      {
-        value: 'Past 1 Day',
-        label: 'Past 1 Day'
-      },
-      {
-        value: 'Past 2 Days',
-        label: 'Past 2 Days'
-      },
-      {
-        value: 'Past 7 Days',
-        label: 'Past 7 Days'
-      },
-      {
-        value: 'Past 14 Days',
-        label: 'Past 14 Days'
-      },
-      {
-        value: 'Past 30 Days',
-        label: 'Past 30 Days'
-      }
-    ],
-    emptyValue: 'Any',
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'date');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition.enabled</label>
-   * @type {Em.View}
-   */
-  enabledFilterView:  filters.createSelectView({
-    column: 6,
-    fieldType: 'filter-input-width',
-    content: [
-      {
-        value: '',
-        label: Em.I18n.t('common.all')
-      },
-      {
-        value: 'enabled',
-        label: Em.I18n.t('alerts.table.state.enabled')
-      },
-      {
-        value: 'disabled',
-        label: Em.I18n.t('alerts.table.state.disabled')
-      }
-    ],
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'enable_disable');
-    }
-  }),
-
-  /**
-   * Filtering header for <label>alertDefinition</label> groups
-   * @type {Em.View}
-   */
-  alertGroupFilterView: filters.createSelectView({
-    column: 7,
-    fieldType: 'filter-input-width',
-    classNames: ['btn-group', 'pull-right', 'groups-filter'],
-    template: Ember.Handlebars.compile(
-      '<button class="btn btn-default dropdown-toggle" data-toggle="dropdown">' +
-        '<span class="filters-label">{{t common.groups}}:  </span>' +
-        '<span>{{view.selected.label}}&nbsp;<span class="caret"></span></span>' +
-      '</button>' +
-      '<ul class="dropdown-menu alert-groups-dropdown">' +
-        '{{#each category in view.content}}' +
-          '<li {{bindAttr class=":category-item category.selected:active"}}>' +
-            '<a {{action selectCategory category target="view"}} href="#">' +
-               '<span {{bindAttr class="category.class"}}></span>{{category.label}}</a>' +
-          '</li>'+
-        '{{/each}}' +
-      '</ul>'
-    ),
-    content: [],
-
-    didInsertElement: function() {
-      this._super();
-      this.updateContent();
-      this.set('value', '');
-    },
-
-    emptyValue: '',
-
-    /**
-     * Update list of <code>App.AlertGroup</code> used in the filter
-     * @method updateContent
-     */
-    updateContent: function() {
-      var defaultGroups = [];
-      var customGroups = [];
-      App.AlertGroup.find().forEach(function (group) {
-        var item = Em.Object.create({
-          value: group.get('id'),
-          label: group.get('displayNameDefinitions')
-        });
-        if (group.get('default')) {
-          defaultGroups.push(item);
-        } else {
-          customGroups.push(item);
-        }
-      });
-      defaultGroups = defaultGroups.sortProperty('label');
-      customGroups = customGroups.sortProperty('label');
-
-      this.set('content', [
-        Em.Object.create({
-          value: '',
-          label: Em.I18n.t('common.all') + ' (' + this.get('parentView.controller.content.length') + ')'
-        })
-      ].concat(defaultGroups, customGroups));
-      this.onValueChange();
-    }.observes('App.router.clusterController.isLoaded', 'App.router.manageAlertGroupsController.changeTrigger'),
-
-    selectCategory: function (event) {
-      var category = event.context;
-      this.set('value', category.value);
-      this.get('parentView').updateFilter(this.get('column'), category.value, 'alert_group');
-    },
-
-    onValueChange: function () {
-      var value = this.get('value');
-      if (value !== undefined) {
-        this.get('content').setEach('selected', false);
-        this.set('selected', this.get('content').findProperty('value', value));
-        var selectEntry = this.get('content').findProperty('value', value);
-        if (selectEntry) {
-          selectEntry.set('selected', true);
-        }
-        this.get('parentView').updateFilter(this.get('column'), value, 'alert_group');
-      } else {
-        this.set('value', '');
-        this.get('parentView').updateFilter(this.get('column'), '', 'alert_group');
-      }
-    }.observes('value')
-  }),
-
-  /**
    * Filtered number of all content number information displayed on the page footer bar
    * @returns {String}
    */

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/views/main/alerts/alert_definition/alert_definition_summary.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/alerts/alert_definition/alert_definition_summary.js b/ambari-web/app/views/main/alerts/alert_definition/alert_definition_summary.js
index 4c6378b..524d451 100644
--- a/ambari-web/app/views/main/alerts/alert_definition/alert_definition_summary.js
+++ b/ambari-web/app/views/main/alerts/alert_definition/alert_definition_summary.js
@@ -40,7 +40,7 @@ App.AlertDefinitionSummary = Em.View.extend({
     var showCounts = hostCnt > 1;
     var ret = [];
     order.forEach(function (state) {
-      var shortState = content.get('shortState')[state];
+      var shortState = App.AlertDefinition.shortState[state];
       var _stateSummary = {
         state: 'alert-state-' + state,
         count: '',

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/views/main/alerts/alert_search_box.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/alerts/alert_search_box.js b/ambari-web/app/views/main/alerts/alert_search_box.js
new file mode 100644
index 0000000..eebd7ee
--- /dev/null
+++ b/ambari-web/app/views/main/alerts/alert_search_box.js
@@ -0,0 +1,318 @@
+/**
+ * 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.MainAlertDefinitionSearchBoxView = Em.View.extend({
+  templateName: require('templates/main/host/combo_search_box'),
+  errMsg: '',
+  classNames: ['col-sm-12'],
+
+  didInsertElement: function () {
+    this.initVS();
+    this.restoreComboFilterQuery();
+    this.showHideClearButton();
+    this.initOpenVSButton();
+  },
+
+  initOpenVSButton: function() {
+    $('.VS-open-box button').click(function() {
+      $('.VS-open-box .popup-arrow-up, .search-box-row').toggleClass('hide');
+    });
+  },
+
+  initVS: function() {
+    window.visualSearch = VS.init({
+      container: $('#combo_search_box'),
+      query: '',
+      showFacets: true,
+      delay: 500,
+      placeholder: Em.I18n.t('common.search'),
+      unquotable: [
+        'text'
+      ],
+      callbacks: {
+        search: this.search.bind(this),
+        facetMatches: this.facetMatches.bind(this),
+        valueMatches: this.valueMatches.bind(this)
+      }
+    });
+  },
+
+  /**
+   * describe filter columns
+   * @type {object}
+   * @const
+   */
+  keyFilterMap: {
+    'Status': {
+      key: 'summary',
+      type: 'alert_status',
+      column: 2
+    },
+    'Alert Definition Name': {
+      key: 'label',
+      type: 'string',
+      column: 1
+    },
+    'Service': {
+      key: 'serviceName',
+      type: 'select',
+      column: 3
+    },
+    'Last Status Changed': {
+      key: 'lastTriggered',
+      type: 'date',
+      column: 5
+    },
+    'State': {
+      key: 'enabled',
+      type: 'enable_disable',
+      column: 6
+    },
+    'Group': {
+      key: 'groups',
+      type: 'alert_group',
+      column: 7
+    }
+  },
+
+  enabledDisabledMap: {
+    'enabled': Em.I18n.t('alerts.table.state.enabled'),
+    'disabled': Em.I18n.t('alerts.table.state.disabled')
+  },
+
+  lastTriggeredOptions: [
+    'Past 1 hour',
+    'Past 1 Day',
+    'Past 2 Days',
+    'Past 7 Days',
+    'Past 14 Days',
+    'Past 30 Days'
+  ],
+
+  /**
+   * populated dynamically in <code>getGroupsAvailableValues<code>
+   * @type {object}
+   */
+  groupsNameIdMap: {},
+
+  /**
+   * 'search' callback for visualsearch.js
+   * @param query
+   * @param searchCollection
+   */
+  search: function (query, searchCollection) {
+    this.clearErrMsg();
+    this.showHideClearButton();
+    var invalidFacet = this.findInvalidFacet(searchCollection);
+    if (invalidFacet) {
+      this.showErrMsg(invalidFacet);
+    }
+    var tableView = this.get('parentView.parentView');
+    App.db.setComboSearchQuery(tableView.get('controller.name'), query);
+    var filterConditions = this.createFilterConditions(searchCollection);
+    tableView.updateComboFilter(filterConditions);
+  },
+
+  /**
+   * 'facetMatches' callback for visualsearch.js
+   * @param callback
+   */
+  facetMatches: function (callback) {
+    callback(Object.keys(this.get('keyFilterMap')), {preserveOrder: true});
+  },
+
+  /**
+   * 'valueMatches' callback for visualsearch.js
+   * @param facetValue
+   * @param searchTerm
+   * @param callback
+   */
+  valueMatches: function (facetValue, searchTerm, callback) {
+    this.showHideClearButton();
+    switch (this.get('keyFilterMap')[facetValue].key) {
+      case 'summary':
+        this.getSummaryAvailableValues(facetValue, callback);
+        break;
+      case 'label':
+        this.getLabelAvailableValues(facetValue, callback);
+        break;
+      case 'serviceName':
+        this.getServiceAvailableValues(facetValue, callback);
+        break;
+      case 'lastTriggered':
+        this.getTriggeredAvailableValues(facetValue, callback);
+        break;
+      case 'enabled':
+        this.getEnabledAvailableValues(facetValue, callback);
+        break;
+      case 'groups':
+        this.getGroupsAvailableValues(facetValue, callback);
+        break;
+    }
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getSummaryAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(Object.keys(App.AlertDefinition.shortState), facetValue), {preserveOrder: true});
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getLabelAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(App.AlertDefinition.find().mapProperty('label').uniq(), facetValue));
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getServiceAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(App.AlertDefinition.find().mapProperty('serviceDisplayName').uniq(), facetValue));
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {function} callback
+   */
+  getTriggeredAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(this.get('lastTriggeredOptions'), facetValue), {preserveOrder: true});
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getEnabledAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(Object.values(this.get('enabledDisabledMap')), facetValue), {preserveOrder: true});
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getGroupsAvailableValues: function(facetValue, callback) {
+    const alertGroups = App.AlertGroup.find();
+    const map = {};
+    alertGroups.forEach((group) => {
+      map[group.get('displayName')] = group.get('id');
+    });
+    this.set('groupsNameIdMap', map);
+    callback(this.rejectUsedValues(alertGroups.mapProperty('displayName'), facetValue));
+  },
+
+  /**
+   *
+   * @param {Array} values
+   * @param {string} facetValue
+   */
+  rejectUsedValues: function(values, facetValue) {
+    return values.reject(function (item) {
+      return visualSearch.searchQuery.values(facetValue).indexOf(item) >= 0;
+    })
+  },
+
+  /**
+   *
+   * @param {object} searchCollection
+   * @returns {!object}
+   */
+  findInvalidFacet: function(searchCollection) {
+    const map = this.get('keyFilterMap');
+    return searchCollection.models.find((facet) => {
+      return !map[facet.attributes.category];
+    });
+  },
+
+  showErrMsg: function(category) {
+    this.set('errMsg', category.attributes.value + " " + Em.I18n.t('hosts.combo.search.invalidCategory'));
+  },
+
+  clearErrMsg: function() {
+    this.set('errMsg', '')
+  },
+
+  showHideClearButton: function () {
+    if (visualSearch.searchQuery.length > 0) {
+      $('.VS-cancel-search-box').removeClass('hide');
+    } else {
+      $('.VS-cancel-search-box').addClass('hide');
+    }
+  },
+
+  restoreComboFilterQuery: function() {
+    const query = App.db.getComboSearchQuery(this.get('parentView.parentView.controller.name'));
+    if (query) {
+      visualSearch.searchBox.setQuery(query);
+    }
+  },
+
+  /**
+   *
+   * @param {object} searchCollection
+   * @returns {Array}
+   */
+  createFilterConditions: function (searchCollection) {
+    const filterConditions = [];
+    const map = this.get('keyFilterMap');
+
+    searchCollection.models.forEach((model) => {
+      const filter = model.attributes;
+      if (map[filter.category]) {
+        filterConditions.push({
+          skipFilter: false,
+          iColumn: map[filter.category].column,
+          value: this.mapLabelToValue(filter.category, filter.value),
+          type: map[filter.category].type
+        });
+      }
+    });
+    return filterConditions;
+  },
+
+  /**
+   *
+   * @param {string} category
+   * @param {string} label
+   */
+  mapLabelToValue: function(category, label) {
+    const enabledDisabledMap = this.get('enabledDisabledMap');
+    const groupsNameIdMap = this.get('groupsNameIdMap');
+
+    switch (category) {
+      case 'State':
+        return Object.keys(enabledDisabledMap)[Object.values(enabledDisabledMap).indexOf(label)];
+      case 'Group':
+        return groupsNameIdMap[label];
+      default:
+        return label;
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/app/views/main/host/combo_search_box.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/combo_search_box.js b/ambari-web/app/views/main/host/combo_search_box.js
index 372c3f7..b77e877 100644
--- a/ambari-web/app/views/main/host/combo_search_box.js
+++ b/ambari-web/app/views/main/host/combo_search_box.js
@@ -23,11 +23,19 @@ App.MainHostComboSearchBoxView = Em.View.extend({
   healthStatusCategories: require('data/host/categories'),
   errMsg: '',
   serviceMap : {},
+  classNames: ['col-sm-12'],
 
   didInsertElement: function () {
     this.initVS();
     this.restoreComboFilterQuery();
     this.showHideClearButton();
+    this.initOpenVSButton();
+  },
+
+  initOpenVSButton: function() {
+    $('.VS-open-box button').click(function() {
+      $('.VS-open-box .popup-arrow-up, .search-box-row').toggleClass('hide');
+    });
   },
 
   initVS: function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/test/init_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/init_test.js b/ambari-web/test/init_test.js
index f6b572a..fe4e543 100644
--- a/ambari-web/test/init_test.js
+++ b/ambari-web/test/init_test.js
@@ -122,6 +122,14 @@ Number.isFinite = Number.isFinite || function(value) {
   return typeof value === 'number' && isFinite(value);
 };
 
+Object.values = Object.values || function (obj) {
+  var values = [];
+  for (var key in obj) {
+    values.push(obj[key]);
+  }
+  return values;
+};
+
 if (!window.performance) {
   window.performance = {
     now: Em.K

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/test/views/main/alert_definitions_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/alert_definitions_view_test.js b/ambari-web/test/views/main/alert_definitions_view_test.js
index 93d1f65..5b98b9c 100644
--- a/ambari-web/test/views/main/alert_definitions_view_test.js
+++ b/ambari-web/test/views/main/alert_definitions_view_test.js
@@ -49,15 +49,6 @@ describe('App.MainAlertDefinitionsView', function () {
 
   App.TestAliases.testAsComputedAlias(getView(), 'totalCount', 'content.length', 'number');
 
-  describe('#serviceFilterView', function () {
-    it('Add Ambari service to filters', function () {
-      var serviceFilterClass = view.serviceFilterView;
-      var content = serviceFilterClass.create({}).get('content');
-      expect(content[0].label).to.be.equal(Em.I18n.t('common.all'));
-      expect(content[content.length - 1].label).to.be.equal(Em.I18n.t('app.name'));
-    });
-  });
-
   describe('#willInsertElement', function () {
 
     beforeEach(function(){
@@ -180,149 +171,6 @@ describe('App.MainAlertDefinitionsView', function () {
     });
   });
 
-  describe("#alertGroupFilterView", function () {
-    var alertGroupFilterView;
-
-    beforeEach(function() {
-      alertGroupFilterView = view.get('alertGroupFilterView').create({
-        parentView: Em.Object.create({
-          updateFilter: Em.K
-        })
-      });
-    });
-
-    describe("#didInsertElement()", function () {
-
-      beforeEach(function() {
-        sinon.stub(alertGroupFilterView, '$').returns({parent: function() {
-          return {
-            addClass: Em.K
-          }
-        }});
-        sinon.stub(alertGroupFilterView, 'showClearFilter');
-        sinon.stub(alertGroupFilterView, 'updateContent');
-        alertGroupFilterView.didInsertElement();
-      });
-
-      afterEach(function() {
-        alertGroupFilterView.$.restore();
-        alertGroupFilterView.updateContent.restore();
-        alertGroupFilterView.showClearFilter.restore();
-      });
-
-      it("updateContent should be called", function() {
-        expect(alertGroupFilterView.updateContent.calledOnce).to.be.true;
-      });
-
-      it("value should be empty", function() {
-        expect(alertGroupFilterView.get('value')).to.be.empty;
-      });
-    });
-
-    describe("#updateContent()", function () {
-
-      beforeEach(function() {
-        sinon.stub(App.AlertGroup, 'find').returns([
-          Em.Object.create({
-            id: 'g1',
-            displayNameDefinitions: 'def1',
-            default: true
-          }),
-          Em.Object.create({
-            id: 'g2',
-            displayNameDefinitions: 'def2',
-            default: false
-          })
-        ]);
-        sinon.stub(alertGroupFilterView, 'onValueChange');
-        alertGroupFilterView.set('parentView.controller', {content: [{}]});
-        alertGroupFilterView.updateContent();
-      });
-
-      afterEach(function() {
-        App.AlertGroup.find.restore();
-        alertGroupFilterView.onValueChange.restore();
-      });
-
-      it("onValueChange should be called", function() {
-        expect(alertGroupFilterView.onValueChange.calledOnce).to.be.true;
-      });
-
-      it("content should be set", function() {
-        expect(alertGroupFilterView.get('content')).to.be.eql([
-          Em.Object.create({
-            value: '',
-            label: Em.I18n.t('common.all') + ' (1)'
-          }),
-          Em.Object.create({
-            value: 'g1',
-            label: 'def1'
-          }),
-          Em.Object.create({
-            value: 'g2',
-            label: 'def2'
-          })
-        ]);
-      });
-    });
-
-    describe("#selectCategory()", function () {
-
-      beforeEach(function() {
-        sinon.stub(alertGroupFilterView.get('parentView'), 'updateFilter');
-        alertGroupFilterView.selectCategory({context: {value: 'val1'}});
-      });
-
-      afterEach(function() {
-        alertGroupFilterView.get('parentView').updateFilter.restore();
-      });
-
-      it("value should be set", function() {
-        expect(alertGroupFilterView.get('value')).to.be.equal('val1');
-      });
-
-      it("updateFilter should be called", function() {
-        expect(alertGroupFilterView.get('parentView').updateFilter.calledWith(
-          7, 'val1', 'alert_group'
-        )).to.be.true;
-      });
-    });
-
-    describe("#onValueChange()", function () {
-
-      beforeEach(function() {
-        sinon.stub(alertGroupFilterView.get('parentView'), 'updateFilter');
-      });
-
-      afterEach(function() {
-        alertGroupFilterView.get('parentView').updateFilter.restore();
-      });
-
-      it("value is undefined", function() {
-        alertGroupFilterView.set('value', undefined);
-        alertGroupFilterView.onValueChange();
-        expect(alertGroupFilterView.get('value')).to.be.empty;
-        expect(alertGroupFilterView.get('parentView').updateFilter.calledWith(
-          7, '', 'alert_group'
-        )).to.be.true;
-      });
-
-      it("value is not undefined", function() {
-        var option = Em.Object.create({
-          selected: true,
-          value: 'val1'
-        });
-        alertGroupFilterView.set('content', [ option ]);
-        alertGroupFilterView.set('value', 'val1');
-        alertGroupFilterView.onValueChange();
-        expect(option.get('selected')).to.be.true;
-        expect(alertGroupFilterView.get('parentView').updateFilter.calledWith(
-          7, 'val1', 'alert_group'
-        )).to.be.true;
-      });
-    });
-  });
-
   describe("#paginationLeftClass", function() {
 
     it("startIndex is 2", function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/daac7df8/ambari-web/test/views/main/alerts/alert_search_box_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/alerts/alert_search_box_test.js b/ambari-web/test/views/main/alerts/alert_search_box_test.js
new file mode 100644
index 0000000..f5ff79c
--- /dev/null
+++ b/ambari-web/test/views/main/alerts/alert_search_box_test.js
@@ -0,0 +1,232 @@
+/**
+ * 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 view;
+
+describe('App.MainAlertDefinitionDetailsView', function () {
+
+  beforeEach(function () {
+    view = App.MainAlertDefinitionSearchBoxView.create({
+      controller: Em.Object.create()
+    });
+  });
+
+  describe('#initVS', function() {
+    beforeEach(function() {
+      sinon.stub(VS, 'init');
+    });
+    afterEach(function() {
+      VS.init.restore();
+    });
+
+    it('VS.init should be called', function() {
+      view.initVS();
+      expect(VS.init.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#facetMatches', function() {
+    var mock = {
+      callback: Em.K
+    };
+    beforeEach(function() {
+      sinon.spy(mock, 'callback');
+    });
+    afterEach(function() {
+      mock.callback.restore();
+    });
+
+    it('callback should be called', function() {
+      view.facetMatches(mock.callback);
+      expect(mock.callback.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#valueMatches', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'showHideClearButton');
+      sinon.stub(view, 'getSummaryAvailableValues');
+      sinon.stub(view, 'getLabelAvailableValues');
+      sinon.stub(view, 'getServiceAvailableValues');
+      sinon.stub(view, 'getTriggeredAvailableValues');
+      sinon.stub(view, 'getEnabledAvailableValues');
+      sinon.stub(view, 'getGroupsAvailableValues');
+    });
+    afterEach(function() {
+      view.showHideClearButton.restore();
+      view.getSummaryAvailableValues.restore();
+      view.getLabelAvailableValues.restore();
+      view.getServiceAvailableValues.restore();
+      view.getTriggeredAvailableValues.restore();
+      view.getEnabledAvailableValues.restore();
+      view.getGroupsAvailableValues.restore();
+    });
+
+    it('showHideClearButton should be called', function() {
+      view.valueMatches('Status');
+      expect(view.showHideClearButton.calledOnce).to.be.true;
+    });
+
+    it('getSummaryAvailableValues should be called', function() {
+      view.valueMatches('Status', '', Em.K);
+      expect(view.getSummaryAvailableValues.calledWith('Status')).to.be.true;
+    });
+
+    it('getLabelAvailableValues should be called', function() {
+      view.valueMatches('Alert Definition Name', '', Em.K);
+      expect(view.getLabelAvailableValues.calledWith('Alert Definition Name')).to.be.true;
+    });
+
+    it('getServiceAvailableValues should be called', function() {
+      view.valueMatches('Service', '', Em.K);
+      expect(view.getServiceAvailableValues.calledWith('Service')).to.be.true;
+    });
+
+    it('getTriggeredAvailableValues should be called', function() {
+      view.valueMatches('Last Status Changed', '', Em.K);
+      expect(view.getTriggeredAvailableValues.calledWith('Last Status Changed')).to.be.true;
+    });
+
+    it('getEnabledAvailableValues should be called', function() {
+      view.valueMatches('State', '', Em.K);
+      expect(view.getEnabledAvailableValues.calledWith('State')).to.be.true;
+    });
+
+    it('getGroupsAvailableValues should be called', function() {
+      view.valueMatches('Group', '', Em.K);
+      expect(view.getGroupsAvailableValues.calledWith('Group')).to.be.true;
+    });
+  });
+
+  describe('#getSummaryAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getSummaryAvailableValues('', callback);
+      expect(callback.calledWith([], {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#getLabelAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getLabelAvailableValues('', callback);
+      expect(callback.calledWith([])).to.be.true;
+    });
+  });
+
+  describe('#getServiceAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getServiceAvailableValues('', callback);
+      expect(callback.calledWith([])).to.be.true;
+    });
+  });
+
+  describe('#getTriggeredAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getTriggeredAvailableValues('', callback);
+      expect(callback.calledWith([], {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#getEnabledAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getEnabledAvailableValues('', callback);
+      expect(callback.calledWith([], {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#getGroupsAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'rejectUsedValues').returns([]);
+      sinon.stub(App.AlertGroup, 'find').returns([
+        Em.Object.create({
+          id: 1,
+          displayName: 'g1'
+        })
+      ]);
+    });
+    afterEach(function() {
+      view.rejectUsedValues.restore();
+      App.AlertGroup.find.restore();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getGroupsAvailableValues('', callback);
+      expect(view.get('groupsNameIdMap')).to.be.eql({
+        'g1': 1
+      });
+      expect(callback.calledWith([])).to.be.true;
+    });
+  });
+
+  describe('#mapLabelToValue', function() {
+    it('should return value of State filter', function() {
+      expect(view.mapLabelToValue('State', Em.I18n.t('alerts.table.state.enabled'))).to.be.equal('enabled');
+    });
+
+    it('should return value of Group filter', function() {
+      view.set('groupsNameIdMap', {'l1': 1});
+      expect(view.mapLabelToValue('Group', 'l1')).to.be.equal(1);
+    });
+
+    it('should return value of filter', function() {
+      expect(view.mapLabelToValue('cat', 'l1')).to.be.equal('l1');
+    });
+  });
+});