src/sap/pdms/ipro/api/IntentManager.js
/**
* @typedef {string} IntentType An intent type
* /
/**
* @typedef {Object<IntentType, ActionMetadata>} ActionsMetadata
* @desc The metadata of a collection of actions implemented in one action.js file.
* @example <caption>Sample ActionsMetadata</caption>
* {
* sampleAlertAction: {
* execute: function(options() {
* ...
* })
* }
* }
*/
/**
* @typedef {Object} ActionMetadata
* @desc The metadata of an action.
* @property {ActionExecution} execute - The execute function of an action
* @property {!string} apiVersion - The API version of an action. This document describes API version "3.0.0". `apiVersion` adheres to [semantic versioning](http://semver.org/).
*/
/**
* Intent manager
*/
export default class IntentManager {
constructor() {
this._remoteActionsMapPromise = null;
this._adhocActionsMap = new Map();
}
/**
* Registers an adhoc action
* @param {IntentType} intentType intent type
* @param {ActionMetadata} actionMetadata the metadata of the action implementing the intent
* @return {void}
*/
addAdhocAction(intentType, actionMetadata) {
this._adhocActionsMap.set(intentType, actionMetadata);
}
_fetchRemoteActionServiceEntries() {
// if it's already being loaded just return the existing promise to unnecessary reloading and race conditions.
if (this._remoteActionsMapPromise && this._remoteActionsMapPromise.isPending()) {
return this._remoteActionsMapPromise;
}
if (this._remoteActionsMapPromise && this._remoteActionsMapPromise.isFulfilled()) {
return Promise.resolve(this._remoteActionsMapPromise.value());
}
return this._remoteActionsMapPromise = Promise.resolve(jQuery.ajax({
url: '/platform/service-catalog/api/v1/service-entries?serviceTypeId=com.sap.pdms.Action',
dataType: 'json',
method: 'GET'
})).then(actionServiceEntries => {
const actionMap = new Map();
actionServiceEntries.forEach(action => {
if (!actionMap.has(action.options.intentType)) {
actionMap.set(action.options.intentType, [{serviceEntry: action}]);
} else {
actionMap.get(action.options.intentType).push({serviceEntry: action});
}
});
return actionMap;
}).catch(err => {
throw new Error('Cannot get actions from service catalog because of: ' + err);
});
};
/**
* Executes an intent
* @param {IntentType} intentType intent type
* @param {Object} options the input options for a given intent
* @return {Promise<Object>} Promise that resolves to a return object for a given intent
*/
executeIntent(intentType, options) {
// adhoc actions take higher precedence
if (this._adhocActionsMap.has(intentType)) {
// there is an adhoc action
return Promise.resolve(this._adhocActionsMap.get(intentType).execute(options));
}
return this._fetchRemoteActionServiceEntries()
.then(actionMap => {
if (!actionMap.has(intentType)) {
// no implementation
throw new Error("no implementation for intentType " + intentType);
}
// inject baseUrl if not already set
if(!options.baseUrl) {
options.baseUrl = actionMap.get(intentType)[0].serviceEntry.serviceUrl;
}
// use first entry in implementation array for now
return loadRemoteActionEntryPoint(actionMap.get(intentType)[0].serviceEntry)
.then(actionFactory => actionFactory.getMetadata()[intentType].execute(options));
});
}
/**
* Determines whether an intent is defined for an intent manager
* @param {IntentType} intentType intent type
* @return {Promise<bool>} Promise that resolves to true (intent is defined) or false (inten is not defined)
*/
intentIsDefined(intentType) {
if (this._adhocActionsMap.has(intentType)) {
return Promise.resolve(true);
}
return this._fetchRemoteActionServiceEntries()
.then(actionMap => {
if (actionMap.get(intentType)) {
return true;
}
else {
return false;
}
});
}
}
function loadRemoteActionEntryPoint(serviceEntry) {
return SystemJS.import(serviceEntry.serviceUrl + '/action.js');
}