-
Notifications
You must be signed in to change notification settings - Fork 1
Triggers and Actions
In order to facilitate customisable events in Application Templates, there is a system of Triggers associated with various events that, in turn, trigger Actions -- "things that happen" in response to a trigger.
An Application Template will specify:
- Set of Triggers
- Action(s) that happen in response to each trigger
- Conditions (using dynamic expression syntax) under which the Action will run
- And parameters (again, as dynamic expressions) that will be sent to the Action at runtime
Most triggers are associated with events on the main database tables (Application, Review, etc.). Specifically, there is a field on these tables called trigger
into which the "event" (e.g. "ON_APPLICATION_SUBMIT") is recorded. The database listens to this field, then notifies the server, which launches the appropriate Actions, using parameters from the current conditions.
Actions can be defined as Sequential or Async (parallel). Async Actions are executed as soon as the server is notified that they are in the Action queue, whereas Sequential Actions have an additional sequence
property, and are processed in the prescribed sequence once they've all been inserted into the Action queue.
Actions also return an output object (e.g. changeStatus
Action returns the new status details). For sequential Actions, the output properties are collected into a cumulativeOutput
object which is passed to the parameter evaluator (along with the application_data* object -- see "Action Parameters" below), so subsequent Actions can access any of the output properties of any previous Action in the sequence.
ON_APPLICATION_CREATE
ON_APPLICATION_RESTART
ON_APPLICATION_SUBMIT
ON_APPLICATION_SAVE
ON_APPLICATION_WITHDRAW
ON_REVIEW_CREATE
ON_REVIEW_SUBMIT
ON_REVIEW_RESTART
ON_REVIEW_ASSIGN
ON_REVIEW_UNASSIGN
ON_APPROVAL_SUBMIT
ON_VERIFICATION
ON_SCHEDULE
-
DEV_TEST
(For testing purposes)
Two other possible Trigger states are PROCESSING
and ERROR
. The state of triggers goes through the following steps:
- Trigger is set by front-end (usually) to one of the above values
- Back-end listener starts processing the actions associated with the trigger (for that template); Trigger is set to
PROCESSING
while this happens. - On completion of Actions, trigger is set back to
NULL
- If any Actions fail, trigger is set to
ERROR
application
review
review_assignment
verification
trigger_schedule
Actions are implemented as plug-ins -- standalone packages that can be created and customised outside the main application. As far as the Server is concerned, an Action plug-in is basically an imported function, with a defined set of expected parameters.
See the list of Action plugins for currently available Action plugins.
Actions associated with templates (in action_template table) have two fields that can store dynamic expressions which are evaluated at runtime. These are:
-
condition: an expression which must evaluate to a boolean. If
true
at runtime, the Action will run. An example usage could be to check the current status of the application and only run if it matches a certain value. - parameter_queries: Every Action plugin has prescribed required parameters (see Action plugin specification). In the parameter_queries field, every required parameter has an expression associated which is used to generate the parameter value at runtime. See the list of Action plugins for each plugin's required parameters
The expressions which are defined in the above fields will often need access to information about the current application state or current user details (for example). While this information can always be extracted from the database (using the pgSQL
or graphQL
operators), it will normally be faster and simpler to pass this information in directly.
There are two local state objects passed into the expression evaluator (which can be accessed using the objectProperties
operator) when processing Triggers/Actions:
- applicationData: A collection of useful application state information that is fetched during trigger processing. The (current) fields provided are:
See the interface "ActionApplicationData" in ./src/types.ts
for all the properties available in applicationData
.
- outputCumulative: When sequential Actions run, the output from each one is collected into this combined object and passed to subsequent Actions in the sequence. So the final Action in a sequence will have access to the output properties from all previous Actions.
All plugins expect an input object of the following shape:
{
parameters: <required and optional parameters>,
applicationData: ..,
outputCumulative:...,
DBConnect:...,
}
Note that applicationData
is regenerated between each Action in a sequence, so each plugin will have access to up-to-date data (even though it may have changed as a result of previous sequential Actions).
Examples:
- If you want a certain Action to only run when the current application status is "Draft", the
condition
expression would be:
{
operator: "=",
children: [
{
operator: "objectProperties",
children: ["applicationData.status"]
},
"Draft"
]
}
- For the "Change Status" plugin, the required parameters are
applicationId
andnewStatus
. To change the triggered application to status "Submitted", theparameter_queries
expression would be:
{
applicationId: {
operator: "objectProperties",
children: ["applicationData.applicationId"] },
newStatus: "Submitted"
}
- A sequential "Console Logger" Action, which follows after "Create User" and "Change Outcome", needs to print a message about newly-created User to the console. It's
parameter_queries
expression could be:
{
message: {
operator: "CONCAT"
children: [
"Output concatenation: The user ",
{
operator: "objectProperties",
children: [ "currentUser.username" ]
},
"'s registration has been ",
{
operator: "objectProperties",
children: [ "applicationData.outcome" ]
}
]
}
}
There is a endpoint on the server which can be used to invoke single actions on demand. This may be useful if, for example, the front-end needs to run an action, such as generating a new serial number (using generateTextString
action)
Endpoint: /run-action
Type: POST
Parameters (via body JSON):
{
"actionCode": "generateTextString", // Code of the action
"applicationId": 4001, // for generating applicationData, so not required for all actions
"parameters": {
<...input parameters for the action itself>
}
}
TO-DO: Add authentication to Endpoint (and most other endpoints)
Powered by mSupply