snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
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

This commit is contained in:
upstream-mirror
2026-09-16 00:29:55 +05:00
commit 240db4e2a7
15309 changed files with 2173406 additions and 0 deletions

View File

@@ -0,0 +1,866 @@
// 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,
};