SubscriptionManagementView.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /**
  2. * Licensed Materials - Property of IBM
  3. *
  4. * IBM Cognos Products: SHARE
  5. *
  6. * Copyright IBM Corp. 2015, 2017
  7. *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  9. */
  10. define([
  11. 'jquery',
  12. 'underscore',
  13. 'moment-timezone',
  14. 'rave2',
  15. 'q',
  16. 'bi/commons/utils/BidiUtil',
  17. 'text!bi/schedule/templates/SubscriptionManagementLoading.html',
  18. 'text!bi/schedule/templates/SubscriptionManagement.html',
  19. 'text!bi/notifications/templates/emptyMessageList.html',
  20. 'bi/glass/app/ContentView',
  21. 'bi/sharecommon/utils/simpledoT',
  22. 'bi/sharecommon/utils/translator',
  23. 'bi/schedule/app/appControler',
  24. 'bi/schedule/utils/CadenceLabelGenerator',
  25. 'bi/commons/ui/properties/CheckBox',
  26. 'bi/commons/utils/Utils',
  27. 'bi/schedule/utils/charts/BarChart',
  28. 'datatables'
  29. ],
  30. function($, _, moment, rave, Q, BidiUtil,
  31. loadingViewTemplate, viewTemplate, emptyListTemplate,
  32. ContentView, dot, t, controler, cadence, CheckBox, Utils, BarChart) {
  33. var DEFAULT_DELAY = 500;
  34. var __STANDARD_DATE_TIME_FORMAT = 'lll';
  35. var view = ContentView.extend({
  36. init: function(options) {
  37. view.inherited('init', this, arguments);
  38. // Initialise default values
  39. this.subscriptionsCount = 0;
  40. this.enabledCount = 0;
  41. this.disabledCount = 0;
  42. this.windowWidth = 0;
  43. this.timezone = options.glassContext.services.userProfile.preferences.timeZoneID;
  44. this.contentLocale = this.glassContext.services.userProfile.preferences.contentLocale || "en-us";
  45. $.extend(this, options);
  46. this._id = _.uniqueId("smv_");
  47. this.$subscriptionsListDiv = null;
  48. this.$noSubscriptionsDiv = null;
  49. },
  50. activate: function() {
  51. return this.updateView();
  52. },
  53. // nothing to do, but needs to be present for AppView.js logic from Glass
  54. deactivate: function() {
  55. },
  56. getContent: function() {
  57. return {};
  58. },
  59. getTitle: function() {
  60. return t.translate("subscribe_mgmt_label");
  61. },
  62. getIcon: function() {
  63. return 'common-subscribe_icon';
  64. },
  65. render: function() {
  66. var deferred = $.Deferred();
  67. var subscribe_graph_title = t.translate("subscribe_graph_title");
  68. var subscribe_last_refresh_label = t.translate("subscribe_last_refresh_label");
  69. // Set up the Subscription Management Loading template
  70. // I don't like this but it works (for now)
  71. var loadingHtmlGenerator = dot.simpleTemplate(loadingViewTemplate);
  72. var currentTime = moment(new Date()).locale(this.contentLocale).tz(this.timezone).format(__STANDARD_DATE_TIME_FORMAT);
  73. var attributes = {
  74. subscribe_graph_title: subscribe_graph_title,
  75. subscribe_last_refresh_label: subscribe_last_refresh_label,
  76. current_time: currentTime
  77. };
  78. this.$el.html(loadingHtmlGenerator(attributes));
  79. var loadingAnimation = Utils.getLoadingAnimation(2);
  80. this.$el.find('div.s10n_loading').html(loadingAnimation);
  81. deferred.resolve(this);
  82. controler.getSubscriptions(this.glassContext).then(function(data) {
  83. var subscriptions = [];
  84. this.enabledCount = 0;
  85. var dataLength = data.length;
  86. for(var i = 0; i < dataLength; i++) {
  87. var name = _.escape(data[i].name.substr(0, 3) + BidiUtil.enforceTextDirection(data[i].name.substr(3))) || "";
  88. var nameInAttr = _.escape(data[i].name)|| "";
  89. var cadenceLabel = cadence.getLabelFor(data[i].scheduleInfo, this.timezone, this.contentLocale);
  90. var ownerName = data[i].scheduleInfo ? _.escape(data[i].scheduleInfo.ownerName) || "" : "";
  91. var lastModified = data[i].scheduleInfo ? data[i].scheduleInfo.modificationTime || "" : "";
  92. lastModified = moment(lastModified).locale(this.contentLocale).tz(this.timezone).format(__STANDARD_DATE_TIME_FORMAT);
  93. data[i].checkbox_aria_label = t.translate("subscribe_mgmt_checkbox_description", {
  94. 'subscription_name': nameInAttr
  95. });
  96. var isEnabled = data[i].scheduleInfo.active || false;
  97. if(isEnabled) {
  98. this.enabledCount++;
  99. }
  100. subscriptions.push({
  101. id: data[i].id,
  102. name: name,
  103. owner: ownerName,
  104. active: isEnabled,
  105. modifiedTime: lastModified,
  106. cadence_label: cadenceLabel, // "Every Wednesday at 5pm"
  107. context_menu_description: t.translate("subs_mgmt_context_menu_description", {
  108. 'subscription_name': nameInAttr
  109. })
  110. });
  111. }
  112. this.subscriptionsCount = subscriptions.length;
  113. this.disabledCount = subscriptions.length - this.enabledCount;
  114. var htmlGenerator = dot.simpleTemplate(viewTemplate);
  115. var currentTime = moment(new Date()).locale(this.contentLocale).tz(this.timezone).format(__STANDARD_DATE_TIME_FORMAT);
  116. var attributes = {
  117. id: this._id,
  118. subscribe_graph_title: subscribe_graph_title,
  119. subscribe_last_refresh_label: subscribe_last_refresh_label,
  120. current_time: currentTime,
  121. ariaLabel: t.translate("subscriptions_table_accessible_label"),
  122. chartDescription: t.translate("subscribe_graph_description", {
  123. enabled: this.enabledCount, disabled: this.disabledCount
  124. }),
  125. columns: this._tableColumnHeaders(),
  126. subs: subscriptions
  127. };
  128. this.$el.html(htmlGenerator(attributes));
  129. // By default both are displayed. We choose which to hide later
  130. this.$subscriptionsListDiv = this.$el.find('.subscriptions_list');
  131. this.$noSubscriptionsDiv = this.$el.find('.no_subscriptions_message');
  132. var emptyTemplate = dot.template(emptyListTemplate);
  133. this.$noSubscriptionsDiv.html(emptyTemplate({
  134. 'text': t.translate("subscription_list_is_empty")
  135. }));
  136. this._setSvg();
  137. this._renderChart();
  138. this._renderCheckBoxes(data);
  139. if (this.subscriptionsCount > 0) {
  140. this.$subscriptionsListDiv.find('.subscriptions_list_table').dataTable({
  141. paging: false,
  142. searching: false,
  143. info: false,
  144. aaSorting: [[1, 'asc']],
  145. scrollY: '60vh',
  146. scrollX: 'auto',
  147. width: '100%'
  148. });
  149. this.$noSubscriptionsDiv.hide();
  150. }
  151. else {
  152. this.$subscriptionsListDiv.hide();
  153. }
  154. this._fixTableBodyHeight();
  155. this._setEvents();
  156. }.bind(this));
  157. return deferred.promise();
  158. },
  159. updateView: function() {
  160. this.$el.empty();
  161. return this.render();
  162. },
  163. _renderChart: function() {
  164. var chartData = [
  165. {
  166. name: 'enabled',
  167. value: this.enabledCount
  168. },
  169. {
  170. name: 'disabled',
  171. value: this.disabledCount
  172. }
  173. ];
  174. // This initialises AND draws the chart
  175. this._chart = new BarChart({
  176. $el: this.$el.find('svg.chart'),
  177. data: chartData
  178. });
  179. },
  180. _updateChart: function(data) {
  181. this._chart.redraw(data);
  182. },
  183. _renderCheckBoxes: function(data) {
  184. var _self = this;
  185. for(var i = 0; i < data.length; i++) {
  186. var stateToggler = new CheckBox({
  187. 'id': 'subscription_' + data[i].id,
  188. 'el': _self.$el.find("[data-subscription-id='"+ data[i].id +"'] > td:first"),
  189. 'name': data[i].id,
  190. 'label': '',
  191. 'ariaLabel': data[i].checkbox_aria_label,
  192. 'checked': data[i].scheduleInfo.active,
  193. 'onChange': function(name, value) {
  194. _self._handleCheckBoxes({
  195. subscriptionId: name,
  196. state: value,
  197. $checkbox: this.getPropertyNode() // 'this' is CheckBox NOT SubMgmtView
  198. });
  199. }
  200. });
  201. stateToggler.doRender();
  202. }
  203. },
  204. _handleCheckBoxes: function(properties) {
  205. var subscriptionId = properties.subscriptionId;
  206. var state = properties.state;
  207. var $checkbox = properties.$checkbox;
  208. $checkbox.addClass('disabled');
  209. controler.getSubscriptionDetails(subscriptionId, this.glassContext).then(function(data) {
  210. subscriptionDescriptor = data;
  211. subscriptionDescriptor.scheduleInfo.active = state;
  212. this._toggleSingleSubscriptionStatus(subscriptionDescriptor).then(function() {
  213. $checkbox.removeClass('disabled');
  214. });
  215. }.bind(this));
  216. },
  217. _toggleSingleSubscriptionStatus: function(descriptor) {
  218. var deferred = Q.defer();
  219. controler.updateSubscription(descriptor, this.glassContext).done(function(data) {
  220. this._updateSubscriptionList().then(function() {
  221. deferred.resolve();
  222. });
  223. }.bind(this));
  224. return deferred.promise;
  225. },
  226. _fixTableBodyHeight: function() {
  227. var contentHeight = this.$el.find('div.s10n_main').height(); // this is height of pane minus top and bottom padding
  228. var topHeight = this.$el.find('div.s10n_header').height() + this.$el.find('svg.chart').height();
  229. // The magic number 40 is for the padding in the content view from the css class s10n_container
  230. this.$el.find('div.dataTables_scrollBody').height(contentHeight - topHeight - 40);
  231. },
  232. _setEvents: function() {
  233. var _self = this;
  234. window.onresize = function() {
  235. if(_self.$el.find('svg.chart').css('visibility') !== 'hidden' && $(window).width() !== _self.windowWidth) {
  236. _self.windowWidth = $(window).width();
  237. _self._updateChart();
  238. }
  239. // Fix height of datatable container
  240. _self._fixTableBodyHeight();
  241. };
  242. $('button.btnContextMenu').on('clicktap', function(event) {
  243. var menuProperties = {
  244. 'menuId': 'com.ibm.bi.subscribe_mgmt.contextMenu',
  245. 'position': {
  246. pageX: event.pageX,
  247. pageY: event.pageY
  248. },
  249. 'activeObject': {
  250. currentTarget: event.currentTarget,
  251. subscriptionId: $(event.currentTarget).closest('tr').data('subscription-id'),
  252. updateCallback: _self.updateView.bind(_self),
  253. deleteCallbacks: {
  254. hideRow: _self._hideDeleteRow.bind(_self),
  255. undoDelete: _self._undoDeleteAndShowRow.bind(_self),
  256. complete: _self._completeSubscriptionDelete.bind(_self)
  257. }
  258. }
  259. };
  260. _self.glassContext.appController.showContextMenu(menuProperties);
  261. });
  262. },
  263. _hideDeleteRow: function($subscriptionRow) {
  264. var deferred = Q.defer();
  265. var _self = this;
  266. $subscriptionRow.hide(DEFAULT_DELAY, function() {
  267. if(_self.subscriptionsCount == 1) {
  268. _self.$noSubscriptionsDiv.show();
  269. _self.$subscriptionsListDiv.hide();
  270. }
  271. deferred.resolve();
  272. });
  273. return deferred.promise;
  274. },
  275. _undoDeleteAndShowRow: function($subscriptionRow) {
  276. var _self = this;
  277. // An undo should show right away that is the reason for zero
  278. $subscriptionRow.show(0, function() {
  279. if(_self.subscriptionsCount == 1) {
  280. _self.$noSubscriptionsDiv.hide();
  281. _self.$subscriptionsListDiv.show();
  282. }
  283. });
  284. },
  285. _completeSubscriptionDelete: function(options) {
  286. if(options.pending) {
  287. controler.deleteSubscription(options.subscriptionId, this.glassContext).done(function() {
  288. this._updateSubscriptionList();
  289. }.bind(this));
  290. }
  291. },
  292. _updateSubscriptionList: function() {
  293. var deferred = Q.defer();
  294. controler.getSubscriptions(this.glassContext).done(function(data) {
  295. this.subscriptionsCount = data.length;
  296. var enabled = _.countBy(data, function(s) {
  297. if(s.scheduleInfo.active)
  298. return "enabled";
  299. });
  300. if(!enabled.enabled) {
  301. enabled.enabled = 0;
  302. }
  303. this.enabledCount = enabled.enabled;
  304. this.disabledCount = this.subscriptionsCount - enabled.enabled;
  305. if(this.subscriptionsCount === 0) {
  306. this.$noSubscriptionsDiv.show();
  307. this.$subscriptionsListDiv.hide();
  308. }
  309. var chartData = [
  310. {
  311. name: 'enabled',
  312. value: this.enabledCount
  313. },
  314. {
  315. name: 'disabled',
  316. value: this.disabledCount
  317. }
  318. ];
  319. this._updateChart(chartData);
  320. deferred.resolve();
  321. }.bind(this));
  322. return deferred.promise;
  323. },
  324. _setSvg: function() {
  325. var $icons = this.$el.find('.common_icon');
  326. for(var i = 0; i < $icons.length; i++) {
  327. var $icon = $($icons[i]);
  328. Utils.setIcon($icon, 'common-' + $icon.data('icon'), t.translate('svg_menu_icon'));
  329. }
  330. },
  331. _tableColumnHeaders: function() {
  332. return [
  333. {
  334. 'name': 'enable',
  335. 'label': t.translate("subscribe_status_header"),
  336. 'class': 's10n_status_col'
  337. },
  338. // Subscription name column
  339. {
  340. 'name': 'name',
  341. 'label': t.translate("subscribe_header"),
  342. 'sort': true
  343. },
  344. // Owner column
  345. {
  346. 'name': 'owner',
  347. 'label': t.translate("subscribe_owner_header"),
  348. 'sort': true
  349. },
  350. // Modified column
  351. {
  352. 'name': 'modified',
  353. 'label': t.translate("subscribe_modified_header"),
  354. 'sort': true
  355. },
  356. // Context Menu column to modify/view history/delete
  357. {
  358. 'name': 'context'
  359. }
  360. ];
  361. }
  362. });
  363. return view;
  364. });