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

[35/56] [abbrv] ambari git commit: AMBARI-22304 Add search box filter to Config History page. (atkach)

AMBARI-22304 Add search box filter to Config History page. (atkach)


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

Branch: refs/heads/branch-feature-AMBARI-14714
Commit: 479cf86ac3c17c8dcaba89280fb2dc5c9012523b
Parents: 655e0a7
Author: Andrii Tkach <at...@apache.org>
Authored: Wed Oct 25 15:40:59 2017 +0300
Committer: Andrii Tkach <at...@apache.org>
Committed: Wed Oct 25 15:40:59 2017 +0300

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   2 +
 .../main/dashboard/config_history_controller.js |  92 ++-----
 ambari-web/app/routes/main.js                   |   2 -
 ambari-web/app/templates/main/alerts.hbs        |   2 +-
 .../templates/main/dashboard/config_history.hbs |  23 +-
 ambari-web/app/templates/main/host.hbs          |   2 +-
 ambari-web/app/utils/ajax/ajax.js               |   4 +
 ambari-web/app/views.js                         |   2 +
 ambari-web/app/views/common/search_box_view.js  | 165 +++++++++++++
 .../app/views/main/alerts/alert_search_box.js   | 161 ++-----------
 .../main/dashboard/config_history_search_box.js | 221 +++++++++++++++++
 .../views/main/dashboard/config_history_view.js | 101 --------
 .../app/views/main/host/combo_search_box.js     |  44 +---
 .../test/views/common/search_box_view_test.js   | 240 +++++++++++++++++++
 .../views/main/alerts/alert_search_box_test.js  |  74 +-----
 .../dashboard/config_history_search_box_test.js | 207 ++++++++++++++++
 .../main/dashboard/config_history_view_test.js  | 188 +--------------
 .../views/main/host/combo_search_box_test.js    |  66 +----
 18 files changed, 908 insertions(+), 688 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/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 fe0dd17..de81764 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -295,6 +295,7 @@ var files = [
   'test/views/main/admin/service_auto_start/component_auto_start_test',
   'test/views/main/admin/service_auto_start_test',
   'test/views/main/dashboard/config_history_view_test',
+  'test/views/main/dashboard/config_history_search_box_test',
   'test/views/main/dashboard/widget_test',
   'test/views/main/dashboard/widgets_test',
   'test/views/main/dashboard/widgets/text_widget_test',
@@ -382,6 +383,7 @@ var files = [
   'test/views/common/form/spinner_input_view_test',
   'test/views/common/form/manage_kdc_credentials_form_test',
   'test/views/common/log_file_search_view_test',
+  'test/views/common/search_box_view_test',
   'test/views/wizard/step3/hostLogPopupBody_view_test',
   'test/views/wizard/step3/hostWarningPopupBody_view_test',
   'test/views/wizard/step3/hostWarningPopupFooter_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/dashboard/config_history_controller.js b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
index 5197ad9..ae3057d 100644
--- a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
+++ b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
@@ -103,79 +103,6 @@ App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin
     }
   ],
 
-  modifiedFilter: Em.Object.create({
-    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'
-      }
-    ],
-    optionValue: 'Any',
-    filterModified: function () {
-      var time = "";
-      var curTime = new Date().getTime();
-
-      switch (this.get('optionValue.value')) {
-        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 'Any':
-          time = "";
-          break;
-      }
-      this.set("actualValues", {
-        endTime: '',
-        startTime: time
-      });
-    }.observes('optionValue'),
-    cancel: function () {
-      this.set('optionValue', this.get('content').findProperty('value', 'Any'));
-    },
-    actualValues: Em.Object.create({
-      startTime: "",
-      endTime: ""
-    })
-  }),
-
   /**
    * load all data components required by config history table
    *  - total counter of service config versions(called in parallel)
@@ -276,5 +203,24 @@ App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin
       }
     });
     return sortParams;
+  },
+
+  /**
+   *
+   * @param {string} name
+   */
+  getSearchBoxSuggestions: function(name) {
+    const dfd = $.Deferred();
+    const key = this.get('filterProps').findProperty('name', name).key;
+    App.ajax.send({
+      name: 'service.serviceConfigVersions.get.suggestions',
+      sender: this,
+      data: {
+        key
+      }
+    })
+    .done((data) => {dfd.resolve(data.items.mapProperty(key).uniq());})
+    .fail(() => {dfd.resolve([]);});
+    return dfd.promise();
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 5ba7c3d..194fb14 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -225,7 +225,6 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       connectOutlets: function (router, context) {
         App.loadTimer.start('Hosts Page');
         router.get('mainController').connectOutlet('mainHost');
-        router.get('mainHostController').connectOutlet('mainHostComboSearchBox');
       }
     }),
 
@@ -375,7 +374,6 @@ 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/479cf86a/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 1ce2c91..a111728 100644
--- a/ambari-web/app/templates/main/alerts.hbs
+++ b/ambari-web/app/templates/main/alerts.hbs
@@ -34,7 +34,7 @@
     </div>
   </div>
   <div class="row search-box-row hide">
-    {{outlet}}
+    {{view App.MainAlertDefinitionSearchBoxView}}
   </div>
   <table class="table advanced-header-table table-hover alerts-table" id="alert-definitions-table">
     <thead>

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/templates/main/dashboard/config_history.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard/config_history.hbs b/ambari-web/app/templates/main/dashboard/config_history.hbs
index bc6ef7c..3a1967a 100644
--- a/ambari-web/app/templates/main/dashboard/config_history.hbs
+++ b/ambari-web/app/templates/main/dashboard/config_history.hbs
@@ -18,7 +18,20 @@
 
 <div id="config_history" class="container-wrap-table">
   <div class="row">
-    <h2 class="table-title col-md-12">{{t dashboard.configHistory.title}}</h2>
+    <h2 class="table-title col-md-2">{{t dashboard.configHistory.title}}</h2>
+    <div class="table-controls row col-sm-10 pull-right">
+      <div class="col-sm-12">
+        <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">
+    {{view App.MainConfigHistorySearchBoxView}}
   </div>
   <table class="table advanced-header-table table-hover">
     <thead>
@@ -29,14 +42,6 @@
       {{view view.parentView.authorSort}}
       {{view view.parentView.notesSort}}
     {{/view}}
-
-    <tr class="filter-row config-history-filter-row">
-      <th class="first cg-service">{{view view.serviceFilterView}}</th>
-      <th class="cg-name">{{view view.configGroupFilterView}}</th>
-      <th class="cg-created">{{view view.modifiedFilterView}}</th>
-      <th class="cg-author">{{view view.authorFilterView}}</th>
-      <th class="cg-notes">{{view view.notesFilterView}}</th>
-    </tr>
     </thead>
     <tbody class="services-menu">
     {{#if view.filteringComplete}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/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 992c6b1..b823b9b 100644
--- a/ambari-web/app/templates/main/host.hbs
+++ b/ambari-web/app/templates/main/host.hbs
@@ -35,7 +35,7 @@
     </div>
   </div>
   <div class="row search-box-row hide">
-    {{outlet}}
+    {{view App.MainHostComboSearchBoxView}}
   </div>
   <table class="table advanced-header-table table-hover" id="hosts-table">
     <thead>

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/utils/ajax/ajax.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js
index c32d8d4..3f85dfdc 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -2831,6 +2831,10 @@ var urls = {
       }
     }
   },
+  'service.serviceConfigVersions.get.suggestions': {
+    real: '/clusters/{clusterName}/configurations/service_config_versions?fields={key}&minimal_response=true',
+    mock: ''
+  },
   'service.serviceConfigVersion.revert': {
     'real': '/clusters/{clusterName}',
     'mock': '',

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 8ffa8f5..394e390 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -35,6 +35,7 @@ require('views/common/chart/pie');
 require('views/common/chart/linear');
 require('views/common/chart/linear_time');
 require('views/common/modal_popup');
+require('views/common/search_box_view');
 require('views/common/modal_popups/alert_popup');
 require('views/common/modal_popups/edit_dashboard_widget_popup');
 require('views/common/modal_popups/manage_kdc_credentials_popup');
@@ -286,6 +287,7 @@ require('views/main/dashboard/widgets/yarn_memory');
 require('views/main/dashboard/widgets/supervisor_live');
 require('views/main/dashboard/widgets/flume_agent_live');
 require('views/main/dashboard/config_history_view');
+require('views/main/dashboard/config_history_search_box');
 
 
 require('views/main/service');

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/views/common/search_box_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/search_box_view.js b/ambari-web/app/views/common/search_box_view.js
new file mode 100644
index 0000000..8a61d4e
--- /dev/null
+++ b/ambari-web/app/views/common/search_box_view.js
@@ -0,0 +1,165 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+App.SearchBoxView = Em.View.extend({
+  templateName: require('templates/main/host/combo_search_box'),
+  errMsg: '',
+  classNames: ['col-sm-12'],
+  keyFilterMap: [],
+
+  didInsertElement: function () {
+    this.initVS();
+    this.restoreComboFilterQuery();
+    this.showHideClearButton();
+    this.initOpenVSButton();
+  },
+
+  showErrMsg: function(category) {
+    this.set('errMsg', category.attributes.value + " " + Em.I18n.t('hosts.combo.search.invalidCategory'));
+  },
+
+  clearErrMsg: function() {
+    this.set('errMsg', '')
+  },
+
+  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)
+      }
+    });
+  },
+
+  /**
+   * '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');
+    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(this.get('keyFilterMap').mapProperty('label'), {preserveOrder: true});
+  },
+
+  valueMatches: Em.K,
+
+  /**
+   *
+   * @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.someProperty('label', facet.attributes.category);
+    });
+  },
+
+  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.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;
+      const category = map.findProperty('label', filter.category);
+      if (category) {
+        filterConditions.push({
+          skipFilter: false,
+          iColumn: category.column,
+          value: this.mapLabelToValue(category.key, filter.value),
+          type: category.type
+        });
+      }
+    });
+    return filterConditions;
+  },
+
+  /**
+   *
+   * @param {string} category
+   * @param {string} label
+   * @returns {string}
+   */
+  mapLabelToValue: function(category, label) {
+    return label;
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/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
index eebd7ee..07fa336 100644
--- a/ambari-web/app/views/main/alerts/alert_search_box.js
+++ b/ambari-web/app/views/main/alerts/alert_search_box.js
@@ -18,79 +18,51 @@
 
 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)
-      }
-    });
-  },
+App.MainAlertDefinitionSearchBoxView = App.SearchBoxView.extend({
 
   /**
    * describe filter columns
-   * @type {object}
+   * @type {Array}
    * @const
    */
-  keyFilterMap: {
-    'Status': {
+  keyFilterMap: [
+    {
+      label: Em.I18n.t('common.status'),
       key: 'summary',
       type: 'alert_status',
       column: 2
     },
-    'Alert Definition Name': {
+    {
+      label: Em.I18n.t('alerts.table.header.definitionName'),
       key: 'label',
       type: 'string',
       column: 1
     },
-    'Service': {
+    {
+      label: Em.I18n.t('common.service'),
       key: 'serviceName',
       type: 'select',
       column: 3
     },
-    'Last Status Changed': {
+    {
+      label: Em.I18n.t('alerts.table.header.lastTriggered'),
       key: 'lastTriggered',
       type: 'date',
       column: 5
     },
-    'State': {
+    {
+      label: Em.I18n.t('alerts.table.state'),
       key: 'enabled',
       type: 'enable_disable',
       column: 6
     },
-    'Group': {
+    {
+      label: Em.I18n.t('common.group'),
       key: 'groups',
       type: 'alert_group',
       column: 7
     }
-  },
+  ],
 
   enabledDisabledMap: {
     'enabled': Em.I18n.t('alerts.table.state.enabled'),
@@ -113,32 +85,6 @@ App.MainAlertDefinitionSearchBoxView = Em.View.extend({
   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
@@ -146,7 +92,7 @@ App.MainAlertDefinitionSearchBoxView = Em.View.extend({
    */
   valueMatches: function (facetValue, searchTerm, callback) {
     this.showHideClearButton();
-    switch (this.get('keyFilterMap')[facetValue].key) {
+    switch (this.get('keyFilterMap').findProperty('label', facetValue).key) {
       case 'summary':
         this.getSummaryAvailableValues(facetValue, callback);
         break;
@@ -230,75 +176,6 @@ App.MainAlertDefinitionSearchBoxView = Em.View.extend({
 
   /**
    *
-   * @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
    */
@@ -307,9 +184,9 @@ App.MainAlertDefinitionSearchBoxView = Em.View.extend({
     const groupsNameIdMap = this.get('groupsNameIdMap');
 
     switch (category) {
-      case 'State':
+      case 'enabled':
         return Object.keys(enabledDisabledMap)[Object.values(enabledDisabledMap).indexOf(label)];
-      case 'Group':
+      case 'groups':
         return groupsNameIdMap[label];
       default:
         return label;

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/views/main/dashboard/config_history_search_box.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/config_history_search_box.js b/ambari-web/app/views/main/dashboard/config_history_search_box.js
new file mode 100644
index 0000000..fee26c8
--- /dev/null
+++ b/ambari-web/app/views/main/dashboard/config_history_search_box.js
@@ -0,0 +1,221 @@
+/**
+ * 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.MainConfigHistorySearchBoxView = App.SearchBoxView.extend({
+
+  /**
+   * @type {Array}
+   * @const
+   */
+  modifiedOptions: [
+    'Past 1 hour',
+    'Past 1 Day',
+    'Past 2 Days',
+    'Past 7 Days',
+    'Past 14 Days',
+    'Past 30 Days'
+  ],
+
+  /**
+   * describe filter columns
+   * @type {Array}
+   * @const
+   */
+  keyFilterMap: [
+    {
+      label: Em.I18n.t('common.service'),
+      key: 'serviceVersion',
+      type: 'select',
+      column: 1
+    },
+    {
+      label: Em.I18n.t('common.configGroup'),
+      key: 'configGroup',
+      type: 'select',
+      column: 2
+    },
+    {
+      label: Em.I18n.t('dashboard.configHistory.table.created.title'),
+      key: 'createTime',
+      type: 'range',
+      column: 3
+    },
+    {
+      label: Em.I18n.t('common.author'),
+      key: 'author',
+      type: 'string',
+      column: 4
+    },
+    {
+      label: Em.I18n.t('common.notes'),
+      key: 'notes',
+      type: 'string',
+      column: 5
+    }
+  ],
+
+  /**
+   * populated dynamically in <code>getGroupsAvailableValues<code>
+   * @type {object}
+   */
+  groupsNameIdMap: {},
+
+  /**
+   * 'valueMatches' callback for visualsearch.js
+   * @param facetValue
+   * @param searchTerm
+   * @param callback
+   */
+  valueMatches: function (facetValue, searchTerm, callback) {
+    this.showHideClearButton();
+    switch (this.get('keyFilterMap').findProperty('label', facetValue).key) {
+      case 'serviceVersion':
+        this.getServiceVersionAvailableValues(facetValue, callback);
+        break;
+      case 'configGroup':
+        this.getConfigGroupAvailableValues(facetValue, callback);
+        break;
+      case 'createTime':
+        this.getCreateTimeAvailableValues(facetValue, callback);
+        break;
+      case 'author':
+        this.getAuthorAvailableValues(facetValue, callback);
+        break;
+      case 'notes':
+        this.getNotesAvailableValues(facetValue, callback);
+        break;
+    }
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getServiceVersionAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(App.StackService.find().mapProperty('displayName'), facetValue), {preserveOrder: true});
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getConfigGroupAvailableValues: function(facetValue, callback) {
+    const configGroups = App.ServiceConfigVersion.find().mapProperty('groupName').uniq().compact();
+    callback(this.rejectUsedValues(configGroups, facetValue));
+    this.requestFacetSuggestions(facetValue, callback);
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getCreateTimeAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(this.get('modifiedOptions'), facetValue), {preserveOrder: true});
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getAuthorAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(App.ServiceConfigVersion.find().mapProperty('author').uniq(), facetValue));
+    this.requestFacetSuggestions(facetValue, callback);
+  },
+
+  /**
+   *
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  getNotesAvailableValues: function(facetValue, callback) {
+    callback(this.rejectUsedValues(App.ServiceConfigVersion.find().mapProperty('notes').uniq(), facetValue));
+    this.requestFacetSuggestions(facetValue, callback);
+  },
+
+
+  /**
+   * request suggestions for facet from server
+   * @param {string} facetValue
+   * @param {Function} callback
+   */
+  requestFacetSuggestions: function (facetValue, callback) {
+    const name = this.get('keyFilterMap').findProperty('label', facetValue).key;
+    this.get('controller').getSearchBoxSuggestions(name).done((suggestions) => {
+      if (suggestions.length) {
+        callback(suggestions);
+      }
+    });
+  },
+
+  /**
+   *
+   * @param {string} category
+   * @param {string} label
+   */
+  mapLabelToValue: function(category, label) {
+    switch (category) {
+      case 'createTime':
+        return this.computeCreateTimeRange(label);
+      case 'serviceVersion':
+        return App.StackService.find().findProperty('displayName', label).get('serviceName');
+      default:
+        return label;
+    }
+  },
+
+  /**
+   *
+   * @param {string} value
+   * @returns {Array} [startTime, endTime]
+   */
+  computeCreateTimeRange: function(value) {
+    let time = "";
+    const curTime = App.dateTime();
+
+    switch (value) {
+      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 'Any':
+        time = "";
+        break;
+    }
+    return [time, ''];
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/app/views/main/dashboard/config_history_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard/config_history_view.js b/ambari-web/app/views/main/dashboard/config_history_view.js
index 2808de3..4376067 100644
--- a/ambari-web/app/views/main/dashboard/config_history_view.js
+++ b/ambari-web/app/views/main/dashboard/config_history_view.js
@@ -72,12 +72,6 @@ App.MainConfigHistoryView = App.TableView.extend(App.TableServerViewMixin, {
     clearTimeout(this.get('controller.timeoutRef'));
   },
 
-  updateFilter: function (iColumn, value, type) {
-    if (!this.get('isInitialRendering')) {
-      this._super(iColumn, value, type);
-    }
-  },
-
   sortView: sort.serverWrapperView,
   versionSort: sort.fieldView.extend({
     column: 1,
@@ -106,81 +100,6 @@ App.MainConfigHistoryView = App.TableView.extend(App.TableServerViewMixin, {
     displayName: Em.I18n.t('common.notes')
   }),
 
-  serviceFilterView: filters.createSelectView({
-    column: 1,
-    fieldType: 'filter-input-width',
-    content: function () {
-      return [
-        {
-          value: '',
-          label: Em.I18n.t('common.all')
-        }
-      ].concat(App.StackService.find().map(function (service) {
-        return {
-          value: service.get('serviceName'),
-          label: service.get('displayName')
-        }
-      }));
-    }.property('App.router.clusterController.isLoaded'),
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
-    }
-  }),
-
-  configGroupFilterView: filters.createSelectView({
-    column: 2,
-    fieldType: 'filter-input-width',
-    content: [],
-    observeContent: function() {
-      var groupName = App.ServiceConfigVersion.find().mapProperty('groupName').uniq().compact();
-      // list of group names can only grow since config versions not removable
-      if (groupName.length >= this.get('content.length')) {
-        this.set('content', [
-          {
-            value: '',
-            label: Em.I18n.t('common.all')
-          }
-        ].concat(groupName.map(function (item) {
-            return {
-              value: item,
-              label: item
-            }
-          })));
-      }
-    }.observes('parentView.isInitialRendering', 'parentView.pageContent'),
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select');
-    }
-  }),
-
-  modifiedFilterView: filters.createSelectView({
-    column: 3,
-    appliedEmptyValue: ["", ""],
-    fieldType: 'filter-input-width,modified-filter',
-    emptyValue: 'Any',
-    contentBinding: "controller.modifiedFilter.content",
-    onChangeValue: function () {
-      this.set("controller.modifiedFilter.optionValue", this.get('selected'));
-      this.get('parentView').updateFilter(this.get('column'), [this.get('controller.modifiedFilter.actualValues.startTime'), this.get('controller.modifiedFilter.actualValues.endTime')], 'range');
-    }
-  }),
-
-  authorFilterView: filters.createTextView({
-    column: 4,
-    fieldType: 'filter-input-width',
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string');
-    }
-  }),
-
-  notesFilterView: filters.createTextView({
-    column: 5,
-    fieldType: 'filter-input-width',
-    onChangeValue: function () {
-      this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string');
-    }
-  }),
-
   ConfigVersionView: Em.View.extend({
     tagName: 'tr',
     showLessNotes: true,
@@ -209,18 +128,6 @@ App.MainConfigHistoryView = App.TableView.extend(App.TableServerViewMixin, {
   },
 
   /**
-   * Clear all filter values, update filter conditions in the localStorage and update table data with API-request
-   *
-   * @method clearFilters
-   * @override
-   */
-  clearFilters: function () {
-    this._super();
-    this.saveAllFilterConditions();
-    this.refresh();
-  },
-
-  /**
    * callback executed after refresh call done
    * @method refreshDone
    */
@@ -236,13 +143,5 @@ App.MainConfigHistoryView = App.TableView.extend(App.TableServerViewMixin, {
     App.db.setStartIndex(this.get('controller.name'), this.get('startIndex'));
   }.observes('startIndex'),
 
-  /**
-   * associations between host property and column index
-   * @type {Array}
-   */
-  colPropAssoc: function () {
-    return this.get('controller.colPropAssoc');
-  }.property('controller.colPropAssoc'),
-
   filter: Em.K
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/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 b77e877..a582286 100644
--- a/ambari-web/app/views/main/host/combo_search_box.js
+++ b/ambari-web/app/views/main/host/combo_search_box.js
@@ -18,25 +18,10 @@
 
 var App = require('app');
 
-App.MainHostComboSearchBoxView = Em.View.extend({
-  templateName: require('templates/main/host/combo_search_box'),
+App.MainHostComboSearchBoxView = App.SearchBoxView.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');
-    });
-  },
+  controllerBinding: 'App.router.mainHostComboSearchBoxController',
 
   initVS: function() {
     this.setupLabelMap();
@@ -68,7 +53,7 @@ App.MainHostComboSearchBoxView = Em.View.extend({
     if (invalidFacet) {
       this.showErrMsg(invalidFacet);
     }
-    var tableView = this.get('parentView.parentView');
+    var tableView = this.get('parentView');
     App.db.setComboSearchQuery(tableView.get('controller.name'), query);
     var filterConditions = this.createFilterConditions(searchCollection);
     tableView.updateComboFilter(filterConditions);
@@ -280,29 +265,6 @@ App.MainHostComboSearchBoxView = Em.View.extend({
     return result;
   },
 
-  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.toJSON().length > 0) {
-      $('.VS-cancel-search-box').removeClass('hide');
-    } else {
-      $('.VS-cancel-search-box').addClass('hide');
-    }
-  },
-
-  restoreComboFilterQuery: function() {
-    var query = App.db.getComboSearchQuery(this.get('parentView.parentView.controller.name'));
-    if (query) {
-      visualSearch.searchBox.setQuery(query);
-    }
-  },
-
   getHostComponentList: function() {
     var hostComponentList = [];
     App.MasterComponent.find().rejectProperty('totalCount', 0).toArray()

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/test/views/common/search_box_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/search_box_view_test.js b/ambari-web/test/views/common/search_box_view_test.js
new file mode 100644
index 0000000..53100e8
--- /dev/null
+++ b/ambari-web/test/views/common/search_box_view_test.js
@@ -0,0 +1,240 @@
+/**
+ * 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('views/common/search_box_view');
+
+describe('App.SearchBoxView', function () {
+  var view;
+
+  beforeEach(function () {
+    view = App.SearchBoxView.create({
+      parentView: Em.Object.create({
+        updateComboFilter: Em.K,
+        controller: {
+          name: 'ctrl1'
+        }
+      }),
+      keyFilterMap: [
+        {
+          label: 'l1',
+          key: 'key1',
+          type: 'type1',
+          column: 1
+        }
+      ]
+    });
+  });
+
+  describe('#didInsertElement', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'initVS');
+      sinon.stub(view, 'restoreComboFilterQuery');
+      sinon.stub(view, 'showHideClearButton');
+      sinon.stub(view, 'initOpenVSButton');
+      view.didInsertElement();
+    });
+    afterEach(function() {
+      view.initVS.restore();
+      view.restoreComboFilterQuery.restore();
+      view.showHideClearButton.restore();
+      view.initOpenVSButton.restore();
+    });
+
+    it('initVS should be called', function() {
+      expect(view.initVS.calledOnce).to.be.true;
+    });
+
+    it('restoreComboFilterQuery should be called', function() {
+      expect(view.restoreComboFilterQuery.calledOnce).to.be.true;
+    });
+
+    it('showHideClearButton should be called', function() {
+      expect(view.showHideClearButton.calledOnce).to.be.true;
+    });
+
+    it('initOpenVSButton should be called', function() {
+      expect(view.initOpenVSButton.calledOnce).to.be.true;
+    });
+  });
+
+  describe('#showErrMsg', function() {
+    it('should set errMsg', function() {
+      view.showErrMsg({attributes: {value: 'val1'}});
+      expect(view.get('errMsg')).to.be.equal('val1 ' + Em.I18n.t('hosts.combo.search.invalidCategory'));
+    });
+  });
+
+  describe('#clearErrMsg', function() {
+    it('should set errMsg', function() {
+      view.set('errMsg', 'aaa');
+      view.clearErrMsg();
+      expect(view.get('errMsg')).to.be.empty;
+    });
+  });
+
+  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('#search', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'clearErrMsg');
+      sinon.stub(view, 'showHideClearButton');
+      sinon.stub(view, 'findInvalidFacet').returns({});
+      sinon.stub(view, 'showErrMsg');
+      sinon.stub(App.db, 'setComboSearchQuery');
+      sinon.stub(view, 'createFilterConditions').returns([]);
+      sinon.stub(view.get('parentView'), 'updateComboFilter');
+      view.search('query', []);
+    });
+    afterEach(function() {
+      view.clearErrMsg.restore();
+      view.showHideClearButton.restore();
+      view.findInvalidFacet.restore();
+      view.showErrMsg.restore();
+      App.db.setComboSearchQuery.restore();
+      view.createFilterConditions.restore();
+      view.get('parentView').updateComboFilter.restore();
+    });
+
+    it('clearErrMsg should be called', function() {
+      expect(view.clearErrMsg.calledOnce).to.be.true;
+    });
+
+    it('showHideClearButton should be called', function() {
+      expect(view.showHideClearButton.calledOnce).to.be.true;
+    });
+
+    it('showErrMsg should be called', function() {
+      expect(view.showErrMsg.calledOnce).to.be.true;
+    });
+
+    it('App.db.setComboSearchQuery should be called', function() {
+      expect(App.db.setComboSearchQuery.calledWith('ctrl1', 'query')).to.be.true;
+    });
+
+    it('createFilterConditions should be called', function() {
+      expect(view.createFilterConditions.calledWith([])).to.be.true;
+    });
+
+    it('updateComboFilter should be called', function() {
+      expect(view.get('parentView').updateComboFilter.calledWith([])).to.be.true;
+    });
+  });
+
+  describe('#facetMatches', function() {
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.facetMatches(callback);
+      expect(callback.calledWith(view.get('keyFilterMap').mapProperty('label'), {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#findInvalidFacet', function() {
+    it('should return invalid facet', function() {
+      var searchCollection = {
+        models: [
+          {
+            attributes: {
+              category: 'wrong'
+            }
+          },
+          {
+            attributes: {
+              category: view.get('keyFilterMap').mapProperty('label')[0]
+            }
+          }
+        ]
+      };
+      expect(view.findInvalidFacet(searchCollection)).to.be.eql(searchCollection.models[0]);
+    });
+  });
+
+  describe('#restoreComboFilterQuery', function() {
+    beforeEach(function() {
+      sinon.stub(App.db, 'getComboSearchQuery').returns('query');
+      visualSearch = {
+        searchBox: {
+          setQuery: sinon.spy()
+        }
+      };
+    });
+    afterEach(function() {
+      App.db.getComboSearchQuery.restore();
+    });
+
+    it('visualSearch.searchBox.setQuery should be called', function() {
+      view.restoreComboFilterQuery();
+      expect(visualSearch.searchBox.setQuery.calledWith('query')).to.be.true;
+    });
+  });
+
+  describe('#createFilterConditions', function() {
+
+    it('should return empty when no correct category passed', function() {
+      var searchCollection = {
+        models: [
+          {
+            attributes: {
+              category: 'wrong'
+            }
+          }
+        ]
+      };
+      expect(view.createFilterConditions(searchCollection)).to.be.empty;
+    });
+
+    it('should return filter condition when correct category passed', function() {
+      var searchCollection = {
+        models: [
+          {
+            attributes: {
+              category: view.get('keyFilterMap').mapProperty('label')[0],
+              value: 'val1'
+            }
+          }
+        ]
+      };
+      expect(view.createFilterConditions(searchCollection)).to.be.eql([
+        {
+          "iColumn": 1,
+          "skipFilter": false,
+          "type": "type1",
+          "value": 'val1'
+        }
+      ]);
+    });
+  });
+
+  describe('#mapLabelToValue', function() {
+    it('should return label', function() {
+      expect(view.mapLabelToValue('cat1', 'l1')).to.be.equal('l1');
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/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
index f5ff79c..4264f8a 100644
--- a/ambari-web/test/views/main/alerts/alert_search_box_test.js
+++ b/ambari-web/test/views/main/alerts/alert_search_box_test.js
@@ -26,37 +26,10 @@ describe('App.MainAlertDefinitionDetailsView', function () {
     view = App.MainAlertDefinitionSearchBoxView.create({
       controller: Em.Object.create()
     });
+    sinon.stub(view, 'rejectUsedValues').returns([]);
   });
-
-  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;
-    });
+  afterEach(function() {
+    view.rejectUsedValues.restore();
   });
 
   describe('#valueMatches', function() {
@@ -116,13 +89,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
   });
 
   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);
@@ -131,13 +97,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
   });
 
   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);
@@ -146,13 +105,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
   });
 
   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);
@@ -161,13 +113,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
   });
 
   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);
@@ -176,13 +121,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
   });
 
   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);
@@ -192,7 +130,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
 
   describe('#getGroupsAvailableValues', function() {
     beforeEach(function() {
-      sinon.stub(view, 'rejectUsedValues').returns([]);
       sinon.stub(App.AlertGroup, 'find').returns([
         Em.Object.create({
           id: 1,
@@ -201,7 +138,6 @@ describe('App.MainAlertDefinitionDetailsView', function () {
       ]);
     });
     afterEach(function() {
-      view.rejectUsedValues.restore();
       App.AlertGroup.find.restore();
     });
 
@@ -217,12 +153,12 @@ describe('App.MainAlertDefinitionDetailsView', function () {
 
   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');
+      expect(view.mapLabelToValue('enabled', 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);
+      expect(view.mapLabelToValue('groups', 'l1')).to.be.equal(1);
     });
 
     it('should return value of filter', function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/test/views/main/dashboard/config_history_search_box_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/dashboard/config_history_search_box_test.js b/ambari-web/test/views/main/dashboard/config_history_search_box_test.js
new file mode 100644
index 0000000..236d3df
--- /dev/null
+++ b/ambari-web/test/views/main/dashboard/config_history_search_box_test.js
@@ -0,0 +1,207 @@
+/**
+ * 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.MainConfigHistorySearchBoxView', function () {
+
+  beforeEach(function () {
+    view = App.MainConfigHistorySearchBoxView.create({
+      controller: Em.Object.create({
+        getSearchBoxSuggestions: function() {
+          return {
+            done: function(clb) {
+              clb([{}]);
+            }
+          }
+        }
+      })
+    });
+    sinon.stub(view, 'rejectUsedValues').returns([]);
+  });
+
+  afterEach(function() {
+    view.rejectUsedValues.restore();
+  });
+
+  describe('#valueMatches', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'showHideClearButton');
+      sinon.stub(view, 'getServiceVersionAvailableValues');
+      sinon.stub(view, 'getConfigGroupAvailableValues');
+      sinon.stub(view, 'getCreateTimeAvailableValues');
+      sinon.stub(view, 'getAuthorAvailableValues');
+      sinon.stub(view, 'getNotesAvailableValues');
+    });
+    afterEach(function() {
+      view.showHideClearButton.restore();
+      view.getServiceVersionAvailableValues.restore();
+      view.getConfigGroupAvailableValues.restore();
+      view.getCreateTimeAvailableValues.restore();
+      view.getAuthorAvailableValues.restore();
+      view.getNotesAvailableValues.restore();
+    });
+
+    it('showHideClearButton should be called', function() {
+      view.valueMatches(Em.I18n.t('common.service'));
+      expect(view.showHideClearButton.calledOnce).to.be.true;
+    });
+
+    it('getServiceVersionAvailableValues should be called', function() {
+      view.valueMatches(Em.I18n.t('common.service'), '', Em.K);
+      expect(view.getServiceVersionAvailableValues.calledWith(Em.I18n.t('common.service'))).to.be.true;
+    });
+
+    it('getConfigGroupAvailableValues should be called', function() {
+      view.valueMatches(Em.I18n.t('common.configGroup'), '', Em.K);
+      expect(view.getConfigGroupAvailableValues.calledWith(Em.I18n.t('common.configGroup'))).to.be.true;
+    });
+
+    it('getCreateTimeAvailableValues should be called', function() {
+      view.valueMatches(Em.I18n.t('dashboard.configHistory.table.created.title'), '', Em.K);
+      expect(view.getCreateTimeAvailableValues.calledWith(Em.I18n.t('dashboard.configHistory.table.created.title'))).to.be.true;
+    });
+
+    it('getAuthorAvailableValues should be called', function() {
+      view.valueMatches(Em.I18n.t('common.author'), '', Em.K);
+      expect(view.getAuthorAvailableValues.calledWith(Em.I18n.t('common.author'))).to.be.true;
+    });
+
+    it('getNotesAvailableValues should be called', function() {
+      view.valueMatches(Em.I18n.t('common.notes'), '', Em.K);
+      expect(view.getNotesAvailableValues.calledWith(Em.I18n.t('common.notes'))).to.be.true;
+    });
+  });
+
+  describe('#getServiceVersionAvailableValues', function() {
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getServiceVersionAvailableValues('', callback);
+      expect(callback.calledWith([], {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#getConfigGroupAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'requestFacetSuggestions');
+    });
+    afterEach(function() {
+      view.requestFacetSuggestions();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getConfigGroupAvailableValues('', callback);
+      expect(callback.calledWith([])).to.be.true;
+    });
+
+    it('requestFacetSuggestions should be called', function() {
+      var callback = sinon.spy();
+      view.getConfigGroupAvailableValues('', callback);
+      expect(view.requestFacetSuggestions.calledWith('', callback)).to.be.true;
+    });
+  });
+
+  describe('#getCreateTimeAvailableValues', function() {
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getCreateTimeAvailableValues('', callback);
+      expect(callback.calledWith([], {preserveOrder: true})).to.be.true;
+    });
+  });
+
+  describe('#getAuthorAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'requestFacetSuggestions');
+    });
+    afterEach(function() {
+      view.requestFacetSuggestions();
+    });
+
+    it('callback should be called', function () {
+      var callback = sinon.spy();
+      view.getAuthorAvailableValues('', callback);
+      expect(callback.calledWith([])).to.be.true;
+    });
+
+    it('requestFacetSuggestions should be called', function() {
+      var callback = sinon.spy();
+      view.getAuthorAvailableValues('', callback);
+      expect(view.requestFacetSuggestions.calledWith('', callback)).to.be.true;
+    });
+  });
+
+  describe('#getNotesAvailableValues', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'requestFacetSuggestions');
+    });
+    afterEach(function() {
+      view.requestFacetSuggestions();
+    });
+
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.getNotesAvailableValues('', callback);
+      expect(callback.calledWith([])).to.be.true;
+    });
+
+    it('requestFacetSuggestions should be called', function() {
+      var callback = sinon.spy();
+      view.getNotesAvailableValues('', callback);
+      expect(view.requestFacetSuggestions.calledWith('', callback)).to.be.true;
+    });
+  });
+
+  describe('#mapLabelToValue', function() {
+    beforeEach(function() {
+      sinon.stub(view, 'computeCreateTimeRange').returns([1,2]);
+      sinon.stub(App.StackService, 'find').returns([
+        Em.Object.create({
+          displayName: 's1',
+          serviceName: 'S1'
+        })
+      ]);
+    });
+    afterEach(function() {
+      view.computeCreateTimeRange.restore();
+      App.StackService.find.restore();
+    });
+
+    it('should return value of State filter', function() {
+      expect(view.mapLabelToValue('enabled', Em.I18n.t('alerts.table.state.enabled'))).to.be.equal(Em.I18n.t('alerts.table.state.enabled'));
+    });
+
+    it('should return value of createTime filter', function() {
+      expect(view.mapLabelToValue('createTime', 'l1')).to.be.eql([1, 2]);
+    });
+
+    it('should return value of serviceVersion filter', function() {
+      expect(view.mapLabelToValue('serviceVersion', 's1')).to.be.equal('S1');
+    });
+  });
+
+  describe('#requestFacetSuggestions', function() {
+    it('callback should be called', function() {
+      var callback = sinon.spy();
+      view.requestFacetSuggestions(view.get('keyFilterMap').mapProperty('label')[0], callback);
+      expect(callback.calledWith([{}])).to.be.true;
+    });
+  });
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/test/views/main/dashboard/config_history_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/dashboard/config_history_view_test.js b/ambari-web/test/views/main/dashboard/config_history_view_test.js
index da9ce31..a104e25 100644
--- a/ambari-web/test/views/main/dashboard/config_history_view_test.js
+++ b/ambari-web/test/views/main/dashboard/config_history_view_test.js
@@ -37,6 +37,7 @@ describe('App.MainConfigHistoryView', function() {
         }
       ],
       doPolling: Em.K,
+      updateFilter: Em.K,
       load: function () {
         return {done: Em.K};
       },
@@ -54,161 +55,6 @@ describe('App.MainConfigHistoryView', function() {
     });
   });
 
-  describe("#serviceFilterView", function () {
-    var subView = view.get('serviceFilterView').create({
-      parentView: view
-    });
-
-    before(function () {
-      sinon.stub(App.StackService, 'find').returns([Em.Object.create({
-        serviceName: 'S1',
-        displayName: 's1'
-      })])
-    });
-    after(function () {
-      App.StackService.find.restore();
-    });
-    it("content", function () {
-      expect(subView.get('content')).to.eql([
-        {
-          "value": "",
-          "label": Em.I18n.t('common.all')
-        },
-        {
-          "value": "S1",
-          "label": "s1"
-        }
-      ]);
-    });
-
-    before(function () {
-      sinon.stub(view, 'updateFilter', Em.K);
-    });
-    after(function () {
-      view.updateFilter.restore();
-    });
-    it("call onChangeValue()", function () {
-      subView.set('column', 1);
-      subView.set('value', 'value');
-      subView.onChangeValue();
-      expect(view.updateFilter.calledWith(1, 'value', 'select')).to.be.true;
-    });
-  });
-
-  describe("#configGroupFilterView", function () {
-    var subView = view.get('configGroupFilterView').create({
-      parentView: view
-    });
-
-    before(function () {
-      sinon.stub(App.ServiceConfigVersion, 'find').returns([
-        Em.Object.create({groupName: 'G1'}),
-        Em.Object.create({groupName: 'G1'}),
-        Em.Object.create({groupName: 'Default'}),
-        Em.Object.create({groupName: null})
-      ]);
-    });
-    after(function () {
-      App.ServiceConfigVersion.find.restore();
-    });
-    it("content", function () {
-      subView.observeContent();
-      expect(subView.get('content')).to.eql([
-        {
-          value: '',
-          label: Em.I18n.t('common.all')
-        },
-        {
-          value: 'G1',
-          label: 'G1'
-        },
-        {
-          value: 'Default',
-          label: 'Default'
-        }
-      ]);
-    });
-
-    before(function () {
-      sinon.stub(view, 'updateFilter', Em.K);
-    });
-    after(function () {
-      view.updateFilter.restore();
-    });
-    it("call onChangeValue()", function () {
-      subView.set('column', 1);
-      subView.set('value', 'value');
-      subView.onChangeValue();
-      expect(view.updateFilter.calledWith(1, 'value', 'select')).to.be.true;
-    });
-  });
-
-  /**
-   * for now we don't use this method
-  describe("#modifiedFilterView", function () {
-    var subView = view.get('modifiedFilterView').create({
-      parentView: view,
-      controller: {
-        modifiedFilter: {
-          actualValues: {
-            startTime: 0,
-            endTime: 1
-          }
-        }
-      }
-    });
-
-    before(function () {
-      sinon.stub(view, 'updateFilter', Em.K);
-    });
-    after(function () {
-      view.updateFilter.restore();
-    });
-    it("call onTimeChange()", function () {
-      subView.set('column', 1);
-      subView.onTimeChange();
-      expect(view.updateFilter.calledWith(1, [0, 1], 'range')).to.be.true;
-    });
-  });*/
-
-  describe("#authorFilterView", function () {
-    var subView = view.get('authorFilterView').create({
-      parentView: view
-    });
-
-    before(function () {
-      sinon.stub(view, 'updateFilter', Em.K);
-    });
-    after(function () {
-      view.updateFilter.restore();
-    });
-    it("call onChangeValue()", function () {
-      subView.set('column', 1);
-      subView.set('value', 'value');
-      subView.onChangeValue();
-      expect(view.updateFilter.calledWith(1, 'value', 'string')).to.be.true;
-    });
-  });
-
-  describe("#notesFilterView", function () {
-    var subView = view.get('notesFilterView').create({
-      parentView: view
-    });
-
-    before(function () {
-      sinon.stub(view, 'updateFilter', Em.K);
-    });
-    after(function () {
-      view.updateFilter.restore();
-    });
-    it("call onChangeValue()", function () {
-      subView.set('column', 1);
-      subView.set('value', 'value');
-      subView.onChangeValue();
-      expect(view.updateFilter.calledWith(1, 'value', 'string')).to.be.true;
-    });
-  });
-
   describe("#ConfigVersionView", function () {
     var subView;
     before(function () {
@@ -289,35 +135,6 @@ describe('App.MainConfigHistoryView', function() {
     });
   });
 
-  describe('#updateFilter()', function () {
-    var cases = [
-      {
-        isInitialRendering: false,
-        updateFilterCalled: true,
-        title: 'updateFilter should be called'
-      },
-      {
-        isInitialRendering: true,
-        updateFilterCalled: false,
-        title: 'updateFilter should not be called'
-      }
-    ];
-    beforeEach(function () {
-      sinon.stub(view, 'saveFilterConditions', Em.K);
-      view.set('filteringComplete', true);
-    });
-    afterEach(function () {
-      view.saveFilterConditions.restore();
-    });
-    cases.forEach(function (item) {
-      it(item.title, function () {
-        view.set('isInitialRendering', item.isInitialRendering);
-        view.updateFilter(1, 'value', 'string');
-        expect(view.get('saveFilterConditions').calledWith(1, 'value', 'string')).to.equal(item.updateFilterCalled);
-      });
-    });
-  });
-
   describe('#willDestroyElement()', function() {
     it('controller.isPolling is false', function() {
       view.willDestroyElement();
@@ -362,7 +179,4 @@ describe('App.MainConfigHistoryView', function() {
       expect(view.get('controller.resetStartIndex')).to.be.false;
     });
   });
-
-  App.TestAliases.testAsComputedAlias(view, 'colPropAssoc', 'controller.colPropAssoc', 'array');
-
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/479cf86a/ambari-web/test/views/main/host/combo_search_box_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/combo_search_box_test.js b/ambari-web/test/views/main/host/combo_search_box_test.js
index 0775f66..a59d845 100644
--- a/ambari-web/test/views/main/host/combo_search_box_test.js
+++ b/ambari-web/test/views/main/host/combo_search_box_test.js
@@ -94,11 +94,11 @@ describe('App.MainHostComboSearchBoxView', function () {
   describe("#search()", function () {
 
     beforeEach(function() {
-      view.set('parentView.parentView', Em.Object.create({
+      view.set('parentView', Em.Object.create({
         updateComboFilter: Em.K,
         controller: {name: 'ctrl1'}
       }));
-      sinon.stub(view.get('parentView.parentView'), 'updateComboFilter');
+      sinon.stub(view.get('parentView'), 'updateComboFilter');
       sinon.stub(view, 'createFilterConditions').returns([{}]);
       sinon.stub(view, 'clearErrMsg');
       sinon.stub(view, 'showErrMsg');
@@ -112,7 +112,7 @@ describe('App.MainHostComboSearchBoxView', function () {
       view.showErrMsg.restore();
       this.mockFacet.restore();
       view.createFilterConditions.restore();
-      view.get('parentView.parentView').updateComboFilter.restore();
+      view.get('parentView').updateComboFilter.restore();
     });
 
     it("clearErrMsg should be called", function() {
@@ -133,7 +133,7 @@ describe('App.MainHostComboSearchBoxView', function () {
 
     it("updateComboFilter should be called", function() {
       view.search('query', {});
-      expect(view.get('parentView.parentView').updateComboFilter.calledWith([{}])).to.be.true;
+      expect(view.get('parentView').updateComboFilter.calledWith([{}])).to.be.true;
     });
   });
 
@@ -576,64 +576,6 @@ describe('App.MainHostComboSearchBoxView', function () {
     });
   });
 
-  describe("#showHideClearButton()", function () {
-    var container = {
-      removeClass: Em.K,
-      addClass: Em.K
-    };
-
-    beforeEach(function() {
-      sinon.stub(window, '$').returns(container);
-      sinon.spy(container, 'removeClass');
-      sinon.spy(container, 'addClass');
-      this.mock = sinon.stub(visualSearch.searchQuery, 'toJSON');
-    });
-
-    afterEach(function() {
-      window.$.restore();
-      container.removeClass.restore();
-      container.addClass.restore();
-      visualSearch.searchQuery.toJSON.restore();
-    });
-
-    it("class should be added", function() {
-      this.mock.returns([]);
-      view.showHideClearButton();
-      expect(container.addClass.calledWith('hide')).to.be.true;
-    });
-
-    it("class should be removed", function() {
-      this.mock.returns(['f']);
-      view.showHideClearButton();
-      expect(container.removeClass.calledWith('hide')).to.be.true;
-    });
-  });
-
-  describe("#restoreComboFilterQuery()", function () {
-
-    beforeEach(function() {
-      this.mockQuery = sinon.stub(App.db, 'getComboSearchQuery');
-      sinon.stub(visualSearch.searchBox, 'setQuery');
-    });
-
-    afterEach(function() {
-      this.mockQuery.restore();
-      visualSearch.searchBox.setQuery.restore();
-    });
-
-    it("query is empty", function() {
-      this.mockQuery.returns('');
-      view.restoreComboFilterQuery();
-      expect(visualSearch.searchBox.setQuery.called).to.be.false;
-    });
-
-    it("query has value", function() {
-      this.mockQuery.returns('query');
-      view.restoreComboFilterQuery();
-      expect(visualSearch.searchBox.setQuery.calledWith('query')).to.be.true;
-    });
-  });
-
   describe("#getHostComponentList()", function () {
     var labelValueMap = {};