enhanced_configs.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var blueprintUtils = require('utils/blueprint');
  20. App.EnhancedConfigsMixin = Em.Mixin.create({
  21. /**
  22. * this value is used for observing
  23. * whether recommendations for dependent properties was received from server
  24. * @type {number}
  25. */
  26. recommendationTimeStamp: null,
  27. /**
  28. * flag is true when Ambari changes some of the dependent properties
  29. * @type {boolean}
  30. */
  31. hasChangedDependencies: function() {
  32. return App.get('isClusterSupportsEnhancedConfigs') && this.get('isControllerSupportsEnhancedConfigs') && this.get('_dependentConfigValues.length') > 0;
  33. }.property('_dependentConfigValues.length'),
  34. /**
  35. * defines is block with changed dependent configs should be shown
  36. * rely on controller
  37. * @type {boolean}
  38. */
  39. isControllerSupportsEnhancedConfigs: function() {
  40. return ['wizardStep7Controller','mainServiceInfoConfigsController'].contains(this.get('name'));
  41. }.property('name'),
  42. /**
  43. * defines if initialValue of config can be used on current controller
  44. * if not savedValue is used instead
  45. * @type {boolean}
  46. */
  47. useInitialValue: function() {
  48. ['wizardStep7Controller'].contains(this.get('name'));
  49. }.property('name'),
  50. /**
  51. * message fro alert box for dependent configs
  52. * @type {string}
  53. */
  54. dependenciesMessage: function() {
  55. var changedServices = this.get('changedProperties').mapProperty('serviceName').uniq();
  56. var cfgLen = this.get('changedProperties.length') === 1 ? 'singular' : 'plural';
  57. var sLen = changedServices.length === 1 ? 'singular' : 'plural';
  58. return Em.I18n.t('popup.dependent.configs.dependencies.config.' + cfgLen).format(this.get('changedProperties.length'))
  59. + Em.I18n.t('popup.dependent.configs.dependencies.service.' + sLen).format(changedServices.length);
  60. }.property('changedProperties'),
  61. /**
  62. * values for dependent configs
  63. * @type {Object[]}
  64. * ex:
  65. * {
  66. * saveRecommended: {boolean}, //by default is true (checkbox binding)
  67. * saveRecommendedDefault: {boolean}, used for cancel operation to restore previous state
  68. * toDelete: {boolean} [true], // defines if property should be deleted
  69. * toAdd: {boolean} [false], // defines if property should be added
  70. * isDeleted: {boolean} [true], // defines if property was deleted, but was present in initial configs
  71. * fileName: {string}, //file name without '.xml'
  72. * propertyName: {string},
  73. * parentConfigs: {string[]} // name of the parent configs
  74. * configGroup: {string},
  75. * value: {string},
  76. * serviceName: {string},
  77. * allowChangeGroup: {boolean}, //used to disable group link for current service
  78. * serviceDisplayName: {string},
  79. * recommendedValue: {string}
  80. * }
  81. * @private
  82. */
  83. _dependentConfigValues: Em.A([]),
  84. /**
  85. * dependent properties that was changed by Ambari
  86. * @type {Object[]}
  87. */
  88. changedProperties: function() {
  89. return this.get('_dependentConfigValues').filterProperty('saveRecommended', true);
  90. }.property('_dependentConfigValues.@each.saveRecommended'),
  91. /**
  92. * dependent file names for configs
  93. * @type {string[]}
  94. */
  95. dependentFileNames: [],
  96. /**
  97. * dependent service names for configs
  98. * @type {string[]}
  99. */
  100. dependentServiceNames: [],
  101. /**
  102. * config groups for dependent services
  103. * @type {App.ConfigGroup[]}
  104. */
  105. dependentConfigGroups: [],
  106. /**
  107. * contains config group name that need to be saved
  108. * {
  109. * serviceName: {String} configGroupName
  110. * }
  111. * @type {Object}
  112. */
  113. groupsToSave: {},
  114. /******************************METHODS THAT WORKS WITH DEPENDENT CONFIGS *************************************/
  115. /**
  116. * clear values for dependent configs
  117. * @method clearDependentConfigs
  118. * @private
  119. */
  120. clearDependentConfigs: function() {
  121. this.setProperties({
  122. groupsToSave: {},
  123. _dependentConfigValues: []
  124. });
  125. },
  126. onConfigGroupChangeForEnhanced: function() {
  127. if (this.get('name') === 'mainServiceInfoConfigsController') {
  128. this.clearDependentConfigs();
  129. } else {
  130. this.set('groupsToSave', {});
  131. }
  132. this.get('dependentServiceNames').forEach(function(serviceName) {
  133. var defaultGroup = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).findProperty('isDefault');
  134. this.get('groupsToSave')[serviceName] = defaultGroup.get('name');
  135. }, this);
  136. }.observes('selectedConfigGroup'),
  137. /**
  138. * runs <code>setDependentServicesAndFileNames<code>
  139. * for stack properties for current service
  140. * @method loadDependentConfigs
  141. */
  142. setDependentServices: function(serviceName) {
  143. App.StackConfigProperty.find().forEach(function(stackProperty) {
  144. if (stackProperty.get('serviceName') === serviceName && stackProperty.get('propertyDependedBy.length') > 0) {
  145. this._setDependentServicesAndFileNames(stackProperty);
  146. }
  147. }, this);
  148. },
  149. /**
  150. * get config group object for current service
  151. * @param serviceName
  152. * @returns {App.ConfigGroup|null}
  153. */
  154. getGroupForService: function(serviceName) {
  155. if (this.get('stepConfigs.length') === 0) return null;
  156. if (this.get('name') === 'wizardStep7Controller') {
  157. return this.get('stepConfigs').findProperty('serviceName', serviceName).get('selectedConfigGroup');
  158. } else {
  159. if (this.get('content.serviceName') === serviceName) {
  160. return this.get('selectedConfigGroup')
  161. } else {
  162. if (this.get('selectedConfigGroup.isDefault')) {
  163. return this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).findProperty('isDefault');
  164. } else {
  165. return this.get('dependentConfigGroups').findProperty('name', this.get('groupsToSave')[serviceName]);
  166. }
  167. }
  168. }
  169. },
  170. /**
  171. * show popup to select config group for dependent services
  172. * to which dependent configs will ve saved
  173. * @method showSelectGroupsPopup
  174. */
  175. showSelectGroupPopup: function(event) {
  176. var serviceName = event.context;
  177. if (serviceName !== this.get('content.serviceName')) {
  178. var groups = this.get('dependentConfigGroups').filterProperty('service.serviceName', serviceName).mapProperty('name').uniq();
  179. if (groups.length) {
  180. var configs = this.get('_dependentConfigValues').filterProperty('serviceName', serviceName);
  181. App.showSelectGroupsPopup(serviceName, groups, this.get('groupsToSave'), configs);
  182. }
  183. }
  184. },
  185. /**
  186. * disable saving recommended value for current config
  187. * @param config
  188. * @param {boolean} saveRecommended
  189. * @method removeCurrentFromDependentList
  190. */
  191. removeCurrentFromDependentList: function (config, saveRecommended) {
  192. var current = this.get('_dependentConfigValues').find(function(dependentConfig) {
  193. return Em.get(dependentConfig, 'propertyName') == config.get('name') && Em.get(dependentConfig, 'fileName') == App.config.getConfigTagFromFileName(config.get('filename'))
  194. });
  195. if (current) {
  196. Em.setProperties(current, {
  197. 'saveRecommended': !!saveRecommended,
  198. 'saveRecommendedDefault': !!saveRecommended
  199. });
  200. }
  201. },
  202. /**
  203. * sends request to get values for dependent configs
  204. * @param {{type: string, name: string}[]} changedConfigs - list of changed configs to track recommendations
  205. * @param {Boolean} initial
  206. * @param {Function} onComplete
  207. * @returns {$.ajax|null}
  208. */
  209. getRecommendationsForDependencies: function(changedConfigs, initial, onComplete) {
  210. if (Em.isArray(changedConfigs) && changedConfigs.length > 0 || initial) {
  211. var recommendations = this.get('hostGroups');
  212. recommendations.blueprint.configurations = blueprintUtils.buildConfigsJSON(this.get('services'), this.get('stepConfigs'));
  213. delete recommendations.config_groups;
  214. var dataToSend = {
  215. recommend: 'configurations',
  216. hosts: this.get('hostNames'),
  217. services: this.get('serviceNames')
  218. };
  219. if (App.get('isClusterSupportsEnhancedConfigs') && changedConfigs) {
  220. if (changedConfigs) {
  221. dataToSend.recommend = 'configuration-dependencies';
  222. dataToSend.changed_configurations = changedConfigs;
  223. }
  224. if (!this.get('selectedConfigGroup.isDefault') && this.get('selectedConfigGroup.hosts.length') > 0) {
  225. var configGroups = this.buildConfigGroupJSON(this.get('stepConfigs').findProperty('serviceName', this.get('content.serviceName')).get('configs'), this.get('selectedConfigGroup'));
  226. recommendations.config_groups = [configGroups];
  227. }
  228. }
  229. dataToSend.recommendations = recommendations;
  230. return App.ajax.send({
  231. name: 'config.recommendations',
  232. sender: this,
  233. data: {
  234. stackVersionUrl: App.get('stackVersionURL'),
  235. dataToSend: dataToSend,
  236. initial: initial
  237. },
  238. success: 'dependenciesSuccess',
  239. error: 'dependenciesError',
  240. callback: function() {
  241. if (onComplete) {
  242. onComplete()
  243. }
  244. }
  245. });
  246. } else {
  247. return null;
  248. }
  249. },
  250. /**
  251. * generates JSON with config group info to send it for recommendations
  252. * @param configs
  253. * @param configGroup
  254. * @returns {{configurations: Object[], hosts: string[]}}
  255. */
  256. buildConfigGroupJSON: function(configs, configGroup) {
  257. Em.assert('configGroup can\'t be null', configGroup);
  258. var hosts = configGroup.get('hosts');
  259. var configurations = {};
  260. var overrides = configs.forEach(function(cp) {
  261. var override = cp.get('overrides') && cp.get('overrides').findProperty('group.name', configGroup.get('name'));
  262. if (override) {
  263. var tag = App.config.getConfigTagFromFileName(cp.get('filename'));
  264. if (!configurations[tag]) {
  265. configurations[tag] = { properties: {} };
  266. }
  267. configurations[tag].properties[cp.get('name')] = override.get('value');
  268. }
  269. });
  270. return {
  271. configurations: [configurations],
  272. hosts: hosts
  273. }
  274. },
  275. /**
  276. * shows popup with results for recommended value
  277. * if case properties that was changes belongs to not default group
  278. * user should pick to what config group from dependent service dependent properties will be saved
  279. * @param data
  280. * @param opt
  281. * @param params
  282. * @method dependenciesSuccess
  283. */
  284. dependenciesSuccess: function (data, opt, params) {
  285. this._saveRecommendedValues(data, params.initial, params.dataToSend.changed_configurations);
  286. this.set("recommendationsConfigs", Em.get(data.resources[0] , "recommendations.blueprint.configurations"));
  287. if (!params.initial) {
  288. this.updateDependentConfigs();
  289. }
  290. },
  291. /**
  292. * method to show popup with dependent configs
  293. * @method showChangedDependentConfigs
  294. */
  295. showChangedDependentConfigs: function(event, callback, secondary) {
  296. var self = this;
  297. if (this.get('_dependentConfigValues.length') > 0) {
  298. App.showDependentConfigsPopup(this.get('_dependentConfigValues'), function() {
  299. self.updateDependentConfigs();
  300. if (callback) {
  301. callback();
  302. }
  303. }, secondary);
  304. } else {
  305. if (callback) {
  306. callback();
  307. }
  308. }
  309. },
  310. /**
  311. *
  312. * @param jqXHR
  313. * @param ajaxOptions
  314. * @param error
  315. * @param opt
  316. */
  317. dependenciesError: function(jqXHR, ajaxOptions, error, opt) {
  318. this.set('recommendationTimeStamp', (new Date).getTime());
  319. App.ajax.defaultErrorHandler(jqXHR, opt.url, opt.method, jqXHR.status);
  320. },
  321. /**
  322. * defines file names for configs and set them to <code>dependentFileNames<code> and
  323. * defines service names for configs and set them to <code>dependentServiceNames<code>
  324. * @param {App.StackConfigProperty} stackProperty
  325. * @private
  326. */
  327. _setDependentServicesAndFileNames: function(stackProperty) {
  328. if (stackProperty.get('propertyDependedBy.length') > 0) {
  329. stackProperty.get('propertyDependedBy').forEach(function(dependent) {
  330. var tag = App.config.getConfigTagFromFileName(dependent.type);
  331. /** setting dependent fileNames (without '.xml') **/
  332. if (!this.get('dependentFileNames').contains(tag)) {
  333. this.get('dependentFileNames').push(tag);
  334. }
  335. /** setting dependent serviceNames (without current serviceName) **/
  336. var dependentProperty = App.StackConfigProperty.find(dependent.name + "_" + tag);
  337. if (dependentProperty) {
  338. if (dependentProperty.get('serviceName') && !this.get('dependentServiceNames').contains(dependentProperty.get('serviceName')) && dependentProperty.get('serviceName') !== this.get('content.serviceName')) {
  339. this.get('dependentServiceNames').push(dependentProperty.get('serviceName'));
  340. }
  341. this._setDependentServicesAndFileNames(dependentProperty);
  342. }
  343. }, this);
  344. }
  345. },
  346. /**
  347. * saves values from response for dependent config properties to <code>_dependentConfigValues<code>
  348. * @param data
  349. * @param [updateOnlyBoundaries=false]
  350. * @param [changedConfigs=null]
  351. * @method saveRecommendedValues
  352. * @private
  353. */
  354. _saveRecommendedValues: function(data, updateOnlyBoundaries, changedConfigs) {
  355. Em.assert('invalid data - `data.resources[0].recommendations.blueprint.configurations` not defined ', data && data.resources[0] && Em.get(data.resources[0], 'recommendations.blueprint.configurations'));
  356. var configObject = data.resources[0].recommendations.blueprint.configurations;
  357. this.parseConfigsByTag(configObject, updateOnlyBoundaries, changedConfigs, false);
  358. if (!this.get('selectedConfigGroup.isDefault') && data.resources[0].recommendations['config-groups']) {
  359. var configFroGroup = data.resources[0].recommendations['config-groups'][0];
  360. this.parseConfigsByTag(configFroGroup.configurations, updateOnlyBoundaries, changedConfigs, true);
  361. this.parseConfigsByTag(configFroGroup.dependent_configurations, updateOnlyBoundaries, changedConfigs, true);
  362. }
  363. },
  364. /**
  365. * saves values from response for dependent configs to <code>_dependentConfigValues<code>
  366. * @param configObject - JSON response from `recommendations` endpoint
  367. * @param updateOnlyBoundaries
  368. * @param notDefaultGroup
  369. * @param {App.ServiceConfigProperty[]} parentConfigs - config properties for which recommendations were received
  370. * @method saveRecommendedValues
  371. * @private
  372. */
  373. parseConfigsByTag: function(configObject, updateOnlyBoundaries, parentConfigs, notDefaultGroup) {
  374. var parentPropertiesNames = parentConfigs ? parentConfigs.mapProperty('name') : [];
  375. /** get all configs by config group **/
  376. for (var key in configObject) {
  377. /** defines main info for file name (service name, config group, config that belongs to filename) **/
  378. var service = App.config.getServiceByConfigType(key);
  379. var serviceName = service.get('serviceName');
  380. var stepConfig = this.get('stepConfigs').findProperty('serviceName', serviceName);
  381. if (stepConfig) {
  382. var initialValue;
  383. var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(key)) : [];
  384. var group = this.getGroupForService(serviceName);
  385. for (var propertyName in configObject[key].properties) {
  386. var dependentProperty = this.get('_dependentConfigValues').filterProperty('propertyName', propertyName).findProperty('fileName', key);
  387. var cp = configProperties.findProperty('name', propertyName);
  388. var override = (notDefaultGroup && group && cp && cp.get('overrides')) ? cp.get('overrides').findProperty('group.name', group.get('name')) : null;
  389. var value = override ? override.get('value') : cp && cp.get('value');
  390. if (this.get('useInitialValue')) {
  391. initialValue = override ? override.get('initialValue') : cp && cp.get('initialValue');
  392. } else {
  393. initialValue = override ? override.get('savedValue') : cp && cp.get('savedValue');
  394. }
  395. initialValue = Em.isNone(initialValue) ? value : initialValue;
  396. var recommendedValue = configObject[key].properties[propertyName];
  397. var isNewProperty = (!notDefaultGroup && Em.isNone(cp)) || (notDefaultGroup && group && Em.isNone(override));
  398. var parsedInit = parseFloat(initialValue);
  399. var parsedRecommended = parseFloat(recommendedValue);
  400. if (!isNaN(parsedInit) && !isNaN(parsedRecommended)) {
  401. initialValue = parsedInit.toString();
  402. recommendedValue = parsedRecommended.toString();
  403. }
  404. if (!updateOnlyBoundaries && !parentPropertiesNames.contains(propertyName) && initialValue != recommendedValue) { //on first initial request we don't need to change values
  405. if (dependentProperty) {
  406. Em.set(dependentProperty, 'value', initialValue);
  407. Em.set(dependentProperty, 'recommendedValue', recommendedValue);
  408. Em.set(dependentProperty, 'toDelete', false);
  409. Em.set(dependentProperty, 'toAdd', isNewProperty);
  410. Em.set(dependentProperty, 'parentConfigs', dependentProperty.parentConfigs.concat(parentPropertiesNames).uniq());
  411. } else {
  412. this.get('_dependentConfigValues').pushObject({
  413. saveRecommended: true,
  414. saveRecommendedDefault: true,
  415. toDelete: false,
  416. isDeleted: false,
  417. toAdd: isNewProperty,
  418. fileName: key,
  419. propertyName: propertyName,
  420. configGroup: group ? group.get('name') : service.get('displayName') + " Default",
  421. value: initialValue,
  422. parentConfigs: parentPropertiesNames,
  423. serviceName: serviceName,
  424. allowChangeGroup: serviceName != this.get('content.serviceName') && !this.get('selectedConfigGroup.isDefault'),
  425. serviceDisplayName: service.get('displayName'),
  426. recommendedValue: recommendedValue
  427. });
  428. }
  429. }
  430. /**
  431. * saving recommended value to service config properties
  432. * this value can be used as marker on slider widget
  433. */
  434. if (notDefaultGroup) {
  435. override && override.set('recommendedValue', recommendedValue);
  436. } else {
  437. cp && cp.set('recommendedValue', recommendedValue);
  438. }
  439. /**
  440. * clear _dependentPropertyValues from
  441. * properties that wasn't changed while recommendations
  442. */
  443. if ((initialValue == recommendedValue) || (Em.isNone(initialValue) && Em.isNone(recommendedValue))) {
  444. /** if recommended value same as default we shouldn't show it in popup **/
  445. if (notDefaultGroup) {
  446. if (override) {
  447. if (override.get('isNotSaved')) {
  448. cp.get('overrides').removeObject(override);
  449. } else {
  450. override.set('value', initialValue);
  451. }
  452. if (dependentProperty) {
  453. this.get('_dependentConfigValues').removeObject(dependentProperty);
  454. }
  455. }
  456. } else {
  457. cp.set('value', initialValue);
  458. if (dependentProperty) {
  459. this.get('_dependentConfigValues').removeObject(dependentProperty);
  460. }
  461. }
  462. }
  463. }
  464. }
  465. this._saveRecommendedAttributes(configObject, parentPropertiesNames, updateOnlyBoundaries);
  466. }
  467. },
  468. /**
  469. * Save property attributes received from recommendations. These attributes are minimum, maximum,
  470. * increment_step. Attributes are stored in <code>App.StackConfigProperty</code> model.
  471. *
  472. * @param {Object[]} configs
  473. * @param parentPropertiesNames
  474. * @param updateOnlyBoundaries
  475. * @private
  476. */
  477. _saveRecommendedAttributes: function(configs, parentPropertiesNames, updateOnlyBoundaries) {
  478. var self = this;
  479. Em.keys(configs).forEach(function (siteName) {
  480. var service = App.config.getServiceByConfigType(siteName);
  481. var serviceName = service.get('serviceName');
  482. var group = self.getGroupForService(serviceName);
  483. var stepConfig = self.get('stepConfigs').findProperty('serviceName', serviceName);
  484. var configProperties = stepConfig ? stepConfig.get('configs').filterProperty('filename', App.config.getOriginalFileName(siteName)) : [];
  485. var properties = configs[siteName].property_attributes || {};
  486. Em.keys(properties).forEach(function (propertyName) {
  487. var cp = configProperties.findProperty('name', propertyName);
  488. var stackProperty = App.StackConfigProperty.find().findProperty('id', propertyName + '_' + siteName);
  489. var attributes = properties[propertyName] || {};
  490. Em.keys(attributes).forEach(function (attributeName) {
  491. if (attributeName == 'delete') {
  492. if (!updateOnlyBoundaries) {
  493. var dependentProperty = self.get('_dependentConfigValues').filterProperty('propertyName', propertyName).findProperty('fileName', siteName);
  494. if (dependentProperty) {
  495. Em.set(dependentProperty, 'toDelete', true);
  496. Em.set(dependentProperty, 'toAdd', false);
  497. Em.set(dependentProperty, 'recommendedValue', null);
  498. } else {
  499. self.get('_dependentConfigValues').pushObject({
  500. saveRecommended: true,
  501. saveRecommendedDefault: true,
  502. propertyValue: cp && (cp.get('useInitialValue') ? cp.get('initialValue') : cp.get('savedValue')),
  503. toDelete: true,
  504. toAdd: false,
  505. isDeleted: true,
  506. fileName: siteName,
  507. propertyName: propertyName,
  508. configGroup: group ? group.get('name') : service.get('displayName') + " Default",
  509. parentConfigs: parentPropertiesNames,
  510. serviceName: service.get('serviceName'),
  511. allowChangeGroup: service.get('serviceName') != self.get('content.serviceName') && !self.get('selectedConfigGroup.isDefault'),
  512. serviceDisplayName: service.get('displayName'),
  513. recommendedValue: null
  514. });
  515. }
  516. }
  517. } else if (stackProperty) {
  518. Em.set(stackProperty.get('valueAttributes'), attributeName, attributes[attributeName]);
  519. }
  520. });
  521. });
  522. });
  523. },
  524. /**
  525. * save values that are stored in <code>_dependentConfigValues<code>
  526. * to step configs
  527. */
  528. updateDependentConfigs: function() {
  529. var self = this;
  530. this.get('stepConfigs').forEach(function(serviceConfigs) {
  531. var selectedGroup = self.getGroupForService(serviceConfigs.get('serviceName'));
  532. self._updateRecommendedValues(serviceConfigs, selectedGroup);
  533. self._addRecommendedProperties(serviceConfigs, selectedGroup);
  534. self._removeUnRecommendedProperties(serviceConfigs, selectedGroup);
  535. });
  536. this.set('recommendationTimeStamp', (new Date).getTime());
  537. },
  538. /**
  539. * add configs that was recommended and wasn't present in stepConfigs
  540. * @param stepConfigs
  541. * @param selectedGroup
  542. * @private
  543. */
  544. _addRecommendedProperties: function(stepConfigs, selectedGroup) {
  545. var propertiesToAdd = this.get('_dependentConfigValues').filterProperty('toAdd').filterProperty('serviceName', stepConfigs.get('serviceName'));
  546. if (propertiesToAdd.length > 0) {
  547. propertiesToAdd.forEach(function(propertyToAdd) {
  548. if (!selectedGroup || selectedGroup.get('isDefault')) {
  549. if (Em.get(propertyToAdd, 'isDeleted')) {
  550. this.get('_dependentConfigValues').removeObject(propertyToAdd);
  551. }
  552. var addedProperty = App.ServiceConfigProperty.create({
  553. name: Em.get(propertyToAdd, 'propertyName'),
  554. displayName: Em.get(propertyToAdd, 'propertyName'),
  555. value: Em.get(propertyToAdd, 'recommendedValue'),
  556. recommendedValue: Em.get(propertyToAdd, 'recommendedValue'),
  557. savedValue: null,
  558. category: 'Advanced ' + Em.get(propertyToAdd, 'fileName'),
  559. serviceName: stepConfigs.get('serviceName'),
  560. filename: App.config.getOriginalFileName(Em.get(propertyToAdd, 'fileName')),
  561. isNotSaved: !Em.get(propertyToAdd, 'isDeleted'),
  562. isRequired: true
  563. });
  564. stepConfigs.get('configs').pushObject(addedProperty);
  565. addedProperty.validate();
  566. } else {
  567. var cp = stepConfigs.get('configs').filterProperty('name', Em.get(propertyToAdd, 'propertyName')).findProperty('filename', App.config.getOriginalFileName(Em.get(propertyToAdd, 'fileName')));
  568. if (Em.get(propertyToAdd, 'isDeleted')) {
  569. this.get('_dependentConfigValues').removeObject(propertyToAdd);
  570. }
  571. this.addOverrideProperty(cp, selectedGroup, Em.get(propertyToAdd, 'recommendedValue'), !Em.get(propertyToAdd, 'isDeleted'));
  572. }
  573. Em.setProperties(propertyToAdd, {
  574. isDeleted: false,
  575. toAdd: false,
  576. toDelete: false
  577. });
  578. }, this);
  579. }
  580. },
  581. /**
  582. * remove configs that was recommended to delete from stepConfigs
  583. * @param stepConfigs
  584. * @param selectedGroup
  585. * @private
  586. */
  587. _removeUnRecommendedProperties: function(stepConfigs, selectedGroup) {
  588. var propertiesToDelete = this.get('_dependentConfigValues').filterProperty('toDelete').filterProperty('serviceName', stepConfigs.get('serviceName'));
  589. if (propertiesToDelete.length > 0) {
  590. propertiesToDelete.forEach(function(propertyToDelete) {
  591. var cp = stepConfigs.get('configs').filterProperty('name', Em.get(propertyToDelete, 'propertyName')).findProperty('filename', App.config.getOriginalFileName(Em.get(propertyToDelete, 'fileName')));
  592. if (cp) {
  593. if (!selectedGroup || selectedGroup.get('isDefault')) {
  594. if (cp.get('isNotSaved')) {
  595. this.get('_dependentConfigValues').removeObject(propertyToDelete);
  596. }
  597. stepConfigs.get('configs').removeObject(cp);
  598. if (!cp.get('isNotSaved')) {
  599. Em.set(propertyToDelete, 'isDeleted', true);
  600. }
  601. } else {
  602. var overriddenConfig = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name'));
  603. if (overriddenConfig) {
  604. if (overriddenConfig.get('isNotSaved')) {
  605. this.get('_dependentConfigValues').removeObject(propertyToDelete);
  606. }
  607. cp.removeObject(overriddenConfig);
  608. if (!overriddenConfig.get('isNotSaved')) {
  609. Em.set(propertyToDelete, 'isDeleted', true);
  610. }
  611. }
  612. }
  613. Em.setProperties(propertyToDelete, {
  614. toAdd: false,
  615. toDelete: false
  616. });
  617. }
  618. }, this);
  619. }
  620. },
  621. /**
  622. * update config to their recommended values
  623. * @param stepConfigs
  624. * @param selectedGroup
  625. * @private
  626. */
  627. _updateRecommendedValues: function(stepConfigs, selectedGroup) {
  628. var propertiesToUpdate = this.get('_dependentConfigValues').filter(function(p) {
  629. return !Em.get(p, 'toDelete') && !Em.get(p, 'toAdd') && Em.get(p, 'serviceName') == stepConfigs.get('serviceName');
  630. });
  631. if (propertiesToUpdate.length > 0) {
  632. stepConfigs.get('configs').forEach(function (cp) {
  633. var propertyToUpdate = propertiesToUpdate.filterProperty('propertyName', cp.get('name')).findProperty('fileName', App.config.getConfigTagFromFileName(cp.get('filename')));
  634. if (propertyToUpdate) {
  635. var valueToSave = propertyToUpdate.saveRecommended ? propertyToUpdate.recommendedValue : propertyToUpdate.value;
  636. if (!selectedGroup || selectedGroup.get('isDefault')) {
  637. if (propertyToUpdate.saveRecommended || cp.get('value') == propertyToUpdate.recommendedValue) {
  638. cp.set('value', valueToSave);
  639. }
  640. cp.set('recommendedValue', propertyToUpdate.recommendedValue);
  641. } else {
  642. if (stepConfigs.get('serviceName') !== this.get('content.serviceName')) {
  643. if (propertyToUpdate.saveRecommended || cp.get('value') == propertyToUpdate.recommendedValue) {
  644. cp.set('value', this.get('useInitialValue') ? cp.get('initialValue') : cp.get('savedValue'));
  645. }
  646. cp.set('recommendedValue', propertyToUpdate.recommendedValue);
  647. }
  648. var overriddenConfig = cp.get('overrides') && cp.get('overrides').findProperty('group.name', selectedGroup.get('name'));
  649. if (overriddenConfig) {
  650. if (propertyToUpdate.saveRecommended || overriddenConfig.get('value') == propertyToUpdate.recommendedValue) {
  651. overriddenConfig.set('value', valueToSave);
  652. }
  653. overriddenConfig.set('recommendedValue', propertyToUpdate.recommendedValue);
  654. }
  655. }
  656. }
  657. }, this);
  658. }
  659. }
  660. });