| /** |
| * 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'); |
| var blueprintUtils = require('utils/blueprint'); |
| |
| App.EnhancedConfigsMixin = Em.Mixin.create(App.ConfigWithOverrideRecommendationParser, { |
| |
| /** |
| * this value is used for observing |
| * whether recommendations for dependent properties was received from server |
| * @type {number} |
| */ |
| recommendationTimeStamp: null, |
| |
| /** |
| * this property is used to force update min/max values |
| * for not default config groups |
| * @type {boolean} |
| */ |
| forceUpdateBoundaries: false, |
| |
| /** |
| * object with loaded recommendations |
| * |
| * @type {?Object} |
| */ |
| recommendationsConfigs: null, |
| |
| /** |
| * list of recommendations that should be applied without any config changes |
| * |
| * @type {Object[]} |
| */ |
| initialRecommendations: [], |
| |
| /** |
| * flag is true when Ambari changes some of the dependent properties |
| * @type {boolean} |
| */ |
| hasChangedDependencies: Em.computed.and('isControllerSupportsEnhancedConfigs', 'changedProperties.length'), |
| |
| /** |
| * defines is block with changed dependent configs should be shown |
| * rely on controller |
| * @type {boolean} |
| */ |
| isControllerSupportsEnhancedConfigs: Em.computed.existsIn('name', ['wizardStep7Controller','mainServiceInfoConfigsController']), |
| |
| /** |
| * Stores name and file name of changed config |
| * This used only for capacity-scheduler |
| * |
| * @property {object} |
| */ |
| currentlyChangedConfig: null, |
| |
| dependenciesGroupMessage: Em.I18n.t('popup.dependent.configs.dependencies.for.groups'), |
| |
| /** |
| * ConfigType-Widget map |
| * key - widget type |
| * value - widget view |
| * @type {object} |
| */ |
| widgetTypeMap: { |
| checkbox: 'CheckboxConfigWidgetView', |
| combo: 'ComboConfigWidgetView', |
| directory: 'TextFieldConfigWidgetView', |
| directories: 'DirectoryConfigWidgetView', |
| list: 'ListConfigWidgetView', |
| password: 'PasswordConfigWidgetView', |
| 'radio-buttons': 'RadioButtonConfigWidgetView', |
| slider: 'SliderConfigWidgetView', |
| 'text-field': 'TextFieldConfigWidgetView', |
| 'time-interval-spinner': 'TimeIntervalSpinnerView', |
| toggle: 'ToggleConfigWidgetView', |
| 'text-area': 'StringConfigWidgetView', |
| 'label': 'LabelView', |
| 'test-db-connection': 'TestDbConnectionWidgetView' |
| }, |
| |
| configNameWidgetMixinMap: { |
| num_llap_nodes: App.NumLlapNodesWidgetMixin |
| }, |
| |
| /** |
| * message for alert box for dependent configs |
| * @type {string} |
| */ |
| dependenciesMessage: function() { |
| var changedProperties = this.get('changedProperties').filterProperty('saveRecommended'); |
| var changedServices = changedProperties.mapProperty('serviceName').uniq(); |
| var cfgLenSuffix = changedProperties.length === 1 ? 'singular' : 'plural'; |
| var sLenSuffix = changedServices.length === 1 ? 'singular' : 'plural'; |
| return Em.I18n.t('popup.dependent.configs.dependencies.config.' + cfgLenSuffix).format(changedProperties.length) |
| + Em.I18n.t('popup.dependent.configs.dependencies.service.' + sLenSuffix).format(changedServices.length); |
| }.property('changedProperties.length'), |
| |
| /** |
| * dependent properties that was changed by Ambari |
| * @type {Object[]} |
| */ |
| changedProperties: function() { |
| return this.get('recommendations').filter(function(dp) { |
| return (this.get('selectedConfigGroup.isDefault') && Em.get(dp, 'configGroup').contains('Default')) |
| || [this.get('selectedConfigGroup.name'), this.get('selectedConfigGroup.dependentConfigGroups') && this.get('selectedConfigGroup.dependentConfigGroups')[Em.get(dp, 'serviceName')]].contains(Em.get(dp, 'configGroup')); |
| }, this); |
| }.property('recommendations.@each.saveRecommended', 'recommendations.@each.recommendedValue', 'selectedConfigGroup'), |
| |
| /** |
| * defines if change dependent group message should be shown |
| * @type {boolean} |
| */ |
| showSelectGroupsPopup: Em.computed.and('!selectedConfigGroup.isDefault', 'selectedService.dependentServiceNames.length'), |
| |
| /** |
| * set default values for dependentGroups |
| * @method setDependentGroups |
| */ |
| setDependentGroups: function () { |
| if (this.shouldSetDependentConfigs()) { |
| this.get('selectedService.dependentServiceNames').forEach(function (serviceName) { |
| if (!this.get('selectedConfigGroup.dependentConfigGroups')[serviceName]) { |
| var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName); |
| if (stepConfig) { |
| this.setDependentConfigGroups(stepConfig, serviceName); |
| } |
| } |
| }, this); |
| } |
| }.observes('selectedConfigGroup'), |
| |
| /** |
| * |
| * @param {Em.Object} stepConfig |
| * @param {string} serviceName |
| */ |
| setDependentConfigGroups: function(stepConfig, serviceName) { |
| stepConfig.get('configGroups').filterProperty('isDefault', false).forEach(function (configGroup) { |
| this.get('selectedService.configGroups').filterProperty('isDefault', false).forEach(function (currentServiceGroup) { |
| if (currentServiceGroup.get('dependentConfigGroups')[serviceName] !== configGroup.get('name')) { |
| var dependentGroups = $.extend({}, this.get('selectedConfigGroup.dependentConfigGroups')); |
| dependentGroups[serviceName] = configGroup.get('name'); |
| this.set('selectedConfigGroup.dependentConfigGroups', dependentGroups); |
| } |
| }, this); |
| }, this); |
| }, |
| |
| /** |
| * |
| * @returns {boolean} |
| */ |
| shouldSetDependentConfigs: function() { |
| return Boolean(this.get('selectedConfigGroup') && |
| this.get('isControllerSupportsEnhancedConfigs') && |
| !this.get('selectedConfigGroup.isDefault') && |
| this.get('selectedService.dependentServiceNames.length')); |
| }, |
| |
| /******************************METHODS THAT WORKS WITH DEPENDENT CONFIGS *************************************/ |
| |
| /** |
| * get config group object for current service |
| * @param serviceName |
| * @returns {App.ConfigGroup|null} |
| */ |
| getGroupForService: function(serviceName) { |
| if (!this.get('stepConfigs') || this.get('stepConfigs.length') === 0) { |
| return null; |
| } |
| if (this.get('selectedService.serviceName') === serviceName) { |
| return this.get('selectedConfigGroup'); |
| } else { |
| var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName); |
| if (stepConfig) { |
| var groups = stepConfig.get('configGroups'); |
| if (this.get('selectedConfigGroup.isDefault')) { |
| return groups.length ? groups.findProperty('isDefault') : null; |
| } else { |
| return groups.length ? groups.findProperty('name', this.get('selectedConfigGroup.dependentConfigGroups')[serviceName]) : null; |
| } |
| } else { |
| return null; |
| } |
| } |
| }, |
| |
| clearRecommendationsInfo: function() { |
| this.set('recommendationsConfigs', null); |
| }, |
| |
| clearRecommendations: function () { |
| this.clearRecommendationsInfo(); |
| this.clearAllRecommendations(); |
| }, |
| |
| /** |
| * sends request to get values for dependent configs |
| * @param {{type: string, name: string}[]} changedConfigs - list of changed configs to track recommendations |
| * @param {Function} [onComplete] |
| * @returns {$.ajax|null} |
| */ |
| loadConfigRecommendations: function (changedConfigs, onComplete) { |
| var updateDependencies = Em.isArray(changedConfigs) && changedConfigs.length > 0; |
| var stepConfigs = this.get('stepConfigs'); |
| var requiredTags = []; |
| |
| if (updateDependencies || Em.isNone(this.get('recommendationsConfigs'))) { |
| var recommendations = this.get('hostGroups'); |
| var dataToSend = this.getConfigRecommendationsParams(updateDependencies, changedConfigs); |
| this.modifyRecommendationConfigGroups(recommendations); |
| |
| if (!stepConfigs.someProperty('serviceName', 'MISC')) { |
| requiredTags.push({site: 'cluster-env', serviceName: 'MISC'}); |
| } |
| if (Em.isArray(changedConfigs) && changedConfigs.mapProperty('type').uniq()[0] === 'capacity-scheduler') { |
| this.set('currentlyChangedConfig', { |
| name: 'capacity-scheduler', |
| fileName: 'capacity-scheduler.xml' |
| }); |
| } else { |
| this.set('currentlyChangedConfig', null); |
| } |
| |
| if (App.Service.find().someProperty('serviceName', 'HDFS') && !stepConfigs.someProperty('serviceName', 'HDFS')) { |
| requiredTags.push({site: 'core-site', serviceName: 'HDFS'}); |
| } |
| |
| this.setUserContext(dataToSend); |
| if (requiredTags.length) { |
| this.loadAdditionalSites(requiredTags, stepConfigs, recommendations, dataToSend, onComplete); |
| } else { |
| this.addRecommendationRequestParams(recommendations, dataToSend, stepConfigs); |
| return this.getRecommendationsRequest(dataToSend, onComplete); |
| } |
| } else { |
| if (onComplete) { |
| onComplete() |
| } |
| } |
| return $.Deferred().resolve().promise(); |
| }, |
| |
| /** |
| * |
| * @param recommendations |
| * @param dataToSend |
| * @param stepConfigs |
| */ |
| addRecommendationRequestParams: function(recommendations, dataToSend, stepConfigs) { |
| recommendations.blueprint.configurations = blueprintUtils.buildConfigsJSON(stepConfigs); |
| dataToSend.recommendations = recommendations; |
| }, |
| |
| /** |
| * |
| * @param {Array} stepConfigs |
| * @param {object} recommendations |
| * @param {object} dataToSend |
| * @param {Function} onComplete |
| */ |
| loadAdditionalSites: function(sites, stepConfigs, recommendations, dataToSend, onComplete) { |
| var self = this; |
| App.router.get('configurationController').getCurrentConfigsBySites(sites).done(function (configs) { |
| stepConfigs = stepConfigs.concat(configs); |
| |
| self.addRecommendationRequestParams(recommendations, dataToSend, stepConfigs); |
| self.getRecommendationsRequest(dataToSend, onComplete); |
| }); |
| }, |
| |
| /** |
| * |
| * @param {object} recommendations |
| */ |
| modifyRecommendationConfigGroups: function(recommendations) { |
| var configGroup = this.get('selectedConfigGroup'); |
| |
| if (configGroup && !configGroup.get('isDefault') && configGroup.get('hosts.length') > 0) { |
| recommendations.config_groups = [this.buildConfigGroupJSON(this.get('selectedService.configs'), configGroup)]; |
| } else { |
| delete recommendations.config_groups; |
| } |
| }, |
| |
| /** |
| * |
| * @param {boolean} updateDependencies |
| * @param {Array} changedConfigs |
| * @returns {{recommend: string, hosts: *, services: *, changed_configurations: *}} |
| */ |
| getConfigRecommendationsParams: function(updateDependencies, changedConfigs) { |
| return { |
| recommend: updateDependencies ? 'configuration-dependencies' : 'configurations', |
| hosts: this.get('hostNames'), |
| services: this.get('serviceNames'), |
| changed_configurations: updateDependencies ? changedConfigs : undefined |
| }; |
| }, |
| |
| getRecommendationsRequest: function (dataToSend, callback) { |
| var self = this; |
| this.set('recommendationsInProgress', true); |
| return App.ajax.send({ |
| name: 'config.recommendations', |
| sender: self, |
| data: { |
| stackVersionUrl: App.get('stackVersionURL'), |
| dataToSend: dataToSend |
| }, |
| success: 'loadRecommendationsSuccess', |
| error: 'loadRecommendationsError', |
| callback: function () { |
| self.set('recommendationsInProgress', false); |
| self.set('recommendationTimeStamp', (new Date).getTime()); |
| if (callback) { |
| callback() |
| } |
| } |
| }); |
| }, |
| |
| setUserContext: function(dataToSend) { |
| var controllerName = this.get('content.controllerName'); |
| var changes = dataToSend.changed_configurations; |
| if (changes) { |
| dataToSend['user_context'] = {"operation" : "EditConfig"}; |
| } else { |
| if (!controllerName) { |
| dataToSend['user_context'] = {"operation" : "RecommendAttribute"}; |
| } else if (controllerName == 'addServiceController') { |
| dataToSend['user_context'] = { |
| "operation" : "AddService", |
| "operation_details" : (this.get('content.services')|| []).filterProperty('isSelected').filterProperty('isInstalled', false).mapProperty('serviceName').join(',') |
| }; |
| } else if (controllerName == 'installerController'){ |
| dataToSend['user_context'] = {"operation" : "ClusterCreate"}; |
| } |
| } |
| }, |
| |
| /** |
| * Defines if there is any changes made by user. |
| * Check all properties except recommended properties from popup |
| * |
| * @returns {boolean} |
| */ |
| isConfigHasInitialState: function() { |
| return Boolean(this.get('selectedConfigGroup.isDefault') && !Em.isNone(this.get('recommendationsConfigs')) |
| && !this.get('stepConfigs').filter(function(stepConfig) { |
| return stepConfig.get('changedConfigProperties').filter(function(c) { |
| var changedConfigIds = this.get('changedProperties').map(function(changed) { |
| return App.config.configId(changed.propertyName, changed.propertyFileName); |
| }); |
| return !changedConfigIds.contains(App.config.configId(c.get('name'), c.get('filename'))); |
| }, this).length; |
| }, this).length); |
| }, |
| |
| /** |
| * generates JSON with config group info to send it for recommendations |
| * @param configs |
| * @param configGroup |
| * @returns {{configurations: Object[], hosts: string[]}} |
| */ |
| buildConfigGroupJSON: function(configs, configGroup) { |
| Em.assert('configGroup can\'t be null', configGroup); |
| var hosts = configGroup.get('hosts'); |
| var configurations = {}; |
| var overrides = configs.forEach(function(cp) { |
| var override = cp.get('overrides') && cp.get('overrides').findProperty('group.name', configGroup.get('name')); |
| if (override) { |
| var tag = App.config.getConfigTagFromFileName(cp.get('filename')); |
| if (!configurations[tag]) { |
| configurations[tag] = { properties: {} }; |
| } |
| configurations[tag].properties[cp.get('name')] = override.get('value'); |
| } |
| }); |
| return { |
| configurations: [configurations], |
| hosts: hosts |
| } |
| }, |
| |
| /** |
| * 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 |
| * @param data |
| * @param opt |
| * @param params |
| * @method dependenciesSuccess |
| */ |
| loadRecommendationsSuccess: function (data, opt, params) { |
| this._saveRecommendedValues(data, params.dataToSend.changed_configurations); |
| if (this.isConfigHasInitialState()) { |
| /** clearing all recommendations info **/ |
| this.undoRedoRecommended(this.get('recommendations'), false); |
| this.clearAllRecommendations(); |
| |
| /** |
| * resetting recommendations to initial state |
| * this case can be present when installed services depends on new added service on ADW |
| **/ |
| this.undoRedoRecommended(this.get('initialRecommendations'), true); |
| this.get('initialRecommendations').forEach(function (r) { |
| this.get('recommendations').pushObject(r); |
| }, this); |
| } |
| this.set("recommendationsConfigs", Em.get(data, "resources.0.recommendations.blueprint.configurations")); |
| }, |
| |
| loadRecommendationsError: Em.K, |
| |
| changedDependentGroup: function () { |
| var dependentServices = this.get('selectedService.dependentServiceNames'); |
| var isInstallWizard = this.get('content.controllerName') === 'installerController'; |
| var installedServices = App.Service.find().mapProperty('serviceName'); |
| var services = this.get('stepConfigs').filter(function (stepConfig) { |
| if (dependentServices.contains(stepConfig.get('serviceName'))) { |
| return isInstallWizard ? true : installedServices.contains(stepConfig.get('serviceName')); |
| } |
| return false; |
| }, this); |
| App.showSelectGroupsPopup(this.get('selectedService.serviceName'), |
| this.get('selectedService.configGroups').findProperty('name', this.get('selectedConfigGroup.name')), |
| services, this.get('recommendations')); |
| }, |
| |
| /** |
| * saves values from response for dependent config properties to <code>recommendations<code> |
| * @param data |
| * @param [changedConfigs=null] |
| * @method saveRecommendedValues |
| * @private |
| */ |
| _saveRecommendedValues: function(data, changedConfigs) { |
| 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 recommendations = data.resources[0].recommendations; |
| if (recommendations['config-groups'] && this.get('selectedConfigGroup') && !this.get('selectedConfigGroup.isDefault')) { |
| this.saveConfigGroupsRecommendations(recommendations, changedConfigs); |
| } else { |
| var configObject = recommendations.blueprint.configurations; |
| this.get('stepConfigs').forEach(function(stepConfig) { |
| this.updateConfigsByRecommendations(configObject, stepConfig.get('configs'), changedConfigs); |
| }, this); |
| this.addByRecommendations(configObject, changedConfigs); |
| } |
| this.cleanUpRecommendations(); |
| }, |
| |
| /** |
| * |
| * @param {object} recommendations |
| * @param {?Array} changedConfigs |
| */ |
| saveConfigGroupsRecommendations: function(recommendations, changedConfigs) { |
| var configForGroup = recommendations['config-groups'][0]; |
| this.get('stepConfigs').forEach(function(stepConfig) { |
| var configGroup = this.getGroupForService(stepConfig.get('serviceName')); |
| if (configGroup && this.isConfigGroupAffected(configForGroup.hosts, configGroup.get('hosts'))) { |
| this.updateOverridesByRecommendations(configForGroup.configurations, stepConfig.get('configs'), changedConfigs, configGroup); |
| this.updateOverridesByRecommendations(configForGroup.dependent_configurations, stepConfig.get('configs'), changedConfigs, configGroup); |
| this.toggleProperty('forceUpdateBoundaries'); |
| } |
| }, this); |
| }, |
| |
| |
| /** |
| * determine whether hosts of group affected by config modifications |
| * @param {Array} affectedHosts |
| * @param {Array} groupHosts |
| * @returns {boolean} |
| */ |
| isConfigGroupAffected: function(affectedHosts, groupHosts) { |
| return _.intersection(affectedHosts, groupHosts).length > 0; |
| }, |
| |
| /** |
| * method to show popup with dependent configs |
| * @method showChangedDependentConfigs |
| */ |
| showChangedDependentConfigs: function(event, callback, secondary) { |
| var self = this; |
| var recommendations = event ? this.get('changedProperties') : this.get('recommendations'), |
| recommendedChanges = recommendations.filterProperty('isEditable'), |
| requiredChanges = this.filterRequiredChanges(recommendations); |
| if (recommendedChanges.length > 0 || requiredChanges.length > 0) { |
| App.showDependentConfigsPopup(recommendedChanges, requiredChanges, function() { |
| self.onSaveRecommendedPopup(recommendedChanges.concat(requiredChanges)); |
| if (callback) callback(); |
| }, secondary, this); |
| } else { |
| if (callback) callback(); |
| } |
| }, |
| |
| /** |
| * |
| * @param {Array} recommendations |
| * @returns {Array} |
| */ |
| filterRequiredChanges: function(recommendations) { |
| return recommendations.filter(function(recommendation) { |
| if (recommendation.isEditable === false) { |
| if (!this.get('selectedConfigGroup.isDefault')) { |
| return App.ServiceConfigGroup.defaultGroupName !== recommendation.configGroup |
| } else { |
| return true; |
| } |
| } |
| }, this); |
| }, |
| |
| /** |
| * update configs when toggle checkbox on dependent configs popup |
| */ |
| onSaveRecommendedPopup: function(recommendations) { |
| var propertiesToUpdate = recommendations.filter(function(c) { |
| return Em.get(c, 'saveRecommendedDefault') !== Em.get(c, 'saveRecommended'); |
| }), |
| propertiesToUndo = propertiesToUpdate.filterProperty('saveRecommended', false), |
| propertiesToRedo = propertiesToUpdate.filterProperty('saveRecommended', true); |
| |
| this.undoRedoRecommended(propertiesToUndo, false); |
| this.undoRedoRecommended(propertiesToRedo, true); |
| this.set('recommendationTimeStamp', (new Date).getTime()); |
| }, |
| |
| /** |
| * 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, 'initialValue') : Em.get(p, 'recommendedValue'); |
| var recommended = redo ? Em.get(p, 'recommendedValue') : Em.get(p, 'initialValue'); |
| 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') === App.config.getOriginalFileName(Em.get(p, 'propertyFileName')); |
| }); |
| var selectedGroup = App.ServiceConfigGroup.find() |
| .filterProperty('serviceName', Em.get(p, 'serviceName')) |
| .findProperty('name', Em.get(p, 'configGroup')); |
| |
| if (selectedGroup.get('isDefault')) { |
| this.setRecommendedForDefaultGroup(recommended, stepConfig, p, initial, config); |
| } else { |
| this.setRecommendedForGroup(recommended, selectedGroup, config, initial); |
| } |
| }, this); |
| }, |
| |
| /** |
| * |
| * @param {string} recommended |
| * @param {Em.Object} selectedGroup |
| * @param {object} config |
| * @param {string}initial |
| */ |
| setRecommendedForGroup: function(recommended, selectedGroup, config, initial) { |
| if (Em.isNone(recommended)) { |
| config.get('overrides').removeObject(config.getOverride(selectedGroup.get('name'))); |
| } else if (Em.isNone(initial)) { |
| this._addConfigOverrideRecommendation(config, recommended, null, selectedGroup); |
| } else { |
| var override = config.getOverride(selectedGroup.get('name')); |
| if (override) { |
| override.set('value', recommended); |
| } |
| } |
| }, |
| |
| /** |
| * |
| * @param {string} recommended |
| * @param {Em.Object} stepConfig |
| * @param {object|Em.Object} prop |
| * @param {string} initial |
| * @param {object} config |
| */ |
| setRecommendedForDefaultGroup: function(recommended, stepConfig, prop, initial, config) { |
| var name = Em.get(prop, 'propertyName'), |
| filename = Em.get(prop, 'propertyFileName'); |
| |
| if (Em.isNone(recommended)) { |
| stepConfig.get('configs').removeObject(config); |
| } else if (Em.isNone(initial)) { |
| var stackConfigProperty = App.configsCollection.getConfigByName(name, filename); |
| stepConfig.get('configs').pushObject(this._createNewProperty( |
| name, |
| filename, |
| Em.get(prop, 'serviceName'), |
| recommended, |
| stackConfigProperty? stackConfigProperty.propertyDependsOn : [])); |
| } else { |
| Em.set(config, 'value', recommended); |
| } |
| }, |
| |
| saveInitialRecommendations: function() { |
| this.get('recommendations').forEach(function (r) { |
| this.get('initialRecommendations').pushObject(r); |
| }, this); |
| }, |
| |
| /** |
| * disable saving recommended value for current config |
| * @param config |
| * @param {boolean} saveRecommended |
| * @method removeCurrentFromDependentList |
| */ |
| removeCurrentFromDependentList: function (config, saveRecommended) { |
| var recommendation = this.getRecommendation(config.get('name'), config.get('filename'), config.get('group.name')); |
| if (recommendation) this.saveRecommendation(recommendation, saveRecommended); |
| }, |
| |
| updateAttributesFromTheme: function (serviceName) { |
| this.prepareSectionsConfigProperties(serviceName); |
| const serviceConfigs = this.get('stepConfigs').findProperty('serviceName', serviceName).get('configs'), |
| configConditions = App.ThemeCondition.find().filter(condition => { |
| const dependentConfigName = condition.get('configName'), |
| dependentConfigFileName = condition.get('fileName'), |
| configsToDependOn = condition.getWithDefault('configs', []); |
| return serviceConfigs.some(serviceConfig => { |
| const serviceConfigName = Em.get(serviceConfig, 'name'), |
| serviceConfigFileName = Em.get(serviceConfig, 'filename'); |
| return (serviceConfigName === dependentConfigName && serviceConfigFileName === dependentConfigFileName) |
| || configsToDependOn.some(config => { |
| const {configName, fileName} = config; |
| return serviceConfigName === configName && serviceConfigFileName === fileName; |
| }); |
| }); |
| }); |
| this.updateAttributesFromConditions(configConditions, serviceConfigs, serviceName); |
| }, |
| |
| prepareSectionsConfigProperties: function (serviceName) { |
| const tabs = App.Tab.find().filterProperty('serviceName', serviceName); |
| tabs.forEach(tab => { |
| this.processTab(tab); |
| tab.get('sectionRows').forEach(row => { |
| row.forEach(section => { |
| section.get('subsectionRows').forEach(subRow => { |
| subRow.forEach(subsection => { |
| this.setConfigsToContainer(subsection); |
| subsection.get('subSectionTabs').forEach(subSectionTab => { |
| this.setConfigsToContainer(subSectionTab); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }, |
| |
| /** |
| * set {code} configs {code} array of subsection or subsection tab. |
| * Also correct widget should be used for each config (it's selected according to <code>widget.type</code> and |
| * <code>widgetTypeMap</code>). It may throw an error if needed widget can't be found in the <code>widgetTypeMap</code> |
| * @param containerObject |
| */ |
| setConfigsToContainer: function (containerObject) { |
| containerObject.set('configs', []); |
| |
| containerObject.get('configProperties').forEach(function (configId) { |
| const config = App.configsCollection.getConfig(configId); |
| if (Em.get(config, 'widgetType')) { |
| const stepConfig = this.get('stepConfigs').findProperty('serviceName', Em.get(config, 'serviceName')); |
| if (!stepConfig) return; |
| |
| const configProperty = stepConfig.get('configs').findProperty('id', Em.get(config, 'id')); |
| if (!configProperty) return; |
| |
| containerObject.get('configs').pushObject(configProperty); |
| |
| const widget = this.getWidgetView(config); |
| Em.assert('Unknown config widget view for config ' + configProperty.get('id') + ' with type ' + Em.get(config, 'widgetType'), widget); |
| |
| let additionalProperties = { |
| widget, |
| stackConfigProperty: config |
| }; |
| |
| const configConditions = App.ThemeCondition.find().filter(_configCondition => { |
| // Filter config condition depending on the value of another config |
| const conditionalConfigs = _configCondition.getWithDefault('configs', []).filterProperty('fileName', Em.get(config, 'filename')).filterProperty('configName', Em.get(config, 'name')); |
| // Filter config condition depending on the service existence or service state |
| const serviceConfigConditionFlag = ((_configCondition.get('configName') === Em.get(config, 'name')) && (_configCondition.get('fileName') === Em.get(config, 'filename')) && (_configCondition.get('resource') === 'service')); |
| let conditions; |
| |
| if (serviceConfigConditionFlag) { |
| const configCondition = { |
| configName: _configCondition.get('configName'), |
| fileName: _configCondition.get('fileName') |
| }; |
| conditions = conditionalConfigs.concat(configCondition) |
| } else { |
| conditions = conditionalConfigs; |
| } |
| return (conditions && conditions.length); |
| }); |
| |
| if (configConditions && configConditions.length) { |
| additionalProperties.configConditions = configConditions; |
| } |
| |
| const configAction = App.ConfigAction.find().filterProperty('fileName', Em.get(config, 'filename')).findProperty('configName', Em.get(config, 'name')); |
| |
| if (configAction) { |
| additionalProperties.configAction = configAction; |
| } |
| |
| configProperty.setProperties(additionalProperties); |
| |
| if (configProperty.get('overrides')) { |
| configProperty.get('overrides').setEach('stackConfigProperty', config); |
| } |
| if (configProperty.get('compareConfigs')) { |
| configProperty.get('compareConfigs').invoke('setProperties', { |
| isComparison: false, |
| stackConfigProperty: config |
| }); |
| } |
| } |
| }, this); |
| }, |
| |
| /** |
| * |
| * @param {object} config |
| * @returns {Em.View} |
| */ |
| getWidgetView: function (config) { |
| const configWidgetType = Em.get(config, 'widgetType'), |
| name = Em.get(config, 'name'), |
| mixin = this.get('configNameWidgetMixinMap')[name], |
| viewClass = App[this.get('widgetTypeMap')[configWidgetType]]; |
| return Em.isNone(mixin) ? viewClass : viewClass.extend(mixin); |
| }, |
| |
| updateAttributesFromConditions: function (configConditions, serviceConfigs, serviceName) { |
| let isConditionTrue; |
| configConditions.forEach(configCondition => { |
| const ifStatement = configCondition.get('if'); |
| if (configCondition.get('resource') === 'config') { |
| isConditionTrue = App.configTheme.calculateConfigCondition(ifStatement, serviceConfigs); |
| if (configCondition.get('type') === 'subsection' || configCondition.get('type') === 'subsectionTab') { |
| this.changeSubsectionAttribute(configCondition, isConditionTrue); |
| } else { |
| this.changeConfigAttribute(configCondition, isConditionTrue, serviceName); |
| } |
| } else if (configCondition.get('resource') === 'service') { |
| const service = App.Service.find().findProperty('serviceName', ifStatement); |
| if (service) { |
| isConditionTrue = true; |
| } else if (!service && this.get('allSelectedServiceNames') && this.get('allSelectedServiceNames').length) { |
| isConditionTrue = this.get('allSelectedServiceNames').contains(ifStatement); |
| } else { |
| isConditionTrue = false; |
| } |
| this.changeConfigAttribute(configCondition, isConditionTrue, serviceName); |
| } |
| }); |
| }, |
| |
| /** |
| * |
| * @param configCondition {App.ThemeCondition} |
| * @param isConditionTrue {boolean} |
| */ |
| changeConfigAttribute: function (configCondition, isConditionTrue, serviceName) { |
| const conditionalConfigName = configCondition.get('configName'), |
| conditionalConfigFileName = configCondition.get('fileName'), |
| serviceConfigs = this.get('stepConfigs').findProperty('serviceName', serviceName).get('configs'), |
| action = isConditionTrue ? configCondition.get('then') : configCondition.get('else'), |
| valueAttributes = action.property_value_attributes; |
| this.set('isChangingConfigAttributes', true); |
| for (let key in valueAttributes) { |
| if (valueAttributes.hasOwnProperty(key)) { |
| const valueAttribute = App.StackConfigValAttributesMap[key] || key, |
| conditionalConfig = serviceConfigs.filterProperty('filename', conditionalConfigFileName).findProperty('name', conditionalConfigName); |
| if (conditionalConfig) { |
| if (key === 'visible') { |
| conditionalConfig.set('hiddenBySection', !valueAttributes[key]); |
| } |
| conditionalConfig.set(valueAttribute, valueAttributes[key]); |
| } |
| } |
| } |
| this.set('isChangingConfigAttributes', false); |
| }, |
| /** |
| * |
| * @param subsectionCondition {App.ThemeCondition} |
| * @param isConditionTrue {boolean} |
| */ |
| changeSubsectionAttribute: function (subsectionCondition, isConditionTrue) { |
| var subsectionConditionName = subsectionCondition.get('name'); |
| var action = isConditionTrue ? subsectionCondition.get('then') : subsectionCondition.get('else'); |
| if (subsectionCondition.get('id')) { |
| const valueAttributes = action.property_value_attributes; |
| if (valueAttributes && !Em.none(valueAttributes.visible)) { |
| let themeResource; |
| if (subsectionCondition.get('type') === 'subsection') { |
| themeResource = App.SubSection.find().find(function (subsection) { |
| return subsection.get('name') === subsectionConditionName && subsectionCondition.get('id').toLowerCase().includes(subsection.get('themeName').toLowerCase()); |
| }); |
| } else if (subsectionCondition.get('type') === 'subsectionTab') { |
| themeResource = App.SubSectionTab.find().find(function (subsectionTab) { |
| return subsectionTab.get('name') === subsectionConditionName && subsectionCondition.get('id').toLowerCase().includes(subsectionTab.get('themeName').toLowerCase()); |
| }); |
| } |
| themeResource.set('isHiddenByConfig', !valueAttributes.visible); |
| themeResource.get('configs').setEach('hiddenBySection', !valueAttributes.visible); |
| themeResource.get('configs').setEach('hiddenBySubSection', !valueAttributes.visible); |
| } |
| } |
| }, |
| |
| /** |
| * Data reordering before tabs rendering. |
| * Reorder all sections/subsections into rows based on their rowIndex |
| * @param tab |
| */ |
| processTab: function (tab) { |
| // process sections |
| let sectionRows = []; |
| const sections = tab.get('sections'); |
| for (let j = 0; j < sections.get('length'); j++) { |
| const section = sections.objectAt(j); |
| let sectionRow = sectionRows[section.get('rowIndex')]; |
| if (!sectionRow) { |
| sectionRow = sectionRows[section.get('rowIndex')] = []; |
| } |
| sectionRow.push(section); |
| |
| //process subsections |
| const subsections = section.get('subSections'); |
| let subsectionRows = []; |
| for (let k = 0; k < subsections.get('length'); k++) { |
| const subsection = subsections.objectAt(k); |
| let subsectionRow = subsectionRows[subsection.get('rowIndex')]; |
| if (!subsectionRow) { |
| subsectionRow = subsectionRows[subsection.get('rowIndex')] = []; |
| } |
| subsectionRow.push(subsection); |
| // leave a title gap if one of the subsection on the same row within the same section has title |
| if (subsection.get('displayName')) { |
| subsectionRow.hasTitleGap = true; |
| } |
| } |
| section.set('subsectionRows', subsectionRows); |
| } |
| tab.set('sectionRows', sectionRows); |
| } |
| }); |