mattermost-mobile-upstream/types/api/integrations.d.ts
Jack Benning 00a40b4c72 Add collapsible section support to interactive dialogs
Mobile had no support for the `collapsible` dialog element: a dialog
using one rendered none of its fields, because the container itself
carries no value and every lookup walked only the top level.

Conversion gains `flattenCollapsible` / `flattenDialogElements` /
`flattenAppFields`, named to match the webapp's helpers. Every path that
resolves a value by field name — submission, `collectFileIds`,
`mergeFileFieldValues`, refresh-source detection, dynamic-select lookup
in the dialog router, and `initValues` — now walks the flattened list, so
a nested field behaves exactly like a top-level one.

`CollapsibleSection` renders the chevron and title. Children unmount
while collapsed; their values live in the form's reducer, so nothing
typed is lost by closing a section, and a value typed into a section
that is then collapsed still submits.

Tested with 199 unit tests. The most complete of them,
dialog_router_collapsible.test.tsx, drives the real payload from the
demo plugin's `/dialog collapsible` sample through the real adapter,
conversion, form and input components, mocking only the network, and
asserts what the server receives on submit.

E2E coverage is added to the existing demo-plugin suite, against the
`/dialog collapsible` sample already present in the pinned demo plugin
release: each section's initial expanded state, opening a nested
section, a value surviving its section being collapsed, and a nested
value surviving a collapse round trip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-12 14:46:35 -04:00

154 lines
3.6 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
type Command = {
'id': string;
'token': string;
'create_at': number;
'update_at': number;
'delete_at': number;
'creator_id': string;
'team_id': string;
'trigger': string;
'method': 'P' | 'G' | '';
'username': string;
'icon_url': string;
'auto_complete': boolean;
'auto_complete_desc': string;
'auto_complete_hint': string;
'display_name': string;
'description': string;
'url': string;
'autocomplete_icon_data'?: string;
};
type CommandArgs = {
channel_id: string;
team_id: string;
root_id?: string;
parent_id?: string;
};
// AutocompleteSuggestion represents a single suggestion downloaded from the server.
type AutocompleteSuggestion = {
Complete: string;
Suggestion: string;
Hint: string;
Description: string;
IconData: string;
};
type DialogSubmission = {
url: string;
callback_id: string;
state: string;
user_id: string;
channel_id: string;
team_id: string;
submission: {
[x: string]: string;
};
cancelled: boolean;
file_ids?: string[];
};
type DialogOption = {
text: string;
value: string;
};
type SelectedDialogOption = DialogOption | DialogOption[] | undefined;
type SelectedDialogValue = string | string[] | undefined;
type DialogElement = {
display_name: string;
name: string;
type: InteractiveDialogElementType;
subtype?: InteractiveDialogTextSubtype;
default: string | boolean;
placeholder: string;
help_text: string;
optional: boolean;
min_length: number;
max_length: number;
data_source: string;
data_source_url?: string;
options: DialogOption[];
multiselect?: boolean;
allow_multiple?: boolean;
refresh?: boolean;
// Date/DateTime fields
min_date?: string;
max_date?: string;
time_interval?: number;
datetime_config?: DateTimeConfig;
// Collapsible sections hold child elements and carry no value of their own.
collapsible_config?: DialogCollapsibleConfig;
};
type DialogCollapsibleConfig = {
elements: DialogElement[];
collapsed?: boolean;
borderless?: boolean;
};
type InteractiveDialogConfig = {
app_id: string;
trigger_id: string;
url: string;
dialog: {
callback_id: string;
title: string;
introduction_text: string;
icon_url?: string;
elements: DialogElement[];
submit_label: string;
notify_on_cancel: boolean;
state: string;
source_url?: string;
};
};
type PostAction = {
id?: string;
type?: string;
name?: string;
disabled?: boolean;
style?: string;
data_source?: string;
options?: PostActionOption[];
default_option?: string;
integration?: PostActionIntegration;
cookie?: string;
};
type PostActionOption = {
text?: string;
value?: string;
};
type PostActionIntegration = {
url?: string;
context?: Record<string, any>;
}
/** `integration_format` on the do-post-action API body — identifies which format originally had the action. */
type PostActionIntegrationFormat =
| 'attachment'
| 'apps_binding'
| 'block'
| 'card'
| 'mm_block';
type PostActionResponse = {
status: string;
trigger_id: string;
goto_location?: string;
};
type InteractiveDialogElementType = 'text' | 'textarea' | 'select' | 'radio' | 'bool' | 'file' | 'date' | 'datetime' | 'collapsible'
type InteractiveDialogTextSubtype = 'email' | 'number' | 'tel' | 'url' | 'password'