Repository: ambari Updated Branches: refs/heads/trunk f15fce5bb -> 8769adc35
AMBARI-10273 Changing of enhanced-config value should trigger /recommendations call. (ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8769adc3 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8769adc3 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8769adc3 Branch: refs/heads/trunk Commit: 8769adc3536a11e73e49addaa3458958444b1336 Parents: f15fce5 Author: aBabiichuk <[email protected]> Authored: Mon Mar 30 16:18:11 2015 +0300 Committer: aBabiichuk <[email protected]> Committed: Mon Mar 30 17:48:42 2015 +0300 ---------------------------------------------------------------------- .../controllers/main/service/info/configs.js | 14 +- ambari-web/app/messages.js | 2 + .../mixins/common/configs/enhanced_configs.js | 139 +++++++++++++++++-- .../templates/common/configs/service_config.hbs | 5 + .../configs/widgets/slider_config_widget.hbs | 2 +- .../configs/widgets/config_widget_view.js | 21 ++- .../widgets/slider_config_widget_view.js | 25 ++++ ambari-web/app/views/common/controls_view.js | 16 +-- .../dependent_configs_list_popup.js | 2 +- 9 files changed, 196 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/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 28c1a63..8c5d8ed 100644 --- a/ambari-web/app/controllers/main/service/info/configs.js +++ b/ambari-web/app/controllers/main/service/info/configs.js @@ -1198,14 +1198,20 @@ App.MainServiceInfoConfigsController = Em.Controller.extend(App.ServerValidatorM * @method showWarningPopupsBeforeSave */ showWarningPopupsBeforeSave: function() { - var displayName = this.get('content.displayName'); + var self = this; if (this.isDirChanged()) { - App.showConfirmationPopup(this.restartServicePopup.bind(this), - Em.I18n.t('services.service.config.confirmDirectoryChange').format(displayName), + App.showConfirmationPopup(function() { + self.showChangedDependentConfigs(null, function() { + self.restartServicePopup(); + }); + }, + Em.I18n.t('services.service.config.confirmDirectoryChange').format(self.get('content.displayName')), this.completeSave.bind(this) ); } else { - this.restartServicePopup(); + self.showChangedDependentConfigs(null, function() { + self.restartServicePopup(); + }); } }, http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index 42a0aaa..18fcd17 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -347,6 +347,8 @@ Em.I18n.translations = { 'popup.dependent.configs.select.config.group': 'Please select to which config group would you like to save dependent properties', + 'popup.dependent.configs.dependencies.info': 'There are {0} configs was changed in {1} services.', + 'login.header':'Sign in', 'login.username':'Username', 'login.loginButton':'Sign in', http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/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 61c2a2e..6de333a 100644 --- a/ambari-web/app/mixins/common/configs/enhanced_configs.js +++ b/ambari-web/app/mixins/common/configs/enhanced_configs.js @@ -22,6 +22,30 @@ var blueprintUtils = require('utils/blueprint'); App.EnhancedConfigsMixin = Em.Mixin.create({ /** + * this value is used for observing + * whether recommendations for dependent properties was received from server + * @type {number} + */ + recommendationTimeStamp: null, + + /** + * flag is true when Ambari changes some of the dependent properties + * @type {boolean} + */ + hasChangedDependencies: function() { + return App.get('supports.enhancedConfigs') && this.get('_dependentConfigValues.length') > 0; + }.property('_dependentConfigValues.length'), + + /** + * message fro alert box for dependent configs + * @type {string} + */ + dependenciesMessage: function() { + var changedServices = this.get('changedProperties').mapProperty('serviceName').uniq(); + return Em.I18n.t('popup.dependent.configs.dependencies.info').format( this.get('changedProperties.length'), changedServices.length); + }.property('changedProperties'), + + /** * values for dependent configs * @type {Object[]} * ex: @@ -39,6 +63,13 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ _dependentConfigValues: [], /** + * dependent properties that was changed by Ambari + * @type {Object[]} + */ + changedProperties: function() { + return this.get('_dependentConfigValues').filterProperty('saveRecommended', true); + }.property('[email protected]'), + /** * dependent file names for configs * @type {string[]} */ @@ -372,7 +403,8 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ dataToSend: dataToSend }, success: 'dependenciesSuccess', - error: 'dependenciesError' + error: 'dependenciesError', + callback: this.onRecommendationsReceived.bind(this) }); } else { return null; @@ -380,6 +412,14 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ }, /** + * complete callback on <code>getRecommendationsForDependencies<code> + * @method onRecommendationsReceived + */ + onRecommendationsReceived: function() { + this.set('recommendationTimeStamp', (new Date).getTime()); + }, + + /** * shows popup with results for recommended value * if case properties that was changes belongs to not default group * user should pick to what config group from dependent service dependent properties will be saved @@ -391,18 +431,31 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ if (!this.get('selectedConfigGroup.isDefault')) { self.showSelectGroupsPopup(function () { self._saveRecommendedValues(data); - if (self.get('_dependentConfigValues.length') > 0) { - App.showDependentConfigsPopup(self.get('_dependentConfigValues'), function () { - self._saveDependentConfigs(); - }); - } + self._saveDependentConfigs(); }); } else { self._saveRecommendedValues(data); - if (self.get('_dependentConfigValues.length') > 0) { - App.showDependentConfigsPopup(self.get('_dependentConfigValues'), function () { - self._saveDependentConfigs(); - }); + self._saveDependentConfigs(); + } + }, + + /** + * method to show popup with dependent configs + * @method showChangedDependentConfigs + */ + showChangedDependentConfigs: function(event, callback) { + var self = this; + if (self.get('_dependentConfigValues.length') > 0) { + App.showDependentConfigsPopup(this.get('_dependentConfigValues'), function() { + self._saveDependentConfigs(); + self._discardChanges(); + if (callback) { + callback(); + } + }, this._discardChanges.bind(this)); + } else { + if (callback) { + callback(); } } }, @@ -494,11 +547,11 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ if (!stepConfig.get('overrides')) { stepConfig.set('overrides', Em.A([])); } - var overridenConfig = stepConfig.get('overrides').findProperty('isEditable'); + var overridenConfig = stepConfig.get('overrides').findProperty('group.name', Em.get(dependentConfig, 'configGroup')); if (overridenConfig) { overridenConfig.set('value', Em.get(dependentConfig, 'recommendedValue')); } else { - self.addOverrideProperty(stepConfig, self.get('selectedConfigGroup'), Em.get(dependentConfig, 'recommendedValue')); + self.addOverrideProperty(stepConfig.set('isNotSaved', true), self.get('selectedConfigGroup'), Em.get(dependentConfig, 'recommendedValue')); } } } @@ -535,6 +588,66 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ }, /** + * opposite to <code>_saveDependentConfigs<code> + * restore values that was before applying changes for dependent configs + * do this action only for properties that has <code>saveRecommended<code> - false + * @private + */ + _discardChanges: function () { + var self = this; + this.get('_dependentConfigValues').forEach(function(dependentConfig) { + if (!Em.get(dependentConfig, 'saveRecommended')) { // if saveRecommended is false leave properties as is + if (Em.get(dependentConfig, 'serviceName') === self.get('content.serviceName')) { //for current service save dependent properties to step configs + self.get('stepConfigs').objectAt(0).get('configs').forEach(function(stepConfig) { + if (stepConfig.get('filename') === App.config.getOriginalFileName(Em.get(dependentConfig, 'fileName')) + && stepConfig.get('name') === Em.get(dependentConfig, 'propertyName')) { + if (self.get('selectedConfigGroup.isDefault')) { + stepConfig.set('value', Em.get(dependentConfig, 'value')) + } else { + if (!stepConfig.get('overrides')) { + stepConfig.set('overrides', Em.A([])); + } + var overridenConfig = stepConfig.get('overrides').findProperty('group.name', Em.get(dependentConfig, 'configGroup')); + if (overridenConfig) { + if (overridenConfig.get('isNotSaved')) { + stepConfig.get('overrides').removeObject(overridenConfig); + } else { + overridenConfig.set('value', Em.get(dependentConfig, 'value')); + } + } + } + } + }) + } else { //for not current service save dependent properties to model + + App.ConfigProperty.find().forEach(function(cp) { + if (cp.get('name') === Em.get(dependentConfig, 'propertyName') + && cp.get('fileName') === App.config.getOriginalFileName(Em.get(dependentConfig, 'fileName'))) { + + if (self.get('selectedConfigGroup.isDefault') || Em.get(dependentConfig, 'configGroup').contains('Default')) { + if (cp.get('isOriginalSCP')) { + cp.set('value', Em.get(dependentConfig, 'value')) + } + } else { + if (cp.get('configVersion.groupName') === self.get('groupsToSave')[dependentConfig.serviceName]) { + if (cp.get('isNotSaved')) { + cp.deleteRecord(); + App.store.commit(); + } else { + cp.set('value', Em.get(dependentConfig, 'value')); + } + } + } + + } + }); + } + } + }); + this.set('recommendationTimeStamp', (new Date).getTime()); + }, + + /** * get array of config objects for current service depends on config group * for default group - it will be current stepConfigs * for not default group - overriden property in case there is such property in group @@ -624,7 +737,7 @@ App.EnhancedConfigsMixin = Em.Mixin.create({ if (configGroup.get('isDefault') || Em.isNone(stepConfig.get('overrides'))) { return stepConfig.get('value'); } else { - var overridenConfig = stepConfig.get('overrides').findProperty('isEditable'); + var overridenConfig = stepConfig.get('overrides').findProperty('group.name', configGroup.get('name')); if (overridenConfig) { return overridenConfig.get('value'); } else { http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/ambari-web/app/templates/common/configs/service_config.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/configs/service_config.hbs b/ambari-web/app/templates/common/configs/service_config.hbs index 6ec3d85..26c7c2f 100644 --- a/ambari-web/app/templates/common/configs/service_config.hbs +++ b/ambari-web/app/templates/common/configs/service_config.hbs @@ -83,6 +83,11 @@ {{/if}} {{#if versionLoaded}} + {{#if hasChangedDependencies}} + <div class="alert alert-warning"> + <span>{{dependenciesMessage}}</span> <a href="#" {{action "showChangedDependentConfigs" target="controller"}}>{{t common.showDetails}}</a> + </div> + {{/if}} {{#if view.supportsConfigLayout}} <ul class="nav nav-tabs"> {{#each tab in view.tabs}} http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/ambari-web/app/templates/common/configs/widgets/slider_config_widget.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/common/configs/widgets/slider_config_widget.hbs b/ambari-web/app/templates/common/configs/widgets/slider_config_widget.hbs index 54ac741..36e3989 100644 --- a/ambari-web/app/templates/common/configs/widgets/slider_config_widget.hbs +++ b/ambari-web/app/templates/common/configs/widgets/slider_config_widget.hbs @@ -23,7 +23,7 @@ <div> <div {{bindAttr class="view.isMirrorValueValid::error :control-group :pull-left"}}> <div {{bindAttr class="view.config.stackConfigProperty.valueAttributes.unit:input-append"}}> - {{view Ember.TextField valueBinding="view.mirrorValue" class="input-mini" disabledBinding="view.disabled"}} + {{view view.MirrorValueView valueBinding="view.mirrorValue" class="input-mini" disabledBinding="view.disabled"}} {{#if view.config.stackConfigProperty.valueAttributes.unit}} <span class="add-on">{{view.config.stackConfigProperty.valueAttributes.unit}}</span> {{/if}} http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/ambari-web/app/views/common/configs/widgets/config_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/widgets/config_widget_view.js b/ambari-web/app/views/common/configs/widgets/config_widget_view.js index b7b1dc7..9fbb04d 100644 --- a/ambari-web/app/views/common/configs/widgets/config_widget_view.js +++ b/ambari-web/app/views/common/configs/widgets/config_widget_view.js @@ -17,12 +17,12 @@ */ var App = require('app'); - +require('views/common/controls_view'); /** * Common view for config widgets * @type {Em.View} */ -App.ConfigWidgetView = Em.View.extend({ +App.ConfigWidgetView = Em.View.extend(App.SupportsDependentConfigs, { /** * @type {App.ConfigProperty} @@ -93,6 +93,21 @@ App.ConfigWidgetView = Em.View.extend({ var config = this.get('config'); if (!config) return false; return !config.get('cantBeUndone') && config.get('isNotDefaultValue'); - }.property('config.cantBeUndone', 'config.isNotDefaultValue') + }.property('config.cantBeUndone', 'config.isNotDefaultValue'), + + /** + * sync widget value with config value when dependent properties + * have been loaded or changed + */ + syncValueWithConfig: function() { + this.setValue(this.get('config.value')); + }.observes('controller.recommendationTimeStamp'), + /** + * set widget value same as config value + * useful for widgets that work with intermediate config value, not original + * for now used in slider widget + * @abstract + */ + setValue: Em.K }); http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/ambari-web/app/views/common/configs/widgets/slider_config_widget_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/common/configs/widgets/slider_config_widget_view.js b/ambari-web/app/views/common/configs/widgets/slider_config_widget_view.js index fad30aa..1182ccd 100644 --- a/ambari-web/app/views/common/configs/widgets/slider_config_widget_view.js +++ b/ambari-web/app/views/common/configs/widgets/slider_config_widget_view.js @@ -96,6 +96,15 @@ App.SliderConfigWidgetView = App.ConfigWidgetView.extend({ }, /** + * view class for text box that is used with slider widget + * @type {Em.TextField} + */ + MirrorValueView: Em.TextField.extend({ + focusOut: function() { + this.get('parentView').sendRequestRorDependentConfigs(this.get('parentView.config')); + } + }), + /** * Check if <code>mirrorValue</code> was updated by user * Validate it. If value is correct, set it to slider and config.value * @method mirrorValueObs @@ -129,6 +138,15 @@ App.SliderConfigWidgetView = App.ConfigWidgetView.extend({ }, /** + * @override + * @method setValue + * set widget value same as config value + */ + setValue: function() { + this.set('mirrorValue', this.get('config.value')); + }, + + /** * valueAttributes are strings, but should be numbers * parse them using <code>parseFunction</code> * @method prepareValueAttributes @@ -179,6 +197,13 @@ App.SliderConfigWidgetView = App.ConfigWidgetView.extend({ self.set('config.value', '' + val); self.set('mirrorValue', val); }); + /** + * action to run sendRequestRorDependentConfigs when + * we have changed config value within slider + */ + slider.on('slideStop', function() { + self.sendRequestRorDependentConfigs(self.get('config')); + }); this.set('slider', slider); // hide some ticks. can't do this via css http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/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 c8cacd8..b611fb6 100644 --- a/ambari-web/app/views/common/controls_view.js +++ b/ambari-web/app/views/common/controls_view.js @@ -60,16 +60,16 @@ App.ServiceConfigPopoverSupport = Ember.Mixin.create({ }.property('serviceConfig.isEditable') }); -App.supportsDependentConfigs = Ember.Mixin.create({ +App.SupportsDependentConfigs = Ember.Mixin.create({ /** * method send request to check if some of dependent configs was changes * and in case there was changes shows popup with info about changed configs */ - sendRequestRorDependentConfigs: function() { + sendRequestRorDependentConfigs: function(config) { if (App.get('supports.enhancedConfigs') && this.get('controller.name') === 'mainServiceInfoConfigsController') { - var name = this.get('serviceConfig.name'); - var type = App.config.getConfigTagFromFileName(this.get('serviceConfig.filename')); + var name = config.get('name'); + var type = App.config.getConfigTagFromFileName(config.get('filename')); var p = App.StackConfigProperty.find(name + '_' + type); if (p && p.get('propertyDependedBy.length') > 0) { this.get('controller').getRecommendationsForDependencies([{ @@ -100,7 +100,7 @@ App.ServiceConfigCalculateId = Ember.Mixin.create({ * Default input control * @type {*} */ -App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.supportsDependentConfigs, { +App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, App.ServiceConfigCalculateId, App.SupportsDependentConfigs, { valueBinding: 'serviceConfig.value', classNameBindings: 'textFieldClassName', @@ -114,7 +114,7 @@ App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupp //Set editDone true for last edited config text field parameter focusOut: function (event) { if (this.get('serviceConfig.isNotDefaultValue')) { - this.sendRequestRorDependentConfigs(); + this.sendRequestRorDependentConfigs(this.get('serviceConfig')); } this.get('serviceConfig').set("editDone", true); }, @@ -141,7 +141,7 @@ App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupp * Customized input control with Units type specified * @type {Em.View} */ -App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, App.supportsDependentConfigs, { +App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, App.SupportsDependentConfigs, { valueBinding: 'serviceConfig.value', classNames: ['input-append', 'with-unit'], placeholderBinding: 'serviceConfig.defaultValue', @@ -149,7 +149,7 @@ App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverS //Set editDone true for last edited config text field parameter focusOut: function (event) { if (this.get('serviceConfig.isNotDefaultValue')) { - this.sendRequestRorDependentConfigs(); + this.sendRequestRorDependentConfigs(this.get('serviceConfig')); } }, templateName: require('templates/wizard/controls_service_config_textfield_with_unit') http://git-wip-us.apache.org/repos/asf/ambari/blob/8769adc3/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 4c221ba..ec7ea1f 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 @@ -30,7 +30,7 @@ App.showDependentConfigsPopup = function (configs, callback, secondaryCallback) return App.ModalPopup.show({ encodeBody: false, primary: Em.I18n.t('common.save'), - secondary: Em.I18n.t('common.cancel'), + secondary: Em.I18n.t('common.discard'), header: Em.I18n.t('popup.dependent.configs.header'), classNames: ['sixty-percent-width-modal','modal-full-width'], configs: configs,
