Files
upstream-mattermost/e2e-tests/cypress/utils/webhook_utils.js
upstream-mirror 240db4e2a7
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
2026-09-16 00:29:55 +05:00

867 lines
33 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// Helper function to create dialog base structure
function createDialog(triggerId, webhookBaseUrl, dialogConfig) {
const baseDialog = {
trigger_id: triggerId,
url: `${webhookBaseUrl}/dialog_submit`,
dialog: {
callback_id: dialogConfig.callback_id,
title: dialogConfig.title,
submit_label: dialogConfig.submit_label || 'Submit',
notify_on_cancel: true,
...dialogConfig.dialog_props,
elements: dialogConfig.elements || [],
},
};
if (dialogConfig.icon_url) {
baseDialog.dialog.icon_url = dialogConfig.icon_url;
}
if (dialogConfig.introduction_text) {
baseDialog.dialog.introduction_text = dialogConfig.introduction_text;
}
if (dialogConfig.state) {
baseDialog.dialog.state = dialogConfig.state;
}
if (dialogConfig.source_url) {
baseDialog.dialog.source_url = dialogConfig.source_url;
}
return baseDialog;
}
// Helper function to create form response structure
function createFormResponse(formConfig) {
return {
callback_id: formConfig.callback_id,
title: formConfig.title,
submit_label: formConfig.submit_label || 'Submit',
notify_on_cancel: true,
elements: formConfig.elements || [],
...formConfig.form_props,
};
}
// Helper function to create common form elements
function createElement(type, config) {
const baseElement = {
display_name: config.display_name,
name: config.name,
type,
optional: config.optional || false,
};
if (config.placeholder) {
baseElement.placeholder = config.placeholder;
}
if (config.help_text) {
baseElement.help_text = config.help_text;
}
if (config.default) {
baseElement.default = config.default;
}
if (config.subtype) {
baseElement.subtype = config.subtype;
}
if (config.min_length) {
baseElement.min_length = config.min_length;
}
if (config.max_length) {
baseElement.max_length = config.max_length;
}
if (config.data_source) {
baseElement.data_source = config.data_source;
}
if (config.options) {
baseElement.options = config.options;
}
if (config.refresh) {
baseElement.refresh = config.refresh;
}
if (config.label_position) {
baseElement.label_position = config.label_position;
}
if (config.matrix_config) {
baseElement.matrix_config = config.matrix_config;
}
if (config.multiselect) {
baseElement.multiselect = true;
}
if (config.action_button) {
baseElement.action_button = config.action_button;
}
return baseElement;
}
// Standard icon URL
const STANDARD_ICON = 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png';
const WAIVER_REASON_OPTIONS = [
{text: 'Reason 1', value: 'reason_1'},
{text: 'Reason 2', value: 'reason_2'},
{text: 'Reason 3', value: 'reason_3'},
];
const SEVERITY_MATRIX_COLUMNS = [
{text: 'High', value: 'high'},
{text: 'Severe', value: 'severe'},
];
// Dialog configurations
const DIALOG_CONFIGS = {
full: {
callback_id: 'somecallbackid',
title: 'Title for Full Dialog Test',
icon_url: STANDARD_ICON,
elements: [
createElement('text', {display_name: 'Display Name', name: 'realname', default: 'default text', placeholder: 'placeholder', help_text: 'This a regular input in an interactive dialog triggered by a test integration.'}),
createElement('text', {display_name: 'Email', name: 'someemail', subtype: 'email', placeholder: 'placeholder@bladekick.com', help_text: 'This a regular email input in an interactive dialog triggered by a test integration.'}),
createElement('text', {display_name: 'Number', name: 'somenumber', subtype: 'number'}),
createElement('text', {display_name: 'Password', name: 'somepassword', subtype: 'password', default: 'p@ssW0rd', placeholder: 'placeholder', help_text: 'This a password input in an interactive dialog triggered by a test integration.', optional: true}),
createElement('textarea', {display_name: 'Display Name Long Text Area', name: 'realnametextarea', placeholder: 'placeholder', optional: true, min_length: 5, max_length: 100}),
createElement('select', {display_name: 'User Selector', name: 'someuserselector', placeholder: 'Select a user...', data_source: 'users'}),
createElement('select', {display_name: 'Channel Selector', name: 'somechannelselector', placeholder: 'Select a channel...', help_text: 'Choose a channel from the list.', data_source: 'channels', optional: true}),
createElement('select', {display_name: 'Option Selector', name: 'someoptionselector', placeholder: 'Select an option...', options: [{text: 'Option1', value: 'opt1'}, {text: 'Option2', value: 'opt2'}, {text: 'Option3', value: 'opt3'}]}),
createElement('radio', {display_name: 'Radio Option Selector', name: 'someradiooptions', help_text: '', options: [{text: 'Engineering', value: 'engineering'}, {text: 'Sales', value: 'sales'}]}),
createElement('bool', {display_name: 'Boolean Selector', name: 'boolean_input', placeholder: 'Was this modal helpful?', default: 'True', optional: true, help_text: 'This is the help text'}),
],
dialog_props: {state: 'somestate'},
},
simple: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test without elements',
icon_url: STANDARD_ICON,
submit_label: 'Submit Test',
dialog_props: {state: 'somestate'},
},
basic: {
callback_id: 'basic_dialog_callback',
title: 'Basic Dialog',
icon_url: STANDARD_ICON,
submit_label: 'Submit',
introduction_text: 'Required text, optional radio, single select, and optional multiselect.',
elements: [
createElement('text', {
display_name: 'Title',
name: 'title',
placeholder: 'Enter a title',
help_text: 'Required text field.',
}),
createElement('radio', {
display_name: 'Department',
name: 'department',
help_text: 'Optional.',
optional: true,
options: [
{text: 'Engineering', value: 'engineering'},
{text: 'Sales', value: 'sales'},
{text: 'Support', value: 'support'},
],
}),
createElement('select', {
display_name: 'Priority',
name: 'priority',
placeholder: 'Choose priority...',
help_text: 'Optional single select. Use the × control to clear.',
optional: true,
options: [
{text: 'Low', value: 'low'},
{text: 'Medium', value: 'medium'},
{text: 'High', value: 'high'},
],
}),
createElement('select', {
display_name: 'Categories',
name: 'categories',
multiselect: true,
placeholder: 'Select one or more...',
help_text: 'Optional multiselect (`type: select` + `multiselect: true`). Submits a string array.',
optional: true,
options: [
{text: 'Bug', value: 'bug'},
{text: 'Feature', value: 'feature'},
{text: 'Documentation', value: 'docs'},
],
}),
],
dialog_props: {state: 'basic_dialog_state'},
},
userAndChannel: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test with user and channel element',
icon_url: STANDARD_ICON,
submit_label: 'Submit Test',
elements: [
createElement('select', {display_name: 'User Selector', name: 'someuserselector', placeholder: 'Select a user...', data_source: 'users'}),
createElement('select', {display_name: 'Channel Selector', name: 'somechannelselector', placeholder: 'Select a channel...', help_text: 'Choose a channel from the list.', data_source: 'channels', optional: true}),
],
dialog_props: {state: 'somestate'},
},
boolean: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test with boolean element',
icon_url: STANDARD_ICON,
submit_label: 'Submit Test',
elements: [
createElement('bool', {display_name: 'Boolean Selector', name: 'boolean_input', placeholder: 'Was this modal helpful?', default: 'True', optional: true, help_text: 'This is the help text'}),
],
dialog_props: {state: 'somestate'},
},
checkboxGroup: {
callback_id: 'checkbox_group_callback',
title: 'Checkbox Dialog Feature Demo',
icon_url: STANDARD_ICON,
submit_label: 'Submit',
introduction_text: 'Two checkbox groups (label before vs after), plus related v1 dialog features for manual QA.',
elements: [
createElement('checkbox_group', {
display_name: 'Group A: label before',
name: 'waiver_group_label_before',
help_text: 'Required. Option text is left of each checkbox (`label_position: before`). Default: reason_1 + reason_3.',
default: 'reason_1,reason_3',
label_position: 'before',
options: WAIVER_REASON_OPTIONS,
}),
createElement('checkbox_group', {
display_name: 'Group B: label after',
name: 'waiver_group_label_after',
help_text: 'Optional. Option text is right of each checkbox (`label_position: after`, default). Clear all → submits [].',
default: 'reason_2',
label_position: 'after',
optional: true,
options: WAIVER_REASON_OPTIONS,
}),
createElement('radio', {
display_name: 'Department (optional)',
name: 'department',
help_text: 'Optional radio with default + Clear selection link.',
default: 'sales',
optional: true,
label_position: 'after',
options: [
{text: 'Engineering', value: 'engineering'},
{text: 'Sales', value: 'sales'},
{text: 'Administration', value: 'administration'},
],
}),
createElement('bool', {
display_name: 'Acknowledgement',
name: 'acknowledged',
placeholder: 'I understand the waiver terms',
help_text: 'Bool with label before the checkbox.',
label_position: 'before',
default: 'false',
}),
createElement('checkbox_matrix', {
display_name: 'Severity (multi per row)',
name: 'severity_multiple',
help_text: 'Matrix with row_selection: multiple — multiple columns per row allowed.',
optional: true,
matrix_config: {
row_selection: 'multiple',
rows: WAIVER_REASON_OPTIONS,
columns: SEVERITY_MATRIX_COLUMNS,
},
}),
createElement('checkbox_matrix', {
display_name: 'Priority (one per row)',
name: 'priority_single',
help_text: 'Matrix with row_selection: single — radio-style, one column per row.',
optional: true,
matrix_config: {
row_selection: 'single',
rows: WAIVER_REASON_OPTIONS,
columns: [
{text: 'Low', value: 'low'},
{text: 'Medium', value: 'medium'},
{text: 'High', value: 'high'},
],
},
}),
],
dialog_props: {state: 'checkbox_group_state'},
},
fieldRefresh: {
callback_id: 'field_refresh_callback',
title: 'Field Refresh Demo',
introduction_text: 'Enter project name then select type to see different fields',
elements: [
createElement('text', {display_name: 'Project Name', name: 'project_name', placeholder: 'Enter project name'}),
createElement('select', {display_name: 'Project Type', name: 'project_type', refresh: true, placeholder: 'Select project type...', options: [{text: 'Web Application', value: 'web'}, {text: 'Mobile App', value: 'mobile'}, {text: 'API Service', value: 'api'}]}),
],
},
multistepStep1: {
callback_id: 'multistep_callback',
title: 'Step 1 - Personal Info',
introduction_text: 'Multi-step registration - Step 1 of 3',
submit_label: 'Next Step',
elements: [
createElement('text', {display_name: 'First Name', name: 'first_name', placeholder: 'Enter your first name'}),
createElement('text', {display_name: 'Email', name: 'email', subtype: 'email', placeholder: 'Enter your email address'}),
],
dialog_props: {state: 'step1'},
},
multistepStep2: {
callback_id: 'multistep_callback',
title: 'Step 2 - Work Info',
introduction_text: 'Multi-step registration - Step 2 of 3',
submit_label: 'Next Step',
elements: [
createElement('select', {display_name: 'Department', name: 'department', placeholder: 'Select department...', options: [{text: 'Engineering', value: 'engineering'}, {text: 'Marketing', value: 'marketing'}, {text: 'Sales', value: 'sales'}]}),
createElement('radio', {display_name: 'Experience Level', name: 'experience_level', options: [{text: 'Junior', value: 'junior'}, {text: 'Mid-level', value: 'mid'}, {text: 'Senior', value: 'senior'}]}),
],
form_props: {state: 'step2'},
},
multistepStep3: {
callback_id: 'multistep_callback',
title: 'Step 3 - Final Details',
introduction_text: 'Multi-step registration - Step 3 of 3',
submit_label: 'Complete Registration',
elements: [
createElement('textarea', {display_name: 'Comments', name: 'comments', placeholder: 'Any additional comments...', optional: true}),
createElement('bool', {display_name: 'Terms & Conditions', name: 'terms_accepted'}),
],
form_props: {state: 'step3'},
},
actionButtonParent: {
callback_id: 'action_button_parent_callback',
title: 'Parent Dialog with Action Button',
elements: [],
},
actionButtonChild: {
callback_id: 'child_callback',
title: 'Child Dialog',
elements: [
createElement('text', {display_name: 'Child Input', name: 'child_input', placeholder: 'Enter value', optional: true}),
],
},
};
// Public API functions
function getFullDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.full);
}
function getSimpleDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.simple);
}
function getBasicDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.basic);
}
function getUserAndChannelDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.userAndChannel);
}
function getBooleanDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.boolean);
}
function getCheckboxGroupDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.checkboxGroup);
}
function getFieldRefreshDialog(triggerId, webhookBaseUrl) {
const config = {...DIALOG_CONFIGS.fieldRefresh};
config.source_url = `${webhookBaseUrl}/field_refresh_source`;
return createDialog(triggerId, webhookBaseUrl, config);
}
function getMultistepStep1Dialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, DIALOG_CONFIGS.multistepStep1);
}
function getMultistepStep2Dialog(triggerId, webhookBaseUrl) {
const config = {...DIALOG_CONFIGS.multistepStep2};
config.dialog_props = {url: `${webhookBaseUrl}/dialog_submit`, ...config.form_props};
return createFormResponse(config);
}
function getMultistepStep3Dialog(triggerId, webhookBaseUrl) {
const config = {...DIALOG_CONFIGS.multistepStep3};
config.dialog_props = {url: `${webhookBaseUrl}/dialog_submit`, ...config.form_props};
return createFormResponse(config);
}
function getMultiSelectDialog(triggerId, webhookBaseUrl, includeDefaults = false) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/dialog_submit`,
dialog: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test with multiselect elements',
icon_url:
'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
submit_label: 'Submit Multiselect Test',
notify_on_cancel: true,
state: 'somestate',
elements: [
{
display_name: 'Multi Option Selector',
name: 'multiselect_options',
type: 'select',
multiselect: true,
default: includeDefaults ? 'opt1,opt3' : '',
placeholder: 'Select multiple options...',
help_text: 'You can select multiple options from this list.',
optional: false,
min_length: 0,
max_length: 0,
data_source: '',
options: [
{
text: 'Engineering',
value: 'opt1',
},
{
text: 'Sales',
value: 'opt2',
},
{
text: 'Marketing',
value: 'opt3',
},
{
text: 'Support',
value: 'opt4',
},
{
text: 'Product',
value: 'opt5',
},
],
},
{
display_name: 'Multi User Selector',
name: 'multiselect_users',
type: 'select',
multiselect: true,
default: '',
placeholder: 'Select multiple users...',
help_text: 'Choose multiple users from the team.',
optional: false,
min_length: 0,
max_length: 0,
data_source: 'users',
options: null,
},
{
display_name: 'Single Option Selector',
name: 'single_select_options',
type: 'select',
multiselect: false,
default: includeDefaults ? 'single2' : '',
placeholder: 'Select one option...',
help_text: 'This is a regular single-select for comparison.',
optional: false,
min_length: 0,
max_length: 0,
data_source: '',
options: [
{
text: 'Single Option 1',
value: 'single1',
},
{
text: 'Single Option 2',
value: 'single2',
},
{
text: 'Single Option 3',
value: 'single3',
},
],
},
],
},
};
}
function getDynamicSelectDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/dialog_submit`,
dialog: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test with dynamic select element',
icon_url:
'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
submit_label: 'Submit Dynamic Select Test',
notify_on_cancel: true,
state: 'somestate',
elements: [
{
display_name: 'Dynamic Role Selector',
name: 'dynamic_role_selector',
type: 'select',
data_source: 'dynamic',
data_source_url: `${webhookBaseUrl}/dynamic_select_source`,
default: '',
placeholder: 'Search for a role...',
help_text: 'Start typing to search for available roles. Options are loaded dynamically.',
optional: false,
min_length: 0,
max_length: 0,
},
{
display_name: 'Optional Dynamic Selector',
name: 'optional_dynamic_selector',
type: 'select',
data_source: 'dynamic',
data_source_url: `${webhookBaseUrl}/dynamic_select_source`,
default: 'backend_eng',
placeholder: 'Search for another role...',
help_text: 'This field is optional and has a default value.',
optional: true,
min_length: 0,
max_length: 0,
},
],
},
};
}
// Basic date field test - MM-T2530A
function getBasicDateDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/datetime_dialog_submit`,
dialog: {
callback_id: 'basic_date_callback',
title: 'DateTime Fields Test',
icon_url: 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
elements: [
{
display_name: 'Event Date',
name: 'event_date',
type: 'date',
default: '',
placeholder: 'Select a date',
help_text: 'Select the date for your event',
optional: false,
},
],
submit_label: 'Submit',
notify_on_cancel: true,
state: 'datetime_state',
},
};
}
// Basic datetime field test - MM-T2530B
function getBasicDateTimeDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/datetime_dialog_submit`,
dialog: {
callback_id: 'basic_datetime_callback',
title: 'DateTime Fields Test',
icon_url: 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
elements: [
{
display_name: 'Event Date',
name: 'event_date',
type: 'date',
default: '',
placeholder: 'Select a date',
help_text: 'Select the date for your event',
optional: false,
},
{
display_name: 'Meeting Time',
name: 'meeting_time',
type: 'datetime',
default: '',
placeholder: 'Select date and time',
help_text: 'Select the date and time for your meeting',
optional: false,
datetime_config: {
time_interval: 60,
},
},
],
submit_label: 'Submit',
notify_on_cancel: true,
state: 'datetime_state',
},
};
}
// Date field with min_date constraint - MM-T2530C
function getMinDateConstraintDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/datetime_dialog_submit`,
dialog: {
callback_id: 'mindate_callback',
title: 'DateTime Fields Test',
icon_url: 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
elements: [
{
display_name: 'Future Date Only',
name: 'future_date',
type: 'date',
default: '',
placeholder: 'Select a future date',
help_text: 'Must be today or later',
optional: true,
datetime_config: {
min_date: 'today',
},
},
],
submit_label: 'Submit',
notify_on_cancel: true,
state: 'datetime_state',
},
};
}
// DateTime field with custom time interval - MM-T2530D
function getCustomIntervalDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/datetime_dialog_submit`,
dialog: {
callback_id: 'interval_callback',
title: 'DateTime Fields Test',
icon_url: 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
elements: [
{
display_name: 'Custom Interval Time',
name: 'interval_time',
type: 'datetime',
default: '',
placeholder: 'Select time (30min intervals)',
help_text: 'Time picker with 30-minute intervals',
optional: true,
datetime_config: {
time_interval: 30,
},
},
],
submit_label: 'Submit',
notify_on_cancel: true,
state: 'datetime_state',
},
};
}
// Relative date values test - MM-T2530F
function getRelativeDateDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/datetime_dialog_submit`,
dialog: {
callback_id: 'relative_callback',
title: 'DateTime Fields Test',
icon_url: 'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
elements: [
{
display_name: 'Relative Date Example',
name: 'relative_date',
type: 'date',
default: 'today',
placeholder: 'Today by default',
help_text: 'Defaults to today using relative date',
optional: true,
},
{
display_name: 'Relative DateTime Example',
name: 'relative_datetime',
type: 'datetime',
default: '+1d',
placeholder: 'Tomorrow by default',
help_text: 'Defaults to tomorrow using relative date',
optional: true,
},
],
submit_label: 'Submit',
notify_on_cancel: true,
state: 'datetime_state',
},
};
}
// Legacy function for backward compatibility - returns basic datetime dialog
function getDateTimeDialog(triggerId, webhookBaseUrl) {
return getBasicDateTimeDialog(triggerId, webhookBaseUrl);
}
function getTimezoneManualDialog(triggerId, webhookBaseUrl) {
return createDialog(triggerId, webhookBaseUrl, {
callback_id: 'timezone_manual',
title: 'Timezone & Manual Entry Demo',
introduction_text: '**Timezone & Manual Entry Demo**\n\n' +
'This dialog demonstrates timezone support and manual time entry features.',
elements: [
{
display_name: 'Your Local Time (Manual Entry)',
name: 'local_manual',
type: 'datetime',
help_text: 'Type any time: 9am, 14:30, 3:45pm - no rounding',
datetime_config: {
manual_time_entry: true,
},
optional: true,
},
{
display_name: 'London Office Hours (Dropdown)',
name: 'london_dropdown',
type: 'datetime',
help_text: 'Times shown in GMT - select from 60 min intervals',
datetime_config: {
location_timezone: 'Europe/London',
time_interval: 60,
},
optional: true,
},
{
display_name: 'London Office Hours (Manual Entry)',
name: 'london_manual',
type: 'datetime',
help_text: 'Type time in GMT: 9am, 14:30, 3:45pm - no rounding',
datetime_config: {
location_timezone: 'Europe/London',
manual_time_entry: true,
},
optional: true,
},
],
});
}
function getFileUploadDialog(triggerId, webhookBaseUrl) {
return {
trigger_id: triggerId,
url: `${webhookBaseUrl}/dialog_submit`,
dialog: {
callback_id: 'somecallbackid',
title: 'Title for Dialog Test with file upload element',
icon_url:
'https://mattermost.com/wp-content/uploads/2022/02/icon_WS.png',
submit_label: 'Submit File Upload Test',
notify_on_cancel: true,
state: 'somestate',
elements: [
{
display_name: 'Upload Single Document',
name: 'single_document',
type: 'file',
placeholder: 'Select one document...',
help_text: 'Upload a single document (replaces previous selection).',
optional: false,
},
{
display_name: 'Upload Multiple Files',
name: 'multiple_files',
type: 'file',
allow_multiple: true,
placeholder: 'Select multiple files...',
help_text: 'Upload multiple files (can select and add more).',
optional: false,
},
{
display_name: 'Description',
name: 'description',
type: 'textarea',
subtype: '',
default: '',
placeholder: 'Describe the uploaded files...',
help_text: 'Provide a description for the uploaded files.',
optional: true,
min_length: 0,
max_length: 500,
data_source: '',
options: null,
},
],
},
};
}
function getActionButtonParentDialog(triggerId, webhookBaseUrl) {
const config = {
...DIALOG_CONFIGS.actionButtonParent,
elements: [
createElement('text', {display_name: 'Your Name', name: 'your_name', placeholder: 'Enter your name', optional: true}),
// Two action buttons on the same dialog. Each carries a distinct
// context.source so the child dialog can reflect which one was pressed.
createElement('action_button', {
display_name: 'Open Details',
name: 'open_details',
action_button: {
url: `${webhookBaseUrl}/dialog/open_child`,
context: {source: 'Details'},
},
}),
createElement('action_button', {
display_name: 'Open Summary',
name: 'open_summary',
action_button: {
url: `${webhookBaseUrl}/dialog/open_child`,
context: {source: 'Summary'},
},
}),
],
};
return createDialog(triggerId, webhookBaseUrl, config);
}
// `source` comes from the pressed action button's context.source and is reflected
// in the child dialog's title and introduction text, so a test can verify which
// button opened it.
function getActionButtonChildDialog(triggerId, webhookBaseUrl, source) {
const label = source || 'Unknown';
const config = {
...DIALOG_CONFIGS.actionButtonChild,
title: `${label} Dialog`,
introduction_text: `This child dialog was opened from the "${label}" action button.`,
};
return createDialog(triggerId, webhookBaseUrl, config);
}
module.exports = {
getFullDialog,
getSimpleDialog,
getBasicDialog,
getUserAndChannelDialog,
getBooleanDialog,
getCheckboxGroupDialog,
getFieldRefreshDialog,
getMultistepStep1Dialog,
getMultistepStep2Dialog,
getMultistepStep3Dialog,
getMultiSelectDialog,
getDynamicSelectDialog,
getDateTimeDialog,
getBasicDateDialog,
getBasicDateTimeDialog,
getMinDateConstraintDialog,
getCustomIntervalDialog,
getRelativeDateDialog,
getTimezoneManualDialog,
getFileUploadDialog,
getActionButtonParentDialog,
getActionButtonChildDialog,
};