summaryrefslogtreecommitdiffstats
path: root/webapp
diff options
context:
space:
mode:
authorJoram Wilander <jwawilander@gmail.com>2016-07-06 08:23:24 -0400
committerGitHub <noreply@github.com>2016-07-06 08:23:24 -0400
commit5f7cb8cfbf879aa0b0d43a7b7068688368fda9fc (patch)
tree555f578f1346d0b18448176ce1dc2a4771f16c6a /webapp
parent19d452c74efb96f718079d5a268ca51a8983c4bd (diff)
downloadchat-5f7cb8cfbf879aa0b0d43a7b7068688368fda9fc.tar.gz
chat-5f7cb8cfbf879aa0b0d43a7b7068688368fda9fc.tar.bz2
chat-5f7cb8cfbf879aa0b0d43a7b7068688368fda9fc.zip
PLT-3346/PLT-3342/PLT-3360 EE: Add the ability to restrict channel management permissions (#3453)
* EE: Add the ability to restrict channel management permissions * Always allow last user in a channel to delete that channel
Diffstat (limited to 'webapp')
-rw-r--r--webapp/components/admin_console/policy_settings.jsx56
-rw-r--r--webapp/components/channel_header.jsx157
-rw-r--r--webapp/components/more_channels.jsx56
-rw-r--r--webapp/components/navbar_dropdown.jsx4
-rw-r--r--webapp/components/new_channel_modal.jsx65
-rw-r--r--webapp/components/sidebar.jsx77
-rw-r--r--webapp/components/sidebar_right_menu.jsx4
-rw-r--r--webapp/components/tutorial/tutorial_intro_screens.jsx2
-rw-r--r--webapp/i18n/en.json12
-rw-r--r--webapp/stores/channel_store.jsx43
-rw-r--r--webapp/utils/channel_intro_messages.jsx4
-rw-r--r--webapp/utils/constants.jsx6
12 files changed, 350 insertions, 136 deletions
diff --git a/webapp/components/admin_console/policy_settings.jsx b/webapp/components/admin_console/policy_settings.jsx
index 7fe8e9460..c7031af7b 100644
--- a/webapp/components/admin_console/policy_settings.jsx
+++ b/webapp/components/admin_console/policy_settings.jsx
@@ -21,12 +21,16 @@ export default class PolicySettings extends AdminSettings {
this.renderSettings = this.renderSettings.bind(this);
this.state = Object.assign(this.state, {
- restrictTeamInvite: props.config.TeamSettings.RestrictTeamInvite
+ restrictTeamInvite: props.config.TeamSettings.RestrictTeamInvite,
+ restrictPublicChannelManagement: props.config.TeamSettings.RestrictPublicChannelManagement,
+ restrictPrivateChannelManagement: props.config.TeamSettings.RestrictPrivateChannelManagement
});
}
getConfigFromState(config) {
config.TeamSettings.RestrictTeamInvite = this.state.restrictTeamInvite;
+ config.TeamSettings.RestrictPublicChannelManagement = this.state.restrictPublicChannelManagement;
+ config.TeamSettings.RestrictPrivateChannelManagement = this.state.restrictPrivateChannelManagement;
return config;
}
@@ -48,9 +52,9 @@ export default class PolicySettings extends AdminSettings {
<DropdownSetting
id='restrictTeamInvite'
values={[
- {value: Constants.TEAM_INVITE_ALL, text: Utils.localizeMessage('admin.general.policy.teamInviteAll', 'All team members')},
- {value: Constants.TEAM_INVITE_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.teamInviteAdmin', 'Team and System Admins')},
- {value: Constants.TEAM_INVITE_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.teamInviteSystemAdmin', 'System Admins')}
+ {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
+ {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
+ {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
]}
label={
<FormattedMessage
@@ -67,6 +71,50 @@ export default class PolicySettings extends AdminSettings {
/>
}
/>
+ <DropdownSetting
+ id='restrictPublicChannelManagement'
+ values={[
+ {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
+ {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
+ {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
+ ]}
+ label={
+ <FormattedMessage
+ id='admin.general.policy.restrictPublicChannelManagementTitle'
+ defaultMessage='Enable public channel management permissions for:'
+ />
+ }
+ value={this.state.restrictPublicChannelManagement}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedHTMLMessage
+ id='admin.general.policy.restrictPublicChannelManagementDescription'
+ defaultMessage='Selecting "All team members" allows any team members to create, delete, rename, and set the header or purpose for public channels.<br/><br/>Selecting "Team and System Admins" restricts channel management permissions for public channels to Team and System Admins, including creating, deleting, renaming, and setting the channel header or purpose.<br/><br/>Selecting "System Admins" restricts channel management permissions for public channels to System Admins, including creating, deleting, renaming, and setting the channel header or purpose.'
+ />
+ }
+ />
+ <DropdownSetting
+ id='restrictPrivateChannelManagement'
+ values={[
+ {value: Constants.PERMISSIONS_ALL, text: Utils.localizeMessage('admin.general.policy.permissionsAll', 'All team members')},
+ {value: Constants.PERMISSIONS_TEAM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsAdmin', 'Team and System Admins')},
+ {value: Constants.PERMISSIONS_SYSTEM_ADMIN, text: Utils.localizeMessage('admin.general.policy.permissionsSystemAdmin', 'System Admins')}
+ ]}
+ label={
+ <FormattedMessage
+ id='admin.general.policy.restrictPrivateChannelManagementTitle'
+ defaultMessage='Enable private group management permissions for:'
+ />
+ }
+ value={this.state.restrictPrivateChannelManagement}
+ onChange={this.handleChange}
+ helpText={
+ <FormattedHTMLMessage
+ id='admin.general.policy.restrictPrivateChannelManagementDescription'
+ defaultMessage='Selecting "All team members" allows any team members to create, delete, rename, and set the header or purpose for private groups.<br/><br/>Selecting "Team and System Admins" restricts group management permissions for private groups to Team and System Admins, including creating, deleting, renaming, and setting the group header or purpose.<br/><br/>Selecting "System Admins" restricts group management permissions for private groups to System Admins, including creating, deleting, renaming, and setting the group header or purpose.'
+ />
+ }
+ />
</SettingsGroup>
);
}
diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx
index 3449a0fd6..2b9b1e1cc 100644
--- a/webapp/components/channel_header.jsx
+++ b/webapp/components/channel_header.jsx
@@ -56,6 +56,7 @@ export default class ChannelHeader extends React.Component {
state.showRenameChannelModal = false;
this.state = state;
}
+
getStateFromStores() {
const extraInfo = ChannelStore.getExtraInfo(this.props.channelId);
@@ -67,6 +68,7 @@ export default class ChannelHeader extends React.Component {
currentUser: UserStore.getCurrentUser()
};
}
+
validState() {
if (!this.state.channel ||
!this.state.memberChannel ||
@@ -77,6 +79,7 @@ export default class ChannelHeader extends React.Component {
}
return true;
}
+
componentDidMount() {
ChannelStore.addChangeListener(this.onListenerChange);
ChannelStore.addExtraInfoChangeListener(this.onListenerChange);
@@ -87,6 +90,7 @@ export default class ChannelHeader extends React.Component {
$('.sidebar--left .dropdown-menu').perfectScrollbar();
document.addEventListener('keydown', this.openRecentMentions);
}
+
componentWillUnmount() {
ChannelStore.removeChangeListener(this.onListenerChange);
ChannelStore.removeExtraInfoChangeListener(this.onListenerChange);
@@ -96,6 +100,7 @@ export default class ChannelHeader extends React.Component {
UserStore.removeStatusesChangeListener(this.onListenerChange);
document.removeEventListener('keydown', this.openRecentMentions);
}
+
onListenerChange() {
const newState = this.getStateFromStores();
if (!Utils.areObjectsEqual(newState, this.state)) {
@@ -103,6 +108,7 @@ export default class ChannelHeader extends React.Component {
}
$('.channel-header__info .description').popover({placement: 'bottom', trigger: 'hover', html: true, delay: {show: 500, hide: 500}});
}
+
handleLeave() {
Client.leaveChannel(this.state.channel.id,
() => {
@@ -119,6 +125,7 @@ export default class ChannelHeader extends React.Component {
}
);
}
+
searchMentions(e) {
e.preventDefault();
@@ -146,12 +153,14 @@ export default class ChannelHeader extends React.Component {
is_mention_search: true
});
}
+
openRecentMentions(e) {
if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.keyCode === Constants.KeyCodes.M) {
e.preventDefault();
this.searchMentions(e);
}
}
+
showRenameChannelModal(e) {
e.preventDefault();
@@ -159,6 +168,7 @@ export default class ChannelHeader extends React.Component {
showRenameChannelModal: true
});
}
+
hideRenameChannelModal() {
this.setState({
showRenameChannelModal: false
@@ -179,6 +189,30 @@ export default class ChannelHeader extends React.Component {
return null;
}
+ showManagementOptions(channel, isAdmin, isSystemAdmin) {
+ if (global.window.mm_license.IsLicensed !== 'true') {
+ return true;
+ }
+
+ if (channel.type === Constants.OPEN_CHANNEL) {
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ return false;
+ }
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ return false;
+ }
+ } else if (channel.type === Constants.PRIVATE_CHANNEL) {
+ if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ return false;
+ }
+ if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
render() {
if (!this.validState()) {
return null;
@@ -210,7 +244,8 @@ export default class ChannelHeader extends React.Component {
);
let channelTitle = channel.display_name;
const currentId = this.state.currentUser.id;
- const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
const isDirect = (this.state.channel.type === 'D');
if (isDirect) {
@@ -331,67 +366,90 @@ export default class ChannelHeader extends React.Component {
dropdownContents.push(
<li
- key='set_channel_header'
+ key='notification_preferences'
role='presentation'
>
<ToggleModalButton
role='menuitem'
- dialogType={EditChannelHeaderModal}
- dialogProps={{channel}}
+ dialogType={ChannelNotificationsModal}
+ dialogProps={{
+ channel,
+ channelMember: this.state.memberChannel,
+ currentUser: this.state.currentUser
+ }}
>
<FormattedMessage
- id='channel_header.setHeader'
- defaultMessage='Set {term} Header...'
- values={{
- term: (channelTerm)
- }}
+ id='channel_header.notificationPreferences'
+ defaultMessage='Notification Preferences'
/>
</ToggleModalButton>
</li>
);
- dropdownContents.push(
+
+ const deleteOption = (
<li
- key='set_channel_purpose'
+ key='delete_channel'
role='presentation'
>
- <a
+ <ToggleModalButton
role='menuitem'
- href='#'
- onClick={() => this.setState({showEditChannelPurposeModal: true})}
+ dialogType={DeleteChannelModal}
+ dialogProps={{channel}}
>
<FormattedMessage
- id='channel_header.setPurpose'
- defaultMessage='Set {term} Purpose...'
+ id='channel_header.delete'
+ defaultMessage='Delete {term}...'
values={{
term: (channelTerm)
}}
/>
- </a>
- </li>
- );
- dropdownContents.push(
- <li
- key='notification_preferences'
- role='presentation'
- >
- <ToggleModalButton
- role='menuitem'
- dialogType={ChannelNotificationsModal}
- dialogProps={{
- channel,
- channelMember: this.state.memberChannel,
- currentUser: this.state.currentUser
- }}
- >
- <FormattedMessage
- id='channel_header.notificationPreferences'
- defaultMessage='Notification Preferences'
- />
</ToggleModalButton>
</li>
);
- if (isAdmin) {
+ if (this.showManagementOptions(channel, isAdmin, isSystemAdmin)) {
+ dropdownContents.push(
+ <li
+ key='set_channel_header'
+ role='presentation'
+ >
+ <ToggleModalButton
+ role='menuitem'
+ dialogType={EditChannelHeaderModal}
+ dialogProps={{channel}}
+ >
+ <FormattedMessage
+ id='channel_header.setHeader'
+ defaultMessage='Set {term} Header...'
+ values={{
+ term: (channelTerm)
+ }}
+ />
+ </ToggleModalButton>
+ </li>
+ );
+
+ dropdownContents.push(
+ <li
+ key='set_channel_purpose'
+ role='presentation'
+ >
+ <a
+ role='menuitem'
+ href='#'
+ onClick={() => this.setState({showEditChannelPurposeModal: true})}
+ >
+ <FormattedMessage
+ id='channel_header.setPurpose'
+ defaultMessage='Set {term} Purpose...'
+ values={{
+ term: (channelTerm)
+ }}
+ />
+ </a>
+ </li>
+ );
+
dropdownContents.push(
<li
key='rename_channel'
@@ -414,27 +472,10 @@ export default class ChannelHeader extends React.Component {
);
if (!ChannelStore.isDefault(channel)) {
- dropdownContents.push(
- <li
- key='delete_channel'
- role='presentation'
- >
- <ToggleModalButton
- role='menuitem'
- dialogType={DeleteChannelModal}
- dialogProps={{channel}}
- >
- <FormattedMessage
- id='channel_header.delete'
- defaultMessage='Delete {term}...'
- values={{
- term: (channelTerm)
- }}
- />
- </ToggleModalButton>
- </li>
- );
+ dropdownContents.push(deleteOption);
}
+ } else if (this.state.userCount === 1) {
+ dropdownContents.push(deleteOption);
}
const canLeave = channel.type === Constants.PRIVATE_CHANNEL ? this.state.userCount > 1 : true;
diff --git a/webapp/components/more_channels.jsx b/webapp/components/more_channels.jsx
index 54a06d0ae..b7ffff712 100644
--- a/webapp/components/more_channels.jsx
+++ b/webapp/components/more_channels.jsx
@@ -6,8 +6,11 @@ import LoadingScreen from './loading_screen.jsx';
import NewChannelFlow from './new_channel_flow.jsx';
import ChannelStore from 'stores/channel_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
import * as Utils from 'utils/utils.jsx';
+import Constants from 'utils/constants.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'actions/global_actions.jsx';
@@ -132,6 +135,41 @@ export default class MoreChannels extends React.Component {
serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
}
+ let createNewChannelButton = (
+ <button
+ type='button'
+ className='btn btn-primary channel-create-btn'
+ onClick={this.handleNewChannel}
+ >
+ <FormattedMessage
+ id='more_channels.create'
+ defaultMessage='Create New Channel'
+ />
+ </button>
+ );
+
+ let createChannelHelpText = (
+ <p className='secondary-message'>
+ <FormattedMessage
+ id='more_channels.createClick'
+ defaultMessage="Click 'Create New Channel' to make a new one"
+ />
+ </p>
+ );
+
+ const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createNewChannelButton = null;
+ createChannelHelpText = null;
+ } else if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createNewChannelButton = null;
+ createChannelHelpText = null;
+ }
+ }
+
var moreChannels;
if (this.state.channels != null) {
@@ -153,12 +191,7 @@ export default class MoreChannels extends React.Component {
defaultMessage='No more channels to join'
/>
</p>
- <p className='secondary-message'>
- <FormattedMessage
- id='more_channels.createClick'
- defaultMessage="Click 'Create New Channel' to make a new one"
- />
- </p>
+ {createChannelHelpText}
</div>
);
}
@@ -195,16 +228,7 @@ export default class MoreChannels extends React.Component {
defaultMessage='More Channels'
/>
</h4>
- <button
- type='button'
- className='btn btn-primary channel-create-btn'
- onClick={this.handleNewChannel}
- >
- <FormattedMessage
- id='more_channels.create'
- defaultMessage='Create New Channel'
- />
- </button>
+ {createNewChannelButton}
<NewChannelFlow
show={this.state.showNewChannelModal}
channelType={this.state.channelType}
diff --git a/webapp/components/navbar_dropdown.jsx b/webapp/components/navbar_dropdown.jsx
index 4f137979e..bc7aaeb5f 100644
--- a/webapp/components/navbar_dropdown.jsx
+++ b/webapp/components/navbar_dropdown.jsx
@@ -122,10 +122,10 @@ export default class NavbarDropdown extends React.Component {
}
if (global.window.mm_license.IsLicensed === 'true') {
- if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
teamLink = null;
inviteLink = null;
- } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
teamLink = null;
inviteLink = null;
}
diff --git a/webapp/components/new_channel_modal.jsx b/webapp/components/new_channel_modal.jsx
index 9fd76395c..23eee625d 100644
--- a/webapp/components/new_channel_modal.jsx
+++ b/webapp/components/new_channel_modal.jsx
@@ -3,8 +3,12 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
+
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
+
+import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
@@ -113,6 +117,47 @@ class NewChannelModal extends React.Component {
serverError = <div className='form-group has-error'><p className='input__help error'>{this.props.serverError}</p></div>;
}
+ let createPublicChannelLink = (
+ <a
+ href='#'
+ onClick={this.props.onTypeSwitched}
+ >
+ <FormattedMessage
+ id='channel_modal.publicChannel1'
+ defaultMessage='Create a public channel'
+ />
+ </a>
+ );
+
+ let createPrivateChannelLink = (
+ <a
+ href='#'
+ onClick={this.props.onTypeSwitched}
+ >
+ <FormattedMessage
+ id='channel_modal.privateGroup2'
+ defaultMessage='Create a private group'
+ />
+ </a>
+ );
+
+ const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createPublicChannelLink = null;
+ } else if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createPublicChannelLink = null;
+ }
+
+ if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createPrivateChannelLink = null;
+ } else if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createPrivateChannelLink = null;
+ }
+ }
+
var channelTerm = '';
var channelSwitchText = '';
switch (this.props.channelType) {
@@ -129,15 +174,7 @@ class NewChannelModal extends React.Component {
id='channel_modal.privateGroup1'
defaultMessage='Create a new private group with restricted membership. '
/>
- <a
- href='#'
- onClick={this.props.onTypeSwitched}
- >
- <FormattedMessage
- id='channel_modal.publicChannel1'
- defaultMessage='Create a public channel'
- />
- </a>
+ {createPublicChannelLink}
</div>
);
break;
@@ -154,15 +191,7 @@ class NewChannelModal extends React.Component {
id='channel_modal.publicChannel2'
defaultMessage='Create a new public channel anyone can join. '
/>
- <a
- href='#'
- onClick={this.props.onTypeSwitched}
- >
- <FormattedMessage
- id='channel_modal.privateGroup2'
- defaultMessage='Create a private group'
- />
- </a>
+ {createPrivateChannelLink}
</div>
);
break;
diff --git a/webapp/components/sidebar.jsx b/webapp/components/sidebar.jsx
index 4f678274d..fdcae1dff 100644
--- a/webapp/components/sidebar.jsx
+++ b/webapp/components/sidebar.jsx
@@ -682,6 +682,55 @@ export default class Sidebar extends React.Component {
/>
);
+ const isAdmin = TeamStore.isTeamAdminForCurrentTeam() || UserStore.isSystemAdminForCurrentUser();
+ const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
+
+ let createPublicChannelIcon = (
+ <OverlayTrigger
+ delayShow={500}
+ placement='top'
+ overlay={createChannelTootlip}
+ >
+ <a
+ className='add-channel-btn'
+ href='#'
+ onClick={this.showNewChannelModal.bind(this, Constants.OPEN_CHANNEL)}
+ >
+ {'+'}
+ </a>
+ </OverlayTrigger>
+ );
+
+ let createPrivateChannelIcon = (
+ <OverlayTrigger
+ delayShow={500}
+ placement='top'
+ overlay={createGroupTootlip}
+ >
+ <a
+ className='add-channel-btn'
+ href='#'
+ onClick={this.showNewChannelModal.bind(this, Constants.PRIVATE_CHANNEL)}
+ >
+ {'+'}
+ </a>
+ </OverlayTrigger>
+ );
+
+ if (global.window.mm_license.IsLicensed === 'true') {
+ if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createPublicChannelIcon = null;
+ } else if (global.window.mm_config.RestrictPublicChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createPublicChannelIcon = null;
+ }
+
+ if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
+ createPrivateChannelIcon = null;
+ } else if (global.window.mm_config.RestrictPrivateChannelManagement === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
+ createPrivateChannelIcon = null;
+ }
+ }
+
return (
<div
className='sidebar--left'
@@ -728,19 +777,7 @@ export default class Sidebar extends React.Component {
id='sidebar.channels'
defaultMessage='Channels'
/>
- <OverlayTrigger
- delayShow={500}
- placement='top'
- overlay={createChannelTootlip}
- >
- <a
- className='add-channel-btn'
- href='#'
- onClick={this.showNewChannelModal.bind(this, 'O')}
- >
- {'+'}
- </a>
- </OverlayTrigger>
+ {createPublicChannelIcon}
</h4>
</li>
{publicChannelItems}
@@ -765,19 +802,7 @@ export default class Sidebar extends React.Component {
id='sidebar.pg'
defaultMessage='Private Groups'
/>
- <OverlayTrigger
- delayShow={500}
- placement='top'
- overlay={createGroupTootlip}
- >
- <a
- className='add-channel-btn'
- href='#'
- onClick={this.showNewChannelModal.bind(this, 'P')}
- >
- {'+'}
- </a>
- </OverlayTrigger>
+ {createPrivateChannelIcon}
</h4>
</li>
{privateChannelItems}
diff --git a/webapp/components/sidebar_right_menu.jsx b/webapp/components/sidebar_right_menu.jsx
index 2cf758f00..25136e8bc 100644
--- a/webapp/components/sidebar_right_menu.jsx
+++ b/webapp/components/sidebar_right_menu.jsx
@@ -186,10 +186,10 @@ export default class SidebarRightMenu extends React.Component {
}
if (global.window.mm_license.IsLicensed === 'true') {
- if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
teamLink = null;
inviteLink = null;
- } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
teamLink = null;
inviteLink = null;
}
diff --git a/webapp/components/tutorial/tutorial_intro_screens.jsx b/webapp/components/tutorial/tutorial_intro_screens.jsx
index b0d831d96..639fa07b2 100644
--- a/webapp/components/tutorial/tutorial_intro_screens.jsx
+++ b/webapp/components/tutorial/tutorial_intro_screens.jsx
@@ -108,7 +108,7 @@ export default class TutorialIntroScreens extends React.Component {
let inviteModalLink;
let inviteText;
- if (global.window.mm_license.IsLicensed !== 'true' || global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_ALL) {
+ if (global.window.mm_license.IsLicensed !== 'true' || global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_ALL) {
if (team.type === Constants.INVITE_TEAM) {
inviteModalLink = (
<a
diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json
index 26b1b47fd..a723b68c7 100644
--- a/webapp/i18n/en.json
+++ b/webapp/i18n/en.json
@@ -233,11 +233,15 @@
"admin.general.localization.serverLocaleTitle": "Default Server Language:",
"admin.general.log": "Logging",
"admin.general.policy": "Policy",
- "admin.general.policy.teamInviteAdmin": "Team and System Admins",
- "admin.general.policy.teamInviteAll": "All team members",
- "admin.general.policy.teamInviteDescription": "Selecting \"All team members\" allows any team member to invite others using an email invitation or team invite link.<br/><br/>Selecting \"Team and System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not Team or System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.<br/><br/>Selecting \"System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.",
- "admin.general.policy.teamInviteSystemAdmin": "System Admins",
+ "admin.general.policy.permissionsAll": "All team members",
+ "admin.general.policy.permissionsAdmin": "Team and System Admins",
+ "admin.general.policy.permissionsSystemAdmin": "System Admins",
"admin.general.policy.teamInviteTitle": "Enable sending team invites from:",
+ "admin.general.policy.teamInviteDescription": "Selecting \"All team members\" allows any team member to invite others using an email invitation or team invite link.<br/><br/>Selecting \"Team and System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not Team or System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.<br/><br/>Selecting \"System Admins\" hides the email invitation and team invite link in the Main Menu from users who are not System Admins. Note: If \"Get Team Invite Link\" is used to share a link, it will need to be regenerated after the desired users joined the team.",
+ "admin.general.policy.restrictPublicChannelManagementTitle": "Enable public channel management permissions for:",
+ "admin.general.policy.restrictPublicChannelManagementDescription": "Selecting \"All team members\" allows any team members to create, delete, rename, and set the header or purpose for public channels.<br/><br/>Selecting \"Team and System Admins\" restricts channel management permissions for public channels to Team and System Admins, including creating, deleting, renaming, and setting the channel header or purpose.<br/><br/>Selecting \"System Admins\" restricts channel management permissions for public channels to System Admins, including creating, deleting, renaming, and setting the channel header or purpose.",
+ "admin.general.policy.restrictPrivateChannelManagementTitle": "Enable private group management permissions for:",
+ "admin.general.policy.restrictPrivateChannelManagementDescription": "Selecting \"All team members\" allows any team members to create, delete, rename, and set the header or purpose for private groups.<br/><br/>Selecting \"Team and System Admins\" restricts group management permissions for private groups to Team and System Admins, including creating, deleting, renaming, and setting the group header or purpose.<br/><br/>Selecting \"System Admins\" restricts group management permissions for private groups to System Admins, including creating, deleting, renaming, and setting the group header or purpose.",
"admin.general.privacy": "Privacy",
"admin.general.usersAndTeams": "Users and Teams",
"admin.gitab.clientSecretDescription": "Obtain this value via the instructions above for logging into GitLab.",
diff --git a/webapp/stores/channel_store.jsx b/webapp/stores/channel_store.jsx
index b65ec330c..dc2577811 100644
--- a/webapp/stores/channel_store.jsx
+++ b/webapp/stores/channel_store.jsx
@@ -53,54 +53,70 @@ class ChannelStoreClass extends EventEmitter {
this.extraInfos = {};
this.unreadCounts = {};
}
+
get POST_MODE_CHANNEL() {
return 1;
}
+
get POST_MODE_FOCUS() {
return 2;
}
+
emitChange() {
this.emit(CHANGE_EVENT);
}
+
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
}
+
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
}
+
emitMoreChange() {
this.emit(MORE_CHANGE_EVENT);
}
+
addMoreChangeListener(callback) {
this.on(MORE_CHANGE_EVENT, callback);
}
+
removeMoreChangeListener(callback) {
this.removeListener(MORE_CHANGE_EVENT, callback);
}
+
emitExtraInfoChange() {
this.emit(EXTRA_INFO_EVENT);
}
+
addExtraInfoChangeListener(callback) {
this.on(EXTRA_INFO_EVENT, callback);
}
+
removeExtraInfoChangeListener(callback) {
this.removeListener(EXTRA_INFO_EVENT, callback);
}
emitLeave(id) {
this.emit(LEAVE_EVENT, id);
}
+
addLeaveListener(callback) {
this.on(LEAVE_EVENT, callback);
}
+
removeLeaveListener(callback) {
this.removeListener(LEAVE_EVENT, callback);
}
+
findFirstBy(field, value) {
return this.doFindFirst(field, value, this.getChannels());
}
+
findFirstMoreBy(field, value) {
return this.doFindFirst(field, value, this.getMoreChannels());
}
+
doFindFirst(field, value, channels) {
for (var i = 0; i < channels.length; i++) {
if (channels[i][field] === value) {
@@ -110,33 +126,43 @@ class ChannelStoreClass extends EventEmitter {
return null;
}
+
get(id) {
return this.findFirstBy('id', id);
}
+
getMember(id) {
return this.getAllMembers()[id];
}
+
getByName(name) {
return this.findFirstBy('name', name);
}
+
getByDisplayName(displayName) {
return this.findFirstBy('display_name', displayName);
}
+
getMoreByName(name) {
return this.findFirstMoreBy('name', name);
}
+
getAll() {
return this.getChannels();
}
+
getAllMembers() {
return this.getChannelMembers();
}
+
getMoreAll() {
return this.getMoreChannels();
}
+
setCurrentId(id) {
this.currentId = id;
}
+
resetCounts(id) {
const cm = this.channelMembers;
for (var cmid in cm) {
@@ -151,9 +177,11 @@ class ChannelStoreClass extends EventEmitter {
}
}
}
+
getCurrentId() {
return this.currentId;
}
+
getCurrent() {
var currentId = this.getCurrentId();
@@ -163,6 +191,7 @@ class ChannelStoreClass extends EventEmitter {
return null;
}
+
getCurrentMember() {
var currentId = this.getCurrentId();
@@ -172,15 +201,18 @@ class ChannelStoreClass extends EventEmitter {
return null;
}
+
setChannelMember(member) {
var members = this.getChannelMembers();
members[member.channel_id] = member;
this.storeChannelMembers(members);
this.emitChange();
}
+
getCurrentExtraInfo() {
return this.getExtraInfo(this.getCurrentId());
}
+
getExtraInfo(channelId) {
var extra = null;
@@ -197,6 +229,7 @@ class ChannelStoreClass extends EventEmitter {
return extra;
}
+
pStoreChannel(channel) {
var channels = this.getChannels();
var found;
@@ -220,35 +253,45 @@ class ChannelStoreClass extends EventEmitter {
channels.sort(Utils.sortByDisplayName);
this.storeChannels(channels);
}
+
storeChannels(channels) {
this.channels = channels;
}
+
getChannels() {
return this.channels;
}
+
pStoreChannelMember(channelMember) {
var members = this.getChannelMembers();
members[channelMember.channel_id] = channelMember;
this.storeChannelMembers(members);
}
+
storeChannelMembers(channelMembers) {
this.channelMembers = channelMembers;
}
+
getChannelMembers() {
return this.channelMembers;
}
+
storeMoreChannels(channels) {
this.moreChannels = channels;
}
+
getMoreChannels() {
return this.moreChannels;
}
+
storeExtraInfos(extraInfos) {
this.extraInfos = extraInfos;
}
+
getExtraInfos() {
return this.extraInfos;
}
+
isDefault(channel) {
return channel.name === Constants.DEFAULT_CHANNEL;
}
diff --git a/webapp/utils/channel_intro_messages.jsx b/webapp/utils/channel_intro_messages.jsx
index 043894b7b..50d12ed42 100644
--- a/webapp/utils/channel_intro_messages.jsx
+++ b/webapp/utils/channel_intro_messages.jsx
@@ -114,9 +114,9 @@ export function createDefaultIntroMessage(channel) {
const isSystemAdmin = UserStore.isSystemAdminForCurrentUser();
if (global.window.mm_license.IsLicensed === 'true') {
- if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_SYSTEM_ADMIN && !isSystemAdmin) {
+ if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_SYSTEM_ADMIN && !isSystemAdmin) {
inviteModalLink = null;
- } else if (global.window.mm_config.RestrictTeamInvite === Constants.TEAM_INVITE_TEAM_ADMIN && !isAdmin) {
+ } else if (global.window.mm_config.RestrictTeamInvite === Constants.PERMISSIONS_TEAM_ADMIN && !isAdmin) {
inviteModalLink = null;
}
}
diff --git a/webapp/utils/constants.jsx b/webapp/utils/constants.jsx
index 1b0fa6374..0191edcf0 100644
--- a/webapp/utils/constants.jsx
+++ b/webapp/utils/constants.jsx
@@ -762,7 +762,7 @@ export default {
POST_COLLAPSE_TIMEOUT: 1000 * 60 * 5, // five minutes
LICENSE_EXPIRY_NOTIFICATION: 1000 * 60 * 60 * 24 * 15, // 15 days
LICENSE_GRACE_PERIOD: 1000 * 60 * 60 * 24 * 15, // 15 days
- TEAM_INVITE_ALL: 'all',
- TEAM_INVITE_TEAM_ADMIN: 'team_admin',
- TEAM_INVITE_SYSTEM_ADMIN: 'system_admin'
+ PERMISSIONS_ALL: 'all',
+ PERMISSIONS_TEAM_ADMIN: 'team_admin',
+ PERMISSIONS_SYSTEM_ADMIN: 'system_admin'
};