Transformations Guide
Transformations Guide
This guide provides an in-depth explanation of the custom transformation engine used within our UI Schema (uiSchema), specifically through the ui:options.transformation object. This powerful mechanism allows certain widgets to dynamically fetch, filter, and update their configuration (like available options) based on the state of other fields in the form or external data sources.
This enables complex dependency scenarios, such as populating an “Application Version” dropdown based on the selected “Application”, or filtering a list of “Metadata Keys” based on a chosen “Service Instance”.
Important: The ui:options.transformation configuration is only processed by the following specific widgets:
SelectWidgetTextWidgetselectautocompleteMultitemplatingeditableSelectDurationAvatarUploadWidgetCheckboxGroup
For these widgets, the primary purpose of using transformations is to dynamically populate the widget’s enum (the actual values) and enumNames (the displayed labels) or to provide data for features like autocompletion and templating suggestions based on data fetched or computed according to the transformation rules. Applying ui:options.transformation to other widgets will have no effect.
Core Concept: ui:options.transformation
The transformation logic for a widget is defined within its ui:options.transformation property in the uiSchema. The structure generally follows this pattern:
{
"fieldName": {
"ui:widget": "SelectWidget", // Or templating, CheckboxGroup, etc.
"ui:options": {
"transformation": {
"dataset": { /* ... Data Source Definitions ... */ },
"select": { /* ... Data Extraction Logic ... */ },
"updates": [ /* ... Target Widget Attribute Updates ... */ ]
}
}
}
}
These three key parts work together:
dataset: Defines the raw data sources needed for the transformation. It specifies what data to fetch.select: Extracts and potentially mutates specific values from the fetched datasets using JSONPath. It specifies how to process the raw data.updates: Specifies which attributes of the target widget (e.g.,enum,enumNames) should be updated with the processed data from theselectstep.
1. dataset - Defining Data Sources
The dataset object contains one or more key-value pairs. Each key is a local alias for the data source within this transformation, and the value describes the dataset configuration.
// Dataset Configuration Structure
{
name: string; // Unique identifier for the data source type (e.g., 'applications', 'metadata_keys')
sourceName?: string; // Optional: Alias if different from 'name'
observes?: ObserveProperty[]; // Defines dependencies on other form fields
params?: Record<string, any>; // Static parameters for the data source request
}
name: Identifies the type of data to fetch (e.g.,'applications','time_series_names','metadata_keys'). This corresponds to a registered data source fetcher.sourceName: Optional alias. If provided, the fetched data will be available under this name in the context; otherwise, it usesname.params: Static parameters passed directly to the data source fetcher. Useful for pre-filtering.- Unlike
observes, these parameters are fixed for this transformation and do not change based on user input in other fields. They provide constant context for the data fetch. - Example: If fetching
metadata_keys, you might use static params to always filter for keys associated with a specific service type, regardless of other form selections:"params": { "serviceType": "EPR" }.
- Unlike
observes: (Crucial for dynamic behavior) An array defining which other form fields this data source depends on.
dataset.observes - Observing Other Fields
The observes array is key to making transformations dynamic. Each element describes an observed property.
// Observe Property Structure
{
name: string; // Name of the parameter expected by the data source fetcher
valueFrom: ValueFrom; // How to get the value for this parameter from the form
isArray?: boolean; // Treat the observed value(s) as an array
hideValues?: string[]; // Only trigger fetch if observed value is NOT in this list
showValues?: string[]; // Only trigger fetch if observed value IS in this list
}
name: The parameter name the data source fetcher expects (e.g.,appName,serviceInstanceName).valueFrom: Defines how to retrieve the value for this parameter from the current form state. This is the core of the dependency logic.isArray,hideValues,showValues: Optional flags to control fetching based on the observed value.
observes.valueFrom - Getting Dependent Values
The valueFrom property can take several forms:
-
Simple JSONPath String: Retrieves a value from the form data using JSONPath notation (relative to the form’s root data object). Example:
"$.serviceIntegration.applicationName"retrieves the value of theapplicationNamefield within theserviceIntegrationobject. -
Array of JSONPath Strings: Retrieves values from multiple paths. The transformation uses the first non-null value found. Example:
["$.someOptionalField", "$.someRequiredField"]. -
Conditional Object: Selects a value based on conditions met by another field.
// Conditional ValueFrom Structure { oneOf: [ // ... ValueFromCondition objects ... ] } // ValueFromCondition Structure { fieldValue: string; // JSONPath to the field whose value determines the condition match: string; // The value the 'fieldValue' path must match valueFrom?: string; // JSONPath to get the value from if condition matches value?: string; // Static value to use if condition matches isArray?: boolean; }Example (getting
appNamebased onapplicationSelection):{ "name": "appName", "valueFrom": { "oneOf": [ { "fieldValue": "$.serviceIntegration.applicationSelection", "match": "Single", "valueFrom": "$.serviceIntegration.applicationName" }, { "fieldValue": "$.serviceIntegration.applicationSelection", "match": "Multi", "valueFrom": "$.serviceIntegration.applications" } ] } }This reads: “The
appNameparameter for the data source depends onserviceIntegration.applicationSelection. If it’s'Single', use the value fromserviceIntegration.applicationName. If it’s'Multi', use the value fromserviceIntegration.applications.” -
Array Item Context (
$item): When a transformation is defined within theuiSchemafor anitemsobject (i.e., inside an array field), you can use$itemas a prefix in the JSONPath to refer to fields within the current array item. This allows a transformation for one item to depend on other values within that specific item.Example (conceptual): Imagine an array of
seriesConfigurationitems, where each item has aname(time series name) andvaluePath(path within that time series). To populate thevaluePathdropdown based on the selectednamefor that specific series:"columns": { "type": "array", "items": { // Schema for each item "type": "object", "properties": { "name": { "type": "string", "title": "Time Series Name" }, "valuePath": { "type": "string", "title": "Value Path" } } } }, // In the uiSchema: "columns": { "items": { "valuePath": { "ui:widget": "SelectWidget", "ui:options": { "transformation": { "dataset": { "timeSeriesValuePaths": { "name": "time_series_value_path", // Data source type "observes": [ { "name": "timeSeriesName", // Param data source expects "valueFrom": "$item.name" // Get value from 'name' field in this item } // ... other observes like appName, serviceInstance ... ] } }, "select": { "paths": { "type": "JSONPath", "value": "$.timeSeriesValuePaths.*" } }, "updates": [ { "attribute": "enum", "value": "${paths}" }, { "attribute": "enumNames", "value": "${paths}" } ] } } } } }Here,
valueFrom: "$item.name"ensures that thetime_series_value_pathdataset is fetched using thenamevalue specifically from the array item currently being rendered or edited.
2. select - Extracting Data with JSONPath
Once the dataset is fetched (potentially triggered by observes), the select object extracts the relevant parts using JSONPath.
// Select Structure
{
type: 'JSONPath';
value: string; // The JSONPath expression to apply to the fetched dataset(s)
mutation?: string; // Optional template string to format the extracted value(s)
observes?: ObserveProperty[]; // Can also observe form fields directly
}
type: 'JSONPath': Currently the only supported select type.value: A JSONPath expression evaluated against the context containing the fetched datasets (aliased by their keys in thedatasetobject). Example:"$.applications.*.name"selects allnameproperties from all objects within theapplicationsdataset.mutation: An optional template string. If provided, each value selected by thevaluepath is interpolated into this template. Example: Ifvalueselects["id1", "id2"]andmutationis"prefix_${value}", the result becomes["prefix_id1", "prefix_id2"].
Example (getting application names):
"select": {
"applicationNames": {
"type": "JSONPath",
"value": "$.applications.*.name" // Select names from the 'applications' dataset
},
"applicationDisplayNames": {
"type": "JSONPath",
"value": "$.applications.*.displayName" // Select display names
}
}
Here, two selections are defined: applicationNames and applicationDisplayNames, extracting different fields from the same applications dataset defined earlier.
3. updates - Applying Data to the Widget
The final step is updates. This array defines how the data extracted by select should be applied to the target widget’s properties.
// Update Structure
{
attribute: string; // The attribute of the widget to update (e.g., 'enum', 'enumNames', 'value')
value: string; // Template string referencing selected data (e.g., '${applicationNames}')
template?: string; // Optional: Further template applied to the value
target?: 'ui:options'; // Optional: Target sub-object (rarely needed)
isArray?: boolean; // Treat the value as an array
}
attribute: The name of the property on the widget’s schema or UI schema options to update. Common targets areenum(for values) andenumNames(for display labels).value: A template string that references the results of theselectstep using${selectKey}notation. Example:"${applicationNames}"uses the data selected by theapplicationNameskey in theselectobject. This provides the initial data for the update.template: (Optional) A more sophisticated template string, often leveraging a built-in templating engine (using|for filters/functions likefilterBy,mapBy,json). This template operates on the data context (including results from theselectstep, often accessed via aparamsobject like${params.selectKey}). It allows complex filtering, mapping, and formatting of the selected data before it gets applied to the targetattribute. If omitted, the raw value from thevalueproperty (if defined) or the direct result of theselectstep is typically used.target: (Optional) Specifies a nested object within the widget’s schema or UI options where theattributeshould be updated (e.g.,'ui:options'). Rarely needed.isArray: (Optional) Iftrue, ensures the final value applied to theattributeis treated as an array.
Example (applying application names - simpler case using value):
"select": {
"appNames": { "type": "JSONPath", "value": "$.applications.*.name" },
"appDisplayNames": { "type": "JSONPath", "value": "$.applications.*.displayName" }
},
"updates": [
{ "attribute": "enum", "value": "${appNames}" },
{ "attribute": "enumNames", "value": "${appDisplayNames}" }
]
Example (using advanced template for filtering/mapping):
This example fetches endpoints but then uses the template to filter them based on metadata.type and map the results to different attributes for enum and enumNames.
{
"transformation": {
"dataset": {
"endpointsData": { // Alias for the dataset result
"name": "endpoints",
"params": {
"serviceName": "EPR",
"appName": "<your_application_name>", // Masked app name
"withMetadata": true
}
}
},
"select": {
"allEndpoints": { // Select all fetched endpoint objects
"type": "JSONPath",
"value": "$.endpointsData.*"
}
},
"updates": [
{
"attribute": "enum", // Target the values
// Process the selected endpoints:
// 1. Filter where metadata.type is 'light_switch'
// 2. Map the filtered list to get only the endpointId
// 3. Format the result as JSON (likely resulting in an array of strings)
"template": "${params.allEndpoints | filterBy('metadata.type', 'light_switch') | mapBy('endpointId') | json}"
},
{
"attribute": "enumNames", // Target the display names
// Process the selected endpoints:
// 1. Filter where metadata.type is 'light_switch'
// 2. Map the filtered list to get the metadata.location
// 3. Format the result as JSON (likely resulting in an array of strings)
"template": "${params.allEndpoints | filterBy('metadata.type', 'light_switch') | mapBy('metadata.location') | json}"
}
]
}
}
Summary
The transformation system provides a declarative way to manage complex data dependencies in forms:
- Define Data Needs (
dataset): Specify what data is required, potentially with staticparams. - Define Dependencies (
observes): Specify when to fetch/re-fetch data based on changes in other form fields, usingvalueFrom(simple path, array, or conditional object) to extract dependent values. - Extract Relevant Data (
select): Use JSONPath (value) and optionalmutationto pull specific pieces from the fetched data. - Apply Updates (
updates): Use template strings (value) referencing selected data to modify target widget attributes (attribute, usuallyenumandenumNames).
By combining these steps, sophisticated dynamic forms can be built, reacting to user input and external data sources in real-time.
Available Dataset Sources
Below is a list of common data source names that can be used in the dataset.name field within a transformation configuration. Each source fetches specific types of data from the platform.
Note: The observes parameters listed are typically required to provide context for the data fetch (e.g., which application to query). Static params offer additional filtering options for the specific data source.
service_instances- Description: Returns a list of configured service instances (like EPR, EPTS, ECR).
params:serviceName(Optional: Filter by service type, e.g., “EPR”).
applications- Description: Returns a list of available applications (solutions).
observes: None.
application_versions- Description: Returns the versions available for a specific application.
observes:appName(Required).
endpoints- Description: Returns a list of endpoints, potentially filtered by application, version, or search term.
params:withMetadata(Optional: Include endpoint metadata in the result),isEndpointsDisplayNameEnabled(Optional: Format endpoint name with metadata),limit,offset,searchExpression(Optional: for server-side filtering/pagination).observes: (serviceInstanceNameorserviceName) (Required),appName(Optional: Filter by application name/s),appVersionName(Optional: Filter by version name).
metadata_keys- Description: Returns all known metadata attribute keys for a specific application or endpoint.
params:onlyEditableFields(Optional: If true, returns only keys marked as editable).observes: (serviceInstanceNameorserviceName) (Required), (appNameorendpointId) (One is required).
editable_metadata_keys- Description: Returns only the editable metadata attribute keys for a specific application or endpoint.
observes: (serviceInstanceNameorserviceName) (Required), (appNameorendpointId) (One is required).
metadata- Description: Returns the full metadata object for a specific endpoint, along with a list of its flattened keys.
observes:endpointId(Required),serviceInstanceName(Required, defaults to ‘epr’).
time_series_names- Description: Returns the names of time series configured for an application.
observes: (serviceInstanceNameorserviceName) (Required),appName(Required).
time_series_value_path- Description: Returns the available value paths within a specific time series (e.g.,
values.temperature,timestamp). observes:serviceInstanceName(Required),appName(Required),timeSeriesName(Required).
- Description: Returns the available value paths within a specific time series (e.g.,
time_series_values- Description: Returns the available value keys within a specific time series (e.g.,
temperature,humidity). (Note: Usetime_series_value_pathfor full paths). observes: (serviceInstanceNameorserviceName) (Required),appName(Required),timeSeriesName(Required).
- Description: Returns the available value keys within a specific time series (e.g.,
filters- Description: Returns saved endpoint filters for an application.
observes:serviceInstanceName(Required),appName(Required).
dashboards_paths- Description: Returns the paths of available dashboards.
observes: None.
configurations- Description: Returns the ECR configuration content (default or endpoint-specific).
params:configurationType(Optional: ‘default’ or ‘current’),defaultConfig(Optional: boolean).observes:appVersionName(Required),endpointId(Required if not fetching default config).
config_keys- Description: Returns flattened keys from an ECR configuration.
params: Same asconfigurations.observes: Same asconfigurations.
system_configurations- Description: Returns available system configurations for a specific entity level.
-
observes:systemConfigLevel(Required: ‘tenant’, ‘application’, ‘appVersion’, ‘endpoint’), (appNameappVersionNameendpointIdtenantId) (Required based on level).
system_configuration- Description: Returns the content of a specific system configuration.
observes:systemConfigLevel(Required),systemConfigEntityId(Required, supports variables),configName(Required, supports variables).
actions- Description: Returns Rule Engine actions.
observes:actionType(Required).
rules- Description: Returns Rule Engine rules.
observes: None.
alertsTypes- Description: Returns alert types for a specific entity type.
observes:entityType(Required).
alert_metadata_keys- Description: Returns metadata keys relevant for alerts based on a specific type.
observes:alertMetadataKeyType(Required).
trigger_types- Description: Returns specific trigger types within a category.
observes:triggerType(Required).
recipients- Description: Returns configured notification recipients.
observes: None.
pools- Description: Returns IAMCore identity pools.
observes: None.
tenant_users- Description: Returns users within the current tenant.
observes: None.
asset_types- Description: Returns defined asset types.
observes: None.
asset_type_keys- Description: Returns attribute keys defined in an asset type’s schema.
observes:assetTypeId(Required).
assets- Description: Returns assets, optionally filtered by type.
params:flattenPayload(Optional: Flatten the asset definition).observes:assetTypeId(Required),filter(Optional: {key, value}).
related_assets- Description: Returns assets related to a specific asset.
params:flattenPayload(Optional).observes:assetId(Required),assetRelationDirection(Required: ‘fromEntityId’ or ‘toEntityId’),assetTypeId(Optional: Filter related assets by type).
relation_asset_types- Description: Returns asset types related to another asset type or an endpoint’s application.
observes: (assetTypeIdorendpointId) (One is required).
relation_endpoints- Description: Returns endpoints related to an asset type or another endpoint’s application.
params:withMetadata,isEndpointsDisplayNameEnabled(Optional).observes: (assetTypeIdorendpointId) (One is required).
form_payload- Description: Returns the entire current form data object. Useful for complex internal logic within a transformation.
observes: None.
report_templates- Description: Returns available report templates.
observes: None.
timezones_list- Description: Returns a list of timezones with labels and offsets.
observes: None.
vpn_clients- Description: Returns configured VPN clients.
observes: None.
vnc_tunnels- Description: Returns VNC tunnels associated with a specific VPN client.
observes:vpnClientId(Required).