12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220 |
- 'use strict';
- var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
- 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, 2021
- *|
- *| US Government Users Restricted Rights - Use, duplication or disclosure
- *| restricted by GSA ADP Schedule Contract with IBM Corp.
- *+------------------------------------------------------------------------+
- */
- define(['ca-modeller/shaping', 'bi/moser/moser.min', 'underscore', '../../nls/StringResources', '../../metadata/MetadataColumn', '../../utils/DashboardSpecUtil', '../../../lib/@waca/core-client/js/core-client/utils/BrowserUtils', '../../../lib/@waca/core-client/js/core-client/ui/dialogs/ConfirmationDialog', '../../../apiHelpers/SlotAPIHelper'], function (Shaping, MoserJS, _, StringResources, MetadataColumn, DashboardSpecUtil, BrowserUtils, ConfirmationDialog, SlotAPIHelper) {
- 'use strict';
- var MAP_SOURCETYPE_TO_USESPECTYPE = {
- uploadedFile: MoserJS.default.UseSpecType.FILE,
- 'package': MoserJS.default.UseSpecType.PACKAGE,
- dataSet2: MoserJS.default.UseSpecType.DATASET,
- module: MoserJS.default.UseSpecType.MODULE,
- data_asset: MoserJS.default.UseSpecType.WA_DATA_ASSET,
- url: MoserJS.default.UseSpecType.URL,
- report: MoserJS.default.UseSpecType.REPORT,
- socialMediaProject: MoserJS.default.UseSpecType.SOCIAL_MEDIA
- };
- var SOURCE_TYPES_TO_UPDATE = ['dataset2', 'uploadedFile', 'module'];
- var UNWANTED_MOSER_OBJECT_TYPES_FOR_METADATACOLUMNS = [MoserJS.default.MoserObjectTypes.ITEM_TYPE, MoserJS.default.MoserObjectTypes.QUERY_SUBJECT, MoserJS.default.MoserObjectTypes.FOLDER, MoserJS.default.MoserObjectTypes.DEF_LINK_TYPE];
- var ShapingModelManager = function () {
- function ShapingModelManager(options) {
- _classCallCheck(this, ShapingModelManager);
- this.dashboardApi = options.dashboardApi;
- this.sourceModel = options.sourceModel;
- this.logger = this.dashboardApi.getGlassCoreSvc('.Logger');
- this.queryService = this.dashboardApi.getFeature('QueryService');
- this.dashboardApi.on('mode:change', this.onModeChange, this);
- if (options.sourceModel) {
- this.shapingModel = options.sourceModel.get('shaping');
- this.shapingModel.setShapingModelManager(this);
- }
- this.sourceModelManager = options.sourceModelManager;
- this.metadataColumnCache = {};
- // Used to track what kind of module we're dealing with
- this._embeddedModule = true;
- this._queryTypeParam = 'module';
- this._loadedMetadataColumns = {};
- }
- ShapingModelManager.prototype.destroy = function destroy() {
- this._shapingHelper.destroy();
- this._shapingHelper = null;
- this.module = null;
- this.tempModuleLoaded = null;
- };
- ShapingModelManager.prototype.isTemporaryModule = function isTemporaryModule() {
- return this._embeddedModule;
- };
- /**
- * Changing dashboard modes authoring to consume or consume to authoring
- */
- ShapingModelManager.prototype.onModeChange = function onModeChange(payload) {
- if (payload && payload.authoring) {
- return this.ensureTemporaryModule();
- }
- return Promise.resolve(this.module);
- };
- /**
- * Ensures we are working against a temporary module
- */
- ShapingModelManager.prototype.ensureTemporaryModule = function ensureTemporaryModule() {
- var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
- if (this.isTemporaryModule()) {
- return Promise.resolve(this.module);
- } else {
- return this._loadModule(undefined, options).then(this._setModule.bind(this)).then(this.whenTemporaryModuleReady.bind(this)).catch(this._handleLoadError.bind(this, false));
- }
- };
- ShapingModelManager.prototype.addWADerivedAttribute = function addWADerivedAttribute(derivedAttribute) {
- this._initializeFormulaeConverter();
- if (this.formulaeConverter && this.attributeProcessor) {
- var qs = this.module.getQuerySubject()[0];
- var v5Exp = this.formulaeConverter.formulaeToV5Expression(derivedAttribute.formulae, MoserJS.default.ExpressionType.CALCULATION);
- var factory = MoserJS.default.createObjectFactory();
- var qi = factory.createQueryItem();
- qi.setFacetDefinition(factory.createFacetType());
- MoserJS.default.ModuleUtils.generateObjectId(qs, qi);
- var prop = factory.createPropertyType();
- prop.setName('wa_attributeUniqueName');
- prop.setValue(derivedAttribute.uniqueName);
- qi.addProperty(prop);
- // Until MUI calls validate when adding a query item
- //qi.setDatatype('NVARCHAR(100)');
- qi.setLabel(derivedAttribute.caption);
- qi.setExpression(v5Exp);
- this.attributeProcessor.execute(qi, derivedAttribute.formulae[0]);
- // Until we have the latest MUI
- if (this._shapingHelper.expressionAddToModuleWithValidation) {
- this._shapingHelper.expressionAddToModuleWithValidation(qi, qs);
- }
- // big hack - until MUI marks the module as dirty after adding a query item
- //this._shapingHelper.context.store.sessionSave.dirtyTracker._dirtyPointer++;
- }
- return Promise.resolve();
- };
- ShapingModelManager.prototype._initializeFormulaeConverter = function _initializeFormulaeConverter() {
- if (!this.formulaeConverter && this.module) {
- if (MoserJS.default.FormulaeV5Converter) {
- this.formulaeConverter = new MoserJS.default.FormulaeV5Converter();
- this.formulaeConverter.initWithModule(this.module);
- }
- if (MoserJS.default.AttributeProcessor) {
- this.attributeProcessor = new MoserJS.default.AttributeProcessor();
- this.attributeProcessor.initWithModule(this.module);
- }
- }
- };
- ShapingModelManager.prototype._setModule = function _setModule(module) {
- if (this.module) {
- this.clearCache();
- this.module.removeListener(this.moduleEventListener.bind(this));
- }
- this.module = module;
- module.addListener(this.moduleEventListener.bind(this));
- return module;
- };
- /**
- * Creates a shapingHelper and moserJS object. Also makes sure the metadata is loaded
- * @param option module id that can be used to load the module if it already exist in the temporary session
- * @return {Promise} Promise that will be resolve when the module is finished loading
- */
- ShapingModelManager.prototype.load = function load(moduleId, showErrorToast) {
- if (this._shapingHelper) {
- return Promise.resolve();
- }
- return this._createShapingHelper().then(this._loadModule.bind(this, moduleId)).then(this._setModule.bind(this)).catch(this._handleLoadError.bind(this, showErrorToast));
- };
- ShapingModelManager.prototype._createShapingHelper = function _createShapingHelper() {
- var _this = this;
- return this.dashboardApi.getGlassSvc('.DataConnectionServiceFactory').then(function (dataConnectionServiceFactory) {
- return dataConnectionServiceFactory.getDataConnectionResolver({
- onAmbiguousConnectionResolved: function onAmbiguousConnectionResolved() {
- _this.dashboardApi.triggerDashboardEvent('ambiguousConnection:resolved', {
- sourceId: _this.sourceModel.id
- });
- }
- });
- }).then(function (dataConnectionService) {
- var DndManager = _this.dashboardApi.getFeature('DashboardDnd.internal');
- var enableNavigationGroupAction = !(_this.sourceModel.getIsOlapPackage() || _this.sourceModelManager.getType() === 'data_asset');
- var enableCustomGroups = !_this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'customGroups', 'disabled');
- var enableOlapMember = _this.dashboardApi.getGlassCoreSvc('.FeatureChecker').checkValue('dashboard', 'showMembers', 'enabled');
- var options = {};
- _this.dashboardApi.prepareGlassOptions(options);
- _this._shapingHelper = new Shaping.Shaping(options.glassContext, {
- glassDnD: DndManager,
- undoCallback: _this.addToUndoStack.bind(_this),
- confirmations: {
- removeFromModule: _this._removeItemsFromModule.bind(_this)
- },
- featureConfig: {
- filterExpressionCreateAction: true,
- filterExpressionEditAction: true,
- filterExpressionRemoveAction: true,
- calculationAction: true,
- includeImportedObjects: false,
- removeAction: true,
- expressionEditorEditAction: true,
- expressionEditorAction: true,
- filterAction: true,
- navigationGroupAction: enableNavigationGroupAction,
- sortAction: true,
- filterIndividualValues: false,
- showFullPackage: true,
- showMembers: enableOlapMember || !!_this.dashboardApi.getAppConfig('showMembers'),
- formatAction: true,
- useValidationDialog: true,
- scrollableTrees: BrowserUtils.isIPad(),
- showModuleTreeNode: false,
- customGroupCreateAction: enableCustomGroups,
- customGroupReplaceAction: enableCustomGroups
- },
- connectionResolver: dataConnectionService
- });
- _this._shapingHelper.context.shapingHelper = _this._shapingHelper; //Add the shapingHelper to the context so that it can be accessed by context menu operations.
- _this.shapingModel.setShapingHelper(_this._shapingHelper);
- }).catch(function (error) {
- if (_this.logger) {
- _this.logger.error(error, _this);
- }
- });
- };
- // Callback function to resolve either true or false so MUI will contiue or cancel the remove action.
- ShapingModelManager.prototype._removeItemsFromModule = function _removeItemsFromModule() {
- return new Promise(function (resolve) {
- var oConfirmationDialog = new ConfirmationDialog('warning', StringResources.get('delete_confirm'), StringResources.get('calculation_navigation_in_use'));
- oConfirmationDialog.confirm(function () {
- resolve(true);
- }, function () {
- resolve(false);
- });
- });
- };
- /**
- * Ensure the temporary session module is up-to-date for external components to consume
- * @returns {Promise<String>} Promises a module id which can be either:
- * - Temporary session module id (authoring)
- * - Embedded module id (consumption on shaped data source)
- * - Original assert id (consumption on non-shaped data source)
- */
- ShapingModelManager.prototype.saveTemporaryModule = function saveTemporaryModule() {
- var _this2 = this;
- if (this.tempModuleLoaded) {
- return this.tempModuleLoaded.then(function () {
- return _this2._shapingHelper.saveSessionModule();
- });
- }
- return Promise.resolve(this._shapingHelper && this._shapingHelper.getModuleId());
- };
- /**
- * Clears any previously loaded temporary module
- */
- ShapingModelManager.prototype.clearTemporaryModule = function clearTemporaryModule() {
- this.tempModuleLoaded = null;
- };
- /**
- * When a temporary module is loaded and completed
- * @return {Promise} resolved when temporary module is loaded or temporary module is not used
- */
- ShapingModelManager.prototype.whenTemporaryModuleReady = function whenTemporaryModuleReady() {
- return this.tempModuleLoaded || Promise.resolve();
- };
- /**
- * Creates a moserJS module object using the shapingHelper
- * @param {Object} moduleId option id to be used to load the module from - used if we already have the temporary module
- * @param {Object} options.forceTemporaryModule --> Force temp module; even in consume
- * @return {Promise} A promise which will get resolved with the module object
- */
- ShapingModelManager.prototype._loadModule = function _loadModule(moduleId) {
- var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { forceTemporaryModule: false };
- // Most paths leads us to a temp module, default it to true
- this._embeddedModule = true;
- this._queryTypeParam = 'module';
- var isAuthoringMode = this.dashboardApi.getMode() === 'authoring';
- var optimizedMetadataIdList = this.getMetadataSubsetIds();
- var forceTemporaryModule = options.forceTemporaryModule;
- if (this.sourceModel.hasInlineModule()) {
- //////////////////////////
- // # CASE 5: Inline module spec for CDE
- return this._shapingHelper.createInlineModule(this.sourceModel.module, this.shapingModel.moserJSON);
- } else {
- //////////////////////////
- // # CASE 4: Data source IS shaped, dashboard is loaded in authoring mode.
- // Temporary session module is created based off the embedded module
- if (this.shapingModel.moserJSON && (!isAuthoringMode && forceTemporaryModule || !this.shapingModel.embeddedModuleUpToDate || isAuthoringMode)) {
- this.tempModuleLoaded = this._shapingHelper.loadFromJSON(this.shapingModel.moserJSON);
- return this.tempModuleLoaded;
- }
- if (moduleId) {
- this.shapingModel.set({
- shapingId: '__initialShapingID__'
- }, {
- silent: true
- });
- //TODO Verify the use case and validate the inputs
- return this._shapingHelper.loadFromModuleId(moduleId, this.sourceModel.type, optimizedMetadataIdList);
- }
- //////////////////////////
- // # CASE 3: Data source is NOT shaped, dashboard is loaded in authoring mode.
- // Temporary session module is created based off the original asset
- // Create a temp module if we're in authoring and useTempModule wasn't set to false, or if useTempModule was set to true
- if (!isAuthoringMode && forceTemporaryModule || isAuthoringMode && this.sourceModel.useTempModule !== false || this.sourceModel.useTempModule === true) {
- this.tempModuleLoaded = this._shapingHelper.addSource({
- id: this.sourceModel.get('assetId'),
- href: this.sourceModel.get('searchPath'),
- type: MAP_SOURCETYPE_TO_USESPECTYPE[this.sourceModel.get('type')],
- name: this.sourceModel.get('name')
- });
- return this.tempModuleLoaded;
- }
- //////////////////////////
- // # CASE 2: Data source IS shaped, dashboard is loaded in consumption mode.
- // Embedded module is loaded. Embedded module is stored as an attachment of the dashboard in CM.
- this._embeddedModule = false;
- if (this.shapingModel.embeddedModuleId) {
- return this._shapingHelper.loadFromModuleId(this.shapingModel.embeddedModuleId, 'module', optimizedMetadataIdList);
- }
- //////////////////////////
- // # CASE 1: Data source is NOT shaped, dashboard is loaded in consumption mode.
- // We need to pass to MUI the right datasource type that is used inside Moser 'useSpec', instead of the CM datasource type
- var useSpecSourceType = MAP_SOURCETYPE_TO_USESPECTYPE[this.sourceModel.get('type')].value();
- this._queryTypeParam = useSpecSourceType;
- return this._shapingHelper.loadFromModuleId(this.sourceModel.assetId, useSpecSourceType, optimizedMetadataIdList);
- }
- };
- /**
- * Called by the tree/grid when a shaping change happens so we can add to our undo/redo stack
- * @param {Object} undoRedoObj Object that has an undo and redo method that we can call
- * @param {Object} payloadData Optional payload data
- */
- ShapingModelManager.prototype.addToUndoStack = function addToUndoStack(undoRedoObj, payloadData) {
- var newShapingId = this.shapingModel._generateUniqueId('shaping');
- // Will be passed back in the onUndoRedoShapingChange function call
- var callbackPayload = {
- undoRedoObj: undoRedoObj,
- prevValue: this.shapingModel.get('shapingId'),
- value: newShapingId
- };
- var payload = {
- sender: 'ShapingModelManager',
- payloadData: payloadData ? payloadData : null,
- senderContext: {
- applyFn: this._onUndoRedoShapingChange.bind(this, callbackPayload)
- }
- };
- this.shapingModel.set({
- shapingId: newShapingId
- }, payload);
- };
- /**
- * Called by our undoRedoController when the user does an undo/redo of a shaping change
- * @param {Object} callbackPayload Object that was build when adding the information to the undo stack
- * @param {String} value the new value for the shapingId
- */
- ShapingModelManager.prototype._onUndoRedoShapingChange = function _onUndoRedoShapingChange(callbackPayload, value) {
- if (callbackPayload.prevValue === value) {
- callbackPayload.undoRedoObj.undo();
- } else {
- callbackPayload.undoRedoObj.redo();
- }
- // Since we're overriding the default handling of undo/redo make sure we update the model with the value
- this.shapingModel.set({
- shapingId: value
- }, {
- payloadData: {
- skipUndoRedo: true
- }
- });
- };
- ShapingModelManager.prototype.getShapingHelper = function getShapingHelper() {
- return this._shapingHelper;
- };
- ShapingModelManager.prototype.getLocalizedName = function getLocalizedName() {
- return this.sourceModelManager.getLocalizedName();
- };
- /**
- * Handles showing error messages when the module fails to load
- * @return {Promise} Promise that will resolve with an augmented error object once the message is shown
- */
- ShapingModelManager.prototype._handleLoadError = function _handleLoadError(showErrorToast, err) {
- var _this3 = this;
- // If the temp module failed to load make sure we don't think we have one or we'll end up deleting the source module.
- this._embeddedModule = false;
- this.sourceModel.set({
- state: 'error',
- errorCode: err.code
- });
- return this.getLocalizedName().then(function (name) {
- var exists = _this3.sourceModelManager.cmObjectExists;
- err.sourceInfo = {
- exists: exists,
- name: name
- };
- if (showErrorToast !== false) {
- // The missingDataSetData message should be displayed for error code MSR-GEN-0091 (data for the file does not exist)
- if (_this3._isMissingDatasetData()) {
- _this3._showToast(StringResources.get('missingDataSetData'), {
- type: 'warning',
- preventDuplicates: true
- });
- } else {
- _this3._showToast(StringResources.get('errorLoadingSource', {
- sourceName: name
- }));
- }
- }
- return err;
- }).catch(function () {
- err.sourceInfo = {
- exists: false,
- name: _this3.sourceModel.name
- };
- if (showErrorToast !== false) {
- if (_this3.sourceModel.name) {
- _this3._showToast(StringResources.get('errorLoadingSource', {
- sourceName: _this3.sourceModel.name
- }));
- } else {
- _this3._showToast(StringResources.get('errorLoadingSourceMetaData'));
- }
- }
- return err;
- }).finally(function () {
- throw err;
- });
- };
- ShapingModelManager.prototype._isMissingDatasetData = function _isMissingDatasetData() {
- return this.sourceModel.get('errorCode') === 'MSR-GEN-0091' || this.sourceModelManager.getState() === 'error' && this.sourceModelManager.getType() === 'dataSet2' && this.sourceModelManager.cmObjectExists;
- };
- ShapingModelManager.prototype._showToast = function _showToast(msg, options) {
- var toastOptions = options || {
- type: 'error',
- preventDuplicates: true
- };
- this.dashboardApi.showToast(msg, toastOptions);
- };
- /**
- * @param {Object} dashboardInfo object containing optional information used to create headers in dss requestedVersion
- * @param isDirty - if the dashboard is currently in an unsaved state
- * @param dashboardId - dashboard store id
- * @param searchPath - dashboard search path.
- * @param {String} dataSearchPath - model search path
- * @return {Object} object which contains ajax options, such as headers
- */
- ShapingModelManager.prototype._getDashboardOptions = function _getDashboardOptions(dashboardInfo, dataSearchPath, options) {
- var dbOptions = {};
- dbOptions.ajaxOptions = {
- headers: {
- 'x-audit-type': dashboardInfo.type,
- // Only add id and search path if the dashboard is not in the dirty state
- 'x-audit-dashboardId': dashboardInfo.isDirty ? null : dashboardInfo.boardId,
- 'x-audit-searchPath': dashboardInfo.isDirty ? null : encodeURI(dashboardInfo.searchPath),
- 'x-audit-dataSearchPath': encodeURI(dataSearchPath),
- 'x-senderId': options ? options.senderId : null
- }
- };
- if (options && options.lastModified) {
- dbOptions.ajaxOptions.headers['x-model-last-modified'] = options.lastModified;
- }
- if (options && options.queryUserId) {
- dbOptions.ajaxOptions.headers['x-queryuserid'] = options.queryUserId;
- }
- return dbOptions;
- };
- /**
- * Queries DSS for data
- * @param {String} querySpec the query specification sent to DSS
- * @param {Object} options
- *
- * @return {Promise}
- */
- ShapingModelManager.prototype.queryData = function queryData(querySpec, options) {
- return this._queryData(querySpec, this._shapingHelper.getData.bind(this._shapingHelper), options);
- };
- /**
- * Query DSS for predict data
- * @param {String} querySpec the predict query specification sent to DSS
- * @param {Object} options
- *
- * @return {Promise}
- */
- ShapingModelManager.prototype.queryPredictData = function queryPredictData(querySpec, options) {
- return this._queryData(querySpec, this._shapingHelper.getPredictData.bind(this._shapingHelper), options);
- };
- /**
- * Query relationship (Smarts Explore)
- * @param {JSONObject} querySpec
- * @param {Object} options
- *
- * @return {Promise}
- */
- ShapingModelManager.prototype.querySmartsExploreRelationshipData = function querySmartsExploreRelationshipData(querySpec, options) {
- //TODO: Currently, this is called by Explorer to query smarts/relatonship endpoint.
- //Before a common 'prompt error response handler component' is implmented. Explorer
- //forwards queryspec to MUI and delegates MUI to send the request so that it can reuse the
- //DB signon and ambiguous connections signon handlers.
- return this._queryData(querySpec, this._shapingHelper.getExploreRelationshipData.bind(this._shapingHelper), options);
- };
- ShapingModelManager.prototype._queryData = function _queryData(querySpec, getData) {
- var _this4 = this;
- var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
- return this.load().then(this.sourceModelManager.getSearchPath.bind(this.sourceModelManager)).then(function (searchPath) {
- /**
- * We need to find the dashboard information needed for auditing.
- * dashboardInfo object containing optional information used to create headers in dss requestedVersion
- * @param dashboardInfo.isDirty - if the dashboard is currently in an unsaved state
- * @param dashboardInfo.dashboardId - dashboard store id
- * @param dashboardInfo.searchPath - dashboard search path.
- */
- var dashboardInfo = _this4.dashboardApi.getDashboardInfo();
- return new Promise(function (resolve, reject) {
- try {
- getData(querySpec, 'rawResponse', _this4._queryTypeParam, _this4._getDashboardOptions(dashboardInfo, searchPath, options), options.qfb, options.qfbMode).then(resolve).catch(function (error) {
- // Workaround since MUI changes the glass error response. Reset this property so our error handling
- // code will still work
- error.responseJSON = error ? error.data : {};
- if ((typeof querySpec === 'undefined' ? 'undefined' : _typeof(querySpec)) === 'object') {
- error.querySpec = querySpec;
- } else if (querySpec) {
- try {
- // Keep track of the query spec that caused the http error
- error.querySpec = JSON.parse(querySpec);
- } catch (e) {
- _this4.logger.error(e);
- }
- }
- reject(error);
- });
- } catch (error) {
- reject(error);
- }
- });
- });
- };
- ShapingModelManager.prototype.moduleEventListener = function moduleEventListener(notification) {
- if (this._ignoreMoserEvents) {
- return;
- }
- switch (notification.getType()) {
- case MoserJS.default.Notification.ADD:
- //when undo removing of a calculated member, and calculated member is referenced in a widget, the widget will be refershed
- if (notification.getFeatureID() === MoserJS.default.Features.FILTER || notification.getFeatureID() === MoserJS.default.Features.ITEM || notification.getFeatureID() === MoserJS.default.Features.CALCULATION) {
- //moser throws a lot of events for a single action, so we only want to notify at the end of thread execution
- if (!this._hasDebounceNotify) {
- this._debounceShapingNotification = this._createDebouncedShapingNotification();
- }
- this._debounceShapingNotification({
- notification: notification,
- action: 'ADD'
- });
- }
- break;
- case MoserJS.default.Notification.SET:
- case MoserJS.default.Notification.REMOVE:
- {
- this.clearCache();
- if (!this._hasDebounceNotify) {
- var featureID = notification.getFeatureID();
- if (featureID === MoserJS.default.Features.TYPE || featureID === MoserJS.default.Features.SEARCH_PATH || featureID === MoserJS.default.Features.STORE_ID || this._isMembersFolderExpansionNotification(notification)) {
- return;
- }
- this._debounceShapingNotification = this._createDebouncedShapingNotification();
- }
- var action = notification.getType() === MoserJS.default.Notification.SET ? 'SET' : 'REMOVE';
- this._debounceShapingNotification({
- noRefresh: this._checkNotificationProperties(notification, 'propertySetByUser_label'),
- notification: notification,
- action: action
- });
- }
- break;
- default:
- break;
- }
- };
- //check if propertyName is present in notification passed in
- ShapingModelManager.prototype._checkNotificationProperties = function _checkNotificationProperties(notification, propertyName) {
- var notifier = typeof notification.getNotifier === 'function' && notification.getNotifier();
- if (notifier && notifier.property) {
- //return true if specific property name is present in property array
- return _.some(notifier.getProperty(), function (prop) {
- return typeof prop.getName === 'function' && prop.getName() === propertyName;
- });
- } else {
- return notifier && typeof notifier.getName === 'function' && notifier.getName() === propertyName;
- }
- };
- // When the folder "Members" is expanded for the first time (lazy loaded), MUI sends a notification to tell "memberHidden" is changed from value "true" to "false".
- // We should not react to this notification (and more importantly should not trigger shaping model change event) as it has no impact to dashbboard.
- // This method checks if the notification is generated from this action to ignore it.
- ShapingModelManager.prototype._isMembersFolderExpansionNotification = function _isMembersFolderExpansionNotification(notification) {
- if (notification.getNotifier && notification.getNotifier() && notification.getNotifier().name === 'memberHidden') {
- if (notification.oldValue === 'true' && notification.newValue === 'false') {
- return true;
- }
- }
- return false;
- };
- ShapingModelManager.prototype._createDebouncedShapingNotification = function _createDebouncedShapingNotification() {
- var _this5 = this;
- this._hasDebounceNotify = true;
- return _.debounce(function (payload) {
- payload = payload || {};
- payload.sender = {};
- var timeStamp = new Date().toISOString();
- _this5.sourceModelManager.modificationTime = timeStamp;
- _this5.sourceModel.set({
- modificationTime: timeStamp
- }, {
- silent: true
- });
- if (payload.notification.newValue || payload.notification.oldValue) {
- payload.sourceId = _this5.sourceModel.id;
- var jsonParseString = function jsonParseString(value) {
- if (typeof value === 'string') {
- // This might be a JSON string or just a string - we have no way of knowing.
- try {
- return JSON.parse(value.trim());
- } catch (e) {
- return value;
- }
- }
- return value;
- };
- payload.newValue = jsonParseString(payload.notification.newValue);
- payload.oldValue = jsonParseString(payload.notification.oldValue);
- }
- _this5.shapingModel.trigger('shapingmodel:changed', payload);
- _this5._hasDebounceNotify = false;
- if (_this5._unitTestResolve) {
- _this5._unitTestResolve();
- }
- }, 0);
- };
- ShapingModelManager.prototype.getModuleId = function getModuleId() {
- return this._shapingHelper.context.store.moduleId;
- };
- /**
- * Returns a MetadataColumn object
- * @param {String} id The Moser object idForExpression for which to get the metadata for
- * @param {boolean} logNotFound - boolean to log error in console when moser object not found or not
- * @return {MetadataColumn} Object that has APIs to get at the column metadata
- */
- ShapingModelManager.prototype.getMetadataColumn = function getMetadataColumn(id) {
- var logNotFound = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
- if (id && id.indexOf(SlotAPIHelper.MULTI_MEASURES_SERIES) !== 0) {
- if (!this.metadataColumnCache[id]) {
- var moserObject = this.getMoserObject(id);
- if (!moserObject) {
- if (logNotFound && this.logger) {
- this.logger.error('Could not find moser object with id ' + id, this);
- }
- return null;
- }
- this.metadataColumnCache[id] = new MetadataColumn({
- moserObject: moserObject,
- sourceId: this.sourceModel.id,
- queryService: this.queryService
- });
- }
- } else {
- return null;
- }
- return this.metadataColumnCache[id];
- };
- /**
- * Called by the shaping moserVisitor. Mostly broken out into its own funciton for easy unit test
- * @param {[MetadataColumns]} metadataColumns The resulting array of metadata columns
- * @param {Function} Callback to call with each metadataColumn. Callback should return true if the item should be part of the resulting array or false otherwise
- * @param {Boolean} breakOnFirstMatch default to false. If true will stop the search once the first item is found.
- * @param {Obj} moserObj The moser object which we're currently visiting
- * @return true if we should continue visiting the child or moserVistor.BREAK if we should stop visiting
- */
- ShapingModelManager.prototype._moserVisitorCallback = function _moserVisitorCallback(metadataColumns, callback, breakOnFirstMatch, moserObj) {
- var isHidden = moserObj.hidden || moserObj.isHidden && moserObj.isHidden();
- if (isHidden) {
- return false;
- }
- if (UNWANTED_MOSER_OBJECT_TYPES_FOR_METADATACOLUMNS.indexOf(moserObj.getObjectType()) === -1) {
- var id = moserObj.getIdForExpression ? moserObj.getIdForExpression() : null;
- if (id) {
- var metadataColumn = this.metadataColumnCache[id] || new MetadataColumn({
- moserObject: moserObj,
- sourceId: this.sourceModel.id,
- queryService: this.queryService
- });
- this._loadedMetadataColumns[id] = metadataColumn;
- if (callback(metadataColumn)) {
- metadataColumns.push(metadataColumn);
- if (breakOnFirstMatch) {
- return Shaping.moserVisitor.BREAK;
- }
- }
- }
- }
- return true;
- };
- /**
- * [description]
- * @param {Function} Callback to call with each metadataColumn. Callback should return true if the item should be part of the resulting array or false otherwise
- * @param {Boolean} breakOnFirstMatch default to false. If true will stop the search once the first item is found.
- * @return {[MetadataColumns]} Array of MetadataColumn objects
- */
- ShapingModelManager.prototype.getMetadataColumns = function getMetadataColumns(callback, breakOnFirstMatch) {
- if (!this.metadataColumns || callback) {
- this.metadataColumns = [];
- Shaping.moserVisitor(this.module.metadataTreeView, this._moserVisitorCallback.bind(this, this.metadataColumns, callback, breakOnFirstMatch));
- }
- return this.metadataColumns;
- };
- /**
- * Returns a MoserJS object
- * @param {String} id The Moser object idForExpression for which to get the metadata for
- * @return a MoserJS object
- */
- ShapingModelManager.prototype.getMoserObject = function getMoserObject(id) {
- return MoserJS.default.ModuleUtils.getMoserObjectByIdForExpression(id, this.module);
- };
- ShapingModelManager.prototype.clearCache = function clearCache() {
- this.metadataColumnCache = {};
- };
- ShapingModelManager.prototype.relink = function relink(sourceModel) {
- var _this6 = this;
- var relinkPromise = void 0;
- // ignore events fired from MOSER while relink is processiong
- this._ignoreMoserEvents = true;
- if (!this.module) {
- //this happens when open a saved dashboard where its data source had been deleted from CM
- if (this.shapingModel.moserJSON) {
- this._updateUseSpecInMoserJSON(sourceModel);
- relinkPromise = this._shapingHelper.loadFromJSON(this.shapingModel.moserJSON);
- } else {
- relinkPromise = this._shapingHelper.addSource({
- id: sourceModel.get('assetId'),
- href: sourceModel.get('searchPath'),
- type: MAP_SOURCETYPE_TO_USESPECTYPE[sourceModel.get('type')],
- name: sourceModel.get('name')
- });
- }
- } else {
- this.clearCache();
- relinkPromise = this._shapingHelper.relink({
- id: sourceModel.get('assetId'),
- href: sourceModel.get('searchPath'),
- type: MAP_SOURCETYPE_TO_USESPECTYPE[sourceModel.type]
- });
- }
- return relinkPromise.then(function (module) {
- _this6.module = module;
- _this6.shapingModel.moserJSON = MoserJS.default.ModuleUtils.prepareModuleForSave(module);
- var payload = void 0;
- if (sourceModel && SOURCE_TYPES_TO_UPDATE.indexOf(sourceModel.type) !== -1) {
- payload = {
- sourceId: sourceModel.id,
- relinkIdForExpressions: function relinkIdForExpressions() {
- var itemIds = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
- return MoserJS.default.ModuleUtils.relinkIdForExpressions(null, itemIds, _this6.module);
- }
- };
- }
- // After a link any embedded module we have is not longer up to date. Flag it
- // as such so it'll get updated during a save operation.
- _this6.shapingModel.setEmbeddedModuleUpToDate(false);
- return payload;
- }).catch(this._reloadMetadataErrorHandler.bind(this)).finally(function () {
- _this6._ignoreMoserEvents = null;
- });
- };
- ShapingModelManager.prototype._updateUseSpecInMoserJSON = function _updateUseSpecInMoserJSON(sourceModel) {
- var objectFactory = MoserJS.default.createObjectFactory();
- var jsonObjectFactory = MoserJS.default.createJSONObjectFactory(objectFactory);
- var module = jsonObjectFactory.createModule(this.shapingModel.moserJSON);
- var useSpec = module.getUseSpec()[0];
- useSpec.setSearchPath(sourceModel.get('searchPath'));
- useSpec.setStoreID(sourceModel.get('assetId'));
- useSpec.setType(MAP_SOURCETYPE_TO_USESPECTYPE[sourceModel.type]);
- this.shapingModel.moserJSON = MoserJS.default.ModuleUtils.prepareModuleForSave(module);
- };
- ShapingModelManager.prototype.reloadMetadata = function reloadMetadata() {
- this.clearCache();
- // If we just reloaded the metadata for a dataset that had no data in the first place
- // then we need to reload the dashboard so that the module and shapingHelper get initialized correctly
- if (this._isMissingDatasetData()) {
- return this.dashboardApi.reloadFromJSONSpec(this.dashboardApi.getSpec());
- }
- return this._shapingHelper.reloadMetadata().then(this._postReloadMetadataHandler.bind(this, null)).catch(this._reloadMetadataErrorHandler.bind(this));
- };
- ShapingModelManager.prototype.getDrillGroups = function getDrillGroups() {
- return this.module.getDrillGroup();
- };
- ShapingModelManager.prototype._reloadMetadataErrorHandler = function _reloadMetadataErrorHandler(error) {
- //always trigger the event as the widget need to the show error
- this.shapingModel.trigger('shapingmodel:changed', {
- error: error
- });
- throw error;
- };
- ShapingModelManager.prototype._postReloadMetadataHandler = function _postReloadMetadataHandler(sourceModel, module) {
- //set the module again because it might be a new one if there is: a session timeout
- this.module = module;
- var payload = {
- sender: {}
- };
- this.shapingModel.trigger('shapingmodel:changed', payload);
- };
- ShapingModelManager.prototype.getDrillGroupsForColumn = function getDrillGroupsForColumn(columnId) {
- var drillGroups = this.getDrillGroups();
- if (!drillGroups || drillGroups.length === 0) {
- return null;
- }
- return drillGroups.filter(this._containsSelectedColumn.bind(this, columnId));
- };
- ShapingModelManager.prototype._containsSelectedColumn = function _containsSelectedColumn(sourceColumnId, drillGroup) {
- return this._findIndex(drillGroup.getSegment(), 'ref', sourceColumnId) !== -1;
- };
- /*
- * Returns the index at which the object with specified property value is found in the array
- */
- ShapingModelManager.prototype._findIndex = function _findIndex(arrayObjects, sProperty, sValue) {
- if (!arrayObjects) {
- return -1;
- }
- for (var idx = 0; idx < arrayObjects.length; idx++) {
- if (arrayObjects[idx][sProperty] === sValue) {
- return idx;
- }
- }
- return -1;
- };
- ShapingModelManager.prototype.addCalculation = function addCalculation(properties) {
- var calculationExpression = this._shapingHelper.expressionCreateObjectSimpleCalculation(properties, null);
- calculationExpression.setRegularAggregate(MoserJS.default.RegularAggregateType.CALCULATED);
- return this._shapingHelper.expressionAddToModuleWithValidation(calculationExpression).then(function () {
- return calculationExpression.idForExpression;
- });
- };
- /**
- * Returns an array of table names for the module
- *
- * @return {array} An array of table names
- */
- ShapingModelManager.prototype.getTableNames = function getTableNames() {
- var _this7 = this;
- if (!this.tableNames) {
- this.tableNames = [];
- if (this.module) {
- var qs = this.module.getQuerySubject();
- qs.forEach(function (subject) {
- _this7.tableNames.push(subject.getIdentifier());
- });
- }
- }
- return this.tableNames;
- };
- /**
- * Return a bolean indicating whether 2 tables have a join relationship or not
- *
- * @param {string} firstTable - the name of the first table to verify
- * @param {string} secondTable - the name of the table to verify against firstTable
- */
- ShapingModelManager.prototype.tablesHaveJointRelationship = function tablesHaveJointRelationship(firstTable, secondTable) {
- if (firstTable && firstTable.length && secondTable && secondTable.length) {
- if (firstTable === secondTable) {
- //If both names are identical return true if the name exists for the module
- var tables = this.getTableNames();
- return tables.indexOf(firstTable) !== -1;
- } else {
- var tableRelationships = this._getRelationships();
- if (tableRelationships) {
- var isMatched = function isMatched(relationship, value, isLeft) {
- return isLeft ? relationship.left === value : relationship.right === value;
- };
- var jointRelationship = _.find(tableRelationships, function (relationship) {
- return isMatched(relationship, firstTable, true) && isMatched(relationship, secondTable, false) || isMatched(relationship, firstTable, false) && isMatched(relationship, secondTable, true);
- });
- return jointRelationship ? true : false;
- }
- }
- }
- };
- ShapingModelManager.prototype._getRelationships = function _getRelationships() {
- var _this8 = this;
- if (!this.tableRelationships) {
- var existMap = {};
- this.tableRelationships = [];
- var relationships = this.module.getRelationship();
- if (relationships && relationships.length) {
- relationships.forEach(function (relationship) {
- var left = relationship.getLeft();
- var right = relationship.getRight();
- if (left && right) {
- var leftRef = left.getRef();
- var rightRef = right.getRef();
- if (leftRef && rightRef) {
- var key = leftRef + rightRef;
- if (!existMap[key]) {
- existMap[key] = true;
- _this8.tableRelationships.push({
- left: leftRef,
- right: rightRef
- });
- }
- }
- }
- });
- }
- }
- return this.tableRelationships;
- };
- /**
- * Returns the temp module JSON
- */
- ShapingModelManager.prototype.getTemporarySessionModuleJSON = function getTemporarySessionModuleJSON() {
- return this.module.toJSON();
- };
- /**
- *
- * Returns the JSON of a partial copy of the current Moser module containing only the query subjects for the given
- * columnIds and/or calculation. This is required for Smarts alternate vis recommender.
- *
- * @param {array} An array of idForExpressions of columns
- */
- ShapingModelManager.prototype.copyPartialMoserModuleJSON = function copyPartialMoserModuleJSON(columnIds) {
- var _this9 = this;
- var factory = MoserJS.default.createObjectFactory();
- var newModule = MoserJS.default.ModuleUtils.createModule(factory, this.module.getLabel(), this.module.getExpressionLocale());
- var relationships = this.module.getRelationship();
- if (relationships.length) {
- relationships.forEach(function (relationship) {
- return newModule.addRelationship(relationship.clone());
- });
- }
- var querySubjects = [];
- var querySubjectInNewModule = function querySubjectInNewModule(querySubject) {
- return querySubjects.indexOf(querySubject.getIdentifier()) !== -1;
- };
- var isCalculation = function isCalculation(column) {
- return column.getObjectType() === MoserJS['default'].MoserObjectTypes.CALCULATION;
- };
- columnIds.forEach(function (columnId) {
- var metadataColumn = _this9.getMetadataColumn(columnId);
- if (metadataColumn) {
- var querySubject = metadataColumn.getTable();
- if (querySubject && !querySubjectInNewModule(querySubject)) {
- var clonedQS = querySubject.clone();
- querySubjects.push(querySubject.getIdentifier());
- MoserJS.default.ModuleUtils.removeMembers(clonedQS); //TODO: Temporary - see https://jsw.ibm.com/browse/CADBLW-665
- newModule.addQuerySubject(clonedQS);
- } else if (!querySubject && isCalculation(metadataColumn)) {
- newModule.addCalculation(metadataColumn.getMoserObject().clone());
- } else if (!querySubject && !isCalculation(metadataColumn)) {
- _this9.logger.error('Unable to add ' + columnId + ' to the module', _this9);
- }
- }
- });
- return newModule.toJSON();
- };
- ShapingModelManager.prototype._getWidgetSubsetIds = function _getWidgetSubsetIds(spec) {
- var _this10 = this;
- var itemIds = [];
- var widgetSpecs = _.flatten([spec.layout ? DashboardSpecUtil.getWidgetModelList(spec.layout) : [], spec.widgets ? _.values(spec.widgets) : [] //Legacy (pre-11.1.7) specs
- ]);
- _.each(widgetSpecs, function (widget) {
- // collect all data items of widget
- var dataItems = _.chain(widget.data).compact().flatten()
- // only those using the current source
- .filter(function (view) {
- return view.modelRef === _this10.sourceModel.id;
- }).pluck('dataItems').compact().flatten().filter(function (dataItem) {
- return dataItem.itemId !== SlotAPIHelper.MULTI_MEASURES_SERIES;
- }).value();
- if (dataItems.length > 0) {
- // include itemId,seletion context itemId, and customGroup itemId among dataItems
- itemIds.push.apply(itemIds, _.pluck(dataItems, 'itemId'));
- itemIds.push.apply(itemIds, _.chain(dataItems).pluck('selection').compact().flatten().pluck('context').compact().flatten().pluck('itemId').value());
- itemIds.push.apply(itemIds, _.chain(dataItems).pluck('originalCustomGroupItemId').compact().flatten().value());
- // include local filter columnIds
- if (widget.localFilters) {
- itemIds.push.apply(itemIds, _this10._getWidgetLocalFilterSubsetIds(widget.localFilters));
- }
- // include saved prompt columnIds
- if (widget.savedPrompts) {
- itemIds.push.apply(itemIds, _this10._getWidgetSavedPromptsSubsetIds(widget.savedPrompts));
- }
- }
- });
- return itemIds;
- };
- ShapingModelManager.prototype._getWidgetLocalFilterSubsetIds = function _getWidgetLocalFilterSubsetIds(localFilters) {
- var _this11 = this;
- var ids = [];
- _.each(localFilters, function (filter) {
- // filter consists with:
- // operator, values and columnId (optional)
- // when columnId is omitted, the values would contain the compound filter
- if ('columnId' in filter) {
- ids.push(filter.columnId);
- } else if ('operator' in filter) {
- // handle the nested filters recurssively
- ids.push.apply(ids, _this11._getWidgetLocalFilterSubsetIds(filter.values));
- }
- });
- return ids;
- };
- ShapingModelManager.prototype._getWidgetSavedPromptsSubsetIds = function _getWidgetSavedPromptsSubsetIds(savedPrompts) {
- var ids = [];
- for (var key in savedPrompts) {
- if (savedPrompts[key]['modelFilterItem']) {
- ids.push(savedPrompts[key]['modelFilterItem']);
- }
- }
- return ids;
- };
- ShapingModelManager.prototype._getPageContextSubsetIds = function _getPageContextSubsetIds(spec) {
- var _this12 = this;
- return _.chain(spec.pageContext)
- // only those using the current source
- .filter(function (pageContext) {
- return pageContext.sourceId === _this12.sourceModel.id;
- })
- // for each page context hierarchyUniqueNames
- .pluck('hierarchyUniqueNames').compact().flatten().value();
- };
- ShapingModelManager.prototype.getMetadataSubsetIds = function getMetadataSubsetIds() {
- // no need for optimization on authoring mode
- // OR temporary module is already loaded
- // OR dealing with inline module (DaaS)
- if (this.dashboardApi.getMode() === 'authoring' || this.tempModuleLoaded || this.sourceModel.hasInlineModule()) {
- return;
- }
- if (!this.metatdataSubsetIds) {
- var boardModel = this.dashboardApi.getFeature('internal').getBoardModel();
- var dataSourcesMoser = this.dashboardApi.getFeature('DataSources.moser');
- // During upgrade we won't have a boardModel yet.
- if (boardModel) {
- var spec = this.dashboardApi.getFeature('Serializer').toJSON();
- // during the upgrade the spec is expected to be undefined
- if (spec) {
- // merge the widget and page context subset item ids
- // @todo the first two should register as metadataSubsetIds providers
- // so these direct dependancies are eliminated
- var itemIds = [];
- itemIds.push.apply(itemIds, this._getWidgetSubsetIds(spec));
- itemIds.push.apply(itemIds, this._getPageContextSubsetIds(spec));
- itemIds.push.apply(itemIds, dataSourcesMoser.getMetadataSubsetIds());
- this.metatdataSubsetIds = _.uniq(itemIds);
- }
- }
- }
- return this.metatdataSubsetIds;
- };
- return ShapingModelManager;
- }();
- return ShapingModelManager;
- });
- //# sourceMappingURL=ShapingModelManager.js.map
|