VisDnDUtils.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Business Analytics (C) Copyright IBM Corp. 2020
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. */
  8. /**
  9. * @class VisDnDUtils
  10. * @hideconstructor
  11. *
  12. * @classdesc Utility feature for drag and drop of metadata onto a visualization content
  13. */
  14. define(['underscore', '../../../lib/@waca/dashboard-common/dist/core/APIFactory', './api/VisDnDUtilsAPI', './OlapHelper.v2', './LocalFilterMemberDNDHelper', './VisMapColumnsToSlot', 'dashboard-analytics/dataSources/utils/ShapingUIUtils', './api/impl/VisDnDColumnToSlotProvider', './api/impl/VisDnDSlotToSlotProvider', './api/impl/VisDnDShapeToSlotProvider', './api/impl/VisDnDSlotLocalFilterProvider', './api/impl/VisDndLiveWidgetProvider', 'dashboard-analytics/dataSources/utils/ShapingConstants', 'dashboard-analytics/apiHelpers/SlotAPIHelper'], function (_, APIFactory, VisDnDUtilsAPI, OlapHelperV2, LocalFilterMemberDNDHelper, VisMapColumnsToSlot, ShapingUIUtils, VisDnDColumnToSlotProvider, VisDnDSlotToSlotProvider, VisDnDShapeToSlotProvider, VisDnDSlotLocalFilterProvider, VisDndLiveWidgetProvider, ShapingConstants, SlotAPIHelper) {
  15. var METADATA_TYPES = ['MODEL_ITEM', 'GRID_HEADER_ITEM', 'filter' // Used for FM package model filters ?
  16. ];
  17. var VisDnDUtils = function () {
  18. function VisDnDUtils(_ref) {
  19. var features = _ref.features,
  20. content = _ref.content;
  21. _classCallCheck(this, VisDnDUtils);
  22. this.content = content;
  23. this.dashboard = features['API'];
  24. this.dashboardDnD = features['Dashboard.DashboardDnd'];
  25. this.transaction = features['Dashboard.Transaction'];
  26. this.datasources = features['Dashboard.DataSources'];
  27. this.datasourcesMoser = features['Dashboard.DataSources.moser'];
  28. this.state = features['state'];
  29. this.visualization = features['Visualization'];
  30. this.visRecommender = features['Visualization.SmartsRecommender'];
  31. this.visDnD = features['VisDnD'];
  32. this.olapHelper = new OlapHelperV2(this.dashboard, this.visualization);
  33. this.visMapColumnsToSlot = new VisMapColumnsToSlot({
  34. content: this.content,
  35. visualization: this.visualization,
  36. transaction: this.transaction
  37. });
  38. this._initializeProviders();
  39. }
  40. VisDnDUtils.prototype.getAPI = function getAPI() {
  41. if (!this.api) {
  42. this.api = APIFactory.createAPI(this, [VisDnDUtilsAPI]);
  43. }
  44. return this.api;
  45. };
  46. VisDnDUtils.prototype._initializeProviders = function _initializeProviders() {
  47. var param = {
  48. visDnDUtils: this,
  49. dashboardAPI: this.dashboard,
  50. dashboardDnD: this.dashboardDnD,
  51. datasources: this.datasources,
  52. datasourcesMoser: this.datasourcesMoser,
  53. transaction: this.transaction,
  54. content: this.content,
  55. state: this.state,
  56. visualization: this.visualization,
  57. visRecommender: this.visRecommender
  58. };
  59. // Register the all livewidget providers
  60. var shapeToSlotProvider = new VisDnDShapeToSlotProvider(param);
  61. this.visDnD.registerProviders('widget.live', [new VisDndLiveWidgetProvider(param), shapeToSlotProvider], ['slot.item']);
  62. // Register the all slot.item providers
  63. var slotItemProviders = [VisDnDColumnToSlotProvider, VisDnDSlotToSlotProvider].map(function (ProviderClass) {
  64. return new ProviderClass(param);
  65. });
  66. this.visDnD.registerProviders('slot.item', [].concat(slotItemProviders, [shapeToSlotProvider]));
  67. // Register the slot.filter provider
  68. this.visDnD.registerProviders('slot.filter', [new VisDnDSlotLocalFilterProvider(param)]);
  69. };
  70. VisDnDUtils.prototype.destroy = function destroy() {
  71. this.dashboard = null;
  72. this.content = null;
  73. this.transaction = null;
  74. this.visualization = null;
  75. this.olapHelper = null;
  76. this.visMapColumnsToSlot = null;
  77. };
  78. VisDnDUtils.prototype._isSameDataSource = function _isSameDataSource(dragData) {
  79. var sourceId = dragData.sourceId;
  80. var dataSource = this.visualization.getDataSource();
  81. var currentModuleId = dataSource ? dataSource.getId() : null;
  82. return currentModuleId && sourceId !== currentModuleId ? false : true;
  83. };
  84. /**
  85. * return all the projected dataItems except MultiMeasure item.
  86. */
  87. VisDnDUtils.prototype._getProjectedDataItemList = function _getProjectedDataItemList() {
  88. if (!this.visualization) {
  89. throw new Error('Invalid visualization');
  90. }
  91. var dataItemList = this.visualization.getSlots().getDataItemList();
  92. dataItemList = dataItemList.filter(function (dataItem) {
  93. return dataItem.getColumnId() !== SlotAPIHelper.MULTI_MEASURES_SERIES;
  94. });
  95. return dataItemList.map(function (dataItem) {
  96. return dataItem.getMetadataColumn();
  97. });
  98. };
  99. VisDnDUtils.prototype._acceptsOlapColumnsV2 = function _acceptsOlapColumnsV2(payload, _ref2) {
  100. var dropTarget = _ref2.dropTarget,
  101. dropAction = _ref2.dropAction;
  102. var metadataColumns = _.map(payload.data.columns, function (column) {
  103. return column.metadataColumn;
  104. });
  105. if (dropTarget === ShapingConstants.DROP_TARGET_OPTIONS.FILTER || !metadataColumns.some(function (col) {
  106. return col.isOlapColumn();
  107. })) {
  108. return true;
  109. }
  110. var targetSlotId = void 0;
  111. var position = void 0,
  112. bReplace = void 0;
  113. if (dropAction) {
  114. //When dnd hover on crosstab, GridDnDManager composes dropAction and call VisDnD.accepts()
  115. position = dropAction.actionSpec.position;
  116. bReplace = dropAction.actionSpec.replace;
  117. var targetSlotAPI = dropAction.actionSpec.slot;
  118. targetSlotId = targetSlotAPI.getDefinition().getId();
  119. } else {
  120. return true;
  121. }
  122. return this.acceptsOlapV2({
  123. targetSlotId: targetSlotId,
  124. sourceSlotId: undefined,
  125. indexInSourceSlot: undefined,
  126. sourceColumns: metadataColumns,
  127. indexInTargetSlot: position,
  128. isReplace: bReplace
  129. });
  130. };
  131. VisDnDUtils.prototype.accepts = function accepts() {
  132. var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  133. var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  134. //No visualizationAPI return false
  135. //No metadata provided return false
  136. if (!this.visualization || !payload.data || !this._isSameDataSource(payload.data)) {
  137. return false;
  138. }
  139. // No restrictions need to be applied when drop target is filter.
  140. var checkHierarchy = !options || options.dropTarget !== ShapingConstants.DROP_TARGET_OPTIONS.FILTER;
  141. if (checkHierarchy) {
  142. /**
  143. * Map of hierarchies used to check if the dragObject follows the drop rules.
  144. */
  145. var oHierarchyMap = {};
  146. var metadataColumns = _.map(payload.data.columns, function (columns) {
  147. return columns.metadataColumn;
  148. });
  149. var metadataColumnsWithMembers = payload.data.utils && payload.data.utils.getColumnsWithMembers();
  150. // Check the metadata item(s) in dragObject
  151. if (!metadataColumns) {
  152. return false;
  153. }
  154. if (ShapingUIUtils.isInvalidDragObject(metadataColumns, oHierarchyMap, metadataColumnsWithMembers)) {
  155. return false;
  156. }
  157. // Check dragObject with widget metadata
  158. // Members from the same hierarchy can only be dropped to same slot.
  159. var projectedMetadataColumns = this._getProjectedDataItemList();
  160. if (options.dropTarget === ShapingConstants.DROP_TARGET_OPTIONS.SLOT) {
  161. var slotMetadataColumnIds = [];
  162. if (options.targetNode) {
  163. var slotId = options.targetNode.getAttribute('data-slot-id');
  164. var slotDataItemList = slotId && this.visualization.getSlots().getSlot(slotId).getDataItemList();
  165. slotMetadataColumnIds = _.map(slotDataItemList, function (dataItem) {
  166. return dataItem.getColumnId() !== SlotAPIHelper.MULTI_MEASURES_SERIES;
  167. }).filter(Boolean);
  168. }
  169. // Get restricted columns that are not in the target slot
  170. var columnsNotInTargetSlot = slotMetadataColumnIds.length ? _.filter(projectedMetadataColumns, function (column) {
  171. return slotMetadataColumnIds.indexOf(column.getId()) === -1;
  172. }) : projectedMetadataColumns;
  173. // Restrict any metadata object from the same hierarchy to be dropped to a different slot
  174. var dragColumnProjected = _.some(columnsNotInTargetSlot, function (column) {
  175. return _.some(metadataColumns, function (dragColumn) {
  176. return column.getId() === dragColumn.getId() && (column.isHierarchy() || column.isNamedSet());
  177. });
  178. });
  179. if (dragColumnProjected) {
  180. return false;
  181. }
  182. }
  183. if (ShapingUIUtils.isInvalidDragObject(projectedMetadataColumns, oHierarchyMap, null, /** metadataColumnsExist */true)) {
  184. return false;
  185. }
  186. }
  187. var expandCollapseFeatureFlag = !this.dashboard.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'expandCollapse', 'disabled');
  188. if (expandCollapseFeatureFlag && this.visualization.getType() === 'Crosstab') {
  189. if (!this._acceptsOlapColumnsV2(payload, options)) {
  190. return false;
  191. }
  192. }
  193. return payload.data && payload.data.utils && payload.data.utils.isValid(options) && METADATA_TYPES.indexOf(payload.type) !== -1 ? true : false;
  194. };
  195. VisDnDUtils.prototype.onDrop = function onDrop(payload) {
  196. return METADATA_TYPES.indexOf(payload.type) !== -1 ? payload.data : null;
  197. };
  198. VisDnDUtils.prototype.mapColumns = function mapColumns(slotId, droppedColumns, options, transactionToken) {
  199. return this.visMapColumnsToSlot.mapColumns(slotId, droppedColumns, options, transactionToken);
  200. };
  201. VisDnDUtils.prototype.acceptsOlapV2 = function acceptsOlapV2(params) {
  202. return this.olapHelper.acceptsOlapV2(params);
  203. };
  204. VisDnDUtils.prototype.addMembersAsLocalFilters = function addMembersAsLocalFilters() {
  205. var _this = this;
  206. var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  207. var transactionToken = arguments[1];
  208. var dataItemList = options.slotAPI ? options.slotAPI.getDataItemList() : this.visualization.getSlots().getDataItemList();
  209. var columns = options.columns ? options.columns.slice() : [];
  210. var removedExistingDataItem = options.columns || [];
  211. var _removeResultFn = function (index) {
  212. if (index > -1 && index < columns.length) {
  213. removedExistingDataItem.splice(index, 1);
  214. }
  215. }.bind(this);
  216. var localFiltersSpec = [];
  217. columns.forEach(function (column) {
  218. var newLocalFilters = column.original.members;
  219. if (newLocalFilters && newLocalFilters.length) {
  220. var hasMappedDatItem = LocalFilterMemberDNDHelper.hasDataItem(dataItemList, column.metadataColumn.getId());
  221. var itemContext = LocalFilterMemberDNDHelper.getItemContext(dataItemList, column.original.metadataColumn);
  222. LocalFilterMemberDNDHelper.addOrUpdateFilter({
  223. bReplace: options.bReplace,
  224. itemContext: itemContext,
  225. localFilters: _this.visualization.getLocalFilters(),
  226. newLocalFilters: newLocalFilters,
  227. localFiltersSpec: localFiltersSpec,
  228. doUpdateFilters: options.doUpdateFilters
  229. }, transactionToken);
  230. var appendMembersToExistingDataItem = hasMappedDatItem && !options.bReplace;
  231. if (appendMembersToExistingDataItem) {
  232. removedExistingDataItem.forEach(function (col, index) {
  233. if (column.metadataColumn.getId() === col.metadataColumn.getId()) {
  234. _removeResultFn(index);
  235. return;
  236. }
  237. });
  238. }
  239. }
  240. });
  241. return localFiltersSpec;
  242. };
  243. VisDnDUtils.prototype.exceedsItemsLimit = function exceedsItemsLimit(countOfItemsToDrop, indexInSlot, addAfter, slot) {
  244. var limit = slot.getDefinition().getMaxItems();
  245. if (typeof limit !== 'number' || limit < 0) {
  246. // no limit verification if maxItems is null or undefined or something else than a positive number (0 is considered as positive in this function)
  247. return false;
  248. }
  249. var mappedItems = slot.getDataItemList().length;
  250. //When dropping on top of an existing slot dataItem, we replace it with the items we're dropping.
  251. //EXCEPTION....for index===-1, we always add to the existing set of items.
  252. //indexInSlot===-1 means add at the end.
  253. //indexInSlot===-1 and addAfter = true means add at the beginning.
  254. var mappedItemsAfterDrop = countOfItemsToDrop + mappedItems - (addAfter || indexInSlot === -1 ? 0 : 1);
  255. return mappedItemsAfterDrop > limit;
  256. };
  257. VisDnDUtils.prototype.validateSupportsOLAP = function validateSupportsOLAP(metadataColumns) {
  258. var supported = true;
  259. var visDefinition = this.visualization.getDefinition();
  260. if (visDefinition.getProperty('supportsOLAP') === false) {
  261. metadataColumns && metadataColumns.forEach(function (metadataColumn) {
  262. if (metadataColumn.isOlapColumn() || metadataColumn.isNamedSet()) {
  263. supported = false;
  264. }
  265. });
  266. }
  267. return supported;
  268. };
  269. return VisDnDUtils;
  270. }();
  271. return VisDnDUtils;
  272. });
  273. //# sourceMappingURL=VisDnDUtils.js.map