SubscriptionManagementTab.js 14 KB

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