Form Fields
Although Limecraft Flow already has a lot of built-in fields, it is often useful to be able to define your own fields, relevant to your use case.
Form Fields can be used to attach custom metadata properties to Delivery Request (submissions), Collections, and Productions. They can also be used to configure user input on actions. Form Fields actually consist out of two parts: FormFieldDefinitions and FormFieldValues.
FormFieldsDefinition: Setting up form fields
The structure and presence of form fields can be defined and limited by using the FormFieldsDefinition.
Each time a form field is updated or created, that field is validated against the relevant FormFieldsDefinition.
-
For Productions both the form field values and the definition are stored at the production object itself.
-
For DeliveryRequests, the definition is located at the delivery request. The values are stored at the submission.
Property reference
At the top level, the FormFieldsDefinition contains the properties listed below. Each of these will be explained further below in their own subsection.
| Field Name | Required | Type | Description | Format |
|---|---|---|---|---|
clientSettings |
✘ |
Object |
||
fields |
✘ |
Map of FormFieldDefinition |
The list of form fields who are subject to validation/visualisation |
|
layout |
✘ |
Object |
||
name |
✘ |
String |
||
validationRules |
✘ |
ValidationRules |
Example FormFieldsDefinition
An example with comments of such a FormFieldsDefinition is:
{
fields: {
episode_title: {
userProperties: { // use for client-side only properties. The backend does nothing with these properties.
prop1: 'value1',
prop2: 'value2',
prop3: 'value3'
},
order: 0.5,
//The type is enforced by trying to cast/convert the values in the custom fields to the type denoted in the CustomFieldsDescription.
// Available types are: STRING, TEXT, BOOLEAN, INTEGER, DATE, DOUBLE and LONG.
type: 'STRING',
//Value to display when the annotation has no value for this custom field
defaultValue: 'no_episode',
//Label to be shown in ui
label: 'episode_title',
//Description
description: 'episode title',
},
clip_number: {
userProperties: {
prop1: 'value1'
},
order: 0.1,
type: 'INTEGER',
defaultValue: 1,
label: 'clip_number',
description: 'clip number'
},
author: {
description: 'Author',
label: 'Author',
skipWhiteListValidation: true,
type: 'STRING',
//It's possible to define blacklist and whitelist values, if the value isn't in the whitelist the the call will be rejected
// unless the skipWhiteListValidation parameter is set. Whitelist validation will also be skipped when the array is empty.
whiteList: [
'Gimli'
],
//When a value is added to the blacklist it's not possible to set the field to that value.
blackList: [
'Legolas'
],
}
}
}
Fields
The fields Map of a FormFieldsDefinition contains the definitions of the individual fields. It is a map from the name of a field to a FormFieldDefinition. The structure of the latter is given below.
Property Reference
The list of form fields who are subject to validation/visualisation
| Field Name | Required | Type | Description | Format |
|---|---|---|---|---|
allowList |
✘ |
List of object |
The list of allowed/possible values. Used in combination with `skipWhiteListValidation`. When `skipWhiteListValidation = true`, the client can use the list as possible values. |
|
autocompleteExtractor |
✘ |
String |
Used by Limecraft Flow to accomplish autocomplete. |
|
autocompleteUrl |
✘ |
String |
Id of the thesaurus which is used for autocomplete. |
|
blackList |
✘ |
List of string |
The list of forbidden values. |
|
clientConfig |
✘ |
Object |
||
compoundDefinition |
✘ |
FormFieldsDefinition |
||
defaultValue |
✘ |
Object |
Can be used be the client, empty form fields are not filled in with the default value by the server |
|
description |
✘ |
String |
Additional information for the form field |
|
handle |
✘ |
String |
A unique handle which can be used to be referenced in the validation rules |
|
hidden |
✘ |
Boolean |
Indicator for Limecraft Flow to show the form field or not. |
|
label |
✘ |
String |
Label for visualization by the client |
|
multiValued |
✘ |
Boolean |
Denotes whether this is a multivalued form field or expects a single value |
|
order |
✘ |
Double |
The order in which the form fields need to be displayed |
double |
readOnly |
✘ |
Boolean |
Indicator for Limecraft Flow to enable form field editing. |
|
required |
✘ |
Boolean |
This field is required. |
|
requiresId |
✘ |
Boolean |
When set, an id is expected for each value in the form fields, typically used in combination with thesaurus. Each entry in the value list will have an id which corresponds to an id in the given thesaurus. The ids itself are not verified. |
|
skipWhiteListValidation |
✘ |
Boolean |
Skips the validation of the whiteList. |
|
subtype |
✘ |
String |
Determines the model type in case type = FLOW_OBJECT |
|
thesaurus |
✘ |
String |
Id of the thesaurus which is used for autocomplete. |
|
type |
✘ |
String |
Determines how the field will be indexed and stored |
Enum: STRING, BOOLEAN, INTEGER, DATE, DOUBLE, LONG, JSON, TEXT, FRAME, COMPOUND, FLOW_ID, FLOW_OBJECT, |
userProperties |
✘ |
Object |
||
whiteList |
✘ |
List of string |
The list of allowed/possible values. Used in combination with `skipWhiteListValidation`. When `skipWhiteListValidation = true`, the client can use the list as possible values. |
userProperties
The userProperties property of a FormFieldDefinition stores properties which influence how a field is shown to the user. These properties are not interpreted or used by the API, only by the Limecraft Flow User Interface.
userProperties.type
Via userProperties.type, one can choose the visualization used for the field. Note that this does not change the storage type, which is set via the type property.
The following table lists which userProperties.type values are compatible with which type values. More info on the behaviour of each userProperties.type can be found in the user input fields documentation.
| type | supported userProperties.type |
|---|---|
|
|
INTEGER |
|
DOUBLE |
|
LONG |
|
DATE |
|
FRAME |
|
|
|
|
|
JSON |
|
COMPOUND |
|
For example, in the FormFieldDefinition below, label and type indicate to the backend this field should be stored as a "STRING" and has label "Role". In addition, via userProperties, we indicate to the Limecraft Flow UI that it should be shown as a "SELECT" dropdown input, with the given selectOptions. The allowList property is used to pass the options to show in the dropdown.
{
"label": "Role",
"type": "STRING",
"allowList": [
{
"label": "Actor",
"value": "ACTOR"
},
{
"label": "Writer",
"value": "WRITER"
},
{
"label": "Author",
"value": "AUTHOR"
}
],
"userProperties": {
"type": "SELECT"
}
}
userProperties.parameterName
The (dot-separated) path to the actual parameter to
set when starting the external service. This only has a meaning when used in the context of an action (eoAction, productionAction, clipAction).
example:
-
"theParameter"
userProperties.extraInputAttributes
An object used to contain extra attributes added to the html input field.
examples:
-
{"step": 5} -
{ autocomplete: "on" }
userProperties.extraOptions
The extraOptions is used to modify a field in various ways. The options do not necessarily work on all types, and are not guaranteed to work in all places.
Email options
-
Multivalued email input will use a 'tag look' by default. If you prefer the full blown multiValued look, set
extraOptions.multiValued.forcetotrue. -
The
valueof a multiValued EMAIL will be an array of strings. If you prefer a single comma separated string, setextraOptions.asCommaSeparatedStringtotrue.
Icon look for BOOLEAN
Instead of a checkbox, you can show an icon which is grayed out when 'unchecked' and darker when 'checked'.
{
"name": "takeCoffee",
"type": "BOOLEAN",
"label": "Take coffee?",
"userProperties": {
"extraOptions": {
"asIcon": true,
"iconClass": "falk-ligh falk-coffee"
}
}
}
Prefix and Suffix
| Property | Description |
|---|---|
extraOptions.prefix |
The
|
extraOptions.prefixIcon |
The
|
extraOptions.suffix |
The
|
extraOptions.multiValued
This is an object allowing you to tweak certain aspects of a multiValued field.
Due to legacy reasons, the default look of a multiValued STRING or EMAIL field will have a 'tags look' instead of the default multiValued look (with x and + buttons). If you prefer the normal multiValued look, you’ll have to force it by setting extraOptions.multiValued.force to true.
As a general rule, the field config options will apply to the input of a single value. The exception to this rule is defaultValue, isRequired, parameterName and extraOptions.multiValued.
The extraOptions.multiValued object allows tweaking some of the behaviour further.
{
"name": "emails",
"type": "EMAIL",
"label": "Emails",
"isRequired": true,
"multiValued": true,
"defaultValue": [
"john.doe@acme.corp",
"john.snow@acme.corp"
],
"extraOptions": {
"prefix": "@",
"multiValued": {
"force": true,
"extraContainerClasses": ["deeppink"],
"extraListClasses": ["orange"],
"extraEntryClasses": ["aqua"],
"entryDefaultValue": "new@new.new",
"minCount": 2,
"maxCount": 5
}
},
"parameterName": "workflowParameters.emails"
}
| Property | Description | Example |
|---|---|---|
|
Force 'generic' multivalued behaviour, e.g. for |
|
|
These classes will be applied on the element representing the multivalued field (including the + button and the list) |
|
|
These classes will be applied on the element representing the list of values for the field |
|
|
These classes will be applied on the element representing a single entry in the multivalued field |
|
|
This value is used as the default value of a new entry. |
|
|
The minimum amount of entries. The remove button will not be shown if current amount of entries is not greater than this amount. The default is 1. Set to 0 if you want to allow completely clearing the field. |
|
|
The maximum amount of entries. The plus button will not be shown if current amount of entries is greater or equal to this amount. |
|
extraOptions.maxLength
When using userProperties.extraInputAttributes.maxlength, it will set the maxlength html attribute of the input. The default behaviour will limit the amount of characters one can input into the field. When pasting more, it will only keep the first part of the pasted text.
This can sometimes be confusing. Therefore, we offer an alternative userProperties.extraOptions.maxLength. This will show a small character counter below the field which will become orange when there is a problem. More text than the maxLength can be entered, but it won’t pass validation.
userProperties.parentFieldName
The name of a field serving as the parent of this field. The value of the parent field can influence the value or possible values of this field.
Behaviour for SELECT
Say we have a country parent field:
{
"name": "country",
"type": "STRING",
"allowList": [
{ "value": "BE", "label": "Belgium" },
{ "value": "US", "label": "United States" }
],
"userProperties": {
"type": "SELECT"
}
}
Now let’s define a state field which will only show the states in the chosen country. The child field allowList should contain an extra property parentValue:
{
"name": "state",
"type": "STRING",
"selectOptions": [
{ "value": "BE-VOV", "label": "Oost-Vlaanderen", "parentValue": "BE" },
{ "value": "BE-VAN", "label": "Antwerpen", "parentValue": "BE" },
{ "value": "US-CA", "label": "California", "parentValue": "US" },
{ "value": "US-AZ", "label": "Arizona", "parentValue": "US" }
],
"userProperties": {
"type": "SELECT",
"parentFieldValue": "country"
}
}
The select dropdown will only show the allowList options for which the option has parentValue equal to the current value of the parent field. If the parent field has no value, the field will show no options at all.
Behaviour for STRING with allowValues
The behaviour is similar to that of SELECT explained in the previous section. The child field will only show allowList options which have a parentValue equal to the current value of the parent field. If the parent field has no value, the field will show no autocomplete.
userProperties.selectButton
The SELECTBUTTON input uses this object for styling the input.
{
"buttonClass": "fb-t-default fb-a-primary fb--size-large",
"menuClass": ""
}
userProperties.timecode
The FRAME input require knowledge of the frame rate. In some contexts, this is filled in automatically by the UI code, but in general, you will have to pass the frame rate to the input. This is done using the timecode.frameRate field.
It is also possible to offset the visualized timecode by setting timecode.offsetFrames to something different than 0. With a framerate of 25fps, an offsetFrames of 50 would result in the input value "00:00:02:00" to be converted to frame 0 (and not 50).
example:
{
"frameRate": {
"numerator": 25,
"denumerator": 1
},
"offsetFrames": 0
}
Compound fields
A compound field is a form field with type "COMPOUND" and with a valid compoundDefinition. Compound fields give the possibility to define certain combinations of fields into a record.
As the definition is recursive (compoundDefinition is of type FormFieldsDefinition), this makes for a very powerful and flexible structure.
The example below defines a COMPOUND type with fields name and age. Note that we also made the field multiValued.
{
"type": "COMPOUND",
"hidden": false,
"label": "Record",
"multiValued": true,
"readOnly": false,
"requiresId": true,
"compoundDefinition": {
"clientSettings": {},
"fields": {
"name": {
"type": "STRING",
"label": "Your name"
},
"age": {
"type": "LONG",
"label": "Age"
}
}
}
}
The values of the example above would look like [{ name: "Luke", age: 30 }, { name: "John", age: 40 }], so an entire table of information can be stored.
Validation
Validation of the form fields occurs at update time, meaning that form fields that do not pass the validation will be rejected and will thus not be stored.
During validation, a number of checks occur:
-
all form field values must have a definition;
-
the type of the value is checked against the defined type;
-
value must not be empty;
-
multiple values for a single-valued field;
-
no valueId when requiresId is set;
-
whiteList/blackList check;
-
validationRules: ValidationRules
ValidationRules
These are evaluated using the validation engine.
The validation rules can run at different stages. It is also possible to set up a validationRule which runs in the UI directly.
The following example defines two fields in and out, and defines a restriction on them so that the value of out should be greater than the value of in.
{
formFieldsDefinition: {
"fields": {
"in": {
label: 'In',
type: 'INTEGER',
},
"out": {
label: 'Out',
type: 'INTEGER',
}
},
"validationRules": {
"rules": [
{
"description": "Not a valid timecode range",
"evaluateClientSide": "Blur",
"handle": "out-gt-in",
"operator": "AND",
"rules": [
{
"leftSide": {
"select": "out.value"
},
"op": "gt",
"rightSide": {
"select": "in.value"
},
"type": "LIMECRAFT_RULE"
}
],
"showClientSide": false,
"validateAt": [
"Runtime",
"DeliveryRequestSubmissionSubmit"
]
}
]
}
}
}
validateAt
When validateAt contains "Runtime", and evaluateClientSide is a valid value, the validation rule will execute on the Limecraft Flow UI client. This is not possible for every LIMECRAFT_RULE. Learn more about client side validationRules.
Other values depend on the context the form field is used in. For example, for a DeliveryRequestSubmission, there is a "DeliveryRequestSubmissionSubmit" value. This allows saving values that are not passing the validation rules, but it won’t allow submitting the DeliveryRequestSubmission with these invalid values.
compound validationRules
Note that validationRules can be defined at different levels. Each COMPOUND form field can again have validationRules defined.
refer to fields using a handle
The handle property of a form field can be set to a unique value (within the form). The validation rules can reference this field using the handle by appending it with a colon in the select.
{
"leftSide": {
"select": "myHandle:/value"
}
}
Using the form field name only works when the other field is at the same level. With handle you can reference fields which are further away in the tree of fields (e.g. a part of another COMPOUND field).
ClientSettings
This is a place to store json data which is not interpreted by the backend but can be used by the client application. This is not used at this time.
Layout
The layout is a JSON definition on how the inputs should be presented and grouped on screen.
See Configure a layout to learn how to write a layout for your fields.
The example below defines a layout for 3 fields. The last field people, illustrates the possibility to pass a layoutConfig down to the compound field.
{
"type": "basic",
"elements": [
{
"name": "name",
"type": "field-with-label"
},
{
"name": "isanNumber",
"type": "field-with-label"
},
{
"name": "people",
"type": "field-with-label",
"extraClasses": [
"flow-flex-col"
],
// you can pass a layoutConfig into the compound field
// the compound has fields name and age
"layoutConfig": {
"type": "basic",
"extraListClasses": [
"flow-flex-row vert-gap-10px gap-20px"
],
"elements": [
{
"name": "name",
"type": "field",
"extraClasses": [
"flow-flex-col"
]
},
{
"name": "age",
"type": "field",
"extraClasses": [
"flow-flex-col"
]
}
]
}
}
],
// classes applied on the layout element at this level
"extraClasses": [
"page-style-1__form",
"version-40px"
],
// classes applied to the list element containing the children of
// the layout element at this level
"extraListClasses": [
"flow-flex-col vert-gap-20px"
]
}
FormFieldValues
We talked a lot about defining the definition of form fields, now it’s time to talk about how to store actual values. Form Field Values are a map of the fields declared in the definition containing the actual value for that field.
For the reader familiar with Custom Fields, Form Fields might look very familiar. The FormFieldValues contain only the actual value(s) though, no label or type is stored here. Also in contrast to Custom Fields, single-valued fields have the value property; multivalued fields have the values property.
Property Reference
Single Valued
If the FormFieldDefinition does not have multiValued=true, a form field value is an object with keys value and optionally valueId.
| Field Name | Required | Type |
|---|---|---|
value |
The value of the form field |
String, Number, Boolean |
valueId |
An id corresponding to the value of the field. Currently only used for fields linked to a thesaurus. |
String |
Multi Valued
If the FormFieldDefinition has multiValued=true, a form field value is an object with keys values and optionally valueIds and handles.
| Field Name | Required | Type |
|---|---|---|
values |
The value of the form field |
Array |
valueIds |
An id corresponding to the value of the field. Currently only used for fields linked to a thesaurus. |
Array |
handles |
A locally unique handle. Used for creating pointers to values that do not depend on the array index position. |
Array |
handles
Handles were introduced for multiValued form field values to avoid pointers to form field values that contains array indices, see also withinTargetPointer.
handles is an optional array which is a sibling to values and (optional) valueIds.
{
"values": ["John", "Don", "Ron"],
"valueIds": [1, 2, 3],
"handles": ["0mjj3OrYyuI", "74HWAn0JEla", "EyuuyVUYUpn"]
}
Its reason of existence is when using pointers to address some form field value, like we do with Partial Reject feature. A pointer like /names/values/1 is dependent on the array index and suffers from array index drift if some name is added or removed at or before index position 1. To make things more robust, we introduced handles and a colon in the pointer indicating special resolving:
/names/values/:b
The :b is interpreted as "the array index where 'b' is at in the sibling handles array".
The handles are set by the client. A handle can only contain the 64 characters that are allowed in base64 (so 65th '=' char is not allowed). By convention we use an 11-char string like "EyuuyVUYUpn".
Examples
String, Text
A single-valued STRING (or TEXT) field’s formFieldValues might look like this
{
"stringFormField": {
"value": "myValue"
},
}
For a multi-valued STRING (or TEXT) field
{
"multiValuedStringFormField": {
"values": [
"myText1",
"myText2"
]
},
}
String linked to thesaurus
When a STRING field is linked to a thesaurus, the formFieldValues will also contain a valueId property.
{
"thesaurusFormField": {
"value": "Lost in translation",
"valueId": "123456"
},
}
For a multi-valued STRING field linked to a thesaurus we use valueIds instead.
{
"multiThesaurusFormField": {
"values": [
"Lost in translation"
],
"valueIds": [
"123456"
]
}
}
Boolean
A single-valued BOOLEAN field’s formFieldValues might look like this
{
"booleanFormField": {
"value": true
},
}
For a multi-valued BOOLEAN field
{
"multiValuedBooleanFormField": {
"values": [
true,
true
]
},
}
Integer, Long
A single-valued INTEGER (or LONG) field’s formFieldValues might look like this
{
"integerFormField": {
"value": 50
},
}
For a multi-valued INTEGER (or LONG) field
{
"multiValuedIntegerFormField": {
"values": [
50,
100
]
},
}
Double
A single-valued DOUBLE field’s formFieldValues might look like this
{
"doubleFormField": {
"value": 10.0
},
}
For a multi-valued DOUBLE field
{
"multiValuedDoubleFormField": {
"values": [
10.0,
20.0
]
},
}
Date
A single-valued DATE field’s formFieldValues might look like this
{
"dateFormField": {
"value": 1681476898907
},
}
For a multi-valued DATE field
{
"multiValuedDateFormField": {
"values": [
1681476898907,
1681390498955
]
},
}
Frame
A single-valued FRAME field’s formFieldValues might look like this
{
"frameFormField": {
"value": 100
},
}
For a multi-valued FRAME field
{
"multiValuedFrameFormField": {
"values": [
100,
200
]
},
}
Json
A single-valued JSON field’s formFieldValues might look like this
{
"jsonFormField": {
"value": {
"randomField": 5
}
},
}
For a multi-valued JSON field
{
"multiValuedJsonFormField": {
"values": [
{
"randomField": 5
},
{
"randomField": 5
}
]
},
}
Compound
A single-valued COMPOUND field’s formFieldValues might look like this
{
"compoundFormField": {
"value": {
"name": {
"value": "John Doe"
},
"age": {
"value": 37
}
}
},
}
For a multi-valued COMPOUND field
{
"multiValuedCompoundFormField": {
"values": [
{
"name": {
"value": "John Doe"
},
"age": {
"value": 37
}
},
{
"name": {
"value": "Francis Ford Copolla"
},
"age": {
"value": 21
}
}
]
},
}
Setting the value of a form field
Once the FormFieldsDescription is set up, you can start saving values to them.
DeliveryRequestSubmission
Setting form field values is done by updating the DeliveryRequestSubmission object.
To update the form field of a DeliveryRequestSubmission, you can use a PATCH call as shown below.
PATCH /api/production/7238/delivery_request_submission/3085614
[
{
"op": "add",
"path": "/formFieldValues",
"value": {
"name": {
"value": "001. Aflevering 1"
},
"isanNumber": {
"value": "test"
}
}
}
]