service_config_property.js 14 KB

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