SubscriptionView.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. /*
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: SHARE
  5. *
  6. * (C) Copyright IBM Corp. 2015, 2018
  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. 'bi/glass/app/ContentView',
  13. 'bi/commons/utils/BidiUtil',
  14. 'bi/schedule/app/appControler',
  15. 'jquery',
  16. 'bi/sharecommon/utils/translator',
  17. 'q',
  18. 'bi/sharecommon/utils/simpledoT',
  19. 'text!bi/schedule/templates/SubscriptionView.html',
  20. 'underscore',
  21. 'bi/commons/ui/widgets/TimePicker',
  22. 'bi/schedule/views/WeeklyCadencePickerView',
  23. 'bi/commons/utils/Utils',
  24. 'bi/schedule/views/FormatPickerView',
  25. 'bi/schedule/views/ScheduleDeliveryPickerView',
  26. 'ca_portal/features/mypreferences/MyPreferences',
  27. 'bi/content_apps/utils/ContentStoreObject',
  28. 'caglass/ajax/CAAuthentication',
  29. 'bi/commons/utils/DateTimeUtils',
  30. 'moment'
  31. ],
  32. function (View, BidiUtil, controler, $, t, Q, dot, template, _,
  33. TimePicker, WeeklyCadencePicker, Utils, FormatPicker, ScheduleDeliveryPickerView,
  34. MyPreferences, ContentStoreObject, CAAuthentication, DateTimeUtils, moment) {
  35. 'use strict';
  36. var subscriptionView = View.extend({
  37. /**
  38. * Constructor / initialization function for view
  39. *
  40. * @param options Options that are apart of this view. options.descriptor is <b>required</b> and inside
  41. * the descriptor object name and reportId are both required.
  42. * descriptor {
  43. * name: 'some-report-name',
  44. * reportId: 'some-report-id'
  45. * }
  46. */
  47. init: function (options) {
  48. subscriptionView.inherited('init', this, arguments);
  49. this.timezone = options.glassContext.services.userProfile.preferences.timeZoneID;
  50. this.locale = options.glassContext.services.userProfile.preferences.contentLocale;
  51. this._initVariables();
  52. $.extend(this, options);
  53. if (typeof this.descriptor !== 'undefined' && this.descriptor.name && this.descriptor.reportId) {
  54. this.id = this.descriptor.id;
  55. if (this.id) {
  56. this.isEditMode = true;
  57. }
  58. if (this.isEditMode) {
  59. this.name = this.descriptor.name;
  60. } else {
  61. this.name = t.translate("subscription_name", { param: this.descriptor.name });
  62. }
  63. this.reportId = this.descriptor.reportId;
  64. this.type = this.descriptor.type;
  65. for (var key in this.descriptor.scheduleInfo) {
  66. this.scheduleInfo[key] = this.descriptor.scheduleInfo[key];
  67. }
  68. for (key in this.descriptor.options) {
  69. this.options[key] = this.descriptor.options[key];
  70. }
  71. if (this.descriptor.parameters) {
  72. this.parameterValues = this.descriptor.parameters;
  73. }
  74. }
  75. else {
  76. throw "Error: No descriptor was given.";
  77. }
  78. },
  79. /**
  80. * Render function
  81. */
  82. render: function () {
  83. var deferred = Q.defer();
  84. var parameterValues = this.parameterValues || [];
  85. this.showPrompts = parameterValues.length > 0;
  86. var htmlGenerator = dot.simpleTemplate(template);
  87. var attributes = {
  88. report_name: _.escape(BidiUtil.enforceTextDirection(this.name)),
  89. subscription_header_region: t.translate("subscription_header_region"),
  90. subscription_panel_title: t.translate("subscription_panel_title"),
  91. schedule_timepicker_label: t.translate("schedule_time_label"),
  92. schedule_output_label: t.translate("schedule_output_label"),
  93. schedule_select_text: t.translate("schedule_select_text"),
  94. schedule_prompts_label: t.translate("schedule_prompts_label"),
  95. schedule_create_btn: this.isEditMode ? t.translate("schedule_update_btn_label") : t.translate("schedule_create_btn_label"),
  96. schedule_cancel_btn: t.translate("schedule_cancel_btn_label"),
  97. subs_delivery_message: t.translate("subs_delivery_message"),
  98. schedule_delivery_label: t.translate("schedule_delivery_label"),
  99. schedule_prompts_text: t.translate("schedule_prompts_text"),
  100. isUpdate: this.isEditMode,
  101. uniqueid: _.uniqueId(),
  102. output_format_select_text: t.translate('output_format_select_text'),
  103. showPrompts: this.showPrompts
  104. };
  105. attributes.subscription_controls_description = t.translate('subscription_controls_description', {
  106. action1: attributes.schedule_create_btn,
  107. action2: attributes.schedule_cancel_btn
  108. });
  109. this.$el.html(htmlGenerator(attributes));
  110. // Render the 'widgets' that this subscription view has
  111. this._setIcons();
  112. this.renderCadencePicker();
  113. this.renderTimePicker();
  114. this.renderOutputFormatPicker();
  115. this.renderDeliveryPicker();
  116. if (this.showPrompts) {
  117. this.renderPromptRow();
  118. }
  119. this._setEvents();
  120. deferred.resolve(this);
  121. return deferred.promise;
  122. },
  123. setFocus: function () {
  124. this.$el.find('.schedule_button_groups').children().first().focus();
  125. },
  126. renderCadencePicker: function () {
  127. this.cadencePicker = new WeeklyCadencePicker({
  128. $el: this.$el.find(".schedule_cadence_picker"),
  129. glassContext: this.glassContext,
  130. objectInformation: {
  131. showRunEvery: false,
  132. showDailyInterval: false,
  133. descriptor: {
  134. scheduleInfo: this.scheduleInfo
  135. }
  136. }
  137. });
  138. this.cadencePicker.render();
  139. },
  140. renderTimePicker: function () {
  141. this.timePicker = new TimePicker({
  142. $el: this.$el.find(".schedule_time_picker_container"),
  143. timezone: this.timezone,
  144. attributes: {
  145. minuteStep: 1,
  146. showMeridian: !DateTimeUtils.is24HrFormat(this.locale),
  147. defaultTime: this.scheduleInfo.startDate
  148. }
  149. });
  150. this.timePicker.render();
  151. },
  152. renderOutputFormatPicker: function () {
  153. try {
  154. var showHtmlOnly = this.type === 'interactiveReport';
  155. var showPdfOnly = this.type === 'powerPlay8Report' || this.type === 'powerPlay8ReportView';
  156. this.outputFormatPicker = new FormatPicker({
  157. $el: this.$el.find('.output_format_list'),
  158. $toggler: this.$el.find('.output_format_picker'),
  159. outputFormats: this.options.outputFormat.slice(),
  160. glassContext: this.glassContext,
  161. slideoutparent: this.slideout,
  162. overlay: true,
  163. showHTML: !showPdfOnly,
  164. showPDF: !showHtmlOnly && this.glassContext.hasCapability("canGeneratePDFOutput"),
  165. showExcel: !showHtmlOnly && !showPdfOnly && this.glassContext.hasCapability("canGenerateXLSOutput"),
  166. showCSV: !showHtmlOnly && !showPdfOnly && this.glassContext.hasCapability("canGenerateCSVOutput"),
  167. showXML: !showHtmlOnly && !showPdfOnly && this.glassContext.hasCapability("canGenerateXMLOutput")
  168. });
  169. this.outputFormatPicker.render();
  170. }
  171. catch (e) {
  172. console.log('There was an error initializing the FormatPicker.', e);
  173. }
  174. },
  175. renderDeliveryPicker: function () {
  176. try {
  177. this.deliveryPicker = new ScheduleDeliveryPickerView({
  178. $el: this.$el.find('.schedule_delivery_picker'),
  179. $toggler: this.$el.find('.schedule_delivery_picker'),
  180. $activeOptionsContainer: this.$el.find('.delivery_list.clearfix'),
  181. reportName: this.name,
  182. deliveryOptions: this.options.delivery,
  183. isEditMode: this.isEditMode,
  184. glassContext: this.glassContext,
  185. slideoutparent: this.slideout,
  186. showMobile: this.glassContext.hasCapability("canUseMobileService") && this.type === "interactiveReport",
  187. showSaveToFileSystem: false,
  188. overlay: true
  189. });
  190. this.deliveryPicker.render();
  191. }
  192. catch (e) {
  193. console.log('There was an error initializing the DeliveryPicker.', e);
  194. }
  195. },
  196. renderPromptRow: function () {
  197. var _self = this;
  198. // Provide bare minimum objectInfo
  199. var _objectInfo = { id: this.reportId };
  200. this.objectInfo = _objectInfo;
  201. // Slide out is to the left of parent and is an overlay
  202. this.$promptTarget = this.$el.find('.prompt_picker_target');
  203. this.$promptTarget.on('clicktap', function () {
  204. _self.glassContext.appController.showSlideOut({
  205. 'position': _self.slideout ? null : 'left',
  206. 'parent': _self.slideout,
  207. 'overlay': true,
  208. 'enableTabLooping': true,
  209. 'label': t.translate("schedule_prompt_picker_name"),
  210. 'content': {
  211. 'module': 'bi/content_apps/PromptValuesView',
  212. 'parentView': _self,
  213. 'glassContext': _self.glassContext,
  214. 'promptDisplayValues': ContentStoreObject.getPromptsDisplayValues(_self.parameterValues),
  215. 'parameters': _self.parameterValues,
  216. 'isEditMode': _self.isEditMode,
  217. 'clearCallback': function () {
  218. if (_self.parameterValues.length > 0) {
  219. _self._updatePromptValueLabel();
  220. }
  221. },
  222. 'editCallback': function (parameters) {
  223. _self._updatePromptValueLabel(parameters);
  224. }
  225. }
  226. });
  227. });
  228. this._updatePromptValueLabel(this.parameterValues);
  229. },
  230. _updatePromptValueLabel: function (prompts) {
  231. // Reset the parameterValues to empty on Clear callback
  232. this.parameterValues = prompts ? prompts : [];
  233. var $promptValueLabel = this.$el.find('.currentPromptValues');
  234. $promptValueLabel.text(this._getPromptValueLabel());
  235. },
  236. _getPromptValueLabel: function () {
  237. var label = t.translate("schedule_prompt_value_label_default");
  238. if (this.parameterValues && this.parameterValues.length > 0) {
  239. if (this.parameterValues.length == 1) {
  240. label = t.translate("schedule_prompt_value_label_single");
  241. }
  242. else {
  243. label = t.translate("schedule_prompt_value_label_multiple", {
  244. 'number': this.parameterValues.length
  245. });
  246. }
  247. }
  248. return label;
  249. },
  250. close: function () {
  251. var _self = this;
  252. this.slideout.hide().then(function () {
  253. _self._runCallback();
  254. });
  255. },
  256. /**
  257. * Mark the pane as in progress with a semi-transparent overlay
  258. */
  259. setWorking: function () {
  260. this.$overlay = this.$el.find(".progress-overlay");
  261. this.$overlay.show();
  262. },
  263. /**
  264. * Show the view if hidden
  265. */
  266. setDone: function () {
  267. if (!this.$overlay) return;
  268. this.$overlay.hide();
  269. },
  270. _setIcons: function () {
  271. var icons = this.$el.find('.common_schedule_icon');
  272. for (var i = 0; i < icons.length; i++) {
  273. var $icon = $(icons[i]);
  274. Utils.setIcon($icon, 'common-' + $icon.data('icon'), t.translate('svg_expand_icon'));
  275. }
  276. },
  277. _setEvents: function () {
  278. this.$el.find('.schedule_primary_button').on('clicktap', function () {
  279. this.setWorking();
  280. // hide time warning message if any present on create button click
  281. // if the user input time is still invalid it will show again
  282. // the message will disappear with a successful creation of schedule
  283. this.hideWarningMessage();
  284. if (this.validate()) {
  285. // if a startDate exists (we are in edit mode), re-use it.
  286. var localDate;
  287. if (this.scheduleInfo.startDate !== 'current') {
  288. localDate = moment.utc(this.scheduleInfo.startDate).toDate();
  289. } else {
  290. localDate = new Date();
  291. }
  292. this.scheduleInfo.startDate = this.timePicker.getDateTimeUTC(localDate);
  293. if (this.outputFormatPicker !== null) {
  294. this.options.outputFormat = this.outputFormatPicker.getOutputFormats();
  295. }
  296. if (this.deliveryPicker !== null) {
  297. this.options.delivery = this.deliveryPicker.getDeliveryOptions();
  298. }
  299. // set default content locale
  300. this.options.outputLocale = [this.glassContext.services.userProfile.preferences.contentLocale];
  301. // grab cadencePicker info
  302. this.scheduleInfo = this.cadencePicker.toDescriptor(this.scheduleInfo);
  303. var subscriptionDesc = {
  304. name: this.name,
  305. reportId: this.reportId,
  306. scheduleInfo: this.scheduleInfo,
  307. options: this.options
  308. };
  309. if (this.id) {
  310. subscriptionDesc.id = this.id;
  311. }
  312. if (this.showPrompts) {
  313. subscriptionDesc.parameters = this.parameterValues;
  314. }
  315. // Check user credentials in tandem when creating subscription
  316. controler.getUserCredential(this.glassContext).then(function () {
  317. this._createOrUpdateSubscription(subscriptionDesc);
  318. }.bind(this)).fail(function () {
  319. // Credentials need to be renewed
  320. this.glassContext.appController.showToast(t.translate('sub_credentials_expired_msg'), {
  321. 'type': 'warning',
  322. 'preventDuplicates': true,
  323. 'btnLabel': t.translate('sub_renew_credentials_button'),
  324. 'callback': function () {
  325. this._caAuthentication = new CAAuthentication();
  326. return this._caAuthentication.storeCredentials(this.glassContext).then(function () {
  327. this._createOrUpdateSubscription(subscriptionDesc);
  328. }.bind(this)).fail(function (error) {
  329. if (error && error.displayObjects) {
  330. this._myPreferences = new MyPreferences({ glassContext: this.glassContext });
  331. return this._myPreferences.openCreateCredentialDialog(error.displayObjects).then(function () {
  332. this._createOrUpdateSubscription(subscriptionDesc);
  333. }.bind(this));
  334. }
  335. }.bind(this)).fail(function () {
  336. this.setDone;
  337. }.bind(this));
  338. }.bind(this)
  339. });
  340. }.bind(this));
  341. }
  342. else {
  343. // show the invalid time warning message
  344. this.showWarningMessage();
  345. // unlock ui
  346. this.setDone();
  347. }
  348. }.bind(this));
  349. this.$el.find('.schedule_secondary_button').on('clicktap', function () {
  350. // Because the callback is (currently) only used for updates just delete it
  351. // if the user clicks cancel so that when in edit mode the view doesn't get refreshed
  352. // with the same data.
  353. delete this.callback;
  354. this.close();
  355. }.bind(this));
  356. },
  357. _createOrUpdateSubscription: function (subscriptionDesc) {
  358. var _self = this;
  359. if (this.isEditMode) {
  360. controler.updateSubscription(subscriptionDesc, this.glassContext).then(function () {
  361. _self.glassContext.appController.showToast(t.translate('sub_update_success_msg'), {
  362. 'preventDuplicates': false
  363. });
  364. _self.setDone();
  365. _self.close();
  366. }, function () {
  367. _self.setDone();
  368. });
  369. }
  370. else {
  371. controler.createSubscription(subscriptionDesc, this.glassContext).then(function (data) {
  372. _self.glassContext.appController.showToast(t.translate('sub_create_success_msg'), {
  373. 'preventDuplicates': false
  374. });
  375. _self.setDone();
  376. _self.close();
  377. }, function () {
  378. _self.setDone();
  379. });
  380. }
  381. },
  382. _runCallback: function () {
  383. // Check to see if there is a callback function to run
  384. if (this.callback) {
  385. if (this.callback.onUpdate && typeof this.callback.onUpdate === 'function') {
  386. this.callback.onUpdate();
  387. }
  388. }
  389. },
  390. validate: function () {
  391. // Starting from the cadence pickers
  392. this.msgs = [];
  393. var $startTimeDiv = this.$el.find(".schedule_time_picker_container");
  394. $startTimeDiv.removeAttr('aria-invalid aria-describedby');
  395. if (!this.timePicker.isValidTime()) {
  396. this.msgs.push(t.translate("schedule_invalid_start_time"));
  397. $startTimeDiv.attr({
  398. 'aria-invalid': 'true',
  399. 'aria-describedby': this.msgs[0]
  400. });
  401. // One message at a time
  402. return false;
  403. }
  404. // Check delivery Options
  405. var deliveryOptions = this.deliveryPicker.getDeliveryOptions();
  406. var $deliveryListDiv = this.$el.find('.delivery_list');
  407. $deliveryListDiv.removeAttr('aria-invalid aria-describedby');
  408. if (deliveryOptions.email) {
  409. if (!deliveryOptions.email.emailAsAttachment && !deliveryOptions.email.emailAsURL) {
  410. this.msgs.push(t.translate('schedule_delivery_email_require_include'));
  411. $deliveryListDiv.attr({
  412. 'aria-invalid': 'true',
  413. 'aria-describedby': this.msgs[0]
  414. });
  415. return false;
  416. }
  417. }
  418. if (deliveryOptions.print && $.trim(deliveryOptions.print.name) === '') {
  419. this.msgs.push(t.translate('schedule_delivery_printer_empty_error'));
  420. $deliveryListDiv.attr({
  421. 'aria-invalid': 'true',
  422. 'aria-describedby': this.msgs[0]
  423. });
  424. return false;
  425. }
  426. return this.msgs.length === 0;
  427. },
  428. /**
  429. * Show warning message for invalid time input by user
  430. */
  431. showWarningMessage: function () {
  432. this.$warningMessage = this.$el.find(".invalid_input_warning_message").text(this.msgs[0]);
  433. if (!this.$warningMessage) {
  434. return;
  435. } else {
  436. this.$warningMessage.show();
  437. }
  438. },
  439. /**
  440. * Hide the warning message
  441. */
  442. hideWarningMessage: function () {
  443. if (!this.$warningMessage) return;
  444. this.$warningMessage.hide();
  445. },
  446. _initVariables: function () {
  447. this.descriptor = null;
  448. this.id = '';
  449. this.name = '';
  450. this.reportId = '';
  451. this.scheduleInfo = {
  452. type: 'weekly',
  453. active: true,
  454. startDate: 'current',
  455. endDate: '',
  456. endType: 'indefinite',
  457. everyNPeriods: 0,
  458. timezone: this.timezone,
  459. weekly: {
  460. weeklySunday: false,
  461. weeklyMonday: false,
  462. weeklyTuesday: false,
  463. weeklyWednesday: false,
  464. weeklyThursday: false,
  465. weeklyFriday: false,
  466. weeklySaturday: false
  467. }
  468. };
  469. this.options = {
  470. delivery: {
  471. save: {
  472. notify: true
  473. }
  474. },
  475. outputFormat: []
  476. };
  477. this.parameterValues = null;
  478. this.cadencePicker = null;
  479. this.timePicker = null;
  480. this.outputFormatPicker = null;
  481. this.deliveryPicker = null;
  482. this.isEditMode = false;
  483. this.showPrompts = false;
  484. this.callback = {};
  485. }
  486. });
  487. return subscriptionView;
  488. });