controls_view.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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. * Abstract view for config fields.
  21. * Add popover support to control
  22. */
  23. App.ServiceConfigPopoverSupport = Ember.Mixin.create({
  24. /**
  25. * Config object. It will instance of App.ServiceConfigProperty
  26. */
  27. serviceConfig: null,
  28. placeholderBinding: 'serviceConfig.defaultValue',
  29. isPopoverEnabled: true,
  30. didInsertElement: function () {
  31. if (this.get('isPopoverEnabled') !== 'false') {
  32. App.popover(this.$(), {
  33. title: Em.I18n.t('installer.controls.serviceConfigPopover.title').format(
  34. this.get('serviceConfig.displayName'),
  35. (this.get('serviceConfig.displayName') == this.get('serviceConfig.name')) ? '' : this.get('serviceConfig.name')
  36. ),
  37. content: this.get('serviceConfig.description'),
  38. placement: 'right',
  39. trigger: 'hover'
  40. });
  41. }
  42. }
  43. });
  44. /**
  45. * Default input control
  46. * @type {*}
  47. */
  48. App.ServiceConfigTextField = Ember.TextField.extend(App.ServiceConfigPopoverSupport, {
  49. valueBinding: 'serviceConfig.value',
  50. classNameBindings: 'textFieldClassName',
  51. placeholderBinding: 'serviceConfig.defaultValue',
  52. keyPress: function (event) {
  53. if (event.keyCode == 13) {
  54. return false;
  55. }
  56. },
  57. //Set editDone true for last edited config text field parameter
  58. focusOut: function (event) {
  59. this.get('serviceConfig').set("editDone", true);
  60. },
  61. //Set editDone false for all current category config text field parameter
  62. focusIn: function (event) {
  63. if (!this.get('serviceConfig.selectedHostOptions')) {
  64. this.get("parentView.categoryConfigsAll").setEach("editDone", false);
  65. }
  66. },
  67. textFieldClassName: function () {
  68. if (this.get('serviceConfig.unit')) {
  69. return ['input-small'];
  70. } else if (this.get('serviceConfig.displayType') === 'principal') {
  71. return ['span12'];
  72. } else {
  73. return ['span9'];
  74. }
  75. }.property('serviceConfig.displayType', 'serviceConfig.unit'),
  76. disabled: function () {
  77. return !this.get('serviceConfig.isEditable');
  78. }.property('serviceConfig.isEditable')
  79. });
  80. /**
  81. * Customized input control with Utits type specified
  82. * @type {*}
  83. */
  84. App.ServiceConfigTextFieldWithUnit = Ember.View.extend(App.ServiceConfigPopoverSupport, {
  85. valueBinding: 'serviceConfig.value',
  86. classNames: ['input-append', 'with-unit'],
  87. placeholderBinding: 'serviceConfig.defaultValue',
  88. template: Ember.Handlebars.compile('{{view App.ServiceConfigTextField serviceConfigBinding="view.serviceConfig" isPopoverEnabled="false"}}<span class="add-on">{{view.serviceConfig.unit}}</span>'),
  89. disabled: function () {
  90. return !this.get('serviceConfig.isEditable');
  91. }.property('serviceConfig.isEditable')
  92. });
  93. /**
  94. * Password control
  95. * @type {*}
  96. */
  97. App.ServiceConfigPasswordField = Ember.TextField.extend({
  98. serviceConfig: null,
  99. type: 'password',
  100. valueBinding: 'serviceConfig.value',
  101. classNames: [ 'span4' ],
  102. placeholder: Em.I18n.t('form.item.placeholders.typePassword'),
  103. template: Ember.Handlebars.compile('{{view view.retypePasswordView}}'),
  104. keyPress: function (event) {
  105. if (event.keyCode == 13) {
  106. return false;
  107. }
  108. },
  109. retypePasswordView: Ember.TextField.extend({
  110. placeholder: Em.I18n.t('form.passwordRetype'),
  111. type: 'password',
  112. classNames: [ 'span4', 'retyped-password' ],
  113. keyPress: function (event) {
  114. if (event.keyCode == 13) {
  115. return false;
  116. }
  117. },
  118. valueBinding: 'parentView.serviceConfig.retypedPassword',
  119. disabled: function () {
  120. return !this.get('parentView.serviceConfig.isEditable');
  121. }.property('parentView.serviceConfig.isEditable')
  122. }),
  123. disabled: function () {
  124. return !this.get('serviceConfig.isEditable');
  125. }.property('serviceConfig.isEditable')
  126. });
  127. /**
  128. * Textarea control
  129. * @type {*}
  130. */
  131. App.ServiceConfigTextArea = Ember.TextArea.extend(App.ServiceConfigPopoverSupport, {
  132. valueBinding: 'serviceConfig.value',
  133. rows: 4,
  134. classNames: ['span9', 'directories'],
  135. placeholderBinding: 'serviceConfig.defaultValue',
  136. disabled: function () {
  137. return !this.get('serviceConfig.isEditable');
  138. }.property('serviceConfig.isEditable')
  139. });
  140. /**
  141. * Textarea control with bigger height
  142. * @type {*}
  143. */
  144. App.ServiceConfigBigTextArea = App.ServiceConfigTextArea.extend({
  145. rows: 10
  146. });
  147. /**
  148. * Checkbox control
  149. * @type {*}
  150. */
  151. App.ServiceConfigCheckbox = Ember.Checkbox.extend(App.ServiceConfigPopoverSupport, {
  152. checkedBinding: 'serviceConfig.value',
  153. disabled: function () {
  154. return !this.get('serviceConfig.isEditable');
  155. }.property('serviceConfig.isEditable')
  156. });
  157. App.ServiceConfigRadioButtons = Ember.View.extend({
  158. template: Ember.Handlebars.compile([
  159. '{{#each option in view.options}}',
  160. '{{#unless option.hidden}}',
  161. '<label class="radio">',
  162. '{{#view App.ServiceConfigRadioButton nameBinding = "view.name" valueBinding = "option.displayName"}}',
  163. '{{/view}}',
  164. '{{option.displayName}} &nbsp;',
  165. '</label>',
  166. '{{/unless}}',
  167. '{{/each}}'
  168. ].join('\n')),
  169. didInsertElement: function () {
  170. // on page render, automatically populate JDBC URLs only for default database settings
  171. // so as to not lose the user's customizations on these fields
  172. if (['addServiceController', 'installerController'].contains(App.clusterStatus.wizardControllerName) && ['New MySQL Database', 'New Derby Database'].contains(this.get('serviceConfig.value'))) {
  173. this.onOptionsChange();
  174. }
  175. },
  176. configs: function () {
  177. return this.get('categoryConfigsAll').filterProperty('isObserved', true);
  178. }.property('categoryConfigsAll'),
  179. serviceConfig: null,
  180. categoryConfigsAll: null,
  181. onOptionsChange: function () {
  182. // The following if condition will be satisfied only for installer wizard flow
  183. if (this.get('configs').length) {
  184. var connectionUrl = this.get('connectionUrl');
  185. if (connectionUrl) {
  186. if (this.get('serviceConfig.serviceName') === 'HIVE') {
  187. switch (this.get('serviceConfig.value')) {
  188. case 'New MySQL Database':
  189. case 'Existing MySQL Database':
  190. connectionUrl.set('value', "jdbc:mysql://" + this.get('hostName') + "/" + this.get('databaseName') + "?createDatabaseIfNotExist=true");
  191. break;
  192. case 'Existing Oracle Database':
  193. connectionUrl.set('value', "jdbc:oracle:thin:@//" + this.get('hostName') + ":1521/" + this.get('databaseName'));
  194. break;
  195. }
  196. } else if (this.get('serviceConfig.serviceName') === 'OOZIE') {
  197. switch (this.get('serviceConfig.value')) {
  198. case 'New Derby Database':
  199. connectionUrl.set('value', "jdbc:derby:${oozie.data.dir}/${oozie.db.schema.name}-db;create=true");
  200. break;
  201. case 'Existing MySQL Database':
  202. connectionUrl.set('value', "jdbc:mysql://" + this.get('hostName') + "/" + this.get('databaseName'));
  203. break;
  204. case 'Existing Oracle Database':
  205. connectionUrl.set('value', "jdbc:oracle:thin:@//" + this.get('hostName') + ":1521/" + this.get('databaseName'));
  206. break;
  207. }
  208. }
  209. connectionUrl.set('defaultValue', connectionUrl.get('value'));
  210. }
  211. }
  212. }.observes('databaseName', 'hostName', 'connectionUrl'),
  213. nameBinding: 'serviceConfig.radioName',
  214. databaseName: function () {
  215. switch (this.get('serviceConfig.serviceName')) {
  216. case 'HIVE':
  217. return this.get('categoryConfigsAll').findProperty('name', 'hive_database_name').get('value');
  218. case 'OOZIE':
  219. return this.get('categoryConfigsAll').findProperty('name', 'oozie.db.schema.name').get('value');
  220. default:
  221. return null;
  222. }
  223. }.property('configs.@each.value', 'serviceConfig.serviceName'),
  224. hostName: function () {
  225. var value = this.get('serviceConfig.value');
  226. var returnValue;
  227. var hostname;
  228. if (this.get('serviceConfig.serviceName') === 'HIVE') {
  229. switch (value) {
  230. case 'New MySQL Database':
  231. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_ambari_host');
  232. break;
  233. case 'Existing MySQL Database':
  234. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_mysql_host');
  235. break;
  236. case 'Existing Oracle Database':
  237. hostname = this.get('categoryConfigsAll').findProperty('name', 'hive_existing_oracle_host');
  238. break;
  239. }
  240. if (hostname) {
  241. returnValue = hostname.get('value');
  242. } else {
  243. returnValue = this.get('categoryConfigsAll').findProperty('name', 'hive_hostname').get('value');
  244. }
  245. } else if (this.get('serviceConfig.serviceName') === 'OOZIE') {
  246. switch (value) {
  247. case 'New Derby Database':
  248. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_ambari_host');
  249. break;
  250. case 'Existing MySQL Database':
  251. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_mysql_host');
  252. break;
  253. case 'Existing Oracle Database':
  254. hostname = this.get('categoryConfigsAll').findProperty('name', 'oozie_existing_oracle_host');
  255. break;
  256. }
  257. if (hostname) {
  258. returnValue = hostname.get('value');
  259. } else {
  260. returnValue = this.get('categoryConfigsAll').findProperty('name', 'oozie_hostname').get('value');
  261. }
  262. }
  263. return returnValue;
  264. }.property('serviceConfig.serviceName', 'serviceConfig.value', 'configs.@each.value'),
  265. connectionUrl: function () {
  266. if (this.get('serviceConfig.serviceName') === 'HIVE') {
  267. return this.get('categoryConfigsAll').findProperty('name', 'javax.jdo.option.ConnectionURL');
  268. } else {
  269. return this.get('categoryConfigsAll').findProperty('name', 'oozie.service.JPAService.jdbc.url');
  270. }
  271. }.property('serviceConfig.serviceName'),
  272. optionsBinding: 'serviceConfig.options',
  273. disabled: function () {
  274. return !this.get('serviceConfig.isEditable');
  275. }.property('serviceConfig.isEditable')
  276. });
  277. App.ServiceConfigRadioButton = Ember.Checkbox.extend({
  278. tagName: 'input',
  279. attributeBindings: ['type', 'name', 'value', 'checked'],
  280. checked: false,
  281. type: 'radio',
  282. name: null,
  283. value: null,
  284. didInsertElement: function () {
  285. if (this.get('parentView.serviceConfig.value') === this.get('value')) {
  286. this.set('checked', true);
  287. }
  288. },
  289. click: function () {
  290. this.set('checked', true);
  291. this.onChecked();
  292. },
  293. onChecked: function () {
  294. this.set('parentView.serviceConfig.value', this.get('value'));
  295. var components = this.get('parentView.serviceConfig.options');
  296. components
  297. .forEach(function (_component) {
  298. if (_component.foreignKeys) {
  299. _component.foreignKeys.forEach(function (_componentName) {
  300. if (this.get('parentView.categoryConfigsAll').someProperty('name', _componentName)) {
  301. var component = this.get('parentView.categoryConfigsAll').findProperty('name', _componentName);
  302. if (_component.displayName === this.get('value')) {
  303. component.set('isVisible', true);
  304. } else {
  305. component.set('isVisible', false);
  306. }
  307. }
  308. }, this);
  309. }
  310. }, this);
  311. }.observes('checked'),
  312. disabled: function () {
  313. return !this.get('parentView.serviceConfig.isEditable');
  314. }.property('parentView.serviceConfig.isEditable')
  315. });
  316. App.ServiceConfigComboBox = Ember.Select.extend(App.ServiceConfigPopoverSupport, {
  317. contentBinding: 'serviceConfig.options',
  318. selectionBinding: 'serviceConfig.value',
  319. classNames: [ 'span3' ],
  320. disabled: function () {
  321. return !this.get('serviceConfig.isEditable');
  322. }.property('serviceConfig.isEditable')
  323. });
  324. /**
  325. * Base component for host config with popover support
  326. */
  327. App.ServiceConfigHostPopoverSupport = Ember.Mixin.create({
  328. /**
  329. * Config object. It will instance of App.ServiceConfigProperty
  330. */
  331. serviceConfig: null,
  332. didInsertElement: function () {
  333. App.popover(this.$(), {
  334. title: this.get('serviceConfig.displayName'),
  335. content: this.get('serviceConfig.description'),
  336. placement: 'right',
  337. trigger: 'hover'
  338. });
  339. }
  340. });
  341. /**
  342. * Master host component.
  343. * Show hostname without ability to edit it
  344. * @type {*}
  345. */
  346. App.ServiceConfigMasterHostView = Ember.View.extend(App.ServiceConfigHostPopoverSupport, {
  347. classNames: ['master-host', 'span6'],
  348. valueBinding: 'serviceConfig.value',
  349. template: Ember.Handlebars.compile('{{value}}')
  350. });
  351. /**
  352. * Base component to display Multiple hosts
  353. * @type {*}
  354. */
  355. App.ServiceConfigMultipleHostsDisplay = Ember.Mixin.create(App.ServiceConfigHostPopoverSupport, {
  356. hasNoHosts: function () {
  357. console.log('view', this.get('viewName')); //to know which View cause errors
  358. console.log('controller', this.get('controller').name); //should be slaveComponentGroupsController
  359. if (!this.get('value')) {
  360. return true;
  361. }
  362. return this.get('value').length === 0;
  363. }.property('value'),
  364. hasOneHost: function () {
  365. return this.get('value').length === 1;
  366. }.property('value'),
  367. hasMultipleHosts: function () {
  368. return this.get('value').length > 1;
  369. }.property('value'),
  370. otherLength: function () {
  371. var len = this.get('value').length;
  372. if (len > 2) {
  373. return Em.I18n.t('installer.controls.serviceConfigMultipleHosts.others').format(len - 1);
  374. } else {
  375. return Em.I18n.t('installer.controls.serviceConfigMultipleHosts.other');
  376. }
  377. }.property('value')
  378. })
  379. /**
  380. * Multiple master host component.
  381. * Show hostnames without ability to edit it
  382. * @type {*}
  383. */
  384. App.ServiceConfigMasterHostsView = Ember.View.extend(App.ServiceConfigMultipleHostsDisplay, {
  385. viewName: "serviceConfigMasterHostsView",
  386. valueBinding: 'serviceConfig.value',
  387. classNames: ['master-hosts', 'span6'],
  388. templateName: require('templates/wizard/master_hosts'),
  389. /**
  390. * Onclick handler for link
  391. */
  392. showHosts: function () {
  393. var serviceConfig = this.get('serviceConfig');
  394. App.ModalPopup.show({
  395. header: Em.I18n.t('installer.controls.serviceConfigMasterHosts.header').format(serviceConfig.category),
  396. bodyClass: Ember.View.extend({
  397. serviceConfig: serviceConfig,
  398. templateName: require('templates/wizard/master_hosts_popup')
  399. }),
  400. onPrimary: function () {
  401. this.hide();
  402. },
  403. secondary: null
  404. });
  405. }
  406. });
  407. /**
  408. * Show tabs list for slave hosts
  409. * @type {*}
  410. */
  411. App.SlaveComponentGroupsMenu = Em.CollectionView.extend({
  412. content: function () {
  413. return this.get('controller.componentGroups');
  414. }.property('controller.componentGroups'),
  415. tagName: 'ul',
  416. classNames: ["nav", "nav-tabs"],
  417. itemViewClass: Em.View.extend({
  418. classNameBindings: ["active"],
  419. active: function () {
  420. return this.get('content.active');
  421. }.property('content.active'),
  422. errorCount: function () {
  423. return this.get('content.properties').filterProperty('isValid', false).filterProperty('isVisible', true).get('length');
  424. }.property('content.properties.@each.isValid', 'content.properties.@each.isVisible'),
  425. template: Ember.Handlebars.compile('<a {{action showSlaveComponentGroup view.content target="controller"}} href="#"> {{view.content.name}}{{#if view.errorCount}}<span class="badge badge-important">{{view.errorCount}}</span>{{/if}}</a><i {{action removeSlaveComponentGroup view.content target="controller"}} class="icon-remove"></i>')
  426. })
  427. });
  428. /**
  429. * <code>Add group</code> button
  430. * @type {*}
  431. */
  432. App.AddSlaveComponentGroupButton = Ember.View.extend({
  433. tagName: 'span',
  434. slaveComponentName: null,
  435. didInsertElement: function () {
  436. App.popover(this.$(), {
  437. title: Em.I18n.t('installer.controls.addSlaveComponentGroupButton.title').format(this.get('slaveComponentName')),
  438. content: Em.I18n.t('installer.controls.addSlaveComponentGroupButton.content').format(this.get('slaveComponentName'), this.get('slaveComponentName'), this.get('slaveComponentName')),
  439. placement: 'right',
  440. trigger: 'hover'
  441. });
  442. }
  443. });
  444. /**
  445. * Multiple Slave Hosts component
  446. * @type {*}
  447. */
  448. App.ServiceConfigSlaveHostsView = Ember.View.extend(App.ServiceConfigMultipleHostsDisplay, {
  449. viewName: 'serviceConfigSlaveHostsView',
  450. classNames: ['slave-hosts', 'span6'],
  451. valueBinding: 'serviceConfig.value',
  452. templateName: require('templates/wizard/slave_hosts'),
  453. /**
  454. * Onclick handler for link
  455. */
  456. showHosts: function () {
  457. var serviceConfig = this.get('serviceConfig');
  458. App.ModalPopup.show({
  459. header: Em.I18n.t('installer.controls.serviceConfigMasterHosts.header').format(serviceConfig.category),
  460. bodyClass: Ember.View.extend({
  461. serviceConfig: serviceConfig,
  462. templateName: require('templates/wizard/master_hosts_popup')
  463. }),
  464. onPrimary: function () {
  465. this.hide();
  466. },
  467. secondary: null
  468. });
  469. }
  470. });
  471. /**
  472. * properties for present active slave group
  473. * @type {*}
  474. */
  475. App.SlaveGroupPropertiesView = Ember.View.extend({
  476. viewName: 'serviceConfigSlaveHostsView',
  477. group: function () {
  478. return this.get('controller.activeGroup');
  479. }.property('controller.activeGroup'),
  480. groupConfigs: function () {
  481. console.log("************************************************************************");
  482. console.log("The value of group is: " + this.get('group'));
  483. console.log("************************************************************************");
  484. return this.get('group.properties');
  485. }.property('group.properties.@each').cacheable(),
  486. errorCount: function () {
  487. return this.get('group.properties').filterProperty('isValid', false).filterProperty('isVisible', true).get('length');
  488. }.property('configs.@each.isValid', 'configs.@each.isVisible')
  489. });
  490. /**
  491. * DropDown component for <code>select hosts for groups</code> popup
  492. * @type {*}
  493. */
  494. App.SlaveComponentDropDownGroupView = Ember.View.extend({
  495. viewName: "slaveComponentDropDownGroupView",
  496. /**
  497. * On change handler for <code>select hosts for groups</code> popup
  498. * @param event
  499. */
  500. changeGroup: function (event) {
  501. var host = this.get('content');
  502. var groupName = $('#' + this.get('elementId') + ' select').val();
  503. this.get('controller').changeHostGroup(host, groupName);
  504. },
  505. optionTag: Ember.View.extend({
  506. /**
  507. * Whether current value(OptionTag value) equals to host value(assigned to SlaveComponentDropDownGroupView.content)
  508. */
  509. selected: function () {
  510. return this.get('parentView.content.group') === this.get('content');
  511. }.property('content')
  512. })
  513. });
  514. /**
  515. * Show info about current group
  516. * @type {*}
  517. */
  518. App.SlaveComponentChangeGroupNameView = Ember.View.extend({
  519. contentBinding: 'controller.activeGroup',
  520. classNames: ['control-group'],
  521. classNameBindings: 'error',
  522. error: false,
  523. setError: function () {
  524. this.set('error', false);
  525. }.observes('controller.activeGroup'),
  526. errorMessage: function () {
  527. return this.get('error') ? Em.I18n.t('installer.controls.slaveComponentChangeGroupName.error') : '';
  528. }.property('error'),
  529. /**
  530. * Onclick handler for saving updated group name
  531. * @param event
  532. */
  533. changeGroupName: function (event) {
  534. var inputVal = $('#' + this.get('elementId') + ' input[type="text"]').val();
  535. if (inputVal !== this.get('content.name')) {
  536. var result = this.get('controller').changeSlaveGroupName(this.get('content'), inputVal);
  537. this.set('error', result);
  538. }
  539. }
  540. });