config_widget_view.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  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. require('views/common/controls_view');
  20. /**
  21. * Common view for config widgets
  22. * @type {Em.View}
  23. */
  24. App.ConfigWidgetView = Em.View.extend(App.SupportsDependentConfigs, App.WidgetPopoverSupport, App.ConvertUnitWidgetViewMixin, App.ServiceConfigCalculateId, {
  25. /**
  26. * @type {App.ConfigProperty}
  27. */
  28. config: null,
  29. /**
  30. * Determines if user hover on widget-view
  31. * @type {boolean}
  32. */
  33. isHover: false,
  34. /**
  35. * Determines if widget controls should be disabled
  36. * @type {boolean}
  37. */
  38. disabled: false,
  39. /**
  40. * Determines if widget is editable
  41. * It true - show all control-elements (undo, override, finalize etc) for widget
  42. * If false - no widget control-elements will be shown
  43. * Bound from template
  44. * @type {boolean}
  45. */
  46. canEdit: true,
  47. canNotEdit: Em.computed.not('canEdit'),
  48. /**
  49. * Config label class attribute. Displays validation status of config.
  50. * @type {string}
  51. */
  52. configLabelClass: '',
  53. /**
  54. * Tab where current widget placed
  55. * Bound in the template
  56. * @type {App.Tab}
  57. */
  58. tab: null,
  59. /**
  60. * Section where current widget placed
  61. * Bound in the template
  62. * @type {App.Section}
  63. */
  64. section: null,
  65. /**
  66. * Subsection where current widget placed
  67. * Bound in the template
  68. * @type {App.SubSection}
  69. */
  70. subSection: null,
  71. /**
  72. * Determines if user can switch custom widget-view to the input-field
  73. * @type {boolean}
  74. */
  75. supportSwitchToCheckBox: false,
  76. /**
  77. * @type {boolean}
  78. */
  79. showPencil: function () {
  80. return this.get('supportSwitchToCheckBox') && !this.get('disabled');
  81. }.property('supportSwitchToCheckBox', 'disabled'),
  82. /**
  83. * Alias to <code>config.isOriginalSCP</code>
  84. * Should be used in the templates
  85. * Don't use original <code>config.isOriginalSCP</code> in the widget-templates!!!
  86. * @type {boolean}
  87. */
  88. isOriginalSCPBinding: 'config.isOriginalSCP',
  89. /**
  90. * Check if property validation failed for overridden property in case when its value is equal to parent
  91. * config property.
  92. * @type {boolean}
  93. */
  94. isOverrideEqualityError: function() {
  95. return this.get('config.parentSCP') && this.get('config.parentSCP.value') == this.get('config.value');
  96. }.property('config.isValid'),
  97. /**
  98. * Alias to <code>config.isComparison</code>
  99. * Should be used in the templates
  100. * Don't use original <code>config.isComparison</code> in the widget-templates!!!
  101. * @type {boolean}
  102. */
  103. isComparisonBinding: 'config.isComparison',
  104. classNameBindings:['isComparison:compare-mode', 'config.overrides.length:overridden-property'],
  105. issueMessage: '',
  106. issueView: Em.View.extend({
  107. tagName: 'i',
  108. classNames: ['icon-warning-sign'],
  109. classNameBindings: ['issueIconClass'],
  110. attributeBindings:['issueMessage:data-original-title'],
  111. /**
  112. * @type {App.ServiceConfigProperty}
  113. */
  114. config: null,
  115. /**
  116. * @type {string}
  117. */
  118. issueIconClass: '',
  119. /**
  120. * @type {string}
  121. */
  122. issueMessage: '',
  123. didInsertElement: function() {
  124. App.tooltip($(this.get('element')));
  125. this.errorLevelObserver();
  126. this.addObserver('issuedConfig.warnMessage', this, this.errorLevelObserver);
  127. this.addObserver('issuedConfig.errorMessage', this, this.errorLevelObserver);
  128. },
  129. willDestroyElement: function() {
  130. this.removeObserver('issuedConfig.warnMessage', this, this.errorLevelObserver);
  131. this.removeObserver('issuedConfig.errorMessage', this, this.errorLevelObserver);
  132. },
  133. /**
  134. *
  135. * @method errorLevelObserver
  136. */
  137. errorLevelObserver: function() {
  138. var messageLevel = this.get('issuedConfig.errorMessage') ? 'ERROR': this.get('issuedConfig.warnMessage') ? 'WARN' : 'NONE';
  139. var issue = {
  140. ERROR: {
  141. iconClass: '',
  142. message: this.get('issuedConfig.errorMessage'),
  143. configLabelClass: 'text-error'
  144. },
  145. WARN: {
  146. iconClass: 'warning',
  147. message: this.get('issuedConfig.warnMessage'),
  148. configLabelClass: 'text-warning'
  149. },
  150. NONE: {
  151. iconClass: 'hide',
  152. message: false,
  153. configLabelClass: ''
  154. }
  155. }[messageLevel];
  156. this.set('parentView.configLabelClass', issue.configLabelClass);
  157. this.set('issueIconClass', issue.iconClass);
  158. this.set('issueMessage', issue.message);
  159. this.set('parentView.issueMessage', issue.message);
  160. },
  161. /**
  162. * @type {App.ServiceConfigProperty}
  163. */
  164. issuedConfig: function() {
  165. var config = this.get('config');
  166. // check editable override
  167. if (!config.get('isEditable') && config.get('isOriginalSCP') && config.get('overrides.length') && config.get('overrides').someProperty('isEditable', true)) {
  168. config = config.get('overrides').findProperty('isEditable', true);
  169. } else if (config.get('isOriginalSCP') && config.get('isEditable')) {
  170. // use original config if it is not valid
  171. if (!config.get('isValid')) {
  172. return config;
  173. // scan overrides for non valid values and use it
  174. } else if (config.get('overrides.length') && config.get('overrides').someProperty('isValid', false)) {
  175. return config.get('overrides').findProperty('isValid', false);
  176. }
  177. }
  178. return config;
  179. }.property('config.isEditable', 'config.overrides.length')
  180. }),
  181. /**
  182. * Config name to display.
  183. * @type {String}
  184. */
  185. configLabel: function() {
  186. return this.get('config.stackConfigProperty.displayName') || this.get('config.displayName') || this.get('config.name');
  187. }.property('config.name', 'config.displayName'),
  188. /**
  189. * Error message computed in config property model
  190. * @type {String}
  191. */
  192. configErrorMessageBinding: 'config.errorMessage',
  193. /**
  194. * Determines if config-value was changed
  195. * @type {boolean}
  196. */
  197. valueIsChanged: function () {
  198. return !Em.isNone(this.get('config.savedValue')) && this.get('config.value') != this.get('config.savedValue');
  199. }.property('config.value', 'config.savedValue'),
  200. /**
  201. * Enable/disable widget state
  202. * @method toggleWidgetState
  203. */
  204. toggleWidgetState: function () {
  205. this.set('disabled', !this.get('config.isEditable'));
  206. }.observes('config.isEditable'),
  207. /**
  208. * Reset config-value to its default
  209. * @method restoreValue
  210. */
  211. restoreValue: function () {
  212. var self = this;
  213. this.set('config.value', this.get('config.savedValue'));
  214. this.sendRequestRorDependentConfigs(this.get('config')).done(function() {
  215. self.restoreDependentConfigs(self.get('config'));
  216. });
  217. if (this.get('config.supportsFinal')) {
  218. this.get('config').set('isFinal', this.get('config.savedIsFinal'));
  219. }
  220. Em.$('body > .tooltip').remove();
  221. },
  222. /**
  223. * set <code>recommendedValue<code> to config
  224. * and send request to change dependent configs
  225. * @method setRecommendedValue
  226. */
  227. setRecommendedValue: function() {
  228. var self = this;
  229. this.set('config.value', this.get('config.recommendedValue'));
  230. this.sendRequestRorDependentConfigs(this.get('config')).done(function() {
  231. if (self.get('config.value') === self.get('config.savedValue')) {
  232. self.restoreDependentConfigs(self.get('config'));
  233. }
  234. });
  235. if (this.get('config.supportsFinal')) {
  236. this.get('config').set('isFinal', this.get('config.recommendedIsFinal'));
  237. }
  238. Em.$('body > .tooltip').remove();
  239. },
  240. /**
  241. * Determines if override is allowed for <code>config</code>
  242. * @type {boolean}
  243. */
  244. overrideAllowed: function () {
  245. var config = this.get('config');
  246. if (!config) return false;
  247. return config.get('isOriginalSCP') && config.get('isPropertyOverridable') && !this.get('config.isComparison');
  248. }.property('config.isOriginalSCP', 'config.isPropertyOverridable', 'config.isComparison'),
  249. /**
  250. * Determines if undo is allowed for <code>config</code>
  251. * @type {boolean}
  252. */
  253. undoAllowed: function () {
  254. var config = this.get('config');
  255. if (!config) return false;
  256. if (!this.get('isOriginalSCP') || this.get('disabled')) return false;
  257. return !config.get('cantBeUndone') && config.get('isNotDefaultValue');
  258. }.property('config.cantBeUndone', 'config.isNotDefaultValue', 'isOriginalSCP', 'disabled'),
  259. /**
  260. * Determines if "final"-button should be shown
  261. * @type {boolean}
  262. */
  263. showFinalConfig: function () {
  264. var config = this.get('config');
  265. return config.get('isFinal') || (!config.get('isNotEditable') && this.get('isHover'));
  266. }.property('config.isFinal', 'config.isNotEditable', 'isHover'),
  267. /**
  268. *
  269. * @param {{context: App.ServiceConfigProperty}} event
  270. * @method toggleFinalFlag
  271. */
  272. toggleFinalFlag: function (event) {
  273. var configProperty = event.context;
  274. if (configProperty.get('isNotEditable')) {
  275. return;
  276. }
  277. configProperty.toggleProperty('isFinal');
  278. },
  279. /**
  280. * sync widget value with config value when dependent properties
  281. * have been loaded or changed
  282. * @method syncValueWithConfig
  283. */
  284. syncValueWithConfig: function() {
  285. this.setValue(this.get('config.value'));
  286. }.observes('controller.recommendationTimeStamp'),
  287. didInsertElement: function () {
  288. App.tooltip($(this.get('element')).find('span'));
  289. var self = this;
  290. var element = this.$();
  291. if (element) {
  292. element.hover(function() {
  293. self.set('isHover', true);
  294. }, function() {
  295. self.set('isHover', false);
  296. });
  297. }
  298. this.initIncompatibleWidgetAsTextBox();
  299. },
  300. /**
  301. * set widget value same as config value
  302. * useful for widgets that work with intermediate config value, not original
  303. * for now used in slider widget
  304. * @abstract
  305. */
  306. setValue: Em.K,
  307. /**
  308. * Config group bound property. Needed for correct render process in template.
  309. *
  310. * @returns {App.ConfigGroup|Boolean}
  311. */
  312. configGroup: function() {
  313. return !this.get('config.group') || this.get('config.group.isDefault') ? false : this.get('config.group');
  314. }.property('config.group.name'),
  315. /**
  316. * switcher to display config as widget or text field
  317. * @method toggleWidgetView
  318. */
  319. toggleWidgetView: function() {
  320. if (!this.get('isWidgetViewAllowed')) {
  321. return false;
  322. }
  323. if (this.get('config.showAsTextBox')) {
  324. this.textBoxToWidget();
  325. } else {
  326. this.widgetToTextBox();
  327. }
  328. },
  329. /**
  330. * switch display of config to text field
  331. * @method widgetToTextBox
  332. */
  333. widgetToTextBox: function() {
  334. this.set("config.showAsTextBox", true);
  335. },
  336. /**
  337. * switch display of config to widget
  338. * @method textBoxToWidget
  339. */
  340. textBoxToWidget: function() {
  341. if (this.isValueCompatibleWithWidget()) {
  342. this.setValue(this.get('config.value'));
  343. this.set("config.showAsTextBox", false);
  344. }
  345. },
  346. /**
  347. * check if config value can be converted to config widget value
  348. * IMPORTANT! Each config-widget that override this method should use <code>updateWarningsForCompatibilityWithWidget</code>
  349. * @returns {boolean}
  350. */
  351. isValueCompatibleWithWidget: function() {
  352. return (this.get('isOverrideEqualityError') && !this.get('config.isValid')) || this.get('config.isValid');
  353. },
  354. /**
  355. * Initialize widget with incompatible value as textbox
  356. */
  357. initIncompatibleWidgetAsTextBox : function() {
  358. if (!this.isValueCompatibleWithWidget()) {
  359. this.get('config').set('showAsTextBox', true);
  360. }
  361. },
  362. /**
  363. * Returns <code>true</code> if raw value can be used by widget or widget view is activated.
  364. * @returns {Boolean}
  365. */
  366. isWidgetViewAllowed: function() {
  367. if (!this.get('config.showAsTextBox')) {
  368. return true;
  369. }
  370. return this.isValueCompatibleWithWidget();
  371. }.property('config.value', 'config.isFinal', 'config.showAsTextBox'),
  372. /**
  373. * Used in <code>isValueCompatibleWithWidget</code>
  374. * Updates issue-parameters if config is in the raw-mode
  375. * @param {string} message empty string if value compatible with widget, error-message if value isn't compatible with widget
  376. * @method updateWarningsForCompatibilityWithWidget
  377. */
  378. updateWarningsForCompatibilityWithWidget: function (message) {
  379. this.setProperties({
  380. warnMessage: message,
  381. 'config.warnMessage': message,
  382. issueMessage: message,
  383. configLabelClass: message ? 'text-warning' : ''
  384. });
  385. }
  386. });