Components

The Tray Javascript class
Copy

To interact with the slots in the javascript code, you need to use the Tray javascript class. This class comprises the following:

  1. Events: these allow you to listen to the load and change events of each slot in the wizard.

  2. Functions: these allow you to interact with the Tray system and extend the functionality of your code.

  3. Environment variables: these allow you to define a set of variables in the code editor, allowing you to abstract the code.

The slot state
Copy

The purpose of Custom JS code is to modify the state of a slot.

Each event is invoked with a set of arguments that describes the different states that you need to listen to.

In the javascript code you either return nothing (maintain the current slot state) or you return a new slot state.

The slot state is a javascript object that comprises the following properties:

  1. externalId: the external ID of the slot, which matches what you can find in the slot's settings

  2. jsonSchema: the schema that defines how the slot should be rendered in the wizard. Follows the JSON schema standard that you can learn more about here: https://json-schema.org/understanding-json-schema/

  3. status: the status of the slot - one of HIDDEN , LOADING , VISIBLE . When a slot is first mounted on to a screen (loaded), it's status is always LOADING .

  4. value: the value of the slot

  5. validation: an object that can be specified in order to throw an error message and block the user from proceeding past the current config wizard screen. When specified as an empty object (default) or undefined no error message will be shown.

  6. className: set a custom class name for the slot. You can use this when defining CSS rules to change the style of the slot.

The state schema is defined as follows in Tray (denoted by JavascriptConfigItemResult):

1
type JavascriptConfigItemResult {
2
status: 'loading' | 'hidden' | 'visible';
3
className ? : string;
4
validation: SlotValidation;
5
jsonSchema: TraySchema7;
6
value: any; // Config slot value
7
}
8
type SlotValidation = {
9
status: 'ERROR';
10
message: string;
11
};

Here is an example state that you could expect to see:

1
{
2
"externalId": "external_salesforce_object",
3
"jsonSchema": {
4
"type": "string"
5
},
6
"status": "VISIBLE",
7
"value": "First name",
8
"validation": {
9
"status": "ERROR",
10
"message": "First name is not a valid value for this field"
11
}
12
}

Tray events
Copy

A note on events: let's say we have a screen where we have two config slots, and on the second slot we have enabled custom javascript. The script for the second slot will listen to events occurring in all slots on the same screen. In this way, you can define dependencies between slots on the same screen (see example for Showing/hiding slots based on dependencies)

  1. The CONFIG_SLOT_MOUNT event is fired when a config slot has loaded onto the screen.

  2. The CONFIG_SLOT_VALUE_CHANGED event is fired when the value of a config slot has been changed.

  3. The CONFIG_SLOT_STATUS_CHANGED event is fired when the status of a config slot has been changed. (example HIDDEN to VISIBLE)

  4. The AUTH_SLOT_MOUNT event is fired when an auth slot has loaded onto the screen.

  5. The AUTH_SLOT_VALUE_CHANGED event is fired when the value of an auth slot has been changed, i.e. a new authentication has been selected.

When the custom javascript is enabled on a slot for the first time, you will notice an example implementation is prefilled that implements the CONFIG_SLOT_MOUNT event.

Event arguments
Copy

Each event is invoked with an object argument that contains the following properties:

1 - event: contains information about the type of event that has fired, as well as data about the state of the slot for which the event fired.

For example, the slot for the salesforce object shown above with external ID external_slot_id will fire the CONFIG_SLOT_MOUNT event when first rendered on a screen. The value of the event would look something like the following:

1
{
2
"type": "CONFIG_SLOT_MOUNT",
3
"data": {
4
"externalId": "external_salesforce_object",
5
"jsonSchema": {
6
"type": "string"
7
},
8
"status": "LOADING"
9
}
10
}

2 - previousSlotState: contains information about the state of the slot before the current event is fired.

This is most useful when listening to changes in other slots, as this property will contain the current schema of the slot on which the javascript is implemented.

The example below shows how this is used in practice. The value of this is the slot's state schema, so in this example where the slot is mounted and no schema has been set, this would be:

1
{
2
"externalId": "external_salesforce_object",
3
"jsonSchema": {},
4
"status": "LOADING"
5
}

3 - previousWizardState:

Contains information about the state of the whole config wizard, including all previous pages.

This is most useful when the rendering of a new slot state depends on the values of previous config and auth slots in the wizard.

For instance, you can access the ID of an auth that has been created by the user for a service in order to dynamically fetch data via API calls and display values to the user as dropdowns (Check example). This property has the following schema (denoted by EmbeddedState):

1
type EmbeddedState {
2
currentScreen: {
3
index: number;
4
status: 'loading' | 'visible';
5
};
6
values: {
7
[slotExternalId: string]: any
8
}
9
validation: {
10
[slotExternalId: string] ? : SlotValidation
11
}
12
}
13
type SlotValidation = {
14
status: 'error';
15
message: string;
16
};

Here's an example for our use case of the previousWizardState when the external_acme_object slot mounts and it's the second slot in the wizard:

1
{
2
"currentScreen": {
3
"index": 1,
4
"status": "VISIBLE"
5
},
6
"values": {
7
"external_acme_object": "Contact"
8
},
9
"validation": {}
10
}

The slot could also be an auth slot, in which case its value is the ID of the authentication that has been created for the end user in Tray:

1
{
2
"currentScreen":{
3
"index":1,
4
"status":"VISIBLE"
5
},
6
"values":{
7
"external_acme_authentication":"asc88xxxxx723"
8
},
9
"validation":{}
10
}

Tray functions
Copy

The tray class currently supports the following function:

callConnector: a wrapper around the GraphQL API mutation callConnector that can be invoked without requiring an API key, to call any Tray connector operation that you can find in the workflow builder.

This function will return a promise that will resolve to the output of the connector call. You can find more information on the API mutation here.

Here is an example of invoking this function in the javascript body to fetch information from Salesforce:

1
// in this example we assume that we have an authentication slot for Salesforce with external ID external_salesforce_authentication
2
const authId = previousWizardState.values.external_salesforce_authentication;
3
const fetchSalesforceAccountFields = await tray.callConnector({
4
connector: 'salesforce',
5
version: '7.5',
6
operation: 'so_object_describe',
7
authId,
8
input: {
9
object: "Account"
10
}
11
});

Unlike the API mutation callConnector, the input does not need to be JSON stringified before sending to the request.

Config wizard environment variables
Copy

Config wizard environment variables allow you to define a set of variables in the code editor, allowing you to abstract the code. You can set them inside the code editor, and then reference them through the tray class in the code under the key env.

An example of this is, By default the editor is set up with the environment variable "slotExternalId" - which you can use to refer to the external ID of the slot you are currently writing code for in the editor. You can access this environment variable in your code with the property tray.env.slotExternalId

1
const slot_external_id = tray.env.slotExternalId;

You can define environment variables in the right-hand panel of the javascript code editor:

Which you can use to reference previously set external variables: