summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/admin_console/email_settings.jsx6
-rw-r--r--web/react/components/admin_console/gitlab_settings.jsx14
-rw-r--r--web/react/components/admin_console/sql_settings.jsx2
-rw-r--r--web/react/components/channel_loader.jsx9
-rw-r--r--web/react/components/create_comment.jsx4
-rw-r--r--web/react/components/email_verify.jsx8
-rw-r--r--web/react/components/more_direct_channels.jsx350
-rw-r--r--web/react/components/popover_list_members.jsx29
-rw-r--r--web/react/components/rhs_thread.jsx8
-rw-r--r--web/react/components/search_results.jsx4
-rw-r--r--web/react/components/sidebar.jsx73
-rw-r--r--web/react/components/user_profile.jsx38
12 files changed, 359 insertions, 186 deletions
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index c028d605d..12480e7eb 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -447,7 +447,7 @@ export default class EmailSettings extends React.Component {
</div>
<div className='help-text'>
<button
- className='btn'
+ className='btn btn-default'
onClick={this.handleTestConnection}
disabled={!this.state.sendEmailNotifications}
id='connection-button'
@@ -482,7 +482,7 @@ export default class EmailSettings extends React.Component {
<p className='help-text'>{'32-character salt added to signing of email invites. Randomly generated on install. Click "Re-Generate" to create new salt.'}</p>
<div className='help-text'>
<button
- className='btn'
+ className='btn btn-default'
onClick={this.handleGenerateInvite}
disabled={!this.state.sendEmailNotifications}
>
@@ -513,7 +513,7 @@ export default class EmailSettings extends React.Component {
<p className='help-text'>{'32-character salt added to signing of password reset emails. Randomly generated on install. Click "Re-Generate" to create new salt.'}</p>
<div className='help-text'>
<button
- className='btn'
+ className='btn btn-default'
onClick={this.handleGenerateReset}
disabled={!this.state.sendEmailNotifications}
>
diff --git a/web/react/components/admin_console/gitlab_settings.jsx b/web/react/components/admin_console/gitlab_settings.jsx
index 5c22bf5cf..41c8ad2fc 100644
--- a/web/react/components/admin_console/gitlab_settings.jsx
+++ b/web/react/components/admin_console/gitlab_settings.jsx
@@ -116,12 +116,14 @@ export default class GitLabSettings extends React.Component {
<p className='help-text'>
{'When true, Mattermost allows team creation and account signup using GitLab OAuth.'} <br/>
</p>
- <ol className='help-text'>
- <li>{'Log in to your GitLab account and go to Applications -> Profile Settings.'}</li>
- <li>{'Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". '}</li>
- <li>{'Then use "Secret" and "Id" fields from GitLab to complete the options below.'}</li>
- <li>{'Complete the Endpoint URLs below. '}</li>
- </ol>
+ <div className='help-text'>
+ <ol>
+ <li>{'Log in to your GitLab account and go to Applications -> Profile Settings.'}</li>
+ <li>{'Enter Redirect URIs "<your-mattermost-url>/login/gitlab/complete" (example: http://localhost:8065/login/gitlab/complete) and "<your-mattermost-url>/signup/gitlab/complete". '}</li>
+ <li>{'Then use "Secret" and "Id" fields from GitLab to complete the options below.'}</li>
+ <li>{'Complete the Endpoint URLs below. '}</li>
+ </ol>
+ </div>
</div>
</div>
diff --git a/web/react/components/admin_console/sql_settings.jsx b/web/react/components/admin_console/sql_settings.jsx
index 16a69e664..655daa30c 100644
--- a/web/react/components/admin_console/sql_settings.jsx
+++ b/web/react/components/admin_console/sql_settings.jsx
@@ -220,7 +220,7 @@ export default class SqlSettings extends React.Component {
<p className='help-text'>{'32-character salt available to encrypt and decrypt sensitive fields in database.'}</p>
<div className='help-text'>
<button
- className='help-link'
+ className='btn btn-default'
onClick={this.handleGenerate}
>
{'Re-Generate'}
diff --git a/web/react/components/channel_loader.jsx b/web/react/components/channel_loader.jsx
index d0d6ab5e2..270631db2 100644
--- a/web/react/components/channel_loader.jsx
+++ b/web/react/components/channel_loader.jsx
@@ -75,15 +75,6 @@ export default class ChannelLoader extends React.Component {
Utils.applyTheme(Constants.THEMES.default);
}
- /* Setup global mouse events */
- $('body').on('click', function hidePopover(e) {
- $('[data-toggle="popover"]').each(function eachPopover() {
- if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
- $(this).popover('hide');
- }
- });
- });
-
$('body').on('mouseenter mouseleave', '.post', function mouseOver(ev) {
if (ev.type === 'mouseenter') {
$(this).parent('div').prev('.date-separator, .new-separator').addClass('hovered--after');
diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx
index 2ac5d2179..fa3f82c2e 100644
--- a/web/react/components/create_comment.jsx
+++ b/web/react/components/create_comment.jsx
@@ -46,7 +46,9 @@ export default class CreateComment extends React.Component {
componentDidUpdate(prevProps, prevState) {
if (prevState.uploadsInProgress < this.state.uploadsInProgress) {
$('.post-right__scroll').scrollTop($('.post-right__scroll')[0].scrollHeight);
- $('.post-right__scroll').perfectScrollbar('update');
+ if ($(window).width() > 768) {
+ $('.post-right__scroll').perfectScrollbar('update');
+ }
}
}
handleSubmit(e) {
diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx
index 9be7f97f8..940b01f8d 100644
--- a/web/react/components/email_verify.jsx
+++ b/web/react/components/email_verify.jsx
@@ -39,11 +39,9 @@ export default class EmailVerify extends React.Component {
return (
<div className='col-sm-12'>
- <div className='panel panel-default verify_panel'>
- <div className='panel-heading'>
- <h3 className='panel-title'>{title}</h3>
- </div>
- <div className='panel-body'>
+ <div className='signup-team__container'>
+ <h3>{title}</h3>
+ <div>
{body}
{resend}
{resendConfirm}
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index bc610cd60..99babe714 100644
--- a/web/react/components/more_direct_channels.jsx
+++ b/web/react/components/more_direct_channels.jsx
@@ -1,133 +1,273 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-var TeamStore = require('../stores/team_store.jsx');
-var Client = require('../utils/client.jsx');
-var Constants = require('../utils/constants.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-var PreferenceStore = require('../stores/preference_store.jsx');
-var utils = require('../utils/utils.jsx');
+const AsyncClient = require('../utils/async_client.jsx');
+const ChannelStore = require('../stores/channel_store.jsx');
+const Constants = require('../utils/constants.jsx');
+const Client = require('../utils/client.jsx');
+const Modal = ReactBootstrap.Modal;
+const PreferenceStore = require('../stores/preference_store.jsx');
+const TeamStore = require('../stores/team_store.jsx');
+const UserStore = require('../stores/user_store.jsx');
+const Utils = require('../utils/utils.jsx');
export default class MoreDirectChannels extends React.Component {
constructor(props) {
super(props);
- this.state = {channels: [], loadingDMChannel: -1};
+ this.handleFilterChange = this.handleFilterChange.bind(this);
+ this.handleHide = this.handleHide.bind(this);
+ this.handleShowDirectChannel = this.handleShowDirectChannel.bind(this);
+ this.handleUserChange = this.handleUserChange.bind(this);
+
+ this.createRowForUser = this.createRowForUser.bind(this);
+
+ this.state = {
+ users: this.getUsersFromStore(),
+ filter: '',
+ loadingDMChannel: -1
+ };
+ }
+
+ getUsersFromStore() {
+ const currentId = UserStore.getCurrentId();
+ const profiles = UserStore.getProfiles();
+ const users = [];
+
+ for (const id in profiles) {
+ if (id !== currentId) {
+ users.push(profiles[id]);
+ }
+ }
+
+ users.sort((a, b) => a.username.localeCompare(b.username));
+
+ return users;
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', (e) => {
- var button = e.relatedTarget;
- this.setState({channels: $(button).data('channels')}); // eslint-disable-line react/no-did-mount-set-state
- });
+ UserStore.addChangeListener(this.handleUserChange);
}
- handleJoinDirectChannel(channel) {
- const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, channel.teammate_id, 'true');
- AsyncClient.savePreferences([preference]);
+ componentWillUnmount() {
+ UserStore.addChangeListener(this.handleUserChange);
}
- render() {
- var directMessageItems = this.state.channels.map((channel, index) => {
- var badge = '';
- var titleClass = '';
- var handleClick = null;
-
- if (channel.fake) {
- // It's a direct message channel that doesn't exist yet so let's create it now
- var otherUserId = utils.getUserIdFromChannelName(channel);
-
- if (this.state.loadingDMChannel === index) {
- badge = (
- <img
- className='channel-loading-gif pull-right'
- src='/static/images/load.gif'
- />
- );
- }
+ handleFilterChange() {
+ const filter = React.findDOMNode(this.refs.filter).value;
- if (this.state.loadingDMChannel === -1) {
- handleClick = (e) => {
- e.preventDefault();
- this.setState({loadingDMChannel: index});
- this.handleJoinDirectChannel(channel);
-
- Client.createDirectChannel(channel, otherUserId,
- (data) => {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
- this.setState({loadingDMChannel: -1});
- AsyncClient.getChannel(data.id);
- utils.switchChannel(data);
- },
- () => {
- this.setState({loadingDMChannel: -1});
- window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channel.name;
- }
- );
- };
- }
- } else {
- if (channel.unread) {
- badge = <span className='badge pull-right small'>{channel.unread}</span>;
- titleClass = 'unread-title';
+ if (filter !== this.state.filter) {
+ this.setState({filter});
+ }
+ }
+
+ handleHide() {
+ if (this.props.onModalDismissed) {
+ this.props.onModalDismissed();
+ }
+
+ this.setState({filter: ''});
+ }
+
+ handleShowDirectChannel(teammate, e) {
+ if (this.state.loadingDMChannel !== -1) {
+ return;
+ }
+
+ e.preventDefault();
+
+ const channelName = Utils.getDirectChannelName(UserStore.getCurrentId(), teammate.id);
+ let channel = ChannelStore.getByName(channelName);
+
+ const preference = PreferenceStore.setPreference(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW, teammate.id, 'true');
+ AsyncClient.savePreferences([preference]);
+
+ if (channel) {
+ Utils.switchChannel(channel);
+
+ this.handleHide();
+ } else {
+ this.setState({loadingDMChannel: teammate.id});
+
+ channel = {
+ name: channelName,
+ last_post_at: 0,
+ total_msg_count: 0,
+ type: 'D',
+ display_name: teammate.username,
+ teammate_id: teammate.id,
+ status: UserStore.getStatus(teammate.id)
+ };
+
+ Client.createDirectChannel(
+ channel,
+ teammate.id,
+ (data) => {
+ this.setState({loadingDMChannel: -1});
+
+ AsyncClient.getChannel(data.id);
+ Utils.switchChannel(data);
+
+ this.handleHide();
+ },
+ () => {
+ this.setState({loadingDMChannel: -1});
+ window.location.href = TeamStore.getCurrentTeamUrl() + '/channels/' + channelName;
}
+ );
+ }
+ }
- handleClick = (e) => {
- e.preventDefault();
- this.handleJoinDirectChannel(channel);
- utils.switchChannel(channel);
- $(React.findDOMNode(this.refs.modal)).modal('hide');
- };
- }
+ handleUserChange() {
+ this.setState({users: this.getUsersFromStore()});
+ }
+
+ createRowForUser(user) {
+ const details = [];
+
+ const fullName = Utils.getFullName(user);
+ if (fullName) {
+ details.push(
+ <span
+ key={`${user.id}__full-name`}
+ className='full-name'
+ >
+ {fullName}
+ </span>
+ );
+ }
- return (
- <li key={channel.name}>
- <a
- className={'sidebar-channel ' + titleClass}
- href='#'
- onClick={handleClick}
- >{badge}{channel.display_name}</a>
- </li>
+ if (user.nickname) {
+ const separator = fullName ? ' - ' : '';
+ details.push(
+ <span
+ key={`${user.nickname}__nickname`}
+ className='nickname'
+ >
+ {separator + user.nickname}
+ </span>
);
- });
+ }
+
+ let joinButton;
+ if (this.state.loadingDMChannel === user.id) {
+ joinButton = (
+ <img
+ className='channel-loading-gif'
+ src='/static/images/load.gif'
+ />
+ );
+ } else {
+ joinButton = (
+ <button
+ type='button'
+ className='btn btn-primary btn-message'
+ onClick={this.handleShowDirectChannel.bind(this, user)}
+ >
+ {'Message'}
+ </button>
+ );
+ }
return (
- <div
- className='modal fade'
- id='more_direct_channels'
- ref='modal'
- tabIndex='-1'
- role='dialog'
- aria-hidden='true'
+ <li
+ key={user.id}
+ className='direct-channel'
>
- <div className='modal-dialog'>
- <div className='modal-content'>
- <div className='modal-header'>
- <button
- type='button'
- className='close'
- data-dismiss='modal'
- >
- <span aria-hidden='true'>{'×'}</span>
- <span className='sr-only'>{'Close'}</span>
- </button>
- <h4 className='modal-title'>{'More Direct Messages'}</h4>
- </div>
- <div className='modal-body'>
- <ul className='nav nav-pills nav-stacked'>
- {directMessageItems}
- </ul>
- </div>
- <div className='modal-footer'>
- <button
- type='button'
- className='btn btn-default'
- data-dismiss='modal'
- >{'Close'}</button>
- </div>
+ <div className='col-xs-1 image-div'>
+ <img
+ className='profile-image'
+ src={`/api/v1/users/${user.id}/image?time=${user.update_at}`}
+ />
+ </div>
+ <div className='col-xs-9'>
+ <div className='username'>
+ {user.username}
</div>
+ <div>
+ {details}
+ </div>
+ </div>
+ <div className='col-xs-2 btn-div'>
+ {joinButton}
</div>
- </div>
+ </li>
+ );
+ }
+
+ render() {
+ if (!this.props.show) {
+ return null;
+ }
+
+ let users = this.state.users;
+ if (this.state.filter !== '') {
+ users = users.filter((user) => {
+ return user.username.indexOf(this.state.filter) !== -1 ||
+ user.first_name.indexOf(this.state.filter) !== -1 ||
+ user.last_name.indexOf(this.state.filter) !== -1 ||
+ user.nickname.indexOf(this.state.filter) !== -1;
+ });
+ }
+
+ const userEntries = users.map(this.createRowForUser);
+
+ if (userEntries.length === 0) {
+ userEntries.push(<li key='no-users-found'>{'No users found :('}</li>);
+ }
+
+ let memberString = 'Member';
+ if (users.length !== 1) {
+ memberString += 's';
+ }
+
+ let count;
+ if (users.length === this.state.users.length) {
+ count = `${users.length} ${memberString}`;
+ } else {
+ count = `${users.length} ${memberString} of ${this.state.users.length} Total`;
+ }
+
+ return (
+ <Modal
+ className='modal-direct-channels'
+ show={this.props.show}
+ bsSize='large'
+ onHide={this.handleHide}
+ >
+ <Modal.Header closeButton={true}>
+ <Modal.Title>{'More Direct Messages'}</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <div>
+ <input
+ ref='filter'
+ className='form-control filter-textbox'
+ placeholder='Search members'
+ onInput={this.handleFilterChange}
+ style={{width: '200px', display: 'inline'}}
+ />
+ <span className='member-count pull-right'>{count}</span>
+ </div>
+ <ul className='user-list'>
+ {userEntries}
+ </ul>
+ </Modal.Body>
+ <Modal.Footer>
+ <button
+ type='button'
+ className='btn btn-default'
+ onClick={this.handleHide}
+ >
+ {'Close'}
+ </button>
+ </Modal.Footer>
+ </Modal>
);
}
}
+
+MoreDirectChannels.propTypes = {
+ show: React.PropTypes.bool.isRequired,
+ onModalDismissed: React.PropTypes.func
+};
diff --git a/web/react/components/popover_list_members.jsx b/web/react/components/popover_list_members.jsx
index 5d9052fd7..16ae693fa 100644
--- a/web/react/components/popover_list_members.jsx
+++ b/web/react/components/popover_list_members.jsx
@@ -2,6 +2,8 @@
// See License.txt for license information.
var UserStore = require('../stores/user_store.jsx');
+var Popover = ReactBootstrap.Popover;
+var OverlayTrigger = ReactBootstrap.OverlayTrigger;
export default class PopoverListMembers extends React.Component {
componentDidMount() {
@@ -24,16 +26,9 @@ export default class PopoverListMembers extends React.Component {
});
}
};
-
- $('#member_popover').popover({placement: 'bottom', trigger: 'click', html: true});
- $('body').on('click', function onClick(e) {
- if (e.target.parentNode && $(e.target.parentNode.parentNode)[0] !== $('#member_popover')[0] && $(e.target).parents('.popover.in').length === 0) {
- $('#member_popover').popover('hide');
- }
- });
}
render() {
- let popoverHtml = '';
+ let popoverHtml = [];
let count = 0;
let countText = '-';
const members = this.props.members;
@@ -46,7 +41,7 @@ export default class PopoverListMembers extends React.Component {
members.forEach(function addMemberElement(m) {
if (teamMembers[m.username] && teamMembers[m.username].delete_at <= 0) {
- popoverHtml += `<div class='text--nowrap'>${m.username}</div>`;
+ popoverHtml.push(<div className='text--nowrap'>{m.username}</div>);
count++;
}
});
@@ -59,15 +54,14 @@ export default class PopoverListMembers extends React.Component {
}
return (
- <div
- id='member_popover'
- data-toggle='popover'
- data-content={popoverHtml}
- data-original-title='Members'
+ <OverlayTrigger
+ trigger='click'
+ placement='bottom'
+ rootClose='true'
+ overlay={<Popover title='Members'>{popoverHtml}</Popover>}
>
- <div
- id='member_tooltip'
- >
+ <div id='member_popover'>
+ <div>
{countText}
<span
className='fa fa-user'
@@ -75,6 +69,7 @@ export default class PopoverListMembers extends React.Component {
/>
</div>
</div>
+ </OverlayTrigger>
);
}
}
diff --git a/web/react/components/rhs_thread.jsx b/web/react/components/rhs_thread.jsx
index 41fd74adb..131253aa5 100644
--- a/web/react/components/rhs_thread.jsx
+++ b/web/react/components/rhs_thread.jsx
@@ -52,8 +52,6 @@ export default class RhsThread extends React.Component {
if ($('.post-right__scroll')[0]) {
$('.post-right__scroll').scrollTop($('.post-right__scroll')[0].scrollHeight);
}
-
- $('.post-right__scroll').perfectScrollbar('update');
this.resize();
}
componentWillUnmount() {
@@ -100,8 +98,10 @@ export default class RhsThread extends React.Component {
var height = $(window).height() - $('#error_bar').outerHeight() - 100;
$('.post-right__scroll').css('height', height + 'px');
$('.post-right__scroll').scrollTop(100000);
- $('.post-right__scroll').perfectScrollbar();
- $('.post-right__scroll').perfectScrollbar('update');
+ if ($(window).width() > 768) {
+ $('.post-right__scroll').perfectScrollbar();
+ $('.post-right__scroll').perfectScrollbar('update');
+ }
}
render() {
var postList = this.state.postList;
diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx
index 5eea3c501..e55fd3752 100644
--- a/web/react/components/search_results.jsx
+++ b/web/react/components/search_results.jsx
@@ -56,7 +56,9 @@ export default class SearchResults extends React.Component {
var height = $(window).height() - $('#error_bar').outerHeight() - 100;
$('#search-items-container').css('height', height + 'px');
$('#search-items-container').scrollTop(0);
- $('#search-items-container').perfectScrollbar();
+ if ($(window).width() > 768) {
+ $('#search-items-container').perfectScrollbar();
+ }
}
render() {
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 4911f17ef..e7d90bb88 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -8,6 +8,7 @@ const Client = require('../utils/client.jsx');
const Constants = require('../utils/constants.jsx');
const PreferenceStore = require('../stores/preference_store.jsx');
const NewChannelFlow = require('./new_channel_flow.jsx');
+const MoreDirectChannels = require('./more_direct_channels.jsx');
const SearchBox = require('./search_bar.jsx');
const SidebarHeader = require('./sidebar_header.jsx');
const SocketStore = require('../stores/socket_store.jsx');
@@ -33,12 +34,19 @@ export default class Sidebar extends React.Component {
this.onResize = this.onResize.bind(this);
this.updateUnreadIndicators = this.updateUnreadIndicators.bind(this);
this.handleLeaveDirectChannel = this.handleLeaveDirectChannel.bind(this);
+
+ this.showNewChannelModal = this.showNewChannelModal.bind(this);
+ this.hideNewChannelModal = this.hideNewChannelModal.bind(this);
+ this.showMoreDirectChannelsModal = this.showMoreDirectChannelsModal.bind(this);
+ this.hideMoreDirectChannelsModal = this.hideMoreDirectChannelsModal.bind(this);
+
this.createChannelElement = this.createChannelElement.bind(this);
this.isLeaving = new Map();
const state = this.getStateFromStores();
- state.modal = '';
+ state.newChannelModalType = '';
+ state.showMoreDirectChannelsModal = false;
state.loadingDMChannel = -1;
this.state = state;
@@ -47,10 +55,11 @@ export default class Sidebar extends React.Component {
const members = ChannelStore.getAllMembers();
var teamMemberMap = UserStore.getActiveOnlyProfiles();
var currentId = ChannelStore.getCurrentId();
+ const currentUserId = UserStore.getCurrentId();
var teammates = [];
for (var id in teamMemberMap) {
- if (id === UserStore.getCurrentId()) {
+ if (id === currentUserId) {
continue;
}
teammates.push(teamMemberMap[id]);
@@ -58,22 +67,16 @@ export default class Sidebar extends React.Component {
const preferences = PreferenceStore.getPreferences(Constants.Preferences.CATEGORY_DIRECT_CHANNEL_SHOW);
- // Create lists of all read and unread direct channels
var visibleDirectChannels = [];
- var hiddenDirectChannels = [];
+ var hiddenDirectChannelCount = 0;
for (var i = 0; i < teammates.length; i++) {
const teammate = teammates[i];
- if (teammate.id === UserStore.getCurrentId()) {
+ if (teammate.id === currentUserId) {
continue;
}
- var channelName = '';
- if (teammate.id > UserStore.getCurrentId()) {
- channelName = UserStore.getCurrentId() + '__' + teammate.id;
- } else {
- channelName = teammate.id + '__' + UserStore.getCurrentId();
- }
+ const channelName = Utils.getDirectChannelName(currentUserId, teammate.id);
let forceShow = false;
let channel = ChannelStore.getByName(channelName);
@@ -106,19 +109,18 @@ export default class Sidebar extends React.Component {
visibleDirectChannels.push(channel);
} else {
- hiddenDirectChannels.push(channel);
+ hiddenDirectChannelCount += 1;
}
}
visibleDirectChannels.sort(this.sortChannelsByDisplayName);
- hiddenDirectChannels.sort(this.sortChannelsByDisplayName);
return {
activeId: currentId,
channels: ChannelStore.getAll(),
members,
visibleDirectChannels,
- hiddenDirectChannels
+ hiddenDirectChannelCount
};
}
@@ -132,7 +134,9 @@ export default class Sidebar extends React.Component {
AsyncClient.getDirectChannelPreferences();
- $('.nav-pills__container').perfectScrollbar();
+ if ($(window).width() > 768) {
+ $('.nav-pills__container').perfectScrollbar();
+ }
this.updateTitle();
this.updateUnreadIndicators();
@@ -336,6 +340,20 @@ export default class Sidebar extends React.Component {
return a.display_name.localeCompare(b.display_name);
}
+ showNewChannelModal(type) {
+ this.setState({newChannelModalType: type});
+ }
+ hideNewChannelModal() {
+ this.setState({newChannelModalType: ''});
+ }
+
+ showMoreDirectChannelsModal() {
+ this.setState({showDirectChannelsModal: true});
+ }
+ hideMoreDirectChannelsModal() {
+ this.setState({showDirectChannelsModal: false});
+ }
+
createChannelElement(channel, index, arr, handleClose) {
var members = this.state.members;
var activeId = this.state.activeId;
@@ -532,25 +550,21 @@ export default class Sidebar extends React.Component {
head.appendChild(link);
var directMessageMore = null;
- if (this.state.hiddenDirectChannels.length > 0) {
+ if (this.state.hiddenDirectChannelCount > 0) {
directMessageMore = (
<li key='more'>
<a
- key={`more${this.state.hiddenDirectChannels.length}`}
href='#'
- data-toggle='modal'
- className='nav-more'
- data-target='#more_direct_channels'
- data-channels={JSON.stringify(this.state.hiddenDirectChannels)}
+ onClick={this.showMoreDirectChannelsModal}
>
- {'More (' + this.state.hiddenDirectChannels.length + ')'}
+ {'More (' + this.state.hiddenDirectChannelCount + ')'}
</a>
</li>
);
}
let showChannelModal = false;
- if (this.state.modal !== '') {
+ if (this.state.newChannelModalType !== '') {
showChannelModal = true;
}
@@ -561,9 +575,14 @@ export default class Sidebar extends React.Component {
<div>
<NewChannelFlow
show={showChannelModal}
- channelType={this.state.modal}
- onModalDismissed={() => this.setState({modal: ''})}
+ channelType={this.state.newChannelModalType}
+ onModalDismissed={this.hideNewChannelModal}
+ />
+ <MoreDirectChannels
+ show={this.state.showDirectChannelsModal}
+ onModalDismissed={this.hideMoreDirectChannelsModal}
/>
+
<SidebarHeader
teamDisplayName={this.props.teamDisplayName}
teamName={this.props.teamName}
@@ -599,7 +618,7 @@ export default class Sidebar extends React.Component {
<a
className='add-channel-btn'
href='#'
- onClick={() => this.setState({modal: 'O'})}
+ onClick={this.showNewChannelModal.bind(this, 'O')}
>
{'+'}
</a>
@@ -632,7 +651,7 @@ export default class Sidebar extends React.Component {
<a
className='add-channel-btn'
href='#'
- onClick={() => this.setState({modal: 'P'})}
+ onClick={this.showNewChannelModal.bind(this, 'P')}
>
{'+'}
</a>
diff --git a/web/react/components/user_profile.jsx b/web/react/components/user_profile.jsx
index cc6165c1b..715161b4f 100644
--- a/web/react/components/user_profile.jsx
+++ b/web/react/components/user_profile.jsx
@@ -3,6 +3,8 @@
var Utils = require('../utils/utils.jsx');
var UserStore = require('../stores/user_store.jsx');
+var Popover = ReactBootstrap.Popover;
+var OverlayTrigger = ReactBootstrap.OverlayTrigger;
var id = 0;
@@ -32,7 +34,6 @@ export default class UserProfile extends React.Component {
componentDidMount() {
UserStore.addChangeListener(this.onChange);
if (!this.props.disablePopover) {
- $('#profile_' + this.uniqueId).popover({placement: 'right', container: 'body', trigger: 'click hover', html: true, delay: {show: 200, hide: 100}});
$('body').tooltip({selector: '[data-toggle=tooltip]', trigger: 'hover click'});
}
}
@@ -62,23 +63,46 @@ export default class UserProfile extends React.Component {
return <div>{name}</div>;
}
- var dataContent = '<img class="user-popover__image" src="/api/v1/users/' + this.state.profile.id + '/image?time=' + this.state.profile.update_at + '" height="128" width="128" />';
+ var dataContent = [];
+ dataContent.push(
+ <img className='user-popover__image'
+ src={'/api/v1/users/' + this.state.profile.id + '/image?time=' + this.state.profile.update_at}
+ height='128'
+ width='128'
+ />
+ );
if (!global.window.config.ShowEmailAddress === 'true') {
- dataContent += '<div class="text-nowrap">Email not shared</div>';
+ dataContent.push(<div className='text-nowrap'>{'Email not shared'}</div>);
} else {
- dataContent += '<div data-toggle="tooltip" title="' + this.state.profile.email + '"><a href="mailto:' + this.state.profile.email + '" class="text-nowrap text-lowercase user-popover__email">' + this.state.profile.email + '</a></div>';
+ dataContent.push(
+ <div
+ data-toggle='tooltip'
+ title="' + this.state.profile.email + '"
+ >
+ <a
+ href="mailto:' + this.state.profile.email + '"
+ className='text-nowrap text-lowercase user-popover__email'
+ >
+ {this.state.profile.email}
+ </a>
+ </div>
+ );
}
return (
+ <OverlayTrigger
+ trigger='click'
+ placement='right'
+ rootClose='true'
+ overlay={<Popover title={this.state.profile.username}>{dataContent}</Popover>}
+ >
<div
className='user-popover'
id={'profile_' + this.uniqueId}
- data-toggle='popover'
- data-content={dataContent}
- data-original-title={this.state.profile.username}
>
{name}
</div>
+ </OverlayTrigger>
);
}
}