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/06/17 12:59:24 UTC

ambari git commit: AMBARI-11968 Service config pages load much slower than 2.0. (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk 0fcbabfcd -> 27c6d7542


AMBARI-11968 Service config pages load much slower than 2.0. (ababiichuk)


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

Branch: refs/heads/trunk
Commit: 27c6d7542fdd4d792f2101679095f544159894e7
Parents: 0fcbabf
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Tue Jun 16 16:05:34 2015 +0300
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Wed Jun 17 13:57:43 2015 +0300

----------------------------------------------------------------------
 .../main/dashboard/config_history_controller.js |   2 +-
 .../controllers/main/service/info/configs.js    | 204 +++++++++----------
 .../service/manage_config_groups_controller.js  |   3 +-
 ambari-web/app/mappers.js                       |   2 +-
 .../app/mappers/configs/config_groups_mapper.js |  82 +++++---
 .../mappers/service_config_version_mapper.js    |  10 +
 ambari-web/app/mixins.js                        |   1 +
 .../app/mixins/common/configs/configs_loader.js | 157 ++++++++++++++
 .../app/mixins/common/configs/configs_saver.js  |  43 ++--
 .../mixins/common/configs/enhanced_configs.js   |   2 +-
 .../main/service/configs/config_overridable.js  |  12 ++
 .../app/mixins/main/service/groups_mapping.js   |   8 +-
 ambari-web/app/models.js                        |   2 +-
 ambari-web/app/models/configs/config_group.js   | 114 ++++++++++-
 ambari-web/app/utils/ajax/ajax.js               |  10 +-
 ambari-web/app/utils/config.js                  | 102 ++++++++--
 .../views/common/configs/config_history_flow.js |   6 +-
 .../dashboard/config_history_controller_test.js |   8 +-
 .../main/host/configs_service_test.js           |   4 +-
 .../main/service/info/config_test.js            |   4 -
 .../common/configs/config_history_flow_test.js  |   4 -
 21 files changed, 588 insertions(+), 192 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/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 5931b40..30b466b 100644
--- a/ambari-web/app/controllers/main/dashboard/config_history_controller.js
+++ b/ambari-web/app/controllers/main/dashboard/config_history_controller.js
@@ -32,7 +32,7 @@ App.MainConfigHistoryController = Em.ArrayController.extend(App.TableServerMixin
   resetStartIndex: true,
   mockUrl: '/data/configurations/service_versions.json',
   realUrl: function () {
-    return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note&minimal_response=true';
+    return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible&minimal_response=true';
   }.property('App.clusterName'),
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/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 a21baa1..f47e396 100644
--- a/ambari-web/app/controllers/main/service/info/configs.js
+++ b/ambari-web/app/controllers/main/service/info/configs.js
@@ -21,7 +21,7 @@ require('controllers/wizard/slave_component_groups_controller');
 var batchUtils = require('utils/batch_scheduled_requests');
 var databaseUtils = require('utils/configs/database');
 
-App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.PreloadRequestsChainMixin, App.ThemesMappingMixin, App.VersionsMappingMixin, App.ConfigsSaverMixin, {
+App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, App.ServerValidatorMixin, App.EnhancedConfigsMixin, App.ThemesMappingMixin, App.VersionsMappingMixin, App.ConfigsSaverMixin, {
 
   name: 'mainServiceInfoConfigsController',
 
@@ -43,19 +43,24 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
 
   requestInProgress: null,
 
-  selectedServiceConfigTypes: [],
-
-  selectedServiceSupportsFinal: [],
+  groupsStore: App.ServiceConfigGroup.find(),
 
   /**
    * config groups for current service
    * @type {App.ConfigGroup[]}
    */
-  configGroups: [],
+  configGroups: function() {
+    return this.get('groupsStore').filterProperty('serviceName', this.get('content.serviceName'));
+  }.property('content.serviceName', 'groupsStore.length', 'groupStore.@each.name'),
 
-  allConfigs: [],
+  dependentConfigGroups: function() {
+    if (this.get('dependentServiceNames.length') === 0) return [];
+    return this.get('groupsStore').filter(function(group) {
+      return this.get('dependentServiceNames').contains(group.get('serviceName'));
+    }, this);
+  }.property('content.serviceName', 'dependentServiceNames', 'groupsStore.length', 'groupStore.@each.name'),
 
-  uiConfigs: [],
+  allConfigs: [],
 
   /**
    * Determines if save configs is in progress
@@ -93,12 +98,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   versionLoaded: false,
 
   /**
-   * current cluster-env version
-   * @type {string}
-   */
-  clusterEnvTagVersion: '',
-
-  /**
    * defines which service configs need to be loaded to stepConfigs
    * @type {string[]}
    */
@@ -129,13 +128,13 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
    */
   isCurrentSelected: function () {
     return App.ServiceConfigVersion.find(this.get('content.serviceName') + "_" + this.get('selectedVersion')).get('isCurrent');
-  }.property('selectedVersion', 'content.serviceName', 'dataIsLoaded'),
+  }.property('selectedVersion', 'content.serviceName', 'dataIsLoaded', 'versionLoaded'),
 
   /**
    * @type {boolean}
    */
   canEdit: function () {
-    return this.get('isCurrentSelected') && !this.get('isCompareMode') && App.isAccessible('MANAGER');
+    return this.get('isCurrentSelected') && !this.get('isCompareMode') && App.isAccessible('MANAGER') && !this.get('isHostsConfigsPage');
   }.property('isCurrentSelected', 'isCompareMode'),
 
   serviceConfigs: function () {
@@ -155,25 +154,6 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   showConfigHistoryFeature: true,
 
   /**
-   * Map, which contains relation between group and site
-   * to upload overridden properties
-   * @type {object}
-   */
-  loadedGroupToOverrideSiteToTagMap: {},
-
-  /**
-   * During page load time the cluster level site to tag
-   * mapping is stored here.
-   *
-   * Example:
-   * {
-   *  'hdfs-site': 'version1',
-   *  'core-site': 'version1'
-   * }
-   */
-  loadedClusterSiteToTagMap: {},
-
-  /**
    * Number of errors in the configs in the selected service (only for AdvancedTab if App supports Enhanced Configs)
    * @type {number}
    */
@@ -289,7 +269,9 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       this.get('requestInProgress').abort();
       this.set('requestInProgress', null);
     }
+    this.clearLoadInfo();
     this.clearSaveInfo();
+    this.clearDependentConfigs();
     this.setProperties({
       saveInProgress: false,
       isInit: true,
@@ -298,13 +280,11 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
       dataIsLoaded: false,
       versionLoaded: false,
       filter: '',
-      loadedGroupToOverrideSiteToTagMap: {},
       serviceConfigVersionNote: ''
     });
     this.get('filterColumns').setEach('selected', false);
     this.get('stepConfigs').clear();
     this.get('allConfigs').clear();
-    this.get('uiConfigs').clear();
     if (this.get('serviceConfigTags')) {
       this.set('serviceConfigTags', null);
     }
@@ -344,7 +324,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
         App.themesMapper.generateAdvancedTabs([serviceName]);
       });
     }
-    this.loadClusterEnvSite();
+    this.loadServiceConfigVersions();
   },
 
   /**
@@ -370,74 +350,56 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
     return JSON.stringify(hash);
   },
 
-  /**
-   * Update configs on the page after <code>selectedConfigGroup</code> is changed
-   * @method onConfigGroupChange
-   */
-  onConfigGroupChange: function () {
+  parseConfigData: function(data) {
+    this.prepareConfigObjects(data, this.get('content.serviceName'));
     var self = this;
+    this.loadCompareVersionConfigs(this.get('allConfigs')).done(function() {
+      self.addOverrides(data, self.get('allConfigs'));
+      self.onLoadOverrides(self.get('allConfigs'));
+    });
+  },
+
+  prepareConfigObjects: function(data, serviceName) {
     this.get('stepConfigs').clear();
-    var selectedConfigGroup = this.get('selectedConfigGroup');
-    var serviceName = this.get('content.serviceName');
-    //STEP 1: handle tags from JSON data for host overrides
-    var configGroupsWithOverrides = selectedConfigGroup.get('isDefault') && !this.get('isHostsConfigsPage') ? this.get('configGroupsToLoad') : [selectedConfigGroup].concat(this.get('dependentConfigGroups'));
-    configGroupsWithOverrides.forEach(function (item) {
-      var groupName = item.get('name');
-      if (Em.isNone(this.loadedGroupToOverrideSiteToTagMap[groupName])) {
-        this.loadedGroupToOverrideSiteToTagMap[groupName] = {};
-        item.get('configSiteTags').forEach(function (siteTag) {
-          var site = siteTag.get('site');
-          this.loadedGroupToOverrideSiteToTagMap[groupName][site] = siteTag.get('tag');
-        }, this);
-      }
-    }, this);
-    //STEP 2: Create an array of objects defining tag names to be polled and new tag names to be set after submit
-    this.setServiceConfigTags(this.loadedClusterSiteToTagMap);
-    //STEP 4: Load on-site config by service from server
-    App.router.get('configurationController').getConfigsByTags(this.get('serviceConfigTags')).done(function(configGroups){
-      //Merge on-site configs with pre-defined
-      var configSet = App.config.mergePreDefinedWithLoaded(configGroups, self.get('advancedConfigs'), self.get('serviceConfigTags'), serviceName);
-      configSet = App.config.syncOrderWithPredefined(configSet);
-
-      var configs = configSet.configs;
-
-      /**
-       * if property defined in stack but somehow it missed from cluster properties (can be after stack upgrade)
-       * ui should add this properties to step configs
-       */
-      configs = self.mergeWithStackProperties(configs);
-
-      //put properties from capacity-scheduler.xml into one config with textarea view
-      if (self.get('content.serviceName') === 'YARN') {
-        var configsToSkip = self.get('advancedConfigs').filterProperty('filename', 'capacity-scheduler.xml').filterProperty('subSection');
-        configs = App.config.fileConfigsIntoTextarea(configs, 'capacity-scheduler.xml', configsToSkip);
+
+    var configGroups = [];
+    data.items.forEach(function (v) {
+      if (v.group_name == 'default') {
+        v.configurations.forEach(function (c) {
+          configGroups.pushObject(c);
+        });
       }
+    });
 
-      if (self.get('content.serviceName') === 'KERBEROS') {
-        var kdc_type = configs.findProperty('name', 'kdc_type');
-        if (kdc_type.get('value') === 'none') {
-          configs.findProperty('name', 'kdc_host').set('isRequired', false).set('isVisible', false);
-          configs.findProperty('name', 'admin_server_host').set('isRequired', false).set('isVisible', false);
-          configs.findProperty('name', 'domains').set('isRequired', false).set('isVisible', false);
-        }
+    var configs = App.config.mergePredefinedWithSaved(configGroups, this.get('advancedConfigs'), serviceName);
+    configs = App.config.syncOrderWithPredefined(configs);
+    /**
+     * if property defined in stack but somehow it missed from cluster properties (can be after stack upgrade)
+     * ui should add this properties to step configs
+     */
+    configs = this.mergeWithStackProperties(configs);
+
+    //put properties from capacity-scheduler.xml into one config with textarea view
+    if (this.get('content.serviceName') === 'YARN') {
+      var configsToSkip = this.get('advancedConfigs').filterProperty('filename', 'capacity-scheduler.xml').filterProperty('subSection');
+      configs = App.config.fileConfigsIntoTextarea(configs, 'capacity-scheduler.xml', configsToSkip);
+    }
 
-        kdc_type.set('value', App.router.get('mainAdminKerberosController.kdcTypesValues')[kdc_type.get('value')]);
+    if (this.get('content.serviceName') === 'KERBEROS') {
+      var kdc_type = configs.findProperty('name', 'kdc_type');
+      if (kdc_type.get('value') === 'none') {
+        configs.findProperty('name', 'kdc_host').set('isRequired', false).set('isVisible', false);
+        configs.findProperty('name', 'admin_server_host').set('isRequired', false).set('isVisible', false);
+        configs.findProperty('name', 'domains').set('isRequired', false).set('isVisible', false);
       }
 
-      self.set('allConfigs', configs);
-      //add configs as names of host components
-      self.addHostNamesToConfig();
-      //load configs of version being compared against
-      self.loadCompareVersionConfigs(self.get('allConfigs')).done(function (isComparison) {
-        //Load and add overridden configs of group
-        if (!isComparison && (!self.get('selectedConfigGroup').get('isDefault') || self.get('isCurrentSelected'))) {
-          App.config.loadServiceConfigGroupOverrides(self.get('allConfigs'), self.get('loadedGroupToOverrideSiteToTagMap'), self.get('configGroupsToLoad'), self.onLoadOverrides, self);
-        } else {
-          self.onLoadOverrides(self.get('allConfigs'));
-        }
-      });
-    });
-  }.observes('selectedConfigGroup'),
+      kdc_type.set('value', App.router.get('mainAdminKerberosController.kdcTypesValues')[kdc_type.get('value')]);
+    }
+
+    this.set('allConfigs', configs);
+    //add configs as names of host components
+    this.addHostNamesToConfig();
+  },
 
   /**
    * adds properties form stack that doesn't belong to cluster
@@ -476,6 +438,28 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
     return configs;
   },
 
+  addOverrides: function(data, allConfigs) {
+    data.items.forEach(function(group) {
+      if (group.group_name != 'default') {
+        var configGroup = App.ServiceConfigGroup.find().filterProperty('serviceName', group.service_name).findProperty('name', group.group_name);
+        group.configurations.forEach(function(config) {
+          for (var prop in config.properties) {
+            var fileName = App.config.getOriginalFileName(config.type);
+            var serviceConfig = allConfigs.filterProperty('name', prop).findProperty('filename', fileName);
+            var hostOverrideValue = App.config.formatOverrideValue(serviceConfig, config.properties[prop]);
+            var hostOverrideIsFinal = !!(config.properties_attributes && config.properties_attributes.final && config.properties_attributes.final[prop]);
+            if (serviceConfig) {
+              // Value of this property is different for this host.
+              if (!Em.get(serviceConfig, 'overrides')) Em.set(serviceConfig, 'overrides', []);
+              serviceConfig.overrides.pushObject({value: hostOverrideValue, group: configGroup, isFinal: hostOverrideIsFinal});
+            } else {
+              allConfigs.push(App.config.createCustomGroupConfig(prop, config, configGroup));
+            }
+          }
+        });
+      }
+    });
+  },
   /**
    * load version configs for comparison
    * @param allConfigs
@@ -838,9 +822,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
    * @method onLoadOverrides
    */
   onLoadOverrides: function (allConfigs) {
-    var self = this;
-    var serviceNames = this.get('servicesToLoad');
-    serviceNames.forEach(function(serviceName) {
+    this.get('servicesToLoad').forEach(function(serviceName) {
       var serviceConfig = App.config.createServiceConfig(serviceName);
       if (serviceName == this.get('content.serviceName')) {
         serviceConfig.set('configGroups', this.get('configGroups'));
@@ -872,11 +854,9 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
     if (!App.Service.find().someProperty('serviceName', 'RANGER')) {
       App.config.removeRangerConfigs(this.get('stepConfigs'));
     }
+    this._onLoadComplete();
     if (App.isAccessible('MANAGER')) {
-      this.getRecommendationsForDependencies(null, true, self._onLoadComplete.bind(self));
-    }
-    else {
-      self._onLoadComplete();
+      this.getRecommendationsForDependencies(null, true, Em.K);
     }
   },
 
@@ -1294,13 +1274,13 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
   },
 
   /**
-   * Trigger loadStep
-   * @method loadStep
+   * Trigger loadSelectedVersion
+   * @method doCancel
    */
   doCancel: function () {
     this.set('preSelectedConfigVersion', null);
     this.clearDependentConfigs();
-    Em.run.once(this, 'onConfigGroupChange');
+    this.loadSelectedVersion(this.get('selectedConfigVersion'), this.get('selectedConfigGroup'));
   },
 
   /**
@@ -1459,11 +1439,11 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM
    * @method selectConfigGroup
    */
   doSelectConfigGroup: function (event) {
-    //clean when switch config group
-    this.loadedGroupToOverrideSiteToTagMap = {};
-    var configGroupVersions = App.ServiceConfigVersion.find().filterProperty('groupId', event.context.get('id'));
+    var configGroupVersions = App.ServiceConfigVersion.find().filterProperty('groupId', event.context.get('configGroupId'));
     //check whether config group has config versions
-    if (configGroupVersions.length > 0) {
+    if (event.context.get('configGroupId') == -1) {
+      this.loadCurrentVersions();
+    } else if (configGroupVersions.length > 0) {
       this.loadSelectedVersion(configGroupVersions.findProperty('isCurrent').get('version'), event.context);
     } else {
       this.loadSelectedVersion(null, event.context);

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/controllers/main/service/manage_config_groups_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/manage_config_groups_controller.js b/ambari-web/app/controllers/main/service/manage_config_groups_controller.js
index f36158c..0e66270 100644
--- a/ambari-web/app/controllers/main/service/manage_config_groups_controller.js
+++ b/ambari-web/app/controllers/main/service/manage_config_groups_controller.js
@@ -826,7 +826,8 @@ App.ManageConfigGroupsController = Em.Controller.extend(App.ConfigOverridable, {
         var managedConfigGroups = configsController.get('configGroups');
         if (!controller) {
           controller = App.router.get('mainServiceInfoConfigsController');
-          controller.set('configGroups', managedConfigGroups);
+          //controller.set('configGroups', managedConfigGroups);
+          controller.loadConfigGroups([controller.get('content.serviceName')]);
         } else {
           controller.set('selectedService.configGroups', managedConfigGroups);
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mappers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers.js b/ambari-web/app/mappers.js
index b96fc50..4b76455 100644
--- a/ambari-web/app/mappers.js
+++ b/ambari-web/app/mappers.js
@@ -23,7 +23,7 @@ require('mappers/stack_mapper');
 require('mappers/stack_version_mapper');
 require('mappers/configs/themes_mapper');
 require('mappers/configs/stack_config_properties_mapper');
-//require('mappers/configs/config_groups_mapper');
+require('mappers/configs/config_groups_mapper');
 require('mappers/configs/config_versions_mapper');
 require('mappers/repository_version_mapper');
 require('mappers/hosts_mapper');

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mappers/configs/config_groups_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/configs/config_groups_mapper.js b/ambari-web/app/mappers/configs/config_groups_mapper.js
index 66a4cc0..55b1185 100644
--- a/ambari-web/app/mappers/configs/config_groups_mapper.js
+++ b/ambari-web/app/mappers/configs/config_groups_mapper.js
@@ -30,11 +30,24 @@ App.configGroupsMapper = App.QuickDataMapper.create({
     name: 'ConfigGroup.group_name',
     service_name: 'ConfigGroup.tag',
     description: 'ConfigGroup.description',
-    host_names: 'host_names',
+    host_names: 'hosts',
     service_id: 'ConfigGroup.tag'
   },
 
-  map: function (json, serviceNames) {
+  /**
+   * using this config when saving group from config_version api
+   */
+  config2: {
+    id: 'id',
+    config_group_id: 'group_id',
+    name: 'group_name',
+    service_name: 'service_name',
+    host_names: 'hosts',
+    service_id: 'service_name'
+  },
+
+
+  map: function (json, mapFromVersions, serviceNames, skipDefault) {
     if (serviceNames && serviceNames.length > 0) {
       var configGroups = [];
 
@@ -48,35 +61,49 @@ App.configGroupsMapper = App.QuickDataMapper.create({
       var hostNamesForService = {};
 
       if (json && json.items) {
-        json.items.forEach(function(configroup) {
-          configroup.id = configroup.ConfigGroup.tag + configroup.ConfigGroup.id;
-          configroup.host_names = configroup.ConfigGroup.hosts.mapProperty('host_name');
+        json.items.forEach(function(configGroup) {
+          if (configGroup.group_name != 'default') {
+            if (mapFromVersions) {
+              configGroup.id = configGroup.service_name + configGroup.group_id;
+            } else {
+              configGroup.id = configGroup.ConfigGroup.tag + configGroup.ConfigGroup.id;
+              configGroup.hosts = configGroup.ConfigGroup.hosts.mapProperty('host_name');
+              configGroup.service_name = configGroup.ConfigGroup.tag;
+            }
 
-          /**
-           * creating (if not exists) field in <code>hostNamesForService<code> with host names for default group
-           */
-          if (!hostNamesForService[configroup.ConfigGroup.tag]) {
-            hostNamesForService[configroup.ConfigGroup.tag] = $.merge([], App.get('allHostNames'));
-          }
+            if (!skipDefault) {
+              /**
+               * creating (if not exists) field in <code>hostNamesForService<code> with host names for default group
+               */
+              if (!hostNamesForService[configGroup.service_name]) {
+                hostNamesForService[configGroup.service_name] = $.merge([], App.get('allHostNames'));
+              }
 
-          /**
-           * excluding host names that belongs for current config group from default group
-           */
-          configroup.host_names.forEach(function(host) {
-            hostNamesForService[configroup.ConfigGroup.tag].splice(hostNamesForService[configroup.ConfigGroup.tag].indexOf(host), 1);
-          });
+              /**
+               * excluding host names that belongs for current config group from default group
+               */
+              configGroup.hosts.forEach(function(host) {
+                hostNamesForService[configGroup.service_name].splice(hostNamesForService[configGroup.service_name].indexOf(host), 1);
+              });
+            }
 
-          configGroups.push(this.parseIt(configroup, this.get('config')));
+            var template = mapFromVersions ? this.get('config2') : this.get('config');
+            configGroups.push(this.parseIt(configGroup, template));
+          }
+        }, this);
+      }
+      if (!skipDefault) {
+        /**
+         * generating default config groups
+         */
+        serviceNames.forEach(function(serviceName) {
+          configGroups.push(this.generateDefaultGroup(serviceName, hostNamesForService[serviceName]));
         }, this);
       }
 
-      /**
-       * generating default config groups
-       */
-      serviceNames.forEach(function(serviceName) {
-        configGroups.push(this.generateDefaultGroup(serviceName, hostNamesForService[serviceName]));
-      }, this);
-
+      configGroups.sort(function (configGroupA, configGroupB) {
+        return configGroupA.config_group_id == -1 || (configGroupA.name > configGroupB.name);
+      });
       App.store.loadMany(this.get('model'), configGroups);
     }
   },
@@ -88,12 +115,13 @@ App.configGroupsMapper = App.QuickDataMapper.create({
    * @returns {{id: string, config_group_id: string, name: string, service_name: string, description: string, host_names: [string], service_id: string}}
    */
   generateDefaultGroup: function(serviceName, hostNames) {
+    var displayName = App.StackService.find(serviceName).get('displayName');
     return {
       id: serviceName + '0',
       config_group_id: '-1',
-      name: serviceName + ' Default',
+      name: displayName + ' Default',
       service_name: serviceName,
-      description: 'Default cluster level '+ serviceName +' configuration',
+      description: 'Default cluster level '+ displayName +' configuration',
       host_names: hostNames ? hostNames : App.get('allHostNames'),
       service_id: serviceName
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mappers/service_config_version_mapper.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mappers/service_config_version_mapper.js b/ambari-web/app/mappers/service_config_version_mapper.js
index 2935cfa..69bc35c 100644
--- a/ambari-web/app/mappers/service_config_version_mapper.js
+++ b/ambari-web/app/mappers/service_config_version_mapper.js
@@ -81,6 +81,16 @@ App.serviceConfigVersionsMapper = App.QuickDataMapper.create({
           defVer.hosts = defaultHostNames;
         }
       });
+
+      result.forEach(function(v) {
+        if (v.is_current) {
+          var formerCurrent = App.ServiceConfigVersion.find().filterProperty('isCurrent').filterProperty('serviceName', v.service_name).findProperty('groupName', v.group_name);
+          if (formerCurrent) {
+            formerCurrent.set('isCurrent', false);
+          }
+        }
+      });
+
       App.store.commit();
       App.store.loadMany(this.get('model'), result);
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mixins.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins.js b/ambari-web/app/mixins.js
index 3b40d11..72e2531 100644
--- a/ambari-web/app/mixins.js
+++ b/ambari-web/app/mixins.js
@@ -44,6 +44,7 @@ require('mixins/wizard/wizard_menu_view');
 require('mixins/wizard/assign_master_components');
 require('mixins/common/configs/enhanced_configs');
 require('mixins/common/configs/configs_saver');
+require('mixins/common/configs/configs_loader');
 require('mixins/common/configs/toggle_isrequired');
 require('mixins/common/widgets/widget_mixin');
 require('mixins/common/widgets/widget_section');

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mixins/common/configs/configs_loader.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/configs_loader.js b/ambari-web/app/mixins/common/configs/configs_loader.js
new file mode 100644
index 0000000..3864b47
--- /dev/null
+++ b/ambari-web/app/mixins/common/configs/configs_loader.js
@@ -0,0 +1,157 @@
+/**
+ * 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.ConfigsLoader = Em.Mixin.create(App.GroupsMappingMixin, {
+
+  /**
+   * the highest version number that is stored in <code>App.ServiceConfigVersion<code>
+   * @type {number}
+   */
+  lastLoadedVersion: 0,
+
+  /**
+   * this method should be used in clear step method
+   * @method clearLoadInfo
+   */
+  clearLoadInfo: function() {
+    this.set('lastLoadedVersion', 0);
+  },
+
+  /**
+   * loads all versions that is not saved on UI for current moment
+   * @returns {$.ajax}
+   */
+  loadServiceConfigVersions: function () {
+    App.ServiceConfigVersion.find().forEach(function (v) {
+      if (v.get('isCurrent') && v.get('serviceName') == this.get('content.serviceName') && v.get('version') > this.get('lastLoadedVersion')) {
+        this.set('lastLoadedVersion', v.get('version'));
+      }
+    }, this);
+    return App.ajax.send({
+      name: 'service.serviceConfigVersions.get.not.loaded',
+      data: {
+        serviceName: this.get('content.serviceName'),
+        lastSavedVersion: this.get('lastLoadedVersion').toString()
+      },
+      sender: this,
+      success: 'loadServiceConfigVersionsSuccess'
+    })
+  },
+
+  /**
+   * success handler for <code>loadServiceConfigVersions<code>
+   * @param data
+   */
+  loadServiceConfigVersionsSuccess: function (data) {
+    if (Em.get(data, 'items.length')) {
+      App.serviceConfigVersionsMapper.map(data);
+      var currentDefault = data.items.filterProperty('group_id', -1).findProperty('is_current');
+      if (currentDefault) {
+        this.set('currentDefaultVersion', currentDefault.service_config_version);
+      }
+    } else {
+      this.set('currentDefaultVersion', App.ServiceConfigVersion.find().find(function(v) {
+        return v.get('isCurrent') && v.get('isDefault') && v.get('serviceName') == this.get('content.serviceName');
+      }, this).get('version'));
+    }
+    if (this.get('preSelectedConfigVersion')) {
+      /** handling redirecting from config history page **/
+      var self = this;
+      this.loadConfigGroups(this.get('servicesToLoad'), false).done(function() {
+        var selectedGroup = App.ServiceConfigGroup.find().find(function(g) {
+          return g.get('serviceName') == self.get('preSelectedConfigVersion.serviceName')
+            && (g.get('name') == self.get('preSelectedConfigVersion.groupName') || (self.get('preSelectedConfigVersion.groupName') == 'default' && g.get('isDefault')));
+        });
+        self.set('selectedConfigGroup', selectedGroup);
+        self.loadSelectedVersion(self.get('preSelectedConfigVersion.version'), selectedGroup);
+        self.set('preSelectedConfigVersion', null);
+      });
+    } else {
+      this.loadCurrentVersions();
+    }
+  },
+
+  /**
+   * loads current versions of current and dependent services
+   * and all current version for config groups
+   * @method loadCurrentVersions
+   */
+  loadCurrentVersions: function() {
+    this.set('versionLoaded', false);
+    this.set('selectedVersion', this.get('currentDefaultVersion'));
+    this.trackRequest(App.ajax.send({
+      name: 'service.serviceConfigVersions.get.current',
+      sender: this,
+      data: {
+        serviceNames: this.get('servicesToLoad').join(',')
+      },
+      success: 'loadCurrentVersionsSuccess'
+    }));
+  },
+
+  /**
+   * success handler for <code>loadCurrentVersions<code>
+   * @param data
+   * @param opt
+   * @param params
+   */
+  loadCurrentVersionsSuccess: function(data, opt, params) {
+    App.configGroupsMapper.map(data, true, params.serviceNames.split(','));
+    this.set('selectedConfigGroup', App.ServiceConfigGroup.find().filterProperty('serviceName', this.get('content.serviceName')).findProperty('isDefault'));
+    this.parseConfigData(data);
+    this.loadConfigGroups(params.serviceNames.split(','), true);
+  },
+
+  /**
+   * loads selected versions of current service
+   * @method loadSelectedVersion
+   */
+  loadSelectedVersion: function (version, switchToGroup) {
+    this.set('versionLoaded', false);
+    version = version || this.get('currentDefaultVersion');
+    //version of non-default group require properties from current version of default group to correctly display page
+    var versions = (this.isVersionDefault(version)) ? [version] : [this.get('currentDefaultVersion'), version];
+    switchToGroup = (this.isVersionDefault(version) && !switchToGroup) ? this.get('configGroups').findProperty('isDefault') : switchToGroup;
+
+    if (this.get('dataIsLoaded') && switchToGroup) {
+      this.set('selectedConfigGroup', switchToGroup);
+    }
+    var selectedVersion = versions.length > 1 ? versions[1] : versions[0];
+    this.set('selectedVersion', selectedVersion);
+    this.trackRequest(App.ajax.send({
+      name: 'service.serviceConfigVersions.get.multiple',
+      sender: this,
+      data: {
+        serviceName: this.get('content.serviceName'),
+        serviceConfigVersions: versions,
+        additionalParams: App.get('isClusterSupportsEnhancedConfigs') && this.get('dependentServiceNames.length') ? '|service_name.in(' +  this.get('dependentServiceNames') + ')&is_current=true' : ''
+      },
+      success: 'loadSelectedVersionsSuccess'
+    }));
+  },
+
+  /**
+   * success handler for <code>loadSelectedVersionsSuccess<code>
+   * @param data
+   */
+  loadSelectedVersionsSuccess: function(data) {
+    this.parseConfigData(data);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mixins/common/configs/configs_saver.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/configs_saver.js b/ambari-web/app/mixins/common/configs/configs_saver.js
index d1891cd..882db86 100644
--- a/ambari-web/app/mixins/common/configs/configs_saver.js
+++ b/ambari-web/app/mixins/common/configs/configs_saver.js
@@ -78,6 +78,24 @@ App.ConfigsSaverMixin = Em.Mixin.create({
   },
 
   /**
+   * get config group object for current service
+   * @param serviceName
+   * @returns {App.ConfigGroup}
+   */
+  getGroupFromModel: function(serviceName) {
+    if (this.get('selectedService.serviceName') === serviceName) {
+      return this.get('selectedConfigGroup');
+    } else {
+      var groups = App.ServiceConfigGroup.find().filterProperty('serviceName', serviceName);
+      if (this.get('selectedConfigGroup.isDefault')) {
+        return groups.length ? groups.findProperty('isDefault', true) : null;
+      } else {
+        return groups.length ? groups.findProperty('name', this.get('selectedConfigGroup.dependentConfigGroups')[serviceName]) : null;
+      }
+    }
+  },
+
+  /**
    * Save changed configs and config groups
    * @method saveConfigs
    */
@@ -106,22 +124,23 @@ App.ConfigsSaverMixin = Em.Mixin.create({
       this.get('stepConfigs').forEach(function(stepConfig) {
         var serviceName = stepConfig.get('serviceName');
         var configs = stepConfig.get('configs');
-        var configGroup = this.getGroupForService(serviceName);
+        var configGroup = this.getGroupFromModel(serviceName);
+        if (configGroup) {
+          if (configGroup.get('isDefault')) {
 
-        if (configGroup.get('isDefault')) {
+            var configsToSave = this.getServiceConfigToSave(serviceName, configs);
 
-          var configsToSave = this.getServiceConfigToSave(serviceName, configs);
+            if (configsToSave) {
+              this.putChangedConfigurations([configsToSave], false);
+            }
 
-          if (configsToSave) {
-            this.putChangedConfigurations([configsToSave], false);
-          }
-
-        } else {
+          } else {
 
-          var overridenConfigs = this.getConfigsForGroup(configs, configGroup.get('name'));
+            var overridenConfigs = this.getConfigsForGroup(configs, configGroup.get('name'));
 
-          if (Em.isArray(overridenConfigs)) {
-            this.saveGroup(overridenConfigs, configGroup, this.get('content.serviceName') === serviceName);
+            if (Em.isArray(overridenConfigs)) {
+              this.saveGroup(overridenConfigs, configGroup, this.get('content.serviceName') === serviceName);
+            }
           }
         }
       }, this);
@@ -565,7 +584,7 @@ App.ConfigsSaverMixin = Em.Mixin.create({
     });
     this.putConfigGroupChanges({
       ConfigGroup: {
-        "id": selectedConfigGroup.get('id'),
+        "id": selectedConfigGroup.get('configGroupId'),
         "cluster_name": App.get('clusterName'),
         "group_name": selectedConfigGroup.get('name'),
         "tag": selectedConfigGroup.get('service.id'),

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/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 cf6a400..f530b27 100644
--- a/ambari-web/app/mixins/common/configs/enhanced_configs.js
+++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js
@@ -124,7 +124,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({
    * @method setDependentGroups
    */
   setDependentGroups: function () {
-    if (this.get('isControllerSupportsEnhancedConfigs') && !this.get('selectedConfigGroup.isDefault') && this.get('selectedService.dependentServiceNames.length')) {
+    if (this.get('selectedConfigGroup') && this.get('isControllerSupportsEnhancedConfigs') && !this.get('selectedConfigGroup.isDefault') && this.get('selectedService.dependentServiceNames.length')) {
       this.get('selectedService.dependentServiceNames').forEach(function (serviceName) {
         if (!this.get('selectedConfigGroup.dependentConfigGroups')[serviceName]) {
           var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName);

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mixins/main/service/configs/config_overridable.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/main/service/configs/config_overridable.js b/ambari-web/app/mixins/main/service/configs/config_overridable.js
index 405e934..61eeb3d 100644
--- a/ambari-web/app/mixins/main/service/configs/config_overridable.js
+++ b/ambari-web/app/mixins/main/service/configs/config_overridable.js
@@ -126,6 +126,7 @@ App.ConfigOverridable = Em.Mixin.create({
         if (this.get('optionSelectConfigGroup')) {
           var selectedConfigGroup = this.get('selectedConfigGroup');
           this.hide();
+          App.get('router.mainServiceInfoConfigsController').loadSelectedVersion(null, this.get('selectedConfigGroup'));
           callback(selectedConfigGroup);
         } else {
           var newConfigGroupName = this.get('newConfigGroupName').trim();
@@ -442,6 +443,17 @@ App.ConfigOverridable = Em.Mixin.create({
       bodyClass: Em.View.extend({
         templateName: require('templates/common/configs/saveConfigGroup')
       }),
+      onPrimary:function() {
+        if (self.get('controller.name') == 'mainServiceInfoConfigsController') {
+          self.get('controller').loadConfigGroups([self.get('content.serviceName')], true).done(function() {
+            var group = App.ServiceConfigGroup.find().find(function(g) {
+              return g.get('serviceName') == self.get('content.serviceName') && g.get('name') == groupName;
+            });
+            self.get('controller').loadSelectedVersion(null, group);
+          });
+        }
+        this._super();
+      },
       onSecondary: function () {
         App.router.get('manageConfigGroupsController').manageConfigurationGroups(null, self.get('content'));
         this.hide();

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/mixins/main/service/groups_mapping.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/main/service/groups_mapping.js b/ambari-web/app/mixins/main/service/groups_mapping.js
index aaf42d7..dbbf5ed 100644
--- a/ambari-web/app/mixins/main/service/groups_mapping.js
+++ b/ambari-web/app/mixins/main/service/groups_mapping.js
@@ -28,10 +28,11 @@ App.GroupsMappingMixin = Em.Mixin.create({
   /**
    * Load config groups
    * @param {String[]} serviceNames
+   * @param skipDefault
    * @returns {$.Deferred()}
    * @method loadConfigGroups
    */
-  loadConfigGroups: function (serviceNames) {
+  loadConfigGroups: function (serviceNames, skipDefault) {
     var dfd = $.Deferred();
     if (!serviceNames || serviceNames.length === 0) {
       dfd.resolve();
@@ -40,7 +41,8 @@ App.GroupsMappingMixin = Em.Mixin.create({
         name: 'configs.config_groups.load.services',
         sender: this,
         data: {
-          serviceList: serviceNames.join(','),
+          serviceNames: serviceNames.join(','),
+          skipDefault: skipDefault,
           dfd: dfd
         },
         success: 'saveConfigGroupsToModel'
@@ -57,7 +59,7 @@ App.GroupsMappingMixin = Em.Mixin.create({
    * @method saveConfigGroupsToModel
    */
   saveConfigGroupsToModel: function (data, opt, params) {
-    App.configGroupsMapper.map(data, params.serviceList.split(','));
+    App.configGroupsMapper.map(data, false, params.serviceNames.split(','), params.skipDefault);
     params.dfd.resolve();
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/models.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models.js b/ambari-web/app/models.js
index 67e7375..b4a9d24 100644
--- a/ambari-web/app/models.js
+++ b/ambari-web/app/models.js
@@ -61,7 +61,7 @@ require('models/root_service');
 require('models/upgrade_entity');
 require('models/configs/service_config_version');
 require('models/configs/stack_config_property');
-//require('models/configs/config_group');
+require('models/configs/config_group');
 require('models/configs/config_version');
 require('models/configs/config_property');
 require('models/configs/tab');

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/models/configs/config_group.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/configs/config_group.js b/ambari-web/app/models/configs/config_group.js
index 898a510..0ad49ad 100644
--- a/ambari-web/app/models/configs/config_group.js
+++ b/ambari-web/app/models/configs/config_group.js
@@ -43,7 +43,119 @@ App.ServiceConfigGroup = DS.Model.extend({
   description: DS.attr('string'),
   hostNames: DS.attr('array'),
   configVersions: DS.hasMany('App.ConfigVersion'),
-  service: DS.belongsTo('App.Service')
+  service: DS.belongsTo('App.Service'),
+
+  /**
+   * same as hostNames
+   * @type {String[]}
+   */
+  hosts: function() {
+    return this.get('hostNames');
+  }.property('hostNames'),
+
+  /**
+   * defines if group is default
+   * @type {boolean}
+   */
+  isDefault: function() {
+    return this.get('configGroupId') == "-1";
+  }.property('configGroupId'),
+
+  /**
+   * list of group names that shows which config
+   * groups should be updated as dependent when current is changed
+   * @type App.ServiceConfigGroup[]
+   */
+  dependentConfigGroups: DS.attr('object', {defaultValue: {}}),
+
+  /**
+   * Parent configuration group for this group.
+   * When {@link #isDefault} is true, this value is <code>null</code>
+   * When {@link #isDefault} is false, this represents the configuration
+   * deltas that are applied on the default.
+   */
+  parentConfigGroup: DS.belongsTo('App.ServiceConfigGroup'),
+
+  /**
+   * Children configuration groups for this group.
+   * When {@link #isDefault} is false, this value is <code>null</code>
+   * When {@link #isDefault} is true, this represents the various
+   * configuration groups that override the default.
+   */
+  childConfigGroups: DS.hasMany('App.ServiceConfigGroup'),
+
+  /**
+   * Hosts on which this configuration-group
+   * is to be applied. For a service, a host can
+   * belong to only one non-default configuration-group.
+   *
+   * When {#isDefault} is false, this contains hosts
+   * for which the overrides will apply.
+   *
+   * When {#isDefault} is true, this value is empty, as
+   * it dynamically reflects hosts not belonging to other
+   * non-default groups.
+   *
+   */
+  properties: DS.attr('array'),
+
+  hash: DS.attr('string'),
+  /**
+   * Provides a display friendly name. This includes trimming
+   * names to a certain length.
+   */
+  displayName: function () {
+    var name = this.get('name');
+    if (name && name.length>App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
+      var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
+      name = name.substring(0, middle) + "..." + name.substring(name.length-middle);
+    }
+    return name;
+  }.property('name'),
+
+  /**
+   *
+   */
+  displayNameHosts: function () {
+    return this.get('displayName') + ' (' + this.get('hostNames.length') + ')';
+  }.property('displayName', 'hostNames.length'),
+
+  /**
+   * Provides hosts which are available for inclusion in
+   * non-default configuration groups.
+   */
+  availableHosts: function () {
+    if (this.get('isDefault')) return [];
+    var unusedHostsMap = {};
+    var availableHosts = [];
+    var sharedHosts = this.get('clusterHosts');
+    // parentConfigGroup.hosts(hosts from default group) - are available hosts, which don't belong to any group
+    this.get('parentConfigGroup.hosts').forEach(function (hostName) {
+      unusedHostsMap[hostName] = true;
+    });
+    sharedHosts.forEach(function (host) {
+      if (unusedHostsMap[host.get('id')]) {
+        availableHosts.pushObject(Ember.Object.create({
+          selected: false,
+          host: host,
+          hostComponentNames: host.get('hostComponents').mapProperty('componentName')
+        }));
+      }
+    });
+    return availableHosts;
+  }.property('isDefault', 'parentConfigGroup', 'childConfigGroups', 'parentConfigGroup.hosts.@each'),
+
+  isAddHostsDisabled: function () {
+    return (this.get('isDefault') || this.get('availableHosts.length') === 0);
+  }.property('availableHosts.length'),
+
+  propertiesList: function () {
+    var result = '';
+    this.get('properties').forEach(function (item) {
+      result += item.name + " : " + item.value + '<br/>';
+    }, this);
+    return result;
+  }.property('properties.length')
 });
 
 App.ServiceConfigGroup.FIXTURES = [];

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/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 2ec11c9..c4c5a3c 100644
--- a/ambari-web/app/utils/ajax/ajax.js
+++ b/ambari-web/app/utils/ajax/ajax.js
@@ -634,7 +634,7 @@ var urls = {
   },
 
   'configs.config_groups.load.services': {
-    'real': '/clusters/{clusterName}/config_groups?ConfigGroup/tag.in({serviceList})&fields=*',
+    'real': '/clusters/{clusterName}/config_groups?ConfigGroup/tag.in({serviceNames})&fields=*',
     'mock': '/data/configurations/config_groups.json'
   },
 
@@ -2317,9 +2317,13 @@ var urls = {
     real: '/clusters/{clusterName}/configurations/service_config_versions?service_name={serviceName}&fields=service_config_version,user,hosts,group_id,group_name,is_current,createtime,service_name,service_config_version_note,stack_id,is_cluster_compatible&minimal_response=true',
     mock: '/data/configurations/service_versions.json'
   },
+  'service.serviceConfigVersions.get.not.loaded': {
+    real: '/clusters/{clusterName}/configurations/service_config_versions?service_config_version>{lastSavedVersion}&service_name={serviceName}&fields=service_config_version,user,hosts,group_id,group_name,is_current,createtime,service_name,service_config_version_note,stack_id,is_cluster_compatible&minimal_response=true',
+    mock: '/data/configurations/service_versions_total.json'
+  },
   'service.serviceConfigVersions.get.current': {
-    real: '/clusters/{clusterName}?fields=Clusters/desired_service_config_versions&minimal_response=true',
-    mock: ''
+    real: '/clusters/{clusterName}/configurations/service_config_versions?service_name.in({serviceNames})&is_current=true&fields=*',
+    mock: '/data/configurations/service_versions.json'
   },
   'service.serviceConfigVersions.get.total': {
     real: '/clusters/{clusterName}/configurations/service_config_versions?page_size=1&minimal_response=true',

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index d599363..cd8a4e3 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -276,6 +276,87 @@ App.config = Em.Object.create({
     });
   },
 
+
+  mergePredefinedWithSaved: function (configCategories, advancedConfigs, serviceName) {
+    var configs = [];
+    var contentProperties = this.createContentProperties(advancedConfigs);
+    var preDefinedConfigs = this.get('preDefinedSiteProperties').concat(contentProperties);
+    var filenameExceptions = this.get('filenameExceptions');
+    configCategories.forEach(function (siteConfig) {
+      var service = this.getServiceByConfigType(siteConfig.type);
+      if (service) {
+        serviceName = service.get('serviceName');
+      }
+      var filename = App.config.getOriginalFileName(siteConfig.type);
+      var attributes = siteConfig['properties_attributes'] || {};
+      var finalAttributes = attributes.final || {};
+      var properties = siteConfig.properties || {};
+
+      for (var index in properties) {
+        var configsPropertyDef = preDefinedConfigs.filterProperty('name', index).findProperty('filename', filename);
+        var advancedConfig = advancedConfigs.filterProperty('name', index).findProperty('filename', filename);
+        var isAdvanced = Boolean(advancedConfig);
+        if (!configsPropertyDef) {
+          configsPropertyDef = advancedConfig;
+        }
+        var value = this.parseValue(properties[index], configsPropertyDef, advancedConfig);
+        var serviceConfigObj = App.ServiceConfig.create({
+          name: index,
+          value: value,
+          savedValue: value,
+          recommendedValue: advancedConfig ? Em.get(advancedConfig, 'recommendedValue') : null,
+          filename: filename,
+          isUserProperty: !advancedConfig,
+          isVisible: !!service,
+          isOverridable: true,
+          isReconfigurable: true,
+          isRequired: isAdvanced,
+          isFinal: finalAttributes[index] === "true",
+          savedIsFinal: finalAttributes[index] === "true",
+          recommendedIsFinal: advancedConfig ? Em.get(advancedConfig, 'recommendedIsFinal') : null,
+          showLabel: true,
+          serviceName: serviceName,
+          belongsToService: [],
+          supportsFinal: advancedConfig ? Em.get(advancedConfig, 'supportsFinal') : this.shouldSupportFinal(serviceName, siteConfig.type)
+        });
+        if (configsPropertyDef) {
+          this.setServiceConfigUiAttributes(serviceConfigObj, configsPropertyDef);
+          // check if defined UI config present in config list obtained from server.
+          // in case when config is absent on server and defined UI config is required
+          // by server, this config should be ignored
+          var serverProperty = properties[serviceConfigObj.get('name')];
+          if (Em.isNone(serverProperty) && serviceConfigObj.get('isRequiredByAgent')) {
+            continue;
+          }
+        }
+
+        this.tweakConfigVisibility(serviceConfigObj, properties);
+        if (!this.getBySiteName(serviceConfigObj.get('filename')).someProperty('name', index)) {
+          if (configsPropertyDef) {
+            if (Em.get(configsPropertyDef, 'isRequiredByAgent') === false) {
+              configs.push(serviceConfigObj);
+              continue;
+            }
+            this.handleSpecialProperties(serviceConfigObj);
+          } else {
+            serviceConfigObj.set('displayType', stringUtils.isSingleLine(serviceConfigObj.get('value')) ? 'advanced' : 'multiLine');
+          }
+          serviceConfigObj.setProperties({
+            'id': 'site property',
+            'displayName': configsPropertyDef && Em.get(configsPropertyDef, 'displayName') ? Em.get(configsPropertyDef, 'displayName') : index,
+            'options': configsPropertyDef ? Em.get(configsPropertyDef, 'options') : null,
+            'radioName': configsPropertyDef ? Em.get(configsPropertyDef, 'radioName') : null,
+            'serviceName': configsPropertyDef && Em.get(configsPropertyDef, 'serviceName') ? Em.get(configsPropertyDef, 'serviceName') : serviceName,
+            'belongsToService': configsPropertyDef && Em.get(configsPropertyDef, 'belongsToService') ? Em.get(configsPropertyDef, 'belongsToService') : []
+          });
+          this.calculateConfigProperties(serviceConfigObj, isAdvanced, advancedConfig);
+          this.setValueByDisplayType(serviceConfigObj);
+          configs.push(serviceConfigObj);
+        }
+      }
+    }, this);
+    return configs;
+  },
   /**
    * return:
    *   configs,
@@ -461,13 +542,11 @@ App.config = Em.Object.create({
    * synchronize order of config properties with order, that on UI side
    *
    * @method syncOrderWithPredefined
-   * @param configSet {object}
-   * @return {Object}
+   * @param {Object[]} siteConfigs
+   * @return {Object[]}
    */
-  syncOrderWithPredefined: function (configSet) {
-    var siteConfigs = configSet.configs,
-      siteStart = [];
-
+  syncOrderWithPredefined: function (siteConfigs) {
+    var siteStart = [];
     var preDefinedSiteProperties = this.get('preDefinedSiteProperties').mapProperty('name');
     var contentProperties = this.createContentProperties(siteConfigs).mapProperty('name');
     var siteProperties = preDefinedSiteProperties.concat(contentProperties);
@@ -484,10 +563,7 @@ App.config = Em.Object.create({
       }
     }, this);
 
-    return {
-      configs: siteStart.concat(siteConfigs.sortProperty('name')),
-      mappingConfigs: configSet.mappingConfigs
-    };
+    return siteStart.concat(siteConfigs.sortProperty('name'))
   },
 
   /**
@@ -1223,18 +1299,18 @@ App.config = Em.Object.create({
       if (/\d+m$/.test(hostOverrideValue)) {
         return hostOverrideValue.slice(0, hostOverrideValue.length - 1);
       }
-    } else if (serviceConfig && 
+    } else if (serviceConfig &&
                serviceConfig.displayType === 'masterHosts' &&
                typeof hostOverrideValue === 'string') {
       try {
         var value = JSON.parse(hostOverrideValue.replace(/'/g, "\""));
-        if (typeof value === 'object') { 
+        if (typeof value === 'object') {
           return value;
         }
       } catch(err) {
         console.error(err);
       }
-      
+
     }
     return hostOverrideValue;
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/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 51b48a4..b0e5bf6 100644
--- a/ambari-web/app/views/common/configs/config_history_flow.js
+++ b/ambari-web/app/views/common/configs/config_history_flow.js
@@ -326,7 +326,11 @@ App.ConfigHistoryFlowView = Em.View.extend({
   compare: function (event) {
     this.set('controller.compareServiceVersion', event.context);
     this.set('compareServiceVersion', event.context);
-    this.get('controller').onConfigGroupChange();
+    var controller = this.get('controller');
+    controller.get('stepConfigs').clear();
+    controller.loadCompareVersionConfigs(controller.get('allConfigs')).done(function() {
+      controller.onLoadOverrides(controller.get('allConfigs'));
+    });
   },
   removeCompareVersionBar: function () {
     var displayedVersion = this.get('displayedServiceVersion.version');

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js b/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
index a33175c..48d03d5 100644
--- a/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
+++ b/ambari-web/test/controllers/main/dashboard/config_history_controller_test.js
@@ -28,11 +28,11 @@ describe('MainConfigHistoryController', function () {
   describe('#realUrl', function () {
     it('cluster name is empty', function () {
       App.set('clusterName', '');
-      expect(controller.get('realUrl')).to.equal('/api/v1/clusters//configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note&minimal_response=true');
+      expect(controller.get('realUrl')).to.equal('/api/v1/clusters//configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible&minimal_response=true');
     });
     it('cluster name is "mycluster"', function () {
       App.set('clusterName', 'mycluster');
-      expect(controller.get('realUrl')).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note&minimal_response=true');
+      expect(controller.get('realUrl')).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?<parameters>fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible&minimal_response=true');
     });
   });
   describe('#load()', function () {
@@ -110,14 +110,14 @@ describe('MainConfigHistoryController', function () {
         if ('testMode' === k) return false;
         return Em.get(App, k);
       });
-      expect(controller.getUrl()).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note&minimal_response=true');
+      expect(controller.getUrl()).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?fields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible&minimal_response=true');
     });
     it('query params is correct', function () {
       sinon.stub(App, 'get', function(k) {
         if ('testMode' === k) return false;
         return Em.get(App, k);
       });
-      expect(controller.getUrl({})).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?paramsfields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note&minimal_response=true');
+      expect(controller.getUrl({})).to.equal('/api/v1/clusters/mycluster/configurations/service_config_versions?paramsfields=service_config_version,user,group_id,group_name,is_current,createtime,service_name,hosts,service_config_version_note,is_cluster_compatible&minimal_response=true');
     });
   });
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/test/controllers/main/host/configs_service_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/host/configs_service_test.js b/ambari-web/test/controllers/main/host/configs_service_test.js
index 02b5b6b..9f5f73b 100644
--- a/ambari-web/test/controllers/main/host/configs_service_test.js
+++ b/ambari-web/test/controllers/main/host/configs_service_test.js
@@ -129,12 +129,10 @@ describe('App.MainHostServiceConfigsController', function () {
 
     beforeEach(function() {
       sinon.stub(controller, 'launchSwitchConfigGroupOfHostDialog', Em.K);
-      sinon.stub(controller, 'onConfigGroupChange', Em.K);
-    });
+      });
 
     afterEach(function () {
       controller.launchSwitchConfigGroupOfHostDialog.restore();
-      controller.onConfigGroupChange.restore();
     });
 
 		it("should call launchSwitchConfigGroupOfHostDialog", function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/test/controllers/main/service/info/config_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/info/config_test.js b/ambari-web/test/controllers/main/service/info/config_test.js
index 4520b89..50d7116 100644
--- a/ambari-web/test/controllers/main/service/info/config_test.js
+++ b/ambari-web/test/controllers/main/service/info/config_test.js
@@ -354,10 +354,6 @@ describe("App.MainServiceInfoConfigsController", function () {
     afterEach(function () {
       Em.run.once.restore();
     });
-    it("trigger onConfigGroupChange", function () {
-      mainServiceInfoConfigsController.doCancel();
-      expect(Em.run.once.calledWith(mainServiceInfoConfigsController, "onConfigGroupChange")).to.equal(true);
-    });
 
     it("should clear dependent configs", function() {
       mainServiceInfoConfigsController.set('groupsToSave', { HDFS: 'my cool group'});

http://git-wip-us.apache.org/repos/asf/ambari/blob/27c6d754/ambari-web/test/views/common/configs/config_history_flow_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/configs/config_history_flow_test.js b/ambari-web/test/views/common/configs/config_history_flow_test.js
index edde670..c272436 100644
--- a/ambari-web/test/views/common/configs/config_history_flow_test.js
+++ b/ambari-web/test/views/common/configs/config_history_flow_test.js
@@ -25,7 +25,6 @@ describe.skip('App.ConfigHistoryFlowView', function () {
   var view = App.ConfigHistoryFlowView.create({
     controller: Em.Object.create({
       loadSelectedVersion: Em.K,
-      onConfigGroupChange: Em.K,
       loadStep: Em.K
     }),
     displayedServiceVersion: Em.Object.create(),
@@ -509,12 +508,9 @@ describe.skip('App.ConfigHistoryFlowView', function () {
 
   describe('#compare()', function () {
     it('should set compareServiceVersion', function () {
-      sinon.spy(view.get('controller'), 'onConfigGroupChange');
       view.compare({context: Em.Object.create({version: 1})});
 
       expect(view.get('controller.compareServiceVersion')).to.eql(Em.Object.create({version: 1}));
-      expect(view.get('controller').onConfigGroupChange.calledOnce).to.be.true;
-      view.get('controller').onConfigGroupChange.restore();
     });
   });