Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 13 Next »

Overview

This documentation provides detailed guidelines on utilizing the JavaScript execution feature within our application. This capability enhances the flexibility and functionality by enabling users to define and execute custom scripts that can interact dynamically with various application elements. Integrated through an internal API, these scripts provide a robust method for automation and customization of processes and data handling.

Key Features

The JavaScript execution is designed for integration with "concept types" through two specific script functionalities:

  1. Guard Scripts: These scripts act as safeguards for updates to the concepts. They are saved as part of the concept type. They evaluate conditions and determine whether an update should proceed or be rejected.

  2. Calculated Fields Scripts: These scripts perform operations such as calculations, concatenations, and other manipulations. The results can then be displayed in the concept.

API Capabilities

The internal JavaScript API exposes several objects and functionalities to the executing scripts, enabling them to interact deeply with the system's internal structures. This interaction includes access to persisted concepts in the current context, master data, the current user, and, in specific cases, the potential future state of a concept (for Guard Scripts) or the fields dependent on calculations (for Calculated Fields Scripts).

Expected Return Values for Guard Scripts

Guard Scripts are used to determine whether updates to a concept should proceed or be blocked. The outcome of these scripts can be communicated back to the application in two forms:

1. Boolean Return Values

  • True: Indicates that the guard script has approved the update, allowing it to proceed.

  • False: Indicates that the guard script has blocked the update. If the return value is false, a generic message will be displayed to the user in the UI, such as "Update not allowed by system rules."

2. GuardResult Object

For more nuanced control over the feedback provided to users, scripts can return a GuardResult object, which allows for customized messages and detailed feedback about why an update was blocked or allowed.

Structure of the GuardResult Object

Field

Type

Description

success

boolean

Indicates whether the update should proceed.

title

String

A brief title summarizing the guard's outcome.

reason

String

A detailed explanation of the decision.

affectedProperties

List<AffectedProperty>

List of properties that influenced the decision.

AffectedProperty Record

Field

Type

Description

reason

String

Explanation of how the property was affected.

propertyIdentifier

String

The identifier of the affected property.

Example Use Cases

  • Success = True: The update is allowed to proceed, and no details are shown to the user since the operation complies with all rules.

  • Success = False: The update is blocked. The details specified in the GuardResult object, such as title, reason, and information about affectedProperties, will be displayed in the UI to inform the user precisely why the update was not permitted.

Implementing Guard Scripts with GuardResult

Guard Scripts can use these structures to provide clear and actionable feedback to users, especially when rejecting an update. For example:

let someCondition = false; // Assume some condition that needs to be checked
let anotherCondition = true; // Another condition for demonstration

if (!someCondition || !anotherCondition) {
    return {
        success: false,
        title: "Update Rejected",
        reason: "Multiple conditions for the update are not met.",
        affectedProperties: [
            {
                reason: "First required condition is not met",
                propertyIdentifier: "firstPropertyKey"
            },
            {
                reason: "Second required condition is not met",
                propertyIdentifier: "secondPropertyKey"
            }
        ]
    };
}
return true; // If all conditions are met, allow the update

Expected Return for Calculated Fields Scripts

Calculated Fields Scripts must return a specific object format to integrate smoothly with the rest of the application, ensuring that calculated data is displayed correctly in the UI. This object, CalculatedFieldResult, contains a list of CalculatedField objects that represent individual calculated field values.

Structure of Return Object

Here is the expected structure for the return object in Calculated Fields Scripts:

  • CalculatedFieldResult:

    • Contains a list of CalculatedField objects.

  • CalculatedFieldDto:

    • id: The user-defined identifier (or key) for the calculated field.

    • value: The calculated value as a string.

Example Script for Returning Calculated Fields

Here is an illustrative example of how a Calculated Fields Script might construct and return the expected result:

// Example calculated values
let result2Value = "42"; // Some dynamic calculation result
let concatenatedKeyValue = "Hello, World"; // Another calculation result

return {
    calculatedFields: [
        {
            id: "result2",
            value: result2Value
        },
        {
            id: "concatenatedKey",
            value: concatenatedKeyValue
        }
    ]
};

Example Use of Calculated Fields in UI Masks

When calculated fields are added to a concept type, the user can set up a display mask that utilizes these identifiers to format and show the calculated values dynamically. For instance, consider the following example mask:

Value Of Calculated Field 2: {result2} Concetenated result: {concatenatedKey}

In this mask:

  • result2 and concatenatedKey are identifiers used in the calculated fields result.

Making External REST Calls

Scripts can make external REST calls using the webClient object provided by the context. This functionality leverages Spring's WebClient for making HTTP requests (see documentation). This section details how to set up and use the webClient object in your scripts.

Accessing the WebClient

To access the webClient, use the following syntax:

let webClient = context.getWebClient("GET", "https://host.com/some-uri");
  • Method: The first argument specifies the HTTP method (GET, PUT, POST, DELETE).

  • URI: The second argument is the URI to which the request will be sent.

Authentication and Connection Routing

For authenticated requests, connection routing must be configured for the given URI. If no routing is configured, the web client will make an unauthenticated call. Refer to the connection routing documentation for detailed configuration steps.

Making the Request

To make an actual call, specify the return type and use the webClient as follows:

let StringClass = Java.type("java.lang.String");
let responseString = webClient.get().uri("https://host.com/some-uri")
                .retrieve()
                .bodyToMono(StringClass)
                .block();

JSON Parsing Example

It is recommended to select String as the return type and then parse the JSON in JavaScript. Here’s how you can parse a JSON response:

let responseString = webClient.get().uri("https://host.com/some-uri")
                .retrieve()
                .bodyToMono(StringClass)
                .block();

let jsonResponse = JSON.parse(responseString);

// Example of accessing JSON fields
let field1 = jsonResponse.field1;
let field2 = jsonResponse.field2;

console.log("Field 1:", field1);
console.log("Field 2:", field2);

Logging Functionality

Scripts executed within the application have the capability to log messages to the application log, which can be invaluable for debugging and monitoring script execution. This logging is facilitated through the SLF4J logging facade, providing a standardized way to log messages at various levels (e.g., info, debug, error).

Using the Logger

To log messages, scripts first need to obtain a logger instance from the execution context. This instance can then be used to log messages at the desired level. Below is an example of how to obtain a logger and log an informational message:

let log = context.getLogger(); 
log.info("Guard currently executing");

Accessing Concept Data

Scripts can access concept data in two forms: the version persisted in the database and, in the case of Guard Scripts, the prospective version that includes pending changes. These versions are accessed through the execution context provided by the internal JavaScript API.

Access Methods

  • Persisted Concept: Represents the concept as it is currently stored in the database. Accessed with:

    let persistedConcept = context.getPersistedConcept();

  • Current Concept (Guard Scripts only): Represents the concept with pending changes that will be saved if the guard script allows it. Accessed with:

    let currentConcept = context.getCurrentConcept();

Example Script

The following example script demonstrates how a Guard Script might use these methods to check if the title of a concept has been changed and, if so, logs the change and decides whether to allow the update:

let log = context.getLogger();
let persistedConcept = context.getPersistedConcept();
let currentConcept = context.getCurrentConcept();

let persistedTitle = persistedConcept.getTitle();
let currentTitle = currentConcept.getTitle();

log.info("Checking title change for approval...");
if (currentTitle !== persistedTitle) {
    log.info("Title change detected: from '" + persistedTitle + "' to '" + currentTitle + "'.");
    // Additional conditions can be checked here
    return true;  // Allow the update
} else {
    log.info("No title change detected.");
    return false; // Prevent the update if no changes are made to the title
}

In this script, the getTitle() method is used to retrieve the title from both the persisted and current concept instances, allowing the script to compare them and decide based on business rules whether to allow the update.

Concept Object Methods

The Concept object provides several methods that enable scripts to interact with concept data effectively. These methods are available across all types of concepts within the application, ensuring a consistent interface for script developers.

Available Methods

Below is a list of methods that scripts can access to retrieve and manipulate data from any concept (configuration area, unit, configuration and configuration item):

Method

Return Type

Description

getId()

ObjectId

Retrieves the unique identifier of the concept.

getTitle()

String

Retrieves the title of the concept.

getDescription()

String

Retrieves the description of the concept.

getConceptTypeKey()

String

Retrieves the key that identifies the concept type.

getStateKey()

String

Retrieves the key that identifies the concept state.

getArchived()

Instant

Retrieves the timestamp when the concept was archived.

getTags()

List<ObjectId>

Retrieves a list of tags associated with the concept.

getConceptType()

ConceptType

Retrieves the concept type of the concept

Accessing Properties and Complex Properties

The Concept object offers methods to retrieve simple properties and complex properties (also known as records) in various data types.

Simple Property Access Methods

These methods allow you to retrieve simple properties directly from a concept in different data types. The methods that return the property as their type throw an exception if the property doesn’t actually have this type:

Method

Return Type

Description

getProperty(String key)

String

Retrieves a property by its key as a string. This method is always available, no matter the data type of the property.

getPropertyAsInt(String key)

Integer

Retrieves an integer property value by its key.

getPropertyAsDouble(String key)

Double

Retrieves a double property value by its key.

getPropertyAsBigDecimal(String key)

BigDecimal

Retrieves a BigDecimal property value by its key.

getPropertyAsBoolean(String key)

Boolean

Retrieves a boolean property value by its key.

getPropertyAsInstant(String key)

Instant

Retrieves an instant (timestamp) property value by its key.

getPropertyAsLong(String key)

Long

Retrieves a long property value by its key.

Complex Property (Record) Access Methods

Complex properties are accessed via the getComplexProperty(String recordTypeKey) method, which retrieves a list of ComplexProperty objects. Each ComplexProperty can hold multiple properties of various types.

Methods Available in ComplexProperty

Method

Return Type

Description

getPropertyByIndex(int index, String propertyKey)

String

Retrieves a string property value by its index and key within the complex property. (Always available)

getPropertyAsIntByIndex(int index, String key)

Integer

Retrieves an integer property value by its index and key.

getPropertyAsDoubleByIndex(int index, String key)

Double

Retrieves a double property value by its index and key.

getPropertyAsBooleanByIndex(int index, String key)

Boolean

Retrieves a boolean property value by its index and key.

getPropertyAsBigDecimalByIndex(int index, String key)

BigDecimal

Retrieves a BigDecimal property value by its index and key.

getPropertyAsLongByIndex(int index, String key)

Long

Retrieves a long property value by its index and key.

getPropertyAsInstantByIndex(int index, String key)

Instant

Retrieves an instant property value by its index and key.

ConceptType Object Methods

The Concept object also includes access to its associated concept type through the ConceptType, which carries detailed type-specific information. This is crucial for scripts that need to adapt their behavior based on the type of the concept they are interacting with.

Available Methods

Below is a list of methods provided by the ConceptType object, accessible through the Concept object:

Method

Return Type

Description

getBaseKind()

ConceptBaseKind

Retrieves the base kind of the concept type, indicating its general classification.

getAssociatedChildConceptTypeKey()

String

Retrieves the key for any associated child concept type.

getPropertyTypeKeys()

List<String>

Retrieves a list of keys for the property types defined for this concept type.

getRecordTypeKeys()

List<String>

Retrieves a list of keys for the record types defined for this concept type.

getStateMachineKey()

String

Retrieves the key for the state machine associated with this concept type, if any.

Type-Specific Concept Methods

Depending on the type of concept instance, additional methods are available that facilitate accessing related concepts and properties specific to their functional role within the application. Below is a breakdown of these methods by concept type:

Unit (Component)

For concepts that are instances of "Unit" or known as "Component":

Method

Return Type

Description

getConfigurationArea()

Concept

Retrieves the parent configuration area

Configuration

For concepts that are instances of "Configuration":

Method

Return Type

Description

getComponent()

Concept

Returns the parent component of this configuration.

getConfigurationItems()

List<Concept>

Returns the configuration items of this configuration

getKind()

ConfigurationKind

Returns the kind of the configuration either BASELINE or STREAM

Configuration Item

For concepts that are instances of "Configuration Item":

Method

Return Type

Description

getStorageLocation()

StorageLocation

Returns the storage location associated with the configuration item.

StorageLocation Methods

The StorageLocation object provides specific information about where the configuration item is stored:

Method

Return Type

Description

name()

String

Retrieves the name of the storage location.

storageLocationType()

String

Retrieves the type of the storage location.

Accessing Calculation-Dependent Fields

In Calculated Fields Scripts, the getCalculationDependentFields() method provides access to specific fields that are pertinent to the calculations being performed. This method returns an object that returns properties and complex properties (records) in the same format as the Concept object.

Methods Available

This object provides similar methods to those available in the Concept object for accessing properties and records (see here):

  • Property Access Methods: Includes methods to retrieve simple properties in various data types (e.g., getProperty(String key), getPropertyAsInt(String key), etc.).

  • Complex Property (Record) Access Methods: Includes methods to access complex properties or records such as getComplexProperty(String recordTypeKey) which retrieves a list of complex properties (records) based on the record type key.

Accessing Master Data

Scripts have the capability to access and utilize master data, which are tables of fixed data independent of the concept units. Master data provides a stable dataset that scripts can rely on for performing various operations, such as validations and computations.

Example how to Access Master Data

To access master data within a script, the script can retrieve a master data table using the execution context provided by the internal JavaScript API. Here is an example of how to access and log information from master data in a guard script:

let log = context.getLogger();
let masterDataTable = context.getMasterDataTable("masterDataKey", 0, 25);
log.info("Master data table title: " + masterDataTable.title());
let masterDataRow = masterDataTable.rows().getContent()[0];
log.info("Master data row title: " + masterDataRow.title());
log.info("Master data row cell 1 value: " + masterDataRow.cells()[0].value());
log.info("Master data row cell 2 value: " + masterDataRow.cells()[1].value());

In this example, the script retrieves a master data table using a key, and then accesses data from the first row of the table. This data can be used to perform checks, inform calculations, or influence script behavior based on the stable data provided.

This ability to interact with master data ensures that your scripts can operate with a consistent set of data, crucial for maintaining the integrity and reliability of operations within the application.

Available methods to Access Master Data

Below is a description of the methods available on the MasterDataTable object. This object encapsulates the structure and data of a master data table, which includes its columns and rows.

Method

Return Type

Description

id()

String

Retrieves the unique identifier of the master data table.

key()

String

Retrieves the key associated with the master data table.

title()

String

Retrieves the title of the master data table.

columns()

List<MasterDataColumn>

Retrieves a list of columns within the table.

rows()

List<MasterDataRow>

Retrieves a list of rows within the table.

created()

ChangeContextDto

Retrieves the creation context of the table.

modified()

ChangeContextDto

Retrieves the last modified context of the table.

getRowKeyColumnKey

String

Retrieves the key of the column that contains the row key value

Below is a table describing the methods available on the MasterDataColumn object, which represents a column within a master data table.

Method

Return Type

Description

key()

String

Retrieves the unique key identifier of the column.

title()

String

Retrieves the title or name of the column.

valueType()

PropertyDataType

Retrieves the data type of the column's values.

isRowKey()

boolean

information if this column contains the row key value

Here's a table that outlines the methods accessible on the MasterDataRow object, which encapsulates a row within a master data table.

Method

Return Type

Description

id()

String

Retrieves the unique identifier of the row.

key()

String

Retrieves the key associated with the row.

title()

String

Retrieves the title of the row.

cells()

List<MasterDataCell>

Retrieves a list of cells contained in the row.

created()

ChangeContext

Retrieves the creation context of the row.

modified()

ChangeContext

Retrieves the last modified context of the row.

Lastly, the following table describes the methods on the MasterDataCell object, which represents individual cells within a master data row.

Method

Return Type

Description

key()

String

Retrieves the key identifying this cell in the row.

value()

String

Retrieves the value held by this cell.

Accessing Current User Details

Access via:

let user = context.getUser();
log.info("User name: " + user.username());

The getUser() method provided by the script context allows access to the current user's information, encapsulated within a User object. This functionality is essential for retrieving user-specific data, which can influence script logic or user experience enhancements.

User Access Methods

The User object represents detailed user information. Here is a breakdown of the methods you can use to access this data directly:

Method

Return Type

Description

id()

String

Retrieves the unique identifier of the user.

username()

String

Retrieves the username of the user.

firstname()

String

Retrieves the first name of the user.

lastname()

String

Retrieves the last name of the user.

email()

String

Retrieves the email address of the user.

firstLogin()

Instant

Retrieves the timestamp of the user's first login.

mostRecentLogin()

Instant

Retrieves the timestamp of the user's most recent login.

  • No labels