'use strict'; /** * Licensed Materials - Property of IBM * * (C) Copyright IBM Corp. 2016, 2018 * * US Government Users Restricted Rights - Use, duplication or disclosure * restricted by GSA ADP Schedule Contract with IBM Corp. */ define(['../lib/@waca/core-client/js/core-client/ui/core/Class', '../DynamicFileLoader', '../lib/@waca/core-client/js/core-client/nls/StringResources', '../lib/@waca/core-client/js/core-client/utils/Deferred', 'underscore'], function (BaseClass, DynamicFileLoader, StringResources, Deferred, _) { 'use strict'; var PromptManager = BaseClass.extend({ SEARCH_AND_SELECT: 'searchAndSelect', INPUT_BOX: 'inputBox', CALENDAR: 'calendar', RANGE: 'range', CANCEL: 'cancelPromptDialog', promptModules: { searchAndSelect: 'dashboard-analytics/prompts/controls/SearchAndSelectPromptView', inputBox: 'dashboard-analytics/prompts/controls/InputPromptView', calendar: 'dashboard-analytics/prompts/controls/DateTimePromptView', range: 'dashboard-analytics/prompts/controls/RangePromptView' }, /** * @classdesc Prompt manager class to handle prompt related gestures. * @constructs * @public * */ init: function init() { PromptManager.inherited('init', this, arguments); this._inProgressMap = {}; this._pendingPrompts = []; } }); /** * @public * @return true if the response status is prompt fault. */ PromptManager.prototype.isPromptFault = function (data) { if (!data.responseJSON || !data.responseJSON.errors || !data.responseJSON.errors.length) { return false; } return data.status === 412; }; /** * @public api to open prompt view. * * @param {Object} options - Mandatory: set of parameters to open the prompt. @param {Object} options.promptSpec - Mandatory: the prompt info used to open the prompt dialog. * @param {Object} options.logger - mandatory: the logger. * @param {Object} options.preferences - mandatory: preferences. * @param {String} options.packageType - mandatory: the package type, e.g. module, package etc. * @param {String} options.id - mandatory: the package store id. * @param {Object} options.whenSingleItemQueryReady - Optional: the callback function to get distinct prompt values. * @param {Object} options.whenColumnsMinMaxQueryReady - Optional: the callback function to get min / max range prompt values. * @example * openPromptView({ * promptSpec: this._getPromptInfo(data), * logger: logger, * preferences: preferences, * packageType: this.dataSetDefinition.type, * id: this.id, * whenColumnsMinMaxQueryReady: this.whenColumnsMinMaxQueryReady.bind(this), * whenSingleItemQueryReady: this.whenSingleItemQueryReady.bind(this), * getPromptSpec: this._getPromptSpec.bind(this) * }); * * Promopt Info: * { * "promptType": "", * "modulePath": null, * "capabilities": { * "multivalued": true, * "optional": false, * "discreteValue": true * }, * "modelFilterItem": "[great_outdoors_warehouse_DB2].[EMP_EMPLOYEE_DIM].[CITY]", * "dataType": "xsdString", * "modelPath": null, * "caption": "", * "parameterName": "multiPrompt", * "name": "multiPrompt", * "errorCode": "QF-888" * } * */ PromptManager.prototype.openPromptView = function (options) { var _this = this; var deferred = new Deferred(); this.logger = options.logger; if (!options.promptSpec || options.promptSpec.length === 0) { deferred.resolve([]); return deferred.promise; } if (options.promptSpec[0].involvesOlapColumn) { deferred.reject(new Error('unSupportedPromptType')); return deferred.promise; } switch (options.promptSpec[0].errorCode) { case 'QF-888': // The prompt defined in FM or Module. var dlgOptions; var aDialogDeferred = []; // Array of promises of prompt dialogs when drag and drop multiple prompt items at the same. var aResovledPromptNames = this._resovleSavedPrompts(options, aDialogDeferred); // Remove the resolved prompt spec. if (aResovledPromptNames.length > 0) { options.promptSpec = _.filter(options.promptSpec, function (promptInfo) { return _.indexOf(aResovledPromptNames, promptInfo.name) < 0; }); } if (!options.promptSpec || !options.promptSpec.length) { // All required prompts are resolved. return this._resolvePromptViews(aDialogDeferred); } else { // If prompting is disabled for preview, do not prompting user, just return specific error message and let the upper stack (explore) handle it if (options.isPreview) { deferred.reject(new Error('promptingIsDisabled')); return deferred.promise; } // There are unresolved prompt(s). Continue to open prompt dialog. return this._buildPromptInfo(options).then(function (aPromptInfo) { _.each(aPromptInfo, function (promptInfo) { dlgOptions = {}; _.extend(dlgOptions, options); dlgOptions.promptInfo = promptInfo; dlgOptions.key = promptInfo.name; dlgOptions.promptDialogName = 'dashboard-analytics/lib/@waca/core-client/js/core-client/ui/dialogs/GenericViewDialog'; aDialogDeferred.push(_this._showPromptView(dlgOptions)); }); return _this._resolvePromptViews(aDialogDeferred); }); } default: } return deferred.promise; }; PromptManager.prototype._showPromptView = function (dlgOptions, dfd) { var key = dlgOptions.key; var deferred = this._inProgressMap[key]; if (!deferred) { deferred = dfd || new Deferred(); // Only continue when the prompt is not canceled yet. if (!dlgOptions.promptInfo || !dlgOptions.promptInfo.canceled) { if (this._isPrompting()) { var pending = this._getPendingPrompt(key); if (pending) { deferred = pending.deferred; } else { this._pendingPrompts.push({ promptFunction: this._showPromptView.bind(this, dlgOptions, deferred), id: key, deferred: deferred }); } } else { this._inProgressMap[key] = deferred; this._prepareAndOpenPromptDialog(dlgOptions, deferred); } } } return deferred.promise; }; PromptManager.prototype._prepareAndOpenPromptDialog = function (dlgOptions, deferred) { var _this2 = this; switch (dlgOptions.promptSpec[0].errorCode) { case 'QF-888': var label = dlgOptions.promptInfo.caption ? dlgOptions.promptInfo.caption : dlgOptions.promptInfo.name; dlgOptions.viewTitle = StringResources.get('promptControlTitle', { paramLabel: label }); switch (dlgOptions.promptInfo.promptModuleName) { case this.INPUT_BOX: dlgOptions.viewOptions = { label: label }; break; case this.CALENDAR: dlgOptions.viewOptions = { columnId: dlgOptions.promptInfo.modelFilterItem, timezone: dlgOptions.preferences.timeZoneID, enableOk: this.enableOk.bind(this) }; break; case this.SEARCH_AND_SELECT: if (dlgOptions.promptInfo.promptValuesPromise) { dlgOptions.promptInfo.promptValuesPromise.then(function (responseData) { var promptValues = _this2._getDistinctPromptValuesFromResponse(responseData); dlgOptions.viewOptions = { columnId: dlgOptions.promptInfo.modelFilterItem, promptModuleName: dlgOptions.promptInfo.promptModuleName, name: dlgOptions.promptInfo.name, singleSelect: dlgOptions.promptInfo.singleSelect, viewTitle: dlgOptions.viewTitle, dataType: dlgOptions.promptInfo.dataType, promptValues: promptValues, capabilities: dlgOptions.promptInfo.capabilities, whenSingleItemQueryReady: dlgOptions.whenSingleItemQueryReady }; _this2._openPromptDialog(dlgOptions, deferred); }).catch(function (jqXHR) { // Glass AjaxService error parameters. deferred.reject(_.extend(jqXHR, { name: dlgOptions.promptInfo.name })); }); } break; case this.RANGE: dlgOptions.viewOptions = { columnId: dlgOptions.promptInfo.modelFilterItem, whenColumnsMinMaxQueryReady: dlgOptions.whenColumnsMinMaxQueryReady, isMultiPrompt: dlgOptions.promptInfo.isMultiPrompt, postAutoAggregation: false // dlgOptions.promptInfo.hasOwnProperty('postAutoAggregation') ? dlgOptions.promptInfo.postAutoAggregation : !dlgOptions.promptInfo.isMultiPrompt }; break; default: } if (!dlgOptions.promptInfo.promptValuesPromise) { _.extend(dlgOptions.viewOptions, { viewTitle: dlgOptions.viewTitle, promptModuleName: dlgOptions.promptInfo.promptModuleName, name: dlgOptions.promptInfo.name, dataType: dlgOptions.promptInfo.dataType, capabilities: dlgOptions.promptInfo.capabilities }); this._openPromptDialog(dlgOptions, deferred); } break; default: } }; PromptManager.prototype._openPromptDialog = function (dlgOptions, deferred) { var _this3 = this; DynamicFileLoader.load([this.promptModules[dlgOptions.promptInfo.promptModuleName]]).then(function (viewModule) { dlgOptions.dlgClassOptions = dlgOptions.dlgClassOptions || { 'buttons': [{ 'text': StringResources.get('ok'), 'handler': _this3.onOk.bind(_this3, dlgOptions, deferred), 'type': 'primary', 'defaultId': 'ok_button' }, { 'text': StringResources.get('cancel'), 'handler': _this3.onCancel.bind(_this3, dlgOptions, deferred), 'type': 'secondary', 'defaultId': 'cancel_button' }], 'title': dlgOptions.viewOptions.viewTitle, 'titleAriaLabel': StringResources.get('promptDialogTitle', { paramLabel: dlgOptions.label }), 'viewClass': viewModule[0], 'viewOptions': dlgOptions.viewOptions }; var currentSpec = _.find(dlgOptions.promptSpec, function (promptSpec) { return dlgOptions.key === promptSpec.name; }); if (currentSpec && currentSpec.values) { dlgOptions.viewOptions.defaultValues = currentSpec.values; } dlgOptions.viewOptions.enableOk = _this3.enableOk.bind(_this3); return _this3._openDialog(dlgOptions); }).then(function () { if (_this3.promptDialog.viewOptions.promptModuleName !== _this3.RANGE && _this3.promptDialog.viewOptions.promptModuleName !== _this3.CALENDAR) { _this3.promptDialog.disableOk(); } }).catch(function () { if (_this3.logger) { _this3.logger.error('Could not open prompt dialog', dlgOptions); } }); }; PromptManager.prototype._openDialog = function (dlgOptions) { var _this4 = this; var deferred = new Deferred(); DynamicFileLoader.load([dlgOptions.promptDialogName]).then(function (modules) { var PromptDialog = modules[0]; var pDialog = new PromptDialog(dlgOptions.dlgClassOptions); _this4.promptDialog = pDialog; pDialog.open(); deferred.resolve(); }); return deferred.promise; }; PromptManager.prototype.onOk = function (options, deferred) { this._removeInProgress(options.key); var promptVals; var aObjPromptVals = []; if (this.promptDialog.view.getPromptValues) { promptVals = this.promptDialog.view.getPromptValues(); } else { promptVals = []; } _.each(promptVals, function (value) { // Normalize the result. if (!value.d || !value.u) { value = { 'd': value, 'u': value }; } aObjPromptVals.push(value); }); var resolvedPromptSpec = _.find(options.promptSpec, function (promptInfo) { return promptInfo.name === options.key; }); if (this.promptDialog.view.getAdditionalOptions) { _.extend(resolvedPromptSpec, this.promptDialog.view.getAdditionalOptions()); } this.promptDialog.hide(); // Close the prompt dialog before resolve the result. deferred.resolve(_.extend(resolvedPromptSpec, { values: aObjPromptVals })); }; PromptManager.prototype.onCancel = function (options, deferred) { // Cancel one prompt dialog should trigger cancel of all requried prompt actions since // all of the non-optional prompts are required for the query to run. _.each(options.promptSpec, function (spec) { this._cleanPromptCache(spec.name); spec.canceled = true; }, this); this.promptDialog.hide(); deferred.reject(new Error(this.CANCEL)); }; PromptManager.prototype.enableOk = function (bEnabled) { this.promptDialog.enableOk(bEnabled); }; PromptManager.prototype._getPendingPrompt = function (id) { var pending = _.find(this._pendingPrompts, function (prompt) { return prompt.id === id; }); return pending; }; PromptManager.prototype._executeNextPrompt = function () { if (this._pendingPrompts.length > 0) { this._pendingPrompts[0].promptFunction(); this._pendingPrompts.splice(0, 1); } }; PromptManager.prototype._removeInProgress = function (id) { delete this._inProgressMap[id]; this._executeNextPrompt(); }; PromptManager.prototype._cleanPromptCache = function (id) { delete this._inProgressMap[id]; // Cancel all for (var i = 0; i < this._pendingPrompts.length; i++) { if (this._pendingPrompts[i].id === id) { this._pendingPrompts.splice(i, 1); break; } } }; PromptManager.prototype._isPrompting = function () { return _.size(this._inProgressMap) > 0; }; PromptManager.prototype._resovleSavedPrompts = function (options, aDialogDeferred) { var aResolved = []; _.each(options.promptSpec, function (promptInfo) { // Note: when re-prompt, we don't pass getPromptSpec function so the saved prompt values won't be resolved. // Instead the prompt dialog will be displayed with saved prompt values. if (options.getPromptSpec) { var promptSpec; promptSpec = options.getPromptSpec(promptInfo.name); if (promptSpec) { promptSpec.isMultiPrompt = promptInfo.isMultiPrompt; aDialogDeferred.push(Promise.resolve(promptSpec)); aResolved.push(promptInfo.name); } } }); return aResolved; }; PromptManager.prototype._buildPromptInfo = function (options) { var _this5 = this; var deferred = new Deferred(); var aParamInfo = []; _.each(options.promptSpec, function (promptInfo) { // Remove the cancel flag when new prompt or reprompt happens. delete promptInfo.canceled; promptInfo.promptModuleName = _this5._getPromptModuleName(promptInfo); if (!promptInfo.promptModuleName) { deferred.reject(new Error('unSupportedPromptType')); return; } promptInfo.singleSelect = promptInfo.promptModuleName === _this5.SEARCH_AND_SELECT && !promptInfo.capabilities.multivalued; promptInfo.columnId = promptInfo.modelFilterItem; promptInfo.promptValuesPromise = promptInfo.promptModuleName === _this5.SEARCH_AND_SELECT ? options.whenSingleItemQueryReady({ 'column': _.pick(promptInfo, 'columnId'), 'nativeQuery': true, 'promptName': options.name, 'queryHints': { 'promptValuesQuery': 'true' } }) : null; aParamInfo.push(promptInfo); }); deferred.resolve(aParamInfo); return deferred.promise; }; /* * The logic to decide what prompt control to show. * */ PromptManager.prototype._getPromptModuleName = function (promptInfo) { var promptModuleName; switch (promptInfo.dataType) { case 'xsdDate': case 'xsdDateTime': case 'xsdTime': if (promptInfo.capabilities.multivalued && promptInfo.capabilities.discreteValue && promptInfo.modelFilterItem) { promptModuleName = this.SEARCH_AND_SELECT; } else { promptModuleName = this.CALENDAR; } break; case 'xsdInt': case 'xsdLong': case 'xsdShort': case 'xsdFloat': case 'xsdDecimal': case 'xsdDouble': if (promptInfo.modelFilterItem) { if (promptInfo.capabilities.multivalued) { if (promptInfo.capabilities.discreteValue) { promptModuleName = this.SEARCH_AND_SELECT; } else { promptModuleName = this.RANGE; } } else { promptModuleName = this.INPUT_BOX; } } else { promptModuleName = this.INPUT_BOX; } break; case 'xsdString': if (promptInfo.modelFilterItem) { promptModuleName = this.SEARCH_AND_SELECT; } else { promptModuleName = this.INPUT_BOX; } break; default: } return promptModuleName; }; /* * @param {Object} responseData - The response data from ajax call. * */ PromptManager.prototype._getDistinctPromptValuesFromResponse = function (resultData) { var resultRowSize = resultData.getDatapointCount(); var aResults = []; for (var rowIndex = 0; rowIndex < resultRowSize; rowIndex++) { // Only one column and one tuple part for singleItemQuery result. aResults.push(resultData.getCellValue(rowIndex, 0)[0]); } return aResults; }; PromptManager.prototype._resolvePromptViews = function (aDialogDeferred) { var _this6 = this; return Promise.all(aDialogDeferred).then(function (resolvedPrompts) { var parameterValues = []; _.each(resolvedPrompts, function (resolvedPrompt) { parameterValues = parameterValues.concat(resolvedPrompt); }); return parameterValues; }).catch(function (error) { if (error.reason && error.reason.name) { _this6._removeInProgress(error.reason.name); } throw error; // re-throw }); }; return new PromptManager(); }); //# sourceMappingURL=PromptManager.js.map