Skip to main content
Version: 9 - Germknödel

Messages and Forms

Cloudomation Engine executions can generate messages and forms for Engine users to read and respond.

Use Cases

Use messages to

  • provide status updates about active executions
  • log processing steps
  • store reports or results

Use forms to

  • query parameters from Engine users
  • wait for confirmation by Engine users

Concept

You can also refer to the underlying message activity here.

Usage

Messages and forms are created by executions. In the Engine user interface messages are accessible via the bell icon in the top menu bar.

The messages button

note

The bell icon can contain a badge with the number of messages which are waiting for a response.

Clicking on a message subject in the "Latest messages" popover will open the message and display the message form.

tip

If an execution is currently waiting for a response of a message, the message form is also embedded within the execution screen.

Simple informational message

To create a simple informational message use the message argument of the this.message() call. The message will be rendered as markdown and include an "OK" button.

example

Create an informational message

import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):
this.message(
subject='Information message',
message=(
'''
# Message body
with **Markdown** formatting!
'''
),
)
return this.success('all done')

note

The execution always waits until an informational message has been acknowledged by a user clicking the OK button. To skip waiting for a message response use the form this.message(..., wait=False).

Simple request form

To create a simple request form use the request argument of the this.message() call. The message will include one string input field and an "OK" button. The value entered by the user is accessible in the string key of the response dictionary.

example

Request one simple input from a user

import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):
message = this.message(
subject='Input request',
request='Please enter some value',
)

# retreive the value which was entered
# the value of a "request" message is always of type string
# and stored in the key `string`
value = message.get('response')['string']

this.log(value=value)

return this.success('all done')

Wait Timeout

Executions can be configured to wait for a message response with a timeout. If the message was not submitted within the timeout, a MessageResponseTimeoutError will be thrown.

example

Use a message wait timeout

import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):
try:
message = this.message(
subject='Input request',
request='Please enter some value',
wait_timeout=60, # allow 60 seconds to answer the message
)
except flow_api.MessageResponseTimeoutError:
this.log('Message was not responded within 60 seconds')
else:
# retreive the value which was entered
# the value of a "request" message is always of type string
# and stored in the key `string`
value = message.get('response')['string']

this.log(value=value)

return this.success('all done')

Deleting

When deleting an execution which currently is waiting for a message response, the message will be deleted as well.

When deleting a message which is currently waited for by an execution, the execution will be notified and raise an ResourceNotFoundError.

Advanced message form

To create advanced message forms use the body argument of the this.message() call. The message can contain multiple informational fields, input fields, and submit buttons. The structure of the response dictionary is configured by the names of the fields.

The value of the body argument is validated with SCHEMA_MESSAGE_BODY which is outlined below:

SCHEMA_MESSAGE_FIELD = {
'type': 'object',
'properties': {
# the form element to use
'element': {
'type': 'string',
'enum': [
'string', # string input field
'number', # number input field
'password', # password input field
'date', # date picker
# returned as string in the format YYYY-mm-dd
'time', # time input field or picker (browser dependent)
# returned as string in the format HH:MM
'date-time', # date-time picker
# returned as string in the format YYYY-mm-ddTHH:MM
'markdown', # markdown output
'toggle', # toggle button
# returned as boolean
'submit', # submit button
# the button which was pressed
# will return boolean `True`
]
},
# datatype of the value in the response dictionary
'type': {
'type': 'string',
'enum': ['string', 'number', 'boolean']
},
# label for the element. if unset, the name of the field is used.
'label': {
'type': 'string'
},
# the "placeholder" value, displayed when the input field is empty
'example': {
'type': ['string', 'number', 'null']
},
# the order in which the element will appear in the form
'order': {
'type': 'integer'
},
# a default value which is pre-filled
'default': {
'type': ['string', 'number', 'boolean', 'null']
},
# an additional format validator.
# see https://json-schema.org/understanding-json-schema/reference/string.html#format
'format': {
'type': 'string'
},
# the markdown content
'docs': {
'type': 'string'
},
},
'required': [
'element',
'type',
'order',
],
'additionalProperties': False,
"if": {
"properties": { "element": { "const": "submit" } }
},
"then": {
"properties": { "type": { "const": "boolean", } }
},
"else": {
}
}

SCHEMA_MESSAGE_PROPERTIES = {
'type': 'object',
'patternProperties': {
# field names must match this pattern
'^[a-zA-Z0-9_]+$': SCHEMA_MESSAGE_FIELD,
},
}

SCHEMA_MESSAGE_BODY = {
'type': 'object',
'properties': {
# always "object"
'type': {'type': 'string', 'enum': ['object']},
'properties': SCHEMA_MESSAGE_PROPERTIES,
# a list of field names which must be entered by the user
'required': {'type': 'array', 'items': {'type': 'string'}},
},
'required': ['type', 'properties'],
}
warning

Naming an input field cloudomation_fe_timezone will cause an error message!

tip

All message forms return the timezone of the user's browser when filling in the form.
You can retrieve it from the response with the key cloudomation_fe_timezone.

example

Create a message form to query several inputs from a user:

import flow_api

def handler(system: flow_api.System, this: flow_api.Execution, inputs: dict):
message = this.message(
subject='Message form',
body={
'type': 'object',
'properties': {
# the key in the response dictinary where the value will be stored
'string-field': {
'element': 'string',
'type': 'string',
'example': 'enter a string',
'order': 1,
'label': 'string-field-label',
},
'number-field': {
'element': 'number',
'type': 'number',
'example': 'enter a number',
'order': 2,
},
'date-field': {
'element': 'date',
'type': 'string',
'format': 'date',
'order': 3,
},
'time-field': {
'element': 'time',
'type': 'string',
'format': 'time',
'order': 4,
},
'date-time-field': {
'element': 'date-time',
'type': 'string',
'format': 'date-time',
'order': 5,
},
# the markdown field is only informational and does
# not produce a key in the response dictionary
'markdown-field': {
'element': 'markdown',
'docs': '### Markdown\n\n- item 1\n- item 2\n- item3',
'order': 6,
},
'toggle-button': {
'element': 'toggle',
'type': 'boolean',
'order': 7,
},
'submit-button': {
'element': 'submit',
'type': 'boolean',
'order': 8,
},
'alternative submit-button': {
'element': 'submit',
'type': 'boolean',
'order': 9,
},
},
'required': [
'string-field',
'time-field',
],
},
)

# retreive all values which were entered
response = message.get('response')

this.log(response=response)

return this.success('all done')

Learn More

Email Integration
Flows
Webhooks