summaryrefslogtreecommitdiffstats
path: root/web/react/components
diff options
context:
space:
mode:
Diffstat (limited to 'web/react/components')
-rw-r--r--web/react/components/access_history_modal.jsx303
-rw-r--r--web/react/components/activity_log_modal.jsx4
-rw-r--r--web/react/components/admin_console/admin_navbar_dropdown.jsx4
-rw-r--r--web/react/components/admin_console/admin_sidebar.jsx6
-rw-r--r--web/react/components/admin_console/email_settings.jsx42
-rw-r--r--web/react/components/admin_console/gitlab_settings.jsx28
-rw-r--r--web/react/components/admin_console/image_settings.jsx58
-rw-r--r--web/react/components/admin_console/log_settings.jsx12
-rw-r--r--web/react/components/admin_console/privacy_settings.jsx4
-rw-r--r--web/react/components/admin_console/rate_settings.jsx18
-rw-r--r--web/react/components/admin_console/reset_password_modal.jsx4
-rw-r--r--web/react/components/admin_console/select_team_modal.jsx2
-rw-r--r--web/react/components/admin_console/service_settings.jsx26
-rw-r--r--web/react/components/admin_console/sql_settings.jsx22
-rw-r--r--web/react/components/admin_console/team_settings.jsx14
-rw-r--r--web/react/components/change_url_modal.jsx4
-rw-r--r--web/react/components/channel_header.jsx138
-rw-r--r--web/react/components/channel_info_modal.jsx2
-rw-r--r--web/react/components/channel_invite_modal.jsx4
-rw-r--r--web/react/components/channel_loader.jsx9
-rw-r--r--web/react/components/channel_members.jsx4
-rw-r--r--web/react/components/channel_notifications.jsx6
-rw-r--r--web/react/components/create_comment.jsx20
-rw-r--r--web/react/components/create_post.jsx32
-rw-r--r--web/react/components/delete_channel_modal.jsx2
-rw-r--r--web/react/components/delete_post_modal.jsx2
-rw-r--r--web/react/components/edit_channel_modal.jsx8
-rw-r--r--web/react/components/edit_post_modal.jsx44
-rw-r--r--web/react/components/email_verify.jsx8
-rw-r--r--web/react/components/file_attachment.jsx4
-rw-r--r--web/react/components/file_upload.jsx4
-rw-r--r--web/react/components/find_team.jsx2
-rw-r--r--web/react/components/get_link_modal.jsx6
-rw-r--r--web/react/components/invite_member_modal.jsx22
-rw-r--r--web/react/components/login.jsx4
-rw-r--r--web/react/components/mention_list.jsx2
-rw-r--r--web/react/components/more_channels.jsx8
-rw-r--r--web/react/components/more_direct_channels.jsx350
-rw-r--r--web/react/components/navbar.jsx74
-rw-r--r--web/react/components/navbar_dropdown.jsx4
-rw-r--r--web/react/components/new_channel_modal.jsx6
-rw-r--r--web/react/components/password_reset_form.jsx2
-rw-r--r--web/react/components/password_reset_send_link.jsx4
-rw-r--r--web/react/components/popover_list_members.jsx29
-rw-r--r--web/react/components/post_body.jsx2
-rw-r--r--web/react/components/post_deleted_modal.jsx2
-rw-r--r--web/react/components/post_list.jsx20
-rw-r--r--web/react/components/register_app_modal.jsx12
-rw-r--r--web/react/components/removed_from_channel_modal.jsx8
-rw-r--r--web/react/components/rename_channel_modal.jsx20
-rw-r--r--web/react/components/rhs_comment.jsx2
-rw-r--r--web/react/components/rhs_root_post.jsx2
-rw-r--r--web/react/components/rhs_thread.jsx8
-rw-r--r--web/react/components/search_bar.jsx2
-rw-r--r--web/react/components/search_results.jsx4
-rw-r--r--web/react/components/setting_picture.jsx2
-rw-r--r--web/react/components/setting_upload.jsx2
-rw-r--r--web/react/components/sidebar.jsx79
-rw-r--r--web/react/components/signup_user_complete.jsx6
-rw-r--r--web/react/components/team_members.jsx4
-rw-r--r--web/react/components/team_signup_display_name_page.jsx2
-rw-r--r--web/react/components/team_signup_email_item.jsx4
-rw-r--r--web/react/components/team_signup_password_page.jsx2
-rw-r--r--web/react/components/team_signup_url_page.jsx2
-rw-r--r--web/react/components/team_signup_username_page.jsx2
-rw-r--r--web/react/components/team_signup_welcome_page.jsx2
-rw-r--r--web/react/components/team_signup_with_email.jsx2
-rw-r--r--web/react/components/team_signup_with_sso.jsx2
-rw-r--r--web/react/components/textbox.jsx38
-rw-r--r--web/react/components/user_profile.jsx38
-rw-r--r--web/react/components/user_settings/import_theme_modal.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_appearance.jsx4
-rw-r--r--web/react/components/user_settings/user_settings_general.jsx2
-rw-r--r--web/react/components/user_settings/user_settings_notifications.jsx14
-rw-r--r--web/react/components/user_settings/user_settings_security.jsx2
-rw-r--r--web/react/components/view_image.jsx2
76 files changed, 1096 insertions, 550 deletions
diff --git a/web/react/components/access_history_modal.jsx b/web/react/components/access_history_modal.jsx
index 2ad4d5b00..c8af2553d 100644
--- a/web/react/components/access_history_modal.jsx
+++ b/web/react/components/access_history_modal.jsx
@@ -2,6 +2,7 @@
// See License.txt for license information.
var UserStore = require('../stores/user_store.jsx');
+var ChannelStore = require('../stores/channel_store.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var LoadingScreen = require('./loading_screen.jsx');
var Utils = require('../utils/utils.jsx');
@@ -14,8 +15,10 @@ export default class AccessHistoryModal extends React.Component {
this.handleMoreInfo = this.handleMoreInfo.bind(this);
this.onHide = this.onHide.bind(this);
this.onShow = this.onShow.bind(this);
+ this.formatAuditInfo = this.formatAuditInfo.bind(this);
+ this.handleRevokedSession = this.handleRevokedSession.bind(this);
- let state = this.getStateFromStoresForAudits();
+ const state = this.getStateFromStoresForAudits();
state.moreInfo = [];
this.state = state;
@@ -34,9 +37,9 @@ export default class AccessHistoryModal extends React.Component {
}
componentDidMount() {
UserStore.addAuditsChangeListener(this.onAuditChange);
- $(React.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.onShow);
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
}
componentWillUnmount() {
UserStore.removeAuditsChangeListener(this.onAuditChange);
@@ -52,23 +55,269 @@ export default class AccessHistoryModal extends React.Component {
newMoreInfo[index] = true;
this.setState({moreInfo: newMoreInfo});
}
- render() {
- var accessList = [];
- var currentHistoryDate = null;
+ handleRevokedSession(sessionId) {
+ return 'The session with id ' + sessionId + ' was revoked';
+ }
+ formatAuditInfo(currentAudit) {
+ const currentActionURL = currentAudit.action.replace(/\/api\/v[1-9]/, '');
- for (var i = 0; i < this.state.audits.length; i++) {
- var currentAudit = this.state.audits[i];
- var newHistoryDate = new Date(currentAudit.create_at);
- var newDate = null;
+ let currentAuditDesc = '';
+
+ if (currentActionURL.indexOf('/channels') === 0) {
+ const channelInfo = currentAudit.extra_info.split(' ');
+ const channelNameField = channelInfo[0].split('=');
+
+ let channelURL = '';
+ let channelObj;
+ let channelName = '';
+ if (channelNameField.indexOf('name') >= 0) {
+ channelURL = channelNameField[channelNameField.indexOf('name') + 1];
+ channelObj = ChannelStore.getByName(channelURL);
+ if (channelObj) {
+ channelName = channelObj.display_name;
+ } else {
+ channelName = channelURL;
+ }
+ }
+
+ switch (currentActionURL) {
+ case '/channels/create':
+ currentAuditDesc = 'Created the ' + channelName + ' channel/group';
+ break;
+ case '/channels/create_direct':
+ currentAuditDesc = 'Established a direct message channel with ' + Utils.getDirectTeammate(channelObj.id).username;
+ break;
+ case '/channels/update':
+ currentAuditDesc = 'Updated the ' + channelName + ' channel/group name';
+ break;
+ case '/channels/update_desc':
+ currentAuditDesc = 'Updated the ' + channelName + ' channel/group description';
+ break;
+ default:
+ let userIdField = [];
+ let userId = '';
+ let username = '';
+
+ if (channelInfo[1]) {
+ userIdField = channelInfo[1].split('=');
+
+ if (userIdField.indexOf('user_id') >= 0) {
+ userId = userIdField[userIdField.indexOf('user_id') + 1];
+ username = UserStore.getProfile(userId).username;
+ }
+ }
+
+ if (/\/channels\/[A-Za-z0-9]+\/delete/.test(currentActionURL)) {
+ currentAuditDesc = 'Deleted the channel/group with the URL ' + channelURL;
+ } else if (/\/channels\/[A-Za-z0-9]+\/add/.test(currentActionURL)) {
+ currentAuditDesc = 'Added ' + username + ' to the ' + channelName + ' channel/group';
+ } else if (/\/channels\/[A-Za-z0-9]+\/remove/.test(currentActionURL)) {
+ currentAuditDesc = 'Removed ' + username + ' from the ' + channelName + ' channel/group';
+ }
+
+ break;
+ }
+ } else if (currentActionURL.indexOf('/oauth') === 0) {
+ const oauthInfo = currentAudit.extra_info.split(' ');
+
+ switch (currentActionURL) {
+ case '/oauth/register':
+ const clientIdField = oauthInfo[0].split('=');
+
+ if (clientIdField[0] === 'client_id') {
+ currentAuditDesc = 'Attempted to register a new OAuth Application with ID ' + clientIdField[1];
+ }
+
+ break;
+ case '/oauth/allow':
+ if (oauthInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to allow a new OAuth service access';
+ } else if (oauthInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully gave a new OAuth service access';
+ } else if (oauthInfo[0] === 'fail - redirect_uri did not match registered callback') {
+ currentAuditDesc = 'Failed to allow a new OAuth service access - the redirect URI did not match the previously registered callback';
+ }
+
+ break;
+ case '/oauth/access_token':
+ if (oauthInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to get an OAuth access token';
+ } else if (oauthInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully added a new OAuth service';
+ } else {
+ const oauthTokenFailure = oauthInfo[0].split('-');
+
+ if (oauthTokenFailure[0].trim() === 'fail' && oauthTokenFailure[1]) {
+ currentAuditDesc = 'Failed to get an OAuth access token - ' + oauthTokenFailure[1].trim();
+ }
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else if (currentActionURL.indexOf('/users') === 0) {
+ const userInfo = currentAudit.extra_info.split(' ');
+
+ switch (currentActionURL) {
+ case '/users/login':
+ if (userInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to login';
+ } else if (userInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully logged in';
+ } else if (userInfo[0]) {
+ currentAuditDesc = 'FAILED login attempt';
+ }
+
+ break;
+ case '/users/revoke_session':
+ currentAuditDesc = this.handleRevokedSession(userInfo[0].split('=')[1]);
+ break;
+ case '/users/newimage':
+ currentAuditDesc = 'Updated your profile picture';
+ break;
+ case '/users/update':
+ currentAuditDesc = 'Updated the general settings of your account';
+ break;
+ case '/users/newpassword':
+ if (userInfo[0] === 'attempted') {
+ currentAuditDesc = 'Attempted to change password';
+ } else if (userInfo[0] === 'completed') {
+ currentAuditDesc = 'Successfully changed password';
+ } else if (userInfo[0] === 'failed - tried to update user password who was logged in through oauth') {
+ currentAuditDesc = 'Failed to change password - tried to update user password who was logged in through oauth';
+ }
+
+ break;
+ case '/users/update_roles':
+ const userRoles = userInfo[0].split('=')[1];
- if (!currentHistoryDate || currentHistoryDate.toLocaleDateString() !== newHistoryDate.toLocaleDateString()) {
- currentHistoryDate = newHistoryDate;
- newDate = (<div> {currentHistoryDate.toDateString()} </div>);
+ currentAuditDesc = 'Updated user role(s) to ';
+ if (userRoles.trim()) {
+ currentAuditDesc += userRoles;
+ } else {
+ currentAuditDesc += 'member';
+ }
+
+ break;
+ case '/users/update_active':
+ const updateType = userInfo[0].split('=')[0];
+ const updateField = userInfo[0].split('=')[1];
+
+ /* Either describes account activation/deactivation or a revoked session as part of an account deactivation */
+ if (updateType === 'active') {
+ if (updateField === 'true') {
+ currentAuditDesc = 'Account made active';
+ } else if (updateField === 'false') {
+ currentAuditDesc = 'Account made inactive';
+ }
+
+ const actingUserInfo = userInfo[1].split('=');
+ if (actingUserInfo[0] === 'session_user') {
+ const actingUser = UserStore.getProfile(actingUserInfo[1]);
+ const currentUser = UserStore.getCurrentUser();
+ if (currentUser && actingUser && (Utils.isAdmin(currentUser.roles) || Utils.isSystemAdmin(currentUser.roles))) {
+ currentAuditDesc += ' by ' + actingUser.username;
+ } else if (currentUser && actingUser) {
+ currentAuditDesc += ' by an admin';
+ }
+ }
+ } else if (updateType === 'session_id') {
+ currentAuditDesc = this.handleRevokedSession(updateField);
+ }
+
+ break;
+ case '/users/send_password_reset':
+ currentAuditDesc = 'Sent an email to ' + userInfo[0].split('=')[1] + ' to reset your password';
+ break;
+ case '/users/reset_password':
+ if (userInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to reset password';
+ } else if (userInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully reset password';
+ }
+
+ break;
+ case '/users/update_notify':
+ currentAuditDesc = 'Updated your global notification settings';
+ break;
+ default:
+ break;
}
+ } else if (currentActionURL.indexOf('/hooks') === 0) {
+ const webhookInfo = currentAudit.extra_info.split(' ');
+
+ switch (currentActionURL) {
+ case '/hooks/incoming/create':
+ if (webhookInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to create a webhook';
+ } else if (webhookInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully created a webhook';
+ } else if (webhookInfo[0] === 'fail - bad channel permissions') {
+ currentAuditDesc = 'Failed to create a webhook - bad channel permissions';
+ }
- if (!currentAudit.session_id && currentAudit.action.search('/users/login') !== -1) {
- currentAudit.session_id = 'N/A (Login attempt)';
+ break;
+ case '/hooks/incoming/delete':
+ if (webhookInfo[0] === 'attempt') {
+ currentAuditDesc = 'Attempted to delete a webhook';
+ } else if (webhookInfo[0] === 'success') {
+ currentAuditDesc = 'Successfully deleted a webhook';
+ } else if (webhookInfo[0] === 'fail - inappropriate conditions') {
+ currentAuditDesc = 'Failed to delete a webhook - inappropriate conditions';
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (currentActionURL) {
+ case '/logout':
+ currentAuditDesc = 'Logged out of your account';
+ break;
+ case '/verify_email':
+ currentAuditDesc = 'Sucessfully verified your email address';
+ break;
+ default:
+ break;
}
+ }
+
+ /* If all else fails... */
+ if (!currentAuditDesc) {
+ /* Currently not called anywhere */
+ if (currentAudit.extra_info.indexOf('revoked_all=') >= 0) {
+ currentAuditDesc = 'Revoked all current sessions for the team';
+ } else {
+ let currentActionDesc = '';
+ if (currentActionURL && currentActionURL.lastIndexOf('/') !== -1) {
+ currentActionDesc = currentActionURL.substring(currentActionURL.lastIndexOf('/') + 1).replace('_', ' ');
+ currentActionDesc = Utils.toTitleCase(currentActionDesc);
+ }
+
+ let currentExtraInfoDesc = '';
+ if (currentAudit.extra_info) {
+ currentExtraInfoDesc = currentAudit.extra_info;
+
+ if (currentExtraInfoDesc.indexOf('=') !== -1) {
+ currentExtraInfoDesc = currentExtraInfoDesc.substring(currentExtraInfoDesc.indexOf('=') + 1);
+ }
+ }
+ currentAuditDesc = currentActionDesc + ' ' + currentExtraInfoDesc;
+ }
+ }
+
+ const currentDate = new Date(currentAudit.create_at);
+ const currentAuditInfo = currentDate.toDateString() + ' - ' + currentDate.toLocaleTimeString(navigator.language, {hour: '2-digit', minute: '2-digit'}) + ' | ' + currentAuditDesc;
+ return currentAuditInfo;
+ }
+ render() {
+ var accessList = [];
+
+ for (var i = 0; i < this.state.audits.length; i++) {
+ const currentAudit = this.state.audits[i];
+ const currentAuditInfo = this.formatAuditInfo(currentAudit);
var moreInfo = (
<a
@@ -76,15 +325,27 @@ export default class AccessHistoryModal extends React.Component {
className='theme'
onClick={this.handleMoreInfo.bind(this, i)}
>
- More info
+ {'More info'}
</a>
);
if (this.state.moreInfo[i]) {
+ if (!currentAudit.session_id) {
+ currentAudit.session_id = 'N/A';
+
+ if (currentAudit.action.search('/users/login') >= 0) {
+ if (currentAudit.extra_info === 'attempt') {
+ currentAudit.session_id += ' (Login attempt)';
+ } else {
+ currentAudit.session_id += ' (Login failure)';
+ }
+ }
+ }
+
moreInfo = (
<div>
+ <div>{'IP: ' + currentAudit.ip_address}</div>
<div>{'Session ID: ' + currentAudit.session_id}</div>
- <div>{'URL: ' + currentAudit.action.replace(/\/api\/v[1-9]/, '')}</div>
</div>
);
}
@@ -99,11 +360,9 @@ export default class AccessHistoryModal extends React.Component {
key={'accessHistoryEntryKey' + i}
className='access-history__table'
>
- <div className='access__date'>{newDate}</div>
<div className='access__report'>
- <div className='report__time'>{newHistoryDate.toLocaleTimeString(navigator.language, {hour: '2-digit', minute: '2-digit'})}</div>
+ <div className='report__time'>{currentAuditInfo}</div>
<div className='report__info'>
- <div>{'IP: ' + currentAudit.ip_address}</div>
{moreInfo}
</div>
{divider}
@@ -138,13 +397,13 @@ export default class AccessHistoryModal extends React.Component {
data-dismiss='modal'
aria-label='Close'
>
- <span aria-hidden='true'>&times;</span>
+ <span aria-hidden='true'>{'×'}</span>
</button>
<h4
className='modal-title'
id='myModalLabel'
>
- Access History
+ {'Access History'}
</h4>
</div>
<div
diff --git a/web/react/components/activity_log_modal.jsx b/web/react/components/activity_log_modal.jsx
index 1fe2133ec..74d6c64e3 100644
--- a/web/react/components/activity_log_modal.jsx
+++ b/web/react/components/activity_log_modal.jsx
@@ -56,9 +56,9 @@ export default class ActivityLogModal extends React.Component {
}
componentDidMount() {
UserStore.addSessionsChangeListener(this.onListenerChange);
- $(React.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', this.onShow);
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
}
componentWillUnmount() {
UserStore.removeSessionsChangeListener(this.onListenerChange);
diff --git a/web/react/components/admin_console/admin_navbar_dropdown.jsx b/web/react/components/admin_console/admin_navbar_dropdown.jsx
index 21ec5c3cf..df8da94e1 100644
--- a/web/react/components/admin_console/admin_navbar_dropdown.jsx
+++ b/web/react/components/admin_console/admin_navbar_dropdown.jsx
@@ -27,7 +27,7 @@ export default class AdminNavbarDropdown extends React.Component {
}
componentDidMount() {
- $(React.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
+ $(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
this.blockToggle = true;
setTimeout(() => {
this.blockToggle = false;
@@ -36,7 +36,7 @@ export default class AdminNavbarDropdown extends React.Component {
}
componentWillUnmount() {
- $(React.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
+ $(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
}
render() {
diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx
index bc6ad1931..4c2a473b6 100644
--- a/web/react/components/admin_console/admin_sidebar.jsx
+++ b/web/react/components/admin_console/admin_sidebar.jsx
@@ -100,6 +100,7 @@ export default class AdminSidebar extends React.Component {
className='menu-icon--right menu__close'
onClick={this.removeTeam.bind(this, team.id)}
style={{cursor: 'pointer'}}
+ title='Remove team from sidebar menu'
>
{'x'}
</span>
@@ -233,7 +234,10 @@ export default class AdminSidebar extends React.Component {
href='#'
onClick={this.showTeamSelect}
>
- <i className='fa fa-plus'></i>
+ <i
+ className='fa fa-plus'
+ title='Add team to sidebar menu'
+ ></i>
</a>
</span>
</h4>
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index c028d605d..01759b222 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -41,28 +41,28 @@ export default class EmailSettings extends React.Component {
buildConfig() {
var config = this.props.config;
- config.EmailSettings.EnableSignUpWithEmail = React.findDOMNode(this.refs.allowSignUpWithEmail).checked;
- config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
- config.EmailSettings.RequireEmailVerification = React.findDOMNode(this.refs.requireEmailVerification).checked;
- config.EmailSettings.SendEmailNotifications = React.findDOMNode(this.refs.sendEmailNotifications).checked;
- config.EmailSettings.FeedbackName = React.findDOMNode(this.refs.feedbackName).value.trim();
- config.EmailSettings.FeedbackEmail = React.findDOMNode(this.refs.feedbackEmail).value.trim();
- config.EmailSettings.SMTPServer = React.findDOMNode(this.refs.SMTPServer).value.trim();
- config.EmailSettings.SMTPPort = React.findDOMNode(this.refs.SMTPPort).value.trim();
- config.EmailSettings.SMTPUsername = React.findDOMNode(this.refs.SMTPUsername).value.trim();
- config.EmailSettings.SMTPPassword = React.findDOMNode(this.refs.SMTPPassword).value.trim();
- config.EmailSettings.ConnectionSecurity = React.findDOMNode(this.refs.ConnectionSecurity).value.trim();
-
- config.EmailSettings.InviteSalt = React.findDOMNode(this.refs.InviteSalt).value.trim();
+ config.EmailSettings.EnableSignUpWithEmail = ReactDOM.findDOMNode(this.refs.allowSignUpWithEmail).checked;
+ config.EmailSettings.SendEmailNotifications = ReactDOM.findDOMNode(this.refs.sendEmailNotifications).checked;
+ config.EmailSettings.RequireEmailVerification = ReactDOM.findDOMNode(this.refs.requireEmailVerification).checked;
+ config.EmailSettings.SendEmailNotifications = ReactDOM.findDOMNode(this.refs.sendEmailNotifications).checked;
+ config.EmailSettings.FeedbackName = ReactDOM.findDOMNode(this.refs.feedbackName).value.trim();
+ config.EmailSettings.FeedbackEmail = ReactDOM.findDOMNode(this.refs.feedbackEmail).value.trim();
+ config.EmailSettings.SMTPServer = ReactDOM.findDOMNode(this.refs.SMTPServer).value.trim();
+ config.EmailSettings.SMTPPort = ReactDOM.findDOMNode(this.refs.SMTPPort).value.trim();
+ config.EmailSettings.SMTPUsername = ReactDOM.findDOMNode(this.refs.SMTPUsername).value.trim();
+ config.EmailSettings.SMTPPassword = ReactDOM.findDOMNode(this.refs.SMTPPassword).value.trim();
+ config.EmailSettings.ConnectionSecurity = ReactDOM.findDOMNode(this.refs.ConnectionSecurity).value.trim();
+
+ config.EmailSettings.InviteSalt = ReactDOM.findDOMNode(this.refs.InviteSalt).value.trim();
if (config.EmailSettings.InviteSalt === '') {
config.EmailSettings.InviteSalt = crypto.randomBytes(256).toString('base64').substring(0, 32);
- React.findDOMNode(this.refs.InviteSalt).value = config.EmailSettings.InviteSalt;
+ ReactDOM.findDOMNode(this.refs.InviteSalt).value = config.EmailSettings.InviteSalt;
}
- config.EmailSettings.PasswordResetSalt = React.findDOMNode(this.refs.PasswordResetSalt).value.trim();
+ config.EmailSettings.PasswordResetSalt = ReactDOM.findDOMNode(this.refs.PasswordResetSalt).value.trim();
if (config.EmailSettings.PasswordResetSalt === '') {
config.EmailSettings.PasswordResetSalt = crypto.randomBytes(256).toString('base64').substring(0, 32);
- React.findDOMNode(this.refs.PasswordResetSalt).value = config.EmailSettings.PasswordResetSalt;
+ ReactDOM.findDOMNode(this.refs.PasswordResetSalt).value = config.EmailSettings.PasswordResetSalt;
}
return config;
@@ -70,14 +70,14 @@ export default class EmailSettings extends React.Component {
handleGenerateInvite(e) {
e.preventDefault();
- React.findDOMNode(this.refs.InviteSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
+ ReactDOM.findDOMNode(this.refs.InviteSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
var s = {saveNeeded: true, serverError: this.state.serverError};
this.setState(s);
}
handleGenerateReset(e) {
e.preventDefault();
- React.findDOMNode(this.refs.PasswordResetSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
+ ReactDOM.findDOMNode(this.refs.PasswordResetSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
var s = {saveNeeded: true, serverError: this.state.serverError};
this.setState(s);
}
@@ -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..8b0f00083 100644
--- a/web/react/components/admin_console/gitlab_settings.jsx
+++ b/web/react/components/admin_console/gitlab_settings.jsx
@@ -37,12 +37,12 @@ export default class GitLabSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.GitLabSettings.Enable = React.findDOMNode(this.refs.Enable).checked;
- config.GitLabSettings.Secret = React.findDOMNode(this.refs.Secret).value.trim();
- config.GitLabSettings.Id = React.findDOMNode(this.refs.Id).value.trim();
- config.GitLabSettings.AuthEndpoint = React.findDOMNode(this.refs.AuthEndpoint).value.trim();
- config.GitLabSettings.TokenEndpoint = React.findDOMNode(this.refs.TokenEndpoint).value.trim();
- config.GitLabSettings.UserApiEndpoint = React.findDOMNode(this.refs.UserApiEndpoint).value.trim();
+ config.GitLabSettings.Enable = ReactDOM.findDOMNode(this.refs.Enable).checked;
+ config.GitLabSettings.Secret = ReactDOM.findDOMNode(this.refs.Secret).value.trim();
+ config.GitLabSettings.Id = ReactDOM.findDOMNode(this.refs.Id).value.trim();
+ config.GitLabSettings.AuthEndpoint = ReactDOM.findDOMNode(this.refs.AuthEndpoint).value.trim();
+ config.GitLabSettings.TokenEndpoint = ReactDOM.findDOMNode(this.refs.TokenEndpoint).value.trim();
+ config.GitLabSettings.UserApiEndpoint = ReactDOM.findDOMNode(this.refs.UserApiEndpoint).value.trim();
Client.saveConfig(
config,
@@ -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>
@@ -258,7 +260,7 @@ export default class GitLabSettings extends React.Component {
}
-//config.GitLabSettings.Scope = React.findDOMNode(this.refs.Scope).value.trim();
+//config.GitLabSettings.Scope = ReactDOM.findDOMNode(this.refs.Scope).value.trim();
// <div className='form-group'>
// <label
// className='control-label col-sm-4'
diff --git a/web/react/components/admin_console/image_settings.jsx b/web/react/components/admin_console/image_settings.jsx
index 24ed5a0a8..8b577e012 100644
--- a/web/react/components/admin_console/image_settings.jsx
+++ b/web/react/components/admin_console/image_settings.jsx
@@ -24,7 +24,7 @@ export default class FileSettings extends React.Component {
var s = {saveNeeded: true, serverError: this.state.serverError};
if (action === 'DriverName') {
- s.DriverName = React.findDOMNode(this.refs.DriverName).value;
+ s.DriverName = ReactDOM.findDOMNode(this.refs.DriverName).value;
}
this.setState(s);
@@ -32,7 +32,7 @@ export default class FileSettings extends React.Component {
handleGenerate(e) {
e.preventDefault();
- React.findDOMNode(this.refs.PublicLinkSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
+ ReactDOM.findDOMNode(this.refs.PublicLinkSalt).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
var s = {saveNeeded: true, serverError: this.state.serverError};
this.setState(s);
}
@@ -42,62 +42,62 @@ export default class FileSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.FileSettings.DriverName = React.findDOMNode(this.refs.DriverName).value;
- config.FileSettings.Directory = React.findDOMNode(this.refs.Directory).value;
- config.FileSettings.AmazonS3AccessKeyId = React.findDOMNode(this.refs.AmazonS3AccessKeyId).value;
- config.FileSettings.AmazonS3SecretAccessKey = React.findDOMNode(this.refs.AmazonS3SecretAccessKey).value;
- config.FileSettings.AmazonS3Bucket = React.findDOMNode(this.refs.AmazonS3Bucket).value;
- config.FileSettings.AmazonS3Region = React.findDOMNode(this.refs.AmazonS3Region).value;
- config.FileSettings.EnablePublicLink = React.findDOMNode(this.refs.EnablePublicLink).checked;
+ config.FileSettings.DriverName = ReactDOM.findDOMNode(this.refs.DriverName).value;
+ config.FileSettings.Directory = ReactDOM.findDOMNode(this.refs.Directory).value;
+ config.FileSettings.AmazonS3AccessKeyId = ReactDOM.findDOMNode(this.refs.AmazonS3AccessKeyId).value;
+ config.FileSettings.AmazonS3SecretAccessKey = ReactDOM.findDOMNode(this.refs.AmazonS3SecretAccessKey).value;
+ config.FileSettings.AmazonS3Bucket = ReactDOM.findDOMNode(this.refs.AmazonS3Bucket).value;
+ config.FileSettings.AmazonS3Region = ReactDOM.findDOMNode(this.refs.AmazonS3Region).value;
+ config.FileSettings.EnablePublicLink = ReactDOM.findDOMNode(this.refs.EnablePublicLink).checked;
- config.FileSettings.PublicLinkSalt = React.findDOMNode(this.refs.PublicLinkSalt).value.trim();
+ config.FileSettings.PublicLinkSalt = ReactDOM.findDOMNode(this.refs.PublicLinkSalt).value.trim();
if (config.FileSettings.PublicLinkSalt === '') {
config.FileSettings.PublicLinkSalt = crypto.randomBytes(256).toString('base64').substring(0, 32);
- React.findDOMNode(this.refs.PublicLinkSalt).value = config.FileSettings.PublicLinkSalt;
+ ReactDOM.findDOMNode(this.refs.PublicLinkSalt).value = config.FileSettings.PublicLinkSalt;
}
var thumbnailWidth = 120;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10))) {
- thumbnailWidth = parseInt(React.findDOMNode(this.refs.ThumbnailWidth).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.ThumbnailWidth).value, 10))) {
+ thumbnailWidth = parseInt(ReactDOM.findDOMNode(this.refs.ThumbnailWidth).value, 10);
}
config.FileSettings.ThumbnailWidth = thumbnailWidth;
- React.findDOMNode(this.refs.ThumbnailWidth).value = thumbnailWidth;
+ ReactDOM.findDOMNode(this.refs.ThumbnailWidth).value = thumbnailWidth;
var thumbnailHeight = 100;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.ThumbnailHeight).value, 10))) {
- thumbnailHeight = parseInt(React.findDOMNode(this.refs.ThumbnailHeight).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.ThumbnailHeight).value, 10))) {
+ thumbnailHeight = parseInt(ReactDOM.findDOMNode(this.refs.ThumbnailHeight).value, 10);
}
config.FileSettings.ThumbnailHeight = thumbnailHeight;
- React.findDOMNode(this.refs.ThumbnailHeight).value = thumbnailHeight;
+ ReactDOM.findDOMNode(this.refs.ThumbnailHeight).value = thumbnailHeight;
var previewWidth = 1024;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.PreviewWidth).value, 10))) {
- previewWidth = parseInt(React.findDOMNode(this.refs.PreviewWidth).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.PreviewWidth).value, 10))) {
+ previewWidth = parseInt(ReactDOM.findDOMNode(this.refs.PreviewWidth).value, 10);
}
config.FileSettings.PreviewWidth = previewWidth;
- React.findDOMNode(this.refs.PreviewWidth).value = previewWidth;
+ ReactDOM.findDOMNode(this.refs.PreviewWidth).value = previewWidth;
var previewHeight = 0;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.PreviewHeight).value, 10))) {
- previewHeight = parseInt(React.findDOMNode(this.refs.PreviewHeight).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.PreviewHeight).value, 10))) {
+ previewHeight = parseInt(ReactDOM.findDOMNode(this.refs.PreviewHeight).value, 10);
}
config.FileSettings.PreviewHeight = previewHeight;
- React.findDOMNode(this.refs.PreviewHeight).value = previewHeight;
+ ReactDOM.findDOMNode(this.refs.PreviewHeight).value = previewHeight;
var profileWidth = 128;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.ProfileWidth).value, 10))) {
- profileWidth = parseInt(React.findDOMNode(this.refs.ProfileWidth).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.ProfileWidth).value, 10))) {
+ profileWidth = parseInt(ReactDOM.findDOMNode(this.refs.ProfileWidth).value, 10);
}
config.FileSettings.ProfileWidth = profileWidth;
- React.findDOMNode(this.refs.ProfileWidth).value = profileWidth;
+ ReactDOM.findDOMNode(this.refs.ProfileWidth).value = profileWidth;
var profileHeight = 128;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.ProfileHeight).value, 10))) {
- profileHeight = parseInt(React.findDOMNode(this.refs.ProfileHeight).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.ProfileHeight).value, 10))) {
+ profileHeight = parseInt(ReactDOM.findDOMNode(this.refs.ProfileHeight).value, 10);
}
config.FileSettings.ProfileHeight = profileHeight;
- React.findDOMNode(this.refs.ProfileHeight).value = profileHeight;
+ ReactDOM.findDOMNode(this.refs.ProfileHeight).value = profileHeight;
Client.saveConfig(
config,
diff --git a/web/react/components/admin_console/log_settings.jsx b/web/react/components/admin_console/log_settings.jsx
index 367605f14..931818bb8 100644
--- a/web/react/components/admin_console/log_settings.jsx
+++ b/web/react/components/admin_console/log_settings.jsx
@@ -46,12 +46,12 @@ export default class LogSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.LogSettings.EnableConsole = React.findDOMNode(this.refs.consoleEnable).checked;
- config.LogSettings.ConsoleLevel = React.findDOMNode(this.refs.consoleLevel).value;
- config.LogSettings.EnableFile = React.findDOMNode(this.refs.fileEnable).checked;
- config.LogSettings.FileLevel = React.findDOMNode(this.refs.fileLevel).value;
- config.LogSettings.FileLocation = React.findDOMNode(this.refs.fileLocation).value.trim();
- config.LogSettings.FileFormat = React.findDOMNode(this.refs.fileFormat).value.trim();
+ config.LogSettings.EnableConsole = ReactDOM.findDOMNode(this.refs.consoleEnable).checked;
+ config.LogSettings.ConsoleLevel = ReactDOM.findDOMNode(this.refs.consoleLevel).value;
+ config.LogSettings.EnableFile = ReactDOM.findDOMNode(this.refs.fileEnable).checked;
+ config.LogSettings.FileLevel = ReactDOM.findDOMNode(this.refs.fileLevel).value;
+ config.LogSettings.FileLocation = ReactDOM.findDOMNode(this.refs.fileLocation).value.trim();
+ config.LogSettings.FileFormat = ReactDOM.findDOMNode(this.refs.fileFormat).value.trim();
Client.saveConfig(
config,
diff --git a/web/react/components/admin_console/privacy_settings.jsx b/web/react/components/admin_console/privacy_settings.jsx
index 70ec04f4a..f2d22f36e 100644
--- a/web/react/components/admin_console/privacy_settings.jsx
+++ b/web/react/components/admin_console/privacy_settings.jsx
@@ -28,8 +28,8 @@ export default class PrivacySettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.PrivacySettings.ShowEmailAddress = React.findDOMNode(this.refs.ShowEmailAddress).checked;
- config.PrivacySettings.ShowFullName = React.findDOMNode(this.refs.ShowFullName).checked;
+ config.PrivacySettings.ShowEmailAddress = ReactDOM.findDOMNode(this.refs.ShowEmailAddress).checked;
+ config.PrivacySettings.ShowFullName = ReactDOM.findDOMNode(this.refs.ShowFullName).checked;
Client.saveConfig(
config,
diff --git a/web/react/components/admin_console/rate_settings.jsx b/web/react/components/admin_console/rate_settings.jsx
index 65c39ac42..4d71777c4 100644
--- a/web/react/components/admin_console/rate_settings.jsx
+++ b/web/react/components/admin_console/rate_settings.jsx
@@ -46,23 +46,23 @@ export default class RateSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.RateLimitSettings.EnableRateLimiter = React.findDOMNode(this.refs.EnableRateLimiter).checked;
- config.RateLimitSettings.VaryByRemoteAddr = React.findDOMNode(this.refs.VaryByRemoteAddr).checked;
- config.RateLimitSettings.VaryByHeader = React.findDOMNode(this.refs.VaryByHeader).value.trim();
+ config.RateLimitSettings.EnableRateLimiter = ReactDOM.findDOMNode(this.refs.EnableRateLimiter).checked;
+ config.RateLimitSettings.VaryByRemoteAddr = ReactDOM.findDOMNode(this.refs.VaryByRemoteAddr).checked;
+ config.RateLimitSettings.VaryByHeader = ReactDOM.findDOMNode(this.refs.VaryByHeader).value.trim();
var PerSec = 10;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.PerSec).value, 10))) {
- PerSec = parseInt(React.findDOMNode(this.refs.PerSec).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.PerSec).value, 10))) {
+ PerSec = parseInt(ReactDOM.findDOMNode(this.refs.PerSec).value, 10);
}
config.RateLimitSettings.PerSec = PerSec;
- React.findDOMNode(this.refs.PerSec).value = PerSec;
+ ReactDOM.findDOMNode(this.refs.PerSec).value = PerSec;
var MemoryStoreSize = 10000;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.MemoryStoreSize).value, 10))) {
- MemoryStoreSize = parseInt(React.findDOMNode(this.refs.MemoryStoreSize).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MemoryStoreSize).value, 10))) {
+ MemoryStoreSize = parseInt(ReactDOM.findDOMNode(this.refs.MemoryStoreSize).value, 10);
}
config.RateLimitSettings.MemoryStoreSize = MemoryStoreSize;
- React.findDOMNode(this.refs.MemoryStoreSize).value = MemoryStoreSize;
+ ReactDOM.findDOMNode(this.refs.MemoryStoreSize).value = MemoryStoreSize;
Client.saveConfig(
config,
diff --git a/web/react/components/admin_console/reset_password_modal.jsx b/web/react/components/admin_console/reset_password_modal.jsx
index 75264be45..35d3cdd17 100644
--- a/web/react/components/admin_console/reset_password_modal.jsx
+++ b/web/react/components/admin_console/reset_password_modal.jsx
@@ -18,7 +18,7 @@ export default class ResetPasswordModal extends React.Component {
doSubmit(e) {
e.preventDefault();
- var password = React.findDOMNode(this.refs.password).value;
+ var password = ReactDOM.findDOMNode(this.refs.password).value;
if (!password || password.length < 5) {
this.setState({serverError: 'Please enter at least 5 characters.'});
@@ -34,7 +34,7 @@ export default class ResetPasswordModal extends React.Component {
Client.resetPassword(data,
() => {
- this.props.onModalSubmit(React.findDOMNode(this.refs.password).value);
+ this.props.onModalSubmit(ReactDOM.findDOMNode(this.refs.password).value);
},
(err) => {
this.setState({serverError: err.message});
diff --git a/web/react/components/admin_console/select_team_modal.jsx b/web/react/components/admin_console/select_team_modal.jsx
index 21d1c25c3..22189821b 100644
--- a/web/react/components/admin_console/select_team_modal.jsx
+++ b/web/react/components/admin_console/select_team_modal.jsx
@@ -13,7 +13,7 @@ export default class SelectTeamModal extends React.Component {
doSubmit(e) {
e.preventDefault();
- this.props.onModalSubmit(React.findDOMNode(this.refs.team).value);
+ this.props.onModalSubmit(ReactDOM.findDOMNode(this.refs.team).value);
}
doCancel() {
this.props.onModalDismissed();
diff --git a/web/react/components/admin_console/service_settings.jsx b/web/react/components/admin_console/service_settings.jsx
index f29d62646..4105ba6da 100644
--- a/web/react/components/admin_console/service_settings.jsx
+++ b/web/react/components/admin_console/service_settings.jsx
@@ -27,28 +27,28 @@ export default class ServiceSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.ServiceSettings.ListenAddress = React.findDOMNode(this.refs.ListenAddress).value.trim();
+ config.ServiceSettings.ListenAddress = ReactDOM.findDOMNode(this.refs.ListenAddress).value.trim();
if (config.ServiceSettings.ListenAddress === '') {
config.ServiceSettings.ListenAddress = ':8065';
- React.findDOMNode(this.refs.ListenAddress).value = config.ServiceSettings.ListenAddress;
+ ReactDOM.findDOMNode(this.refs.ListenAddress).value = config.ServiceSettings.ListenAddress;
}
- config.ServiceSettings.SegmentDeveloperKey = React.findDOMNode(this.refs.SegmentDeveloperKey).value.trim();
- config.ServiceSettings.GoogleDeveloperKey = React.findDOMNode(this.refs.GoogleDeveloperKey).value.trim();
- config.ServiceSettings.EnableIncomingWebhooks = React.findDOMNode(this.refs.EnableIncomingWebhooks).checked;
- config.ServiceSettings.EnablePostUsernameOverride = React.findDOMNode(this.refs.EnablePostUsernameOverride).checked;
- config.ServiceSettings.EnablePostIconOverride = React.findDOMNode(this.refs.EnablePostIconOverride).checked;
- config.ServiceSettings.EnableTesting = React.findDOMNode(this.refs.EnableTesting).checked;
- config.ServiceSettings.EnableSecurityFixAlert = React.findDOMNode(this.refs.EnableSecurityFixAlert).checked;
+ config.ServiceSettings.SegmentDeveloperKey = ReactDOM.findDOMNode(this.refs.SegmentDeveloperKey).value.trim();
+ config.ServiceSettings.GoogleDeveloperKey = ReactDOM.findDOMNode(this.refs.GoogleDeveloperKey).value.trim();
+ config.ServiceSettings.EnableIncomingWebhooks = ReactDOM.findDOMNode(this.refs.EnableIncomingWebhooks).checked;
+ config.ServiceSettings.EnablePostUsernameOverride = ReactDOM.findDOMNode(this.refs.EnablePostUsernameOverride).checked;
+ config.ServiceSettings.EnablePostIconOverride = ReactDOM.findDOMNode(this.refs.EnablePostIconOverride).checked;
+ config.ServiceSettings.EnableTesting = ReactDOM.findDOMNode(this.refs.EnableTesting).checked;
+ config.ServiceSettings.EnableSecurityFixAlert = ReactDOM.findDOMNode(this.refs.EnableSecurityFixAlert).checked;
- //config.ServiceSettings.EnableOAuthServiceProvider = React.findDOMNode(this.refs.EnableOAuthServiceProvider).checked;
+ //config.ServiceSettings.EnableOAuthServiceProvider = ReactDOM.findDOMNode(this.refs.EnableOAuthServiceProvider).checked;
var MaximumLoginAttempts = 10;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.MaximumLoginAttempts).value, 10))) {
- MaximumLoginAttempts = parseInt(React.findDOMNode(this.refs.MaximumLoginAttempts).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value, 10))) {
+ MaximumLoginAttempts = parseInt(ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value, 10);
}
config.ServiceSettings.MaximumLoginAttempts = MaximumLoginAttempts;
- React.findDOMNode(this.refs.MaximumLoginAttempts).value = MaximumLoginAttempts;
+ ReactDOM.findDOMNode(this.refs.MaximumLoginAttempts).value = MaximumLoginAttempts;
Client.saveConfig(
config,
diff --git a/web/react/components/admin_console/sql_settings.jsx b/web/react/components/admin_console/sql_settings.jsx
index 16a69e664..b43108bf7 100644
--- a/web/react/components/admin_console/sql_settings.jsx
+++ b/web/react/components/admin_console/sql_settings.jsx
@@ -29,27 +29,27 @@ export default class SqlSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.SqlSettings.Trace = React.findDOMNode(this.refs.Trace).checked;
- config.SqlSettings.AtRestEncryptKey = React.findDOMNode(this.refs.AtRestEncryptKey).value.trim();
+ config.SqlSettings.Trace = ReactDOM.findDOMNode(this.refs.Trace).checked;
+ config.SqlSettings.AtRestEncryptKey = ReactDOM.findDOMNode(this.refs.AtRestEncryptKey).value.trim();
if (config.SqlSettings.AtRestEncryptKey === '') {
config.SqlSettings.AtRestEncryptKey = crypto.randomBytes(256).toString('base64').substring(0, 32);
- React.findDOMNode(this.refs.AtRestEncryptKey).value = config.SqlSettings.AtRestEncryptKey;
+ ReactDOM.findDOMNode(this.refs.AtRestEncryptKey).value = config.SqlSettings.AtRestEncryptKey;
}
var MaxOpenConns = 10;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.MaxOpenConns).value, 10))) {
- MaxOpenConns = parseInt(React.findDOMNode(this.refs.MaxOpenConns).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaxOpenConns).value, 10))) {
+ MaxOpenConns = parseInt(ReactDOM.findDOMNode(this.refs.MaxOpenConns).value, 10);
}
config.SqlSettings.MaxOpenConns = MaxOpenConns;
- React.findDOMNode(this.refs.MaxOpenConns).value = MaxOpenConns;
+ ReactDOM.findDOMNode(this.refs.MaxOpenConns).value = MaxOpenConns;
var MaxIdleConns = 10;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.MaxIdleConns).value, 10))) {
- MaxIdleConns = parseInt(React.findDOMNode(this.refs.MaxIdleConns).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaxIdleConns).value, 10))) {
+ MaxIdleConns = parseInt(ReactDOM.findDOMNode(this.refs.MaxIdleConns).value, 10);
}
config.SqlSettings.MaxIdleConns = MaxIdleConns;
- React.findDOMNode(this.refs.MaxIdleConns).value = MaxIdleConns;
+ ReactDOM.findDOMNode(this.refs.MaxIdleConns).value = MaxIdleConns;
Client.saveConfig(
config,
@@ -79,7 +79,7 @@ export default class SqlSettings extends React.Component {
return;
}
- React.findDOMNode(this.refs.AtRestEncryptKey).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
+ ReactDOM.findDOMNode(this.refs.AtRestEncryptKey).value = crypto.randomBytes(256).toString('base64').substring(0, 32);
var s = {saveNeeded: true, serverError: this.state.serverError};
this.setState(s);
}
@@ -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/admin_console/team_settings.jsx b/web/react/components/admin_console/team_settings.jsx
index a517c56fe..da4299714 100644
--- a/web/react/components/admin_console/team_settings.jsx
+++ b/web/react/components/admin_console/team_settings.jsx
@@ -27,17 +27,17 @@ export default class TeamSettings extends React.Component {
$('#save-button').button('loading');
var config = this.props.config;
- config.TeamSettings.SiteName = React.findDOMNode(this.refs.SiteName).value.trim();
- config.TeamSettings.RestrictCreationToDomains = React.findDOMNode(this.refs.RestrictCreationToDomains).value.trim();
- config.TeamSettings.EnableTeamCreation = React.findDOMNode(this.refs.EnableTeamCreation).checked;
- config.TeamSettings.EnableUserCreation = React.findDOMNode(this.refs.EnableUserCreation).checked;
+ config.TeamSettings.SiteName = ReactDOM.findDOMNode(this.refs.SiteName).value.trim();
+ config.TeamSettings.RestrictCreationToDomains = ReactDOM.findDOMNode(this.refs.RestrictCreationToDomains).value.trim();
+ config.TeamSettings.EnableTeamCreation = ReactDOM.findDOMNode(this.refs.EnableTeamCreation).checked;
+ config.TeamSettings.EnableUserCreation = ReactDOM.findDOMNode(this.refs.EnableUserCreation).checked;
var MaxUsersPerTeam = 50;
- if (!isNaN(parseInt(React.findDOMNode(this.refs.MaxUsersPerTeam).value, 10))) {
- MaxUsersPerTeam = parseInt(React.findDOMNode(this.refs.MaxUsersPerTeam).value, 10);
+ if (!isNaN(parseInt(ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value, 10))) {
+ MaxUsersPerTeam = parseInt(ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value, 10);
}
config.TeamSettings.MaxUsersPerTeam = MaxUsersPerTeam;
- React.findDOMNode(this.refs.MaxUsersPerTeam).value = MaxUsersPerTeam;
+ ReactDOM.findDOMNode(this.refs.MaxUsersPerTeam).value = MaxUsersPerTeam;
Client.saveConfig(
config,
diff --git a/web/react/components/change_url_modal.jsx b/web/react/components/change_url_modal.jsx
index f8db13392..714e93ff8 100644
--- a/web/react/components/change_url_modal.jsx
+++ b/web/react/components/change_url_modal.jsx
@@ -29,7 +29,7 @@ export default class ChangeUrlModal extends React.Component {
}
componentDidUpdate(prevProps) {
if (this.props.show === true && prevProps.show === false) {
- React.findDOMNode(this.refs.urlinput).select();
+ ReactDOM.findDOMNode(this.refs.urlinput).select();
}
}
onURLChanged(e) {
@@ -60,7 +60,7 @@ export default class ChangeUrlModal extends React.Component {
doSubmit(e) {
e.preventDefault();
- const url = React.findDOMNode(this.refs.urlinput).value;
+ const url = ReactDOM.findDOMNode(this.refs.urlinput).value;
const cleanedURL = Utils.cleanUpUrlable(url);
if (cleanedURL !== url || url.length < 2 || url.indexOf('__') > -1) {
this.setState({urlError: this.getURLError(url)});
diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx
index e47db073d..7582de6c4 100644
--- a/web/react/components/channel_header.jsx
+++ b/web/react/components/channel_header.jsx
@@ -17,6 +17,9 @@ const AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
const Constants = require('../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
+const Popover = ReactBootstrap.Popover;
+const OverlayTrigger = ReactBootstrap.OverlayTrigger;
+
export default class ChannelHeader extends React.Component {
constructor(props) {
super(props);
@@ -110,7 +113,21 @@ export default class ChannelHeader extends React.Component {
}
const channel = this.state.channel;
- const popoverContent = React.renderToString(<MessageWrapper message={channel.description}/>);
+ const popoverContent = (
+ <Popover
+ id='hader-popover'
+ bStyle='info'
+ bSize='large'
+ placement='bottom'
+ className='description'
+ onMouseOver={() => this.refs.descriptionOverlay.show()}
+ onMouseOut={() => this.refs.descriptionOverlay.hide()}
+ >
+ <MessageWrapper
+ message={channel.description}
+ />
+ </Popover>
+ );
let channelTitle = channel.display_name;
const currentId = UserStore.getCurrentId();
const isAdmin = Utils.isAdmin(this.state.memberChannel.roles) || Utils.isAdmin(this.state.memberTeam.roles);
@@ -301,75 +318,82 @@ export default class ChannelHeader extends React.Component {
return (
<table className='channel-header alt'>
- <tr>
- <th>
- <div className='channel-header__info'>
- <div className='dropdown'>
+ <tbody>
+ <tr>
+ <th>
+ <div className='channel-header__info'>
+ <div className='dropdown'>
+ <a
+ href='#'
+ className='dropdown-toggle theme'
+ type='button'
+ id='channel_header_dropdown'
+ data-toggle='dropdown'
+ aria-expanded='true'
+ >
+ <strong className='heading'>{channelTitle} </strong>
+ <span className='glyphicon glyphicon-chevron-down header-dropdown__icon' />
+ </a>
+ <ul
+ className='dropdown-menu'
+ role='menu'
+ aria-labelledby='channel_header_dropdown'
+ >
+ {dropdownContents}
+ </ul>
+ </div>
+ <OverlayTrigger
+ trigger={['hover', 'focus']}
+ placement='bottom'
+ overlay={popoverContent}
+ ref='descriptionOverlay'
+ >
+ <div
+ onClick={TextFormatting.handleClick}
+ className='description'
+ dangerouslySetInnerHTML={{__html: TextFormatting.formatText(channel.description, {singleline: true, mentionHighlight: false})}}
+ />
+ </OverlayTrigger>
+ </div>
+ </th>
+ <th>
+ <PopoverListMembers
+ members={this.state.users}
+ channelId={channel.id}
+ />
+ </th>
+ <th className='search-bar__container'><NavbarSearchBox /></th>
+ <th>
+ <div className='dropdown channel-header__links'>
<a
href='#'
className='dropdown-toggle theme'
type='button'
- id='channel_header_dropdown'
+ id='channel_header_right_dropdown'
data-toggle='dropdown'
aria-expanded='true'
>
- <strong className='heading'>{channelTitle} </strong>
- <span className='glyphicon glyphicon-chevron-down header-dropdown__icon' />
+ <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} />
</a>
<ul
- className='dropdown-menu'
+ className='dropdown-menu dropdown-menu-right'
role='menu'
- aria-labelledby='channel_header_dropdown'
+ aria-labelledby='channel_header_right_dropdown'
>
- {dropdownContents}
+ <li role='presentation'>
+ <a
+ role='menuitem'
+ href='#'
+ onClick={this.searchMentions}
+ >
+ Recent Mentions
+ </a>
+ </li>
</ul>
</div>
- <div
- data-toggle='popover'
- data-content={popoverContent}
- className='description'
- onClick={TextFormatting.handleClick}
- dangerouslySetInnerHTML={{__html: TextFormatting.formatText(channel.description, {singleline: true, mentionHighlight: false})}}
- />
- </div>
- </th>
- <th>
- <PopoverListMembers
- members={this.state.users}
- channelId={channel.id}
- />
- </th>
- <th className='search-bar__container'><NavbarSearchBox /></th>
- <th>
- <div className='dropdown channel-header__links'>
- <a
- href='#'
- className='dropdown-toggle theme'
- type='button'
- id='channel_header_right_dropdown'
- data-toggle='dropdown'
- aria-expanded='true'
- >
- <span dangerouslySetInnerHTML={{__html: Constants.MENU_ICON}} />
- </a>
- <ul
- className='dropdown-menu dropdown-menu-right'
- role='menu'
- aria-labelledby='channel_header_right_dropdown'
- >
- <li role='presentation'>
- <a
- role='menuitem'
- href='#'
- onClick={this.searchMentions}
- >
- Recent Mentions
- </a>
- </li>
- </ul>
- </div>
- </th>
- </tr>
+ </th>
+ </tr>
+ </tbody>
</table>
);
}
diff --git a/web/react/components/channel_info_modal.jsx b/web/react/components/channel_info_modal.jsx
index d6de958e7..bccd8d0b9 100644
--- a/web/react/components/channel_info_modal.jsx
+++ b/web/react/components/channel_info_modal.jsx
@@ -15,7 +15,7 @@ export default class CommandList extends React.Component {
componentDidMount() {
var self = this;
if (this.refs.modal) {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function show(e) {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function show(e) {
var button = e.relatedTarget;
self.setState({channel_id: $(button).attr('data-channelid')});
});
diff --git a/web/react/components/channel_invite_modal.jsx b/web/react/components/channel_invite_modal.jsx
index 1e621c683..7c7770095 100644
--- a/web/react/components/channel_invite_modal.jsx
+++ b/web/react/components/channel_invite_modal.jsx
@@ -56,8 +56,8 @@ export default class ChannelInviteModal extends React.Component {
};
}
componentDidMount() {
- $(React.findDOMNode(this)).on('hidden.bs.modal', this.onHide);
- $(React.findDOMNode(this)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this)).on('hidden.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this)).on('show.bs.modal', this.onShow);
ChannelStore.addExtraInfoChangeListener(this.onListenerChange);
ChannelStore.addChangeListener(this.onListenerChange);
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/channel_members.jsx b/web/react/components/channel_members.jsx
index 0cd384977..86cc2464d 100644
--- a/web/react/components/channel_members.jsx
+++ b/web/react/components/channel_members.jsx
@@ -74,9 +74,9 @@ export default class ChannelMembers extends React.Component {
componentDidMount() {
ChannelStore.addExtraInfoChangeListener(this.onChange);
ChannelStore.addChangeListener(this.onChange);
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.onHide);
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
}
componentWillUnmount() {
ChannelStore.removeExtraInfoChangeListener(this.onChange);
diff --git a/web/react/components/channel_notifications.jsx b/web/react/components/channel_notifications.jsx
index 2114be905..6151d4bdd 100644
--- a/web/react/components/channel_notifications.jsx
+++ b/web/react/components/channel_notifications.jsx
@@ -51,7 +51,7 @@ export default class ChannelNotifications extends React.Component {
componentDidMount() {
ChannelStore.addChangeListener(this.onListenerChange);
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
}
componentWillUnmount() {
ChannelStore.removeChangeListener(this.onListenerChange);
@@ -104,7 +104,7 @@ export default class ChannelNotifications extends React.Component {
}
handleUpdateNotifyLevel(notifyLevel) {
this.setState({notifyLevel});
- React.findDOMNode(this.refs.modal).focus();
+ ReactDOM.findDOMNode(this.refs.modal).focus();
}
createNotifyLevelSection(serverError) {
var handleUpdateSection;
@@ -266,7 +266,7 @@ export default class ChannelNotifications extends React.Component {
handleUpdateMarkUnreadLevel(markUnreadLevel) {
this.setState({markUnreadLevel});
- React.findDOMNode(this.refs.modal).focus();
+ ReactDOM.findDOMNode(this.refs.modal).focus();
}
createMarkUnreadLevelSection(serverError) {
diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx
index 680d693f1..2df3dc40f 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) {
@@ -126,7 +128,7 @@ export default class CreateComment extends React.Component {
commentMsgKeyPress(e) {
if (e.which === 13 && !e.shiftKey && !e.altKey) {
e.preventDefault();
- React.findDOMNode(this.refs.textbox).blur();
+ ReactDOM.findDOMNode(this.refs.textbox).blur();
this.handleSubmit(e);
}
@@ -189,7 +191,7 @@ export default class CreateComment extends React.Component {
handleTextDrop(text) {
const newText = this.state.messageText + text;
this.handleUserInput(newText);
- Utils.setCaretPosition(React.findDOMNode(this.refs.textbox.refs.message), newText.length);
+ Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length);
}
removePreview(id) {
let previews = this.state.previews;
@@ -255,6 +257,17 @@ export default class CreateComment extends React.Component {
postFooterClassName += ' has-error';
}
+ let uploadsInProgressText = null;
+ if (this.state.uploadsInProgress.length > 0) {
+ uploadsInProgressText = (
+ <span
+ className='pull-right post-right-comments-upload-in-progress'
+ >
+ {this.state.uploadsInProgress.length === 1 ? 'File uploading' : 'Files uploading'}
+ </span>
+ );
+ }
+
return (
<form onSubmit={this.handleSubmit}>
<div className='post-create'>
@@ -295,6 +308,7 @@ export default class CreateComment extends React.Component {
value='Add Comment'
onClick={this.handleSubmit}
/>
+ {uploadsInProgressText}
{postError}
{serverError}
</div>
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index f35079383..2581bdcca 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -16,6 +16,7 @@ const Utils = require('../utils/utils.jsx');
const Constants = require('../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
+const KeyCodes = Constants.KeyCodes;
export default class CreatePost extends React.Component {
constructor(props) {
@@ -35,6 +36,7 @@ export default class CreatePost extends React.Component {
this.removePreview = this.removePreview.bind(this);
this.onChange = this.onChange.bind(this);
this.getFileCount = this.getFileCount.bind(this);
+ this.handleArrowUp = this.handleArrowUp.bind(this);
PostStore.clearDraftUploads();
@@ -172,9 +174,9 @@ export default class CreatePost extends React.Component {
}
}
postMsgKeyPress(e) {
- if (e.which === 13 && !e.shiftKey && !e.altKey) {
+ if (e.which === KeyCodes.ENTER && !e.shiftKey && !e.altKey) {
e.preventDefault();
- React.findDOMNode(this.refs.textbox).blur();
+ ReactDOM.findDOMNode(this.refs.textbox).blur();
this.handleSubmit(e);
}
@@ -192,7 +194,7 @@ export default class CreatePost extends React.Component {
PostStore.storeCurrentDraft(draft);
}
resizePostHolder() {
- const height = $(window).height() - $(React.findDOMNode(this.refs.topDiv)).height() - 50;
+ const height = $(window).height() - $(ReactDOM.findDOMNode(this.refs.topDiv)).height() - 50;
$('.post-list-holder-by-time').css('height', `${height}px`);
$(window).trigger('resize');
if ($(window).width() > 960) {
@@ -243,7 +245,7 @@ export default class CreatePost extends React.Component {
handleTextDrop(text) {
const newText = this.state.messageText + text;
this.handleUserInput(newText);
- Utils.setCaretPosition(React.findDOMNode(this.refs.textbox.refs.message), newText.length);
+ Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.textbox.refs.message), newText.length);
}
removePreview(id) {
const previews = Object.assign([], this.state.previews);
@@ -292,6 +294,27 @@ export default class CreatePost extends React.Component {
const draft = PostStore.getDraft(channelId);
return draft.previews.length + draft.uploadsInProgress.length;
}
+ handleArrowUp(e) {
+ if (e.keyCode === KeyCodes.UP && this.state.messageText === '') {
+ e.preventDefault();
+
+ const channelId = ChannelStore.getCurrentId();
+ const lastPost = PostStore.getCurrentUsersLatestPost(channelId);
+ if (!lastPost) {
+ return;
+ }
+ var type = (lastPost.root_id && lastPost.root_id.length > 0) ? 'Comment' : 'Post';
+
+ AppDispatcher.handleViewAction({
+ type: ActionTypes.RECIEVED_EDIT_POST,
+ refocusId: '#post_textbox',
+ title: type,
+ message: lastPost.message,
+ postId: lastPost.id,
+ channelId: lastPost.channel_id
+ });
+ }
+ }
render() {
let serverError = null;
if (this.state.serverError) {
@@ -336,6 +359,7 @@ export default class CreatePost extends React.Component {
<Textbox
onUserInput={this.handleUserInput}
onKeyPress={this.postMsgKeyPress}
+ onKeyDown={this.handleArrowUp}
onHeightChange={this.resizePostHolder}
messageText={this.state.messageText}
createMessage='Write a message...'
diff --git a/web/react/components/delete_channel_modal.jsx b/web/react/components/delete_channel_modal.jsx
index 9358c98d7..b7d633b38 100644
--- a/web/react/components/delete_channel_modal.jsx
+++ b/web/react/components/delete_channel_modal.jsx
@@ -41,7 +41,7 @@ export default class DeleteChannelModal extends React.Component {
});
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
}
render() {
const channel = ChannelStore.getCurrent();
diff --git a/web/react/components/delete_post_modal.jsx b/web/react/components/delete_post_modal.jsx
index ea7d76b1e..3a3dabce5 100644
--- a/web/react/components/delete_post_modal.jsx
+++ b/web/react/components/delete_post_modal.jsx
@@ -73,7 +73,7 @@ export default class DeletePostModal extends React.Component {
this.setState(newState);
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
PostStore.addSelectedPostChangeListener(this.onListenerChange);
}
componentWillUnmount() {
diff --git a/web/react/components/edit_channel_modal.jsx b/web/react/components/edit_channel_modal.jsx
index 6ccf12be6..d63a1db30 100644
--- a/web/react/components/edit_channel_modal.jsx
+++ b/web/react/components/edit_channel_modal.jsx
@@ -34,7 +34,7 @@ export default class EditChannelModal extends React.Component {
function handleUpdateSuccess() {
this.setState({serverError: ''});
AsyncClient.getChannel(this.state.channelId);
- $(React.findDOMNode(this.refs.modal)).modal('hide');
+ $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
}.bind(this),
function handleUpdateError(err) {
if (err.message === 'Invalid channel_description parameter') {
@@ -56,11 +56,11 @@ export default class EditChannelModal extends React.Component {
this.setState({description: $(button).attr('data-desc'), title: $(button).attr('data-title'), channelId: $(button).attr('data-channelid'), serverError: ''});
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
}
componentWillUnmount() {
- $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
}
render() {
var serverError = null;
diff --git a/web/react/components/edit_post_modal.jsx b/web/react/components/edit_post_modal.jsx
index 165a28a64..90d9696e7 100644
--- a/web/react/components/edit_post_modal.jsx
+++ b/web/react/components/edit_post_modal.jsx
@@ -5,6 +5,7 @@ var Client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var Textbox = require('./textbox.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
+var PostStore = require('../stores/post_store.jsx');
export default class EditPostModal extends React.Component {
constructor() {
@@ -14,6 +15,7 @@ export default class EditPostModal extends React.Component {
this.handleEditInput = this.handleEditInput.bind(this);
this.handleEditKeyPress = this.handleEditKeyPress.bind(this);
this.handleUserInput = this.handleUserInput.bind(this);
+ this.handleEditPostEvent = this.handleEditPostEvent.bind(this);
this.state = {editText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
}
@@ -35,16 +37,15 @@ export default class EditPostModal extends React.Component {
Client.updatePost(updatedPost,
function success() {
- AsyncClient.getPosts(this.state.channel_id);
+ AsyncClient.getPosts(updatedPost.channel_id);
window.scrollTo(0, 0);
- }.bind(this),
+ },
function error(err) {
AsyncClient.dispatchError(err, 'updatePost');
}
);
$('#edit_post').modal('hide');
- $(this.state.refocusId).focus();
}
handleEditInput(editMessage) {
this.setState({editText: editMessage});
@@ -52,28 +53,57 @@ export default class EditPostModal extends React.Component {
handleEditKeyPress(e) {
if (e.which === 13 && !e.shiftKey && !e.altKey) {
e.preventDefault();
- React.findDOMNode(this.refs.editbox).blur();
+ ReactDOM.findDOMNode(this.refs.editbox).blur();
this.handleEdit(e);
}
}
handleUserInput(e) {
this.setState({editText: e.target.value});
}
+ handleEditPostEvent(options) {
+ this.setState({
+ editText: options.message || '',
+ title: options.title || '',
+ post_id: options.postId || '',
+ channel_id: options.channelId || '',
+ comments: options.comments || 0,
+ refocusId: options.refocusId || ''
+ });
+
+ $(React.findDOMNode(this.refs.modal)).modal('show');
+ }
componentDidMount() {
var self = this;
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function onHidden() {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function onHidden() {
self.setState({editText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''});
});
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function onShow(e) {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function onShow(e) {
var button = e.relatedTarget;
+ if (!button) {
+ return;
+ }
self.setState({editText: $(button).attr('data-message'), title: $(button).attr('data-title'), channel_id: $(button).attr('data-channelid'), post_id: $(button).attr('data-postid'), comments: $(button).attr('data-comments'), refocusId: $(button).attr('data-refoucsid')});
});
- $(React.findDOMNode(this.refs.modal)).on('shown.bs.modal', function onShown() {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', function onShown() {
self.refs.editbox.resize();
+ $('#edit_textbox').get(0).focus();
});
+
+ $(React.findDOMNode(this.refs.modal)).on('hide.bs.modal', function onShown() {
+ if (self.state.refocusId !== '') {
+ setTimeout(() => {
+ $(self.state.refocusId).get(0).focus();
+ });
+ }
+ });
+
+ PostStore.addEditPostListener(this.handleEditPostEvent);
+ }
+ componentWillUnmount() {
+ PostStore.removeEditPostListener(this.handleEditPostEvent);
}
render() {
var error = (<div className='form-group'><br /></div>);
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/file_attachment.jsx b/web/react/components/file_attachment.jsx
index 659da4f5e..c6dff6550 100644
--- a/web/react/components/file_attachment.jsx
+++ b/web/react/components/file_attachment.jsx
@@ -43,7 +43,7 @@ export default class FileAttachment extends React.Component {
return function loader() {
$(this).remove();
if (name in self.refs) {
- var imgDiv = React.findDOMNode(self.refs[name]);
+ var imgDiv = ReactDOM.findDOMNode(self.refs[name]);
$(imgDiv).removeClass('post__load');
$(imgDiv).addClass('post__image');
@@ -82,7 +82,7 @@ export default class FileAttachment extends React.Component {
if (nextState.fileSize !== this.state.fileSize) {
if (this.refs.fileSize) {
// update the UI element to display the file size without re-rendering the whole component
- React.findDOMNode(this.refs.fileSize).innerHTML = utils.fileSizeToString(nextState.fileSize);
+ ReactDOM.findDOMNode(this.refs.fileSize).innerHTML = utils.fileSizeToString(nextState.fileSize);
return false;
}
diff --git a/web/react/components/file_upload.jsx b/web/react/components/file_upload.jsx
index e947fc50c..8854a54df 100644
--- a/web/react/components/file_upload.jsx
+++ b/web/react/components/file_upload.jsx
@@ -86,7 +86,7 @@ export default class FileUpload extends React.Component {
}
handleChange() {
- var element = $(React.findDOMNode(this.refs.fileInput));
+ var element = $(ReactDOM.findDOMNode(this.refs.fileInput));
this.uploadFiles(element.prop('files'));
@@ -115,7 +115,7 @@ export default class FileUpload extends React.Component {
}
componentDidMount() {
- var inputDiv = React.findDOMNode(this.refs.input);
+ var inputDiv = ReactDOM.findDOMNode(this.refs.input);
var self = this;
if (this.props.postType === 'post') {
diff --git a/web/react/components/find_team.jsx b/web/react/components/find_team.jsx
index 9e3e3a683..e324f3666 100644
--- a/web/react/components/find_team.jsx
+++ b/web/react/components/find_team.jsx
@@ -17,7 +17,7 @@ export default class FindTeam extends React.Component {
var state = { };
- var email = React.findDOMNode(this.refs.email).value.trim().toLowerCase();
+ var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
if (!email || !utils.isEmail(email)) {
state.email_error = 'Please enter a valid email address';
this.setState(state);
diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx
index eb6bfa9b6..325e86f3d 100644
--- a/web/react/components/get_link_modal.jsx
+++ b/web/react/components/get_link_modal.jsx
@@ -22,12 +22,12 @@ export default class GetLinkModal extends React.Component {
}
componentDidMount() {
if (this.refs.modal) {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
- $(React.findDOMNode(this.refs.modal)).on('hide.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.onShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hide.bs.modal', this.onHide);
}
}
handleClick() {
- var copyTextarea = $(React.findDOMNode(this.refs.textarea));
+ var copyTextarea = $(ReactDOM.findDOMNode(this.refs.textarea));
copyTextarea.select();
try {
diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx
index c2f2c15ac..90290099d 100644
--- a/web/react/components/invite_member_modal.jsx
+++ b/web/react/components/invite_member_modal.jsx
@@ -36,7 +36,7 @@ export default class InviteMemberModal extends React.Component {
var notEmpty = false;
for (var i = 0; i < self.state.inviteIds.length; i++) {
var index = self.state.inviteIds[i];
- if (React.findDOMNode(self.refs['email' + index]).value.trim() !== '') {
+ if (ReactDOM.findDOMNode(self.refs['email' + index]).value.trim() !== '') {
notEmpty = true;
break;
}
@@ -69,7 +69,7 @@ export default class InviteMemberModal extends React.Component {
for (var i = 0; i < count; i++) {
var index = inviteIds[i];
var invite = {};
- invite.email = React.findDOMNode(this.refs['email' + index]).value.trim();
+ invite.email = ReactDOM.findDOMNode(this.refs['email' + index]).value.trim();
if (!invite.email || !utils.isEmail(invite.email)) {
emailErrors[index] = 'Please enter a valid email address';
valid = false;
@@ -77,9 +77,9 @@ export default class InviteMemberModal extends React.Component {
emailErrors[index] = '';
}
- invite.firstName = React.findDOMNode(this.refs['first_name' + index]).value.trim();
+ invite.firstName = ReactDOM.findDOMNode(this.refs['first_name' + index]).value.trim();
- invite.lastName = React.findDOMNode(this.refs['last_name' + index]).value.trim();
+ invite.lastName = ReactDOM.findDOMNode(this.refs['last_name' + index]).value.trim();
invites.push(invite);
}
@@ -95,8 +95,8 @@ export default class InviteMemberModal extends React.Component {
Client.inviteMembers(data,
function success() {
- $(React.findDOMNode(this.refs.modal)).attr('data-confirm', 'true');
- $(React.findDOMNode(this.refs.modal)).modal('hide');
+ $(ReactDOM.findDOMNode(this.refs.modal)).attr('data-confirm', 'true');
+ $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
}.bind(this),
function fail(err) {
if (err.message === 'This person is already on your team') {
@@ -110,8 +110,8 @@ export default class InviteMemberModal extends React.Component {
}
componentDidUpdate() {
- $(React.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 200);
- $(React.findDOMNode(this.refs.modalBody)).css('overflow-y', 'scroll');
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('max-height', $(window).height() - 200);
+ $(ReactDOM.findDOMNode(this.refs.modalBody)).css('overflow-y', 'scroll');
}
addInviteFields() {
@@ -126,9 +126,9 @@ export default class InviteMemberModal extends React.Component {
for (var i = 0; i < inviteIds.length; i++) {
var index = inviteIds[i];
- React.findDOMNode(this.refs['email' + index]).value = '';
- React.findDOMNode(this.refs['first_name' + index]).value = '';
- React.findDOMNode(this.refs['last_name' + index]).value = '';
+ ReactDOM.findDOMNode(this.refs['email' + index]).value = '';
+ ReactDOM.findDOMNode(this.refs['first_name' + index]).value = '';
+ ReactDOM.findDOMNode(this.refs['last_name' + index]).value = '';
}
this.setState({
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index f81822e1e..c982d57ca 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -25,14 +25,14 @@ export default class Login extends React.Component {
return;
}
- const email = React.findDOMNode(this.refs.email).value.trim();
+ const email = ReactDOM.findDOMNode(this.refs.email).value.trim();
if (!email) {
state.serverError = 'An email is required';
this.setState(state);
return;
}
- const password = React.findDOMNode(this.refs.password).value.trim();
+ const password = ReactDOM.findDOMNode(this.refs.password).value.trim();
if (!password) {
state.serverError = 'A password is required';
this.setState(state);
diff --git a/web/react/components/mention_list.jsx b/web/react/components/mention_list.jsx
index b9ba5f58c..8c1da942d 100644
--- a/web/react/components/mention_list.jsx
+++ b/web/react/components/mention_list.jsx
@@ -61,7 +61,7 @@ export default class MentionList extends React.Component {
}
onClick(e) {
if (!($('#' + this.props.id).is(e.target) || $('#' + this.props.id).has(e.target).length ||
- ('mentionlist' in this.refs && $(React.findDOMNode(this.refs.mentionlist)).has(e.target).length))) {
+ ('mentionlist' in this.refs && $(ReactDOM.findDOMNode(this.refs.mentionlist)).has(e.target).length))) {
this.setState({mentionText: '-1'});
}
}
diff --git a/web/react/components/more_channels.jsx b/web/react/components/more_channels.jsx
index 884b0d6ca..a20c5cad5 100644
--- a/web/react/components/more_channels.jsx
+++ b/web/react/components/more_channels.jsx
@@ -31,12 +31,12 @@ export default class MoreChannels extends React.Component {
}
componentDidMount() {
ChannelStore.addMoreChangeListener(this.onListenerChange);
- $(React.findDOMNode(this.refs.modal)).on('shown.bs.modal', function shown() {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', function shown() {
asyncClient.getMoreChannels(true);
});
var self = this;
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function show(e) {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function show(e) {
var button = e.relatedTarget;
self.setState({channelType: $(button).attr('data-channeltype')});
});
@@ -54,7 +54,7 @@ export default class MoreChannels extends React.Component {
this.setState({joiningChannel: channelIndex});
client.joinChannel(channel.id,
function joinSuccess() {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
+ $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
asyncClient.getChannel(channel.id);
utils.switchChannel(channel);
this.setState({joiningChannel: -1});
@@ -65,7 +65,7 @@ export default class MoreChannels extends React.Component {
);
}
handleNewChannel() {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
+ $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
this.setState({showNewChannelModal: true});
}
render() {
diff --git a/web/react/components/more_direct_channels.jsx b/web/react/components/more_direct_channels.jsx
index bc610cd60..08b64de8b 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 = ReactDOM.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/navbar.jsx b/web/react/components/navbar.jsx
index 6503bd801..f9cd525fd 100644
--- a/web/react/components/navbar.jsx
+++ b/web/react/components/navbar.jsx
@@ -14,6 +14,9 @@ var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+var Popover = ReactBootstrap.Popover;
+var OverlayTrigger = ReactBootstrap.OverlayTrigger;
+
export default class Navbar extends React.Component {
constructor(props) {
super(props);
@@ -36,12 +39,6 @@ export default class Navbar extends React.Component {
ChannelStore.addChangeListener(this.onChange);
ChannelStore.addExtraInfoChangeListener(this.onChange);
$('.inner__wrap').click(this.hideSidebars);
-
- $('body').on('click.infopopover', function handlePopoverClick(e) {
- if ($(e.target).attr('data-toggle') !== 'popover' && $(e.target).parents('.popover.in').length === 0) {
- $('.info-popover').popover('hide');
- }
- });
}
componentWillUnmount() {
ChannelStore.removeChangeListener(this.onChange);
@@ -224,11 +221,15 @@ export default class Navbar extends React.Component {
return (
<div className='navbar-brand'>
<div className='dropdown'>
- <div
- data-toggle='popover'
- data-content={popoverContent}
- className='description info-popover'
- />
+ <OverlayTrigger
+ trigger='click'
+ placement='bottom'
+ overlay={popoverContent}
+ className='description'
+ rootClose={true}
+ >
+ <div className='description info-popover'/>
+ </OverlayTrigger>
<a
href='#'
className='dropdown-toggle theme'
@@ -330,11 +331,17 @@ export default class Navbar extends React.Component {
var isDirect = false;
if (channel) {
- popoverContent = React.renderToString(
- <MessageWrapper
- message={channel.description}
- options={{singleline: true, mentionHighlight: false}}
- />
+ popoverContent = (
+ <Popover
+ bsStyle='info'
+ placement='bottom'
+ id='description-popover'
+ >
+ <MessageWrapper
+ message={channel.description}
+ options={{singleline: true, mentionHighlight: false}}
+ />
+ </Popover>
);
isAdmin = Utils.isAdmin(this.state.member.roles);
@@ -354,19 +361,28 @@ export default class Navbar extends React.Component {
}
if (channel.description.length === 0) {
- popoverContent = React.renderToString(
- <div>
- No channel description yet. <br/>
- <a
- href='#'
- data-toggle='modal'
- data-desc={channel.description}
- data-title={channel.display_name}
- data-channelid={channel.id}
- data-target='#edit_channel'
- >
- Click here
- </a> to add one.</div>
+ popoverContent = (
+ <Popover
+ bsStyle='info'
+ placement='bottom'
+ id='description-popover'
+ >
+ <div>
+ {'No channel description yet.'}
+ <br/>
+ <a
+ href='#'
+ data-toggle='modal'
+ data-desc={channel.description}
+ data-title={channel.display_name}
+ data-channelid={channel.id}
+ data-target='#edit_channel'
+ >
+ {'Click here'}
+ </a>
+ {' to add one.'}
+ </div>
+ </Popover>
);
}
}
diff --git a/web/react/components/navbar_dropdown.jsx b/web/react/components/navbar_dropdown.jsx
index dc41775c7..1cb13bbe5 100644
--- a/web/react/components/navbar_dropdown.jsx
+++ b/web/react/components/navbar_dropdown.jsx
@@ -57,7 +57,7 @@ export default class NavbarDropdown extends React.Component {
UserStore.addTeamsChangeListener(this.onListenerChange);
TeamStore.addChangeListener(this.onListenerChange);
- $(React.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
+ $(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
this.blockToggle = true;
setTimeout(() => {
this.blockToggle = false;
@@ -68,7 +68,7 @@ export default class NavbarDropdown extends React.Component {
UserStore.removeTeamsChangeListener(this.onListenerChange);
TeamStore.removeChangeListener(this.onListenerChange);
- $(React.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
+ $(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
}
onListenerChange() {
var newState = getStateFromStores();
diff --git a/web/react/components/new_channel_modal.jsx b/web/react/components/new_channel_modal.jsx
index c3d9c046d..4e6280c99 100644
--- a/web/react/components/new_channel_modal.jsx
+++ b/web/react/components/new_channel_modal.jsx
@@ -25,7 +25,7 @@ export default class NewChannelModal extends React.Component {
handleSubmit(e) {
e.preventDefault();
- const displayName = React.findDOMNode(this.refs.display_name).value.trim();
+ const displayName = ReactDOM.findDOMNode(this.refs.display_name).value.trim();
if (displayName.length < 1) {
this.setState({displayNameError: 'This field is required'});
return;
@@ -35,8 +35,8 @@ export default class NewChannelModal extends React.Component {
}
handleChange() {
const newData = {
- displayName: React.findDOMNode(this.refs.display_name).value,
- description: React.findDOMNode(this.refs.channel_desc).value
+ displayName: ReactDOM.findDOMNode(this.refs.display_name).value,
+ description: ReactDOM.findDOMNode(this.refs.channel_desc).value
};
this.props.onDataChanged(newData);
}
diff --git a/web/react/components/password_reset_form.jsx b/web/react/components/password_reset_form.jsx
index 6112adbaf..217f1b393 100644
--- a/web/react/components/password_reset_form.jsx
+++ b/web/react/components/password_reset_form.jsx
@@ -15,7 +15,7 @@ export default class PasswordResetForm extends React.Component {
e.preventDefault();
var state = {};
- var password = React.findDOMNode(this.refs.password).value.trim();
+ var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
if (!password || password.length < 5) {
state.error = 'Please enter at least 5 characters.';
this.setState(state);
diff --git a/web/react/components/password_reset_send_link.jsx b/web/react/components/password_reset_send_link.jsx
index f547499b0..8f1890705 100644
--- a/web/react/components/password_reset_send_link.jsx
+++ b/web/react/components/password_reset_send_link.jsx
@@ -16,7 +16,7 @@ export default class PasswordResetSendLink extends React.Component {
e.preventDefault();
var state = {};
- var email = React.findDOMNode(this.refs.email).value.trim().toLowerCase();
+ var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
if (!email || !Utils.isEmail(email)) {
state.error = 'Please enter a valid email address.';
this.setState(state);
@@ -33,7 +33,7 @@ export default class PasswordResetSendLink extends React.Component {
client.sendPasswordReset(data,
function passwordResetSent() {
this.setState({error: null, updateText: <p>A password reset link has been sent to <b>{email}</b> for your <b>{this.props.teamDisplayName}</b> team on {window.location.hostname}.</p>, moreUpdateText: 'Please check your inbox.'});
- $(React.findDOMNode(this.refs.reset_form)).hide();
+ $(ReactDOM.findDOMNode(this.refs.reset_form)).hide();
}.bind(this),
function passwordResetFailedToSend(err) {
this.setState({error: err.message, update_text: null, moreUpdateText: null});
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/post_body.jsx b/web/react/components/post_body.jsx
index e87ac6743..1db0b12e7 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -37,7 +37,7 @@ export default class PostBody extends React.Component {
}
parseEmojis() {
- twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE});
}
componentDidMount() {
diff --git a/web/react/components/post_deleted_modal.jsx b/web/react/components/post_deleted_modal.jsx
index 87afc6a7f..ba07a22f5 100644
--- a/web/react/components/post_deleted_modal.jsx
+++ b/web/react/components/post_deleted_modal.jsx
@@ -15,7 +15,7 @@ export default class PostDeletedModal extends React.Component {
this.state = {};
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', () => {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', () => {
this.handleClose();
});
}
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index 643b38af5..7e5160c2b 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -107,7 +107,7 @@ export default class PostList extends React.Component {
UserStore.addStatusesChangeListener(this.onTimeChange);
SocketStore.addChangeListener(this.onSocketChange);
- const postHolder = $(React.findDOMNode(this.refs.postlist));
+ const postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
$(window).resize(() => {
this.resize();
@@ -133,7 +133,7 @@ export default class PostList extends React.Component {
$('.top-visible-post').removeClass('top-visible-post');
- $(React.findDOMNode(this.refs.postlistcontent)).children().each(function select() {
+ $(ReactDOM.findDOMNode(this.refs.postlistcontent)).children().each(function select() {
if ($(this).position().top + $(this).height() / 2 > 0) {
$(this).addClass('top-visible-post');
return false;
@@ -158,7 +158,7 @@ export default class PostList extends React.Component {
SocketStore.removeChangeListener(this.onSocketChange);
$('body').off('click.userpopover');
$(window).off('resize');
- var postHolder = $(React.findDOMNode(this.refs.postlist));
+ var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
postHolder.off('scroll');
}
componentDidUpdate(prevProps, prevState) {
@@ -214,7 +214,7 @@ export default class PostList extends React.Component {
}
}
componentWillUpdate() {
- var postHolder = $(React.findDOMNode(this.refs.postlist));
+ var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
this.prevScrollTop = postHolder.scrollTop();
}
componentWillReceiveProps(nextProps) {
@@ -225,7 +225,7 @@ export default class PostList extends React.Component {
}
}
resize() {
- const postHolder = $(React.findDOMNode(this.refs.postlist));
+ const postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
if ($('#create_post').length > 0) {
const height = $(window).height() - $('#create_post').height() - $('#error_bar').outerHeight() - 50;
postHolder.css('height', height + 'px');
@@ -233,12 +233,12 @@ export default class PostList extends React.Component {
}
scrollTo(val) {
this.isUserScroll = false;
- var postHolder = $(React.findDOMNode(this.refs.postlist));
+ var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
postHolder[0].scrollTop = val;
}
scrollToBottom(force) {
this.isUserScroll = false;
- var postHolder = $(React.findDOMNode(this.refs.postlist));
+ var postHolder = $(ReactDOM.findDOMNode(this.refs.postlist));
if ($('#new_message_' + this.props.channelId)[0] && !this.userHasSeenNew && !force) {
$('#new_message_' + this.props.channelId)[0].scrollIntoView();
} else {
@@ -596,14 +596,14 @@ export default class PostList extends React.Component {
var order = this.state.postList.order;
var channelId = this.props.channelId;
- $(React.findDOMNode(this.refs.loadmore)).text('Retrieving more messages...');
+ $(ReactDOM.findDOMNode(this.refs.loadmore)).text('Retrieving more messages...');
Client.getPostsPage(
channelId,
order.length,
Constants.POST_CHUNK_SIZE,
function success(data) {
- $(React.findDOMNode(this.refs.loadmore)).text('Load more messages');
+ $(ReactDOM.findDOMNode(this.refs.loadmore)).text('Load more messages');
this.gotMorePosts = true;
this.setState({numToDisplay: this.state.numToDisplay + Constants.POST_CHUNK_SIZE});
@@ -628,7 +628,7 @@ export default class PostList extends React.Component {
Client.getProfiles();
}.bind(this),
function fail(err) {
- $(React.findDOMNode(this.refs.loadmore)).text('Load more messages');
+ $(ReactDOM.findDOMNode(this.refs.loadmore)).text('Load more messages');
AsyncClient.dispatchError(err, 'getPosts');
}.bind(this)
);
diff --git a/web/react/components/register_app_modal.jsx b/web/react/components/register_app_modal.jsx
index e93c44126..3d4d9bf45 100644
--- a/web/react/components/register_app_modal.jsx
+++ b/web/react/components/register_app_modal.jsx
@@ -14,7 +14,7 @@ export default class RegisterAppModal extends React.Component {
this.state = {clientId: '', clientSecret: '', saved: false};
}
componentDidMount() {
- $(React.findDOMNode(this)).on('hide.bs.modal', this.onHide);
+ $(ReactDOM.findDOMNode(this)).on('hide.bs.modal', this.onHide);
}
register() {
var state = this.state;
@@ -22,7 +22,7 @@ export default class RegisterAppModal extends React.Component {
var app = {};
- var name = this.refs.name.getDOMNode().value;
+ var name = this.refs.name.value;
if (!name || name.length === 0) {
state.nameError = 'Application name must be filled in.';
this.setState(state);
@@ -31,7 +31,7 @@ export default class RegisterAppModal extends React.Component {
state.nameError = null;
app.name = name;
- var homepage = this.refs.homepage.getDOMNode().value;
+ var homepage = this.refs.homepage.value;
if (!homepage || homepage.length === 0) {
state.homepageError = 'Homepage must be filled in.';
this.setState(state);
@@ -40,10 +40,10 @@ export default class RegisterAppModal extends React.Component {
state.homepageError = null;
app.homepage = homepage;
- var desc = this.refs.desc.getDOMNode().value;
+ var desc = this.refs.desc.value;
app.description = desc;
- var rawCallbacks = this.refs.callback.getDOMNode().value.trim();
+ var rawCallbacks = this.refs.callback.value.trim();
if (!rawCallbacks || rawCallbacks.length === 0) {
state.callbackError = 'At least one callback URL must be filled in.';
this.setState(state);
@@ -73,7 +73,7 @@ export default class RegisterAppModal extends React.Component {
this.setState({clientId: '', clientSecret: '', saved: false});
}
save() {
- this.setState({saved: this.refs.save.getDOMNode().checked});
+ this.setState({saved: this.refs.save.checked});
}
render() {
var nameError;
diff --git a/web/react/components/removed_from_channel_modal.jsx b/web/react/components/removed_from_channel_modal.jsx
index ca35d6fb0..7cf0a2ef1 100644
--- a/web/react/components/removed_from_channel_modal.jsx
+++ b/web/react/components/removed_from_channel_modal.jsx
@@ -37,13 +37,13 @@ export default class RemovedFromChannelModal extends React.Component {
}
componentDidMount() {
- $(React.findDOMNode(this)).on('show.bs.modal', this.handleShow);
- $(React.findDOMNode(this)).on('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this)).on('show.bs.modal', this.handleShow);
+ $(ReactDOM.findDOMNode(this)).on('hidden.bs.modal', this.handleClose);
}
componentWillUnmount() {
- $(React.findDOMNode(this)).off('show.bs.modal', this.handleShow);
- $(React.findDOMNode(this)).off('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this)).off('show.bs.modal', this.handleShow);
+ $(ReactDOM.findDOMNode(this)).off('hidden.bs.modal', this.handleClose);
}
render() {
diff --git a/web/react/components/rename_channel_modal.jsx b/web/react/components/rename_channel_modal.jsx
index 7f7d4554c..80f0956f2 100644
--- a/web/react/components/rename_channel_modal.jsx
+++ b/web/react/components/rename_channel_modal.jsx
@@ -76,13 +76,13 @@ export default class RenameChannelModal extends React.Component {
Client.updateChannel(channel,
function handleUpdateSuccess() {
- $(React.findDOMNode(this.refs.modal)).modal('hide');
+ $(ReactDOM.findDOMNode(this.refs.modal)).modal('hide');
AsyncClient.getChannel(channel.id);
Utils.updateAddressBar(channel.name);
- React.findDOMNode(this.refs.displayName).value = '';
- React.findDOMNode(this.refs.channelName).value = '';
+ ReactDOM.findDOMNode(this.refs.displayName).value = '';
+ ReactDOM.findDOMNode(this.refs.channelName).value = '';
}.bind(this),
function handleUpdateError(err) {
state.serverError = err.message;
@@ -92,15 +92,15 @@ export default class RenameChannelModal extends React.Component {
);
}
onNameChange() {
- this.setState({channelName: React.findDOMNode(this.refs.channelName).value});
+ this.setState({channelName: ReactDOM.findDOMNode(this.refs.channelName).value});
}
onDisplayNameChange() {
- this.setState({displayName: React.findDOMNode(this.refs.displayName).value});
+ this.setState({displayName: ReactDOM.findDOMNode(this.refs.displayName).value});
}
displayNameKeyUp() {
- const displayName = React.findDOMNode(this.refs.displayName).value.trim();
+ const displayName = ReactDOM.findDOMNode(this.refs.displayName).value.trim();
const channelName = Utils.cleanUpUrlable(displayName);
- React.findDOMNode(this.refs.channelName).value = channelName;
+ ReactDOM.findDOMNode(this.refs.channelName).value = channelName;
this.setState({channelName: channelName});
}
handleClose() {
@@ -119,11 +119,11 @@ export default class RenameChannelModal extends React.Component {
this.setState({displayName: button.attr('data-display'), channelName: button.attr('data-name'), channelId: button.attr('data-channelid')});
}
componentDidMount() {
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', this.handleShow);
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', this.handleShow);
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', this.handleClose);
}
componentWillUnmount() {
- $(React.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
+ $(ReactDOM.findDOMNode(this.refs.modal)).off('hidden.bs.modal', this.handleClose);
}
render() {
let displayNameError = null;
diff --git a/web/react/components/rhs_comment.jsx b/web/react/components/rhs_comment.jsx
index d1ed9b2c0..402e64080 100644
--- a/web/react/components/rhs_comment.jsx
+++ b/web/react/components/rhs_comment.jsx
@@ -55,7 +55,7 @@ export default class RhsComment extends React.Component {
this.forceUpdate();
}
parseEmojis() {
- twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE});
}
componentDidMount() {
this.parseEmojis();
diff --git a/web/react/components/rhs_root_post.jsx b/web/react/components/rhs_root_post.jsx
index 442d3483e..a9f1fcd30 100644
--- a/web/react/components/rhs_root_post.jsx
+++ b/web/react/components/rhs_root_post.jsx
@@ -19,7 +19,7 @@ export default class RhsRootPost extends React.Component {
this.state = {};
}
parseEmojis() {
- twemoji.parse(React.findDOMNode(this), {size: Constants.EMOJI_SIZE});
+ twemoji.parse(ReactDOM.findDOMNode(this), {size: Constants.EMOJI_SIZE});
}
componentDidMount() {
this.parseEmojis();
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_bar.jsx b/web/react/components/search_bar.jsx
index a6f9441ec..2e9764bd9 100644
--- a/web/react/components/search_bar.jsx
+++ b/web/react/components/search_bar.jsx
@@ -90,7 +90,7 @@ export default class SearchBar extends React.Component {
function success(data) {
this.setState({isSearching: false});
if (utils.isMobile()) {
- React.findDOMNode(this.refs.search).value = '';
+ ReactDOM.findDOMNode(this.refs.search).value = '';
}
AppDispatcher.handleServerAction({
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/setting_picture.jsx b/web/react/components/setting_picture.jsx
index c9031e67c..2f577fe39 100644
--- a/web/react/components/setting_picture.jsx
+++ b/web/react/components/setting_picture.jsx
@@ -12,7 +12,7 @@ export default class SettingPicture extends React.Component {
if (file) {
var reader = new FileReader();
- var img = React.findDOMNode(this.refs.image);
+ var img = ReactDOM.findDOMNode(this.refs.image);
reader.onload = function load(e) {
$(img).attr('src', e.target.result);
};
diff --git a/web/react/components/setting_upload.jsx b/web/react/components/setting_upload.jsx
index c7107b84d..a25789dff 100644
--- a/web/react/components/setting_upload.jsx
+++ b/web/react/components/setting_upload.jsx
@@ -37,7 +37,7 @@ export default class SettingsUpload extends React.Component {
doSubmit(e) {
e.preventDefault();
- var inputnode = React.findDOMNode(this.refs.uploadinput);
+ var inputnode = ReactDOM.findDOMNode(this.refs.uploadinput);
if (inputnode.files && inputnode.files[0]) {
this.props.submit(inputnode.files[0]);
} else {
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 4911f17ef..7a209de2b 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();
@@ -280,13 +284,13 @@ export default class Sidebar extends React.Component {
this.updateUnreadIndicators();
}
updateUnreadIndicators() {
- const container = $(React.findDOMNode(this.refs.container));
+ const container = $(ReactDOM.findDOMNode(this.refs.container));
var showTopUnread = false;
var showBottomUnread = false;
if (this.firstUnreadChannel) {
- var firstUnreadElement = $(React.findDOMNode(this.refs[this.firstUnreadChannel]));
+ var firstUnreadElement = $(ReactDOM.findDOMNode(this.refs[this.firstUnreadChannel]));
if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) {
showTopUnread = true;
@@ -294,7 +298,7 @@ export default class Sidebar extends React.Component {
}
if (this.lastUnreadChannel) {
- var lastUnreadElement = $(React.findDOMNode(this.refs[this.lastUnreadChannel]));
+ var lastUnreadElement = $(ReactDOM.findDOMNode(this.refs[this.lastUnreadChannel]));
if (lastUnreadElement.position().top > container.height()) {
showBottomUnread = true;
@@ -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/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index 98f862e69..f74c29d27 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -28,7 +28,7 @@ export default class SignupUserComplete extends React.Component {
handleSubmit(e) {
e.preventDefault();
- const providedEmail = React.findDOMNode(this.refs.email).value.trim();
+ const providedEmail = ReactDOM.findDOMNode(this.refs.email).value.trim();
if (!providedEmail) {
this.setState({nameError: '', emailError: 'This field is required', passwordError: ''});
return;
@@ -39,7 +39,7 @@ export default class SignupUserComplete extends React.Component {
return;
}
- const providedUsername = React.findDOMNode(this.refs.name).value.trim().toLowerCase();
+ const providedUsername = ReactDOM.findDOMNode(this.refs.name).value.trim().toLowerCase();
if (!providedUsername) {
this.setState({nameError: 'This field is required', emailError: '', passwordError: '', serverError: ''});
return;
@@ -59,7 +59,7 @@ export default class SignupUserComplete extends React.Component {
return;
}
- const providedPassword = React.findDOMNode(this.refs.password).value.trim();
+ const providedPassword = ReactDOM.findDOMNode(this.refs.password).value.trim();
if (!providedPassword || providedPassword.length < 5) {
this.setState({nameError: '', emailError: '', passwordError: 'Please enter at least 5 characters', serverError: ''});
return;
diff --git a/web/react/components/team_members.jsx b/web/react/components/team_members.jsx
index 0f60d93b2..33590c89a 100644
--- a/web/react/components/team_members.jsx
+++ b/web/react/components/team_members.jsx
@@ -44,11 +44,11 @@ export default class TeamMembers extends React.Component {
UserStore.addChangeListener(this.onChange);
var self = this;
- $(React.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function show() {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', function show() {
self.setState({render_members: false});
});
- $(React.findDOMNode(this.refs.modal)).on('show.bs.modal', function hide() {
+ $(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', function hide() {
self.setState({render_members: true});
});
}
diff --git a/web/react/components/team_signup_display_name_page.jsx b/web/react/components/team_signup_display_name_page.jsx
index c91ed0811..4d08274e4 100644
--- a/web/react/components/team_signup_display_name_page.jsx
+++ b/web/react/components/team_signup_display_name_page.jsx
@@ -21,7 +21,7 @@ export default class TeamSignupDisplayNamePage extends React.Component {
submitNext(e) {
e.preventDefault();
- var displayName = React.findDOMNode(this.refs.name).value.trim();
+ var displayName = ReactDOM.findDOMNode(this.refs.name).value.trim();
if (!displayName) {
this.setState({nameError: 'This field is required'});
return;
diff --git a/web/react/components/team_signup_email_item.jsx b/web/react/components/team_signup_email_item.jsx
index 7253e80e9..1d2b24ed7 100644
--- a/web/react/components/team_signup_email_item.jsx
+++ b/web/react/components/team_signup_email_item.jsx
@@ -13,10 +13,10 @@ export default class TeamSignupEmailItem extends React.Component {
this.state = {};
}
getValue() {
- return React.findDOMNode(this.refs.email).value.trim();
+ return ReactDOM.findDOMNode(this.refs.email).value.trim();
}
validate(teamEmail) {
- const email = React.findDOMNode(this.refs.email).value.trim().toLowerCase();
+ const email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
if (!email) {
return true;
diff --git a/web/react/components/team_signup_password_page.jsx b/web/react/components/team_signup_password_page.jsx
index cb9a9f05b..daa898b53 100644
--- a/web/react/components/team_signup_password_page.jsx
+++ b/web/react/components/team_signup_password_page.jsx
@@ -22,7 +22,7 @@ export default class TeamSignupPasswordPage extends React.Component {
submitNext(e) {
e.preventDefault();
- var password = React.findDOMNode(this.refs.password).value.trim();
+ var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
if (!password || password.length < 5) {
this.setState({passwordError: 'Please enter at least 5 characters'});
return;
diff --git a/web/react/components/team_signup_url_page.jsx b/web/react/components/team_signup_url_page.jsx
index 3fb0aaa27..67e4c9dd7 100644
--- a/web/react/components/team_signup_url_page.jsx
+++ b/web/react/components/team_signup_url_page.jsx
@@ -23,7 +23,7 @@ export default class TeamSignupUrlPage extends React.Component {
submitNext(e) {
e.preventDefault();
- const name = React.findDOMNode(this.refs.name).value.trim();
+ const name = ReactDOM.findDOMNode(this.refs.name).value.trim();
if (!name) {
this.setState({nameError: 'This field is required'});
return;
diff --git a/web/react/components/team_signup_username_page.jsx b/web/react/components/team_signup_username_page.jsx
index 82dabad3d..fa8a031a0 100644
--- a/web/react/components/team_signup_username_page.jsx
+++ b/web/react/components/team_signup_username_page.jsx
@@ -21,7 +21,7 @@ export default class TeamSignupUsernamePage extends React.Component {
submitNext(e) {
e.preventDefault();
- var name = React.findDOMNode(this.refs.name).value.trim().toLowerCase();
+ var name = ReactDOM.findDOMNode(this.refs.name).value.trim().toLowerCase();
var usernameError = Utils.isValidUsername(name);
if (usernameError === 'Cannot use a reserved word as a username.') {
diff --git a/web/react/components/team_signup_welcome_page.jsx b/web/react/components/team_signup_welcome_page.jsx
index 2d7ef081f..1e9d8df0a 100644
--- a/web/react/components/team_signup_welcome_page.jsx
+++ b/web/react/components/team_signup_welcome_page.jsx
@@ -36,7 +36,7 @@ export default class TeamSignupWelcomePage extends React.Component {
var state = {useDiff: true, serverError: ''};
- var email = React.findDOMNode(this.refs.email).value.trim().toLowerCase();
+ var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
if (!email || !Utils.isEmail(email)) {
state.emailError = 'Please enter a valid email address';
this.setState(state);
diff --git a/web/react/components/team_signup_with_email.jsx b/web/react/components/team_signup_with_email.jsx
index ba32a9f97..ff4ccd4d8 100644
--- a/web/react/components/team_signup_with_email.jsx
+++ b/web/react/components/team_signup_with_email.jsx
@@ -17,7 +17,7 @@ export default class EmailSignUpPage extends React.Component {
var team = {};
var state = {serverError: ''};
- team.email = React.findDOMNode(this.refs.email).value.trim().toLowerCase();
+ team.email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
if (!team.email || !Utils.isEmail(team.email)) {
state.emailError = 'Please enter a valid email address';
state.inValid = true;
diff --git a/web/react/components/team_signup_with_sso.jsx b/web/react/components/team_signup_with_sso.jsx
index 6ccf762c1..a0ccdf2c7 100644
--- a/web/react/components/team_signup_with_sso.jsx
+++ b/web/react/components/team_signup_with_sso.jsx
@@ -54,7 +54,7 @@ export default class SSOSignUpPage extends React.Component {
);
}
nameChange() {
- this.setState({name: React.findDOMNode(this.refs.teamname).value.trim()});
+ this.setState({name: ReactDOM.findDOMNode(this.refs.teamname).value.trim()});
}
render() {
var nameError = null;
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index 741dbcd5d..86bb42f62 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -9,6 +9,7 @@ const ErrorStore = require('../stores/error_store.jsx');
const Utils = require('../utils/utils.jsx');
const Constants = require('../utils/constants.jsx');
const ActionTypes = Constants.ActionTypes;
+const KeyCodes = Constants.KeyCodes;
export default class Textbox extends React.Component {
constructor(props) {
@@ -83,7 +84,7 @@ export default class Textbox extends React.Component {
componentDidUpdate() {
if (this.caret >= 0) {
- Utils.setCaretPosition(React.findDOMNode(this.refs.message), this.caret);
+ Utils.setCaretPosition(ReactDOM.findDOMNode(this.refs.message), this.caret);
this.caret = -1;
}
if (this.doProcessMentions) {
@@ -97,7 +98,7 @@ export default class Textbox extends React.Component {
if (!this.addedMention) {
this.checkForNewMention(nextProps.messageText);
}
- const text = React.findDOMNode(this.refs.message).value;
+ const text = ReactDOM.findDOMNode(this.refs.message).value;
if (nextProps.channelId !== this.props.channelId || nextProps.messageText !== text) {
this.doProcessMentions = true;
}
@@ -117,11 +118,11 @@ export default class Textbox extends React.Component {
}
handleChange() {
- this.props.onUserInput(React.findDOMNode(this.refs.message).value);
+ this.props.onUserInput(ReactDOM.findDOMNode(this.refs.message).value);
}
handleKeyPress(e) {
- const text = React.findDOMNode(this.refs.message).value;
+ const text = ReactDOM.findDOMNode(this.refs.message).value;
if (!this.refs.commands.isEmpty() && text.indexOf('/') === 0 && e.which === 13) {
this.refs.commands.addFirstCommand();
@@ -130,7 +131,7 @@ export default class Textbox extends React.Component {
}
if (!this.doProcessMentions) {
- const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const caret = Utils.getCaretPosition(ReactDOM.findDOMNode(this.refs.message));
const preText = text.substring(0, caret);
const lastSpace = preText.lastIndexOf(' ');
const lastAt = preText.lastIndexOf('@');
@@ -144,17 +145,19 @@ export default class Textbox extends React.Component {
}
handleKeyDown(e) {
- if (Utils.getSelectedText(React.findDOMNode(this.refs.message)) !== '') {
+ if (Utils.getSelectedText(ReactDOM.findDOMNode(this.refs.message)) !== '') {
this.doProcessMentions = true;
}
- if (e.keyCode === 8) {
+ if (e.keyCode === KeyCodes.BACKSPACE) {
this.handleBackspace(e);
+ } else if (this.props.onKeyDown) {
+ this.props.onKeyDown(e);
}
}
handleBackspace() {
- const text = React.findDOMNode(this.refs.message).value;
+ const text = ReactDOM.findDOMNode(this.refs.message).value;
if (text.indexOf('/') === 0) {
this.refs.commands.getSuggestedCommands(text.substring(0, text.length - 1));
}
@@ -163,7 +166,7 @@ export default class Textbox extends React.Component {
return;
}
- const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const caret = Utils.getCaretPosition(ReactDOM.findDOMNode(this.refs.message));
const preText = text.substring(0, caret);
const lastSpace = preText.lastIndexOf(' ');
const lastAt = preText.lastIndexOf('@');
@@ -174,7 +177,7 @@ export default class Textbox extends React.Component {
}
checkForNewMention(text) {
- const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const caret = Utils.getCaretPosition(ReactDOM.findDOMNode(this.refs.message));
const preText = text.substring(0, caret);
@@ -201,7 +204,7 @@ export default class Textbox extends React.Component {
}
addMention(name) {
- const caret = Utils.getCaretPosition(React.findDOMNode(this.refs.message));
+ const caret = Utils.getCaretPosition(ReactDOM.findDOMNode(this.refs.message));
const text = this.props.messageText;
@@ -224,14 +227,14 @@ export default class Textbox extends React.Component {
}
addCommand(cmd) {
- const elm = React.findDOMNode(this.refs.message);
+ const elm = ReactDOM.findDOMNode(this.refs.message);
elm.value = cmd;
this.handleChange();
}
resize() {
- const e = React.findDOMNode(this.refs.message);
- const w = React.findDOMNode(this.refs.wrapper);
+ const e = ReactDOM.findDOMNode(this.refs.message);
+ const w = ReactDOM.findDOMNode(this.refs.wrapper);
const prevHeight = $(e).height();
@@ -259,14 +262,14 @@ export default class Textbox extends React.Component {
}
handleFocus() {
- const elm = React.findDOMNode(this.refs.message);
+ const elm = ReactDOM.findDOMNode(this.refs.message);
if (elm.title === elm.value) {
elm.value = '';
}
}
handleBlur() {
- const elm = React.findDOMNode(this.refs.message);
+ const elm = ReactDOM.findDOMNode(this.refs.message);
if (elm.value === '') {
elm.value = elm.title;
}
@@ -318,5 +321,6 @@ Textbox.propTypes = {
onUserInput: React.PropTypes.func.isRequired,
onKeyPress: React.PropTypes.func.isRequired,
onHeightChange: React.PropTypes.func,
- createMessage: React.PropTypes.string.isRequired
+ createMessage: React.PropTypes.string.isRequired,
+ onKeyDown: React.PropTypes.func
};
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>
);
}
}
diff --git a/web/react/components/user_settings/import_theme_modal.jsx b/web/react/components/user_settings/import_theme_modal.jsx
index de0663874..1a9ac0ad3 100644
--- a/web/react/components/user_settings/import_theme_modal.jsx
+++ b/web/react/components/user_settings/import_theme_modal.jsx
@@ -35,7 +35,7 @@ export default class ImportThemeModal extends React.Component {
handleSubmit(e) {
e.preventDefault();
- const text = React.findDOMNode(this.refs.input).value;
+ const text = ReactDOM.findDOMNode(this.refs.input).value;
if (!this.isInputValid(text)) {
this.setState({inputError: 'Invalid format, please try copying and pasting in again.'});
diff --git a/web/react/components/user_settings/user_settings_appearance.jsx b/web/react/components/user_settings/user_settings_appearance.jsx
index a16440d55..7f363e92e 100644
--- a/web/react/components/user_settings/user_settings_appearance.jsx
+++ b/web/react/components/user_settings/user_settings_appearance.jsx
@@ -29,14 +29,14 @@ export default class UserSettingsAppearance extends React.Component {
UserStore.addChangeListener(this.onChange);
if (this.props.activeSection === 'theme') {
- $(React.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
+ $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
}
$('#user_settings').on('hidden.bs.modal', this.handleClose);
}
componentDidUpdate() {
if (this.props.activeSection === 'theme') {
$('.color-btn').removeClass('active-border');
- $(React.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
+ $(ReactDOM.findDOMNode(this.refs[this.state.theme])).addClass('active-border');
}
}
componentWillUnmount() {
diff --git a/web/react/components/user_settings/user_settings_general.jsx b/web/react/components/user_settings/user_settings_general.jsx
index 0e872315d..9c03f77a6 100644
--- a/web/react/components/user_settings/user_settings_general.jsx
+++ b/web/react/components/user_settings/user_settings_general.jsx
@@ -211,7 +211,7 @@ export default class UserSettingsGeneralTab extends React.Component {
this.props.updateSection(section);
}
handleClose() {
- $(React.findDOMNode(this)).find('.form-control').each(function clearForms() {
+ $(ReactDOM.findDOMNode(this)).find('.form-control').each(function clearForms() {
this.value = '';
});
diff --git a/web/react/components/user_settings/user_settings_notifications.jsx b/web/react/components/user_settings/user_settings_notifications.jsx
index 4728a33ee..4dbb9b96f 100644
--- a/web/react/components/user_settings/user_settings_notifications.jsx
+++ b/web/react/components/user_settings/user_settings_notifications.jsx
@@ -129,7 +129,7 @@ export default class NotificationsTab extends React.Component {
);
}
handleClose() {
- $(React.findDOMNode(this)).find('.form-control').each(function clearField() {
+ $(ReactDOM.findDOMNode(this)).find('.form-control').each(function clearField() {
this.value = '';
});
@@ -158,15 +158,15 @@ export default class NotificationsTab extends React.Component {
}
handleNotifyRadio(notifyLevel) {
this.setState({notifyLevel: notifyLevel});
- React.findDOMNode(this.refs.wrapper).focus();
+ ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
handleEmailRadio(enableEmail) {
this.setState({enableEmail: enableEmail});
- React.findDOMNode(this.refs.wrapper).focus();
+ ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
handleSoundRadio(enableSound) {
this.setState({enableSound: enableSound});
- React.findDOMNode(this.refs.wrapper).focus();
+ ReactDOM.findDOMNode(this.refs.wrapper).focus();
}
updateUsernameKey(val) {
this.setState({usernameKey: val});
@@ -184,10 +184,10 @@ export default class NotificationsTab extends React.Component {
this.setState({channelKey: val});
}
updateCustomMentionKeys() {
- var checked = React.findDOMNode(this.refs.customcheck).checked;
+ var checked = ReactDOM.findDOMNode(this.refs.customcheck).checked;
if (checked) {
- var text = React.findDOMNode(this.refs.custommentions).value;
+ var text = ReactDOM.findDOMNode(this.refs.custommentions).value;
// remove all spaces and split string into individual keys
this.setState({customKeys: text.replace(/ /g, ''), customKeysChecked: true});
@@ -196,7 +196,7 @@ export default class NotificationsTab extends React.Component {
}
}
onCustomChange() {
- React.findDOMNode(this.refs.customcheck).checked = true;
+ ReactDOM.findDOMNode(this.refs.customcheck).checked = true;
this.updateCustomMentionKeys();
}
render() {
diff --git a/web/react/components/user_settings/user_settings_security.jsx b/web/react/components/user_settings/user_settings_security.jsx
index 74190781c..983a10df0 100644
--- a/web/react/components/user_settings/user_settings_security.jsx
+++ b/web/react/components/user_settings/user_settings_security.jsx
@@ -82,7 +82,7 @@ export default class SecurityTab extends React.Component {
$('#user_settings').modal('hide');
}
handleClose() {
- $(React.findDOMNode(this)).find('.form-control').each(function resetValue() {
+ $(ReactDOM.findDOMNode(this)).find('.form-control').each(function resetValue() {
this.value = '';
});
this.setState({currentPassword: '', newPassword: '', confirmPassword: '', serverError: null, passwordError: null});
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index c5f0abc12..f75693470 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -77,7 +77,7 @@ export default class ViewImageModal extends React.Component {
}
onModalHidden() {
if (this.refs.video) {
- var video = React.findDOMNode(this.refs.video);
+ var video = ReactDOM.findDOMNode(this.refs.video);
video.pause();
video.currentTime = 0;
}