service_config_property.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  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. /**
  20. * @class ServiceConfigProperty
  21. */
  22. App.ServiceConfigProperty = Em.Object.extend({
  23. name: '',
  24. displayName: '',
  25. /**
  26. * value that is shown on IU
  27. * and is changing by user
  28. * @type {String|null}
  29. */
  30. value: '',
  31. /**
  32. * value that is saved on cluster configs
  33. * and stored in /api/v1/clusters/{name}/configurations
  34. * @type {String|null}
  35. */
  36. savedValue: null,
  37. /**
  38. * value that is returned from server as recommended
  39. * or stored on stack
  40. * @type {String|null}
  41. */
  42. recommendedValue: null,
  43. /**
  44. * initial value of config. if value is saved it will be initial
  45. * otherwise first recommendedValue will be initial
  46. * @type {String|null}
  47. */
  48. initialValue: null,
  49. /**
  50. * value that is shown on IU
  51. * and is changing by user
  52. * @type {boolean}
  53. */
  54. isFinal: false,
  55. /**
  56. * value that is saved on cluster configs api
  57. * @type {boolean}
  58. */
  59. savedIsFinal: null,
  60. /**
  61. * value that is returned from server as recommended
  62. * or stored on stack
  63. * @type {boolean}
  64. */
  65. recommendedIsFinal: null,
  66. /**
  67. * @type {boolean}
  68. */
  69. supportsFinal: false,
  70. /**
  71. * Hint message to display in tooltip. Tooltip will be wrapped on question mark icon.
  72. * If value is <code>false</code> no tooltip and question mark icon.
  73. *
  74. * @type {boolean|string}
  75. */
  76. hintMessage: false,
  77. /**
  78. * Display label on the right side from input. In general used for checkbox only.
  79. *
  80. * @type {boolean}
  81. */
  82. rightSideLabel: false,
  83. /**
  84. * Text to be shown as placeholder
  85. * By default savedValue is shown as placeholder
  86. * @type {String}
  87. */
  88. placeholderText: '',
  89. /**
  90. * type of widget View
  91. * @type {string}
  92. * @default null
  93. */
  94. widgetType: null,
  95. /**
  96. * Placeholder used for configs with input type text
  97. */
  98. placeholder: Em.computed.firstNotBlank('placeholderText', 'savedValue'),
  99. retypedPassword: '',
  100. description: '',
  101. displayType: 'string', // string, digits, number, directories, custom
  102. unit: '',
  103. category: 'General',
  104. isRequired: true, // by default a config property is required
  105. isReconfigurable: true, // by default a config property is reconfigurable
  106. isEditable: true, // by default a config property is editable
  107. disabledAsComponentAction: false, // is true for component action configs
  108. isNotEditable: Em.computed.not('isEditable'),
  109. hideFinalIcon: Em.computed.and('!isFinal', 'isNotEditable'),
  110. isVisible: true,
  111. isMock: false, // mock config created created only to displaying
  112. isRequiredByAgent: true, // Setting it to true implies property will be stored in configuration
  113. isSecureConfig: false,
  114. errorMessage: '',
  115. warnMessage: '',
  116. validationErrors: [], // stores messages from validation response marked as ERRROR
  117. validationWarnings: [], // stores message from validation response marked as WARN
  118. serviceConfig: null, // points to the parent App.ServiceConfig object
  119. filename: '',
  120. isOriginalSCP : true, // if true, then this is original SCP instance and its value is not overridden value.
  121. parentSCP: null, // This is the main SCP which is overridden by this. Set only when isOriginalSCP is false.
  122. overrides : null,
  123. overrideValues: [],
  124. group: null, // Contain group related to this property. Set only when isOriginalSCP is false.
  125. isUserProperty: null, // This property was added by user. Hence they get removal actions etc.
  126. isOverridable: true,
  127. compareConfigs: [],
  128. isComparison: false,
  129. hasCompareDiffs: false,
  130. showLabel: true,
  131. isConfigIdentity: false,
  132. copy: '',
  133. error: Em.computed.bool('errorMessage.length'),
  134. warn: Em.computed.bool('warnMessage.length'),
  135. hasValidationErrors: Em.computed.bool('validationErrors.length'),
  136. hasValidationWarnings: Em.computed.bool('validationWarnings.length'),
  137. isValid: Em.computed.equal('errorMessage', ''),
  138. previousValue: null, // cached value before changing config <code>value</code>
  139. /**
  140. * List of <code>isFinal</code>-values for overrides
  141. * Set in the controller
  142. * Should be empty array by default!
  143. * @type {boolean[]}
  144. */
  145. overrideIsFinalValues: [],
  146. /**
  147. * true if property has warning or error
  148. * @type {boolean}
  149. */
  150. hasIssues: Em.computed.or('error', 'warn', 'overridesWithIssues.length'),
  151. overridesWithIssues: Em.computed.filterBy('overrides', 'hasIssues', true),
  152. index: null, //sequence number in category
  153. editDone: false, //Text field: on focusOut: true, on focusIn: false
  154. isNotSaved: false, // user property was added but not saved
  155. hasInitialValue: false, //if true then property value is defined and saved to server
  156. isHiddenByFilter: false, //if true then hide this property (filtered out)
  157. rowStyleClass: null, // CSS-Class to be applied on the row showing this config
  158. showAsTextBox: false,
  159. /**
  160. * config is invisible since wrapper section is hidden
  161. * @type {boolean}
  162. */
  163. hiddenBySection: false,
  164. /**
  165. * Determines config visibility on subsection level when wrapped.
  166. * @type {boolean}
  167. */
  168. hiddenBySubSection: false,
  169. /**
  170. * Determines visibility state including section/subsection state.
  171. * When <code>true</code> means that property is shown and may affect validation process.
  172. * When <code>false</code> means that property won't affect validation.
  173. */
  174. isActive: function() {
  175. return this.get('isVisible') && !this.get('hiddenBySubSection') && !this.get('hiddenBySection');
  176. }.property('isVisible', 'hiddenBySubSection', 'hiddenBySection'),
  177. /**
  178. * @type {boolean}
  179. */
  180. recommendedValueExists: function () {
  181. return !Em.isNone(this.get('recommendedValue')) && (this.get('recommendedValue') != "")
  182. && this.get('isRequiredByAgent') && !this.get('cantBeUndone');
  183. }.property('recommendedValue'),
  184. /**
  185. * Usage example see on <code>App.ServiceConfigRadioButtons.handleDBConnectionProperty()</code>
  186. *
  187. * @property {Ember.View} additionalView - custom view related to property
  188. **/
  189. additionalView: null,
  190. /**
  191. * If config is saved we should compare config <code>value<code> with <code>savedValue<code> to
  192. * find out if it was changed, but if config in not saved there is no <code>savedValue<code>, so
  193. * we should use <code>initialValue<code> instead.
  194. */
  195. isNotInitialValue: function() {
  196. if (Em.isNone(this.get('savedValue')) && !Em.isNone(this.get('initialValue'))) {
  197. var value = this.get('value'), initialValue = this.get('initialValue');
  198. if (this.get('stackConfigProperty.valueAttributes.type') == 'float') {
  199. initialValue = !Em.isNone(initialValue) ? '' + parseFloat(initialValue) : null;
  200. value = '' + parseFloat(value);
  201. }
  202. return initialValue !== value;
  203. }
  204. return false;
  205. }.property('initialValue', 'savedValue', 'value', 'stackConfigProperty.valueAttributes.type'),
  206. /**
  207. * Is property has active override with error
  208. */
  209. isValidOverride: function () {
  210. return this.get('overrides.length') ? !this.get('overrides').find(function(o) {
  211. return Em.get(o, 'isEditable') && Em.get(o, 'errorMessage');
  212. }) : true;
  213. }.property("overrides.@each.errorMessage"),
  214. /**
  215. * No override capabilities for fields which are not edtiable
  216. * and fields which represent master hosts.
  217. */
  218. isPropertyOverridable: function () {
  219. var overrideable = this.get('isOverridable');
  220. var editable = this.get('isEditable');
  221. var overrides = this.get('overrides');
  222. var dt = this.get('displayType');
  223. return overrideable && (editable || !overrides || !overrides.length) && (!["componentHost", "password"].contains(dt));
  224. }.property('isEditable', 'displayType', 'isOverridable', 'overrides.length'),
  225. isOverridden: function() {
  226. return (this.get('overrides') != null && this.get('overrides.length') > 0) || !this.get('isOriginalSCP');
  227. }.property('overrides', 'overrides.length', 'isOriginalSCP'),
  228. isOverrideChanged: function () {
  229. if (Em.isNone(this.get('overrides')) && this.get('overrideValues.length') === 0) return false;
  230. return JSON.stringify(this.get('overrides').mapProperty('isFinal')) !== JSON.stringify(this.get('overrideIsFinalValues'))
  231. || JSON.stringify(this.get('overrides').mapProperty('value')) !== JSON.stringify(this.get('overrideValues'));
  232. }.property('overrides.@each.isNotDefaultValue', 'overrides.@each.overrideIsFinalValues', 'overrideValues.length'),
  233. isRemovable: function() {
  234. return this.get('isEditable') && this.get('isRequiredByAgent') && !(this.get('overrides.length') > 0)
  235. && (this.get('isUserProperty') || !this.get('isOriginalSCP'));
  236. }.property('isUserProperty', 'isOriginalSCP', 'overrides.length', 'isRequiredByAgent'),
  237. init: function () {
  238. this.setInitialValues();
  239. this.set('viewClass', App.config.getViewClass(this.get("displayType"), this.get('dependentConfigPattern'), this.get('unit')));
  240. this.set('validator', App.config.getValidator(this.get("displayType")));
  241. this.validate();
  242. },
  243. setInitialValues: function () {
  244. if (Em.isNone(this.get('value'))) {
  245. if (!Em.isNone(this.get('savedValue'))) {
  246. this.set('value', this.get('savedValue'));
  247. } else if (!Em.isNone(this.get('recommendedValue'))) {
  248. this.set('value', this.get('recommendedValue'));
  249. }
  250. }
  251. this.set('previousValue', this.get('value'));
  252. if (this.get('value') === null) {
  253. this.set('isVisible', false);
  254. }
  255. if (this.get("displayType") === "password") {
  256. this.set('retypedPassword', this.get('value'));
  257. this.set('recommendedValue', '');
  258. }
  259. this.set('initialValue', this.get('value'));
  260. },
  261. /**
  262. * updates configs list that belongs to config group
  263. */
  264. updateGroupConfigs: function() {
  265. if (this.get('group')) {
  266. var o = this.get('group.properties').find(function(c) {
  267. return Em.get(c, 'name') === this.get('name') && Em.get(c, 'filename') === this.get('filename');
  268. }, this);
  269. if (o) {
  270. Em.set(o, 'value', this.get('value'));
  271. }
  272. }
  273. }.observes('value'),
  274. /**
  275. * Indicates when value is not the default value.
  276. * Returns false when there is no default value.
  277. *
  278. * @type {boolean}
  279. */
  280. isNotDefaultValue: function () {
  281. var value = this.get('value'),
  282. savedValue = this.get('savedValue'),
  283. supportsFinal = this.get('supportsFinal'),
  284. isFinal = this.get('isFinal'),
  285. savedIsFinal = this.get('savedIsFinal');
  286. if (this.get('name') === 'kdc_type') {
  287. return App.router.get('mainAdminKerberosController.kdcTypesValues')[savedValue] !== value;
  288. }
  289. // ignore precision difference for configs with type of `float` which value may ends with 0
  290. // e.g. between 0.4 and 0.40
  291. if (this.get('stackConfigProperty') && this.get('stackConfigProperty.valueAttributes.type') == 'float') {
  292. savedValue = !Em.isNone(savedValue) ? '' + parseFloat(savedValue) : null;
  293. value = '' + parseFloat(value);
  294. }
  295. return (savedValue != null && value !== savedValue) || (supportsFinal && !Em.isNone(savedIsFinal) && isFinal !== savedIsFinal);
  296. }.property('value', 'savedValue', 'isEditable', 'isFinal', 'savedIsFinal'),
  297. /**
  298. * Don't show "Undo" for hosts on Installer Step7
  299. */
  300. cantBeUndone: Em.computed.existsIn('displayType', ["componentHost", "componentHosts", "radio button"]),
  301. validate: function () {
  302. if (!this.get('isEditable')) {
  303. this.set('errorMessage', ''); // do not perform validation for not editable configs
  304. } else if ((typeof this.get('value') != 'object') && ((this.get('value') + '').length === 0)) {
  305. var widgetType = this.get('widgetType');
  306. this.set('errorMessage', (this.get('isRequired') && (!['test-db-connection','label'].contains(widgetType))) ? Em.I18n.t('errorMessage.config.required') : '');
  307. } else if (this.get('name') === 'llap_queue_capacity') {
  308. if (!isNaN(parseInt(this.get('value'), 10)) && parseInt(this.get('value'), 10) === 100) {
  309. this.set('warnMessage', Em.I18n.t('config.warnMessage.llap_queue_capacity.max'));
  310. } else {
  311. this.set('warnMessage', '');
  312. this.set('errorMessage', this.validator(this.get('value'), this.get('name'), this.get('retypedPassword')));
  313. }
  314. } else {
  315. this.set('errorMessage', this.validator(this.get('value'), this.get('name'), this.get('retypedPassword')));
  316. }
  317. }.observes('value', 'retypedPassword', 'isEditable'),
  318. viewClass: App.ServiceConfigTextField,
  319. validator: function() { return '' },
  320. /**
  321. * Get override for selected group
  322. *
  323. * @param {String} groupName
  324. * @returns {App.ServiceConfigProperty|null}
  325. */
  326. getOverride: function(groupName) {
  327. Em.assert('Group name should be defined string', (typeof groupName === 'string') && groupName);
  328. if (this.get('overrides.length')) {
  329. return this.get('overrides').findProperty('group.name', groupName);
  330. }
  331. return null;
  332. }
  333. });