cv-dialog-sdk
Version:
Catavolt Dialog Javascript API
438 lines (437 loc) • 14.2 kB
JavaScript
import { Dialog, Form, PropertyFormatter, RedirectionUtil, TypeNames } from '../models';
import { DialogProxy } from '../proxy/DialogProxy';
import { CvLocale } from '../util/CvLocale';
import { Log } from '../util/Log';
import { ObjUtil } from '../util/ObjUtil';
import { SessionTimer } from "../util/SessionTimer";
import { DialogService } from './DialogService';
/**
* Top-level entry point into the Catavolt API
*/
export class CatavoltApiImpl {
/**
* Construct an CatavoltApiImpl
* This should not be called directly, instead use the 'singleton' method
* @private
*/
constructor(serverUrl, serverVersion) {
this.DEFAULT_LOCALE = new CvLocale('en');
this.dataLastChangedTime = new Date();
this._locale = null;
this._sessionTimer = null;
this._onSessionExpiration = null;
if (CatavoltApiImpl._singleton) {
throw new Error('Singleton instance already created');
}
this._devicePropsStatic = {};
this._devicePropsDynamic = {};
this._sessionTimer = new SessionTimer(() => this.remainingSessionTime, CatavoltApiImpl.CHECK_SESSION_INTERVAL_MILLIS, () => {
this.logout().then(() => {
this._onSessionExpiration && this._onSessionExpiration();
});
});
this.initDialogApi(serverUrl, serverVersion);
CatavoltApiImpl._singleton = this;
}
/* ********************
Statics
*********************** */
/**
* Get the default session time
* @returns {number}
*/
static get defaultTTLInMillis() {
return CatavoltApiImpl.ONE_HOUR_IN_MILLIS;
}
/**
* Get the singleton instance of the CatavoltApiImpl
* @returns {CatavoltApiImpl}
*/
static get singleton() {
if (!CatavoltApiImpl._singleton) {
CatavoltApiImpl._singleton = new CatavoltApiImpl(CatavoltApiImpl.SERVER_URL, CatavoltApiImpl.SERVER_VERSION);
}
return CatavoltApiImpl._singleton;
}
/* *****************
Public Ops
******************* */
/**
* Add or replace a dynamic device property (func)
* @param propName
* @param propFn
*/
addDynamicDeviceProp(propName, propFn) {
this._devicePropsDynamic[propName] = propFn;
}
/**
* Add or replace a static device property
*
* @param propName
* @param propValue
*/
addStaticDeviceProp(propName, propValue) {
this._devicePropsStatic[propName] = propValue;
}
/**
*
* @param {ClientListener} clientListener
*/
addClientListener(clientListener) {
this._dialogApi.addClientListener(clientListener, this.locale);
}
/**
* Get the preferred locale
* @returns {CvLocale}
*/
get locale() {
if (!this._locale) {
const defaultLocale = this.session.tenantProperties.browserLocale;
if (defaultLocale) {
try {
const localeJson = JSON.parse(defaultLocale);
if (localeJson.language) {
this._locale = new CvLocale(localeJson.language, localeJson.country);
}
}
catch (err) {
this._locale = this.DEFAULT_LOCALE;
}
}
}
if (!this._locale) {
this._locale = this.DEFAULT_LOCALE;
}
return this._locale;
}
set locale(locale) {
this._locale = locale;
}
/*@TODO*/
changePasswordAndLogin(tenantId, clientType, userId, existingPassword, newPassword) {
return Promise.reject(new Error('Not Yet Implemented'));
}
/**
* Get the number of millis that the client will remain active between calls
* to the server.
* @returns {number}
*/
get clientTimeoutMillis() {
const mins = this.session.tenantProperties.clientTimeoutMinutes;
return mins ? Number(mins) * 60 * 1000 : CatavoltApiImpl.defaultTTLInMillis;
}
/**
* Get the currency symbol override if defined from the server.
* @returns {string}
*/
get currencySymbol() {
const currencySymbol = this.session.tenantProperties.currencySymbol;
return currencySymbol ? currencySymbol : null;
}
/**
* Get the device props
* @returns {{[p: string]: string}}
*/
get deviceProps() {
const newProps = ObjUtil.addAllProps(this._devicePropsStatic, {});
for (const attr in this._devicePropsDynamic) {
if (this._devicePropsDynamic.hasOwnProperty(attr)) {
newProps[attr] = this._devicePropsDynamic[attr]();
}
}
return newProps;
}
/**
* Get the DialogApi instance
* @returns {DialogApi}
*/
get dialogApi() {
return this._dialogApi;
}
/**
* Initialize a dialog service implementation for use by this CatavoltApiImpl
*
* @param serverVersion
* @param serverUrl
*/
initDialogApi(serverUrl, serverVersion = CatavoltApiImpl.SERVER_VERSION) {
this._dialogApi = new DialogService(new DialogProxy(), serverUrl, serverVersion);
}
/**
* Check for the availability of the given featureSet
* @see FeatureSet
* @param featureSet
* @returns {boolean}
*/
isFeatureSetAvailable(featureSet) {
try {
const currentVersion = AppVersion.getAppVersion(this.session.serverVersion);
const featureMinimumVersion = FeatureVersionMap[featureSet];
return featureMinimumVersion.isLessThanOrEqualTo(currentVersion);
}
catch (error) {
Log.error('Failed to compare appVersions for feature ' + featureSet);
Log.error(error);
return false;
}
}
/**
* Checked logged in status
* @returns {boolean}
*/
get isLoggedIn() {
return !!this._session;
}
/**
* Check offline status
*
* @param tenantId
*/
isAnyUserInBriefcaseMode(tenantId) {
return this.dialogApi.isAnyUserInBriefcaseMode(tenantId);
}
/**
* Check offline status
*
* @param userInfo
* @returns {Promise<boolean>}
*/
isUserInBriefcaseMode(userInfo) {
return this.dialogApi.isUserInBriefcaseMode(userInfo);
}
/**
* Log in and retrieve the Session
*
* @param tenantId
* @param clientType
* @param userId
* @param password
*
* @returns {Promise<Session | Redirection>}
*/
login(tenantId, clientType, userId, password) {
if (this.isLoggedIn) {
return this.logout().then(result => this.processLogin(tenantId, clientType, userId, password));
}
else {
return this.processLogin(tenantId, clientType, userId, password);
}
}
loginWithToken(tenantId, clientType, permissionToken, proofKey) {
if (this.isLoggedIn) {
return this.logout().then(result => this.processLogin(tenantId, clientType, null, null, permissionToken, proofKey));
}
else {
return this.processLogin(tenantId, clientType, null, null, permissionToken, proofKey);
}
}
/**
* Logout and destroy the session
* @returns {{sessionId:string}}
*/
logout() {
if (this.isLoggedIn) {
const sessionId = this.session.id;
return this.dialogApi
.deleteSession(this.session.tenantId, this.session.id)
.then(result => {
this._session = null;
this._sessionTimer.stopSessionTimer();
return result;
})
.catch(error => {
Log.error(`Error logging out ${error}`);
this._session = null;
this._sessionTimer.stopSessionTimer();
return { sessionId };
});
}
else {
return Promise.resolve({ sessionId: null });
}
}
openDialogWithId(dialogId) {
return this.dialogApi.getDialog(this.session.tenantId, this.session.id, dialogId).then((dialog) => {
dialog.initialize(this);
if (dialog.view instanceof Form) {
return dialog;
}
else {
throw new Error(`Unexpected top-level dialog view type: ${dialog.view.type}`);
}
});
}
openDialog(redirection) {
return this.openDialogWithId(redirection.dialogId);
}
/**
* Not yet implemented
* @param {string} url
* @returns {Promise<StreamProducer>}
*/
openStream(url) {
// return this.dialogApi.streamUrl(null, null, url);
throw Error('not yet implemented');
}
toDialogOrRedirection(resultPr) {
return resultPr.then((actionResult) => {
if (RedirectionUtil.isDialogRedirection(actionResult)) {
return this.openDialog(actionResult);
}
else if (RedirectionUtil.isRedirection(actionResult)) {
return Promise.resolve(actionResult);
}
else {
// @TODO - this shouldn't be a null redirection - what should it be?
return Promise.resolve(actionResult);
}
});
}
getRedirection(redirectionId) {
return this.dialogApi.getRedirection(this.session.tenantId, this.session.id, redirectionId);
}
/**
* Open a {@link WorkbenchAction}
* @param workbenchAction
* @returns {Promise<{actionId:string} | Redirection>}
*/
performWorkbenchAction(workbenchAction) {
return this.performWorkbenchActionForId(workbenchAction.workbenchId, workbenchAction.id);
}
/**
* Open a {@link WorkbenchWorkbenchAction}
* @param workbenchId
* @param workbenchActionId
* @returns {Promise<{actionId:string} | Redirection>}
*/
performWorkbenchActionForId(workbenchId, workbenchActionId) {
if (!this.isLoggedIn) {
return Promise.reject(new Error('User is not logged in'));
}
return this.dialogApi.performWorkbenchAction(this.session.tenantId, this.session.id, workbenchId, workbenchActionId);
}
/**
* Refresh the CatavoltApiImpl
*
* @returns {Promise<Session>}
*/
refreshSession(tenantId, sessionId) {
return this.dialogApi.getSession(tenantId, sessionId).then(session => {
this._session = session;
return session;
});
}
/**
* Time remaining before this session is expired by the server
* @returns {number}
*/
get remainingSessionTime() {
return this.clientTimeoutMillis - (new Date().getTime() - this.dialogApi.lastServiceActivity.getTime());
}
/**
*
* @param {ClientListener} clientListener
*/
removeClientListener(clientListener) {
this._dialogApi.removeClientListener(clientListener);
}
/**
* Get the Session
* @returns {Session}
*/
get session() {
return this._session;
}
/**
* Return whether or not the session has expired
* @returns {boolean}
*/
get sessionHasExpired() {
return this.remainingSessionTime < 0;
}
/**
* Function that will be notified when the session expires
* @param {() => void} onSessionExpiration
*/
set onSessionExpiration(onSessionExpiration) {
this._onSessionExpiration = onSessionExpiration;
}
/**
*
* @param {string} contentId
* @param {StreamConsumer} streamConsumer
* @returns {Promise<LargeProperty>}
*/
streamContent(contentId, streamConsumer) {
return Dialog.loadLargeProperty((params) => {
return this.dialogApi.getContent(this.session.tenantId, this.session.id, contentId, params);
}, streamConsumer);
}
processLogin(tenantId, clientType, userId, password, permissionToken, proofKey) {
const login = {
userId,
password,
permissionToken,
proofKey,
clientType,
deviceProperties: this.deviceProps,
type: TypeNames.LoginTypeName
};
return this.dialogApi.createSession(tenantId, login).then((result) => {
if (result.type === TypeNames.SessionTypeName) {
this._session = result;
this._sessionTimer.resetSessionTimer();
return result;
}
else {
return result;
}
});
}
}
CatavoltApiImpl.ONE_HOUR_IN_MILLIS = 60 * 60 * 1000;
CatavoltApiImpl.CHECK_SESSION_INTERVAL_MILLIS = 30 * 1000;
// defaults
CatavoltApiImpl.SERVER_URL = 'https://dialog.hxgn-api.net';
CatavoltApiImpl.SERVER_VERSION = 'v0';
class AppVersion {
constructor(major, minor, patch) {
this.major = major;
this.minor = minor;
this.patch = patch;
}
static getAppVersion(versionString) {
const [major, minor, patch] = versionString.split('.');
return new AppVersion(Number(major || 0), Number(minor || 0), Number(patch || 0));
}
/**
* Is 'this' version less than or equal to the supplied version?
* @param anotherVersion - the version to compare to 'this' version
* @returns {boolean}
*/
isLessThanOrEqualTo(anotherVersion) {
if (anotherVersion.major > this.major) {
return true;
}
else if (anotherVersion.major === this.major) {
if (anotherVersion.minor > this.minor) {
return true;
}
else if (anotherVersion.minor === this.minor) {
return anotherVersion.patch >= this.patch;
}
else {
return false;
}
}
else {
return false;
}
}
}
const FeatureVersionMap = {
View_Support: AppVersion.getAppVersion('1.3.447'),
Unified_Search: AppVersion.getAppVersion('1.3.463')
};
export const Catavolt = CatavoltApiImpl.singleton;
export const propertyFormatter = PropertyFormatter.singleton(Catavolt);