Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

[MM-16934] Add ability for channel type toggle (public/private) to go both directions #3568

Merged
merged 11 commits into from
Sep 18, 2019
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,6 @@ exports[`admin_console/team_channel_settings/channel/ChannelDetails should match
<div
className="admin-console__content"
>
<RemoveConfirmModal
amount={0}
inChannel={false}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
/>
<ChannelProfile
channel={
Object {
Expand All @@ -48,8 +41,29 @@ exports[`admin_console/team_channel_settings/channel/ChannelDetails should match
}
}
/>
<ConvertConfirmModal
displayName=""
onCancel={[Function]}
onConfirm={[Function]}
show={false}
toPublic={true}
/>
<RemoveConfirmModal
amount={0}
inChannel={true}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
/>
<ConvertAndRemoveConfirmModal
displayName=""
onCancel={[Function]}
onConfirm={[Function]}
removeAmount={0}
show={false}
toPublic={true}
/>
<ChannelModes
isOriginallyPrivate={false}
isPublic={true}
isSynced={false}
onToggle={[Function]}
Expand Down Expand Up @@ -116,13 +130,6 @@ exports[`admin_console/team_channel_settings/channel/ChannelDetails should match
<div
className="admin-console__content"
>
<RemoveConfirmModal
amount={0}
inChannel={false}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
/>
<ChannelProfile
channel={
Object {
Expand All @@ -135,8 +142,29 @@ exports[`admin_console/team_channel_settings/channel/ChannelDetails should match
}
team={Object {}}
/>
<ConvertConfirmModal
displayName=""
onCancel={[Function]}
onConfirm={[Function]}
show={false}
toPublic={true}
/>
<RemoveConfirmModal
amount={0}
inChannel={true}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
/>
<ConvertAndRemoveConfirmModal
displayName=""
onCancel={[Function]}
onConfirm={[Function]}
removeAmount={0}
show={false}
toPublic={true}
/>
<ChannelModes
isOriginallyPrivate={false}
isPublic={true}
isSynced={false}
onToggle={[Function]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ exports[`admin_console/team_channel_settings/channel/ChannelModes should match s
onToggle={[MockFunction]}
/>
<AllowAllToggle
isOriginallyPrivate={false}
isPublic={true}
isSynced={false}
onToggle={[MockFunction]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import FormError from 'components/form_error';
import Constants from 'utils/constants';

import {NeedGroupsError, UsersWillBeRemovedError} from '../../errors';
import ConvertConfirmModal from '../../convert_confirm_modal';
import RemoveConfirmModal from '../../remove_confirm_modal';
import ConvertAndRemoveConfirmModal from '../../convert_and_remove_confirm_modal';
import SaveChangesPanel from '../../save_changes_panel';

import {ChannelModes} from './channel_modes';
Expand All @@ -30,13 +32,13 @@ export default class ChannelDetails extends React.Component {
actions: PropTypes.shape({
getGroups: PropTypes.func.isRequired,
linkGroupSyncable: PropTypes.func.isRequired,
convertChannelToPrivate: PropTypes.func.isRequired,
unlinkGroupSyncable: PropTypes.func.isRequired,
membersMinusGroupMembers: PropTypes.func.isRequired,
setNavigationBlocked: PropTypes.func.isRequired,
getChannel: PropTypes.func.isRequired,
getTeam: PropTypes.func.isRequired,
patchChannel: PropTypes.func.isRequired,
updateChannelPrivacy: PropTypes.func.isRequired,
}).isRequired,
};

Expand All @@ -49,9 +51,12 @@ export default class ChannelDetails extends React.Component {
this.state = {
isSynced: Boolean(props.channel.group_constrained),
isPublic: props.channel.type === Constants.OPEN_CHANNEL,
isPrivacyChanging: false,
saving: false,
totalGroups: props.totalGroups,
showRemoveConfirmation: false,
showConvertConfirmModal: false,
showRemoveConfirmModal: false,
showConvertAndRemoveConfirmModal: false,
usersToRemove: 0,
groups: props.groups,
saveNeeded: false,
Expand Down Expand Up @@ -88,10 +93,13 @@ export default class ChannelDetails extends React.Component {
}

setToggles = (isSynced, isPublic) => {
const {channel} = this.props;
const isOriginallyPublic = (channel.type === Constants.OPEN_CHANNEL);
this.setState({
saveNeeded: true,
isSynced,
isPublic: !isSynced && isPublic,
isPublic,
isPrivacyChanging: isPublic !== isOriginallyPublic,
}, () => this.processGroupsChange(this.state.groups));
this.props.actions.setNavigationBlocked(true);
}
Expand Down Expand Up @@ -140,20 +148,57 @@ export default class ChannelDetails extends React.Component {
this.processGroupsChange(groups);
}

hideRemoveUsersModal = () => {
this.setState({showRemoveConfirmation: false});
hideConvertConfirmModal = () => {
this.setState({showConvertConfirmModal: false});
}
showRemoveUsersModal = () => {
if (this.state.usersToRemove > 0) {
this.setState({showRemoveConfirmation: true});
} else {
this.handleSubmit();

hideRemoveConfirmModal = () => {
this.setState({showRemoveConfirmModal: false});
}

hideConvertAndRemoveConfirmModal = () => {
this.setState({showConvertAndRemoveConfirmModal: false});
}

onSave = () => {
const {channel} = this.props;
const {isSynced, usersToRemove} = this.state;
let {isPublic, isPrivacyChanging} = this.state;
const isOriginallyPublic = (channel.type === Constants.OPEN_CHANNEL);

if (isSynced) {
isPublic = false;
isPrivacyChanging = isOriginallyPublic;
this.setState({
isPublic,
isPrivacyChanging,
});
if (this.state.groups.length === 0) {
return;
}
}

if (isPrivacyChanging && usersToRemove > 0) {
this.setState({showConvertAndRemoveConfirmModal: true});
return;
}

if (isPrivacyChanging && usersToRemove === 0) {
this.setState({showConvertConfirmModal: true});
return;
}

if (!isPrivacyChanging && usersToRemove > 0) {
this.setState({showRemoveConfirmModal: true});
return;
}

this.handleSubmit();
}

handleSubmit = async () => {
this.setState({showRemoveConfirmation: false, saving: true});
const {groups, isSynced, isPublic} = this.state;
this.setState({showConvertConfirmModal: false, showRemoveConfirmModal: false, showConvertAndRemoveConfirmModal: false, saving: true});
const {groups, isSynced, isPublic, isPrivacyChanging} = this.state;

let serverError = null;
let saveNeeded = false;
Expand All @@ -164,14 +209,24 @@ export default class ChannelDetails extends React.Component {
saveNeeded = true;
} else {
const promises = [];
if (!isPublic && channel.type === Constants.OPEN_CHANNEL) {
promises.push(actions.convertChannelToPrivate(channel.id));
if (isPrivacyChanging) {
const convert = actions.updateChannelPrivacy(channel.id, isPublic ? Constants.OPEN_CHANNEL : Constants.PRIVATE_CHANNEL);
promises.push(convert.then((res) => {
if (res && res.error) {
return res;
}
return actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
});
}));
} else {
promises.push(actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
}));
}
promises.push(actions.patchChannel(channel.id, {
...channel,
group_constrained: isSynced,
type: isPublic ? Constants.OPEN_CHANNEL : Constants.PRIVATE_CHANNEL,
}));

const unlink = origGroups.filter((g) => !groups.includes(g)).map((g) => actions.unlinkGroupSyncable(g.id, channelID, Groups.SYNCABLE_TYPE_CHANNEL));
const link = groups.filter((g) => !origGroups.includes(g)).map((g) => actions.linkGroupSyncable(g.id, channelID, Groups.SYNCABLE_TYPE_CHANNEL, {auto_add: true}));
const result = await Promise.all([...promises, ...unlink, ...link]);
Expand All @@ -188,10 +243,11 @@ export default class ChannelDetails extends React.Component {
}

render = () => {
const {totalGroups, saving, saveNeeded, serverError, isSynced, isPublic, groups, showRemoveConfirmation, usersToRemove} = this.state;
const {totalGroups, saving, saveNeeded, serverError, isSynced, isPublic, groups, showConvertConfirmModal, showRemoveConfirmModal, showConvertAndRemoveConfirmModal, usersToRemove} = this.state;
const {channel, team} = this.props;
const missingGroup = (og) => !groups.find((g) => g.id === og.id);
const removedGroups = this.props.groups.filter(missingGroup);

return (
<div className='wrapper--fixed'>
<div className='admin-console__header with-back'>
Expand All @@ -208,22 +264,39 @@ export default class ChannelDetails extends React.Component {
</div>
<div className='admin-console__wrapper'>
<div className='admin-console__content'>
<RemoveConfirmModal
amount={usersToRemove}
inChannel={false}
show={showRemoveConfirmation}
onCancel={this.hideRemoveUsersModal}
onConfirm={this.handleSubmit}
/>
<ChannelProfile
channel={channel}
team={team}
/>

<ConvertConfirmModal
show={showConvertConfirmModal}
onCancel={this.hideConvertConfirmModal}
onConfirm={this.handleSubmit}
displayName={channel.display_name || ''}
toPublic={isPublic}
/>

<RemoveConfirmModal
show={showRemoveConfirmModal}
onCancel={this.hideRemoveConfirmModal}
onConfirm={this.handleSubmit}
inChannel={true}
amount={usersToRemove}
/>

<ConvertAndRemoveConfirmModal
show={showConvertAndRemoveConfirmModal}
onCancel={this.hideConvertAndRemoveConfirmModal}
onConfirm={this.handleSubmit}
displayName={channel.display_name || ''}
toPublic={isPublic}
removeAmount={usersToRemove}
/>

<ChannelModes
isPublic={isPublic}
isSynced={isSynced}
isOriginallyPrivate={channel.type === Constants.PRIVATE_CHANNEL}
onToggle={this.setToggles}
/>

Expand All @@ -242,11 +315,10 @@ export default class ChannelDetails extends React.Component {
<SaveChangesPanel
saving={saving}
saveNeeded={saveNeeded}
onClick={this.showRemoveUsersModal}
onClick={this.onSave}
serverError={serverError}
cancelLink='/admin_console/user_management/channels'
/>

</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
const actions = {
getChannel: jest.fn().mockResolvedValue([]),
getTeam: jest.fn().mockResolvedValue([]),
convertChannelToPrivate: jest.fn(),
linkGroupSyncable: jest.fn(),
conver: jest.fn(),
patchChannel: jest.fn(),
setNavigationBlocked: jest.fn(),
unlinkGroupSyncable: jest.fn(),
getGroups: jest.fn().mockResolvedValue([]),
membersMinusGroupMembers: jest.fn(),
updateChannelPrivacy: jest.fn(),
};

let wrapper = shallow(
Expand Down
Loading