diff --git a/app/components/channel_drawer/channels_list/channel_item/channel_item.js b/app/components/channel_drawer/channels_list/channel_item/channel_item.js index cf4855aa8..3b2a979b7 100644 --- a/app/components/channel_drawer/channels_list/channel_item/channel_item.js +++ b/app/components/channel_drawer/channels_list/channel_item/channel_item.js @@ -31,6 +31,7 @@ export default class ChannelItem extends PureComponent { mentions: PropTypes.number.isRequired, navigator: PropTypes.object, onSelectChannel: PropTypes.func.isRequired, + shouldHideChannel: PropTypes.bool, status: PropTypes.string, teammateDeletedAt: PropTypes.number, type: PropTypes.string.isRequired, @@ -81,12 +82,17 @@ export default class ChannelItem extends PureComponent { isMyUser, isUnread, mentions, + shouldHideChannel, status, teammateDeletedAt, theme, type, } = this.props; + if (shouldHideChannel) { + return null; + } + const {intl} = this.context; let channelDisplayName = displayName; diff --git a/app/components/channel_drawer/channels_list/channel_item/index.js b/app/components/channel_drawer/channels_list/channel_item/index.js index ef25b66e2..416ee3c5f 100644 --- a/app/components/channel_drawer/channels_list/channel_item/index.js +++ b/app/components/channel_drawer/channels_list/channel_item/index.js @@ -4,7 +4,7 @@ import {connect} from 'react-redux'; import {General} from 'mattermost-redux/constants'; -import {getCurrentChannelId, makeGetChannel, getMyChannelMember} from 'mattermost-redux/selectors/entities/channels'; +import {getCurrentChannelId, makeGetChannel, getMyChannelMember, isChannelReadOnlyById} from 'mattermost-redux/selectors/entities/channels'; import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentUserId, getUser} from 'mattermost-redux/selectors/entities/users'; import {isChannelMuted} from 'mattermost-redux/utils/channel_utils'; @@ -29,6 +29,9 @@ function makeMapStateToProps() { } } + const isReadOnly = isChannelReadOnlyById(state, channel.id); + const shouldHideChannel = !ownProps.isSearchResult && !ownProps.isFavorite && isReadOnly; + return { currentChannelId: getCurrentChannelId(state), displayName: channel.display_name, @@ -36,6 +39,7 @@ function makeMapStateToProps() { isChannelMuted: isChannelMuted(member), isMyUser, mentions: member ? member.mention_count : 0, + shouldHideChannel, status: channel.status, teammateDeletedAt, theme: getTheme(state), diff --git a/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js b/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js index 067aa6133..d8bb6607b 100644 --- a/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js +++ b/app/components/channel_drawer/channels_list/filtered_list/filtered_list.js @@ -113,6 +113,7 @@ class FilteredList extends Component { ref={channel.id} channelId={channel.id} channel={channel} + isSearchResult={true} isUnread={false} mentions={0} onSelectChannel={this.onSelectChannel} diff --git a/app/components/channel_drawer/channels_list/list/index.js b/app/components/channel_drawer/channels_list/list/index.js index ca719a2a5..22c812153 100644 --- a/app/components/channel_drawer/channels_list/list/index.js +++ b/app/components/channel_drawer/channels_list/list/index.js @@ -15,7 +15,7 @@ import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/ import {getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; import {getTheme, getFavoritesPreferences} from 'mattermost-redux/selectors/entities/preferences'; import {showCreateOption} from 'mattermost-redux/utils/channel_utils'; -import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils'; +import {isAdmin as checkIsAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils'; import List from './list'; @@ -24,13 +24,16 @@ function mapStateToProps(state) { const roles = getCurrentUserId(state) ? getCurrentUserRoles(state) : ''; const unreadChannelIds = getSortedUnreadChannelIds(state); const favoriteChannelIds = getSortedFavoriteChannelIds(state); - const publicChannelIds = getSortedPublicChannelIds(state); const privateChannelIds = getSortedPrivateChannelIds(state); const directChannelIds = getSortedDirectChannelIds(state); const currentTeamId = getCurrentTeamId(state); + const publicChannelIds = getSortedPublicChannelIds(state); + + const isAdmin = checkIsAdmin(roles); + const isSystemAdmin = checkIsSystemAdmin(roles); return { - canCreatePrivateChannels: showCreateOption(state, config, license, currentTeamId, General.PRIVATE_CHANNEL, isAdmin(roles), isSystemAdmin(roles)), + canCreatePrivateChannels: showCreateOption(state, config, license, currentTeamId, General.PRIVATE_CHANNEL, isAdmin, isSystemAdmin), unreadChannelIds, favoriteChannelIds, publicChannelIds, diff --git a/app/components/channel_drawer/channels_list/list/list.js b/app/components/channel_drawer/channels_list/list/list.js index c21e18c73..887a56285 100644 --- a/app/components/channel_drawer/channels_list/list/list.js +++ b/app/components/channel_drawer/channels_list/list/list.js @@ -257,6 +257,7 @@ export default class List extends PureComponent { return ( diff --git a/app/components/post/index.js b/app/components/post/index.js index 6ec909aeb..55c5a1ca1 100644 --- a/app/components/post/index.js +++ b/app/components/post/index.js @@ -5,13 +5,13 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import {createPost, deletePost, removePost} from 'mattermost-redux/actions/posts'; +import {getCurrentChannelId, isCurrentChannelReadOnly} from 'mattermost-redux/selectors/entities/channels'; import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {getCurrentUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users'; import {getMyPreferences, getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentTeamUrl, getCurrentTeamId} from 'mattermost-redux/selectors/entities/teams'; -import {getCurrentChannelId} from 'mattermost-redux/selectors/entities/channels'; import {canDeletePost, canEditPost, isPostFlagged} from 'mattermost-redux/utils/post_utils'; -import {isAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils'; +import {isAdmin as checkIsAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils'; import {insertToDraft, setPostTooltipVisible} from 'app/actions/views/channel'; import {addReaction} from 'app/actions/views/emoji'; @@ -56,14 +56,18 @@ function mapStateToProps(state, ownProps) { const {deviceWidth} = getDimensions(state); + const isAdmin = checkIsAdmin(roles); + const isSystemAdmin = checkIsSystemAdmin(roles); + let canDelete = false; let canEdit = false; if (post) { - canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin(roles), isSystemAdmin(roles)); + canDelete = canDeletePost(state, config, license, currentTeamId, currentChannelId, currentUserId, post, isAdmin, isSystemAdmin); canEdit = canEditPost(state, config, license, currentTeamId, currentChannelId, currentUserId, post); } return { + channelIsReadOnly: isCurrentChannelReadOnly(state), config, canDelete, canEdit, diff --git a/app/components/post/post.js b/app/components/post/post.js index 16fddc5a7..ce36b8aaa 100644 --- a/app/components/post/post.js +++ b/app/components/post/post.js @@ -39,6 +39,7 @@ export default class Post extends PureComponent { insertToDraft: PropTypes.func.isRequired, removePost: PropTypes.func.isRequired, }).isRequired, + channelIsReadOnly: PropTypes.bool, config: PropTypes.object.isRequired, currentTeamUrl: PropTypes.string.isRequired, currentUserId: PropTypes.string.isRequired, @@ -70,6 +71,7 @@ export default class Post extends PureComponent { static defaultProps = { isSearchResult: false, showLongPost: false, + channelIsReadOnly: false, }; static contextTypes = { @@ -377,6 +379,7 @@ export default class Post extends PureComponent { render() { const { + channelIsReadOnly, commentedOnPost, highlight, isLastReply, @@ -443,6 +446,7 @@ export default class Post extends PureComponent { canDelete={this.props.canDelete} canEdit={this.state.canEdit} highlight={highlight} + channelIsReadOnly={channelIsReadOnly} isSearchResult={isSearchResult} navigator={this.props.navigator} onAddReaction={this.handleAddReaction} diff --git a/app/components/post_body/post_body.js b/app/components/post_body/post_body.js index f8a15ebeb..66db41a2f 100644 --- a/app/components/post_body/post_body.js +++ b/app/components/post_body/post_body.js @@ -37,6 +37,7 @@ export default class PostBody extends PureComponent { }).isRequired, canDelete: PropTypes.bool, canEdit: PropTypes.bool, + channelIsReadOnly: PropTypes.bool.isRequired, fileIds: PropTypes.array, hasBeenDeleted: PropTypes.bool, hasBeenEdited: PropTypes.bool, @@ -116,6 +117,7 @@ export default class PostBody extends PureComponent { canEdit, canDelete, canAddReaction, + channelIsReadOnly, hasBeenDeleted, isPending, isFailed, @@ -132,7 +134,7 @@ export default class PostBody extends PureComponent { // we should check for the user roles and permissions if (!isPendingOrFailedPost && !isSystemMessage && !isPostEphemeral) { - if (canAddReaction) { + if (canAddReaction && !channelIsReadOnly) { actions.push({ text: formatMessage({id: 'mobile.post_info.add_reaction', defaultMessage: 'Add Reaction'}), onPress: this.props.onAddReaction, @@ -147,16 +149,18 @@ export default class PostBody extends PureComponent { }); } - if (isFlagged) { - actions.push({ - text: formatMessage({id: 'post_info.mobile.unflag', defaultMessage: 'Unflag'}), - onPress: this.unflagPost, - }); - } else { - actions.push({ - text: formatMessage({id: 'post_info.mobile.flag', defaultMessage: 'Flag'}), - onPress: this.flagPost, - }); + if (!channelIsReadOnly) { + if (isFlagged) { + actions.push({ + text: formatMessage({id: 'post_info.mobile.unflag', defaultMessage: 'Unflag'}), + onPress: this.unflagPost, + }); + } else { + actions.push({ + text: formatMessage({id: 'post_info.mobile.flag', defaultMessage: 'Flag'}), + onPress: this.flagPost, + }); + } } if (canEdit) { diff --git a/app/components/post_textbox/index.js b/app/components/post_textbox/index.js index 7a8d75b40..4fd71c362 100644 --- a/app/components/post_textbox/index.js +++ b/app/components/post_textbox/index.js @@ -6,7 +6,7 @@ import {connect} from 'react-redux'; import {General} from 'mattermost-redux/constants'; import {createPost} from 'mattermost-redux/actions/posts'; -import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels'; +import {getCurrentChannel, isCurrentChannelReadOnly} from 'mattermost-redux/selectors/entities/channels'; import {canUploadFilesOnMobile, getConfig} from 'mattermost-redux/selectors/entities/general'; import {getTheme} from 'mattermost-redux/selectors/entities/preferences'; import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users'; @@ -41,6 +41,7 @@ function mapStateToProps(state, ownProps) { channelId: ownProps.channelId || (currentChannel ? currentChannel.id : ''), canUploadFiles: canUploadFilesOnMobile(state), channelIsLoading: state.views.channel.loading, + channelIsReadOnly: isCurrentChannelReadOnly(state), currentUserId: getCurrentUserId(state), deactivatedChannel, files: currentDraft.files, diff --git a/app/components/post_textbox/post_textbox.js b/app/components/post_textbox/post_textbox.js index a0814ceab..2d2138aea 100644 --- a/app/components/post_textbox/post_textbox.js +++ b/app/components/post_textbox/post_textbox.js @@ -39,6 +39,7 @@ export default class PostTextbox extends PureComponent { canUploadFiles: PropTypes.bool.isRequired, channelId: PropTypes.string.isRequired, channelIsLoading: PropTypes.bool.isRequired, + channelIsReadOnly: PropTypes.bool.isRequired, currentUserId: PropTypes.string.isRequired, deactivatedChannel: PropTypes.bool.isRequired, files: PropTypes.array, @@ -397,6 +398,7 @@ export default class PostTextbox extends PureComponent { canUploadFiles, channelId, channelIsLoading, + channelIsReadOnly, deactivatedChannel, files, navigator, @@ -422,7 +424,9 @@ export default class PostTextbox extends PureComponent { const textValue = channelIsLoading ? '' : this.state.value; let placeholder; - if (rootId) { + if (channelIsReadOnly) { + placeholder = {id: 'mobile.create_post.read_only', defaultMessage: 'This channel is read-only.'}; + } else if (rootId) { placeholder = {id: 'create_comment.addComment', defaultMessage: 'Add a comment...'}; } else { placeholder = {id: 'create_post.write', defaultMessage: 'Write a message...'}; @@ -463,8 +467,8 @@ export default class PostTextbox extends PureComponent { rootId={rootId} /> - {attachmentButton} - + {!channelIsReadOnly && attachmentButton} + {this.renderSendButton()} diff --git a/app/screens/channel_info/index.js b/app/screens/channel_info/index.js index db0432c7d..ee0659b38 100644 --- a/app/screens/channel_info/index.js +++ b/app/screens/channel_info/index.js @@ -21,10 +21,11 @@ import { getCurrentChannelStats, getSortedFavoriteChannelIds, getMyCurrentChannelMembership, + isCurrentChannelReadOnly, } from 'mattermost-redux/selectors/entities/channels'; import {getCurrentUserId, getUser, getStatusForUserId, getCurrentUserRoles} from 'mattermost-redux/selectors/entities/users'; import {getUserIdFromChannelName, isChannelMuted, showDeleteOption, showManagementOptions} from 'mattermost-redux/utils/channel_utils'; -import {isAdmin, isChannelAdmin, isSystemAdmin} from 'mattermost-redux/utils/user_utils'; +import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, isSystemAdmin as checkIsSystemAdmin} from 'mattermost-redux/utils/user_utils'; import { closeDMChannel, @@ -56,9 +57,16 @@ function mapStateToProps(state) { status = getStatusForUserId(state, teammateId); } + const isAdmin = checkIsAdmin(roles); + const isChannelAdmin = checkIsChannelAdmin(roles); + const isSystemAdmin = checkIsSystemAdmin(roles); + + const channelIsReadOnly = isCurrentChannelReadOnly(state); + const canEditChannel = !channelIsReadOnly && showManagementOptions(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin); + return { - canDeleteChannel: showDeleteOption(state, config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)), - canEditChannel: showManagementOptions(state, config, license, currentChannel, isAdmin(roles), isSystemAdmin(roles), isChannelAdmin(roles)), + canDeleteChannel: showDeleteOption(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin), + canEditChannel, currentChannel, currentChannelCreatorName, currentChannelMemberCount, diff --git a/assets/base/config.json b/assets/base/config.json index 1b12796ba..4d7500889 100644 --- a/assets/base/config.json +++ b/assets/base/config.json @@ -28,9 +28,9 @@ "console": true } }, - + "ExperimentalNormalizeMarkdownLinks": false, - + "AutoSelectServerUrl": false, "EnableMobileClientUpgrade": false, diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 999cc8417..1a36ba8e3 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -2071,6 +2071,7 @@ "mobile.create_channel": "Create", "mobile.create_channel.private": "New Private Channel", "mobile.create_channel.public": "New Public Channel", + "mobile.create_post.read_only": "This channel is read-only", "mobile.custom_list.no_results": "No Results", "mobile.document_preview.failed_description": "An error occurred while opening the document. Please make sure you have a {fileType} viewer installed and try again.\n", "mobile.document_preview.failed_title": "Open Document failed",