App Studio
Chaining Actions
Chain actions execute multiple action steps in sequence in response to a single widget event. Build complex interaction flows — set variable, then trigger workflow, then navigate.
Chain Action Config
// ChainActionConfig — sequential execution
{
"type": "chain",
"actions": [
{ "type": "set-variable", "variable": "isLoading", "value": true },
{
"type": "trigger-workflow",
"processId": "process-order",
"waitForCompletion": true,
"input": { "orderId": "{{ route.id }}" }
},
{ "type": "set-variable", "variable": "isLoading", "value": false },
{ "type": "navigate", "target": "/orders", "replace": true }
]
}
// Steps execute in order: set isLoading, trigger workflow (wait), clear isLoading, navigate
Sequential vs. Parallel
The chain action always executes steps sequentially. Each step waits for the previous step to complete (or in the case of fire-and-forget actions, waits for them to be dispatched) before starting.
For parallel execution (start multiple workflows simultaneously), use the parallel action type:
// Parallel action — all steps start simultaneously
{
"type": "parallel",
"actions": [
{ "type": "trigger-workflow", "processId": "send-email-notification", "input": { ... } },
{ "type": "trigger-workflow", "processId": "update-crm-record", "input": { ... } }
]
// Both workflows start at the same time — app does not wait for either
}
Nesting Chains
Chains can be nested inside other chains for complex flows:
// onSuccess of a workflow trigger contains a chain
{
"type": "trigger-workflow",
"processId": "approve-request",
"waitForCompletion": true,
"input": { "requestId": "{{ route.id }}" },
"onSuccess": {
"type": "chain",
"actions": [
{ "type": "set-variable", "variable": "successMsg", "value": "Approved!" },
{ "type": "set-variable", "variable": "approvalStatus", "value": "{{ workflowOutput.status }}" },
{ "type": "navigate", "target": "/approvals", "replace": true }
]
}
}
Error Handling in Chains
If any step in a chain throws an error:
- Subsequent steps in the chain do not execute (fail-fast)
- If the chain has an
onErrorhandler, it runs instead - Without an
onError, errors are swallowed and logged to the State Inspector
{
"type": "chain",
"actions": [ ... ],
"onError": {
"type": "set-variable",
"variable": "errorMessage",
"value": "An error occurred. Please try again."
}
}