Skip to content
74 changes: 72 additions & 2 deletions site/content/integrate/plugins/interactive-dialogs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Integrations open dialogs by sending an `HTTP POST`, containing some data in the

Moreover, [plugins]({{< ref "/integrate/plugins/using-and-managing-plugins" >}}) can trigger a dialog based on user actions. For instance, if a plugin adds a button in the channel header, clicking that button may open a dialog.

From Mattermost v11.10, dialogs can be stacked: an [`action_button`](#action-button-elements) element inside a dialog lets a user open a child dialog on top of the current one. Up to three dialogs may be open at once; any request to open a dialog beyond this limit is silently ignored by the client.

Here is an example of what a dialog looks like for creating a Jira issue within the Mattermost user interface:

![image](interactive-dialog-example.png)
Expand Down Expand Up @@ -69,6 +71,7 @@ Each dialog supports elements for users to enter information.
- `date`: Date picker field. Use this for selecting dates without time information.
- `datetime`: Date and time picker field. Use this for selecting both date and time with timezone support.
- `file`: File upload field. Use this to allow users to attach one or more files as part of a dialog submission.
- `action_button`: Clickable button that opens a child (stacked) dialog. Use this to branch into a follow-up dialog without submitting the current one. (Minimum server version 11.10.)

Each element is required by default, otherwise the client will return an error as shown below. Note that the error message will appear below the help text, if one is specified. To make an element optional, set the field `"optional": "true"`.

Expand Down Expand Up @@ -623,7 +626,7 @@ The `datetime_config` object groups date/datetime configuration into a single ne
- Invalid: `"time_interval": 7` (7 is not a divisor of 1440)

### File elements
##### Minimum Server Version: 11.9
##### Minimum Server Version: 11.10

File elements allow users to upload one or more files as part of an interactive dialog submission. Below is an example of a `file` element that requests a single file attachment.

Expand Down Expand Up @@ -671,6 +674,69 @@ The full list of supported fields is included below:

When a dialog containing file elements is submitted, the uploaded file IDs are sent in a top-level `file_ids` array alongside the standard `submission` map. Use `file_ids` as the authoritative source of uploaded file IDs — each ID can be used with the [Files API](https://api.mattermost.com/#tag/files) to attach files to posts or retrieve file metadata.

### Action button elements
#### Minimum Server Version: 11.10

Action button elements render a clickable button inside a dialog. Instead of submitting the current dialog, clicking the button asks your integration to open a *child* dialog that is stacked on top of the current one. Use this to branch into a follow-up workflow (for example, "Add another item" or "Configure advanced options") while preserving the dialog the user is already working in.

```json
{
"display_name": "Add attachment",
"name": "add_attachment",
"type": "action_button",
"action_button": {
"url": "https://your-mattermost-server.com/plugins/your-plugin-id/api/attach",
"context": {
"action": "open_attachment_dialog"
}
}
}
```

The full list of supported fields is included below:

| Field | Type | Description |
|-----------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------|
| `display_name` | String | Display name shown on the button. Maximum 24 characters. |
| `name` | String | Name of the field element used by the integration. Maximum 300 characters. You should use unique `name` fields in the same dialog. |
| `type` | String | Set this value to `action_button` for an action button element. |
| `action_button` | Object | Action button configuration. Required for this element type. See the fields below. |

The `action_button` object supports:

| Field | Type | Description |
|-----------|--------|---------------------------------------------------------------------------------------------------------------------------------------|
| `url` | String | The URL the action is sent to when the button is clicked. Required. Must be a valid lookup URL — an HTTPS URL or a `/plugins/` path. |
| `context` | Object | (Optional) String map of arbitrary key/value pairs forwarded to your integration when the button is clicked. Use this to identify which button was pressed or to carry state. |

Action button elements are not input fields: their values are never included in the dialog submission payload, and they are not subject to the required/optional validation applied to other elements.

#### Action button flow

When a user clicks an action button, the Mattermost client sends an `HTTP POST` to the `/api/v4/actions/dialogs/execute` endpoint. The server validates the request, generates a new trigger ID, and forwards the button's `context` to the `url` configured on the button. The payload your integration receives is a `PostActionIntegrationRequest`:

```json
{
"type": "dialog_action",
"trigger_id": "<new trigger ID generated by the server>",
"user_id": "<user ID of the user who clicked the button>",
"user_name": "<username of that user>",
"channel_id": "<channel ID the user clicked the button from>",
"channel_name": "<name of that channel>",
"team_id": "<team ID the channel belongs to, empty for DM/GM channels>",
"team_name": "<name of that team, empty for DM/GM channels>",
"context": {
"action": "open_attachment_dialog"
}
}
```

Use the `trigger_id` from this payload to [open a child dialog](#open-a-dialog) — send an `HTTP POST` to `/api/v4/actions/dialogs/open` exactly as you would for a top-level dialog. The child dialog is displayed stacked on top of the dialog the user clicked the button in.

{{<note "Note:">}}
Up to three dialogs may be open at once. If three dialogs are already open, the request to open a further child dialog is silently ignored by the client, so design your workflows to stay within this limit.
{{</note>}}

## Dialog submission

When a user submits a dialog, Mattermost will perform client-side input validation to make sure:
Expand All @@ -687,7 +753,7 @@ The submission payload sent to the integration is:
"state": "<state provided by the integration>",
"user_id": "<user ID of the user who submitted the dialog>",
"channel_id": "<channel ID the user was in when submitting the dialog>",
"team_id": "<team ID the user was on when submitting the dialog>",
"team_id": "<team ID the channel belongs to, empty for DM/GM channels>",
"submission": {
"some_element_name": "<value of that element>",
"some_other_element": "<value of some other element>"
Expand All @@ -697,6 +763,10 @@ The submission payload sent to the integration is:
}
```

{{<note "team_id behavior change (server version 11.10):">}}
For the `/api/v4/actions/dialogs/submit`, `/api/v4/actions/dialogs/lookup`, and `/api/v4/actions/dialogs/execute` endpoints, the `team_id` forwarded to your integration is now always derived by the server from the channel the dialog was opened in, rather than from the value supplied by the client. Any client-supplied `team_id` is ignored. For direct (DM) and group (GM) message channels — which do not belong to a team — `team_id` is sent as an empty string. If your integration previously relied on a client-supplied `team_id` for team-specific logic, update it to use this channel-derived value (and to handle the empty case for DM/GM channels).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a breaking change? Are we notifying the customers as this being a breaking change?

{{</note>}}

Optionally, the dialog can send an event back to the integration if `notify_on_cancel` parameter is set to `true`. If this happens, `cancelled` will be set to `true` on the above payload, and `submission` will be empty.

Moreover, Mattermost also allows the integration itself to perform input validation. This can be done by responding to the dialog submission request with a JSON body containing an `errors` field. The `errors` field can contain a JSON object, mapping input field names to string error messages you would like to display to the user. For example, if you have a field named `num_between_0_and_10`, you can enforce the user to enter a number between 0 and 10 by returning the following response body if the condition isn't satisfied:
Expand Down
Loading