PLT-6484 Add /leave command to leave a channel (#6402)
* PLT-6484 Add /leave command to leave a channel * Text changes requeted on review. * PLT-6484 Display the right error message when trying to /leave town-square * PLT-6484 Be able to execute /leave command in direct and group message channels with the same effect as clicking x * PLT-6484 Refactor to create new leave_private_channel_modal.jsx * PLT-6484 Remove previous leave private channel logic to use new leave_private_channel_modal.jsx * Remove dot in command description. Change localized error when leaving Town square. * disable /leave command in reply threads on the right-hand sidebar, since it is not obvious which channel you should leave
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
19804c4e40
Коммит
b54d134299
66
api/command_leave_test.go
Обычный файл
66
api/command_leave_test.go
Обычный файл
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mattermost/platform/model"
|
||||
)
|
||||
|
||||
func TestLeaveCommands(t *testing.T) {
|
||||
th := Setup().InitBasic()
|
||||
Client := th.BasicClient
|
||||
team := th.BasicTeam
|
||||
user2 := th.BasicUser2
|
||||
|
||||
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
|
||||
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
|
||||
Client.Must(Client.JoinChannel(channel1.Id))
|
||||
|
||||
channel2 := &model.Channel{DisplayName: "BB", Name: "bb" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
|
||||
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
|
||||
Client.Must(Client.JoinChannel(channel2.Id))
|
||||
Client.Must(Client.AddChannelMember(channel2.Id, user2.Id))
|
||||
|
||||
channel3 := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
|
||||
|
||||
rs1 := Client.Must(Client.Command(channel1.Id, "/leave")).Data.(*model.CommandResponse)
|
||||
if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
|
||||
t.Fatal("failed to leave open channel 1")
|
||||
}
|
||||
|
||||
rs2 := Client.Must(Client.Command(channel2.Id, "/leave")).Data.(*model.CommandResponse)
|
||||
if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
|
||||
t.Fatal("failed to leave private channel 1")
|
||||
}
|
||||
|
||||
rs3 := Client.Must(Client.Command(channel3.Id, "/leave")).Data.(*model.CommandResponse)
|
||||
if strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+model.DEFAULT_CHANNEL) {
|
||||
t.Fatal("should not have left direct message channel")
|
||||
}
|
||||
|
||||
cdata := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
|
||||
|
||||
found := false
|
||||
for _, c := range *cdata {
|
||||
if c.Id == channel1.Id || c.Id == channel2.Id {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
t.Fatal("did not leave right channels")
|
||||
}
|
||||
|
||||
for _, c := range *cdata {
|
||||
if c.Name == model.DEFAULT_CHANNEL {
|
||||
if _, err := Client.LeaveChannel(c.Id); err == nil {
|
||||
t.Fatal("should have errored on leaving default channel")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
55
app/command_leave.go
Обычный файл
55
app/command_leave.go
Обычный файл
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"github.com/mattermost/platform/model"
|
||||
goi18n "github.com/nicksnyder/go-i18n/i18n"
|
||||
)
|
||||
|
||||
type LeaveProvider struct {
|
||||
}
|
||||
|
||||
const (
|
||||
CMD_LEAVE = "leave"
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterCommandProvider(&LeaveProvider{})
|
||||
}
|
||||
|
||||
func (me *LeaveProvider) GetTrigger() string {
|
||||
return CMD_LEAVE
|
||||
}
|
||||
|
||||
func (me *LeaveProvider) GetCommand(T goi18n.TranslateFunc) *model.Command {
|
||||
return &model.Command{
|
||||
Trigger: CMD_LEAVE,
|
||||
AutoComplete: true,
|
||||
AutoCompleteDesc: T("api.command_leave.desc"),
|
||||
DisplayName: T("api.command_leave.name"),
|
||||
}
|
||||
}
|
||||
|
||||
func (me *LeaveProvider) DoCommand(args *model.CommandArgs, message string) *model.CommandResponse {
|
||||
var channel *model.Channel
|
||||
var noChannelErr *model.AppError
|
||||
if channel, noChannelErr = GetChannel(args.ChannelId); noChannelErr != nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_leave.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
if channel.Name == model.DEFAULT_CHANNEL {
|
||||
return &model.CommandResponse{Text: args.T("api.channel.leave.default.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
err := LeaveChannel(args.ChannelId, args.UserId)
|
||||
if err != nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_leave.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
team, err := GetTeam(args.TeamId)
|
||||
if err != nil {
|
||||
return &model.CommandResponse{Text: args.T("api.command_leave.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
|
||||
return &model.CommandResponse{GotoLocation: args.SiteURL + "/" + team.Name + "/channels/" + model.DEFAULT_CHANNEL, Text: args.T("api.command_leave.success"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
|
||||
}
|
||||
24
i18n/en.json
24
i18n/en.json
@@ -691,6 +691,30 @@
|
||||
"id": "api.command_join.success",
|
||||
"translation": "Joined channel."
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.desc",
|
||||
"translation": "Leave the current channel"
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.fail.app_error",
|
||||
"translation": "An error occurred while leaving the channel."
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.list.app_error",
|
||||
"translation": "An error occurred while listing channels."
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.missing.app_error",
|
||||
"translation": "We couldn't find the channel."
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.name",
|
||||
"translation": "leave"
|
||||
},
|
||||
{
|
||||
"id": "api.command_leave.success",
|
||||
"translation": "Left the channel."
|
||||
},
|
||||
{
|
||||
"id": "api.command_logout.desc",
|
||||
"translation": "Logout of Mattermost"
|
||||
|
||||
@@ -72,6 +72,39 @@ export function executeCommand(message, args, success, error) {
|
||||
msg = '/shortcuts';
|
||||
}
|
||||
break;
|
||||
case '/leave': {
|
||||
// /leave command not supported in reply threads.
|
||||
if (args.channel_id && (args.root_id || args.parent_id)) {
|
||||
GlobalActions.sendEphemeralPost('/leave is not supported in reply threads. Use it in the center channel instead.', args.channel_id, args.parent_id);
|
||||
return;
|
||||
}
|
||||
const channel = ChannelStore.getCurrent();
|
||||
if (channel.type === Constants.PRIVATE_CHANNEL) {
|
||||
GlobalActions.showLeavePrivateChannelModal(channel);
|
||||
return;
|
||||
} else if (
|
||||
channel.type === Constants.DM_CHANNEL ||
|
||||
channel.type === Constants.GM_CHANNEL
|
||||
) {
|
||||
let name;
|
||||
let category;
|
||||
if (channel.type === Constants.DM_CHANNEL) {
|
||||
name = Utils.getUserIdFromChannelName(channel);
|
||||
category = Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW;
|
||||
} else {
|
||||
name = channel.id;
|
||||
category = Constants.Preferences.CATEGORY_GROUP_CHANNEL_SHOW;
|
||||
}
|
||||
const currentUserId = UserStore.getCurrentId();
|
||||
savePreferences(currentUserId, [{category, name, user_id: currentUserId, value: 'false'}])(dispatch, getState);
|
||||
if (ChannelUtils.isFavoriteChannel(channel)) {
|
||||
unmarkFavorite(channel.id);
|
||||
}
|
||||
browserHistory.push(`${TeamStore.getCurrentTeamRelativeUrl()}/channels/town-square`);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '/settings':
|
||||
GlobalActions.showAccountSettingsModal();
|
||||
return;
|
||||
|
||||
@@ -281,6 +281,13 @@ export function showLeaveTeamModal() {
|
||||
});
|
||||
}
|
||||
|
||||
export function showLeavePrivateChannelModal(channel) {
|
||||
AppDispatcher.handleViewAction({
|
||||
type: ActionTypes.TOGGLE_LEAVE_PRIVATE_CHANNEL_MODAL,
|
||||
value: channel
|
||||
});
|
||||
}
|
||||
|
||||
export function emitSuggestionPretextChanged(suggestionId, pretext) {
|
||||
AppDispatcher.handleViewAction({
|
||||
type: ActionTypes.SUGGESTION_PRETEXT_CHANGED,
|
||||
@@ -351,7 +358,7 @@ export function emitPreferencesDeletedEvent(preferences) {
|
||||
});
|
||||
}
|
||||
|
||||
export function sendEphemeralPost(message, channelId) {
|
||||
export function sendEphemeralPost(message, channelId, parentId) {
|
||||
const timestamp = Utils.getTimestamp();
|
||||
const post = {
|
||||
id: Utils.generateId(),
|
||||
@@ -361,6 +368,8 @@ export function sendEphemeralPost(message, channelId) {
|
||||
type: Constants.PostTypes.EPHEMERAL,
|
||||
create_at: timestamp,
|
||||
update_at: timestamp,
|
||||
root_id: parentId,
|
||||
parent_id: parentId,
|
||||
props: {}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ import ChannelMembersModal from './channel_members_modal.jsx';
|
||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||
import DeleteChannelModal from './delete_channel_modal.jsx';
|
||||
import RenameChannelModal from './rename_channel_modal.jsx';
|
||||
import ConfirmModal from './confirm_modal.jsx';
|
||||
import ToggleModalButton from './toggle_modal_button.jsx';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
@@ -60,8 +59,6 @@ export default class ChannelHeader extends React.Component {
|
||||
this.initWebrtc = this.initWebrtc.bind(this);
|
||||
this.onBusy = this.onBusy.bind(this);
|
||||
this.openDirectMessageModal = this.openDirectMessageModal.bind(this);
|
||||
this.createLeaveChannelModal = this.createLeaveChannelModal.bind(this);
|
||||
this.hideLeaveChannelModal = this.hideLeaveChannelModal.bind(this);
|
||||
|
||||
const state = this.getStateFromStores();
|
||||
state.showEditChannelHeaderModal = false;
|
||||
@@ -91,7 +88,6 @@ export default class ChannelHeader extends React.Component {
|
||||
enableFormatting: PreferenceStore.getBool(Preferences.CATEGORY_ADVANCED_SETTINGS, 'formatting', true),
|
||||
isBusy: WebrtcStore.isBusy(),
|
||||
isFavorite: channel && ChannelUtils.isFavoriteChannel(channel),
|
||||
showLeaveChannelModal: false,
|
||||
pinsOpen: SearchStore.getIsPinnedPosts()
|
||||
};
|
||||
}
|
||||
@@ -144,9 +140,7 @@ export default class ChannelHeader extends React.Component {
|
||||
|
||||
handleLeave() {
|
||||
if (this.state.channel.type === Constants.PRIVATE_CHANNEL) {
|
||||
this.setState({
|
||||
showLeaveChannelModal: true
|
||||
});
|
||||
GlobalActions.showLeavePrivateChannelModal(this.state.channel);
|
||||
} else {
|
||||
ChannelActions.leaveChannel(this.state.channel.id);
|
||||
}
|
||||
@@ -233,54 +227,6 @@ export default class ChannelHeader extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
hideLeaveChannelModal() {
|
||||
this.setState({
|
||||
showLeaveChannelModal: false
|
||||
});
|
||||
}
|
||||
|
||||
createLeaveChannelModal() {
|
||||
const title = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.title'
|
||||
defaultMessage='Leave Private Channel {channel}'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const message = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.message'
|
||||
defaultMessage='Are you sure you wish to leave the private channel {channel}? You must be re-invited in order to re-join this channel in the future.'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const buttonClass = 'btn btn-danger';
|
||||
const button = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.leave'
|
||||
defaultMessage='Yes, leave channel'
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
show={this.state.showLeaveChannelModal}
|
||||
title={title}
|
||||
message={message}
|
||||
confirmButtonClass={buttonClass}
|
||||
confirmButtonText={button}
|
||||
onConfirm={() => ChannelActions.leaveChannel(this.state.channel.id)}
|
||||
onCancel={this.hideLeaveChannelModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const flagIcon = Constants.FLAG_ICON_SVG;
|
||||
const pinIcon = Constants.PIN_ICON_SVG;
|
||||
@@ -885,8 +831,6 @@ export default class ChannelHeader extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const leaveChannelModal = this.createLeaveChannelModal();
|
||||
|
||||
let pinnedIconClass = 'channel-header__icon';
|
||||
if (this.state.pinsOpen) {
|
||||
pinnedIconClass += ' active';
|
||||
@@ -1001,7 +945,6 @@ export default class ChannelHeader extends React.Component {
|
||||
{editHeaderModal}
|
||||
{editPurposeModal}
|
||||
{channelMembersModal}
|
||||
{leaveChannelModal}
|
||||
<RenameChannelModal
|
||||
show={this.state.showRenameChannelModal}
|
||||
onHide={this.hideRenameChannelModal}
|
||||
|
||||
120
webapp/components/modals/leave_private_channel_modal.jsx
Обычный файл
120
webapp/components/modals/leave_private_channel_modal.jsx
Обычный файл
@@ -0,0 +1,120 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ConfirmModal from 'components/confirm_modal.jsx';
|
||||
|
||||
import * as ChannelActions from 'actions/channel_actions.jsx';
|
||||
|
||||
import ModalStore from 'stores/modal_store.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import {intlShape, injectIntl, FormattedMessage} from 'react-intl';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class LeavePrivateChannelModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleToggle = this.handleToggle.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.handleHide = this.handleHide.bind(this);
|
||||
this.handleKeyPress = this.handleKeyPress.bind(this);
|
||||
|
||||
this.state = {
|
||||
show: false,
|
||||
channel: null
|
||||
};
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
ModalStore.addModalListener(Constants.ActionTypes.TOGGLE_LEAVE_PRIVATE_CHANNEL_MODAL, this.handleToggle);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
ModalStore.removeModalListener(Constants.ActionTypes.TOGGLE_LEAVE_PRIVATE_CHANNEL_MODAL, this.handleToggle);
|
||||
}
|
||||
|
||||
handleKeyPress(e) {
|
||||
if (e.key === 'Enter' && this.state.show) {
|
||||
this.handleSubmit();
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit() {
|
||||
const channelId = this.state.channel.id;
|
||||
this.setState({
|
||||
show: false,
|
||||
channel: null
|
||||
});
|
||||
ChannelActions.leaveChannel(channelId);
|
||||
}
|
||||
|
||||
handleToggle(value) {
|
||||
this.setState({
|
||||
channel: value,
|
||||
show: value !== null
|
||||
});
|
||||
}
|
||||
|
||||
handleHide() {
|
||||
this.setState({
|
||||
show: false
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let title = '';
|
||||
let message = '';
|
||||
if (this.state.channel) {
|
||||
title = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.title'
|
||||
defaultMessage='Leave Private Channel {channel}'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
message = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.message'
|
||||
defaultMessage='Are you sure you wish to leave the private channel {channel}? You must be re-invited in order to re-join this channel in the future.'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const buttonClass = 'btn btn-danger';
|
||||
const button = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.leave'
|
||||
defaultMessage='Yes, leave channel'
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
show={this.state.show}
|
||||
title={title}
|
||||
message={message}
|
||||
confirmButtonClass={buttonClass}
|
||||
confirmButtonText={button}
|
||||
onConfirm={this.handleSubmit}
|
||||
onCancel={this.handleHide}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
LeavePrivateChannelModal.propTypes = {
|
||||
intl: intlShape.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(LeavePrivateChannelModal);
|
||||
@@ -12,7 +12,6 @@ import ChannelMembersModal from './channel_members_modal.jsx';
|
||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||
import DeleteChannelModal from './delete_channel_modal.jsx';
|
||||
import RenameChannelModal from './rename_channel_modal.jsx';
|
||||
import ConfirmModal from './confirm_modal.jsx';
|
||||
import ToggleModalButton from './toggle_modal_button.jsx';
|
||||
import StatusIcon from './status_icon.jsx';
|
||||
|
||||
@@ -75,9 +74,6 @@ export default class Navbar extends React.Component {
|
||||
this.openDirectMessageModal = this.openDirectMessageModal.bind(this);
|
||||
this.getPinnedPosts = this.getPinnedPosts.bind(this);
|
||||
|
||||
this.createLeaveChannelModal = this.createLeaveChannelModal.bind(this);
|
||||
this.hideLeaveChannelModal = this.hideLeaveChannelModal.bind(this);
|
||||
|
||||
const state = this.getStateFromStores();
|
||||
state.showEditChannelPurposeModal = false;
|
||||
state.showEditChannelHeaderModal = false;
|
||||
@@ -97,8 +93,7 @@ export default class Navbar extends React.Component {
|
||||
users: [],
|
||||
userCount: ChannelStore.getCurrentStats().member_count,
|
||||
currentUser: UserStore.getCurrentUser(),
|
||||
isFavorite: channel && ChannelUtils.isFavoriteChannel(channel),
|
||||
showLeaveChannelModal: false
|
||||
isFavorite: channel && ChannelUtils.isFavoriteChannel(channel)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,9 +134,7 @@ export default class Navbar extends React.Component {
|
||||
|
||||
handleLeave() {
|
||||
if (this.state.channel.type === Constants.PRIVATE_CHANNEL) {
|
||||
this.setState({
|
||||
showLeaveChannelModal: true
|
||||
});
|
||||
GlobalActions.showLeavePrivateChannelModal(this.state.channel);
|
||||
} else {
|
||||
ChannelActions.leaveChannel(this.state.channel.id);
|
||||
}
|
||||
@@ -739,54 +732,6 @@ export default class Navbar extends React.Component {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
hideLeaveChannelModal() {
|
||||
this.setState({
|
||||
showLeaveChannelModal: false
|
||||
});
|
||||
}
|
||||
|
||||
createLeaveChannelModal() {
|
||||
const title = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.title'
|
||||
defaultMessage='Leave Private Channel {channel}'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const message = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.message'
|
||||
defaultMessage='Are you sure you wish to leave the private channel {channel}? You must be re-invited in order to re-join this channel in the future.'
|
||||
values={{
|
||||
channel: <b>{this.state.channel.display_name}</b>
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const buttonClass = 'btn btn-danger';
|
||||
const button = (
|
||||
<FormattedMessage
|
||||
id='leave_private_channel_modal.leave'
|
||||
defaultMessage='Yes, leave channel'
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<ConfirmModal
|
||||
show={this.state.showLeaveChannelModal}
|
||||
title={title}
|
||||
message={message}
|
||||
confirmButtonClass={buttonClass}
|
||||
confirmButtonText={button}
|
||||
onConfirm={() => ChannelActions.leaveChannel(this.state.channel.id)}
|
||||
onCancel={this.hideLeaveChannelModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
getTeammateStatus() {
|
||||
const channel = this.state.channel;
|
||||
|
||||
@@ -961,8 +906,6 @@ export default class Navbar extends React.Component {
|
||||
|
||||
var channelMenuDropdown = this.createDropdown(channel, channelTitle, isSystemAdmin, isTeamAdmin, isChannelAdmin, isDirect, isGroup, popoverContent);
|
||||
|
||||
const leaveChannelModal = this.createLeaveChannelModal();
|
||||
|
||||
return (
|
||||
<div>
|
||||
<nav
|
||||
@@ -979,7 +922,6 @@ export default class Navbar extends React.Component {
|
||||
</nav>
|
||||
{editChannelHeaderModal}
|
||||
{editChannelPurposeModal}
|
||||
{leaveChannelModal}
|
||||
{renameChannelModal}
|
||||
{channelMembersModal}
|
||||
{quickSwitchModal}
|
||||
|
||||
@@ -45,6 +45,7 @@ import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
|
||||
import InviteMemberModal from 'components/invite_member_modal.jsx';
|
||||
import LeaveTeamModal from 'components/leave_team_modal.jsx';
|
||||
import ResetStatusModal from 'components/reset_status_modal';
|
||||
import LeavePrivateChannelModal from 'components/modals/leave_private_channel_modal.jsx';
|
||||
|
||||
import iNoBounce from 'inobounce';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
@@ -231,6 +232,7 @@ export default class NeedsTeam extends React.Component {
|
||||
<DeletePostModal/>
|
||||
<RemovedFromChannelModal/>
|
||||
<ResetStatusModal/>
|
||||
<LeavePrivateChannelModal/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -44,6 +44,7 @@ class ModalStoreClass extends EventEmitter {
|
||||
case ActionTypes.TOGGLE_CHANNEL_HEADER_UPDATE_MODAL:
|
||||
case ActionTypes.TOGGLE_CHANNEL_PURPOSE_UPDATE_MODAL:
|
||||
case ActionTypes.TOGGLE_CHANNEL_NAME_UPDATE_MODAL:
|
||||
case ActionTypes.TOGGLE_LEAVE_PRIVATE_CHANNEL_MODAL:
|
||||
this.emit(type, value, args);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ export const ActionTypes = keyMirror({
|
||||
TOGGLE_CHANNEL_HEADER_UPDATE_MODAL: null,
|
||||
TOGGLE_CHANNEL_PURPOSE_UPDATE_MODAL: null,
|
||||
TOGGLE_CHANNEL_NAME_UPDATE_MODAL: null,
|
||||
TOGGLE_LEAVE_PRIVATE_CHANNEL_MODAL: null,
|
||||
|
||||
SUGGESTION_PRETEXT_CHANGED: null,
|
||||
SUGGESTION_RECEIVED_SUGGESTIONS: null,
|
||||
|
||||
Ссылка в новой задаче
Block a user