File

libs/ngx-pfe/pfe-service-activator/service/service-activator.model.ts

Index

Properties

Properties

headline
headline: string
Type : string
subline
subline: string
Type : string
Optional
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
import { JsonPathExpression } from '../../models/jsonpath-expression-type.model';
import { ConditionAdvancedE, ConditionE, NavOptionErrorPageConfig } from '../../models/navigation-config-error-page.model';
import { StateUpdates } from '../../models/navigation-config.model';
import { PfeUserInputState } from '../../models/pfe-state/user-input-state.model';
import { UnknownObject } from '../../models/unknown-object.model';
import { PfeActionConfig } from '../../pfe-actions/pfe-actions.model';
import { Conditions, ExpressionCondition } from '../../pfe-conditions/public-api';
import { HTTPResponseHeaders } from '../../util/convert-http-response-headers';

export interface HttpParamsOptionsFromObject {
  [key: string]: string | string[];
}

export enum ServiceActivatorHTTPMethods {
  GET = 'GET',
  POST = 'POST',
  PUT = 'PUT',
  DELETE = 'DELETE',
}

export interface ExtendedDisplayMessage {
  headline: string;
  subline?: string;
}

export type ServiceActivatorProgressDetails = Omit<NavServiceActivatorConfig, 'displayMessage'> & {
  displayMessage?: ExtendedDisplayMessage;
};

/**
 * Configuration for the HTTP response status used by the service activators.
 * Allows to write to the state custom messages depending of the configured
 * HTTP status codes. If the response code is a match a value will be written
 * to the state.
 */
export interface ServiceActivatorResponseStatusHandler {
  /**
   * The HTTP response code expected that triggers this config.
   */
  statusCode: number;
  /**
   * The key specified in `stateValue` property will be written in this path.
   */
  stateKeyExpression: JsonPathExpression;
  /**
   * Writes the string passed here to the state in case that the response
   * HTTP status code is a match.
   */
  stateValue: string;
}

/**
 * Configuration for a service activator to be called.
 */
export interface NavServiceActivatorConfig<ACTIONS = PfeActionConfig> extends LegacyErrorHandlingConfig {
  /**
   *
   * @deprecated true
   * @deprecationMessage Will throw an error if used. Please use `globalConfigId` instead.
   */
  globalConfigID?: string;
  /**
   * Optional id of a service activator in the global config.
   *
   * If a service activator with this id is found in the global config, it is used.
   *
   * If there are additional attributes defined in this configuration, those will partially override
   * the global configuration.
   */
  globalConfigId?: string;

  /**
   * Short message to communicate what the system is doing. You can pass an object with
   * the keys `headline` (mandatory) and `subline` (optional). Alternatively, you can directly pass a string,
   * which sets the `headline` of the spinner implicitly.
   */
  displayMessage?: string | ExtendedDisplayMessage;

  /**
   * The path of the service activator.
   * This is defined by the BFF API.
   */
  path?: string;

  /**
   * Path params that appear in the path
   * With this we are going to be able to build the complete url<br>
   * <b>Example</b>: If we want to make a call to <i>https://endpoint.com/contract/1</i>
   * where that '1' is a value from the app then we should:<br>
   *  - Define path as endpoint/contract/{appValueId} <b>IMPORTANT</b>: No spaces in the dynamic content. <br>
   *  - Define pathParams as: <br>
   *   [
   *     { <br>
   *       id: 'appValueId', <br>
   *       value: jsonExpression <br>
   *     }
   *   ]<br> being jsonExpression, the expression to get from state the value.
   */
  pathParams?: PathParams[];

  /**
   * Defines the HTTP call method. Use: POST, GET or PUT.
   */
  serviceActivatorMethod?: ServiceActivatorHTTPMethods;

  /**
   * Defines the conditions to make the ServiceActivator call to the back-end.
   * As it is an Array, you can define more then one condition and all of them
   * must be TRUE to make the ServiceActivator call.
   * (in short: it's an "AND" condition, not an "OR").
   *
   * Example:
   *
   * conditions: [
   *       {
   *         value1Expression: '$.food',
   *         operator: '==',
   *         value2Expression: 'schnitzel'
   *       },
   *       {
   *         value1Expression: '$.price',
   *         operator: '>',
   *         value2Expression: '1'
   *       }
   *     ]
   */
  conditions?: Conditions;

  /**
   * Defines, how the state should be mapped to the request payload.
   * This enables you to transform the state objects into anything you would like to send to the back-end API.
   *
   * Example, if you have your state modeled like this:
   *
   * {
   *  "user": {
   *     "name": "Michael"
   *     "age": "33"
   *   },
   *  "familyInformation": {
   *    "children": 1,
   *    "married": yes,
   *   }
   *  "sensitiveInformation": {
   *    "password": "1234",
   *    "creditcard": "1234-1234-1234-1234",
   *   }
   * };
   *
   * You probably want to avoid sending the "sensitiveInformation" object to the back-end,
   * and for this example, lets glue the "user" and "familyInformation" objects into just one
   * object called "userInfo" to show how we can manipulate/extend objects.
   *
   * Your requestDataMapping configuration has to be like this:
   *
   * {
   *  requestDataMapping: [{
   *     stateKeyExpression: '$.user',
   *     requestDataExpression: '$.userInfo'
   *  }, {
   *     stateKeyExpression: '$.familyInformation',
   *     requestDataExpression: '$.userInfo'
   *  }]
   * }
   *
   * Then the back-end API will receive this object:
   *
   * {
   *  "userInfo": {
   *     "name": "Michael"
   *     "age": "33"
   *     "children": 1,
   *     "married": yes,
   *   }
   * };
   */
  requestDataMapping?: ServiceActivatorDataMappingForRequesting[];

  /**
   * Defines, how the response data should be mapped to the state.
   */
  responseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * Execute the service activator call asynchronously.
   * This means, that the loading of a page is not blocked, when
   * the service has not yet returned a result.
   * Should not be set for the following page in the navigation.
   * In this case, a service activator should just be executed synchronously
   * Default: false
   */
  async?: boolean;

  /**
   * Ensures, that an asynchronous service activator call finishes successfully
   * (i.e., "is resolved") before one of the pages with one of the "pageIDs" is shown.
   * If the call has not yet returned, the display of the page will be delayed until
   * it is returned.
   *
   * If the same call is performed several times, it is considered as "resolved" as long
   * as the latest call was successful. Therefore, a retry mechanism for unsuccessful
   * calls could eventually mark the call as "resolved".
   */
  asyncResolveBeforePageIds?: string[];

  /**
   * Custom response handling per service activator. See ServiceActivatorResponseStatusHandler interface.
   */
  serviceActivatorResponseStatusHandlers?: ServiceActivatorResponseStatusHandler[];

  /**
   * If set to "true", the SA don't emit `serviceActivatorCallInProgress$` in that way you can make a call
   * in your app and don't show the page loader (a.k.a LottieAnimations)
   * If you want to trigger only before a page you can have a GlobalServiceActivator and then in the cfg
   * ```json
   *  {
   *      "globalConfigId": "myServiceActivator",
   *      "dontEmitInProgress": true
   *  }
   * ```
   * If a pages have more than 1 OnEnter / OnLeave service activator and only one of them emit the event
   * all emit the event.
   */
  dontEmitInProgress?: boolean;

  /**
   * set to true to trigger stale state cleaning
   * this is optional because it can be overriden by the pfeConfig "autoCleanState"
   */
  cleanStaleState?: boolean;

  /**
   * List of possible userInputState updates
   * To be executed before doing the service activator call
   */
  updateStateValuesBefore?: StateUpdates[];

  /**
   * Boolean to enable undefined responses to be mapped to the state
   */
  mapUndefinedResponses?: boolean;

  /**
   * Contains the error handling configuration for this service activator.
   *
   * If no configuration is given, the default behavior of going to the global error page is active.
   *
   * If a configuration is given, it will be activated in case of error responses.
   */
  errorHandling?: ServiceActivatorErrorHandlingConfig<ACTIONS>;
}

/**
 * Internal NavServiceActivatorConfig, that is not published in the json-schema
 */
export interface NavServiceActivatorConfigInternally<ACTIONS = PfeActionConfig> extends NavServiceActivatorConfig<ACTIONS> {
  /**
   * Flag to remember, if this service activator config was already spread with the global one.
   */
  _alreadySpread?: boolean;

  /**
   * Service activators that are run during the startup of the application cannot
   * use the standard error handling, as the navigation is not fully ready yet.
   *
   * This flag is used to prevent the error navigation in that case.
   * Everything else in the service activator error handling is done as usual. (For example the mapping)
   */
  _disableErrorPageNavigation?: boolean;
}

/**
 * The service activator configs.
 */
export type NavServiceActivatorConfigsArray<ACTIONS = PfeActionConfig> = NavServiceActivatorConfig<ACTIONS>[];

export interface ServiceActivatorDataMapping {
  /**
   * The jsonpath expression, where the retrieved data should
   * be stored in the state.
   *
   * It is possible, to access deeply nested structures in this expression.
   * Parts to the structure, that do not yet exist, are automatically created.
   *
   * If $ is used as expression, a spread of the responseData on the state is done
   */
  stateKeyExpression: JsonPathExpression;

  /**
   * Jsonpath expression to extract data from the retrieved service
   * activator response.
   */
  responseDataExpression: JsonPathExpression;

  /**
   * Use the http response instead of the body as source for
   * the responseDataExpression.
   * Allows access to the HttpResponse @link{https://angular.io/api/common/http/HttpResponse}
   * which also contains the http headers and status code.
   *
   * Example Expressions:
   * Get the HTTP Status:
   * ```
   * $.status
   * ```
   *
   * Access the response body of a successful call:
   * ```
   * $.body
   * ```
   *
   * Access the response body in an error case:
   * ```
   * $.error
   * ```
   */
  useHTTPResponseAsData?: boolean;

  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   *  "responseDataMapping": [
        {
          "responseDataExpression": "$.response",
          "stateKeyExpression": "$.response.localObject",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        },
   * ```
   */
  conditions?: ExpressionCondition[];
}

export interface ServiceActivatorDataMappingForRequesting {
  /**
   * The local state object to get mapped into the request.
   * this is the "FROM" part of the Mapping
   * (From the State > To the Request)
   */
  stateKeyExpression: JsonPathExpression;

  /**
   * How to be addressed into the request.
   * This is the "TO" part of the Mapping
   * (From the State > To the Request)
   */
  requestDataExpression: JsonPathExpression;

  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   * "requestDataMapping": [
        {
          "requestDataExpression": "$.licenseplate",
          "stateKeyExpression": "$.userdata.insuredProperty.licensePlate",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        }
      ]
   * ```
   */
  conditions?: Conditions;
}

export interface PathParams {
  /**
   * Id of the param that matches with the one in
   * that is part of the path.
   */
  id: string;
  /**
   * The jsonpath expression, where the retrieved data should
   * be retrieved from the state.
   */
  value: JsonPathExpression;
  /**
   * # ExpressionCondition Syntax
   *
   * The conditions use jsonPath (https://github.com/dchester/jsonpath) expressions to select data from the state.
   * There is tooling support available to create and test jsonpath expression.
   * The PFE dev tools also contain a possibility to test and debug expressions against a JSON.
   *
   * The conditions to be evaluated can either be an array of {@link ExpressionCondition} or an {@link ConditionAdvanced} object.
   *
   * They are an optional attribute. If they are omitted, the result of true is assumed.
   *
   * The selected data can then be compared with certain operators to a second value or a literal.
   *
   * Possible operators are
   *
   * ```
   * ==
   * ```
   * Checks if the two values are equal.
   *
   * ```
   * !=
   * ```
   * Checks that the two values are not equal.
   *
   * ```
   * < and >
   * ```
   * Compares the numerical value, to check if one of them is larger or
   * smaller than the other one.
   *
   * The jsonpath syntax has the following basic format:
   *
   * ```
   *  $.<attribute or expression>
   * ```
   *
   * For example:
   *
   * ```
   *  $.myCustomTextAreaID
   * ```
   *
   * Keys, that contain special characters can be accessed in the following way:
   *
   * ```
   *  $['some-attribute-name']
   * ```
   *
   * Example configuration.
   *
   *
   * ```json
   * "pathParams": [
        {
          "id": "myParam",
          "value": "$.some.state.value",
          "conditions": [{
            "expression": "{$.booleanValueInTheState}"
          }]
        }
      ]
   * ```
   */
  conditions?: Conditions;
}

export interface ServiceActivatorErrorHandlingConfig<ACTIONS> {
  /**
   * An error case configuration contains the handling of a specific error response.
   *
   * The configured conditions decide if an error case becomes active.
   *
   * Once it is active, all other cases are ignored. The cases are checked in the configured order.
   *
   * An error case can then contain a specific handling of an error, with actions, a data mapping and the decision
   * what should happen in the navigation.
   *
   * If only some errors should be handled and all others should be ignored, it is possible to add
   * a case at the end of the list, that simply matches all errors and ignores them.
   */
  errorCases: ErrorCase<ACTIONS>[];
}

/**
 * Used in {@link ServiceActivatorErrorHandlingConfig#errorCases}
 * @see {ServiceActivatorErrorHandlingConfig}
 */
export interface ErrorCase<ACTIONS> {
  // The documentation about the conditions is the same as in the NavOptionErrorPageConfig
  // It is partially duplicated here, so that it shows up everywhere in the json schema
  /**
   * The conditions to determine if this error case should be activated.
   *
   * They are similar to the NavOptionConfig conditions.
   * But in difference to those, the state is only available under $.state in these conditions.
   * The error response is available under $.response
   * The response body for error responses is available under $.response.error;
   * The response headers under $.responseHeaders
   *
   * See also the data model for the data/state the JSONPath expressions run against:
   * {@link ErrorCaseConditionsState}
   * See also, the standard NavOptionConfig conditions:
   * {@link NavOptionConfig#conditions}
   */
  conditions?: ConditionE[] | ConditionAdvancedE;

  /**
   * Defines, how the error response data should be mapped to the state.
   *
   * This is similar to the standard response mapping for a successful service activator.
   *
   * @memberof NavServiceActivatorConfig
   */
  errorResponseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * Actions to run, if this error handling gets active. The result of the action is mapped to these flags:
   * true response from the action = ignoreError
   * false response = disableErrorPageNavigation
   */
  actions?: ACTIONS[];

  /**
   * Ignore the result of the actions and handle the error according to the configuration.
   */
  ignoreActionsResult?: boolean;

  /**
   * Ignore this error. Do not go to the error page.
   * Do not stop the navigation. Do not throw the error upwards.
   * Only the responseDataMapping and the actions are still executed.
   */
  ignoreError?: boolean;

  /**
   * Do not run the errorPageNavigation. Do not go to the global error page.
   *
   * - If the call was triggered in a navigation, this stops the current navigation if this error case is detected.
   * This means, that the user will stay on the current page.
   * - If this call was triggered through some other trigger point, the error
   * will be thrown up to the source of the call trigger and has to be handled there.
   */
  disableErrorPageNavigation?: boolean;

  /**
   * Determines the error page to be displayed. Only executed if disableErrorPageNavigation and ignoreError are false.
   * Allows it to evaluate navigation options. Additionally to the state, the full response object is available under the key "$.response"
   * For example the status response code can be accessed like this: "$.response.status"
   *
   * The response body for error responses is available under $.response.error;
   *
   * The state is available under the key "$.state"
   */
  errorPageNavigation?: NavOptionErrorPageConfig[];
}

/**
 * This interface contains all the legacy service activator error handling attributes.
 * Realistically these are not going to be removed for a long time, as they are used by various configurations.
 */
interface LegacyErrorHandlingConfig {
  /**
   * Defines, how the error response data should be mapped to the state.
   * This will be done, before the navigation to the error page is triggered.
   *
   * @deprecated true
   * @deprecationMessage Please switch to the errorResponseDataMapping attribute in the new service activator errorHandling configuration
   */
  errorResponseDataMapping?: ServiceActivatorDataMapping[];

  /**
   * A list of http status codes, that will not be treated as an error by the service activator
   * response handling. For these status codes, the response handling will be executed.
   * This makes it possible to use error status codes for validation errors.
   *
   * The navigation will not be prevented in this case. Use the preventNavigationOnError flag to stay on the page.
   *
   * For a more complex response handling, it is possible to extend the PfeServiceActivatorService
   * and to implement a custom functionality.
   * @deprecated true
   * @deprecationMessage Please switch to the new service activator errorHandling configuration
   */
  serviceActivatorErrorHandlingExcludeStatusCodes?: number[];

  /**
   * When the serviceActivatorErrorHandlingExcludeStatusCodes are used, the navigation is also triggered in case of an error.
   * This flag can be used to activate the previous behavior, where the navigation was not done in case of http error responses.
   * @deprecated true
   * @deprecationMessage Please switch to the new disableErrorPageNavigation attribute in the service activator errorHandling configuration
   */
  preventNavigationOnError?: boolean;
}

/**
 * This interface describes the data model the error case conditions run against.
 * The fields can be accessed in the JSONPath expressions.
 */
export interface ErrorCaseConditionsState {
  state: PfeUserInputState;
  response: HttpErrorResponse;
  responseHeaders: HTTPResponseHeaders;
}

export interface ActiveAsyncServiceActivatorCallForPage {
  /**
   * Unique identifier of service activator.
   * This could be globalConfigId or path.
   */
  id: string;
  callPromise: Promise<HttpResponse<UnknownObject>>;
  dontEmitInProgress: boolean;
  /**
   * Short message to communicate what the system is doing. You can pass an object with
   * the keys `headline` (mandatory) and `subline` (optional). Alternatively, you can directly pass a string,
   * which sets the `headline` of the spinner implicitly.
   */
  displayMessage?: string | ExtendedDisplayMessage;
}

results matching ""

    No results matching ""