Skip to content

Commit

Permalink
[MM-12330] Add "Unarchive Channel" option to archived channels menu (m…
Browse files Browse the repository at this point in the history
…attermost#4458)

Automatic Merge
  • Loading branch information
Allen Lai committed Feb 27, 2020
1 parent f536a6d commit 299cfb1
Show file tree
Hide file tree
Showing 11 changed files with 428 additions and 2 deletions.
12 changes: 12 additions & 0 deletions actions/websocket_actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,10 @@ export function handleEvent(msg) {
handleChannelDeletedEvent(msg);
break;

case SocketEvents.CHANNEL_UNARCHIVED:
handleChannelUnarchivedEvent(msg);
break;

case SocketEvents.CHANNEL_CONVERTED:
handleChannelConvertedEvent(msg);
break;
Expand Down Expand Up @@ -847,6 +851,14 @@ function handleChannelDeletedEvent(msg) {
dispatch({type: ChannelTypes.RECEIVED_CHANNEL_DELETED, data: {id: msg.data.channel_id, team_id: msg.broadcast.team_id, deleteAt: msg.data.delete_at, viewArchivedChannels}});
}

function handleChannelUnarchivedEvent(msg) {
const state = getState();
const config = getConfig(state);
const viewArchivedChannels = config.ExperimentalViewArchivedChannels === 'true';

dispatch({type: ChannelTypes.RECEIVED_CHANNEL_UNARCHIVED, data: {id: msg.data.channel_id, team_id: msg.broadcast.team_id, viewArchivedChannels}});
}

function handlePreferenceChangedEvent(msg) {
const preference = JSON.parse(msg.data.preference);
dispatch({type: PreferenceTypes.RECEIVED_PREFERENCES, data: [preference]});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,31 @@ exports[`components/ChannelHeaderDropdown should match snapshot with no plugin i
isArchived={false}
/>
</MenuGroup>
<MenuGroup>
<Connect(ChannelPermissionGate)
channelId="test-channel-id"
permissions={
Array [
"manage_team",
]
}
>
<MenuItemToggleModalRedux
dialogProps={
Object {
"channel": Object {
"id": "test-channel-id",
},
}
}
dialogType={[Function]}
id="channelUnarchiveChannel"
modalId="unarchive_channel"
show={false}
text="Unarchive Channel"
/>
</Connect(ChannelPermissionGate)>
</MenuGroup>
</Fragment>
`;

Expand Down Expand Up @@ -674,5 +699,30 @@ exports[`components/ChannelHeaderDropdown should match snapshot with plugins 1`]
isArchived={false}
/>
</MenuGroup>
<MenuGroup>
<Connect(ChannelPermissionGate)
channelId="test-channel-id"
permissions={
Array [
"manage_team",
]
}
>
<MenuItemToggleModalRedux
dialogProps={
Object {
"channel": Object {
"id": "test-channel-id",
},
}
}
dialogType={[Function]}
id="channelUnarchiveChannel"
modalId="unarchive_channel"
show={false}
text="Unarchive Channel"
/>
</Connect(ChannelPermissionGate)>
</MenuGroup>
</Fragment>
`;
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import EditChannelPurposeModal from 'components/edit_channel_purpose_modal';
import RenameChannelModal from 'components/rename_channel_modal';
import ConvertChannelModal from 'components/convert_channel_modal';
import DeleteChannelModal from 'components/delete_channel_modal';
import UnarchiveChannelModal from 'components/unarchive_channel_modal';
import MoreDirectChannels from 'components/more_direct_channels';
import AddGroupsToChannelModal from 'components/add_groups_to_channel_modal';
import ChannelGroupsManageModal from 'components/channel_groups_manage_modal';
Expand Down Expand Up @@ -69,6 +70,7 @@ export default class ChannelHeaderDropdown extends React.PureComponent {
const channelMembersPermission = isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_MEMBERS : Permissions.MANAGE_PUBLIC_CHANNEL_MEMBERS;
const channelPropertiesPermission = isPrivate ? Permissions.MANAGE_PRIVATE_CHANNEL_PROPERTIES : Permissions.MANAGE_PUBLIC_CHANNEL_PROPERTIES;
const channelDeletePermission = isPrivate ? Permissions.DELETE_PRIVATE_CHANNEL : Permissions.DELETE_PUBLIC_CHANNEL;
const channelUnarchivePermission = Permissions.MANAGE_TEAM;

let divider;
if (isMobile) {
Expand Down Expand Up @@ -311,6 +313,25 @@ export default class ChannelHeaderDropdown extends React.PureComponent {
isArchived={isArchived}
/>
</Menu.Group>

<Menu.Group divider={divider}>
<ChannelPermissionGate
channelId={channel.id}
teamId={channel.team_id}
permissions={[channelUnarchivePermission]}
>
<Menu.ItemToggleModalRedux
id='channelUnarchiveChannel'
show={isArchived && !isDefault && channel.type !== Constants.DM_CHANNEL && channel.type !== Constants.GM_CHANNEL}
modalId={ModalIdentifiers.UNARCHIVE_CHANNEL}
dialogType={UnarchiveChannelModal}
dialogProps={{
channel,
}}
text={localizeMessage('channel_header.unarchive', 'Unarchive Channel')}
/>
</ChannelPermissionGate>
</Menu.Group>
</React.Fragment>
);
}
Expand Down
17 changes: 17 additions & 0 deletions components/post_markdown/system_message_helpers.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,22 @@ function renderChannelDeletedMessage(post) {
);
}

function renderChannelUnarchivedMessage(post) {
if (!post.props.username) {
return null;
}

const username = renderUsername(post.props.username);

return (
<FormattedMessage
id='api.channel.restore_channel.unarchived'
defaultMessage='{username} has unarchived the channel.'
values={{username}}
/>
);
}

function renderMeMessage(post) {
return renderFormattedText((post.props && post.props.message) ? post.props.message : post.message);
}
Expand All @@ -351,6 +367,7 @@ const systemMessageRenderers = {
[Posts.POST_TYPES.CONVERT_CHANNEL]: renderConvertChannelToPrivateMessage,
[Posts.POST_TYPES.PURPOSE_CHANGE]: renderPurposeChangeMessage,
[Posts.POST_TYPES.CHANNEL_DELETED]: renderChannelDeletedMessage,
[Posts.POST_TYPES.CHANNEL_UNARCHIVED]: renderChannelUnarchivedMessage,
[Posts.POST_TYPES.ME]: renderMeMessage,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`components/unarchive_channel_modal should match snapshot for unarchive_channel_modal 1`] = `
<Modal
animation={true}
aria-labelledby="unarchiveChannelModalLabel"
autoFocus={true}
backdrop={true}
bsClass="modal"
dialogClassName="a11y__modal"
dialogComponentClass={[Function]}
enforceFocus={true}
id="unarchiveChannelModal"
keyboard={true}
manager={
ModalManager {
"add": [Function],
"containers": Array [],
"data": Array [],
"handleContainerOverflow": true,
"hideSiblingNodes": true,
"isTopModal": [Function],
"modals": Array [],
"remove": [Function],
}
}
onExited={[MockFunction]}
onHide={[Function]}
renderBackdrop={[Function]}
restoreFocus={true}
role="dialog"
show={true}
>
<ModalHeader
bsClass="modal-header"
closeButton={true}
closeLabel="Close"
>
<ModalTitle
bsClass="modal-title"
componentClass="h1"
id="unarchiveChannelModalLabel"
>
<FormattedMessage
defaultMessage="Confirm UNARCHIVE Channel"
id="unarchive_channel.confirm"
values={Object {}}
/>
</ModalTitle>
</ModalHeader>
<ModalBody
bsClass="modal-body"
componentClass="div"
>
<div
className="alert alert-danger"
>
<injectIntl(FormattedMarkdownMessage)
defaultMessage="Are you sure you wish to unarchive the **{display_name}** channel?"
id="unarchive_channel.viewArchived.question"
values={
Object {
"display_name": "testing",
}
}
/>
</div>
</ModalBody>
<ModalFooter
bsClass="modal-footer"
componentClass="div"
>
<button
className="btn btn-link"
onClick={[Function]}
type="button"
>
<FormattedMessage
defaultMessage="Cancel"
id="unarchive_channel.cancel"
values={Object {}}
/>
</button>
<button
autoFocus={true}
className="btn btn-danger"
data-dismiss="modal"
id="unarchiveChannelModalDeleteButton"
onClick={[Function]}
type="button"
>
<FormattedMessage
defaultMessage="Unarchive"
id="unarchive_channel.del"
values={Object {}}
/>
</button>
</ModalFooter>
</Modal>
`;
18 changes: 18 additions & 0 deletions components/unarchive_channel_modal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {unarchiveChannel} from 'mattermost-redux/actions/channels';

import UnarchiveChannelModal from './unarchive_channel_modal.jsx';

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
unarchiveChannel,
}, dispatch),
};
}

export default connect(null, mapDispatchToProps)(UnarchiveChannelModal);
114 changes: 114 additions & 0 deletions components/unarchive_channel_modal/unarchive_channel_modal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import PropTypes from 'prop-types';
import React from 'react';
import {Modal} from 'react-bootstrap';
import {FormattedMessage} from 'react-intl';

import Constants from 'utils/constants';
import FormattedMarkdownMessage from 'components/formatted_markdown_message';

export default class UnarchiveChannelModal extends React.PureComponent {
static propTypes = {

/**
* Function called when modal is dismissed
*/
onHide: PropTypes.func.isRequired,

/**
* channel data
*/
channel: PropTypes.object.isRequired,

actions: PropTypes.shape({

/**
* Function called for deleting channel,
*/

unarchiveChannel: PropTypes.func.isRequired,
}),
}

constructor(props) {
super(props);

this.state = {show: true};
}

handleUnarchive = () => {
if (this.props.channel.id.length !== Constants.CHANNEL_ID_LENGTH) {
return;
}
this.props.actions.unarchiveChannel(this.props.channel.id);
this.onHide();
}

onHide = () => {
this.setState({show: false});
}

render() {
return (
<Modal
dialogClassName='a11y__modal'
show={this.state.show}
onHide={this.onHide}
onExited={this.props.onHide}
role='dialog'
aria-labelledby='unarchiveChannelModalLabel'
id='unarchiveChannelModal'
>
<Modal.Header closeButton={true}>
<Modal.Title
componentClass='h1'
id='unarchiveChannelModalLabel'
>
<FormattedMessage
id='unarchive_channel.confirm'
defaultMessage='Confirm UNARCHIVE Channel'
/>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className='alert alert-danger'>
<FormattedMarkdownMessage
id='unarchive_channel.viewArchived.question'
defaultMessage={'Are you sure you wish to unarchive the **{display_name}** channel?'}
values={{
display_name: this.props.channel.display_name,
}}
/>
</div>
</Modal.Body>
<Modal.Footer>
<button
type='button'
className='btn btn-link'
onClick={this.onHide}
>
<FormattedMessage
id='unarchive_channel.cancel'
defaultMessage='Cancel'
/>
</button>
<button
type='button'
className='btn btn-danger'
data-dismiss='modal'
onClick={this.handleUnarchive}
autoFocus={true}
id='unarchiveChannelModalDeleteButton'
>
<FormattedMessage
id='unarchive_channel.del'
defaultMessage='Unarchive'
/>
</button>
</Modal.Footer>
</Modal>
);
}
}
Loading

0 comments on commit 299cfb1

Please sign in to comment.