diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js index 0f9494668..93b019483 100644 --- a/app/components/post_body/post_body.js +++ b/app/components/post_body/post_body.js @@ -174,6 +174,7 @@ export default class PostBody extends PureComponent { channelIsReadOnly, hasBeenDeleted, isFlagged, + isSystemMessage, postId, managedConfig, showAddReaction, diff --git a/app/screens/post_options/__snapshots__/post_options.test.js.snap b/app/screens/post_options/__snapshots__/post_options.test.js.snap new file mode 100644 index 000000000..eeb433783 --- /dev/null +++ b/app/screens/post_options/__snapshots__/post_options.test.js.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PostOptions should match snapshot, no option for system message to user who doesn't have the permission to delete 1`] = `null`; + +exports[`PostOptions should match snapshot, showing Delete option only for system message to user who has permission to delete 1`] = ` + + + + + +`; + +exports[`PostOptions should match snapshot, showing all possible options 1`] = ` + + + + + + + + + + + +`; diff --git a/app/screens/post_options/post_options.js b/app/screens/post_options/post_options.js index 9e5c81fdd..4c9a8763b 100644 --- a/app/screens/post_options/post_options.js +++ b/app/screens/post_options/post_options.js @@ -24,7 +24,6 @@ export default class PostOptions extends PureComponent { unflagPost: PropTypes.func.isRequired, unpinPost: PropTypes.func.isRequired, }).isRequired, - additionalOption: PropTypes.object, canAddReaction: PropTypes.bool, canDelete: PropTypes.bool, canPin: PropTypes.bool, @@ -36,6 +35,7 @@ export default class PostOptions extends PureComponent { hasBeenDeleted: PropTypes.bool, isFlagged: PropTypes.bool, isMyPost: PropTypes.bool, + isSystemMessage: PropTypes.bool, managedConfig: PropTypes.object.isRequired, navigator: PropTypes.object.isRequired, post: PropTypes.object.isRequired, @@ -63,9 +63,9 @@ export default class PostOptions extends PureComponent { getAddReactionOption = () => { const {formatMessage} = this.context.intl; - const {canAddReaction, channelIsReadOnly, showAddReaction} = this.props; + const {canAddReaction, channelIsReadOnly, isSystemMessage, showAddReaction} = this.props; - if (showAddReaction && canAddReaction && !channelIsReadOnly) { + if (!isSystemMessage && showAddReaction && canAddReaction && !channelIsReadOnly) { return ( { + if (this.props.isSystemMessage) { + return null; + } + const {formatMessage} = this.context.intl; return ( @@ -94,9 +98,9 @@ export default class PostOptions extends PureComponent { getCopyText = () => { const {formatMessage} = this.context.intl; - const {managedConfig, post} = this.props; + const {isSystemMessage, managedConfig, post} = this.props; - if (managedConfig.copyAndPasteProtection !== 'true' && post.message) { + if (!isSystemMessage && managedConfig.copyAndPasteProtection !== 'true' && post.message) { return ( { const {formatMessage} = this.context.intl; - const {canEdit, canEditUntil} = this.props; + const {canEdit, canEditUntil, isSystemMessage} = this.props; - if (canEdit && (canEditUntil === -1 || canEditUntil > Date.now())) { + if (!isSystemMessage && canEdit && (canEditUntil === -1 || canEditUntil > Date.now())) { return ( { const {formatMessage} = this.context.intl; - const {channelIsReadOnly, isFlagged} = this.props; + const {channelIsReadOnly, isFlagged, isSystemMessage} = this.props; - if (channelIsReadOnly) { + if (isSystemMessage || channelIsReadOnly) { return null; } @@ -178,9 +182,9 @@ export default class PostOptions extends PureComponent { getPinOption = () => { const {formatMessage} = this.context.intl; - const {channelIsReadOnly, post} = this.props; + const {channelIsReadOnly, isSystemMessage, post} = this.props; - if (channelIsReadOnly) { + if (isSystemMessage || channelIsReadOnly) { return null; } @@ -398,6 +402,10 @@ export default class PostOptions extends PureComponent { render() { const {deviceHeight} = this.props; const options = this.getPostOptions(); + if (!options || !options.length) { + return null; + } + const marginFromTop = deviceHeight - BOTTOM_MARGIN - ((options.length + 1) * OPTION_HEIGHT); const initialPosition = getInitialPosition(deviceHeight, marginFromTop); diff --git a/app/screens/post_options/post_options.test.js b/app/screens/post_options/post_options.test.js new file mode 100644 index 000000000..57503d8be --- /dev/null +++ b/app/screens/post_options/post_options.test.js @@ -0,0 +1,88 @@ +// 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 PostOptions from './post_options'; + +jest.mock('react-intl'); + +describe('PostOptions', () => { + const navigator = { + showModal: jest.fn(), + dismissModal: jest.fn(), + }; + + const actions = { + addReaction: jest.fn(), + deletePost: jest.fn(), + flagPost: jest.fn(), + pinPost: jest.fn(), + removePost: jest.fn(), + unflagPost: jest.fn(), + unpinPost: jest.fn(), + }; + + const post = { + id: 'post_id', + message: 'message', + }; + + const baseProps = { + actions, + canAddReaction: true, + canDelete: true, + canPin: true, + canEdit: true, + canEditUntil: -1, + channelIsReadOnly: false, + currentTeamUrl: 'http://localhost:8065/team-name', + deviceHeight: 600, + hasBeenDeleted: false, + isFlagged: false, + isMyPost: true, + isSystemMessage: false, + managedConfig: {}, + navigator, + post, + showAddReaction: true, + theme: Preferences.THEMES.default, + }; + + test('should match snapshot, showing all possible options', () => { + const wrapper = shallow( + , + {context: {intl: {formatMessage: jest.fn((format) => format.defaultMessage)}}}, + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should match snapshot, showing Delete option only for system message to user who has permission to delete', () => { + const wrapper = shallow( + , + {context: {intl: {formatMessage: jest.fn((format) => format.defaultMessage)}}}, + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should match snapshot, no option for system message to user who doesn\'t have the permission to delete', () => { + const wrapper = shallow( + , + {context: {intl: {formatMessage: jest.fn((format) => format.defaultMessage)}}}, + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); +}); diff --git a/package-lock.json b/package-lock.json index 22c8a997e..a39747895 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2688,6 +2688,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -2732,7 +2733,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "4.0.0", @@ -4359,7 +4361,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -4377,11 +4380,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4394,15 +4399,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4505,7 +4513,8 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4515,6 +4524,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4527,17 +4537,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -4554,6 +4567,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4626,7 +4640,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4636,6 +4651,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4711,7 +4727,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -4741,6 +4758,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4758,6 +4776,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4796,11 +4815,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.0.3", - "bundled": true + "bundled": true, + "optional": true } } }, @@ -12338,7 +12359,8 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "dev": true, + "optional": true }, "braces": { "version": "2.3.2", @@ -12624,7 +12646,8 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "dev": true, + "optional": true }, "micromatch": { "version": "3.1.10",