diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html index a3d343e720..fb1afd544d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html @@ -42,6 +42,7 @@ { +export const getDefaultProcessImageFunction = (type: WidgetMobileActionType): TbFunction => { let title: string; switch (type) { case WidgetMobileActionType.takePictureFromGallery: @@ -220,7 +221,7 @@ export const getDefaultProcessImageFunction = (type: WidgetMobileActionType): st return processImageFunctionTemplate.replace('--TITLE--', title); }; -export const getDefaultProcessLaunchResultFunction = (type: WidgetMobileActionType): string => { +export const getDefaultProcessLaunchResultFunction = (type: WidgetMobileActionType): TbFunction => { let title: string; switch (type) { case WidgetMobileActionType.mapLocation: @@ -244,7 +245,7 @@ export const getDefaultGetLocationFunction = () => getLocationFunctionTemplate; export const getDefaultGetPhoneNumberFunction = () => getPhoneNumberFunctionTemplate; -export const getDefaultHandleEmptyResultFunction = (type: WidgetMobileActionType): string => { +export const getDefaultHandleEmptyResultFunction = (type: WidgetMobileActionType): TbFunction => { let message = 'Mobile action was cancelled!'; switch (type) { case WidgetMobileActionType.takePictureFromGallery: @@ -275,7 +276,7 @@ export const getDefaultHandleEmptyResultFunction = (type: WidgetMobileActionType return handleEmptyResultFunctionTemplate.replace('--MESSAGE--', message); }; -export const getDefaultHandleErrorFunction = (type: WidgetMobileActionType): string => { +export const getDefaultHandleErrorFunction = (type: WidgetMobileActionType): TbFunction => { let title = 'Mobile action failed'; switch (type) { case WidgetMobileActionType.takePictureFromGallery: diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 92fc7d7621..d1517a2e72 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -70,9 +70,12 @@ import { IDynamicWidgetComponent, ShowWidgetHeaderActionFunction, updateEntityParams, - WidgetContext, widgetContextToken, widgetErrorMessagesToken, + WidgetContext, + widgetContextToken, + widgetErrorMessagesToken, WidgetHeaderAction, - WidgetInfo, widgetTitlePanelToken, + WidgetInfo, + widgetTitlePanelToken, WidgetTypeInstance } from '@home/models/widget-component.models'; import { @@ -1204,157 +1207,212 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, break; case WidgetMobileActionType.mapDirection: case WidgetMobileActionType.mapLocation: - const getLocationFunctionString = mobileAction.getLocationFunction; - const getLocationFunction = new Function('$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', getLocationFunctionString); - const locationArgs = getLocationFunction($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - if (locationArgs && locationArgs instanceof Observable) { - argsObservable = locationArgs; - } else { - argsObservable = of(locationArgs); - } - argsObservable = argsObservable.pipe(map(latLng => { - let valid = false; - if (Array.isArray(latLng) && latLng.length === 2) { - if (typeof latLng[0] === 'number' && typeof latLng[1] === 'number') { - valid = true; + argsObservable = compileTbFunction(this.http, mobileAction.getLocationFunction, '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').pipe( + switchMap(getLocationFunction => { + const locationArgs = getLocationFunction.execute($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + if (locationArgs && locationArgs instanceof Observable) { + return locationArgs; + } else { + return of(locationArgs); } - } - if (valid) { - return latLng; - } else { - throw new Error('Location function did not return valid array of latitude/longitude!'); - } - })); + }), + map(latLng => { + let valid = false; + if (Array.isArray(latLng) && latLng.length === 2) { + if (typeof latLng[0] === 'number' && typeof latLng[1] === 'number') { + valid = true; + } + } + if (valid) { + return latLng; + } else { + throw new Error('Location function did not return valid array of latitude/longitude!'); + } + }) + ); break; case WidgetMobileActionType.makePhoneCall: - const getPhoneNumberFunctionString = mobileAction.getPhoneNumberFunction; - const getPhoneNumberFunction = new Function('$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', getPhoneNumberFunctionString); - const phoneNumberArg = getPhoneNumberFunction($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - if (phoneNumberArg && phoneNumberArg instanceof Observable) { - argsObservable = phoneNumberArg.pipe(map(phoneNumber => [phoneNumber])); - } else { - argsObservable = of([phoneNumberArg]); - } - argsObservable = argsObservable.pipe(map(phoneNumberArr => { - let valid = false; - if (Array.isArray(phoneNumberArr) && phoneNumberArr.length === 1) { - if (phoneNumberArr[0] !== null) { - valid = true; + argsObservable = compileTbFunction(this.http, mobileAction.getPhoneNumberFunction, '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').pipe( + switchMap(getPhoneNumberFunction => { + const phoneNumberArg = getPhoneNumberFunction.execute($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + if (phoneNumberArg && phoneNumberArg instanceof Observable) { + return phoneNumberArg.pipe(map(phoneNumber => [phoneNumber])); + } else { + return of([phoneNumberArg]); } - } - if (valid) { - return phoneNumberArr; - } else { - throw new Error('Phone number function did not return valid number!'); - } - })); + }), + map(phoneNumberArr => { + let valid = false; + if (Array.isArray(phoneNumberArr) && phoneNumberArr.length === 1) { + if (phoneNumberArr[0] !== null) { + valid = true; + } + } + if (valid) { + return phoneNumberArr; + } else { + throw new Error('Phone number function did not return valid number!'); + } + }) + ); break; } - argsObservable.subscribe((args) => { - this.mobileService.handleWidgetMobileAction(type, ...args).subscribe( - (result) => { - if (result) { - if (result.hasError) { - this.handleWidgetMobileActionError(result.error, $event, mobileAction, entityId, entityName, additionalParams, entityLabel); - } else if (result.hasResult) { - const actionResult = result.result; - switch (type) { - case WidgetMobileActionType.takePictureFromGallery: - case WidgetMobileActionType.takePhoto: - case WidgetMobileActionType.takeScreenshot: - const imageUrl = actionResult.imageUrl; - if (mobileAction.processImageFunction && mobileAction.processImageFunction.length) { - try { - const processImageFunction = new Function('imageUrl', '$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.processImageFunction); - processImageFunction(imageUrl, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); - } + argsObservable.subscribe( + { + next: (args) => { + this.mobileService.handleWidgetMobileAction(type, ...args).subscribe( + (result) => { + if (result) { + if (result.hasError) { + this.handleWidgetMobileActionError(result.error, $event, mobileAction, entityId, entityName, additionalParams, entityLabel); + } else if (result.hasResult) { + const actionResult = result.result; + switch (type) { + case WidgetMobileActionType.takePictureFromGallery: + case WidgetMobileActionType.takePhoto: + case WidgetMobileActionType.takeScreenshot: + const imageUrl = actionResult.imageUrl; + if (isNotEmptyTbFunction(mobileAction.processImageFunction)) { + compileTbFunction(this.http, mobileAction.processImageFunction, 'imageUrl', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(imageUrl, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); + } + break; + case WidgetMobileActionType.scanQrCode: + const code = actionResult.code; + const format = actionResult.format; + if (isNotEmptyTbFunction(mobileAction.processQrCodeFunction)) { + compileTbFunction(this.http, mobileAction.processQrCodeFunction, 'code', 'format', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(code, format, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); + } + break; + case WidgetMobileActionType.getLocation: + const latitude = actionResult.latitude; + const longitude = actionResult.longitude; + if (isNotEmptyTbFunction(mobileAction.processLocationFunction)) { + compileTbFunction(this.http, mobileAction.processLocationFunction, 'latitude', 'longitude', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(latitude, longitude, $event, this.widgetContext, + entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); + } + break; + case WidgetMobileActionType.mapDirection: + case WidgetMobileActionType.mapLocation: + case WidgetMobileActionType.makePhoneCall: + const launched = actionResult.launched; + if (isNotEmptyTbFunction(mobileAction.processLaunchResultFunction)) { + compileTbFunction(this.http, mobileAction.processLaunchResultFunction, 'launched', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(launched, $event, this.widgetContext, + entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); + } + break; } - break; - case WidgetMobileActionType.scanQrCode: - const code = actionResult.code; - const format = actionResult.format; - if (mobileAction.processQrCodeFunction && mobileAction.processQrCodeFunction.length) { - try { - const processQrCodeFunction = new Function('code', 'format', '$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.processQrCodeFunction); - processQrCodeFunction(code, format, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); - } + } else { + if (isNotEmptyTbFunction(mobileAction.handleEmptyResultFunction)) { + compileTbFunction(this.http, mobileAction.handleEmptyResultFunction, '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); } - break; - case WidgetMobileActionType.getLocation: - const latitude = actionResult.latitude; - const longitude = actionResult.longitude; - if (mobileAction.processLocationFunction && mobileAction.processLocationFunction.length) { - try { - const processLocationFunction = new Function('latitude', 'longitude', '$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.processLocationFunction); - processLocationFunction(latitude, longitude, $event, this.widgetContext, - entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); - } - } - break; - case WidgetMobileActionType.mapDirection: - case WidgetMobileActionType.mapLocation: - case WidgetMobileActionType.makePhoneCall: - const launched = actionResult.launched; - if (mobileAction.processLaunchResultFunction && mobileAction.processLaunchResultFunction.length) { - try { - const processLaunchResultFunction = new Function('launched', '$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.processLaunchResultFunction); - processLaunchResultFunction(launched, $event, this.widgetContext, - entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); - } - } - break; - } - } else { - if (mobileAction.handleEmptyResultFunction && mobileAction.handleEmptyResultFunction.length) { - try { - const handleEmptyResultFunction = new Function('$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.handleEmptyResultFunction); - handleEmptyResultFunction($event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); } } } + ); + }, + error: err => { + let errorMessage: string; + if (err && typeof err === 'string') { + errorMessage = err; + } else if (err && err.message) { + errorMessage = err.message; } + errorMessage = `Failed to get mobile action arguments${errorMessage ? `: ${errorMessage}` : '!'}`; + this.handleWidgetMobileActionError(errorMessage, $event, mobileAction, entityId, entityName, additionalParams, entityLabel); } - ); - }, - (err) => { - let errorMessage; - if (err && typeof err === 'string') { - errorMessage = err; - } else if (err && err.message) { - errorMessage = err.message; - } - errorMessage = `Failed to get mobile action arguments${errorMessage ? `: ${errorMessage}` : '!'}`; - this.handleWidgetMobileActionError(errorMessage, $event, mobileAction, entityId, entityName, additionalParams, entityLabel); - }); + }); } private handleWidgetMobileActionError(error: string, $event: Event, mobileAction: WidgetMobileActionDescriptor, entityId?: EntityId, entityName?: string, additionalParams?: any, entityLabel?: string) { - if (mobileAction.handleErrorFunction && mobileAction.handleErrorFunction.length) { - try { - const handleErrorFunction = new Function('error', '$event', 'widgetContext', 'entityId', - 'entityName', 'additionalParams', 'entityLabel', mobileAction.handleErrorFunction); - handleErrorFunction(error, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); - } catch (e) { - console.error(e); - } + if (isNotEmptyTbFunction(mobileAction.handleErrorFunction)) { + compileTbFunction(this.http, mobileAction.handleErrorFunction, 'error', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(error, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); } } diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 79330cdffd..37ea1c1607 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -621,27 +621,27 @@ export interface WidgetMobileActionResult { } export interface ProcessImageDescriptor { - processImageFunction: string; + processImageFunction: TbFunction; } export interface ProcessLaunchResultDescriptor { - processLaunchResultFunction?: string; + processLaunchResultFunction?: TbFunction; } export interface LaunchMapDescriptor extends ProcessLaunchResultDescriptor { - getLocationFunction: string; + getLocationFunction: TbFunction; } export interface ScanQrCodeDescriptor { - processQrCodeFunction: string; + processQrCodeFunction: TbFunction; } export interface MakePhoneCallDescriptor extends ProcessLaunchResultDescriptor { - getPhoneNumberFunction: string; + getPhoneNumberFunction: TbFunction; } export interface GetLocationDescriptor { - processLocationFunction: string; + processLocationFunction: TbFunction; } export type WidgetMobileActionDescriptors = ProcessImageDescriptor & @@ -652,8 +652,8 @@ export type WidgetMobileActionDescriptors = ProcessImageDescriptor & export interface WidgetMobileActionDescriptor extends WidgetMobileActionDescriptors { type: WidgetMobileActionType; - handleErrorFunction?: string; - handleEmptyResultFunction?: string; + handleErrorFunction?: TbFunction; + handleEmptyResultFunction?: TbFunction; } export interface CustomActionDescriptor {