diff --git a/app/components/interactive_dialog_controller/interactive_dialog_controller.test.js b/app/components/interactive_dialog_controller/interactive_dialog_controller.test.js
index 29bd8a573..d048b5732 100644
--- a/app/components/interactive_dialog_controller/interactive_dialog_controller.test.js
+++ b/app/components/interactive_dialog_controller/interactive_dialog_controller.test.js
@@ -55,7 +55,7 @@ describe('InteractiveDialogController', () => {
});
});
-function getBaseProps(triggerId, elements) {
+function getBaseProps(triggerId, elements, introductionText) {
const dialogData = {
dialog: {
callback_id: 'somecallbackid',
@@ -65,6 +65,7 @@ function getBaseProps(triggerId, elements) {
state: 'somestate',
submit_label: 'Submit Test',
title: 'Dialog Test',
+ introductionText,
},
trigger_id: triggerId,
url: 'https://localhost:8065/dialog_submit',
diff --git a/app/screens/interactive_dialog/__snapshots__/dialog_introduction_text.test.js.snap b/app/screens/interactive_dialog/__snapshots__/dialog_introduction_text.test.js.snap
new file mode 100644
index 000000000..4ecbe6655
--- /dev/null
+++ b/app/screens/interactive_dialog/__snapshots__/dialog_introduction_text.test.js.snap
@@ -0,0 +1,125 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`DialogIntroductionText should not render the component with an empty value 1`] = `null`;
+
+exports[`DialogIntroductionText should render the introduction text correctly 1`] = `
+
+
+
+`;
diff --git a/app/screens/interactive_dialog/__snapshots__/interactive_dialog.test.js.snap b/app/screens/interactive_dialog/__snapshots__/interactive_dialog.test.js.snap
new file mode 100644
index 000000000..a2753b402
--- /dev/null
+++ b/app/screens/interactive_dialog/__snapshots__/interactive_dialog.test.js.snap
@@ -0,0 +1,53 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`InteractiveDialog should display introduction text if present 1`] = `
+
+
+
+
+
+
+`;
diff --git a/app/screens/interactive_dialog/dialog_introduction_text.js b/app/screens/interactive_dialog/dialog_introduction_text.js
new file mode 100644
index 000000000..db54b075f
--- /dev/null
+++ b/app/screens/interactive_dialog/dialog_introduction_text.js
@@ -0,0 +1,58 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React, {PureComponent} from 'react';
+import {View} from 'react-native';
+import PropTypes from 'prop-types';
+
+import Markdown from 'app/components/markdown';
+
+import {getMarkdownTextStyles, getMarkdownBlockStyles} from 'app/utils/markdown';
+import {makeStyleSheetFromTheme} from 'app/utils/theme';
+
+export default class DialogIntroductionText extends PureComponent {
+ static propTypes = {
+ value: PropTypes.string.isRequired,
+ theme: PropTypes.object.isRequired,
+ };
+
+ render() {
+ const {
+ value,
+ theme,
+ } = this.props;
+
+ if (value) {
+ const style = getStyleFromTheme(theme);
+ const blockStyles = getMarkdownBlockStyles(theme);
+ const textStyles = getMarkdownTextStyles(theme);
+
+ return (
+
+
+
+ );
+ }
+
+ return null;
+ }
+}
+
+const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
+ return {
+ introductionTextView: {
+ marginHorizontal: 15,
+ },
+ introductionText: {
+ color: theme.centerChannelColor,
+ },
+ };
+});
diff --git a/app/screens/interactive_dialog/dialog_introduction_text.test.js b/app/screens/interactive_dialog/dialog_introduction_text.test.js
new file mode 100644
index 000000000..bf54f5353
--- /dev/null
+++ b/app/screens/interactive_dialog/dialog_introduction_text.test.js
@@ -0,0 +1,38 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+import React from 'react';
+import {shallow} from 'enzyme';
+
+import Preferences from 'mattermost-redux/constants/preferences';
+
+import DialogIntroductionText from './dialog_introduction_text.js';
+
+describe('DialogIntroductionText', () => {
+ const baseProps = {
+ theme: Preferences.THEMES.default,
+ value: '**bold** *italic* [link](https://mattermost.com/)
[link target blank](!https://mattermost.com/)',
+ };
+
+ test('should render the introduction text correctly', () => {
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+
+ test('should not render the component with an empty value', () => {
+ baseProps.value = '';
+
+ const wrapper = shallow(
+
+ );
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+});
diff --git a/app/screens/interactive_dialog/index.js b/app/screens/interactive_dialog/index.js
index 6170b7b6e..6b4fa1672 100644
--- a/app/screens/interactive_dialog/index.js
+++ b/app/screens/interactive_dialog/index.js
@@ -19,6 +19,7 @@ function mapStateToProps(state) {
callbackId: data.dialog.callback_id,
elements: data.dialog.elements,
title: data.dialog.title,
+ introductionText: data.dialog.introduction_text,
iconUrl: data.dialog.icon_url,
submitLabel: data.dialog.submit_label,
notifyOnCancel: data.dialog.notify_on_cancel,
diff --git a/app/screens/interactive_dialog/interactive_dialog.js b/app/screens/interactive_dialog/interactive_dialog.js
index a682c1648..e6bd696bb 100644
--- a/app/screens/interactive_dialog/interactive_dialog.js
+++ b/app/screens/interactive_dialog/interactive_dialog.js
@@ -14,11 +14,13 @@ import StatusBar from 'app/components/status_bar';
import FormattedText from 'app/components/formatted_text';
import DialogElement from './dialog_element.js';
+import DialogIntroductionText from './dialog_introduction_text.js';
export default class InteractiveDialog extends PureComponent {
static propTypes = {
url: PropTypes.string.isRequired,
callbackId: PropTypes.string,
+ introductionText: PropTypes.string,
elements: PropTypes.arrayOf(PropTypes.object),
notifyOnCancel: PropTypes.bool,
state: PropTypes.string,
@@ -150,13 +152,19 @@ export default class InteractiveDialog extends PureComponent {
}
render() {
- const {elements, theme} = this.props;
+ const {introductionText, elements, theme} = this.props;
const style = getStyleFromTheme(theme);
return (
+ {Boolean(introductionText) &&
+
+ }
{elements && elements.map((e) => {
return (
{
expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledTimes(1);
expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledWith(dialog);
});
+
+ test('should display introduction text if present', async () => {
+ baseProps.introductionText = '**Some** _introduction_ text';
+
+ const wrapper = shallow(
+ ,
+ );
+
+ expect(wrapper.getElement()).toMatchSnapshot();
+ });
+
+ test('introduction text should not affect submission', async () => {
+ baseProps.introductionText = '**Some** _introduction_ text';
+
+ const wrapper = shallow(
+ ,
+ );
+
+ const dialog = {
+ url: baseProps.url,
+ callback_id: baseProps.callbackId,
+ state: baseProps.state,
+ submission: {},
+ };
+
+ wrapper.instance().handleSubmit();
+ expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledTimes(1);
+ expect(baseProps.actions.submitInteractiveDialog).toHaveBeenCalledWith(dialog);
+ });
});