MM-13413 Make user names in system messages tappable (#3376)
Opens profile pop-over for: * User changed channel purpose * User changed channel name * User changed channel header * User archived channel
This commit is contained in:
parent
1557b08d59
commit
0f3728a185
6 changed files with 311 additions and 0 deletions
|
|
@ -0,0 +1,37 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renderSystemMessage uses renderer for Channel Display Name update 1`] = `
|
||||
<Connect(Markdown)
|
||||
baseTextStyle={Object {}}
|
||||
onPostPress={[MockFunction]}
|
||||
textStyles={Object {}}
|
||||
value="{username} updated the channel display name from: {oldDisplayName} to: {newDisplayName}"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`renderSystemMessage uses renderer for Channel Header update 1`] = `
|
||||
<Connect(Markdown)
|
||||
baseTextStyle={Object {}}
|
||||
onPostPress={[MockFunction]}
|
||||
textStyles={Object {}}
|
||||
value="{username} updated the channel header from: {oldHeader} to: {newHeader}"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`renderSystemMessage uses renderer for Channel Purpose update 1`] = `
|
||||
<Connect(Markdown)
|
||||
baseTextStyle={Object {}}
|
||||
onPostPress={[MockFunction]}
|
||||
textStyles={Object {}}
|
||||
value="{username} updated the channel purpose from: {oldPurpose} to: {newPurpose}"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`renderSystemMessage uses renderer for archived channel 1`] = `
|
||||
<Connect(Markdown)
|
||||
baseTextStyle={Object {}}
|
||||
onPostPress={[MockFunction]}
|
||||
textStyles={Object {}}
|
||||
value="{username} archived the channel"
|
||||
/>
|
||||
`;
|
||||
|
|
@ -13,6 +13,7 @@ import Icon from 'react-native-vector-icons/Ionicons';
|
|||
import {Posts} from 'mattermost-redux/constants';
|
||||
|
||||
import CombinedSystemMessage from 'app/components/combined_system_message';
|
||||
import {renderSystemMessage} from './system_message_helpers';
|
||||
import FormattedText from 'app/components/formatted_text';
|
||||
import Markdown from 'app/components/markdown';
|
||||
import MarkdownEmoji from 'app/components/markdown/markdown_emoji';
|
||||
|
|
@ -348,6 +349,13 @@ export default class PostBody extends PureComponent {
|
|||
const messageStyle = isSystemMessage ? [style.message, style.systemMessage] : style.message;
|
||||
const isPendingOrFailedPost = isPending || isFailed;
|
||||
|
||||
const messageStyles = {messageStyle, textStyles};
|
||||
const intl = this.context.intl;
|
||||
const systemMessage = renderSystemMessage(this.props, messageStyles, intl);
|
||||
if (systemMessage) {
|
||||
return systemMessage;
|
||||
}
|
||||
|
||||
let body;
|
||||
let messageComponent;
|
||||
if (hasBeenDeleted) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import PostBodyAdditionalContent from 'app/components/post_body_additional_conte
|
|||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import PostBody from './post_body.js';
|
||||
import * as SystemMessageHelpers from './system_message_helpers';
|
||||
|
||||
jest.mock('./system_message_helpers');
|
||||
|
||||
describe('PostBody', () => {
|
||||
const baseProps = {
|
||||
|
|
@ -122,4 +125,9 @@ describe('PostBody', () => {
|
|||
instance.measurePost(event);
|
||||
expect(wrapper.state('isLongPost')).toEqual(false);
|
||||
});
|
||||
|
||||
test('should return system message as post body', () => {
|
||||
shallowWithIntl(<PostBody {...baseProps}/>);
|
||||
expect(SystemMessageHelpers.renderSystemMessage.mock.calls.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
160
app/components/post_body/system_message_helpers.js
Normal file
160
app/components/post_body/system_message_helpers.js
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {Posts} from 'mattermost-redux/constants';
|
||||
import Markdown from 'app/components/markdown';
|
||||
import {t} from 'app/utils/i18n';
|
||||
|
||||
const renderUsername = (value) => {
|
||||
return (value[0] === '@') ? value : `@${value}`;
|
||||
};
|
||||
|
||||
const renderMessage = (postBodyProps, styles, intl, localeHolder, values) => {
|
||||
const {onPress} = postBodyProps;
|
||||
const {messageStyle, textStyles} = styles;
|
||||
|
||||
return (
|
||||
<Markdown
|
||||
baseTextStyle={messageStyle}
|
||||
onPostPress={onPress}
|
||||
textStyles={textStyles}
|
||||
value={intl.formatMessage(localeHolder, values)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const renderHeaderChangeMessage = (postBodyProps, styles, intl) => {
|
||||
const {postProps} = postBodyProps;
|
||||
let values;
|
||||
|
||||
if (!postProps.username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const username = renderUsername(postProps.username);
|
||||
const oldHeader = postProps.old_header;
|
||||
const newHeader = postProps.new_header;
|
||||
let localeHolder;
|
||||
|
||||
if (postProps.new_header) {
|
||||
if (postProps.old_header) {
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_header_message_and_forget.updated_from'),
|
||||
defaultMessage: '{username} updated the channel header from: {oldHeader} to: {newHeader}',
|
||||
};
|
||||
|
||||
values = {username, oldHeader, newHeader};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
}
|
||||
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_header_message_and_forget.updated_to'),
|
||||
defaultMessage: '{username} updated the channel header to: {newHeader}',
|
||||
};
|
||||
|
||||
values = {username, oldHeader, newHeader};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
} else if (postProps.old_header) {
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_header_message_and_forget.removed'),
|
||||
defaultMessage: '{username} removed the channel header (was: {oldHeader})',
|
||||
};
|
||||
|
||||
values = {username, oldHeader, newHeader};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderPurposeChangeMessage = (postBodyProps, styles, intl) => {
|
||||
const {postProps} = postBodyProps;
|
||||
let values;
|
||||
|
||||
if (!postProps.username) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const username = renderUsername(postProps.username);
|
||||
const oldPurpose = postProps.old_purpose;
|
||||
const newPurpose = postProps.new_purpose;
|
||||
let localeHolder;
|
||||
|
||||
if (postProps.new_purpose) {
|
||||
if (postProps.old_purpose) {
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_purpose_message.updated_from'),
|
||||
defaultMessage: '{username} updated the channel purpose from: {oldPurpose} to: {newPurpose}',
|
||||
};
|
||||
|
||||
values = {username, oldPurpose, newPurpose};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
}
|
||||
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_purpose_message.updated_to'),
|
||||
defaultMessage: '{username} updated the channel purpose to: {newPurpose}',
|
||||
};
|
||||
|
||||
values = {username, oldPurpose, newPurpose};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
} else if (postProps.old_purpose) {
|
||||
localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_purpose_message.removed'),
|
||||
defaultMessage: '{username} removed the channel purpose (was: {oldPurpose})',
|
||||
};
|
||||
|
||||
values = {username, oldPurpose, newPurpose};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderDisplayNameChangeMessage = (postBodyProps, styles, intl) => {
|
||||
const {postProps} = postBodyProps;
|
||||
const oldDisplayName = postProps.old_displayname;
|
||||
const newDisplayName = postProps.new_displayname;
|
||||
|
||||
if (!(postProps.username && postProps.old_displayname && postProps.new_displayname)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const username = renderUsername(postProps.username);
|
||||
const localeHolder = {
|
||||
id: t('mobile.system_message.update_channel_displayname_message_and_forget.updated_from'),
|
||||
defaultMessage: '{username} updated the channel display name from: {oldDisplayName} to: {newDisplayName}',
|
||||
};
|
||||
|
||||
const values = {username, oldDisplayName, newDisplayName};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
};
|
||||
|
||||
const renderArchivedMessage = (postBodyProps, styles, intl) => {
|
||||
const {postProps} = postBodyProps;
|
||||
|
||||
const username = renderUsername(postProps.username);
|
||||
const localeHolder = {
|
||||
id: t('mobile.system_message.channel_archived_message'),
|
||||
defaultMessage: '{username} archived the channel',
|
||||
};
|
||||
|
||||
const values = {username};
|
||||
return renderMessage(postBodyProps, styles, intl, localeHolder, values);
|
||||
};
|
||||
|
||||
const systemMessageRenderers = {
|
||||
[Posts.POST_TYPES.HEADER_CHANGE]: renderHeaderChangeMessage,
|
||||
[Posts.POST_TYPES.DISPLAYNAME_CHANGE]: renderDisplayNameChangeMessage,
|
||||
[Posts.POST_TYPES.PURPOSE_CHANGE]: renderPurposeChangeMessage,
|
||||
[Posts.POST_TYPES.CHANNEL_DELETED]: renderArchivedMessage,
|
||||
};
|
||||
|
||||
export const renderSystemMessage = (postBodyProps, styles, intl) => {
|
||||
const renderer = systemMessageRenderers[postBodyProps.postType];
|
||||
if (!renderer) {
|
||||
return null;
|
||||
}
|
||||
return renderer(postBodyProps, styles, intl);
|
||||
};
|
||||
90
app/components/post_body/system_message_helpers.test.js
Normal file
90
app/components/post_body/system_message_helpers.test.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as SystemMessageHelpers from './system_message_helpers';
|
||||
import {Posts} from 'mattermost-redux/constants';
|
||||
|
||||
const basePostBodyProps = {
|
||||
postProps: {
|
||||
username: 'username',
|
||||
},
|
||||
onPress: jest.fn(),
|
||||
};
|
||||
|
||||
const mockStyles = {
|
||||
messageStyle: {},
|
||||
textStyles: {},
|
||||
};
|
||||
|
||||
const mockIntl = {
|
||||
formatMessage: ({defaultMessage}) => defaultMessage,
|
||||
};
|
||||
|
||||
describe('renderSystemMessage', () => {
|
||||
test('uses renderer for Channel Header update', () => {
|
||||
const postBodyProps = {
|
||||
...basePostBodyProps,
|
||||
postProps: {
|
||||
...basePostBodyProps.postProps,
|
||||
old_header: 'old header',
|
||||
new_header: 'new header',
|
||||
},
|
||||
postType: Posts.POST_TYPES.HEADER_CHANGE,
|
||||
};
|
||||
const renderedMessage = SystemMessageHelpers.renderSystemMessage(postBodyProps, mockStyles, mockIntl);
|
||||
expect(renderedMessage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('uses renderer for Channel Display Name update', () => {
|
||||
const postBodyProps = {
|
||||
...basePostBodyProps,
|
||||
postProps: {
|
||||
...basePostBodyProps.postProps,
|
||||
old_displayname: 'old displayname',
|
||||
new_displayname: 'new displayname',
|
||||
},
|
||||
postType: Posts.POST_TYPES.DISPLAYNAME_CHANGE,
|
||||
};
|
||||
|
||||
const renderedMessage = SystemMessageHelpers.renderSystemMessage(postBodyProps, mockStyles, mockIntl);
|
||||
expect(renderedMessage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('uses renderer for Channel Purpose update', () => {
|
||||
const postBodyProps = {
|
||||
...basePostBodyProps,
|
||||
postProps: {
|
||||
...basePostBodyProps.postProps,
|
||||
old_purpose: 'old purpose',
|
||||
new_purpose: 'new purpose',
|
||||
},
|
||||
postType: Posts.POST_TYPES.PURPOSE_CHANGE,
|
||||
};
|
||||
|
||||
const renderedMessage = SystemMessageHelpers.renderSystemMessage(postBodyProps, mockStyles, mockIntl);
|
||||
expect(renderedMessage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('uses renderer for archived channel', () => {
|
||||
const postBodyProps = {
|
||||
...basePostBodyProps,
|
||||
postProps: {
|
||||
...basePostBodyProps.postProps,
|
||||
},
|
||||
postType: Posts.POST_TYPES.CHANNEL_DELETED,
|
||||
};
|
||||
|
||||
const renderedMessage = SystemMessageHelpers.renderSystemMessage(postBodyProps, mockStyles, mockIntl);
|
||||
expect(renderedMessage).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('is null for non-qualifying system messages', () => {
|
||||
const postBodyProps = {
|
||||
...basePostBodyProps,
|
||||
postType: 'not_relevant',
|
||||
};
|
||||
|
||||
const renderedMessage = SystemMessageHelpers.renderSystemMessage(postBodyProps, mockStyles, mockIntl);
|
||||
expect(renderedMessage).toBeNull();
|
||||
});
|
||||
});
|
||||
|
|
@ -463,6 +463,14 @@
|
|||
"mobile.storage_permission_denied_description": "Upload files to your Mattermost instance. Open Settings to grant Mattermost Read and Write access to files on this device.",
|
||||
"mobile.storage_permission_denied_title": "{applicationName} would like to access your files",
|
||||
"mobile.suggestion.members": "Members",
|
||||
"mobile.system_message.channel_archived_message": "{username} archived the channel",
|
||||
"mobile.system_message.update_channel_displayname_message_and_forget.updated_from": "{username} updated the channel display name from: {oldDisplayName} to: {newDisplayName}",
|
||||
"mobile.system_message.update_channel_header_message_and_forget.removed": "{username} removed the channel header (was: {oldHeader})",
|
||||
"mobile.system_message.update_channel_header_message_and_forget.updated_from": "{username} updated the channel header from: {oldHeader} to: {newHeader}",
|
||||
"mobile.system_message.update_channel_header_message_and_forget.updated_to": "{username} updated the channel header to: {newHeader}",
|
||||
"mobile.system_message.update_channel_purpose_message.removed": "{username} removed the channel purpose (was: {oldPurpose})",
|
||||
"mobile.system_message.update_channel_purpose_message.updated_from": "{username} updated the channel purpose from: {oldPurpose} to: {newPurpose}",
|
||||
"mobile.system_message.update_channel_purpose_message.updated_to": "{username} updated the channel purpose to: {newPurpose}",
|
||||
"mobile.terms_of_service.alert_cancel": "Cancel",
|
||||
"mobile.terms_of_service.alert_ok": "OK",
|
||||
"mobile.terms_of_service.alert_retry": "Try Again",
|
||||
|
|
|
|||
Loading…
Reference in a new issue