Repository: ambari Updated Branches: refs/heads/trunk 8acfcd892 -> 810d6e82b
AMBARI-14483 Improve config recommendations flow. (ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/810d6e82 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/810d6e82 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/810d6e82 Branch: refs/heads/trunk Commit: 810d6e82b03726f68b45b9c31cfc37469ea5decb Parents: 8acfcd8 Author: ababiichuk <ababiic...@hortonworks.com> Authored: Wed Dec 23 15:15:05 2015 +0200 Committer: ababiichuk <ababiic...@hortonworks.com> Committed: Thu Dec 24 13:15:40 2015 +0200 ---------------------------------------------------------------------- .../controllers/main/service/info/configs.js | 6 +- .../app/controllers/wizard/step7_controller.js | 26 +- .../mixins/common/configs/enhanced_configs.js | 601 ++++++++----------- ambari-web/app/mixins/common/serverValidator.js | 6 +- ambari-web/app/utils/config.js | 16 +- ambari-web/app/views/common/controls_view.js | 5 +- .../dependent_configs_list_popup.js | 7 +- 7 files changed, 286 insertions(+), 381 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/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 c59bd91..1eef9a1 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -445,8 +445,8 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A for (var prop in config.properties) { var fileName = App.config.getOriginalFileName(config.type); var serviceConfig = allConfigs.filterProperty('name', prop).findProperty('filename', fileName); + var value = App.config.formatPropertyValue(serviceConfig, config.properties[prop]); if (serviceConfig) { - var value = App.config.formatPropertyValue(serviceConfig, config.properties[prop]); var isFinal = !!(config.properties_attributes && config.properties_attributes.final && config.properties_attributes.final[prop]); if (self.get('selectedConfigGroup.isDefault') || configGroup.get('name') == self.get('selectedConfigGroup.name')) { var overridePlainObject = { @@ -460,7 +460,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A } } else { var isEditable = self.get('canEdit') && configGroup.get('name') == self.get('selectedConfigGroup.name'); - allConfigs.push(App.config.createCustomGroupConfig(prop, config, configGroup, isEditable)); + allConfigs.push(App.config.createCustomGroupConfig(prop, fileName, value, configGroup, isEditable)); } } }); @@ -494,7 +494,7 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ConfigsLoader, A } else { App.config.removeRangerConfigs(this.get('stepConfigs')); } - this.getRecommendationsForDependencies(null, true, function () {self._onLoadComplete();}, this.get('selectedConfigGroup')); + this.getRecommendationsForDependencies(null, true, function () {self._onLoadComplete();}); App.loadTimer.finish('Service Configs Page'); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/ambari-web/app/controllers/wizard/step7_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/wizard/step7_controller.js b/ambari-web/app/controllers/wizard/step7_controller.js index 608b163..2726236 100644 --- a/ambari-web/app/controllers/wizard/step7_controller.js +++ b/ambari-web/app/controllers/wizard/step7_controller.js @@ -485,7 +485,7 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E if (!Em.get(serviceConfig, 'overrides')) Em.set(serviceConfig, 'overrides', []); serviceConfig.overrides.pushObject({value: hostOverrideValue, group: group, isFinal: hostOverrideIsFinal}); } else { - params.serviceConfigs.push(App.config.createCustomGroupConfig(prop, config, group)); + params.serviceConfigs.push(App.config.createCustomGroupConfig(prop, fileName, config.properties[prop], group)); } } }); @@ -707,29 +707,15 @@ App.WizardStep7Controller = Em.Controller.extend(App.ServerValidatorMixin, App.E App.config.removeRangerConfigs(self.get('stepConfigs')); } this.loadServerSideConfigsRecommendations().always(function() { - self.updateConfigsRecommendations(); + if (self.get('wizardController.name') == 'addServiceController') { + // for Add Service just remove or add dependent properties and ignore config values changes + // for installed services only + self.clearDependenciesForInstalledServices(self.get('installedServiceNames'), self.get('stepConfigs')); + } self.completeConfigLoading(); }); }, - /** - * update dependent configs based on recommendations from - * stack adviser - * - * @method updateConfigsRecommendations - */ - updateConfigsRecommendations: function() { - if (this.get('wizardController.name') == 'addServiceController') { - // for Add Service just remove or add dependent properties and ignore config values changes - // for installed services only - this.clearDependenciesForInstalledServices(this.get('installedServiceNames'), this.get('stepConfigs')); - } - // * add dependencies based on recommendations - // * update config values with recommended - // * remove properties received from recommendations - this.updateDependentConfigs(); - }, - completeConfigLoading: function() { this.clearDependentConfigsByService(App.StackService.find().filterProperty('isSelected').mapProperty('serviceName')); console.timeEnd('wizard loadStep: '); http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/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 230493b..7efcf55 100644 --- a/ambari-web/app/mixins/common/configs/enhanced_configs.js +++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js @@ -252,14 +252,11 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ * @param {{type: string, name: string}[]} changedConfigs - list of changed configs to track recommendations * @param {Boolean} initial * @param {Function} onComplete - * @param {App.ConfigGroup|null} [configGroup=null] * @returns {$.ajax|null} */ - getRecommendationsForDependencies: function(changedConfigs, initial, onComplete, configGroup) { + getRecommendationsForDependencies: function(changedConfigs, initial, onComplete) { if (Em.isArray(changedConfigs) && changedConfigs.length > 0 || initial) { - if (!configGroup) { - configGroup = this.get('selectedConfigGroup'); - } + var configGroup = this.get('selectedConfigGroup'); var recommendations = this.get('hostGroups'); delete recommendations.config_groups; @@ -289,7 +286,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ data: { stackVersionUrl: App.get('stackVersionURL'), dataToSend: dataToSend, - selectedConfigGroup: configGroup.get('isDefault') ? null : configGroup.get('name'), + notDefaultGroup: configGroup && !configGroup.get('isDefault'), initial: initial, clearConfigsOnAddService: clearConfigsOnAddService }, @@ -382,15 +379,15 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ * @method dependenciesSuccess */ dependenciesSuccess: function (data, opt, params) { - this._saveRecommendedValues(data, params.initial, params.dataToSend.changed_configurations, params.selectedConfigGroup); + this._saveRecommendedValues(data, params.initial, params.dataToSend.changed_configurations, params.notDefaultGroup); this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations")); if (params.clearConfigsOnAddService) { - this.clearDependenciesForInstalledServices(this.get('installedServiceNames'), this.get('stepConfigs')); + if (this.get('wizardController.name') == 'addServiceController') { + this.clearDependenciesForInstalledServices(this.get('installedServiceNames'), this.get('stepConfigs')); + } this.clearConfigValues(); } - if (!params.initial) { - this.updateDependentConfigs(); - } + this.set('recommendationTimeStamp', (new Date).getTime()); }, /** @@ -398,14 +395,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ * @method showChangedDependentConfigs */ showChangedDependentConfigs: function(event, callback, secondary) { - var self = this; if (this.get('_dependentConfigValues.length') > 0) { - App.showDependentConfigsPopup(this.get('changedProperties'), function() { - self.updateDependentConfigs(); - if (callback) { - callback(); - } - }, secondary); + App.showDependentConfigsPopup(this.get('changedProperties'), this.onSaveRecommendedPopup.bind(this), secondary); } else { if (callback) { callback(); @@ -414,8 +405,46 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ }, /** - * + * run through config properties list (form dependent popup) + * and set value to default (undo) or recommended (redo) + * this happens when toggle checkbox in popup + * @param {Object[]} propertiesToUpdate + * @param {boolean} redo */ + undoRedoRecommended: function(propertiesToUpdate, redo) { + propertiesToUpdate.forEach(function(p) { + var initial = redo ? Em.get(p, 'value') : Em.get(p, 'recommendedValue'); + var recommended = redo ? Em.get(p, 'recommendedValue') : Em.get(p, 'value'); + var stepConfig = this.get('stepConfigs').findProperty('serviceName', Em.get(p, 'serviceName')); + var config = stepConfig.get('configs').find(function(scp) { + return scp.get('name') == Em.get(p, 'propertyName') && scp.get('filename') == Em.get(p, 'fileName'); + }); + var selectedGroup = App.ServiceConfigGroup.find().filterProperty('serviceName', Em.get(p, 'serviceName')).findProperty('name', Em.get(p, 'configGroup')); + if (Em.isNone(recommended)) { + if (selectedGroup.get('isDefault')) { + stepConfig.get('configs').removeObject(config); + } else { + config.get('overrides').removeObject(this._getOverride(config, selectedGroup)); + } + } else if (Em.isNone(initial)) { + this._addConfigByRecommendation(stepConfig, selectedGroup, Em.get(p, 'propertyName'), Em.get(p, 'fileName'), Em.get(p, 'serviceName'), recommended, initial, config); + } else { + Em.set(config, 'value', recommended); + } + }, this); + }, + + /** + * update configs when toggle checkbox on dependent configs popup + * @param propertiesToUndo + * @param propertiesToRedo + */ + onSaveRecommendedPopup: function(propertiesToUndo, propertiesToRedo) { + this.undoRedoRecommended(propertiesToUndo, false); + this.undoRedoRecommended(propertiesToRedo, true); + this.set('recommendationTimeStamp', (new Date).getTime()); + }, + changedDependentGroup: function() { var dependentServices = this.get('stepConfigs').filter(function(stepConfig) { return this.get('selectedService.dependentServiceNames').contains(stepConfig.get('serviceName')); @@ -442,37 +471,34 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ * @param data * @param [updateOnlyBoundaries=false] * @param [changedConfigs=null] + * @param notDefaultGroup + * @param updateInitial * @method saveRecommendedValues * @private */ - _saveRecommendedValues: function(data, updateOnlyBoundaries, changedConfigs, selectedConfigGroup) { + _saveRecommendedValues: function(data, updateOnlyBoundaries, changedConfigs, notDefaultGroup, updateInitial) { Em.assert('invalid data - `data.resources[0].recommendations.blueprint.configurations` not defined ', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations')); var configObject = data.resources[0].recommendations.blueprint.configurations; - if (!selectedConfigGroup) { - this.parseConfigsByTag(configObject, updateOnlyBoundaries, changedConfigs, selectedConfigGroup); + if (!notDefaultGroup) { + this.parseConfigsByTag(configObject, changedConfigs, updateInitial, updateOnlyBoundaries); } else if (data.resources[0].recommendations['config-groups']){ var configFroGroup = data.resources[0].recommendations['config-groups'][0]; - this.parseConfigsByTag(configFroGroup.configurations, updateOnlyBoundaries, changedConfigs, selectedConfigGroup); - this.parseConfigsByTag(configFroGroup.dependent_configurations, updateOnlyBoundaries, changedConfigs, selectedConfigGroup); + this.parseConfigsByTag(configFroGroup.configurations, changedConfigs, updateInitial, updateOnlyBoundaries); + this.parseConfigsByTag(configFroGroup.dependent_configurations, changedConfigs, updateInitial, updateOnlyBoundaries); } + this._cleanUpPopupProperties(); }, /** * saves values from response for dependent configs to <code>_dependentConfigValues<code> * @param configObject - JSON response from `recommendations` endpoint - * @param updateOnlyBoundaries - * @param selectedConfigGroup * @param {App.ServiceConfigProperty[]} parentConfigs - config properties for which recommendations were received + * @param updateInitial + * @param updateOnlyBoundaries * @method saveRecommendedValues * @private */ - parseConfigsByTag: function(configObject, updateOnlyBoundaries, parentConfigs, selectedConfigGroup) { - var wizardController = this.get('wizardController'); - if (wizardController) { - var fileNamesToUpdate = wizardController.getDBProperty('fileNamesToUpdate') || []; - this.set('_fileNamesToUpdate', fileNamesToUpdate); - } - var notDefaultGroup = !!selectedConfigGroup; + parseConfigsByTag: function(configObject, parentConfigs, updateInitial, updateOnlyBoundaries) { var parentPropertiesNames = parentConfigs ? parentConfigs.map(function(p) { return App.config.configId(Em.get(p, 'name'), Em.get(p, 'type'))}) : []; /** get all configs by config group **/ for (var key in configObject) { @@ -482,7 +508,6 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ var serviceName = service.get('serviceName'); var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName); if (stepConfig) { - var initialValue; var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(key)) : []; var group = this.getGroupForService(serviceName); @@ -490,103 +515,24 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ for (var propertyName in configObject[key].properties) { var cp = configProperties.findProperty('name', propertyName); - var override = (notDefaultGroup && group && cp && cp.get('overrides')) ? cp.get('overrides').findProperty('group.name', group.get('name')) : null; - var value = override ? override.get('value') : cp && cp.get('value'); - - if (this.useInitialValue(serviceName)) { - initialValue = override ? override.get('initialValue') : cp && cp.get('initialValue'); - } else { - initialValue = override ? override.get('savedValue') : cp && cp.get('savedValue'); - } - - var recommendedValue = configObject[key].properties[propertyName]; - - var isNewProperty = (!notDefaultGroup && Em.isNone(cp)) || (notDefaultGroup && group && Em.isNone(override)); - - initialValue = validator.isValidFloat(initialValue) ? parseFloat(initialValue).toString() : initialValue; - recommendedValue = validator.isValidFloat(recommendedValue) ? parseFloat(recommendedValue).toString() : recommendedValue; - - var groupName = group && Em.get(group, 'name'); - var dependentProperty = this.get('_dependentConfigValues').find(function (dcv) { - return dcv.propertyName === propertyName && dcv.fileName === key && dcv.configGroup === groupName; - }); - - if (!updateOnlyBoundaries && !parentPropertiesNames.contains(App.config.configId(propertyName, key)) && initialValue != recommendedValue) { //on first initial request we don't need to change values - if (dependentProperty) { - Em.set(dependentProperty, 'value', initialValue); - Em.set(dependentProperty, 'notDefined', Em.isNone(initialValue)); - Em.set(dependentProperty, 'recommendedValue', recommendedValue); - Em.set(dependentProperty, 'toDelete', false); // handled in <code>saveRecommendedAttributes</code> - Em.set(dependentProperty, 'toAdd', isNewProperty); - Em.set(dependentProperty, 'parentConfigs', dependentProperty.parentConfigs.concat(parentPropertiesNames).uniq()); - } else { - this.get('_dependentConfigValues').pushObject({ - saveRecommended: true, - saveRecommendedDefault: true, - toDelete: false, - isDeleted: false, // handled in <code>saveRecommendedAttributes</code> - toAdd: isNewProperty, - fileName: key, - propertyName: propertyName, - configGroup: group ? group.get('name') : "", - value: initialValue, - notDefined: Em.isNone(initialValue), - parentConfigs: parentPropertiesNames, - serviceName: serviceName, - allowChangeGroup: !this.get('selectedService.isDefault') && service.get('serviceName') != stepConfig.get('serviceName') && stepConfig.get('configGroups.length') > 1, - serviceDisplayName: service.get('displayName'), - recommendedValue: recommendedValue - }); - } - } + var configPropertyObject = (!group || group.get('isDefault')) ? cp : this._getOverride(cp, group); - /** - * saving recommended value to service config properties - * this value can be used as marker on slider widget - */ - if (notDefaultGroup) { - override && override.set('recommendedValue', recommendedValue); - } else { - cp && cp.set('recommendedValue', recommendedValue); + var recommendedValue = this.getFormattedValue(configObject[key].properties[propertyName]); + var popupProperty = this.getPopupProperty(propertyName, key, Em.get(group || {}, 'name')); + var initialValue = this._getInitialValue(configObject, popupProperty, serviceName, recommendedValue, updateInitial); + if (configPropertyObject) { + this._updateConfigByRecommendation(configPropertyObject, recommendedValue, updateInitial, updateOnlyBoundaries); + } else if (!updateOnlyBoundaries) { + this._addConfigByRecommendation(stepConfig, group, propertyName, key, serviceName, recommendedValue, initialValue, cp); } if (!updateOnlyBoundaries) { - /** - * clear _dependentPropertyValues from - * properties that wasn't changed while recommendations - */ - - if ((initialValue == recommendedValue) || (Em.isNone(initialValue) && Em.isNone(recommendedValue))) { - /** if recommended value same as default we shouldn't show it in popup **/ - if (notDefaultGroup) { - if (override) { - if (override.get('isNotSaved')) { - cp.get('overrides').removeObject(override); - } else { - override.set('value', initialValue); - } - if (dependentProperty) { - this.get('_dependentConfigValues').removeObject(dependentProperty); - } - } - } else { - cp.set('value', initialValue); - if (!this.useInitialValue(serviceName)) { - cp.set('savedValue', initialValue); - } - if (dependentProperty) { - this.get('_dependentConfigValues').removeObject(dependentProperty); - } - } - } + this._updatePopup(popupProperty, propertyName, key, recommendedValue, Em.get(configPropertyObject || {}, 'initialValue'), service, Em.get(group || {},'name') || "Default", parentPropertiesNames); } } } - this._saveRecommendedAttributes(configObject, parentPropertiesNames, updateOnlyBoundaries, selectedConfigGroup); - } - if (wizardController) { - wizardController.setDBProperty('fileNamesToUpdate', this.get('_fileNamesToUpdate').uniq()); } + this.parseConfigAttributes(configObject, parentPropertiesNames, updateOnlyBoundaries); }, installedServices: function () { @@ -604,266 +550,233 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ * @param updateOnlyBoundaries * @private */ - _saveRecommendedAttributes: function(configs, parentPropertiesNames, updateOnlyBoundaries, selectedConfigGroup) { + parseConfigAttributes: function(configs, parentPropertiesNames, updateOnlyBoundaries) { var self = this; - var installedServices = this.get('installedServices'); - var wizardController = this.get('wizardController'); - var fileNamesToUpdate = wizardController ? this.get('_fileNamesToUpdate') : []; Em.keys(configs).forEach(function (siteName) { - var fileName = App.config.getOriginalFileName(siteName); - var service = App.config.get('serviceByConfigTypeMap')[siteName]; - var serviceName = service.get('serviceName'); - var group = self.getGroupForService(serviceName); - var stepConfig = self.get('stepConfigs').findProperty('serviceName', serviceName); - var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(siteName)) : []; - var properties = configs[siteName].property_attributes || {}; - Em.keys(properties).forEach(function (propertyName) { - var cp = configProperties.findProperty('name', propertyName); - var stackProperty = App.configsCollection.getConfigByName(propertyName, siteName); - var attributes = properties[propertyName] || {}; - Em.keys(attributes).forEach(function (attributeName) { - if (attributeName == 'delete' && cp) { - if (!updateOnlyBoundaries) { - var modifiedFileNames = self.get('modifiedFileNames'); - var groupName = group && Em.get(group,'name'); - var dependentProperty = self.get('_dependentConfigValues').find(function (dcv) { - return dcv.propertyName === propertyName && dcv.fileName === siteName && dcv.configGroup === groupName; - }); - if (dependentProperty) { - Em.set(dependentProperty, 'toDelete', true); - Em.set(dependentProperty, 'toAdd', false); - Em.set(dependentProperty, 'recommendedValue', null); - } else { - self.get('_dependentConfigValues').pushObject({ - saveRecommended: true, - saveRecommendedDefault: true, - value: cp && (self.useInitialValue(serviceName) ? cp.get('initialValue') : cp.get('savedValue')), - toDelete: true, - toAdd: false, - isDeleted: true, - fileName: siteName, - propertyName: propertyName, - configGroup: group ? group.get('name') : "", - parentConfigs: parentPropertiesNames, - serviceName: service.get('serviceName'), - allowChangeGroup: !self.get('selectedService.isDefault') && service.get('serviceName') != stepConfig.get('serviceName') && stepConfig.get('configGroups.length') > 1, - serviceDisplayName: service.get('displayName'), - recommendedValue: null - }); - } - if (modifiedFileNames && !modifiedFileNames.contains(fileName)) { - modifiedFileNames.push(fileName); - } else if (wizardController && installedServices[service.get('serviceName')]) { - if (!fileNamesToUpdate.contains(fileName)) { - fileNamesToUpdate.push(fileName); + var fileName = App.config.getOriginalFileName(siteName), + service = App.config.get('serviceByConfigTypeMap')[siteName]; + var serviceName = service && service.get('serviceName'), + stepConfig = self.get('stepConfigs').findProperty('serviceName', serviceName); + if (stepConfig) { + var group = self.getGroupForService(serviceName), + configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(siteName)) : [], + properties = configs[siteName].property_attributes || {}; + Em.keys(properties).forEach(function (propertyName) { + var cp = configProperties.findProperty('name', propertyName); + var stackProperty = App.configsCollection.getConfigByName(propertyName, siteName); + var configObject = (!group || group.get('isDefault')) ? cp : self._getOverride(cp, group); + var configsCollection = !group || group.get('isDefault') ? stepConfig.get('configs') : Em.getWithDefault(cp, 'overrides', []); + var dependentProperty = self.getPopupProperty(propertyName, fileName, Em.get(group || {},'name')); + var attributes = properties[propertyName] || {}; + Em.keys(attributes).forEach(function (attributeName) { + if (attributeName == 'delete' && configObject) { + if (!updateOnlyBoundaries) { + self._removeConfigByRecommendation(configObject, configsCollection); + self._updatePopup(dependentProperty, propertyName, siteName, null, Em.get(configObject, 'initialValue'), service, Em.get(group || {},'name') || "Default", parentPropertiesNames); + } + } else if (stackProperty) { + var selectedConfigGroup = group && !group.get('isDefault') ? group.get('name') : null; + if (selectedConfigGroup) { + if (!stackProperty.valueAttributes[selectedConfigGroup]) { + /** create not default group object for updating such values as min/max **/ + Em.set(stackProperty.valueAttributes, selectedConfigGroup, {}); + } + if (stackProperty.valueAttributes[selectedConfigGroup][attributeName] != attributes[attributeName]) { + Em.set(stackProperty.valueAttributes[selectedConfigGroup], attributeName, attributes[attributeName]); + self.toggleProperty('forceUpdateBoundaries'); + } + } else { + Em.set(stackProperty.valueAttributes, attributeName, attributes[attributeName]); + } } - } - } - } else if (stackProperty) { - if (selectedConfigGroup) { - if (!stackProperty.valueAttributes[selectedConfigGroup]) { - /** create not default group object for updating such values as min/max **/ - Em.set(stackProperty.valueAttributes, selectedConfigGroup, {}); - } - if (stackProperty.valueAttributes[selectedConfigGroup][attributeName] != attributes[attributeName]) { - Em.set(stackProperty.valueAttributes[selectedConfigGroup], attributeName, attributes[attributeName]); - self.toggleProperty('forceUpdateBoundaries'); - } - } else { - Em.set(stackProperty.valueAttributes, attributeName, attributes[attributeName]); - } - } - }); - }); + }); + }); + } }); - this.set('_fileNamesToUpdate', fileNamesToUpdate); }, /** - * save values that are stored in <code>_dependentConfigValues<code> - * to step configs + * update config based on recommendations + * @param config + * @param recommendedValue + * @param updateInitial + * @param updateOnlyBoundaries + * @private */ - updateDependentConfigs: function() { - var self = this; - this.get('stepConfigs').forEach(function(serviceConfigs) { - var selectedGroup = self.getGroupForService(serviceConfigs.get('serviceName')); - if (selectedGroup) { - self._updateRecommendedValues(serviceConfigs, selectedGroup); - - self._addRecommendedProperties(serviceConfigs, selectedGroup); + _updateConfigByRecommendation: function(config, recommendedValue, updateInitial, updateOnlyBoundaries) { + Em.assert('config should be defined', config); + Em.set(config, 'recommendedValue', recommendedValue); + if (!updateOnlyBoundaries) Em.set(config, 'value', recommendedValue); + if (updateInitial && Em.isNone(Em.get(config, 'savedValue'))) Em.set(config, 'initialValue', recommendedValue); + }, - self._removeUnRecommendedProperties(serviceConfigs, selectedGroup); + /** + * remove config based on recommendations + * @param config + * @param configsCollection + * @private + */ + _removeConfigByRecommendation: function(config, configsCollection) { + Em.assert('config and configsCollection should be defined', config && configsCollection); + configsCollection.removeObject(config); + /** + * need to update wizard info when removing configs for installed services; + */ + var installedServices = this.get('installedServices'), wizardController = this.get('wizardController'), + fileNamesToUpdate = wizardController ? wizardController.getDBProperty('fileNamesToUpdate') || [] : [], + fileName = Em.get(config, 'filename'), serviceName = Em.get(config, 'serviceName'); + var modifiedFileNames = this.get('modifiedFileNames'); + if (modifiedFileNames && !modifiedFileNames.contains(fileName)) { + modifiedFileNames.push(fileName); + } else if (wizardController && installedServices[serviceName]) { + if (!fileNamesToUpdate.contains(fileName)) { + fileNamesToUpdate.push(fileName); } - }); - this.set('recommendationTimeStamp', (new Date).getTime()); + } + if (wizardController) { + wizardController.setDBProperty('fileNamesToUpdate', fileNamesToUpdate.uniq()); + } }, /** - * add configs that was recommended and wasn't present in stepConfigs + * add config based on recommendations * @param stepConfigs * @param selectedGroup + * @param name + * @param fileName + * @param serviceName + * @param recommendedValue + * @param initialValue + * @param cp * @private */ - _addRecommendedProperties: function(stepConfigs, selectedGroup) { - var propertiesToAdd = this.get('_dependentConfigValues').filterProperty('toAdd').filterProperty('serviceName', stepConfigs.get('serviceName')).filterProperty('configGroup', selectedGroup.get('name')); - if (propertiesToAdd.length > 0) { - propertiesToAdd.forEach(function(propertyToAdd) { - if (!selectedGroup || selectedGroup.get('isDefault')) { - if (Em.get(propertyToAdd, 'isDeleted')) { - this.get('_dependentConfigValues').removeObject(propertyToAdd); - } - var originalFileName = App.config.getOriginalFileName(Em.get(propertyToAdd, 'fileName')); - var stackProperty = App.configsCollection.getConfigByName(Em.get(propertyToAdd, 'propertyName'), Em.get(propertyToAdd, 'fileName')); - var addedProperty = App.ServiceConfigProperty.create({ - name: Em.get(propertyToAdd, 'propertyName'), - displayName: Em.get(propertyToAdd, 'propertyName'), - value: Em.get(propertyToAdd, 'recommendedValue'), - recommendedValue: Em.get(propertyToAdd, 'recommendedValue'), - savedValue: null, - category: 'Advanced ' + Em.get(propertyToAdd, 'fileName'), - serviceName: stepConfigs.get('serviceName'), - filename: originalFileName, - isNotSaved: !Em.get(propertyToAdd, 'isDeleted'), - isRequired: stackProperty && stackProperty.isRequired !== false - }); - if (!Em.get(propertyToAdd, 'isDeleted')) { - addedProperty.set('initialValue', null); - } - stepConfigs.get('configs').pushObject(addedProperty); - addedProperty.validate(); - } else { - var cp = stepConfigs.get('configs').filterProperty('name', Em.get(propertyToAdd, 'propertyName')).findProperty('filename', App.config.getOriginalFileName(Em.get(propertyToAdd, 'fileName'))); - if (Em.get(propertyToAdd, 'isDeleted')) { - this.get('_dependentConfigValues').removeObject(propertyToAdd); - } - var overriddenProperty = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name')); - if (overriddenProperty) { - overriddenProperty.set('value', Em.get(propertyToAdd, 'recommendedValue')); - overriddenProperty.set('recommendedValue', Em.get(propertyToAdd, 'recommendedValue')); - } else { - var overridePlainObject = { - "value": Em.get(propertyToAdd, 'recommendedValue'), - "recommendedValue": Em.get(propertyToAdd, 'recommendedValue'), - "isNotSaved": !Em.get(propertyToAdd, 'isDeleted'), - "isEditable": true - }; - App.config.createOverride(cp, overridePlainObject, selectedGroup); - } - } - Em.setProperties(propertyToAdd, { - isDeleted: Em.get(propertyToAdd, 'isDeleted'), - toAdd: false, - toDelete: false - }); - }, this); + _addConfigByRecommendation: function(stepConfigs, selectedGroup, name, fileName, serviceName, recommendedValue, initialValue, cp) { + fileName = App.config.getOriginalFileName(fileName); + var coreObject = { + "value": recommendedValue, + "recommendedValue": recommendedValue, + "initialValue": initialValue, + "savedValue": !this.useInitialValue(serviceName) && !Em.isNone(initialValue) ? initialValue : null, + "isEditable": true + }; + if (!selectedGroup || selectedGroup.get('isDefault')) { + var addedProperty = App.configsCollection.getConfigByName(name, fileName) || App.config.createDefaultConfig(name, serviceName, fileName, false, coreObject); + var addedPropertyObject = App.ServiceConfigProperty.create(addedProperty); + stepConfigs.get('configs').pushObject(addedPropertyObject); + addedPropertyObject.validate(); + } else { + if (cp) { + var newOverride = App.config.createOverride(cp, coreObject, selectedGroup); + selectedGroup.get('properties').pushObject(newOverride); + } else { + stepConfigs.get('configs').push(App.config.createCustomGroupConfig(name, fileName, recommendedValue, selectedGroup, true, true)); + } } }, /** - * remove configs that was recommended to delete from stepConfigs - * @param stepConfigs - * @param selectedGroup + * @param configProperty + * @param popupProperty + * @param serviceName + * @param recommendedValue + * @param updateInitial + * @returns {*} * @private */ - _removeUnRecommendedProperties: function(stepConfigs, selectedGroup) { - var propertiesToDelete = this.get('_dependentConfigValues').filterProperty('toDelete').filterProperty('serviceName', stepConfigs.get('serviceName')).filterProperty('configGroup', selectedGroup.get('name')); - if (propertiesToDelete.length > 0) { - - propertiesToDelete.forEach(function(propertyToDelete) { - var cp = stepConfigs.get('configs').filterProperty('name', Em.get(propertyToDelete, 'propertyName')).findProperty('filename', App.config.getOriginalFileName(Em.get(propertyToDelete, 'fileName'))); - if (cp) { - if (!selectedGroup || selectedGroup.get('isDefault')) { - if (cp.get('isNotSaved')) { - this.get('_dependentConfigValues').removeObject(propertyToDelete); - } - stepConfigs.get('configs').removeObject(cp); - if (!cp.get('isNotSaved')) { - Em.set(propertyToDelete, 'isDeleted', true); - } - } else { - var overriddenConfig = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name')); - if (overriddenConfig) { - if (overriddenConfig.get('isNotSaved')) { - this.get('_dependentConfigValues').removeObject(propertyToDelete); - } - cp.removeObject(overriddenConfig); - if (!overriddenConfig.get('isNotSaved')) { - Em.set(propertyToDelete, 'isDeleted', true); - } - } - } - Em.setProperties(propertyToDelete, { - toAdd: false, - toDelete: false - }); - } else { - this.get('_dependentConfigValues').removeObject(propertyToDelete); - } - }, this); + _getInitialValue: function(configProperty, popupProperty, serviceName, recommendedValue, updateInitial) { + if (!this.useInitialValue(serviceName)) { + return configProperty ? Em.get(configProperty, 'savedValue') : null; + } else if (updateInitial) { + return recommendedValue; + } else { + return popupProperty ? popupProperty.value : configProperty ? Em.get(configProperty, 'initialValue') : null; } }, /** - * update config to their recommended values - * @param stepConfigs + * format value for float values + * @param value + * @returns {*} + */ + getFormattedValue: function(value) { + return validator.isValidFloat(value) ? parseFloat(value).toString() : value; + }, + + /** + * just get config override + * @param cp * @param selectedGroup + * @returns {*|Object} * @private */ - _updateRecommendedValues: function(stepConfigs, selectedGroup) { - var propertiesToUpdate = this.get('_dependentConfigValues').filter(function(p) { - return !Em.get(p, 'toDelete') && !Em.get(p, 'toAdd') && Em.get(p, 'serviceName') == stepConfigs.get('serviceName') && Em.get(p, 'configGroup') == selectedGroup.get('name'); + _getOverride: function(cp, selectedGroup) { + return Em.get(cp, 'overrides.length') && Em.get(cp, 'overrides').findProperty('group.name', Em.get(selectedGroup, 'name')); + }, + + /** + * get property form popup + * @param name + * @param fileName + * @param groupName + * @returns {Object} + */ + getPopupProperty: function(name, fileName, groupName) { + return this.get('_dependentConfigValues').find(function (dcv) { + return dcv.propertyName === name && dcv.fileName === App.config.getOriginalFileName(fileName) && dcv.configGroup === (groupName || "Default"); }); - if (propertiesToUpdate.length > 0) { - stepConfigs.get('configs').forEach(function (cp) { - var propertyToUpdate = propertiesToUpdate.filterProperty('propertyName', cp.get('name')).findProperty('fileName', App.config.getConfigTagFromFileName(cp.get('filename'))); - if (propertyToUpdate) { - var valueToSave = propertyToUpdate.saveRecommended ? propertyToUpdate.recommendedValue : propertyToUpdate.value; - if (!selectedGroup || selectedGroup.get('isDefault')) { - if (propertyToUpdate.saveRecommended || cp.get('value') == propertyToUpdate.recommendedValue) { - cp.set('value', valueToSave); - } - cp.set('recommendedValue', propertyToUpdate.recommendedValue); - } else { - var overriddenConfig = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name')); - if (overriddenConfig) { - if (propertyToUpdate.saveRecommended || overriddenConfig.get('value') == propertyToUpdate.recommendedValue) { - overriddenConfig.set('value', valueToSave); - } - overriddenConfig.set('recommendedValue', propertyToUpdate.recommendedValue); - } - } - } - }, this); - } }, /** - * On first load on installer and add service <code>initialValue<code> of <code>serviceConfigProperty<code> object - * that contains value from stack should be overriden by dynamic recommendation. - * Do this only for not installed services as in this case <code>initialValue<code> is not used. - * @param configObject + * add or update proeprty in popup + * @param popupProperty + * @param name + * @param fileName + * @param recommendedValue + * @param initialValue + * @param service + * @param groupName + * @param parentPropertiesNames + * @private */ - updateInitialValue: function(configObject) { - for (var key in configObject) { - /** defines main info for file name (service name, config group, config that belongs to filename) **/ - var service = App.config.getServiceByConfigType(key); - if (App.Service.find().filterProperty('serviceName', service.get('serviceName'))) { - var stepConfig = this.get('stepConfigs').findProperty('serviceName', service.get('serviceName')); - if (stepConfig) { - var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(key)) : []; - - for (var propertyName in configObject[key].properties) { - var configProperty = configProperties.findProperty('name', propertyName); - if (configProperty) { - configProperty.set('initialValue', configObject[key].properties[propertyName]); - } - } - } - } + _updatePopup: function(popupProperty, name, fileName, recommendedValue, initialValue, service, groupName, parentPropertiesNames) { + if (popupProperty) { + Em.set(popupProperty, 'recommendedValue', recommendedValue); + Em.set(popupProperty, 'isDeleted', Em.isNone(recommendedValue)); + } else { + var popupPropertyObject = { + saveRecommended: true, + saveRecommendedDefault: true, + fileName: App.config.getOriginalFileName(fileName), + propertyName: name, + + isDeleted: Em.isNone(recommendedValue), + notDefined: Em.isNone(initialValue), + + configGroup: groupName, + value: initialValue, + parentConfigs: parentPropertiesNames, + serviceName: service.get('serviceName'), + allowChangeGroup: groupName!= "Default" && (service.get('serviceName') != this.get('selectedService.serviceName')) + && (App.ServiceConfigGroup.find().filterProperty('serviceName', service.get('serviceName')).length > 1), + serviceDisplayName: service.get('displayName'), + recommendedValue: recommendedValue + }; + this.get('_dependentConfigValues').pushObject(popupPropertyObject); } }, /** + * clean properties that have same current and recommended values + * @private + */ + _cleanUpPopupProperties: function() { + var cleanDependentList = this.get('_dependentConfigValues').filter(function(d) { + return !((Em.isNone(d.value) && Em.isNone(d.recommendedValue)) || d.value == d.recommendedValue); + }, this); + this.set('_dependentConfigValues', cleanDependentList); + }, + + /** * Helper method to get property from the <code>stepConfigs</code> * * @param {String} name - config property name http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/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 0306a97..7938729 100644 --- a/ambari-web/app/mixins/common/serverValidator.js +++ b/ambari-web/app/mixins/common/serverValidator.js @@ -174,10 +174,9 @@ App.ServerValidatorMixin = Em.Mixin.create({ * @param data */ loadRecommendationsSuccess: function(data) { - this._saveRecommendedValues(data); - var configObject = data.resources[0].recommendations.blueprint.configurations; - if (configObject) this.updateInitialValue(configObject); + this._saveRecommendedValues(data, false, null, false, true); this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations")); + this.set('recommendationTimeStamp', (new Date).getTime()); }, loadRecommendationsError: function(jqXHR, ajaxOptions, error, opt) { @@ -186,7 +185,6 @@ App.ServerValidatorMixin = Em.Mixin.create({ serverSideValidation: function () { var deferred = $.Deferred(); - var self = this; this.set('configValidationFailed', false); this.set('configValidationGlobalMessage', []); if (this.get('configValidationFailed')) { http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/ambari-web/app/utils/config.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js index df92ebe..f4c8034 100644 --- a/ambari-web/app/utils/config.js +++ b/ambari-web/app/utils/config.js @@ -630,17 +630,19 @@ App.config = Em.Object.create({ * can be created and assigned to non-default config group. * * @param {String} propertyName - name of the property - * @param {Object} config - config info + * @param {String} fileName - file name of the property + * @param {String} value - config value * @param {Em.Object} group - config group to set - * @param {Boolean} isEditable + * @param {Boolean} [isEditable] + * @param {Boolean} [isInstaller] * @return {Object} **/ - createCustomGroupConfig: function (propertyName, config, group, isEditable) { - var propertyObject = this.createDefaultConfig(propertyName, group.get('service.serviceName'), this.getOriginalFileName(config.type), false, { - savedValue: config.properties[propertyName], - value: config.properties[propertyName], + createCustomGroupConfig: function (propertyName, fileName, value, group, isEditable, isInstaller) { + var propertyObject = this.createDefaultConfig(propertyName, group.get('service.serviceName'), this.getOriginalFileName(fileName), false, { + savedValue: isInstaller ? null : value, + value: value, group: group, - isEditable: isEditable !== false, + isEditable: !!isEditable, isOverridable: false }); group.set('switchGroupTextShort', Em.I18n.t('services.service.config_groups.switchGroupTextShort').format(group.get('name'))); http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/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 2644192..a88be76 100644 --- a/ambari-web/app/views/common/controls_view.js +++ b/ambari-web/app/views/common/controls_view.js @@ -114,8 +114,7 @@ App.SupportsDependentConfigs = Ember.Mixin.create({ restoreDependentConfigs: function(parentConfig) { var controller = this.get('controller'); var dependentConfigs = controller.get('_dependentConfigValues'); - if (controller.updateDependentConfigs) { - controller.updateDependentConfigs(); + try { controller.set('_dependentConfigValues', dependentConfigs.reject(function(item) { if (item.parentConfigs.contains(parentConfig.get('name'))) { if (item.parentConfigs.length > 1) { @@ -131,6 +130,8 @@ App.SupportsDependentConfigs = Ember.Mixin.create({ } return false; })); + } catch(e) { + console.warn('Dependent properties popup was not cleared'); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/810d6e82/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 684598e..334ca75 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 @@ -57,11 +57,16 @@ App.showDependentConfigsPopup = function (configs, primary, secondary) { }), onPrimary: function () { this._super(); + var propertiesToUpdate = this.get('configs').filter(function(c) { + return Em.get(c, 'saveRecommendedDefault') != Em.get(c, 'saveRecommended'); + }), + propertiesToUndo = propertiesToUpdate.filterProperty('saveRecommended', false), + propertiesToRedo = propertiesToUpdate.filterProperty('saveRecommended', true); this.get('configs').forEach(function (c) { Em.set(c, 'saveRecommendedDefault', Em.get(c, 'saveRecommended')); }); if (primary) { - primary(); + primary(propertiesToUndo, propertiesToRedo); } }, onSecondary: function() {