libs/ngx-pfe/pfe-util/services/util.service.ts
The following parameters can be used in the URL to control certain functionalities of the application.
Properties |
|
Static Readonly APPLICATION_ID |
Type : string
|
Default value : 'applicationId'
|
The applicationId is used by the config service to determine the configuration to load. Usually, this corresponds to the branch in the configuration repository. |
Static Readonly STATE_ID |
Type : string
|
Default value : 'stateId'
|
Restore a previously saved state with a specific ID. Usually, the state service will handle this. |
Static Readonly TENANT |
Type : string
|
Default value : 'tenant'
|
The tenant determines the sbp-plugin, where the gateway will forward the calls to. |
import { NgxLoggerService } from '@allianz/ngx-logger';
import { DOCUMENT } from '@angular/common';
import { Inject, Injectable } from '@angular/core';
import jsonpath from 'jsonpath';
import { Subject } from 'rxjs';
import { tap } from 'rxjs/operators';
import { NGX_PFE_CONFIGURATION, NgxPfeModuleConfiguration } from '../../models/ngx-pfe-module-configuration.model';
import { PfeUserInputState } from '../../models/pfe-state/user-input-state.model';
import { TrackingEvent } from '../../models/tracking.model';
import { UnknownObject } from '../../models/unknown-object.model';
import { clone } from '../../util/clone';
/**
* The RegExp to find JSONPath Expressions in URL
* Math {$.anything} or {$['anything']}
*/
export const URL_STATE_REGEX = /{\$[^}]*}/gi;
export const STATE_EXPRESSION = '$';
export const ARRAY_STATE_EXPRESSION = '[]$';
/**
* The following parameters can be used in the URL to control
* certain functionalities of the application.
*
* @export
*/
export class PfeUrlParameters {
/**
* The applicationId is used by the config service to determine the configuration to load.
* Usually, this corresponds to the branch in the configuration repository.
*/
public static readonly APPLICATION_ID = 'applicationId';
/**
* The tenant determines the sbp-plugin, where the gateway will forward the calls to.
*/
public static readonly TENANT = 'tenant';
/**
* Restore a previously saved state with a specific ID.
* Usually, the state service will handle this.
*/
public static readonly STATE_ID = 'stateId';
}
@Injectable()
export class PfeUtilService {
/**
* This subject is used as a bridge to the tracking integration in @allianz/ngx-pfe/tracking.
* Events that are triggered here, are forwarded by the PfeTrackingService.
*
* As the @allianz/ngx-pfe/tracking integration is optional, a custom integration can also attach to this.
* (This might be moved to it's own service, if more events are triggered)
*/
public trackingEvents$ = new Subject<TrackingEvent>();
public trackingStateRestoredSubject$ = new Subject<PfeUserInputState>();
/**
* Triggers when a state is restored, with the restored state as value.
*/
public trackingStateRestored$ = this.trackingStateRestoredSubject$.asObservable().pipe(tap((value) => clone(value)));
private _applicationId: string | undefined;
private _tenant: string | undefined;
constructor(
@Inject(NGX_PFE_CONFIGURATION) private ngxPfeModuleConfiguration: NgxPfeModuleConfiguration,
// @Inject(WINDOW_INJECTION) private window: any
@Inject(DOCUMENT) private _document: Document,
private ngxLoggerService: NgxLoggerService
) {
this.readApplicationParameters();
}
public get applicationId(): string | undefined {
if (!this._applicationId) {
this.readApplicationParameters();
}
return this._applicationId;
}
public get tenant(): string | undefined {
if (!this._tenant) {
this.readApplicationParameters();
}
return this._tenant;
}
/**
* Retrieves elements in `obj` that match the jsonpath expression `pathExpression`.
*
* Returns the element value if only a single element is found at the path, otherwise
* a list of matching elements is returned.
* If you want to receive the result as an array, even if it contains only a single element
* prepend your pathExpression with '[]' (e.g. '[]$.arrayWithOneElement[0:]')
*
* If you want to receive `undefined` in case the result is an empty array, set the optional
* third parameter to true.
*
*/
public static getValueOrList(obj: UnknownObject, pathExpression: string, returnUndefinedForEmptyArray = false) {
let shouldReturnArray = false;
if (PfeUtilService.isJsonArrayPathExpression(pathExpression)) {
shouldReturnArray = true;
pathExpression = pathExpression.replace(ARRAY_STATE_EXPRESSION, STATE_EXPRESSION);
}
const notAJsonPathExpression = !PfeUtilService.isJsonPathExpression(pathExpression);
if (notAJsonPathExpression) {
return pathExpression;
}
const result = jsonpath.query(obj, pathExpression);
if (result.length === 0) {
return undefined;
}
if (result.length > 1) {
return result;
}
const onlyResult = result[0];
const resultIsEmptyArray = Array.isArray(onlyResult) && onlyResult.length === 0;
if (resultIsEmptyArray && returnUndefinedForEmptyArray) {
return undefined;
}
return shouldReturnArray ? result : onlyResult;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public static setValueFromJsonExpression(obj: UnknownObject, pathExpression: string, value: any) {
if (PfeUtilService.isJsonPathExpression(pathExpression)) {
jsonpath.value(obj, pathExpression, value);
}
}
/**
* Check if the pathExpression is a JsonPathExpression
* Some other services send values that are not really path expressions (like `false` or `true` values)
* Or some strings that don't start with "$"
* @param maybeJsonPathExpression Maybe a JsonPathExpression
* @return true if is a JsonPathExpression
*/
private static isJsonPathExpression(maybeJsonPathExpression: unknown): boolean {
return (
Boolean(maybeJsonPathExpression) && typeof maybeJsonPathExpression == 'string' && maybeJsonPathExpression.startsWith(STATE_EXPRESSION)
);
}
/**
* Check if the pathExpression is a JsonArrayPathExpression, i.e. starts with '[]$'
* @param maybeJsonArrayPathExpression Maybe a JsonArrayPathExpression
* @return true if is a JsonArrayPathExpression
*/
private static isJsonArrayPathExpression(maybeJsonArrayPathExpression: unknown): boolean {
return (
Boolean(maybeJsonArrayPathExpression) &&
typeof maybeJsonArrayPathExpression == 'string' &&
maybeJsonArrayPathExpression.startsWith(ARRAY_STATE_EXPRESSION)
);
}
/**
* Returns a URL parameter, that is either set in the location.search
* or location.hash.
*/
public getURLParam(paramName: string): string {
let paramResult = this.getUrlParams(this._document.location.search, '?')[paramName];
if (!paramResult) {
paramResult = this.getUrlParams(this._document.location.hash, '#')[paramName];
}
return paramResult ?? '';
}
public getUrlParams(search: string, separator: string): Record<string, string> {
if (!search) {
return {};
}
const hashes = search.slice(search.indexOf(separator) + 1).split('&');
return hashes.reduce((params, hash) => {
const [key, val] = hash.split('=');
return Object.assign(params, { [key]: decodeURIComponent(val ?? '') });
}, {});
}
private readApplicationParameters() {
this._applicationId = this.getURLParam(PfeUrlParameters.APPLICATION_ID);
this._tenant = this.getURLParam(PfeUrlParameters.TENANT);
if (!this._applicationId) {
this._applicationId = this.ngxPfeModuleConfiguration.applicationId;
}
if (!this._tenant) {
this._tenant = this.ngxPfeModuleConfiguration.tenant;
}
if (this._applicationId && this._applicationId !== '') {
this.ngxLoggerService.debug('Using application: ' + this._applicationId);
}
if (this._tenant && this._tenant !== '') {
this.ngxLoggerService.debug('Using tenant: ' + this._tenant);
}
}
}