edit_dataset_controller.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  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. App.MainMirroringEditDataSetController = Ember.Controller.extend({
  19. name: 'mainMirroringEditDataSetController',
  20. /**
  21. * Defines to show Edit Dataset or Create New Dataset popup
  22. * @type {Boolean}
  23. */
  24. isEdit: false,
  25. /**
  26. * Contains Dataset id if <code>isEdit</code> is true
  27. * @type {Boolean}
  28. */
  29. datasetIdToEdit: null,
  30. /**
  31. * Fields values from Edit DataSet form
  32. * @type {Object}
  33. */
  34. formFields: Ember.Object.create({
  35. datasetName: null,
  36. datasetTargetClusterName: null,
  37. datasetSourceDir: null,
  38. datasetTargetDir: null,
  39. datasetStartDate: null,
  40. hoursForStart: null,
  41. minutesForStart: null,
  42. middayPeriodForStart: null,
  43. datasetEndDate: null,
  44. hoursForEnd: null,
  45. minutesForEnd: null,
  46. middayPeriodForEnd: null,
  47. datasetFrequency: null,
  48. repeatOptionSelected: null
  49. }),
  50. /**
  51. * Messages for errors occurred during Edit DataSet form validation
  52. * @type {Object}
  53. */
  54. errorMessages: Ember.Object.create({
  55. name: '',
  56. sourceDir: '',
  57. targetDir: '',
  58. startDate: '',
  59. endDate: '',
  60. frequency: '',
  61. targetClusterName: ''
  62. }),
  63. /**
  64. * Flags with errors related to each field in Edit/Create Dataset form
  65. * @type {Object}
  66. */
  67. errors: Ember.Object.create({
  68. isNameError: false,
  69. isSourceDirError: false,
  70. isTargetDirError: false,
  71. isStartDateError: false,
  72. isEndDateError: false,
  73. isFrequencyError: false,
  74. isTargetClusterNameError: false
  75. }),
  76. /**
  77. * Clear all fields in Edit/Create Dataset form and clears all errors
  78. */
  79. clearStep: function () {
  80. var formFields = this.get('formFields');
  81. Em.keys(formFields).forEach(function (key) {
  82. formFields.set(key, null);
  83. }, this);
  84. this.clearErrors();
  85. },
  86. /**
  87. * Clear all error flags and messages
  88. */
  89. clearErrors: function () {
  90. var errorMessages = this.get('errorMessages');
  91. Em.keys(errorMessages).forEach(function (key) {
  92. errorMessages.set(key, '');
  93. }, this);
  94. var errors = this.get('errors');
  95. Em.keys(errors).forEach(function (key) {
  96. errors.set(key, false);
  97. }, this);
  98. },
  99. /**
  100. * Show Create New Dataset popup
  101. * @return {Object} popup view
  102. */
  103. showAddPopup: function () {
  104. var popup = this.showPopup(Em.I18n.t('mirroring.dataset.newDataset'));
  105. this.set('isEdit', false);
  106. return popup;
  107. },
  108. /**
  109. * Show Edit Dataset popup
  110. * @return {Object} popup view
  111. */
  112. showEditPopup: function (dataset) {
  113. this.set('datasetIdToEdit', dataset.get('id'));
  114. var popup = this.showPopup(Em.I18n.t('mirroring.dataset.editDataset'));
  115. this.set('isEdit', true);
  116. return popup;
  117. },
  118. /**
  119. * Show popup with Dataset form fields
  120. * @return {Object} popup view
  121. */
  122. showPopup: function (header) {
  123. var self = this;
  124. var popup = App.ModalPopup.show({
  125. classNames: ['sixty-percent-width-modal'],
  126. header: header,
  127. primary: Em.I18n.t('mirroring.dataset.save'),
  128. secondary: Em.I18n.t('common.cancel'),
  129. showCloseButton: false,
  130. isSaving: false,
  131. saveDisabled: function () {
  132. return self.get('saveDisabled');
  133. }.property('App.router.' + self.get('name') + '.saveDisabled'),
  134. disablePrimary: function () {
  135. return this.get('saveDisabled') || this.get('isSaving');
  136. }.property('saveDisabled', 'isSaving'),
  137. onPrimary: function () {
  138. // Apply form validation for first click
  139. if (!this.get('primaryWasClicked')) {
  140. this.toggleProperty('primaryWasClicked');
  141. self.applyValidation();
  142. if (this.get('saveDisabled')) {
  143. return false;
  144. }
  145. }
  146. self.save();
  147. App.router.transitionTo('main.mirroring.index');
  148. },
  149. primaryWasClicked: false,
  150. onSecondary: function () {
  151. this.hide();
  152. App.router.send('gotoShowJobs');
  153. },
  154. bodyClass: App.MainMirroringEditDataSetView.extend({
  155. controller: self
  156. })
  157. });
  158. this.set('popup', popup);
  159. return popup;
  160. },
  161. /**
  162. * Set observer to call validate method if any property from formFields will change
  163. */
  164. applyValidation: function () {
  165. Em.keys(this.get('formFields')).forEach(function (key) {
  166. this.addObserver('formFields.' + key, this, 'validate');
  167. }, this);
  168. this.validate();
  169. },
  170. /**
  171. * Return date object calculated from appropriate fields
  172. * @type {Date}
  173. */
  174. scheduleStartDate: function () {
  175. var startDate = this.get('formFields.datasetStartDate');
  176. var hoursForStart = this.get('formFields.hoursForStart');
  177. var minutesForStart = this.get('formFields.minutesForStart');
  178. var middayPeriodForStart = this.get('formFields.middayPeriodForStart');
  179. if (startDate && hoursForStart && minutesForStart && middayPeriodForStart) {
  180. return new Date(startDate + ' ' + hoursForStart + ':' + minutesForStart + ' ' + middayPeriodForStart);
  181. }
  182. return null;
  183. }.property('formFields.datasetStartDate', 'formFields.hoursForStart', 'formFields.minutesForStart', 'formFields.middayPeriodForStart'),
  184. /**
  185. * Return date object calculated from appropriate fields
  186. * @type {Date}
  187. */
  188. scheduleEndDate: function () {
  189. var endDate = this.get('formFields.datasetEndDate');
  190. var hoursForEnd = this.get('formFields.hoursForEnd');
  191. var minutesForEnd = this.get('formFields.minutesForEnd');
  192. var middayPeriodForEnd = this.get('formFields.middayPeriodForEnd');
  193. if (endDate && hoursForEnd && minutesForEnd && middayPeriodForEnd) {
  194. return new Date(endDate + ' ' + hoursForEnd + ':' + minutesForEnd + ' ' + middayPeriodForEnd);
  195. }
  196. return null;
  197. }.property('formFields.datasetEndDate', 'formFields.hoursForEnd', 'formFields.minutesForEnd', 'formFields.middayPeriodForEnd'),
  198. /**
  199. * Validation for every field in Edit DataSet form
  200. */
  201. validate: function () {
  202. var formFields = this.get('formFields');
  203. var errors = this.get('errors');
  204. var errorMessages = this.get('errorMessages');
  205. this.clearErrors();
  206. // Check if feild is empty
  207. Em.keys(errorMessages).forEach(function (key) {
  208. if (!formFields.get('dataset' + key.capitalize())) {
  209. errors.set('is' + key.capitalize() + 'Error', true);
  210. errorMessages.set(key, Em.I18n.t('mirroring.required.error'));
  211. }
  212. }, this);
  213. // Check that endDate is after startDate
  214. var scheduleStartDate = this.get('scheduleStartDate');
  215. var scheduleEndDate = this.get('scheduleEndDate');
  216. if (scheduleStartDate && scheduleEndDate && (scheduleStartDate > scheduleEndDate)) {
  217. errors.set('isEndDateError', true);
  218. errorMessages.set('endDate', Em.I18n.t('mirroring.dateOrder.error'));
  219. }
  220. // Check that startDate is after current date
  221. if (scheduleStartDate && !this.get('isEdit') && new Date(App.dateTime()) > scheduleStartDate) {
  222. errors.set('isStartDateError', true);
  223. errorMessages.set('startDate', Em.I18n.t('mirroring.startDate.error'));
  224. }
  225. // Check that repeat field value consists only from digits
  226. if (isNaN(this.get('formFields.datasetFrequency'))) {
  227. errors.set('isFrequencyError', true);
  228. errorMessages.set('frequency', Em.I18n.t('mirroring.required.invalidNumberError'));
  229. }
  230. },
  231. /**
  232. * Add '0' for numbers less than 10
  233. * @param {Number|String} number
  234. * @return {String}
  235. */
  236. addZero: function (number) {
  237. return ('0' + number).slice(-2);
  238. },
  239. /**
  240. * Convert date to TZ format
  241. * @param {Date} date
  242. * @return {String}
  243. */
  244. toTZFormat: function (date) {
  245. return date.toISOString().replace(/\:\d{2}\.\d{3}/,'');
  246. },
  247. /**
  248. * Converts hours value from 24-hours format to AM/PM format
  249. * @param {Number|String} hours
  250. * @return {String}
  251. */
  252. toAMPMHours: function (hours) {
  253. var result = hours % 12;
  254. result = result ? result : 12;
  255. return this.addZero(result);
  256. },
  257. /**
  258. * Save data from dataset form to server
  259. */
  260. save: function () {
  261. this.set('popup.isSaving', true);
  262. var datasetXML = this.createDatasetXML();
  263. this.sendDatasetToServer(datasetXML);
  264. },
  265. /**
  266. * Compose XML-object from populated dataset form fields
  267. * @return {String}
  268. */
  269. createDatasetXML: function () {
  270. var datasetNamePrefix = App.mirroringDatasetNamePrefix;
  271. var datasetName = this.get('formFields.datasetName');
  272. var prefixedDatasetName = datasetNamePrefix + datasetName;
  273. var sourceCluster = App.get('clusterName');
  274. var targetCluster = this.get('formFields.datasetTargetClusterName');
  275. var sourceDir = this.get('formFields.datasetSourceDir');
  276. var targetDir = this.get('formFields.datasetTargetDir');
  277. var datasetFrequency = this.get('formFields.datasetFrequency');
  278. var repeatOptionSelected = this.get('formFields.repeatOptionSelected');
  279. var startDate = this.get('scheduleStartDate');
  280. var endDate = this.get('scheduleEndDate');
  281. var scheduleStartDateFormatted = this.toTZFormat(startDate);
  282. var scheduleEndDateFormatted = this.toTZFormat(endDate);
  283. return '<?xml version="1.0"?><feed description="" name="' + prefixedDatasetName + '" xmlns="uri:falcon:feed:0.1"><frequency>' + repeatOptionSelected + '(' + datasetFrequency + ')' +
  284. '</frequency><clusters><cluster name="' + sourceCluster + '" type="source"><validity start="' + scheduleStartDateFormatted + '" end="' + scheduleEndDateFormatted +
  285. '"/><retention limit="days(7)" action="delete"/></cluster><cluster name="' + targetCluster + '" type="target"><validity start="' + scheduleStartDateFormatted + '" end="' + scheduleEndDateFormatted +
  286. '"/><retention limit="months(1)" action="delete"/><locations><location type="data" path="' + targetDir + '" /></locations></cluster></clusters><locations><location type="data" path="' +
  287. sourceDir + '" /></locations><ACL owner="hue" group="users" permission="0755" /><schema location="/none" provider="none"/></feed>';
  288. },
  289. /**
  290. * Send dataset XML-data to server
  291. * @param {String} datasetXML
  292. */
  293. sendDatasetToServer: function (datasetXML) {
  294. var datasetNamePrefix = App.mirroringDatasetNamePrefix;
  295. var datasetName = this.get('formFields.datasetName');
  296. var prefixedDatasetName = datasetNamePrefix + datasetName;
  297. return App.ajax.send({
  298. name: this.get('isEdit') ? 'mirroring.update_entity' : 'mirroring.create_new_dataset',
  299. sender: this,
  300. data: {
  301. name: prefixedDatasetName,
  302. type: 'feed',
  303. entity: datasetXML,
  304. falconServer: App.get('falconServerURL')
  305. },
  306. success: 'onSaveSuccess',
  307. error: 'onSaveError'
  308. });
  309. },
  310. /**
  311. * Callback for success saving XML-data on server
  312. */
  313. onSaveSuccess: function () {
  314. this.set('popup.isSaving', false);
  315. this.get('popup').hide();
  316. App.router.get('mainMirroringController').loadData();
  317. },
  318. /**
  319. * Callback for error while saving XML-data on server
  320. */
  321. onSaveError: function (response) {
  322. this.set('popup.isSaving', false);
  323. if (response && response.responseText) {
  324. var errorMessage = /(?:\<message\>)((.|\n)+)(?:\<\/message\>)/.exec(response.responseText);
  325. if (errorMessage.length > 1) {
  326. App.showAlertPopup(Em.I18n.t('common.error'), Em.I18n.t('mirroring.manageClusters.error') + ': ' + errorMessage[1]);
  327. }
  328. }
  329. },
  330. /**
  331. * Defines if save button should be disabled
  332. * @type {Boolean}
  333. */
  334. saveDisabled: function () {
  335. var errors = this.get('errors');
  336. return errors.get('isNameError') || errors.get('isSourceDirError') || errors.get('isTargetDirError') || errors.get('isStartDateError') || errors.get('isEndDateError') || errors.get('isFrequencyError') || errors.get('isTargetClusterNameError');
  337. }.property('errors.isNameError', 'errors.isSourceDirError', 'errors.isTargetDirError', 'errors.isStartDateError', 'errors.isEndDateError', 'errors.isFrequencyError', 'errors.isTargetClusterNameError')
  338. });