SchedulesView.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: SHARE
  5. *
  6. * (C) Copyright IBM Corp. 2015, 2020
  7. *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure
  9. * restricted by GSA ADP Schedule Contract with IBM Corp.
  10. */
  11. define([
  12. 'react',
  13. 'react-dom',
  14. 'ba-react-admin/ba-react-admin.min',
  15. 'bi/commons/ui/View',
  16. 'jquery',
  17. 'bi/sharecommon/utils/translator',
  18. 'q',
  19. 'underscore',
  20. 'bi/sharecommon/utils/simpledoT',
  21. 'bi/commons/utils/Utils',
  22. 'text!bi/schedule/templates/SchedulesView.html',
  23. 'bi/schedule/utils/CadenceLabelGenerator',
  24. 'bi/commons/ui/properties/ToggleButton',
  25. 'bi/schedule/app/appControler',
  26. 'text!bi/notifications/templates/emptyMessageList.html',
  27. 'bi/commons/ui/dialogs/ConfirmationDialog'
  28. ],
  29. function (React, ReactDOM, AdminReact, View, $, t, Q, _, dot, Utils, template, cadence, ToggleButton, controller, emptySchTemplate, ConfirmationDialog) {
  30. 'use strict';
  31. var schedulesView = View.extend({
  32. schedule: {},
  33. /**
  34. * @constructor
  35. */
  36. init: function (options) {
  37. schedulesView.inherited('init', this, arguments);
  38. // defaults
  39. this.stateToggler = null;
  40. this.hasPermission = {
  41. execute: true,
  42. read: true,
  43. setPolicy: true,
  44. traverse: true,
  45. write: true
  46. };
  47. $.extend(this, options);
  48. this.timezone = this.glassContext.services.userProfile.preferences.timeZoneID;
  49. this.productLocale = this.glassContext.services.userProfile.preferences.productLocale || 'en-us';
  50. if (typeof (this.objectInfo.descriptor) == 'undefined') {
  51. this.hasPermission = {
  52. execute: $.inArray('execute', this.objectInfo.permissions) != -1,
  53. read: $.inArray('read', this.objectInfo.permissions) != -1,
  54. setPolicy: $.inArray('setPolicy', this.objectInfo.permissions) != -1,
  55. traverse: $.inArray('traverse', this.objectInfo.permissions) != -1,
  56. write: $.inArray('write', this.objectInfo.permissions) != -1
  57. };
  58. }
  59. },
  60. /**
  61. * Render the schedule view within the flyout panel
  62. *
  63. */
  64. renderOld: function () {
  65. var deferred = Q.defer();
  66. this.updateScheduleList().then(function() {
  67. controller.getSchedule(this.objectInfo.id, this.glassContext).then(function (schedule) {
  68. if (!((this.glassContext.isDevInstall) && (this.glassContext.isDevInstall()))) {
  69. this.$el.append("<div class='newSchedPane'/>");
  70. var $newPane = this.$el.find('.newSchedPane');
  71. var scheduleDialog = React.createElement(AdminReact.SchedulesListView, { glassContext: this.glassContext, StringResource: t, runnable: this.objectInfo, shareAppController: controller, schedule: schedule, deleteFunction: this._deleteFunction.bind(this) });
  72. ReactDOM.render(scheduleDialog, $newPane[0]);
  73. }
  74. deferred.resolve(this);
  75. }.bind(this));
  76. }.bind(this));
  77. return deferred.promise;
  78. },
  79. renderNew: function () {
  80. var deferred = Q.defer();
  81. controller.getSchedule(this.objectInfo.id, this.glassContext).then(function (schedule) {
  82. this.$el.append("<div class='newSchedPane'/>");
  83. var $newPane = this.$el.find('.newSchedPane');
  84. var runnableObj = JSON.parse(JSON.stringify(this.objectInfo));
  85. var schedulesListView = React.createElement(AdminReact.SchedulesListView, { glassContext: this.glassContext, StringResource: t, runnable: runnableObj, shareAppController: controller, schedule: schedule, deleteRequest : controller.deleteSchedule });
  86. ReactDOM.render(schedulesListView, $newPane[0]);
  87. deferred.resolve(this);
  88. }.bind(this));
  89. if (this.slideout.contentView) {
  90. this.slideout.contentView.canHide = this._canHide.bind(this);
  91. }
  92. return deferred.promise;
  93. },
  94. _canHide: function() {
  95. return !AdminReact.ScheduleUIStore.isDialogOpen;
  96. },
  97. render: function() {
  98. if ((this.glassContext.isDevInstall) && (this.glassContext.isDevInstall())) {
  99. return this.renderOld();
  100. } else {
  101. return this.renderNew();
  102. }
  103. },
  104. _supportsFormats: function () {
  105. var objWithNoFormats = ['agentDefinition', 'agentDefinitionView', 'jobDefinition', 'jupyterNotebook'];
  106. return objWithNoFormats.indexOf(this.objectInfo.type) === -1;
  107. },
  108. /*update schedule list based on object Info*/
  109. updateScheduleList: function () {
  110. var deferred = Q.defer();
  111. var showCreate = true;
  112. var scheduleType = null;
  113. controller.getSchedule(this.objectInfo.id, this.glassContext).then(function (schedule) {
  114. var cadenceLabel = cadence.getLabelFor(schedule.scheduleInfo, this.timezone, this.productLocale);
  115. var outputFormats = [];
  116. var showFormats = this._supportsFormats();
  117. this.schedule = schedule;
  118. if (schedule && schedule.scheduleInfo) {
  119. // schedule exists, hide create button
  120. showCreate = false;
  121. scheduleType = t.translate(this._getScheduleType() + '_label');
  122. var numberOfFormats = (schedule.options && schedule.options.outputFormat) ? schedule.options.outputFormat.length : 0;
  123. for (var i = 0; i < numberOfFormats; i++) {
  124. var newFormat = { format: schedule.options.outputFormat[i] };
  125. switch (newFormat.format) {
  126. case 'HTML':
  127. newFormat['icon'] = 'html_icon';
  128. newFormat['displayName'] = t.translate('schedule_format_web');
  129. break;
  130. case 'PDF':
  131. newFormat['icon'] = 'pdf_icon';
  132. newFormat['displayName'] = t.translate('schedule_format_pdf');
  133. break;
  134. case 'spreadsheetML':
  135. newFormat['icon'] = 'excel_icon';
  136. newFormat['displayName'] = t.translate('schedule_format_xlsx');
  137. break;
  138. case 'xlsxData':
  139. newFormat['icon'] = 'excel_icon';
  140. newFormat['displayName'] = t.translate('schedule_format_xlsx_data');
  141. break;
  142. case 'XLWA':
  143. newFormat['icon'] = 'unsupportedformat_icon';
  144. newFormat['displayName'] = t.translate('schedule_format_unsupported');
  145. break;
  146. case 'CSV':
  147. newFormat['icon'] = 'csv_icon';
  148. newFormat['displayName'] = t.translate('schedule_format_csv');
  149. break;
  150. case 'XML':
  151. newFormat['icon'] = 'xml_icon';
  152. newFormat['displayName'] = t.translate('schedule_format_xml');
  153. break;
  154. case 'dataSet':
  155. newFormat['icon'] = 'dataset';
  156. newFormat['displayName'] = t.translate('schedule_format_dataset');
  157. break;
  158. default: // unknown, skip
  159. continue;
  160. }
  161. outputFormats.push(newFormat);
  162. }
  163. // no format defined? default to HTML
  164. if (outputFormats.length === 0) {
  165. outputFormats.push({
  166. format: 'HTML',
  167. icon: 'html_icon',
  168. displayName: t.translate('schedule_format_web')
  169. });
  170. }
  171. }
  172. var attributes = {
  173. schedule_toolbar_label: t.translate('schedule_toolbar_label'),
  174. schedule_new_label: t.translate('schedule_new_label'),
  175. schedule_delete_label: t.translate('schedule_delete_label'),
  176. schedule_update_label: t.translate('schedule_update_label'),
  177. schedule_toggle_label: t.translate('schedule_enable_label'),
  178. schedule_new_btn_label: t.translate('schedule_new_btn_label'),
  179. report_id: schedule.reportId,
  180. schedule_type: scheduleType,
  181. schedule_cadence_label: cadenceLabel || '',
  182. show_create: showCreate,
  183. show_formats: showFormats,
  184. outputFormat: outputFormats
  185. };
  186. this._loadTemplates(attributes, showCreate);
  187. if (!showCreate) {
  188. this._renderToggleButton();
  189. }
  190. // Disable based on permissions
  191. if (!this.hasPermission.write && showCreate) {
  192. // Remove new
  193. this.$el.find('.schedule_create_new').remove();
  194. }
  195. if (!this.hasPermission.write && !showCreate) {
  196. // Remove Toolbar
  197. this.$el.find('.schedule_toolbar').remove();
  198. if (!this.hasPermission.read) {
  199. // No read permission disable Forward
  200. this.$el.find('.schedule_expand').prop('disabled', true);
  201. }
  202. }
  203. if (this.schedule.id) {
  204. return controller.getRawSchedule(this.schedule.id, this.glassContext);
  205. } else {
  206. return Promise.resolve({ data: [{ options: [] }] });
  207. }
  208. }.bind(this)).then(function(result) {
  209. if (this.schedule.id) {
  210. this.objectInfo.rawOptions = result.data[0].options;
  211. } else if (this.schedule.reportId) {
  212. this.objectInfo.rawOptions = result.data[0].options;
  213. }
  214. console.log("raw result is", result);
  215. deferred.resolve();
  216. }.bind(this));
  217. return deferred.promise;
  218. },
  219. _getScheduleType: function () {
  220. switch (this.schedule.scheduleInfo.type) {
  221. case 'daily':
  222. case 'dailyWithIntradayRecurrence':
  223. return 'daily';
  224. case 'monthlyRelative':
  225. case 'monthlyAbsolute':
  226. case 'monthlyRelativeWithIntradayRecurrence':
  227. case 'monthlyAbsoluteWithIntradayRecurrence':
  228. return 'monthly';
  229. case 'yearlyRelative':
  230. case 'yearlyAbsolute':
  231. case 'yearlyRelativeWithIntradayRecurrence':
  232. case 'yearlyAbsoluteWithIntradayRecurrence':
  233. return 'yearly';
  234. case 'trigger':
  235. return 'trigger';
  236. default:
  237. return 'weekly';
  238. }
  239. },
  240. _loadTemplates: function (attributes, showCreate) {
  241. var htmlGenerator = dot.simpleTemplate(template);
  242. this.$el.html(htmlGenerator(attributes));
  243. if (showCreate) {
  244. var sHtml = dot.template(emptySchTemplate)({
  245. 'text': t.translate('no_schedule_label', { type: t.translate(this.objectInfo.type + '_type') })
  246. });
  247. this.$el.find('.schedule_no_schedule_container').append(sHtml);
  248. }
  249. this._setIcons();
  250. this._setEvents();
  251. },
  252. _renderToggleButton: function () {
  253. var reportState = false;
  254. if (this.schedule && this.schedule.scheduleInfo) {
  255. reportState = this.schedule.scheduleInfo.active;
  256. }
  257. this.stateToggler = new ToggleButton({
  258. id: 'schedule_toggler_' + this.schedule.reportId,
  259. el: this.$el.find('.schedule_toggle_button_container'),
  260. name: 'schedule_status_toggler',
  261. ariaLabel: t.translate('schedule_toggle_label'),
  262. checked: reportState,
  263. onChange: this._handleToggler.bind(this)
  264. });
  265. this.stateToggler.doRender();
  266. },
  267. _handleToggler: function (name, value) {
  268. if (name === 'schedule_status_toggler') {
  269. var newDescriptor = this.schedule;
  270. newDescriptor.scheduleInfo.active = value;
  271. delete newDescriptor.name; //Need to delete the name property before making CM call
  272. controller.updateSchedule(newDescriptor, this.glassContext).then(function (data) {
  273. this.schedule = data;
  274. }.bind(this));
  275. }
  276. },
  277. /**
  278. * Open a slideout with the schedule view in it
  279. *
  280. * @param isUpdating {boolean} - Default false; Set true if opening an existing schedule to view/edit.
  281. */
  282. _openScheduleView: function (isUpdating) {
  283. var _self = this;
  284. if (typeof (isUpdating) !== 'boolean') {
  285. isUpdating = false;
  286. }
  287. this.glassContext.getSvc('.Content').then(function (contentSvc) {
  288. var server_URL = contentSvc.getBaseObjectsURL() + '/' + _self.schedule.reportId + '?fields=canBurst';
  289. contentSvc.get(server_URL, {}).done(function (data, textStatus, jqXHR) {
  290. if (isUpdating) {
  291. _self.objectInfo.descriptor = _self.schedule;
  292. }
  293. _self.objectInfo.hasPermission = _self.hasPermission;
  294. var module = _self._getScheduleModule();
  295. _self.glassContext.appController.showSlideOut({
  296. 'parent': _self.slideout,
  297. 'overlay': true,
  298. 'enableTabLooping': true,
  299. 'label': t.translate('schedule_report_properties_name'),
  300. 'content': {
  301. 'module': module,
  302. 'objectInformation': _self.objectInfo,
  303. 'onCreateOrUpdateCallback': _self.updateScheduleList.bind(_self),
  304. 'canBurst': data.data[0].canBurst,
  305. 'glassContext': _self.glassContext,
  306. 'slideoutparent': _self.slideout
  307. }
  308. });
  309. });
  310. });
  311. },
  312. remove: function() {
  313. var $newPane = this.$el.find('.newSchedPane');
  314. if (($newPane) && ($newPane.length === 1)) {
  315. ReactDOM.unmountComponentAtNode($newPane[0]);
  316. } else {
  317. this.glassContext.getCoreSvc('.Logger').log('could not remove schedule react element');
  318. }
  319. },
  320. _getScheduleModule: function () {
  321. if (this.objectInfo.type === 'dataSet2') {
  322. return 'bi/schedule/views/DatasetScheduleView';
  323. } else if (this.objectInfo.type === 'jobDefinition') {
  324. return 'bi/schedule/views/JobScheduleView';
  325. }
  326. return 'bi/schedule/views/ScheduleView';
  327. },
  328. _getOutputFormat: function(options) {
  329. var outputFormat = '';
  330. try {
  331. for (var i = 0; i < options.length; i++) {
  332. if (options[i].name === 'outputFormat') {
  333. // expect output format option value to be a MobX ObservableArray
  334. outputFormat = options[i].value.join(',');
  335. break;
  336. }
  337. }
  338. } catch(e) {
  339. // return outputFormat as empty string
  340. }
  341. return outputFormat;
  342. },
  343. _deleteFunction: function() {
  344. var deleteDialog = new ConfirmationDialog('warning', t.translate('delete_confirm'),
  345. t.translate('delete_schedule_confirm_message'));
  346. deleteDialog.confirm(function () {
  347. controller.deleteSchedule(this.objectInfo.id, this.glassContext).done(function () {
  348. var trackingOpts = {
  349. type: 'Deleted Object',
  350. objectType: this.objectInfo.type,
  351. object: this.objectInfo.id,
  352. action: 'scheduleDeleted',
  353. milestoneName: 'scheduleDeleted_' + this.objectInfo.type,
  354. 'custom.outputFormat': this._getOutputFormat(this.schedule.options.outputFormat)
  355. };
  356. var instrumentor = this.glassContext.getCoreSvc('.Instrumentation');
  357. if ((instrumentor) && (instrumentor.track)) {
  358. instrumentor.track(trackingOpts);
  359. }
  360. if (this.objectInfo && this.objectInfo.descriptor) {
  361. delete this.objectInfo.descriptor;
  362. }
  363. this.updateScheduleList();
  364. }.bind(this));
  365. }.bind(this));
  366. },
  367. _setEvents: function () {
  368. this.$el.find('.schedule_create_new button').on('clicktap', function () {
  369. this._openScheduleView(false);
  370. return false;
  371. }.bind(this));
  372. this.$el.find('.schedule_expand').on('clicktap', function () {
  373. this._openScheduleView(true);
  374. return false;
  375. }.bind(this));
  376. this.$el.find('.schedule_delete_button').on('clicktap', function () {
  377. var deleteDialog = new ConfirmationDialog('warning', t.translate('delete_confirm'),
  378. t.translate('delete_schedule_confirm_message'));
  379. deleteDialog.confirm(function () {
  380. controller.deleteSchedule(this.objectInfo.id, this.glassContext).done(function () {
  381. var trackingOpts = {
  382. type: 'Deleted Object',
  383. objectType: this.objectInfo.type,
  384. object: this.objectInfo.id,
  385. action: 'scheduleDeleted',
  386. milestoneName: 'scheduleDeleted_' + this.objectInfo.type,
  387. 'custom.outputFormat': this._getOutputFormat(this.schedule.options.outputFormat)
  388. };
  389. var instrumentor = this.glassContext.getCoreSvc('.Instrumentation');
  390. if ((instrumentor) && (instrumentor.track)) {
  391. instrumentor.track(trackingOpts);
  392. }
  393. if (this.objectInfo && this.objectInfo.descriptor) {
  394. delete this.objectInfo.descriptor;
  395. }
  396. this.updateScheduleList();
  397. }.bind(this));
  398. }.bind(this));
  399. }.bind(this));
  400. },
  401. _setIcons: function () {
  402. var icons = this.$el.find('.schedule_common_icon');
  403. for (var k = 0; k < icons.length; k++) {
  404. var $icon = $(icons[k]);
  405. var display = icons[k].dataset.displayName;
  406. Utils.setIcon($icon, 'common-' + icons[k].dataset.icon, display ? display : icons[k].dataset.icon);
  407. }
  408. }
  409. });
  410. return schedulesView;
  411. });