diff --git a/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap b/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap index e0dd5914a2..2824843da8 100644 --- a/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap +++ b/webapp/channels/src/components/drafts/panel/__snapshots__/panel_body.test.tsx.snap @@ -231,7 +231,6 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe } channelNamesMap={Object {}} dispatch={[Function]} - editedAt={0} emojiMap={ EmojiMap { "customEmojis": Map {}, @@ -240,7 +239,6 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe } enableFormatting={true} hasImageProxy={false} - imagesMetadata={Object {}} managedResourcePaths={Array []} mentionKeys={Array []} message="message" @@ -251,8 +249,6 @@ exports[`components/drafts/panel/panel_body should have called handleFormattedTe "mentionHighlight": false, } } - postId="" - proxyImages={true} siteURL="http://localhost:8065" team={ Object { @@ -508,7 +504,6 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = ` } channelNamesMap={Object {}} dispatch={[Function]} - editedAt={0} emojiMap={ EmojiMap { "customEmojis": Map {}, @@ -517,7 +512,6 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = ` } enableFormatting={true} hasImageProxy={false} - imagesMetadata={Object {}} managedResourcePaths={Array []} mentionKeys={Array []} message="message" @@ -528,8 +522,6 @@ exports[`components/drafts/panel/panel_body should match snapshot 1`] = ` "mentionHighlight": false, } } - postId="" - proxyImages={true} siteURL="http://localhost:8065" team={ Object { @@ -853,7 +845,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1 } channelNamesMap={Object {}} dispatch={[Function]} - editedAt={0} emojiMap={ EmojiMap { "customEmojis": Map {}, @@ -862,7 +853,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1 } enableFormatting={true} hasImageProxy={false} - imagesMetadata={Object {}} managedResourcePaths={Array []} mentionKeys={Array []} message="message" @@ -873,8 +863,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for priority 1 "mentionHighlight": false, } } - postId="" - proxyImages={true} siteURL="http://localhost:8065" team={ Object { @@ -1277,7 +1265,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_ } channelNamesMap={Object {}} dispatch={[Function]} - editedAt={0} emojiMap={ EmojiMap { "customEmojis": Map {}, @@ -1286,7 +1273,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_ } enableFormatting={true} hasImageProxy={false} - imagesMetadata={Object {}} managedResourcePaths={Array []} mentionKeys={Array []} message="message" @@ -1297,8 +1283,6 @@ exports[`components/drafts/panel/panel_body should match snapshot for requested_ "mentionHighlight": false, } } - postId="" - proxyImages={true} siteURL="http://localhost:8065" team={ Object { diff --git a/webapp/channels/src/components/markdown/__snapshots__/markdown.test.tsx.snap b/webapp/channels/src/components/markdown/__snapshots__/markdown.test.tsx.snap index 7f20a2bb54..b235b063ee 100644 --- a/webapp/channels/src/components/markdown/__snapshots__/markdown.test.tsx.snap +++ b/webapp/channels/src/components/markdown/__snapshots__/markdown.test.tsx.snap @@ -1,30 +1,31 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`components/Markdown should not render markdown when formatting is disabled 1`] = ` - - This _is_ some **Markdown** - - +
+

+ This + + is + + some + + Markdown + +

+
`; exports[`components/Markdown should render properly 1`] = ` -

- This - - is - - some - - Markdown - -

+
+

+ This + + is + + some + + Markdown + +

+
`; diff --git a/webapp/channels/src/components/markdown/index.ts b/webapp/channels/src/components/markdown/index.ts index 9d4654f988..ba562269f5 100644 --- a/webapp/channels/src/components/markdown/index.ts +++ b/webapp/channels/src/components/markdown/index.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {connect} from 'react-redux'; +import {connect, type ConnectedProps} from 'react-redux'; import {Preferences} from 'mattermost-redux/constants'; import {createSelector} from 'mattermost-redux/selectors/create_selector'; @@ -14,24 +14,17 @@ import {getCurrentTeam} from 'mattermost-redux/selectors/entities/teams'; import {getEmojiMap} from 'selectors/emojis'; -import type {ChannelNamesMap, MentionKey} from 'utils/text_formatting'; import {getSiteURL} from 'utils/url'; import type {GlobalState} from 'types/store'; -import Markdown from './markdown'; - -type Props = { - channelNamesMap?: ChannelNamesMap; - mentionKeys?: MentionKey[]; - postId?: string; -} +import Markdown, {type OwnProps} from './markdown'; function makeGetChannelNamesMap() { return createSelector( 'makeGetChannelNamesMap', getChannelNameToDisplayNameMap, - (state: GlobalState, props: Props) => props && props.channelNamesMap, + (state: GlobalState, props: OwnProps) => props && props.channelNamesMap, (channelNamesMap, channelMentions) => { if (channelMentions) { return Object.assign({}, channelMentions, channelNamesMap); @@ -45,7 +38,7 @@ function makeGetChannelNamesMap() { function makeMapStateToProps() { const getChannelNamesMap = makeGetChannelNamesMap(); - return function mapStateToProps(state: GlobalState, ownProps: Props) { + return function mapStateToProps(state: GlobalState, ownProps: OwnProps) { const config = getConfig(state); let channelId; @@ -69,4 +62,7 @@ function makeMapStateToProps() { }; } -export default connect(makeMapStateToProps)(Markdown); +const connector = connect(makeMapStateToProps); +export type PropsFromRedux = ConnectedProps; + +export default connector(Markdown); diff --git a/webapp/channels/src/components/markdown/markdown.test.tsx b/webapp/channels/src/components/markdown/markdown.test.tsx index 7399cbcdb4..de808571b4 100644 --- a/webapp/channels/src/components/markdown/markdown.test.tsx +++ b/webapp/channels/src/components/markdown/markdown.test.tsx @@ -1,13 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {shallow} from 'enzyme'; import React from 'react'; import type {TeamType} from '@mattermost/types/teams'; -import Markdown from 'components/markdown/markdown'; +import Markdown from 'components/markdown'; +import {renderWithContext} from 'tests/react_testing_utils'; import EmojiMap from 'utils/emoji_map'; import {TestHelper} from 'utils/test_helper'; @@ -42,10 +42,8 @@ describe('components/Markdown', () => { }; test('should render properly', () => { - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + const {container} = renderWithContext(); + expect(container).toMatchSnapshot(); }); test('should not render markdown when formatting is disabled', () => { @@ -54,9 +52,7 @@ describe('components/Markdown', () => { enableFormatting: false, }; - const wrapper = shallow( - , - ); - expect(wrapper).toMatchSnapshot(); + const {container} = renderWithContext(); + expect(container).toMatchSnapshot(); }); }); diff --git a/webapp/channels/src/components/markdown/markdown.tsx b/webapp/channels/src/components/markdown/markdown.tsx index 0fef2751cf..3ff9c62376 100644 --- a/webapp/channels/src/components/markdown/markdown.tsx +++ b/webapp/channels/src/components/markdown/markdown.tsx @@ -4,93 +4,35 @@ import React from 'react'; import type {PostImage, PostType} from '@mattermost/types/posts'; -import type {Team} from '@mattermost/types/teams'; import PostEditedIndicator from 'components/post_view/post_edited_indicator'; import type EmojiMap from 'utils/emoji_map'; import messageHtmlToComponent from 'utils/message_html_to_component'; +import type {ChannelNamesMap, MentionKey, TextFormattingOptions} from 'utils/text_formatting'; import {formatText} from 'utils/text_formatting'; -import type {ChannelNamesMap, TextFormattingOptions, MentionKey} from 'utils/text_formatting'; -type Props = { +import type {PropsFromRedux} from './index'; - /* - * An object mapping channel names to channels for the current team - */ - channelNamesMap?: ChannelNamesMap; +export type Props = PropsFromRedux & OwnProps; - /* - * An array of URL schemes that should be turned into links. Anything that looks - * like a link will be turned into a link if this is not provided. - */ - autolinkedUrlSchemes?: string[]; +export type OwnProps = { - /* - * Whether or not to do Markdown rendering - */ - enableFormatting?: boolean; - - /* - * An array of paths on the server that are managed by another server - */ - managedResourcePaths?: string[]; - - /* - * An array of words that can be used to mention a user - */ - mentionKeys?: MentionKey[]; - - /* - * The text to be rendered - */ - message: string; - - /* + /** * Any additional text formatting options to be used */ - options: Partial; - - /* - * The root Site URL for the page - */ - siteURL?: string; - - /* - * The current team - */ - team?: Team; - - /** - * If an image proxy is enabled. - */ - hasImageProxy?: boolean; - - /** - * Minimum number of characters in a hashtag. - */ - minimumHashtagLength?: number; + options?: Partial; /** * Whether or not to proxy image URLs */ proxyImages?: boolean; - /** - * Any extra props that should be passed into the image component - */ - imageProps?: object; - /** * prop for passed down to image component for dimensions */ imagesMetadata?: Record; - /** - * Whether or not to place the LinkTooltip component inside links - */ - hasPluginTooltips?: boolean; - /** * Post id prop passed down to markdown image */ @@ -101,13 +43,34 @@ type Props = { */ editedAt?: number; + /* + * The text to be rendered + */ + message?: string; + channelNamesMap?: ChannelNamesMap; + + /* + * An array of words that can be used to mention a user + */ + mentionKeys?: MentionKey[]; + + /** + * Any extra props that should be passed into the image component + */ + imageProps?: object; + + /** + * Whether or not to place the LinkTooltip component inside links + */ + hasPluginTooltips?: boolean; + channelId?: string; /** * Post id prop passed down to markdown image */ postType?: PostType; - emojiMap: EmojiMap; + emojiMap?: EmojiMap; /** * Some components processed by messageHtmlToComponent e.g. AtSumOfMembersMention require to have a list of userIds @@ -120,59 +83,73 @@ type Props = { messageMetadata?: Record; } -export default class Markdown extends React.PureComponent { - static defaultProps: Partial = { - options: {}, - proxyImages: true, - imagesMetadata: {}, - postId: '', // Needed to avoid proptypes console errors for cases like channel header, which doesn't have a proper value - editedAt: 0, - }; - - render() { - const {postId, editedAt, message, enableFormatting} = this.props; - if (message === '' || !enableFormatting) { - return ( - - {message} - - - ); - } - - const options = Object.assign({ - autolinkedUrlSchemes: this.props.autolinkedUrlSchemes, - siteURL: this.props.siteURL, - mentionKeys: this.props.mentionKeys, - atMentions: true, - channelNamesMap: this.props.channelNamesMap, - proxyImages: this.props.hasImageProxy && this.props.proxyImages, - team: this.props.team, - minimumHashtagLength: this.props.minimumHashtagLength, - managedResourcePaths: this.props.managedResourcePaths, - editedAt, - postId, - }, this.props.options); - - const htmlFormattedText = formatText(message, options, this.props.emojiMap); - - return messageHtmlToComponent(htmlFormattedText, { - imageProps: this.props.imageProps, - imagesMetadata: this.props.imagesMetadata, - hasPluginTooltips: this.props.hasPluginTooltips, - postId: this.props.postId, - userIds: this.props.userIds, - messageMetadata: this.props.messageMetadata, - channelId: this.props.channelId, - postType: this.props.postType, - mentionHighlight: this.props.options.mentionHighlight, - disableGroupHighlight: this.props.options.disableGroupHighlight, - editedAt, - atSumOfMembersMentions: this.props.options.atSumOfMembersMentions, - atPlanMentions: this.props.options.atPlanMentions, - }); +function Markdown({ + options = {}, + proxyImages = true, + imagesMetadata = {}, + postId = '', // Needed to avoid proptypes console errors for cases like channel header, which doesn't have a proper value + editedAt = 0, + message = '', + channelNamesMap, + mentionKeys, + imageProps, + channelId, + hasPluginTooltips, + postType, + emojiMap, + userIds, + messageMetadata, + enableFormatting, + autolinkedUrlSchemes, + siteURL, + hasImageProxy, + team, + minimumHashtagLength, + managedResourcePaths, +}: Props) { + if (message === '' || !enableFormatting) { + return ( + + {message} + + + ); } + + const inputOptions = Object.assign({ + autolinkedUrlSchemes, + siteURL, + mentionKeys, + atMentions: true, + channelNamesMap, + proxyImages: hasImageProxy && proxyImages, + team, + minimumHashtagLength, + managedResourcePaths, + editedAt, + postId, + }, options); + + const htmlFormattedText = formatText(message, inputOptions, emojiMap); + + return messageHtmlToComponent(htmlFormattedText, { + imageProps, + imagesMetadata, + hasPluginTooltips, + postId, + userIds, + messageMetadata, + channelId, + postType, + mentionHighlight: options?.mentionHighlight, + disableGroupHighlight: options?.disableGroupHighlight, + editedAt, + atSumOfMembersMentions: options?.atSumOfMembersMentions, + atPlanMentions: options?.atPlanMentions, + }); } + +export default Markdown;