mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
[MM-55339] Improve types for Markdown component (#25350)
This commit is contained in:
parent
ee6457c3df
commit
cd58a5baaf
@ -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 {
|
||||
|
@ -1,30 +1,31 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/Markdown should not render markdown when formatting is disabled 1`] = `
|
||||
<span>
|
||||
This _is_ some **Markdown**
|
||||
<Connect(PostEditedIndicator)
|
||||
editedAt={0}
|
||||
postId=""
|
||||
/>
|
||||
</span>
|
||||
<div>
|
||||
<p>
|
||||
This
|
||||
<em>
|
||||
is
|
||||
</em>
|
||||
some
|
||||
<strong>
|
||||
Markdown
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/Markdown should render properly 1`] = `
|
||||
<p
|
||||
key="0"
|
||||
>
|
||||
This
|
||||
<em
|
||||
key="1"
|
||||
>
|
||||
is
|
||||
</em>
|
||||
some
|
||||
<strong
|
||||
key="3"
|
||||
>
|
||||
Markdown
|
||||
</strong>
|
||||
</p>
|
||||
<div>
|
||||
<p>
|
||||
This
|
||||
<em>
|
||||
is
|
||||
</em>
|
||||
some
|
||||
<strong>
|
||||
Markdown
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
@ -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<typeof connector>;
|
||||
|
||||
export default connector(Markdown);
|
||||
|
@ -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(
|
||||
<Markdown {...baseProps}/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const {container} = renderWithContext(<Markdown {...baseProps}/>);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should not render markdown when formatting is disabled', () => {
|
||||
@ -54,9 +52,7 @@ describe('components/Markdown', () => {
|
||||
enableFormatting: false,
|
||||
};
|
||||
|
||||
const wrapper = shallow(
|
||||
<Markdown {...props}/>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const {container} = renderWithContext(<Markdown {...props}/>);
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -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<TextFormattingOptions>;
|
||||
|
||||
/*
|
||||
* 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<TextFormattingOptions>;
|
||||
|
||||
/**
|
||||
* 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<string, PostImage>;
|
||||
|
||||
/**
|
||||
* 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<string, string>;
|
||||
}
|
||||
|
||||
export default class Markdown extends React.PureComponent<Props> {
|
||||
static defaultProps: Partial<Props> = {
|
||||
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 (
|
||||
<span>
|
||||
{message}
|
||||
<PostEditedIndicator
|
||||
postId={postId}
|
||||
editedAt={editedAt}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
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 (
|
||||
<span>
|
||||
{message}
|
||||
<PostEditedIndicator
|
||||
postId={postId}
|
||||
editedAt={editedAt}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user