You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2017/01/23 18:27:12 UTC

ambari git commit: AMBARI-19678 Confirmation for adding host component from service summary page should be displayed once. (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk 796658f67 -> 3871f4a8d


AMBARI-19678 Confirmation for adding host component from service summary page should be displayed once. (ababiichuk)


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

Branch: refs/heads/trunk
Commit: 3871f4a8d31aff1f61bad695ec5eb884820638c0
Parents: 796658f
Author: ababiichuk <ab...@hortonworks.com>
Authored: Mon Jan 23 19:47:11 2017 +0200
Committer: ababiichuk <ab...@hortonworks.com>
Committed: Mon Jan 23 20:36:07 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/main/host/details.js | 202 +++++++++++++++----
 ambari-web/app/controllers/main/service/item.js |  58 +-----
 .../host/details/addDeleteComponentPopup.hbs    |  34 +++-
 .../templates/main/service/add_host_popup.hbs   |  33 ---
 .../test/controllers/main/host/details_test.js  | 144 +++++++++++--
 5 files changed, 317 insertions(+), 154 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3871f4a8/ambari-web/app/controllers/main/host/details.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/host/details.js b/ambari-web/app/controllers/main/host/details.js
index 1fcc14d..093603e 100644
--- a/ambari-web/app/controllers/main/host/details.js
+++ b/ambari-web/app/controllers/main/host/details.js
@@ -89,27 +89,32 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     'HIVE_METASTORE': {
       deletePropertyName: 'deleteHiveMetaStore',
       hostPropertyName: 'hiveMetastoreHost',
-      configsCallbackName: 'loadHiveConfigs'
+      configTagsCallbackName: 'loadHiveConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
     },
     'WEBHCAT_SERVER': {
       deletePropertyName: 'deleteWebHCatServer',
       hostPropertyName: 'webhcatServerHost',
-      configsCallbackName: 'loadWebHCatConfigs'
+      configTagsCallbackName: 'loadWebHCatConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
     },
     'HIVE_SERVER': {
       addPropertyName: 'addHiveServer',
       deletePropertyName: 'deleteHiveServer',
-      configsCallbackName: 'loadHiveConfigs'
+      configTagsCallbackName: 'loadHiveConfigs',
+      configsCallbackName: 'onLoadHiveConfigs'
     },
     'NIMBUS': {
       deletePropertyName: 'deleteNimbusHost',
       hostPropertyName: 'nimbusHost',
-      configsCallbackName: 'loadStormConfigs'
+      configTagsCallbackName: 'loadStormConfigs',
+      configsCallbackName: 'onLoadStormConfigs'
     },
     'RANGER_KMS_SERVER': {
       deletePropertyName: 'deleteRangerKMSServer',
       hostPropertyName: 'rangerKMSServerHost',
-      configsCallbackName: 'loadRangerConfigs'
+      configTagsCallbackName: 'loadRangerConfigs',
+      configsCallbackName: 'onLoadRangerConfigs'
     }
   },
 
@@ -158,6 +163,12 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   isReconfigureRequired: false,
 
   /**
+   * Contains component-related config properties loaded from server
+   * @type {Object|null}
+   */
+  configs: null,
+
+  /**
    * Array of all properties affected by adding/deleting host component
    * @type {Array}
    */
@@ -189,16 +200,38 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     manualKerberosWarning: App.get('router.mainAdminKerberosController.isManualKerberos') ?
       Em.I18n.t('hosts.host.manualKerberosWarning') : '',
     lastComponent: false,
-    lastComponentError: ''
+    lastComponentError: '',
+    hasHostsSelect: false,
+    selectedHost: null,
+    anyHostsWithoutComponent: true
   }),
 
-  clearConfigsChanges: function () {
+  saveLoadedConfigs: function (data) {
+    var configs = {
+      items: []
+    };
+    data.items.forEach(function (item) {
+      var configTypeObject = Em.getProperties(item, ['type', 'properties_attributes']),
+        properties = {};
+      Em.keys(item.properties).forEach(function (propertyName) {
+        properties[propertyName] = item.properties[propertyName];
+      });
+      configTypeObject.properties = properties;
+      configs.items.push(configTypeObject);
+    });
+    this.set('configs', configs);
+  },
+
+  clearConfigsChanges: function (shouldKeepLoadedConfigs) {
     var arrayNames = ['allPropertiesToChange', 'recommendedPropertiesToChange', 'requiredPropertiesToChange', 'groupedPropertiesToChange'];
     this.abortRequests();
     arrayNames.forEach(function (arrayName) {
       this.get(arrayName).clear();
     }, this);
     this.set('isReconfigureRequired', false);
+    if (!shouldKeepLoadedConfigs) {
+      this.set('configs', null);
+    }
   },
 
   applyConfigsCustomization: function () {
@@ -456,7 +489,6 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     var component = event.context;
     var componentName = component.get('componentName');
     var displayName = component.get('displayName');
-    var hostName = event.selectedHost || this.get('content.hostName');
     var returnFunc;
     var componentsMapItem = this.get('addDeleteComponentsMap')[componentName];
     if (componentsMapItem) {
@@ -465,7 +497,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       }
       this.clearConfigsChanges();
       this.set('isReconfigureRequired', true);
-      returnFunc = this.showDeleteComponentPopup(component, componentsMapItem.configsCallbackName);
+      returnFunc = this.showDeleteComponentPopup(component);
     } else if (componentName === 'JOURNALNODE') {
       returnFunc = App.showConfirmationPopup(function () {
         App.router.transitionTo('main.services.manageJournalNode');
@@ -476,18 +508,20 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     return returnFunc;
   },
 
-  showDeleteComponentPopup: function (component, callbackName) {
+  showDeleteComponentPopup: function (component) {
     var self = this,
       isLastComponent = (this.getTotalComponent(component) === 1),
       componentName = component.get('componentName'),
       componentDisplayName = component.get('displayName'),
-      commonMessage = Em.I18n.t('hosts.host.deleteComponent.popup.msg1').format(componentDisplayName);
-    if (this.get('isReconfigureRequired')) {
-      this.set('isConfigsLoadingInProgress', true);
-      this.isServiceMetricsLoaded(function () {
-        self.loadConfigs(callbackName);
-      });
+      componentsMapItem = this.get('addDeleteComponentsMap')[componentName],
+      commonMessage = Em.I18n.t('hosts.host.deleteComponent.popup.msg1').format(componentDisplayName),
+      configTagsCallbackName,
+      configsCallbackName;
+    if (componentsMapItem) {
+      configTagsCallbackName = componentsMapItem.configTagsCallbackName;
+      configsCallbackName = componentsMapItem.configsCallbackName;
     }
+    this.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
     return App.ModalPopup.show({
       header: Em.I18n.t('popup.confirmation.commonHeader'),
       controller: self,
@@ -711,9 +745,10 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       returnFunc,
       self = this,
       component = event.context,
-      hostName = event.selectedHost || this.get('content.hostName'),
+      hostName = this.get('content.hostName'),
       componentName = component.get('componentName'),
-      missedComponents = event.selectedHost ? [] : this.checkComponentDependencies(componentName, {
+      hasHostsSelect = event.hasOwnProperty('selectedHost'),
+      missedComponents = hasHostsSelect ? [] : this.checkComponentDependencies(componentName, {
         scope: 'host',
         installedComponents: this.get('content.hostComponents').mapProperty('componentName')
       }),
@@ -742,29 +777,40 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       }
       this.clearConfigsChanges();
       this.set('isReconfigureRequired', true);
-      returnFunc = self.showAddComponentPopup(component, hostName, null, componentsMapItem.configsCallbackName, primary);
+      returnFunc = self.showAddComponentPopup(component, hostName, null, primary, hasHostsSelect);
     } else if (componentName === 'JOURNALNODE') {
       returnFunc = App.showConfirmationPopup(function () {
         App.router.transitionTo('main.services.manageJournalNode');
       }, Em.I18n.t('hosts.host.addComponent.' + componentName) + manualKerberosWarning);
     } else {
       returnFunc = this.showAddComponentPopup(component, hostName, function () {
+        if (hasHostsSelect) {
+          hostName = self.get('content.hostName');
+        }
         self.installHostComponentCall(hostName, component);
-      });
+      }, null, hasHostsSelect);
     }
     return returnFunc;
   },
 
-  showAddComponentPopup: function (component, hostName, primary, callbackName, primaryOnReconfigure) {
+  showAddComponentPopup: function (component, hostName, primary, primaryOnReconfigure, hasHostsSelect) {
     var self = this,
       componentName = component.get('componentName'),
       componentDisplayName = component.get('displayName'),
-      commonMessage = Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName);
-    if (this.get('isReconfigureRequired')) {
-      this.set('isConfigsLoadingInProgress', true);
-      this.isServiceMetricsLoaded(function () {
-        self.loadConfigs(callbackName);
-      });
+      componentsMapItem = this.get('addDeleteComponentsMap')[componentName],
+      commonMessage = Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
+      configTagsCallbackName,
+      configsCallbackName;
+    if (componentsMapItem) {
+      configTagsCallbackName = componentsMapItem.configTagsCallbackName || 'loadConfigsSuccessCallback';
+      configsCallbackName = componentsMapItem.configsCallbackName || 'saveZkConfigs';
+    }
+    if (hasHostsSelect) {
+      if (this.get('isReconfigureRequired')) {
+        this.set('isConfigsLoadingInProgress', true);
+      }
+    } else {
+      this.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
     }
     return App.ModalPopup.show({
       header: Em.I18n.t('popup.confirmation.commonHeader'),
@@ -776,7 +822,51 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       }.property('controller.hasPropertiesToChange'),
       primary: Em.I18n.t('hosts.host.addComponent.popup.confirm'),
       bodyClass: self.get('addDeleteComponentPopupBody').extend({
-        commonMessage: commonMessage
+        commonMessage: commonMessage,
+        hasHostsSelect: hasHostsSelect,
+        addComponentMsg: Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
+        selectHostMsg: Em.I18n.t('services.summary.selectHostForComponent').format(componentDisplayName),
+        thereIsNoHostsMsg: Em.I18n.t('services.summary.allHostsAlreadyRunComponent').format(componentDisplayName),
+        hostsWithoutComponent: function () {
+          if (this.get('hasHostsSelect')) {
+            var hostsWithComponent = App.HostComponent.find().filterProperty('componentName', componentName).mapProperty('hostName'),
+              result = App.get('allHostNames');
+            hostsWithComponent.forEach(function (host) {
+              result = result.without(host);
+            });
+            return result;
+          } else {
+            return [];
+          }
+        }.property('hasHostsSelect'),
+        anyHostsWithoutComponent: Em.computed.or('!hasHostsSelect', 'hostsWithoutComponent.length'),
+        selectedHostObserver: function () {
+          hostName = this.get('selectedHost');
+          self.clearConfigsChanges(true);
+          if (!self.get('content')) {
+            self.set('content', {});
+          }
+          self.setProperties({
+            'isReconfigureRequired': !!componentsMapItem,
+            'content.hostName': hostName
+          });
+          if (componentsMapItem) {
+            var configs = self.get('configs'),
+              params = configs && configs.params || {};
+            if (componentsMapItem.hostPropertyName) {
+              self.set(componentsMapItem.hostPropertyName, hostName);
+            }
+            if (componentsMapItem.addPropertyName) {
+              self.set(componentsMapItem.addPropertyName, true);
+            }
+            if (configs) {
+              this.set('isConfigsLoadingInProgress', true);
+              self[configsCallbackName](configs, null, params);
+            } else {
+              self.loadComponentRelatedConfigs(configTagsCallbackName, configsCallbackName);
+            }
+          }
+        }.observes('selectedHost')
       }),
       disablePrimary: Em.computed.and('controller.isReconfigureRequired', 'controller.isConfigsLoadingInProgress'),
       onPrimary: function () {
@@ -803,6 +893,16 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     });
   },
 
+  loadComponentRelatedConfigs: function (configTagsCallbackName, configsCallbackName) {
+    var self = this;
+    if (this.get('isReconfigureRequired')) {
+      this.set('isConfigsLoadingInProgress', true);
+      this.isServiceMetricsLoaded(function () {
+        self.loadConfigs(configTagsCallbackName, configsCallbackName);
+      });
+    }
+  },
+
   /**
    * Success callback for install host component request (sent in <code>addNewComponentSuccessCallback</code>)
    * @param {object} data
@@ -870,16 +970,18 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for Storm load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadStormConfigs
    */
-  loadStormConfigs: function (data) {
+  loadStormConfigs: function (data, opt, params) {
     var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
         urlParams: '(type=storm-site&tag=' + data.Clusters.desired_configs['storm-site'].tag + ')'
       },
-      success: 'onLoadStormConfigs'
+      success: params.callback
     });
     this.trackRequest(request);
   },
@@ -975,6 +1077,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       attributes = {},
       propertiesToChange = this.get('allPropertiesToChange');
 
+    this.saveLoadedConfigs(data);
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
@@ -1015,9 +1118,11 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadWebHCatConfigs
    */
-  loadWebHCatConfigs: function (data) {
+  loadWebHCatConfigs: function (data, opt, params) {
     var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
@@ -1030,7 +1135,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
         ].join('|')
       },
-      success: 'onLoadHiveConfigs'
+      success: params.callback
     });
     this.trackRequest(request);
     return request;
@@ -1043,7 +1148,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * @param {object} params
    * @method loadHiveConfigs
    */
-  loadHiveConfigs: function (data) {
+  loadHiveConfigs: function (data, opt, params) {
     var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
@@ -1055,7 +1160,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
           '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')'
         ].join('|')
       },
-      success: 'onLoadHiveConfigs'
+      success: params.callback
     });
     this.trackRequest(request);
     return request;
@@ -1082,6 +1187,10 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       hiveMetastorePort: ""
     };
     var initializer = params.webHCat ? App.AddWebHCatComponentsInitializer : App.AddHiveComponentsInitializer;
+    this.saveLoadedConfigs(data);
+    this.set('configs.params', {
+      webHCat: params.webHCat
+    });
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
@@ -1275,16 +1384,18 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadRangerConfigs
    */
-  loadRangerConfigs: function (data) {
+  loadRangerConfigs: function (data, opt, params) {
     var request = App.ajax.send({
       name: 'admin.get.all_configurations',
       sender: this,
       data: {
         urlParams: '(type=core-site&tag=' + data.Clusters.desired_configs['core-site'].tag + ')|(type=hdfs-site&tag=' + data.Clusters.desired_configs['hdfs-site'].tag + ')|(type=kms-env&tag=' + data.Clusters.desired_configs['kms-env'].tag + ')'
       },
-      success: 'onLoadRangerConfigs'
+      success: params.callback
     });
     this.trackRequest(request);
   },
@@ -1325,6 +1436,8 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
       ],
       propertiesToChange = this.get('allPropertiesToChange');
 
+    this.saveLoadedConfigs(data);
+
     properties.forEach(function (property) {
       var typeConfigs = data.items.findProperty('type', property.type).properties,
         currentValue = typeConfigs[property.name],
@@ -1453,11 +1566,14 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
    * This is required to make sure that service metrics API determining the HA state of components is loaded
    * @method loadConfigs
    */
-  loadConfigs: function (callback) {
+  loadConfigs: function (configTagsCallback, configsCallback) {
     var request = App.ajax.send({
       name: 'config.tags',
       sender: this,
-      success: callback ? callback : 'loadConfigsSuccessCallback',
+      data: {
+        callback: configsCallback || 'saveZkConfigs'
+      },
+      success: configTagsCallback || 'loadConfigsSuccessCallback',
       error: 'onLoadConfigsErrorCallback'
     });
     this.trackRequest(request);
@@ -1474,9 +1590,11 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   /**
    * Success callback for load configs request
    * @param {object} data
+   * @param {object} opt
+   * @param {object} params
    * @method loadConfigsSuccessCallback
    */
-  loadConfigsSuccessCallback: function (data) {
+  loadConfigsSuccessCallback: function (data, opt, params) {
     var urlParams = this.constructConfigUrlParams(data);
     if (urlParams.length > 0) {
       var request = App.ajax.send({
@@ -1485,7 +1603,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
         data: {
           urlParams: urlParams.join('|')
         },
-        success: 'saveZkConfigs'
+        success: params.callback || 'saveZkConfigs'
       });
       this.trackRequest(request);
       return true;
@@ -1524,6 +1642,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   saveZkConfigs: function (data) {
     var configs = {};
     var attributes = {};
+    this.saveLoadedConfigs(data);
     data.items.forEach(function (item) {
       configs[item.type] = item.properties;
       attributes[item.type] = item.properties_attributes || {};
@@ -2524,7 +2643,6 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
     });
   },
   deleteHostSuccessCallback: function (data, rq, requestBody) {
-    var self = this;
     App.router.get('updateController').updateHost(function () {
       App.router.transitionTo('hosts.index');
     });
@@ -2535,7 +2653,7 @@ App.MainHostDetailsController = Em.Controller.extend(App.SupportClientConfigsDow
   deleteHostErrorCallback: function (xhr, textStatus, errorThrown, opt) {
     xhr.responseText = "{\"message\": \"" + xhr.statusText + "\"}";
     var self = this;
-    var callback =   function () {
+    var callback = function () {
       self.loadConfigs();
     };
     self.isServiceMetricsLoaded(callback);

http://git-wip-us.apache.org/repos/asf/ambari/blob/3871f4a8/ambari-web/app/controllers/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index 3a60137..9758ac3 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -937,63 +937,15 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
    * @param componentName
    */
   addComponent: function (componentName) {
-    var self = this;
     var component = App.StackServiceComponent.find().findProperty('componentName', componentName);
-    var componentDisplayName = component.get('displayName');
 
     App.get('router.mainAdminKerberosController').getKDCSessionState(function () {
-      return App.ModalPopup.show({
-        primary: Em.computed.ifThenElse('anyHostsWithoutComponent', Em.I18n.t('hosts.host.addComponent.popup.confirm'), undefined),
-
-        header: Em.I18n.t('popup.confirmation.commonHeader'),
-
-        addComponentMsg: Em.I18n.t('hosts.host.addComponent.msg').format(componentDisplayName),
-
-        selectHostMsg: Em.computed.i18nFormat('services.summary.selectHostForComponent', 'componentDisplayName'),
-
-        thereIsNoHostsMsg: Em.computed.i18nFormat('services.summary.allHostsAlreadyRunComponent', 'componentDisplayName'),
-
-        hostsWithoutComponent: function () {
-          var hostsWithComponent = App.HostComponent.find().filterProperty('componentName', componentName).mapProperty('hostName');
-          var result = App.get('allHostNames');
-
-          hostsWithComponent.forEach(function (host) {
-            result = result.without(host);
-          });
-
-          return result;
-        }.property(),
-
-        anyHostsWithoutComponent: Em.computed.gt('hostsWithoutComponent.length', 0),
-
-        selectedHost: null,
-
-        componentName: componentName,
-
-        componentDisplayName: componentDisplayName,
-
-        bodyClass: Em.View.extend({
-          templateName: require('templates/main/service/add_host_popup')
-        }),
-
-        onPrimary: function () {
-          var selectedHost = this.get('selectedHost');
-
-          // Install
-          if (['HIVE_METASTORE', 'RANGER_KMS_SERVER', 'NIMBUS'].contains(component.get('componentName')) && !!selectedHost) {
-            App.router.get('mainHostDetailsController').addComponentWithCheck(
-                {
-                  context: component,
-                  selectedHost: selectedHost
-                }
-            );
-          } else {
-            self.installHostComponentCall(selectedHost, component);
-          }
-
-          this.hide();
+      App.router.get('mainHostDetailsController').addComponentWithCheck(
+        {
+          context: component,
+          selectedHost: null
         }
-      });
+      );
     });
   },
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/3871f4a8/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs b/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
index ed8445e..2aa5e71 100644
--- a/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
+++ b/ambari-web/app/templates/main/host/details/addDeleteComponentPopup.hbs
@@ -24,17 +24,29 @@
     </div>
   </div>
 {{/if}}
-{{#if controller.isReconfigureRequired}}
-  {{#if controller.isConfigsLoadingInProgress}}
-    {{view App.SpinnerView}}
-  {{else}}
-    {{view.commonMessage}}
-    {{#if controller.hasPropertiesToChange}}
-      {{view App.DependentConfigsListView isAfterRecommendation=false recommendationsBinding="controller.recommendedPropertiesToChange" requiredChangesBinding="controller.requiredPropertiesToChange"}}
+{{#if view.anyHostsWithoutComponent}}
+  {{#if view.hasHostsSelect}}
+    <div>{{view.selectHostMsg}}</div>
+    <div class="row">
+      <div class="col-md-12">
+        {{view Ember.Select contentBinding="view.hostsWithoutComponent" selectionBinding="view.selectedHost" classNames="form-control"}}
+      </div>
+    </div>
+  {{/if}}
+  {{#if controller.isReconfigureRequired}}
+    {{#if controller.isConfigsLoadingInProgress}}
+      {{view App.SpinnerView}}
+    {{else}}
+      {{view.commonMessage}}
+      {{#if controller.hasPropertiesToChange}}
+        {{view App.DependentConfigsListView isAfterRecommendation=false recommendationsBinding="controller.recommendedPropertiesToChange" requiredChangesBinding="controller.requiredPropertiesToChange"}}
+      {{/if}}
+      {{{view.manualKerberosWarning}}}
     {{/if}}
-    {{{view.manualKerberosWarning}}}
+  {{else}}
+    <div>{{view.commonMessage}}</div>
+    <div>{{{view.manualKerberosWarning}}}</div>
   {{/if}}
 {{else}}
-  <div>{{view.commonMessage}}</div>
-  <div>{{{view.manualKerberosWarning}}}</div>
-{{/if}}
+  {{view.thereIsNoHostsMsg}}
+{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/3871f4a8/ambari-web/app/templates/main/service/add_host_popup.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/add_host_popup.hbs b/ambari-web/app/templates/main/service/add_host_popup.hbs
deleted file mode 100644
index e5f2c99..0000000
--- a/ambari-web/app/templates/main/service/add_host_popup.hbs
+++ /dev/null
@@ -1,33 +0,0 @@
-{{!
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-}}
-
-{{#if anyHostsWithoutComponent}}
-  <p>{{selectHostMsg}}</p>
-  <div class="row">
-    <div class="col-md-12">
-      {{view Ember.Select contentBinding="hostsWithoutComponent" selectionBinding="selectedHost" classNames="form-control"}}
-    </div>
-  </div>
-  <div class="row">
-    <div class="col-md-12">
-      <p>{{addComponentMsg}}</p>
-    </div>
-  </div>
-{{else}}
-  <p>{{thereIsNoHostsMsg}}</p>
-{{/if}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/3871f4a8/ambari-web/test/controllers/main/host/details_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/host/details_test.js b/ambari-web/test/controllers/main/host/details_test.js
index ff5887c..4eccf95 100644
--- a/ambari-web/test/controllers/main/host/details_test.js
+++ b/ambari-web/test/controllers/main/host/details_test.js
@@ -594,7 +594,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -619,6 +619,7 @@ describe('App.MainHostDetailsController', function () {
       sinon.stub(controller, 'getStormNimbusHosts').returns("host1");
       sinon.stub(controller, 'updateZkConfigs', Em.K);
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
       controller.set('nimbusHost', 'host2');
       controller.onLoadStormConfigs(data);
     });
@@ -626,6 +627,7 @@ describe('App.MainHostDetailsController', function () {
       controller.getStormNimbusHosts.restore();
       controller.updateZkConfigs.restore();
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
     it("updateZkConfigs called with valid arguments", function() {
       expect(controller.updateZkConfigs.calledWith({'storm-site': {
@@ -665,7 +667,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -689,7 +691,7 @@ describe('App.MainHostDetailsController', function () {
             tag: 'tag'
           }
         }
-      }});
+      }}, null, {});
       var args = testHelpers.findAjaxRequest('name', 'admin.get.all_configurations');
       expect(args[0]).exists;
       expect(args[0].sender).to.be.eql(controller);
@@ -952,7 +954,7 @@ describe('App.MainHostDetailsController', function () {
     });
 
     it('url params is empty', function () {
-      expect(controller.loadConfigsSuccessCallback()).to.be.false;
+      expect(controller.loadConfigsSuccessCallback(null, null, {})).to.be.false;
       var args = testHelpers.findAjaxRequest('name', 'reassign.load_configs');
       expect(args).not.exists;
     });
@@ -1018,6 +1020,7 @@ describe('App.MainHostDetailsController', function () {
     beforeEach(function () {
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
       sinon.stub(controller, 'updateZkConfigs', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
       sinon.stub(App.Service, 'find', function() {
         return [
           Em.Object.create({ serviceName: 'HIVE' }),
@@ -1034,6 +1037,7 @@ describe('App.MainHostDetailsController', function () {
       App.Service.find.restore();
       controller.updateZkConfigs.restore();
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
       it('configs for YARN', function () {
@@ -3270,11 +3274,13 @@ describe('App.MainHostDetailsController', function () {
     ];
 
     beforeEach(function () {
-      sinon.spy(controller, 'saveConfigsBatch')
+      sinon.spy(controller, 'saveConfigsBatch');
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
     });
 
     afterEach(function () {
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
     cases.forEach(function (item) {
@@ -3518,10 +3524,13 @@ describe('App.MainHostDetailsController', function () {
 
     beforeEach(function() {
       sinon.stub(controller, 'saveConfigsBatch', Em.K);
+      sinon.stub(controller, 'saveLoadedConfigs', Em.K);
+      controller.set('configs', {});
     });
 
     afterEach(function() {
       controller.saveConfigsBatch.restore();
+      controller.saveLoadedConfigs.restore();
     });
 
     var makeHostComponentModel = function(componentName, hostNames) {
@@ -3960,29 +3969,134 @@ describe('App.MainHostDetailsController', function () {
         recommendedPropertiesToChange: [{}],
         requiredPropertiesToChange: [{}],
         groupedPropertiesToChange: [{}],
-        isReconfigureRequired: true
+        isReconfigureRequired: true,
+        configs: {}
       });
-      controller.clearConfigsChanges();
     });
 
     afterEach(function () {
       controller.abortRequests.restore();
     });
 
-    it('allPropertiesToChange', function () {
-      expect(controller.get('allPropertiesToChange')).to.have.length(0);
+    describe('default case', function () {
+
+      beforeEach(function () {
+        controller.clearConfigsChanges();
+      });
+
+      it('allPropertiesToChange', function () {
+        expect(controller.get('allPropertiesToChange')).to.have.length(0);
+      });
+
+      it('recommendedPropertiesToChange', function () {
+        expect(controller.get('recommendedPropertiesToChange')).to.have.length(0);
+      });
+
+      it('groupedPropertiesToChange', function () {
+        expect(controller.get('groupedPropertiesToChange')).to.have.length(0);
+      });
+
+      it('isReconfigureRequired', function () {
+        expect(controller.get('isReconfigureRequired')).to.be.false;
+      });
+
+      it('configs', function () {
+        expect(controller.get('configs')).to.be.null;
+      });
+
     });
 
-    it('recommendedPropertiesToChange', function () {
-      expect(controller.get('recommendedPropertiesToChange')).to.have.length(0);
+    describe('no loaded configs cleanup', function () {
+
+      beforeEach(function () {
+        controller.clearConfigsChanges(true);
+      });
+
+      it('configs shouldn\'t be cleared', function () {
+        expect(controller.get('configs')).to.not.be.null;
+      });
+
     });
 
-    it('groupedPropertiesToChange', function () {
-      expect(controller.get('groupedPropertiesToChange')).to.have.length(0);
+  });
+
+  describe('#saveLoadedConfigs', function () {
+
+    var data = {
+      items: [
+        {
+          type: 't0',
+          properties: {
+            p0: 'v0',
+            p1: 'v1'
+          },
+          properties_attributes: {}
+        },
+        {
+          type: 't1',
+          properties: {
+            p2: 'v2',
+            p3: 'v3'
+          },
+          properties_attributes: {}
+        }
+      ]
+    };
+
+    it('should store data in configs object', function () {
+      controller.set('configs', null);
+      controller.saveLoadedConfigs(data);
+      expect(controller.get('configs')).to.eql(data);
     });
 
-    it('isReconfigureRequired', function () {
-      expect(controller.get('isReconfigureRequired')).to.be.false;
+  });
+
+  describe('#loadComponentRelatedConfigs', function () {
+
+    var testCases = [
+      {
+        isReconfigureRequired: true,
+        loadConfigsCallCount: 1,
+        isConfigsLoadingInProgress: true,
+        message: 'reconfigure required'
+      },
+      {
+        isReconfigureRequired: false,
+        loadConfigsCallCount: 0,
+        isConfigsLoadingInProgress: false,
+        message: 'no reconfigure required'
+      }
+    ];
+
+    testCases.forEach(function (test) {
+
+      describe(test.message, function () {
+
+        beforeEach(function () {
+          sinon.stub(controller, 'isServiceMetricsLoaded', Em.clb);
+          sinon.stub(controller, 'loadConfigs', Em.K);
+          controller.setProperties({
+            isReconfigureRequired: test.isReconfigureRequired,
+            isConfigsLoadingInProgress: false
+          });
+          controller.loadComponentRelatedConfigs();
+        });
+
+        afterEach(function () {
+          controller.isServiceMetricsLoaded.restore();
+          controller.loadConfigs.restore();
+        });
+
+        it('loadConfigs', function () {
+          expect(controller.loadConfigs.callCount).to.equal(test.loadConfigsCallCount);
+        });
+
+        it('isConfigsLoadingInProgress', function () {
+          expect(controller.get('isConfigsLoadingInProgress')).to.equal(test.isConfigsLoadingInProgress);
+        });
+
+      });
+
     });
 
   });