'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * Licensed Materials - Property of IBM * IBM Cognos Products: Dashboard * (C) Copyright IBM Corp. 2017, 2020 * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['ca-modeller/shaping', '../nls/StringResources', 'underscore', '../metadata/MetadataColumn', './ShapingConstants', '../../metadataDND/MetadataDNDMapping'], function (Shaping, StringResources, _, MetadataColumn, ShapingConstants, MetadataDNDMapping) { var INVALID_OBJECT_TYPES_IN_PAYLOAD = ['QuerySubject', 'FolderType', 'Folder', 'DrillGroup']; var MODEL_FILTER_TYPE = 'Filter'; var DRAG_ORIGIN = { HIERARCHY: 1, LEVEL: 2, SET: 3, HIERARCHY_MEMBER: 4, SET_MEMBER: 5 }; var ShapingUIUtils = function () { function ShapingUIUtils() { _classCallCheck(this, ShapingUIUtils); } /** * Renders the either the common simple calculation dialog or the global expression editor depending on * whether the object(s) is a query item or the shaping module, respectively. * @param itemIds array of dataitemids which are converted to moserObjects before passing * to the dialog * @return a promise containing the calculation moser object */ ShapingUIUtils.renderCalculationDialog = function renderCalculationDialog(moduleAPI, itemIds, isEditCalculation, options) { var shapingHelper = moduleAPI.getShapingHelper(); //create a global calc from the tree if (!itemIds) { return shapingHelper.openExpressionDialog(shapingHelper.getModule()); } //convert the dataItemIds to moserObjects var elements = []; itemIds.forEach(function (element) { elements.push(moduleAPI.getMoserObject(element)); }); //open the appropriate dialog to create/edit the simple or global calculations if (isEditCalculation && Shaping.getExpressionType(elements[0]) === 'customCalculation') { if (options && options.forceGlobal === true) { return shapingHelper.openExpressionDialog(elements[0], true, { forceGlobal: true }); } else { return shapingHelper.openExpressionDialog(elements[0], true); } } if (options && options.forceGlobal === true) { return shapingHelper.openSimpleCalculationDialog(elements, isEditCalculation, { forceGlobal: true }); } else { return shapingHelper.openSimpleCalculationDialog(elements, isEditCalculation); } }; /** * Renders the Expression dialog * @param itemIds array of dataitemids which are converted to moserObjects before passing * to the dialog * @return a promise containing the calculation moser object */ ShapingUIUtils.renderMemberCalculationDialog = function renderMemberCalculationDialog(moduleAPI, elementId, itemIds, isEditCalculation) { //convert the dataItemIds to moserObjects //var editorMembers = []; var element; element = moduleAPI.getMoserObject(elementId); //NOT sure what to do with the Ids here // itemIds.forEach(function (id) { // editorMembers.push(element.getItem(id)); // }); return moduleAPI.getShapingHelper().openExpressionDialog(element, 'modeler-wa-member', StringResources.get('memberCalculationDialogLabels'), null, itemIds, isEditCalculation); }; /** * Renders the either the simple custom group dialog or the complete custom group dialog from MUI * @param moduleAPI * @param itemId the itemId that can be converted to element * @param isEdit a boolean value indicate if the current dialog is in edit mode * @param mode a JSON object describing how the dialog will behave * @param data a JSON object describing the custom group data info * @return a promise containing the custom group moser object */ ShapingUIUtils.renderCustomGroupDialog = function renderCustomGroupDialog(moduleAPI, itemId, isEdit, data, view) { return moduleAPI.load().then(function () { if (!view) { view = { startView: Shaping.customGroupUtils.getCustomGroupViews().CUSTOM_GROUP_VIEW_NAME }; } var shapingHelper = moduleAPI.getShapingHelper(); var element = moduleAPI.getMoserObject(itemId); return shapingHelper.customGroupAction(element, isEdit, view, data).then(function (response) { var custom_group_success = function custom_group_success(response) { var SUCCESS = Shaping.customGroupUtils.getCustomGroupMessageIds().CUSTOM_GROUP_INT_MSG_SUCCESS; return response.messages && response.messages.length === 1 && response.messages[0].messageId === SUCCESS; }; if (custom_group_success(response)) { return response.data; } else { return Promise.reject(response); } }); }); }; /** * Validates the supplied customGroup context to see if it supports customGroup creation * @param moduleAPI * @param itemId the itemId that can be converted to element * @param isEdit a boolean value indicate if the current dialog is in edit mode * @param view a JSON object describing the view type * @param data a JSON object describing the custom group data info * @return a promise containing the custom group moser object */ ShapingUIUtils.validateCustomGroup = function validateCustomGroup(moduleAPI, itemId, isEdit, data) { var view = { startView: Shaping.customGroupUtils.getCustomGroupViews().CUSTOM_GROUP_VIEW_NAME }; var element = moduleAPI.getMoserObject(itemId); return Shaping.customGroupUtils.validateCustomGroup(element, isEdit, view, data); }; /** * Remove column from module, the events of the shaping model change is listened by dashboard in ShapingModelManager * @param moduleAPI * @param itemId the itemId that can be converted to element * @return a promise */ ShapingUIUtils.removeColumnFromModule = function removeColumnFromModule(moduleAPI, itemId) { return moduleAPI.load().then(function () { var shapingHelper = moduleAPI.getShapingHelper(); var element = moduleAPI.getMoserObject(itemId); shapingHelper.removeFromModule([element]); }); }; ShapingUIUtils.renderGrid = function renderGrid(moduleAPI, enableDataQuality, domNode, selectedId, dashboard) { return moduleAPI.load().then(function () { var shapingHelper = moduleAPI.getShapingHelper(); var props = { onBeginDrag: function onBeginDrag(payload) { ShapingUIUtils.onBeginDrag(moduleAPI, dashboard, payload); }, onEndDrag: function onEndDrag() { shapingHelper.clearSelection(); }, querySubjects: shapingHelper.getModule().basicGetQuerySubject(), selectedId: selectedId, enableDataQuality: enableDataQuality }; shapingHelper.render(Shaping.ShapingTabGrid, props, domNode); }); }; ShapingUIUtils.copySelectedTreeItems = function copySelectedTreeItems(moduleAPI) { var shapingHelper = moduleAPI.getShapingHelper(); var selections = shapingHelper.getSelection(); ShapingUIUtils.selectedTreeItems = selections; ShapingUIUtils.moduleAPI = moduleAPI; }; ShapingUIUtils.clearCopiedTreeItems = function clearCopiedTreeItems() { ShapingUIUtils.selectedTreeItems = undefined; }; ShapingUIUtils.getCopiedTreeItems = function getCopiedTreeItems(moduleAPI, dashboard) { // if this is the first "paste" action into an empty widget, the moduleAPI will be null // because the module has not been established yet. For this case we fall back to the // moduleAPI used at copy time. moduleAPI = moduleAPI ? moduleAPI : ShapingUIUtils.moduleAPI; //Mock a Dnd drag object var copiedItems = ShapingUIUtils.selectedTreeItems; if (!copiedItems) { return null; } var payload = { data: { items: copiedItems }, type: 'MODEL_ITEM' }; ShapingUIUtils.onBeginDrag(moduleAPI, dashboard, payload.data); return payload; }; /** * Renders the metadata tree for the current module * @param {Object} domNode Dom node in which the tree should be rendered */ ShapingUIUtils.renderTree = function renderTree(moduleAPI, dashboard, domNode, callback) { return moduleAPI.load().then(function () { var enableShowNavigationGroups = !(moduleAPI.isOlapPackage() || moduleAPI.getSourceType() === 'data_asset'); var shapingHelper = moduleAPI.getShapingHelper(); var props = { onBeginDrag: function onBeginDrag(payload) { ShapingUIUtils.onBeginDrag(moduleAPI, dashboard, payload); }, onKeyDown: function onKeyDown(key, payload) { ShapingUIUtils.onKeyDown(callback, payload, key, moduleAPI, dashboard); }, onEndDrag: function onEndDrag() { shapingHelper.clearSelection(); }, showModule: false, allowReorder: false, showFullPackage: true, showNavigationGroups: enableShowNavigationGroups, forceGlobalCalcs: false }; shapingHelper.render(Shaping.ShapingTree, props, domNode); }); }; ShapingUIUtils.onKeyDown = function onKeyDown(callback, payload, key, moduleAPI, dashboard) { if (!payload.data) { payload.data = {}; } payload.data.items = payload; ShapingUIUtils.onBeginDrag(moduleAPI, dashboard, payload.data); payload.type = 'MODEL_ITEM'; callback(payload, key); }; ShapingUIUtils.onBeginDrag = function onBeginDrag(moduleAPI, dashboard, payload) { var metadataPayload = ShapingUIUtils.getMetadataColumnsFromDnDPayload(moduleAPI, dashboard, payload); _.extend(payload, metadataPayload); payload.isValid = function (options) { console.warn('isValid is depreacted. Use payload.utils.isValid.'); return ShapingUIUtils.isValid(payload, options); }; }; /** * Gets an array of MetadataColumns for the items in the drop payload * @param {[MoserObjects]} moserObjects The moserJS objects for the items being dropped * @return {[MetadataColumn]} array of MetadataColumn objects */ ShapingUIUtils.getMetadataColumnsFromDnDPayload = function getMetadataColumnsFromDnDPayload(moduleAPI, dashboard, payload) { var moserObjects = payload.items; var metadataDNDMapping = new MetadataDNDMapping(moduleAPI, dashboard, { moserObjects: moserObjects }); var mappResults = metadataDNDMapping.getMappedResults(); var dragColumns = []; mappResults.forEach(function (result) { var mappedMetadataColumn = result.mappedMetadataColumn; var realObj = result.referencedObject || mappedMetadataColumn; var objType = realObj && realObj.getObjectType(); // there are cases, e.g. folderType, wont have corresponding metadataColumn. var metadataColumn = null; if (objType && INVALID_OBJECT_TYPES_IN_PAYLOAD.indexOf(objType) === -1) { metadataColumn = realObj; } var item = { // @todo deprecate all moser objects // Use original.metadataColumn and original.children metadataColumn: metadataColumn, original: { metadataColumn: mappedMetadataColumn || metadataColumn, members: result.members } }; dragColumns.push(item); }); var baseUtils = { isValid: function isValid(options) { return ShapingUIUtils.isValid(payload, options); } }; var extendedUtils = metadataDNDMapping.getUtils(); return { sourceId: moduleAPI.getSourceId(), columns: dragColumns, utils: _.extend(baseUtils, extendedUtils) }; }; ShapingUIUtils.isValid = function isValid() { var payload = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var originalColumns = null; var metadataColumns = null; var columnsWithMembers = null; var columns = payload.columns; // TODO: The metadata column could be created with old APIs and mixed with new APIs, so need to consider both cases // TODO: Should clean up this part once the major clean up code is in for 11.1.7 originalColumns = _.map(columns, function (column) { return column.original.metadataColumn; }); metadataColumns = _.map(columns, function (column) { return column.metadataColumn; }); columnsWithMembers = metadataColumns.length && payload.utils.getColumnsWithMembers(); if (!originalColumns || originalColumns.length === 0 || !metadataColumns || metadataColumns.length === 0) { return false; } var checkModelFilter = false; if (options.fromCanvas || options.fromTemplate) { // If all drag objects are model filter, we don't allow to drop them in canvas, template container or filterDock. // If model filters are dropped along with other items, then we accept the drop in this case checkModelFilter = true; } var modelFilterCount = 0; for (var i = 0; i < originalColumns.length; ++i) { var objType = originalColumns[i] && originalColumns[i].getObjectType(); if (!objType || INVALID_OBJECT_TYPES_IN_PAYLOAD.indexOf(objType) >= 0) { return false; } if (objType === MODEL_FILTER_TYPE) { // do not accept drop if object is model filter and is being dropped to non-filter data slot in live widget (alone or not) if (options.dropTarget && options.dropTarget !== ShapingConstants.DROP_TARGET_OPTIONS.FILTER) { return false; } modelFilterCount++; } } if (checkModelFilter && modelFilterCount === originalColumns.length) { return false; } // Check the metadata columns. if (this.isInvalidDragObject(metadataColumns, null, columnsWithMembers)) { return false; } return true; }; /** * Check whether the drag object violate any rules and pass the result back to the * DnD manager so that it can determine if the drop is allowed. * For OLAP sources, within the same hierarchy the following rules need to be applied: * 1) one hierarchy is allowed, i.e the current hierarchy is only allowed to be dropped once * 2) one named set is allowed * 3) any number of members from a hierarchy or a namedSet is allowed * 4) any number of levels or properties is allowed * 5) No mix is allowed between 1), 2), 3) and 4), but mix is allowed between 1) and 3), or 2) and 3) * @param metadataColumns - the metadata columns used to compare with the cached dimensions and hierarchies. * @param oHierarchyMap - Map of hierarchies, used to check conflict of the existing metadata and the new dragged dataItem. * @example * { * hierarchyID1: [DRAG_ORIGIN.HIERARCHY, DRAG_ORIGIN.HIERARCHY_MEMBER], * hierarchyID2: [DRAG_ORIGIN.LEVEL] * } * @param metadataColumnsWithMembers - Object with keys are column IDs and values are the members from the corresponding column. * @param metadataColumnsExist - boolean to indicate whether the first parameter: metadataColumns are from current dragged columns or projected columns in Viz. * The flag is required with member support. For example drop a member to one slot, then a member to another slot of the same hierarchy. * Once the same column were mapped to 2 slots, there is nothing to indicate the 2 columns are built from members. * @returns {boolean} true if invalid drag metadata item is found. */ ShapingUIUtils.isInvalidDragObject = function isInvalidDragObject(metadataColumns, oHierarchyMap, metadataColumnsWithMembers, metadataColumnsExist) { var _this = this; if ((!oHierarchyMap || _.isEmpty(oHierarchyMap)) && metadataColumnsExist) { // metadataColumns are already projected return false; } oHierarchyMap = oHierarchyMap || {}; return _.some(metadataColumns, function (metadataColumn) { return !metadataColumn || _this._canNotDropMetadata(oHierarchyMap, metadataColumn, metadataColumnsWithMembers, metadataColumnsExist); }); }; ShapingUIUtils._canNotDropMetadata = function _canNotDropMetadata(oHierarchyMap, metadataColumn, metadataColumnsWithMembers, metadataColumnsExist) { var hierarchyID = void 0; var canNotDropMetadata = void 0; metadataColumnsWithMembers = metadataColumnsWithMembers || {}; var isMemberColumn = function isMemberColumn(hierarchyID) { return metadataColumnsWithMembers[hierarchyID] !== undefined && !_.isEmpty(metadataColumnsWithMembers[hierarchyID]); }; var origin = null; if (metadataColumn.isHierarchy && metadataColumn.isHierarchy()) { hierarchyID = metadataColumn.getId(); origin = isMemberColumn(hierarchyID) ? DRAG_ORIGIN.HIERARCHY_MEMBER : DRAG_ORIGIN.HIERARCHY; } else if (!metadataColumn.isMissing() && (metadataColumn.isLevel() || metadataColumn.isProperty() || metadataColumn.isNamedSet())) { var parent = metadataColumn.getParent(); hierarchyID = parent.getId(); if (!hierarchyID) { hierarchyID = metadataColumn.getReferencedHierarchyId(); } var isNamedSet = metadataColumn.isNamedSet(); origin = isNamedSet ? isMemberColumn(hierarchyID) ? DRAG_ORIGIN.SET_MEMBER : DRAG_ORIGIN.SET : DRAG_ORIGIN.LEVEL; } else { // For all the other cases, return false so the drag and drop is not restricted. return false; } canNotDropMetadata = this._isRestrictedMetadata(oHierarchyMap, hierarchyID, origin); if (!metadataColumnsExist) { this._addMetadataToMap(oHierarchyMap, hierarchyID, origin); } return canNotDropMetadata; }; /** * @returns {boolean} true if the metadata item is restricted to be dropped. */ ShapingUIUtils._isRestrictedMetadata = function _isRestrictedMetadata(oHierarchyMap, hierarchyID, origin) { var hierarchyOrigins = oHierarchyMap[hierarchyID]; if (!hierarchyOrigins || !hierarchyOrigins.length) { return false; } switch (origin) { case DRAG_ORIGIN.HIERARCHY: return _.some(hierarchyOrigins, function (hierarchyOrigin) { return hierarchyOrigin !== DRAG_ORIGIN.HIERARCHY_MEMBER; }); case DRAG_ORIGIN.HIERARCHY_MEMBER: return _.some(hierarchyOrigins, function (hierarchyOrigin) { return hierarchyOrigin !== DRAG_ORIGIN.HIERARCHY && hierarchyOrigin !== DRAG_ORIGIN.HIERARCHY_MEMBER; }); case DRAG_ORIGIN.SET: return _.some(hierarchyOrigins, function (hierarchyOrigin) { return hierarchyOrigin !== DRAG_ORIGIN.SET_MEMBER; }); case DRAG_ORIGIN.SET_MEMBER: return _.some(hierarchyOrigins, function (hierarchyOrigin) { return hierarchyOrigin !== DRAG_ORIGIN.SET && hierarchyOrigin === DRAG_ORIGIN.SET_MEMBER; }); case DRAG_ORIGIN.LEVEL: return _.some(hierarchyOrigins, function (hierarchyOrigin) { return hierarchyOrigin !== DRAG_ORIGIN.LEVEL; }); default: return false; } }; // Store the metadata to map and use the map to check next metadata object. ShapingUIUtils._addMetadataToMap = function _addMetadataToMap(oHierarchyMap, hierID, origin) { if (!oHierarchyMap[hierID]) { oHierarchyMap[hierID] = []; } if (oHierarchyMap[hierID].indexOf(origin) === -1) { oHierarchyMap[hierID].push(origin); } }; return ShapingUIUtils; }(); return ShapingUIUtils; }); //# sourceMappingURL=ShapingUIUtils.js.map