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 2015/03/24 14:53:21 UTC

ambari git commit: AMBARI-10156 Editing configs with depended-by configs should trigger call to /recommendations (additional 2). (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk fd5e6e682 -> 3b8e577db


AMBARI-10156 Editing configs with depended-by configs should trigger call to /recommendations (additional 2). (ababiichuk)


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

Branch: refs/heads/trunk
Commit: 3b8e577dba282d97f3e8dd511d520aac29cf1629
Parents: fd5e6e6
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Tue Mar 24 13:04:47 2015 +0200
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Tue Mar 24 15:52:15 2015 +0200

----------------------------------------------------------------------
 .../controllers/main/service/info/configs.js    | 188 ++++++++++++-------
 .../mixins/common/configs/enhanced_configs.js   |  34 +---
 ambari-web/app/mixins/common/serverValidator.js |  26 +--
 ambari-web/app/models/cluster_states.js         |  22 ++-
 .../app/templates/main/service/info/configs.hbs |   2 +-
 .../views/common/configs/config_history_flow.js |   2 +-
 .../configs/service_configs_by_category_view.js |   8 +-
 ambari-web/app/views/common/controls_view.js    |  34 +++-
 .../dependent_configs_list_popup.js             |  41 ++--
 .../common/configs/enhanced_configs_test.js     |  29 ++-
 10 files changed, 226 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/controllers/main/service/info/configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/info/configs.js b/ambari-web/app/controllers/main/service/info/configs.js
index be086ac..4fb538f 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -41,7 +41,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   configGroups: [],
   allConfigs: [],
   uiConfigs: [],
-  isApplyingChanges: false,
+  saveInProgress: false,
   saveConfigsFlag: true,
   isCompareMode: false,
   compareServiceVersion: null,
@@ -65,13 +65,18 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   }.property('selectedVersion', 'content.serviceName', 'dataIsLoaded'),
 
   /**
-   * @type {[Object]} that will contain items like
-   *{
-   *  "type": "yarn-site",
-   *  "name": "yarn.nodemanager.resource.memory-mb"
-   *}
+   * array that contains config properties that were changed and
+   * belongs to not current service
+   * @returns {*|Array}
    */
-  changedConfigWithDependencies: [],
+  unsavedDependentConfigs: function() {
+    return App.ConfigProperty.find().filter(function(cp) {
+      return cp.get('stackConfigProperty.serviceName') !== this.get('content.serviceName')
+        && this.get('dependentFileNames').contains(cp.get('fileName'))
+        && cp.get('isNotDefaultValue');
+    }, this);
+  },
+
   /**
    * @type {boolean}
    */
@@ -111,8 +116,8 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   loadedClusterSiteToTagMap: {},
 
   isSubmitDisabled: function () {
-    return (!(this.get('stepConfigs').everyProperty('errorCount', 0)) || this.get('isApplyingChanges'));
-  }.property('stepConfigs.@each.errorCount', 'isApplyingChanges'),
+    return (!(this.get('stepConfigs').everyProperty('errorCount', 0)) || this.get('saveInProgress'));
+  }.property('stepConfigs.@each.errorCount', 'saveInProgress'),
 
   isPropertiesChanged: function(){
     return this.get('stepConfigs').someProperty('isPropertiesChanged', true);
@@ -212,7 +217,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       this.get('requestInProgress').abort();
       this.set('requestInProgress', null);
     }
-    this.set("isApplyingChanges", false);
+    this.set("saveInProgress", false);
     this.set('modifiedFileNames', []);
     this.set('isInit', true);
     this.set('hash', null);
@@ -1199,31 +1204,71 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   },
 
   /**
-   * Initialize save configs popup
+   * tells controller in saving configs was started
+   * for now just changes flag <code>saveInProgress<code> to true
    */
-  restartServicePopup: function () {
-    if (this.get("isSubmitDisabled")) {
-      return;
+  startSave: function() {
+    this.set("saveInProgress", true);
+  },
+
+  /**
+   * tells controller that save has been finished
+   * for now just changes flag <code>saveInProgress<code> to true
+   */
+  completeSave: function() {
+    this.set("saveInProgress", false);
+  },
+
+  /**
+   * method to run saving configs
+   * @method saveStepConfigs
+   */
+  saveStepConfigs: function() {
+    if (!this.get("isSubmitDisabled")) {
+      this.startSave();
+      this.showWarningPopupsBeforeSave();
+    }
+  },
+
+  /**
+   * show some warning popups before user save configs
+   * @method showWarningPopupsBeforeSave
+   */
+  showWarningPopupsBeforeSave: function() {
+    var displayName = this.get('content.displayName');
+    if (this.isDirChanged()) {
+      App.showConfirmationPopup(this.showDependenciesAndSave.bind(this),
+        Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName),
+        this.completeSave.bind(this)
+      );
+    } else {
+      this.showDependenciesAndSave();
     }
-    this.set("isApplyingChanges", true);
-    var self = this;
-    var header, message, messageClass, status;
-    var serviceName = this.get('content.serviceName'),
-      displayName = this.get('content.displayName'),
-      urlParams = '';
-    this.serverSideValidation().done(function () {
-      if (self.isDirChanged()) {
-        App.showConfirmationPopup(function () {
-          self.saveConfigs();
-        }, Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName), function () {
-          self.set('isApplyingChanges', false);
-        });
-      } else {
-        self.saveConfigs();
-      }
-    }).fail(function () {
-      self.set('isApplyingChanges', false);
-    });
+  },
+
+  /**
+   * if there are some dependent configs in different services
+   * this popup will be shown with info about this configs
+   * @method showDependenciesAndSave
+   */
+  showDependenciesAndSave: function() {
+    var dependentConfigs = this.unsavedDependentConfigs();
+    if (dependentConfigs.length > 0) {
+      App.showDependentConfigsPopup(dependentConfigs,
+        this.restartServicePopup.bind(this),
+        this.completeSave.bind(this));
+    } else {
+      this.restartServicePopup();
+    }
+  },
+
+  /**
+   * Runs config validation before save
+   */
+  restartServicePopup: function () {
+    this.serverSideValidation()
+      .done(this.saveConfigs.bind(this))
+      .fail(this.completeSave.bind(this));
   },
 
   /**
@@ -1264,48 +1309,45 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
         } else if (this.get('content.serviceName') === 'OOZIE') {
           this.setOozieHostName(configs);
         }
-      }
 
-      /**
-       * generates list of properties that was changed
-       * @type {Array}
-       */
-      var modifiedProperties = configs
-        // get only modified and created configs
-        .filter(function(config) { return config.get('isNotDefaultValue') || config.get('isNotSaved'); });
+        this.loadConfigsToModel(configs, self.get('selectedVersion'));
 
-      if (App.get('supports.enhancedConfigs')) {
-        this.loadStepConfigsToModel(modifiedProperties, self.get('selectedVersion'));
-      }
-      this.getRecommendationsForDependencies(this.get('changedConfigWithDependencies')).done(function() {
-
-        if (App.get('supports.enhancedConfigs')) {
-          self.saveEnhancedConfigs();
-        } else {
+        this.saveEnhancedConfigs();
 
-          var modifiedConfigs = modifiedProperties
-            // get file names and add file names that was modified, for example after property removing
-            .mapProperty('filename').concat(self.get('modifiedFileNames')).uniq()
-            // get configs by filename
-            .map(function(fileName) {
-              return configs.filterProperty('filename', fileName);
-            });
+      } else {
+        /**
+         * generates list of properties that was changed
+         * @type {Array}
+         */
+        var modifiedConfigs = configs
+          // get only modified and created configs
+          .filter(function (config) {
+            return config.get('isNotDefaultValue') || config.get('isNotSaved');
+          })
+          // get file names and add file names that was modified, for example after property removing
+          .mapProperty('filename').concat(this.get('modifiedFileNames')).uniq()
+          // get configs by filename
+          .map(function (fileName) {
+            return configs.filterProperty('filename', fileName);
+          });
 
-          if (!!modifiedConfigs.length) {
-            // concatenate results
-            modifiedConfigs = modifiedConfigs.reduce(function(current, prev) { return current.concat(prev); });
-          }
-          // save modified original configs that have no group
-          self.saveSiteConfigs(modifiedConfigs.filter(function(config) { return !config.get('group'); }));
-
-          /**
-           * First we put cluster configurations, which automatically creates /configurations
-           * resources. Next we update host level overrides.
-           */
-          self.doPUTClusterConfigurations();
+        if (!!modifiedConfigs.length) {
+          // concatenate results
+          modifiedConfigs = modifiedConfigs.reduce(function (current, prev) {
+            return current.concat(prev);
+          });
         }
-      });
+        // save modified original configs that have no group
+        this.saveSiteConfigs(modifiedConfigs.filter(function (config) {
+          return !config.get('group');
+        }));
 
+        /**
+         * First we put cluster configurations, which automatically creates /configurations
+         * resources. Next we update host level overrides.
+         */
+        this.doPUTClusterConfigurations();
+      }
     } else {
       var overridenConfigs = [];
       var groupHosts = [];
@@ -1318,7 +1360,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
 
       if (App.get('supports.enhancedConfigs')) {
 
-        this.loadStepConfigsToModel(overridenConfigs, this.get('selectedVersion'));
+        this.loadConfigsToModel(overridenConfigs, this.get('selectedVersion'));
 
         this.saveEnhancedConfigsAndGroup(this.get('selectedConfigGroup'));
 
@@ -1405,12 +1447,12 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       onPrimary: function () {
         this.hide();
         if (!flag) {
-          self.set('isApplyingChanges', false);
+          self.completeSave();
         }
       },
       onClose: function () {
         this.hide();
-        self.set('isApplyingChanges', false);
+        self.completeSave();
       },
       disablePrimary: true,
       bodyClass: Ember.View.extend({
@@ -2828,7 +2870,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       secondary: Em.I18n.t('common.cancel'),
       onSave: function () {
         self.set('serviceConfigVersionNote', this.get('serviceConfigNote'));
-        self.restartServicePopup();
+        self.saveStepConfigs();
         this.hide();
       },
       onDiscard: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/mixins/common/configs/enhanced_configs.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/enhanced_configs.js b/ambari-web/app/mixins/common/configs/enhanced_configs.js
index ea8c6b1..a661ddb 100644
--- a/ambari-web/app/mixins/common/configs/enhanced_configs.js
+++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js
@@ -63,36 +63,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
   },
 
   /**
-   *
-   * @param modifiedProperties
-   * @param versionNumber
-   */
-  loadStepConfigsToModel: function(modifiedProperties, versionNumber) {
-
-    this.loadConfigsToModel(modifiedProperties, versionNumber);
-
-    this.generateChangedConfigWithDependencies();
-
-  },
-
-  /**
-   * generates <code>changedConfigWithDependencies<code>
-   * this array will be send for recommendations as <code>changed_configurations<code>
-   * @method generateChangedConfigWithDependencies
-   */
-  generateChangedConfigWithDependencies: function() {
-    App.ConfigProperty.find().forEach(function(cp) {
-      if (cp.get('isNotDefaultValue') && cp.get('stackConfigProperty.propertyDependedBy.length') > 0) {
-        this.get('changedConfigWithDependencies').push({
-          "type": cp.get('fileName'),
-          "name": cp.get("name")
-        });
-      }
-    }, this);
-  },
-
-
-  /**
    * generates data and save configs for default group
    * @method saveEnhancedConfigs
    */
@@ -143,7 +113,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
   },
 
   /**
-   * get file names that need t obe saved
+   * get file names that need to be saved
    * @param {Array} modifiedFileNames
    * @returns {Ember.Enumerable}
    */
@@ -161,7 +131,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
   getConfigsToSave: function(fileNamesToSave) {
     if (Em.isArray(fileNamesToSave) && fileNamesToSave.length) {
       return App.ConfigProperty.find().filter(function(cp) {
-        return fileNamesToSave.contains(cp.get('fileName'));
+        return (fileNamesToSave.contains(cp.get('fileName')) && cp.get('isOriginalSCP')) || cp.get('isNotSaved');
       });
     } else {
       return Em.A([]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/mixins/common/serverValidator.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/serverValidator.js b/ambari-web/app/mixins/common/serverValidator.js
index bc4dd59..4c89182 100644
--- a/ambari-web/app/mixins/common/serverValidator.js
+++ b/ambari-web/app/mixins/common/serverValidator.js
@@ -137,9 +137,9 @@ App.ServerValidatorMixin = Em.Mixin.create({
   /**
    *
    * @param changedConfigs
+   * @returns {$.ajax|null}
    */
   getRecommendationsForDependencies: function(changedConfigs) {
-    var dfd = $.Deferred();
     if (Em.isArray(changedConfigs) && changedConfigs.length > 0) {
       var recommendations = this.get('hostGroups');
       recommendations.blueprint.configurations = blueprintUtils.buildConfigsJSON(this.get('services'), this.get('stepConfigs'));
@@ -156,32 +156,31 @@ App.ServerValidatorMixin = Em.Mixin.create({
         dataToSend.changed_configurations = changedConfigs;
       }
        **/
-      App.ajax.send({
+    return App.ajax.send({
         name: 'config.recommendations',
         sender: this,
         data: {
           stackVersionUrl: App.get('stackVersionURL'),
-          dataToSend: dataToSend,
-          dfd: dfd
+          dataToSend: dataToSend
         },
         success: 'dependenciesSuccess',
         error: 'dependenciesError'
       });
     } else {
-      dfd.resolve();
+      return null;
     }
-    return dfd.promise();
   },
 
   /**
    *
    * @param data
-   * @param opt
-   * @param params
    */
-  dependenciesSuccess: function(data, opt, params) {
+  dependenciesSuccess: function(data) {
     Em.assert('invalid data', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations'));
     var configs = data.resources[0].recommendations.blueprint.configurations;
+
+    this.loadConfigsToModel(this.get('stepConfigs')[0].get('configs'), this.get('selectedVersion'));
+
     var currentProperties = App.ConfigProperty.find().filterProperty('configVersion.isCurrent').filterProperty('configVersion.groupId', -1);
     for (var key in configs) {
       for (var propertyName in configs[key].properties) {
@@ -197,11 +196,8 @@ App.ServerValidatorMixin = Em.Mixin.create({
     });
 
     if (configsToShow.length > 0) {
-      App.showDependentConfigsPopup(configsToShow, params.dfd);
-    } else {
-      params.dfd.resolve();
+      App.showDependentConfigsPopup(configsToShow);
     }
-
   },
 
   /**
@@ -210,11 +206,9 @@ App.ServerValidatorMixin = Em.Mixin.create({
    * @param ajaxOptions
    * @param error
    * @param opt
-   * @param params
    */
-  dependenciesError: function(jqXHR, ajaxOptions, error, opt, params) {
+  dependenciesError: function(jqXHR, ajaxOptions, error, opt) {
     App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
-    params.dfd.reject();
   },
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/models/cluster_states.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/cluster_states.js b/ambari-web/app/models/cluster_states.js
index 7300e0b..f4a9b59 100644
--- a/ambari-web/app/models/cluster_states.js
+++ b/ambari-web/app/models/cluster_states.js
@@ -233,16 +233,18 @@ App.clusterStatus = Em.Object.create(App.UserPref, {
         App.db.setUser(user);
         App.db.setLoginName(login);
       }
-      this.postUserPref(this.get('key'), val)
-          .done(function () {
-            !!opt && Em.typeOf(opt.successCallback) === 'function' && opt.successCallback.call(opt.sender || this, opt.successCallbackData);
-          })
-          .fail(function () {
-            !!opt && Em.typeOf(opt.errorCallback) === 'function' && opt.errorCallback.call(opt.sender || this, opt.errorCallbackData);
-          })
-          .always(function () {
-            !!opt && Em.typeOf(opt.alwaysCallback) === 'function' && opt.alwaysCallback.call(opt.sender || this, opt.alwaysCallbackData);
-          });
+      if (!$.mocho) {
+        this.postUserPref(this.get('key'), val)
+            .done(function () {
+              !!opt && Em.typeOf(opt.successCallback) === 'function' && opt.successCallback.call(opt.sender || this, opt.successCallbackData);
+            })
+            .fail(function () {
+              !!opt && Em.typeOf(opt.errorCallback) === 'function' && opt.errorCallback.call(opt.sender || this, opt.errorCallbackData);
+            })
+            .always(function () {
+              !!opt && Em.typeOf(opt.alwaysCallback) === 'function' && opt.alwaysCallback.call(opt.sender || this, opt.alwaysCallbackData);
+            });
+      }
       return newValue;
     }
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/templates/main/service/info/configs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/service/info/configs.hbs b/ambari-web/app/templates/main/service/info/configs.hbs
index 9f4c946..030d330 100644
--- a/ambari-web/app/templates/main/service/info/configs.hbs
+++ b/ambari-web/app/templates/main/service/info/configs.hbs
@@ -55,7 +55,7 @@
               <!--<input class="btn btn-primary" type="button" value="Save" {{!bindAttr disabled="isSubmitDisabled"}} />-->
               <a class="btn" {{action doCancel target="controller"}}>{{t common.cancel}}</a>
               <a class="btn btn-primary" {{bindAttr disabled="isSubmitDisabled"}}
-                {{action restartServicePopup target="controller"}}>{{t common.save}}</a>
+                {{action saveStepConfigs target="controller"}}>{{t common.save}}</a>
           </p>
       {{/unless}}
     {{/isAccessible}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/views/common/configs/config_history_flow.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/config_history_flow.js b/ambari-web/app/views/common/configs/config_history_flow.js
index 7c55fca..e0bcff1 100644
--- a/ambari-web/app/views/common/configs/config_history_flow.js
+++ b/ambari-web/app/views/common/configs/config_history_flow.js
@@ -495,7 +495,7 @@ App.ConfigHistoryFlowView = Em.View.extend({
           serviceName: self.get('displayedServiceVersion.serviceName'),
           groupName: self.get('controller.selectedConfigGroup.name')
         }));
-        self.get('controller').restartServicePopup();
+        self.get('controller').saveStepConfigs();
         this.hide();
       },
       onDiscard: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/views/common/configs/service_configs_by_category_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/configs/service_configs_by_category_view.js b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
index 8be73a4..1cf2187 100644
--- a/ambari-web/app/views/common/configs/service_configs_by_category_view.js
+++ b/ambari-web/app/views/common/configs/service_configs_by_category_view.js
@@ -583,10 +583,12 @@ App.ServiceConfigsByCategoryView = Em.View.extend(App.UserPref, {
       var deletedConfig = App.ConfigProperty.find().find(function(cp) {
         return cp.get('name') === serviceConfigProperty.get('name')
           && cp.get('fileName') === serviceConfigProperty.get('filename')
-          && cp.get('isDefault');
+          && cp.get('isOriginalSCP');
       });
-      deletedConfig.deleteRecord();
-      App.store.commit();
+      if (deletedConfig) {
+        deletedConfig.deleteRecord();
+        App.store.commit();
+      }
     }
     // push config's file name if this config was stored on server
     if (!serviceConfigProperty.get('isNotSaved')) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/views/common/controls_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/controls_view.js b/ambari-web/app/views/common/controls_view.js
index 118534e..a0730e5 100644
--- a/ambari-web/app/views/common/controls_view.js
+++ b/ambari-web/app/views/common/controls_view.js
@@ -59,6 +59,27 @@ App.ServiceConfigPopoverSupport = Ember.Mixin.create({
   }.property('serviceConfig.isEditable')
 });
 
+App.supportsDependentConfigs = Ember.Mixin.create({
+
+  /**
+   * method send request to check if some of dependent configs was changes
+   * and in case there was changes shows popup with info about changed configs
+   */
+  sendRequestRorDependentConfigs: function() {
+    if (App.get('supports.enhancedConfigs') && this.get('controller.name') === 'mainServiceInfoConfigsController') {
+      var name = this.get('serviceConfig.name');
+      var type = App.config.getConfigTagFromFileName(this.get('serviceConfig.filename'));
+      var p = App.StackConfigProperty.find(name + '_' + type);
+      if (p && p.get('propertyDependedBy.length') > 0) {
+        this.get('controller').getRecommendationsForDependencies([{
+          "type": type,
+          "name": name
+        }]);
+      }
+    }
+  }
+});
+
 /**
  * mixin set class that serve as unique element identificator,
  * id not used in order to avoid collision with ember ids
@@ -78,7 +99,7 @@ App.ServiceConfigCalculateId = Ember.Mixin.create({
  * Default input control
  * @type {*}
  */
-App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, {
+App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.supportsDependentConfigs, {
 
   valueBinding: 'serviceConfig.value',
   classNameBindings: 'textFieldClassName',
@@ -91,6 +112,9 @@ App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupp
   },
   //Set editDone true for last edited config text field parameter
   focusOut: function (event) {
+    if (this.get('serviceConfig.isNotDefaultValue')) {
+      this.sendRequestRorDependentConfigs();
+    }
     this.get('serviceConfig').set("editDone", true);
   },
   //Set editDone false for all current category config text field parameter
@@ -116,11 +140,17 @@ App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupp
  * Customized input control with Units type specified
  * @type {Em.View}
  */
-App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, {
+App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, App.supportsDependentConfigs, {
   valueBinding: 'serviceConfig.value',
   classNames: ['input-append', 'with-unit'],
   placeholderBinding: 'serviceConfig.defaultValue',
 
+  //Set editDone true for last edited config text field parameter
+  focusOut: function (event) {
+    if (this.get('serviceConfig.isNotDefaultValue')) {
+      this.sendRequestRorDependentConfigs();
+    }
+  },
   templateName: require('templates/wizard/controls_service_config_textfield_with_unit')
 });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
index 14cb6aa..73ed1f6 100644
--- a/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
+++ b/ambari-web/app/views/common/modal_popups/dependent_configs_list_popup.js
@@ -21,46 +21,45 @@ var App = require('app');
 /**
  * Show confirmation popup
  * @param {[Object]} configs
+ * @param {function} [callback=null]
+ * @param {function} [secondaryCallback=null]
  * we use this parameter to defer saving configs before we make some decisions.
- * @param {$.Deferred} dfd
  * @return {App.ModalPopup}
  */
-App.showDependentConfigsPopup = function (configs, dfd) {
-  if (!configs || configs.length === 0) {
-    dfd.resolve();
-  }
+App.showDependentConfigsPopup = function (configs, callback, secondaryCallback) {
   return App.ModalPopup.show({
     encodeBody: false,
     primary: Em.I18n.t('common.save'),
     secondary: Em.I18n.t('common.cancel'),
-    third: Em.I18n.t('common.discard'),
     header: Em.I18n.t('popup.dependent.configs.header'),
     classNames: ['full-width-modal'],
     configs: configs,
     bodyClass: Em.View.extend({
       templateName: require('templates/common/modal_popups/dependent_configs_list')
     }),
+    stepConfigs: function() {
+      return App.get('router.mainServiceInfoConfigsController.stepConfigs').objectAt(0).get('configs');
+    }.property('controller.stepConfigs.@each'),
     onPrimary: function () {
       this.hide();
       configs.filterProperty('saveRecommended', true).forEach(function(c) {
         c.set('value', c.get('recommendedValue'));
-      });
-      dfd.resolve();
+        var stepConfig = this.get('stepConfigs').find(function(stepConf) {
+          return stepConf.get('name') === c.get('name') && stepConf.get('filename') === c.get('fileName');
+        });
+        if (stepConfig) {
+          stepConfig.set('value', c.get('recommendedValue'));
+        }
+      }, this);
+      if (callback) {
+        callback();
+      }
     },
-    onSecondary: function () {
-      App.get('router.mainServiceInfoConfigsController').set('isApplyingChanges', false);
-      dfd.reject();
+    onSecondary: function() {
       this.hide();
-    },
-    onThird: function () {
-      App.get('router.mainServiceInfoConfigsController').set('isApplyingChanges', false);
-      App.get('router.mainServiceInfoConfigsController').set('preSelectedConfigVersion', null);
-      App.get('router.mainServiceInfoConfigsController').onConfigGroupChange();
-      dfd.reject();
-      this.hide();
-    },
-    onClose: function () {
-      this.onSecondary();
+      if(secondaryCallback) {
+        secondaryCallback();
+      }
     }
   });
 };

http://git-wip-us.apache.org/repos/asf/ambari/blob/3b8e577d/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/mixins/common/configs/enhanced_configs_test.js b/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
index f47e51b..eacfea5 100644
--- a/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
+++ b/ambari-web/test/mixins/common/configs/enhanced_configs_test.js
@@ -138,6 +138,33 @@ describe('App.EnhancedConfigsMixin', function() {
         "service_config_version_note": 'note'
       })
     })
-  })
+  });
+
+  describe('#generateDesiredConfigsJSON()', function() {
+    beforeEach(function() {
+      sinon.stub(instanceObject, 'createDesiredConfig', function(type) {
+        return 'desiredConfig_' + type;
+      });
+      sinon.stub(instanceObject, 'allowSaveSite', function() {
+        return true;
+      });
+
+    });
+    afterEach(function() {
+      instanceObject.createDesiredConfig.restore();
+      instanceObject.allowSaveSite.restore();
+    });
+
+    it('generates empty array as data is missing', function() {
+      expect(instanceObject.generateDesiredConfigsJSON()).to.eql([]);
+      expect(instanceObject.generateDesiredConfigsJSON(1,1)).to.eql([]);
+      expect(instanceObject.generateDesiredConfigsJSON([],[])).to.eql([]);
+    });
+
+    it('generates array with desired configs', function() {
+      expect(instanceObject.generateDesiredConfigsJSON([Em.Object.create({'name': 'p1', 'fileName': 'f1.xml'})], ['f1'])).to.eql(['desiredConfig_f1']);
+      expect(instanceObject.createDesiredConfig).to.be.calledOnce
+    })
+  });
 });