Skip to content

Commit 0abe0df

Browse files
authored
Update documentation for interactive dialog (#1498)
* fix documentation for interactive dialog * Retrigger CI
1 parent 94bdd23 commit 0abe0df

1 file changed

Lines changed: 97 additions & 68 deletions

File tree

  • site/content/integrate/plugins/interactive-dialogs

site/content/integrate/plugins/interactive-dialogs/_index.md

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ Interactive dialogs support the following parameters:
3636
| `submit_label` | String | (Optional) Label of the button to complete the dialog. Default is `Submit`. |
3737
| `notify_on_cancel` | Boolean | (Optional) When `true`, sends an event back to the integration whenever there's a user-induced dialog cancellation. No other data is sent back with the event. Default is `false`. |
3838
| `state` | String | (Optional) String provided by the integration that will be echoed back with dialog submission. Default is the empty string. |
39-
| `is_multistep` | Boolean | (Optional) Set to `true` to enable multi-step dialog functionality. Default is `false`. |
40-
| `refresh_on_select` | Boolean | (Optional) When `true`, sends field refresh requests when select field values change. Default is `false`. |
39+
| `source_url` | String | (Optional) URL for field refresh requests. When a select element with `refresh: true` changes value, Mattermost sends a refresh request to this URL. Also used as the endpoint for multi-step form responses. |
4140

4241
Sample JSON is given below. Form submissions are sent back to the URL defined by the integration. You must also include the trigger ID you received from the slash command or interactive message.
4342

@@ -53,8 +52,7 @@ Sample JSON is given below. Form submissions are sent back to the URL defined by
5352
"submit_label": "<label of the button to complete the dialog>",
5453
"notify_on_cancel": false,
5554
"state": "<string provided by the integration that will be echoed back with dialog submission>",
56-
"is_multistep": false,
57-
"refresh_on_select": false
55+
"source_url": "<optional URL for field refresh and multi-step form handling>"
5856
}
5957
}
6058
```
@@ -218,17 +216,27 @@ To use dynamic select, set `data_source: "dynamic"` and provide a `data_source_u
218216
}
219217
```
220218

221-
When users interact with a dynamic select field, Mattermost will send HTTP POST requests to your `data_source_url` with the following payload:
219+
When users interact with a dynamic select field, Mattermost sends an HTTP POST request to the `/api/v4/actions/dialogs/lookup` endpoint, which proxies the request to your `data_source_url`. The payload uses the same `SubmitDialogRequest` structure:
222220

223221
```json
224222
{
225-
"user_id": "user_id_here",
226-
"channel_id": "channel_id_here",
227-
"team_id": "team_id_here",
228-
"term": "user_search_input"
223+
"type": "dialog_lookup",
224+
"url": "<your data_source_url>",
225+
"callback_id": "<callback ID>",
226+
"state": "<state>",
227+
"user_id": "<user ID>",
228+
"channel_id": "<channel ID>",
229+
"team_id": "<team ID>",
230+
"submission": {
231+
"query": "user_search_input",
232+
"selected_field": "dynamic_field",
233+
"other_field_name": "current_value"
234+
}
229235
}
230236
```
231237

238+
The `submission` map contains `query` (the user's search input), `selected_field` (the field being searched), and current values of all other form fields.
239+
232240
Your endpoint should respond with an array of options:
233241

234242
```json
@@ -239,16 +247,16 @@ Your endpoint should respond with an array of options:
239247
"value": "option1"
240248
},
241249
{
242-
"text": "Option 2",
250+
"text": "Option 2",
243251
"value": "option2"
244252
}
245253
]
246254
}
247255
```
248256

249257
**Security Requirements:**
250-
- Dynamic select URLs must use HTTPS
251-
- URLs must be within the `/plugins/` path for security
258+
- External URLs must use HTTPS
259+
- Plugin paths (starting with `/plugins/`) are proxied locally and do not require HTTPS
252260
- The lookup endpoint should validate user permissions
253261

254262
**Dynamic select with multiselect:**
@@ -322,7 +330,8 @@ The list of supported fields for the `select` type element is included below:
322330
| `type` | String | Set this value to `select` for a `select` element. |
323331
| `multiselect` | Boolean | (Optional) Set to `true` to allow multiple selections from the list. Default is `false`. |
324332
| `data_source` | String | (Optional) One of `users`, `channels`, or `dynamic`. If none specified, assumes a manual list of options is provided by the integration. |
325-
| `data_source_url` | String | (Optional) URL for dynamic option loading when `data_source` is `dynamic`. Must be HTTPS and within `/plugins/` path. |
333+
| `data_source_url` | String | (Optional) URL for dynamic option loading when `data_source` is `dynamic`. Must be HTTPS or a `/plugins/` path. |
334+
| `refresh` | Boolean | (Optional) When `true`, triggers a field refresh request to the dialog's `source_url` when this field's value changes. Use this for dependent dropdowns or conditional form fields. Default is `false`. |
326335
| `optional` | Boolean | (Optional) Set to `true` if this form element is not required. Default is `false`. |
327336
| `options` | Array | (Optional) An array of options for the select element. Not applicable for `users`, `channels`, or `dynamic` data sources. |
328337
| `help_text` | String | (Optional) Set help text for this form element. Maximum 150 characters. |
@@ -613,48 +622,45 @@ Finally, once the request is submitted, we recommend that the integration respon
613622
## Multi-step dialogs
614623
##### Minimum Server Version: 11.1
615624

616-
Multi-step dialogs enable wizard-like form experiences where users can navigate through multiple steps to complete a complex workflow. Each step can have different fields, and form values are preserved as users progress through the steps.
625+
Multi-step dialogs enable wizard-like form experiences where users progress through multiple steps to complete a complex workflow. Each step can have different fields, and form values are accumulated across steps.
617626

618-
To enable multi-step functionality, set `is_multistep: true` in your dialog configuration.
627+
Multi-step behavior is achieved by having your submit handler return a new form instead of closing the dialog. No special dialog property is required.
619628

620629
### Multi-step workflow
621630

622-
1. **Initial dialog**: Open with `is_multistep: true` and provide the first step's elements
623-
2. **Step navigation**: Users can navigate between steps using Next/Previous buttons
624-
3. **State preservation**: Form values are automatically preserved across steps
625-
4. **Final submission**: Submit the completed form with all step data
631+
1. **Initial dialog**: Open a normal dialog with the first step's elements. Use the `state` field to track which step you're on (e.g., `"step_1"`).
632+
2. **Step submission**: When the user clicks Submit, your integration receives a standard `dialog_submission` request with `type: "dialog_submission"`.
633+
3. **Return next step**: Instead of returning an empty response (which closes the dialog), return a response with `type: "form"` and a `form` object containing the next step's dialog definition.
634+
4. **Value accumulation**: The client automatically accumulates submission values across steps. Each step's submission includes all values from previous steps plus the current step.
635+
5. **Final submission**: On the last step, return an empty response (HTTP 200) or `{"type": "ok"}` to close the dialog.
626636

627637
### Multi-step submission handling
628638

629-
When a user submits a multi-step dialog, your integration will receive webhook calls to handle step transitions and final submission:
630-
631-
#### Step transition webhook
632-
633-
When users navigate between steps, Mattermost sends a request to your configured URL with the following payload:
639+
Each step submission uses the standard dialog submission format:
634640

635641
```json
636642
{
637-
"type": "dialog_multistep",
638-
"callback_id": "<callback ID provided by the integration>",
639-
"state": "<state provided by the integration>",
643+
"type": "dialog_submission",
644+
"callback_id": "<callback ID>",
645+
"state": "step_1",
640646
"user_id": "<user ID>",
641647
"channel_id": "<channel ID>",
642648
"team_id": "<team ID>",
643-
"step": 2,
644-
"direction": "next",
645649
"submission": {
646-
"field_name_from_step_1": "value",
647-
"field_name_from_step_2": "value"
648-
}
650+
"step1_field": "value_from_step_1"
651+
},
652+
"cancelled": false
649653
}
650654
```
651655

652-
Your integration should respond with the next step's dialog configuration:
656+
To advance to the next step, your integration responds with a new form:
653657

654658
```json
655659
{
656-
"dialog": {
657-
"title": "Step 2 of 3",
660+
"type": "form",
661+
"form": {
662+
"callback_id": "multistep_wizard",
663+
"title": "Setup Wizard - Step 2 of 3",
658664
"elements": [
659665
{
660666
"display_name": "Step 2 Field",
@@ -663,20 +669,18 @@ Your integration should respond with the next step's dialog configuration:
663669
}
664670
],
665671
"submit_label": "Next",
666-
"state": "updated_state_for_step_2"
672+
"state": "step_2"
667673
}
668674
}
669675
```
670676

671-
#### Final submission
672-
673-
The final step submission uses the same format as regular dialog submissions, but includes data from all steps:
677+
On the final step, the submission includes accumulated values from all steps:
674678

675679
```json
676680
{
677681
"type": "dialog_submission",
678682
"callback_id": "<callback ID>",
679-
"state": "<final state>",
683+
"state": "step_3",
680684
"user_id": "<user ID>",
681685
"channel_id": "<channel ID>",
682686
"team_id": "<team ID>",
@@ -689,6 +693,8 @@ The final step submission uses the same format as regular dialog submissions, bu
689693
}
690694
```
691695

696+
Return an empty response (HTTP 200 with empty body) or `{"type": "ok"}` to close the dialog.
697+
692698
### Multi-step example
693699

694700
```json
@@ -699,7 +705,6 @@ The final step submission uses the same format as regular dialog submissions, bu
699705
"callback_id": "multistep_wizard",
700706
"title": "Setup Wizard - Step 1 of 3",
701707
"introduction_text": "Welcome to the setup wizard",
702-
"is_multistep": true,
703708
"elements": [
704709
{
705710
"display_name": "Project Name",
@@ -719,67 +724,89 @@ The final step submission uses the same format as regular dialog submissions, bu
719724

720725
Interactive dialogs support dynamic field refresh functionality, allowing fields to be updated based on user input. This is useful for dependent dropdowns or conditional form fields.
721726

722-
To enable field refresh, set `refresh_on_select: true` in your dialog configuration. When users change select field values, Mattermost will send a field refresh request to your configured URL.
727+
To enable field refresh, two things are required:
728+
1. Set `refresh: true` on the **element** that should trigger refreshes when its value changes.
729+
2. Set `source_url` on the **dialog** to specify where refresh requests are sent.
730+
731+
When a user changes a select element that has `refresh: true`, Mattermost sends a request to the dialog's `source_url` via the `/api/v4/actions/dialogs/submit` endpoint.
723732

724733
### Field refresh webhook
725734

726-
The field refresh webhook payload includes the current form state and the changed field:
735+
The field refresh request uses the standard `SubmitDialogRequest` structure with `type` set to `"refresh"`:
727736

728737
```json
729738
{
730-
"type": "dialog_field_refresh",
739+
"type": "refresh",
740+
"url": "<source_url>",
731741
"callback_id": "<callback ID>",
732742
"state": "<current state>",
733743
"user_id": "<user ID>",
734744
"channel_id": "<channel ID>",
735745
"team_id": "<team ID>",
736-
"field_name": "changed_field_name",
737746
"submission": {
738-
"changed_field_name": "new_value",
739-
"other_field": "existing_value"
747+
"category": "software",
748+
"subcategory": "",
749+
"selected_field": "category"
740750
}
741751
}
742752
```
743753

744-
Your integration should respond with updated field configurations:
754+
The `submission` map contains the current values of all form fields, plus a `selected_field` key indicating which field triggered the refresh. Cleared fields are sent as empty strings.
755+
756+
Your integration should respond with a complete updated dialog wrapped in a `form` response:
745757

746758
```json
747759
{
748-
"elements": [
749-
{
750-
"display_name": "Updated Field",
751-
"name": "dependent_field",
752-
"type": "select",
753-
"options": [
754-
{
755-
"text": "New Option 1",
756-
"value": "new_opt1"
757-
},
758-
{
759-
"text": "New Option 2",
760-
"value": "new_opt2"
761-
}
762-
]
763-
}
764-
]
760+
"type": "form",
761+
"form": {
762+
"callback_id": "dynamic_form",
763+
"title": "Dynamic Form",
764+
"source_url": "/plugins/your-plugin-id/refresh",
765+
"elements": [
766+
{
767+
"display_name": "Category",
768+
"name": "category",
769+
"type": "select",
770+
"refresh": true,
771+
"options": [
772+
{"text": "Software", "value": "software"},
773+
{"text": "Hardware", "value": "hardware"}
774+
]
775+
},
776+
{
777+
"display_name": "Subcategory",
778+
"name": "subcategory",
779+
"type": "select",
780+
"options": [
781+
{"text": "Frontend", "value": "frontend"},
782+
{"text": "Backend", "value": "backend"}
783+
]
784+
}
785+
],
786+
"submit_label": "Submit",
787+
"state": "step_1"
788+
}
765789
}
766790
```
767791

792+
The response replaces the entire dialog with the new form definition. The client preserves the user's current field values where field names match.
793+
768794
### Field refresh example
769795

770796
```json
771797
{
772798
"trigger_id": "trigger_id_here",
773-
"url": "https://your-integration.com/dialog",
799+
"url": "https://your-integration.com/dialog/submit",
774800
"dialog": {
775801
"callback_id": "dynamic_form",
776802
"title": "Dynamic Form",
777-
"refresh_on_select": true,
803+
"source_url": "/plugins/your-plugin-id/refresh",
778804
"elements": [
779805
{
780806
"display_name": "Category",
781807
"name": "category",
782808
"type": "select",
809+
"refresh": true,
783810
"options": [
784811
{"text": "Software", "value": "software"},
785812
{"text": "Hardware", "value": "hardware"}
@@ -791,7 +818,9 @@ Your integration should respond with updated field configurations:
791818
"type": "select",
792819
"options": []
793820
}
794-
]
821+
],
822+
"submit_label": "Submit",
823+
"state": "step_1"
795824
}
796825
}
797826
```

0 commit comments

Comments
 (0)