PLT-4167 Team Sidebar (#4569)
* PLT-4167 Team Sidebar * Address feedback from PM * change route from my_members to members * bug fixes * Updating styles for teams sidebar (#4681) * Added PM changes * Fix corner cases * Addressing feedback * use two different endpoints * Bug fixes * Rename model and client functions, using preferences to store last team and channel viewed * Fix mobile notification count and closing the team sidebar * unit test, fixed bad merge and retrieve from cached when available * bug fixes * use id for last channel in preferences, query optimization * Updating multi team css (#4830)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
3ce2ce9dc8
Коммит
999d1553e1
@@ -50,13 +50,14 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
var teams = [];
|
||||
const teams = [];
|
||||
let switchTeams;
|
||||
|
||||
if (this.state.teamMembers && this.state.teamMembers.length > 0) {
|
||||
for (var index in this.state.teamMembers) {
|
||||
for (const index in this.state.teamMembers) {
|
||||
if (this.state.teamMembers.hasOwnProperty(index)) {
|
||||
var teamMember = this.state.teamMembers[index];
|
||||
var team = this.state.teams[teamMember.team_id];
|
||||
const teamMember = this.state.teamMembers[index];
|
||||
const team = this.state.teams[teamMember.team_id];
|
||||
teams.push(
|
||||
<li key={'team_' + team.name}>
|
||||
<Link
|
||||
@@ -79,6 +80,20 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
className='divider'
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
switchTeams = (
|
||||
<li>
|
||||
<Link
|
||||
to={'/select_team'}
|
||||
>
|
||||
<i className='fa fa-exchange'/>
|
||||
<FormattedMessage
|
||||
id='admin.nav.switch'
|
||||
defaultMessage='Team Selection'
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -104,17 +119,7 @@ export default class AdminNavbarDropdown extends React.Component {
|
||||
role='menu'
|
||||
>
|
||||
{teams}
|
||||
<li>
|
||||
<Link
|
||||
to={'/select_team'}
|
||||
>
|
||||
<i className='fa fa-exchange'/>
|
||||
<FormattedMessage
|
||||
id='admin.nav.switch'
|
||||
defaultMessage='Team Selection'
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
{switchTeams}
|
||||
<li
|
||||
key='teamDiv'
|
||||
className='divider'
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory, Link} from 'react-router/es6';
|
||||
@@ -47,11 +49,21 @@ export default class CreateTeamController extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let url = '/select_team';
|
||||
const team = TeamStore.getCurrent();
|
||||
const channel = ChannelStore.getCurrent();
|
||||
if (team) {
|
||||
url = `/${team.name}`;
|
||||
if (channel) {
|
||||
url += `/channels/${channel.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<div className='signup-header'>
|
||||
<Link to='/select_team'>
|
||||
<Link to={url}>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='web.header.back'
|
||||
|
||||
@@ -54,7 +54,7 @@ export default class LoginController extends React.Component {
|
||||
document.title = global.window.mm_config.SiteName;
|
||||
|
||||
if (UserStore.getCurrentUser()) {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
|
||||
AsyncClient.checkVersion();
|
||||
@@ -205,7 +205,7 @@ export default class LoginController extends React.Component {
|
||||
} else if (team) {
|
||||
browserHistory.push(`/${team.name}`);
|
||||
} else {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -146,6 +146,7 @@ export default class Navbar extends React.Component {
|
||||
if (e.target.className !== 'navbar-toggle' && e.target.className !== 'icon-bar') {
|
||||
$('.app__body .inner-wrap').removeClass('move--right move--left move--left-small');
|
||||
$('.app__body .sidebar--left').removeClass('move--right');
|
||||
$('.multi-teams .team-sidebar').removeClass('move--right');
|
||||
$('.app__body .sidebar--right').removeClass('move--left');
|
||||
$('.app__body .sidebar--menu').removeClass('move--left');
|
||||
}
|
||||
@@ -155,6 +156,7 @@ export default class Navbar extends React.Component {
|
||||
toggleLeftSidebar() {
|
||||
$('.app__body .inner-wrap').toggleClass('move--right');
|
||||
$('.app__body .sidebar--left').toggleClass('move--right');
|
||||
$('.multi-teams .team-sidebar').toggleClass('move--right');
|
||||
}
|
||||
|
||||
toggleRightSidebar() {
|
||||
|
||||
@@ -141,6 +141,7 @@ export default class NeedsTeam extends React.Component {
|
||||
content.push(
|
||||
this.props.navbar
|
||||
);
|
||||
content.push(this.props.team_sidebar);
|
||||
content.push(
|
||||
this.props.sidebar
|
||||
);
|
||||
@@ -197,6 +198,7 @@ NeedsTeam.propTypes = {
|
||||
]),
|
||||
navbar: React.PropTypes.element,
|
||||
sidebar: React.PropTypes.element,
|
||||
team_sidebar: React.PropTypes.element,
|
||||
center: React.PropTypes.element,
|
||||
params: React.PropTypes.object,
|
||||
user: React.PropTypes.object
|
||||
|
||||
@@ -3,14 +3,22 @@
|
||||
|
||||
import * as utils from 'utils/utils.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
function getCountsStateFromStores() {
|
||||
var count = 0;
|
||||
var channels = ChannelStore.getAll();
|
||||
var members = ChannelStore.getMyMembers();
|
||||
let count = 0;
|
||||
const teamMembers = TeamStore.getMyTeamMembers();
|
||||
const channels = ChannelStore.getAll();
|
||||
const members = ChannelStore.getMyMembers();
|
||||
|
||||
teamMembers.forEach((member) => {
|
||||
if (member.team_id !== TeamStore.getCurrentId()) {
|
||||
count += ((member.msg_count || 0) + (member.mention_count || 0));
|
||||
}
|
||||
});
|
||||
|
||||
channels.forEach((channel) => {
|
||||
var channelMember = members[channel.id];
|
||||
const channelMember = members[channel.id];
|
||||
if (channelMember == null) {
|
||||
return;
|
||||
}
|
||||
@@ -41,10 +49,12 @@ export default class NotifyCounts extends React.Component {
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
ChannelStore.addChangeListener(this.onListenerChange);
|
||||
TeamStore.addChangeListener(this.onListenerChange);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
ChannelStore.removeChangeListener(this.onListenerChange);
|
||||
TeamStore.removeChangeListener(this.onListenerChange);
|
||||
}
|
||||
onListenerChange() {
|
||||
if (this.mounted) {
|
||||
|
||||
@@ -50,7 +50,7 @@ export default class Root extends React.Component {
|
||||
if (UserStore.getNoAccounts()) {
|
||||
browserHistory.push('/signup_user_complete');
|
||||
} else if (UserStore.getCurrentUser()) {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
} else {
|
||||
browserHistory.push('/login');
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export default class SelectTeam extends React.Component {
|
||||
super(props);
|
||||
this.onTeamChange = this.onTeamChange.bind(this);
|
||||
this.handleTeamClick = this.handleTeamClick.bind(this);
|
||||
this.teamContentsCompare = this.teamContentsCompare.bind(this);
|
||||
|
||||
const state = this.getStateFromStores(false);
|
||||
state.loadingTeamId = '';
|
||||
@@ -61,33 +62,15 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let content = null;
|
||||
let teamContents = [];
|
||||
let openTeamContents = [];
|
||||
const isAlreadyMember = new Map();
|
||||
const isSystemAdmin = Utils.isSystemAdmin(UserStore.getCurrentUser().roles);
|
||||
let teamMembersCount = 0;
|
||||
|
||||
for (const teamMember of this.state.teamMembers) {
|
||||
const teamId = teamMember.team_id;
|
||||
const team = this.state.teams[teamId];
|
||||
isAlreadyMember[teamId] = true;
|
||||
teamMembersCount++;
|
||||
|
||||
teamContents.push(
|
||||
<SelectTeamItem
|
||||
key={'team_' + team.name}
|
||||
team={team}
|
||||
url={'/' + team.name + '/channels/town-square'}
|
||||
onTeamClick={this.handleTeamClick}
|
||||
loading={this.state.loadingTeamId === teamId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
teamContents = teamContents.sort(this.teamContentsCompare);
|
||||
|
||||
var openTeamContents = [];
|
||||
|
||||
for (const id in this.state.teamListings) {
|
||||
if (this.state.teamListings.hasOwnProperty(id) && !isAlreadyMember[id]) {
|
||||
const openTeam = this.state.teamListings[id];
|
||||
@@ -103,8 +86,8 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
if (teamMembersCount === 0 && teamContents.length === 0 && openTeamContents.length === 0 && (global.window.mm_config.EnableTeamCreation === 'true' || isSystemAdmin)) {
|
||||
teamContents = (
|
||||
if (openTeamContents.length === 0 && (global.window.mm_config.EnableTeamCreation === 'true' || isSystemAdmin)) {
|
||||
openTeamContents = (
|
||||
<div className='signup-team-dir-err'>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
@@ -114,8 +97,8 @@ export default class SelectTeam extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (teamMembersCount === 0 && teamContents.length === 0 && openTeamContents.length === 0) {
|
||||
teamContents = (
|
||||
} else if (openTeamContents.length === 0) {
|
||||
openTeamContents = (
|
||||
<div className='signup-team-dir-err'>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
@@ -125,42 +108,25 @@ export default class SelectTeam extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (teamContents.length === 0 && openTeamContents.length > 0) {
|
||||
teamContents = null;
|
||||
}
|
||||
|
||||
if (teamContents) {
|
||||
content = (
|
||||
<div className='signup__content'>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='signup_team.choose'
|
||||
defaultMessage='Your teams:'
|
||||
/>
|
||||
</h4>
|
||||
<div className='signup-team-all'>
|
||||
{teamContents}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (Array.isArray(openTeamContents)) {
|
||||
openTeamContents = openTeamContents.sort(this.teamContentsCompare);
|
||||
}
|
||||
|
||||
var openContent;
|
||||
if (openTeamContents.length > 0) {
|
||||
openContent = (
|
||||
<div className='signup__content'>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='signup_team.join_open'
|
||||
defaultMessage='Teams you can join: '
|
||||
/>
|
||||
</h4>
|
||||
<div className='signup-team-all'>
|
||||
{openTeamContents.sort(this.teamContentsCompare)}
|
||||
</div>
|
||||
let openContent = (
|
||||
<div className='signup__content'>
|
||||
<h4>
|
||||
<FormattedMessage
|
||||
id='signup_team.join_open'
|
||||
defaultMessage='Teams you can join: '
|
||||
/>
|
||||
</h4>
|
||||
<div className='signup-team-all'>
|
||||
{openTeamContents}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
||||
if (!this.state.loaded) {
|
||||
openContent = <LoadingScreen/>;
|
||||
@@ -177,7 +143,7 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
|
||||
let teamSignUp;
|
||||
if (isSystemAdmin || (global.window.mm_config.EnableTeamCreation === 'true' && !UserAgent.isMobileApp())) {
|
||||
if (isSystemAdmin || global.window.mm_config.EnableTeamCreation === 'true') {
|
||||
teamSignUp = (
|
||||
<div className='margin--extra'>
|
||||
<Link
|
||||
@@ -197,7 +163,7 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
|
||||
let adminConsoleLink;
|
||||
if (isSystemAdmin) {
|
||||
if (isSystemAdmin && !UserAgent.isMobileApp()) {
|
||||
adminConsoleLink = (
|
||||
<div className='margin--extra hidden-xs'>
|
||||
<Link
|
||||
@@ -225,19 +191,30 @@ export default class SelectTeam extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
let headerButton;
|
||||
if (this.state.teamMembers.length) {
|
||||
headerButton = (
|
||||
<Link to='/'>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage id='web.header.back'/>
|
||||
</Link>
|
||||
);
|
||||
} else {
|
||||
headerButton = (
|
||||
<a
|
||||
href='#'
|
||||
onClick={GlobalActions.emitUserLoggedOutEvent}
|
||||
>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage id='web.header.logout'/>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<ErrorBar/>
|
||||
<div className='signup-header'>
|
||||
<a
|
||||
href='#'
|
||||
onClick={GlobalActions.emitUserLoggedOutEvent}
|
||||
>
|
||||
<span className='fa fa-chevron-left'/>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.logout'
|
||||
/>
|
||||
</a>
|
||||
{headerButton}
|
||||
</div>
|
||||
<div className='col-sm-12'>
|
||||
<div className={'signup-team__container'}>
|
||||
@@ -249,7 +226,6 @@ export default class SelectTeam extends React.Component {
|
||||
<h4 className='color--light'>
|
||||
{description}
|
||||
</h4>
|
||||
{content}
|
||||
{openContent}
|
||||
{teamSignUp}
|
||||
{adminConsoleLink}
|
||||
|
||||
@@ -82,11 +82,19 @@ export default class Sidebar extends React.Component {
|
||||
let msgs = 0;
|
||||
let mentions = 0;
|
||||
const unreadCounts = this.state.unreadCounts;
|
||||
const teamMembers = this.state.teamMembers;
|
||||
|
||||
teamMembers.forEach((member) => {
|
||||
if (member.team_id !== this.state.currentTeam.id) {
|
||||
msgs += member.msg_count || 0;
|
||||
mentions += member.mention_count || 0;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(unreadCounts).forEach((chId) => {
|
||||
const channel = ChannelStore.get(chId);
|
||||
|
||||
if (channel && (!channel.team_id || channel.team_id === this.state.currentTeam.id)) {
|
||||
if (channel && (channel.type === 'D' || channel.team_id === this.state.currentTeam.id)) {
|
||||
msgs += unreadCounts[chId].msgs;
|
||||
mentions += unreadCounts[chId].mentions;
|
||||
}
|
||||
@@ -97,6 +105,7 @@ export default class Sidebar extends React.Component {
|
||||
|
||||
getStateFromStores() {
|
||||
const members = ChannelStore.getMyMembers();
|
||||
const teamMembers = TeamStore.getMyTeamMembers();
|
||||
const currentChannelId = ChannelStore.getCurrentId();
|
||||
const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
|
||||
const channelList = ChannelUtils.buildDisplayableChannelList(Object.assign([], ChannelStore.getAll()));
|
||||
@@ -104,6 +113,7 @@ export default class Sidebar extends React.Component {
|
||||
return {
|
||||
activeId: currentChannelId,
|
||||
members,
|
||||
teamMembers,
|
||||
...channelList,
|
||||
unreadCounts: JSON.parse(JSON.stringify(ChannelStore.getUnreadCounts())),
|
||||
showTutorialTip: tutorialStep === TutorialSteps.CHANNEL_POPOVER,
|
||||
@@ -153,6 +163,7 @@ export default class Sidebar extends React.Component {
|
||||
if (this.state.activeId !== prevState.activeId) {
|
||||
$('.app__body .inner-wrap').removeClass('move--right');
|
||||
$('.app__body .sidebar--left').removeClass('move--right');
|
||||
$('.multi-teams .team-sidebar').removeClass('move--right');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +180,7 @@ export default class Sidebar extends React.Component {
|
||||
|
||||
onChange() {
|
||||
this.setState(this.getStateFromStores());
|
||||
this.updateTitle();
|
||||
}
|
||||
|
||||
updateTitle() {
|
||||
|
||||
@@ -45,7 +45,6 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
this.showGetTeamInviteLinkModal = this.showGetTeamInviteLinkModal.bind(this);
|
||||
this.showTeamMembersModal = this.showTeamMembersModal.bind(this);
|
||||
this.hideTeamMembersModal = this.hideTeamMembersModal.bind(this);
|
||||
this.handleSwitchTeams = this.handleSwitchTeams.bind(this);
|
||||
|
||||
this.onTeamChange = this.onTeamChange.bind(this);
|
||||
this.openAccountSettings = this.openAccountSettings.bind(this);
|
||||
@@ -55,8 +54,8 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
|
||||
this.state = {
|
||||
teams: TeamStore.getAll(),
|
||||
teamMembers: TeamStore.getMyTeamMembers(),
|
||||
teamListings: TeamStore.getTeamListings(),
|
||||
showAboutModal: false,
|
||||
showDropdown: false,
|
||||
showTeamMembersModal: false,
|
||||
@@ -131,11 +130,6 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
handleSwitchTeams() {
|
||||
// The actual switching of teams is handled by the react-router Link
|
||||
this.setState({showDropdown: false});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
TeamStore.addChangeListener(this.onTeamChange);
|
||||
document.addEventListener('keydown', this.openAccountSettings);
|
||||
@@ -143,8 +137,8 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
|
||||
onTeamChange() {
|
||||
this.setState({
|
||||
teams: TeamStore.getAll(),
|
||||
teamMembers: TeamStore.getMyTeamMembers()
|
||||
teamMembers: TeamStore.getMyTeamMembers(),
|
||||
teamListings: TeamStore.getTeamListings()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -182,14 +176,14 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
|
||||
render() {
|
||||
const config = global.mm_config;
|
||||
var teamLink = '';
|
||||
var inviteLink = '';
|
||||
var manageLink = '';
|
||||
var sysAdminLink = '';
|
||||
var currentUser = this.props.currentUser;
|
||||
var isAdmin = false;
|
||||
var isSystemAdmin = false;
|
||||
var teamSettings = null;
|
||||
const currentUser = this.props.currentUser;
|
||||
let teamLink = '';
|
||||
let inviteLink = '';
|
||||
let manageLink = '';
|
||||
let sysAdminLink = '';
|
||||
let isAdmin = false;
|
||||
let isSystemAdmin = false;
|
||||
let teamSettings = null;
|
||||
let integrationsLink = null;
|
||||
|
||||
if (!currentUser) {
|
||||
@@ -322,6 +316,7 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
}
|
||||
|
||||
const teams = [];
|
||||
let moreTeams = false;
|
||||
|
||||
if (config.EnableTeamCreation === 'true') {
|
||||
teams.push(
|
||||
@@ -340,6 +335,31 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
const isAlreadyMember = this.state.teamMembers.reduce((result, item) => {
|
||||
result[item.team_id] = true;
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
for (const id in this.state.teamListings) {
|
||||
if (this.state.teamListings.hasOwnProperty(id) && !isAlreadyMember[id]) {
|
||||
moreTeams = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (moreTeams) {
|
||||
teams.push(
|
||||
<li key='joinTeam_li'>
|
||||
<Link to='/select_team'>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.join'
|
||||
defaultMessage='Join Another Team'
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
teams.push(
|
||||
<li key='leaveTeam_li'>
|
||||
<a
|
||||
@@ -354,39 +374,6 @@ export default class SidebarHeaderDropdown extends React.Component {
|
||||
</li>
|
||||
);
|
||||
|
||||
if (this.state.teamMembers && this.state.teamMembers.length > 1) {
|
||||
teams.push(
|
||||
<li
|
||||
key='teamDiv'
|
||||
className='divider'
|
||||
/>
|
||||
);
|
||||
|
||||
for (var index in this.state.teamMembers) {
|
||||
if (this.state.teamMembers.hasOwnProperty(index)) {
|
||||
var teamMember = this.state.teamMembers[index];
|
||||
var team = this.state.teams[teamMember.team_id];
|
||||
|
||||
if (team.name !== this.props.teamName) {
|
||||
teams.push(
|
||||
<li key={'team_' + team.name}>
|
||||
<Link
|
||||
to={'/' + team.name + '/channels/town-square'}
|
||||
onClick={this.handleSwitchTeams}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.switchTo'
|
||||
defaultMessage='Switch to '
|
||||
/>
|
||||
{team.display_name}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let helpLink = null;
|
||||
if (config.HelpLink) {
|
||||
helpLink = (
|
||||
|
||||
@@ -82,6 +82,7 @@ export default class SidebarRight extends React.Component {
|
||||
$('.app__body .inner-wrap').removeClass('.move--right');
|
||||
$('.app__body .inner-wrap').addClass('move--left');
|
||||
$('.app__body .sidebar--left').removeClass('move--right');
|
||||
$('.multi-teams .team-sidebar').removeClass('move--right');
|
||||
$('.app__body .sidebar--right').addClass('move--left');
|
||||
|
||||
//$('.sidebar--right').prepend('<div class="sidebar__overlay"></div>');
|
||||
|
||||
@@ -391,15 +391,6 @@ export default class SidebarRightMenu extends React.Component {
|
||||
{teamSettingsLink}
|
||||
{manageLink}
|
||||
{consoleLink}
|
||||
<li>
|
||||
<Link to='/select_team'>
|
||||
<i className='icon fa fa-exchange'/>
|
||||
<FormattedMessage
|
||||
id='sidebar_right_menu.switch_team'
|
||||
defaultMessage='Team Selection'
|
||||
/>
|
||||
</Link>
|
||||
</li>
|
||||
<li className='divider'/>
|
||||
{helpLink}
|
||||
{reportLink}
|
||||
|
||||
@@ -110,7 +110,7 @@ export default class SignupEmail extends React.Component {
|
||||
if (query.redirect_to) {
|
||||
browserHistory.push(query.redirect_to);
|
||||
} else {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -133,7 +133,7 @@ export default class SignupEmail extends React.Component {
|
||||
if (query.redirect_to) {
|
||||
browserHistory.push(query.redirect_to);
|
||||
} else {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -90,8 +90,13 @@ export default class SignupLdap extends React.Component {
|
||||
finishSignup() {
|
||||
GlobalActions.emitInitialLoad(
|
||||
() => {
|
||||
const query = this.props.location.query;
|
||||
GlobalActions.loadDefaultLocale();
|
||||
browserHistory.push('/select_team');
|
||||
if (query.redirect_to) {
|
||||
browserHistory.push(query.redirect_to);
|
||||
} else {
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export default class SignupController extends React.Component {
|
||||
}
|
||||
|
||||
if (userLoggedIn) {
|
||||
browserHistory.push('/select_team');
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
84
webapp/components/team_sidebar/components/team_button.jsx
Обычный файл
84
webapp/components/team_sidebar/components/team_button.jsx
Обычный файл
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
import React from 'react';
|
||||
import {Link} from 'react-router/es6';
|
||||
import {Tooltip, OverlayTrigger} from 'react-bootstrap';
|
||||
|
||||
export default class TeamButton extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.handleDisabled = this.handleDisabled.bind(this);
|
||||
}
|
||||
|
||||
handleDisabled(e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
render() {
|
||||
let teamClass = this.props.active ? 'active' : '';
|
||||
const disabled = this.props.disabled ? 'team-disabled' : '';
|
||||
const handleClick = (this.props.active || this.props.disabled) ? this.handleDisabled : null;
|
||||
let badge;
|
||||
|
||||
if (!teamClass) {
|
||||
teamClass = this.props.unread ? 'unread' : '';
|
||||
|
||||
if (this.props.mentions) {
|
||||
badge = (
|
||||
<span className='badge pull-right small'>{this.props.mentions}</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`team-container ${teamClass}`}
|
||||
>
|
||||
<Link
|
||||
className={disabled}
|
||||
to={this.props.url}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<OverlayTrigger
|
||||
delayShow={Constants.OVERLAY_TIME_DELAY}
|
||||
placement={this.props.placement}
|
||||
overlay={
|
||||
<Tooltip id={`tooltip-${this.props.url}`}>
|
||||
{this.props.tip}
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<div className='team-btn'>
|
||||
{badge}
|
||||
{this.props.contents}
|
||||
</div>
|
||||
</OverlayTrigger>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TeamButton.defaultProps = {
|
||||
tip: '',
|
||||
placement: 'right',
|
||||
active: false,
|
||||
disabled: false,
|
||||
unread: false,
|
||||
mentions: 0
|
||||
};
|
||||
|
||||
TeamButton.propTypes = {
|
||||
url: React.PropTypes.string.isRequired,
|
||||
contents: React.PropTypes.node.isRequired,
|
||||
tip: React.PropTypes.node,
|
||||
active: React.PropTypes.bool,
|
||||
disabled: React.PropTypes.bool,
|
||||
unread: React.PropTypes.bool,
|
||||
mentions: React.PropTypes.number,
|
||||
placement: React.PropTypes.oneOf(['left', 'right', 'top', 'bottom'])
|
||||
};
|
||||
169
webapp/components/team_sidebar/team_sidebar_controller.jsx
Обычный файл
169
webapp/components/team_sidebar/team_sidebar_controller.jsx
Обычный файл
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import TeamButton from './components/team_button.jsx';
|
||||
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import $ from 'jquery';
|
||||
import React from 'react';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
export default class TeamSidebar extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.getStateFromStores = this.getStateFromStores.bind(this);
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
this.setStyles = this.setStyles.bind(this);
|
||||
|
||||
this.state = this.getStateFromStores();
|
||||
}
|
||||
|
||||
getStateFromStores() {
|
||||
const teamMembers = TeamStore.getMyTeamMembers();
|
||||
const currentTeamId = TeamStore.getCurrentId();
|
||||
|
||||
return {
|
||||
teams: TeamStore.getAll(),
|
||||
teamListings: TeamStore.getTeamListings(),
|
||||
teamMembers,
|
||||
currentTeamId,
|
||||
show: teamMembers && teamMembers.length > 1
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
window.addEventListener('resize', this.handleResize);
|
||||
TeamStore.addChangeListener(this.onChange);
|
||||
TeamStore.addUnreadChangeListener(this.onChange);
|
||||
AsyncClient.getAllTeamListings();
|
||||
this.setStyles();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('resize', this.handleResize);
|
||||
TeamStore.removeChangeListener(this.onChange);
|
||||
TeamStore.removeUnreadChangeListener(this.onChange);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
$('.team-wrapper').perfectScrollbar();
|
||||
|
||||
// reset the scrollbar upon switching teams
|
||||
if (this.state.currentTeam !== prevState.currentTeam) {
|
||||
this.refs.container.scrollTop = 0;
|
||||
$('.team-wrapper').perfectScrollbar('update');
|
||||
}
|
||||
}
|
||||
|
||||
onChange() {
|
||||
this.setState(this.getStateFromStores());
|
||||
this.setStyles();
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
const teamMembers = this.state.teamMembers;
|
||||
this.setState({show: teamMembers && teamMembers.length > 1});
|
||||
this.setStyles();
|
||||
}
|
||||
|
||||
setStyles() {
|
||||
const root = document.querySelector('#root');
|
||||
|
||||
if (this.state.show) {
|
||||
root.classList.add('multi-teams');
|
||||
} else {
|
||||
root.classList.remove('multi-teams');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.show) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const myTeams = [];
|
||||
const isSystemAdmin = Utils.isSystemAdmin(UserStore.getCurrentUser().roles);
|
||||
const isAlreadyMember = new Map();
|
||||
let moreTeams = false;
|
||||
|
||||
for (const index in this.state.teamMembers) {
|
||||
if (this.state.teamMembers.hasOwnProperty(index)) {
|
||||
const teamMember = this.state.teamMembers[index];
|
||||
const teamId = teamMember.team_id;
|
||||
myTeams.push(Object.assign({
|
||||
unread: teamMember.msg_count > 0,
|
||||
mentions: teamMember.mention_count
|
||||
}, this.state.teams[teamId]));
|
||||
isAlreadyMember[teamId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const id in this.state.teamListings) {
|
||||
if (this.state.teamListings.hasOwnProperty(id) && !isAlreadyMember[id]) {
|
||||
moreTeams = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const teams = myTeams.
|
||||
sort((a, b) => a.display_name.localeCompare(b.display_name)).
|
||||
map((team) => {
|
||||
return (
|
||||
<TeamButton
|
||||
key={'switch_team_' + team.name}
|
||||
url={`/${team.name}`}
|
||||
tip={team.display_name}
|
||||
active={team.id === this.state.currentTeamId}
|
||||
contents={team.display_name.substring(0, 1).toUpperCase()}
|
||||
unread={team.unread}
|
||||
mentions={team.mentions}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
if (moreTeams) {
|
||||
teams.push(
|
||||
<TeamButton
|
||||
key='more_teams'
|
||||
url='/select_team'
|
||||
tip={
|
||||
<FormattedMessage
|
||||
id='team_sidebar.join'
|
||||
defaultMessage='Other teams you can join.'
|
||||
/>
|
||||
}
|
||||
contents={<i className='fa fa-plus'/>}
|
||||
/>
|
||||
);
|
||||
} else if (global.window.mm_config.EnableTeamCreation === 'true' || isSystemAdmin) {
|
||||
teams.push(
|
||||
<TeamButton
|
||||
key='more_teams'
|
||||
url='/create_team'
|
||||
tip={
|
||||
<FormattedMessage
|
||||
id='navbar_dropdown.create'
|
||||
defaultMessage='Create a New Team'
|
||||
/>
|
||||
}
|
||||
contents={<i className='fa fa-plus'/>}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='team-sidebar'>
|
||||
<div className='team-wrapper'>
|
||||
{teams}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ export default class SidebarRight extends React.Component {
|
||||
$('.app__body .inner-wrap').removeClass('move--right');
|
||||
$('.app__body .inner-wrap').addClass('webrtc--show');
|
||||
$('.app__body .sidebar--left').removeClass('move--right');
|
||||
$('.multi-teams .team-sidebar').removeClass('move--right');
|
||||
$('.app__body .webrtc').addClass('webrtc--show');
|
||||
|
||||
//$('.sidebar--right').prepend('<div class="sidebar__overlay"></div>');
|
||||
|
||||
Ссылка в новой задаче
Block a user