summaryrefslogtreecommitdiffstats
path: root/webapp/components
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/components')
-rw-r--r--webapp/components/activity_log_modal.jsx2
-rw-r--r--webapp/components/admin_console/admin_navbar_dropdown.jsx20
-rw-r--r--webapp/components/admin_console/admin_sidebar_header.jsx3
-rw-r--r--webapp/components/admin_console/compliance_reports.jsx4
-rw-r--r--webapp/components/admin_console/compliance_settings.jsx2
-rw-r--r--webapp/components/admin_console/email_settings.jsx2
-rw-r--r--webapp/components/admin_console/gitlab_settings.jsx2
-rw-r--r--webapp/components/admin_console/image_settings.jsx2
-rw-r--r--webapp/components/admin_console/ldap_settings.jsx32
-rw-r--r--webapp/components/admin_console/legal_and_support_settings.jsx2
-rw-r--r--webapp/components/admin_console/license_settings.jsx7
-rw-r--r--webapp/components/admin_console/log_settings.jsx2
-rw-r--r--webapp/components/admin_console/privacy_settings.jsx2
-rw-r--r--webapp/components/admin_console/rate_settings.jsx2
-rw-r--r--webapp/components/admin_console/reset_password_modal.jsx13
-rw-r--r--webapp/components/admin_console/service_settings.jsx2
-rw-r--r--webapp/components/admin_console/sql_settings.jsx2
-rw-r--r--webapp/components/admin_console/team_settings.jsx105
-rw-r--r--webapp/components/admin_console/team_users.jsx2
-rw-r--r--webapp/components/admin_console/user_item.jsx133
-rw-r--r--webapp/components/authorize.jsx2
-rw-r--r--webapp/components/backstage/add_command.jsx10
-rw-r--r--webapp/components/backstage/add_incoming_webhook.jsx5
-rw-r--r--webapp/components/backstage/add_outgoing_webhook.jsx7
-rw-r--r--webapp/components/backstage/backstage_navbar.jsx2
-rw-r--r--webapp/components/backstage/backstage_sidebar.jsx3
-rw-r--r--webapp/components/backstage/installed_commands.jsx3
-rw-r--r--webapp/components/backstage/installed_incoming_webhook.jsx11
-rw-r--r--webapp/components/backstage/installed_incoming_webhooks.jsx3
-rw-r--r--webapp/components/backstage/installed_outgoing_webhooks.jsx3
-rw-r--r--webapp/components/backstage/integrations.jsx7
-rw-r--r--webapp/components/channel_header.jsx2
-rw-r--r--webapp/components/channel_info_modal.jsx30
-rw-r--r--webapp/components/channel_invite_button.jsx8
-rw-r--r--webapp/components/channel_members_modal.jsx7
-rw-r--r--webapp/components/channel_notifications_modal.jsx6
-rw-r--r--webapp/components/channel_select.jsx2
-rw-r--r--webapp/components/claim/claim.jsx32
-rw-r--r--webapp/components/claim/components/email_to_ldap.jsx47
-rw-r--r--webapp/components/claim/components/email_to_oauth.jsx23
-rw-r--r--webapp/components/claim/components/ldap_to_email.jsx33
-rw-r--r--webapp/components/claim/components/oauth_to_email.jsx18
-rw-r--r--webapp/components/create_comment.jsx3
-rw-r--r--webapp/components/create_post.jsx4
-rw-r--r--webapp/components/create_team/components/display_name.jsx (renamed from webapp/components/signup_team_complete/components/team_signup_display_name_page.jsx)33
-rw-r--r--webapp/components/create_team/components/team_url.jsx (renamed from webapp/components/signup_team_complete/components/team_signup_url_page.jsx)88
-rw-r--r--webapp/components/create_team/create_team.jsx72
-rw-r--r--webapp/components/delete_channel_modal.jsx2
-rw-r--r--webapp/components/delete_post_modal.jsx2
-rw-r--r--webapp/components/do_verify_email.jsx8
-rw-r--r--webapp/components/edit_channel_header_modal.jsx2
-rw-r--r--webapp/components/edit_channel_purpose_modal.jsx11
-rw-r--r--webapp/components/edit_post_modal.jsx49
-rw-r--r--webapp/components/error_bar.jsx4
-rw-r--r--webapp/components/file_attachment.jsx4
-rw-r--r--webapp/components/file_upload.jsx46
-rw-r--r--webapp/components/filtered_user_list.jsx3
-rw-r--r--webapp/components/header_footer_template.jsx (renamed from webapp/components/not_logged_in.jsx)8
-rw-r--r--webapp/components/invite_member_modal.jsx2
-rw-r--r--webapp/components/logged_in.jsx147
-rw-r--r--webapp/components/login/login.jsx198
-rw-r--r--webapp/components/member_list_team.jsx16
-rw-r--r--webapp/components/more_channels.jsx2
-rw-r--r--webapp/components/navbar.jsx2
-rw-r--r--webapp/components/navbar_dropdown.jsx59
-rw-r--r--webapp/components/needs_team.jsx148
-rw-r--r--webapp/components/new_channel_flow.jsx8
-rw-r--r--webapp/components/notify_counts.jsx11
-rw-r--r--webapp/components/password_reset_form.jsx14
-rw-r--r--webapp/components/password_reset_send_link.jsx8
-rw-r--r--webapp/components/popover_list_members.jsx3
-rw-r--r--webapp/components/post.jsx4
-rw-r--r--webapp/components/register_app_modal.jsx2
-rw-r--r--webapp/components/rename_channel_modal.jsx2
-rw-r--r--webapp/components/rhs_comment.jsx6
-rw-r--r--webapp/components/rhs_header_post.jsx12
-rw-r--r--webapp/components/root.jsx50
-rw-r--r--webapp/components/search_bar.jsx2
-rw-r--r--webapp/components/select_team/select_team.jsx257
-rw-r--r--webapp/components/should_verify_email.jsx20
-rw-r--r--webapp/components/sidebar_header.jsx3
-rw-r--r--webapp/components/sidebar_right_menu.jsx7
-rw-r--r--webapp/components/signup_team.jsx235
-rw-r--r--webapp/components/signup_team_complete/components/signup_team_complete.jsx1
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_email_item.jsx89
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_finished.jsx17
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_password_page.jsx225
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_send_invites_page.jsx215
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_username_page.jsx169
-rw-r--r--webapp/components/signup_team_complete/components/team_signup_welcome_page.jsx243
-rw-r--r--webapp/components/signup_team_confirm.jsx49
-rw-r--r--webapp/components/signup_user_complete.jsx199
-rw-r--r--webapp/components/suggestion/at_mention_provider.jsx3
-rw-r--r--webapp/components/suggestion/search_user_provider.jsx3
-rw-r--r--webapp/components/team_export_tab.jsx2
-rw-r--r--webapp/components/team_general_tab.jsx160
-rw-r--r--webapp/components/team_members_dropdown.jsx46
-rw-r--r--webapp/components/team_settings.jsx1
-rw-r--r--webapp/components/team_signup_choose_auth.jsx132
-rw-r--r--webapp/components/team_signup_with_email.jsx116
-rw-r--r--webapp/components/team_signup_with_ldap.jsx231
-rw-r--r--webapp/components/team_signup_with_sso.jsx174
-rw-r--r--webapp/components/toggle_modal_button.jsx7
-rw-r--r--webapp/components/user_list.jsx10
-rw-r--r--webapp/components/user_list_row.jsx11
-rw-r--r--webapp/components/user_profile.jsx3
-rw-r--r--webapp/components/user_settings/import_theme_modal.jsx2
-rw-r--r--webapp/components/user_settings/manage_languages.jsx2
-rw-r--r--webapp/components/user_settings/user_settings_general.jsx8
-rw-r--r--webapp/components/user_settings/user_settings_notifications.jsx2
-rw-r--r--webapp/components/user_settings/user_settings_security.jsx37
-rw-r--r--webapp/components/user_settings/user_settings_theme.jsx2
-rw-r--r--webapp/components/view_image.jsx2
113 files changed, 1425 insertions, 2898 deletions
diff --git a/webapp/components/activity_log_modal.jsx b/webapp/components/activity_log_modal.jsx
index f1dd4a26a..d3e5ce66d 100644
--- a/webapp/components/activity_log_modal.jsx
+++ b/webapp/components/activity_log_modal.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import UserStore from 'stores/user_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {Modal} from 'react-bootstrap';
import LoadingScreen from './loading_screen.jsx';
diff --git a/webapp/components/admin_console/admin_navbar_dropdown.jsx b/webapp/components/admin_console/admin_navbar_dropdown.jsx
index 729d4b14d..dd56411f4 100644
--- a/webapp/components/admin_console/admin_navbar_dropdown.jsx
+++ b/webapp/components/admin_console/admin_navbar_dropdown.jsx
@@ -3,27 +3,20 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Utils from 'utils/utils.jsx';
-import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
+import * as GlobalActions from 'action_creators/global_actions.jsx';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router';
-function getStateFromStores() {
- return {currentTeam: TeamStore.getCurrent()};
-}
-
import React from 'react';
export default class AdminNavbarDropdown extends React.Component {
constructor(props) {
super(props);
this.blockToggle = false;
-
- this.state = getStateFromStores();
}
componentDidMount() {
@@ -64,24 +57,27 @@ export default class AdminNavbarDropdown extends React.Component {
>
<li>
<Link
- to={'/' + this.state.currentTeam.name + '/channels/town-square'}
+ to={'/select_team'}
>
<FormattedMessage
id='admin.nav.switch'
defaultMessage='Switch to {display_name}'
values={{
- display_name: this.state.currentTeam.display_name
+ display_name: global.window.mm_config.SiteName
}}
/>
</Link>
</li>
<li>
- <Link to={Utils.getTeamURLFromAddressBar() + '/logout'}>
+ <a
+ href='#'
+ onClick={GlobalActions.emitUserLoggedOutEvent}
+ >
<FormattedMessage
id='admin.nav.logout'
defaultMessage='Logout'
/>
- </Link>
+ </a>
</li>
</ul>
</li>
diff --git a/webapp/components/admin_console/admin_sidebar_header.jsx b/webapp/components/admin_console/admin_sidebar_header.jsx
index 2e6252075..400730030 100644
--- a/webapp/components/admin_console/admin_sidebar_header.jsx
+++ b/webapp/components/admin_console/admin_sidebar_header.jsx
@@ -4,6 +4,7 @@
import $ from 'jquery';
import AdminNavbarDropdown from './admin_navbar_dropdown.jsx';
import UserStore from 'stores/user_store.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
@@ -41,7 +42,7 @@ export default class SidebarHeader extends React.Component {
profilePicture = (
<img
className='user__picture'
- src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at}
+ src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.update_at}
/>
);
}
diff --git a/webapp/components/admin_console/compliance_reports.jsx b/webapp/components/admin_console/compliance_reports.jsx
index 84def2bce..702c1a969 100644
--- a/webapp/components/admin_console/compliance_reports.jsx
+++ b/webapp/components/admin_console/compliance_reports.jsx
@@ -7,7 +7,7 @@ import * as Utils from '../../utils/utils.jsx';
import AdminStore from '../../stores/admin_store.jsx';
import UserStore from '../../stores/user_store.jsx';
-import * as Client from '../../utils/client.jsx';
+import * as Client from '../../utils/web_client.jsx';
import * as AsyncClient from '../../utils/async_client.jsx';
import {FormattedMessage, FormattedDate, FormattedTime} from 'react-intl';
@@ -153,7 +153,7 @@ export default class ComplianceReports extends React.Component {
var download = '';
if (report.status === 'finished') {
download = (
- <a href={'/api/v1/admin/download_compliance_report/' + report.id}>
+ <a href={Client.getAdminRoute() + '/download_compliance_report/' + report.id}>
<FormattedMessage
id='admin.compliance_table.download'
defaultMessage='Download'
diff --git a/webapp/components/admin_console/compliance_settings.jsx b/webapp/components/admin_console/compliance_settings.jsx
index 206bb0faa..b127634e8 100644
--- a/webapp/components/admin_console/compliance_settings.jsx
+++ b/webapp/components/admin_console/compliance_settings.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import $ from 'jquery';
-import * as Client from '../../utils/client.jsx';
+import * as Client from '../../utils/web_client.jsx';
import * as AsyncClient from '../../utils/async_client.jsx';
import * as Utils from '../../utils/utils.jsx';
diff --git a/webapp/components/admin_console/email_settings.jsx b/webapp/components/admin_console/email_settings.jsx
index 8df48b206..1fa75ead9 100644
--- a/webapp/components/admin_console/email_settings.jsx
+++ b/webapp/components/admin_console/email_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import crypto from 'crypto';
import ConnectionSecurityDropdownSetting from './connection_security_dropdown_setting.jsx';
diff --git a/webapp/components/admin_console/gitlab_settings.jsx b/webapp/components/admin_console/gitlab_settings.jsx
index 7fdedde13..747905ac6 100644
--- a/webapp/components/admin_console/gitlab_settings.jsx
+++ b/webapp/components/admin_console/gitlab_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/image_settings.jsx b/webapp/components/admin_console/image_settings.jsx
index 576ff18fd..023e9af3b 100644
--- a/webapp/components/admin_console/image_settings.jsx
+++ b/webapp/components/admin_console/image_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import crypto from 'crypto';
diff --git a/webapp/components/admin_console/ldap_settings.jsx b/webapp/components/admin_console/ldap_settings.jsx
index dd6e4338f..01402a588 100644
--- a/webapp/components/admin_console/ldap_settings.jsx
+++ b/webapp/components/admin_console/ldap_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
@@ -61,6 +61,7 @@ class LdapSettings extends React.Component {
config.LdapSettings.BindPassword = this.refs.BindPassword.value.trim();
config.LdapSettings.FirstNameAttribute = this.refs.FirstNameAttribute.value.trim();
config.LdapSettings.LastNameAttribute = this.refs.LastNameAttribute.value.trim();
+ config.LdapSettings.NicknameAttribute = this.refs.NicknameAttribute.value.trim();
config.LdapSettings.EmailAttribute = this.refs.EmailAttribute.value.trim();
config.LdapSettings.UsernameAttribute = this.refs.UsernameAttribute.value.trim();
config.LdapSettings.IdAttribute = this.refs.IdAttribute.value.trim();
@@ -441,6 +442,35 @@ class LdapSettings extends React.Component {
<div className='form-group'>
<label
className='control-label col-sm-4'
+ htmlFor='NicknameAttribute'
+ >
+ <FormattedMessage
+ id='admin.ldap.nicknameAttrTitle'
+ defaultMessage='Nickname Attribute:'
+ />
+ </label>
+ <div className='col-sm-8'>
+ <input
+ type='text'
+ className='form-control'
+ id='NicknameAttribute'
+ ref='NicknameAttribute'
+ placeholder={Utils.localizeMessage('admin.ldap.nicknameAttrEx', 'Ex "nickname"')}
+ defaultValue={this.props.config.LdapSettings.NicknameAttribute}
+ onChange={this.handleChange}
+ disabled={!this.state.enable}
+ />
+ <p className='help-text'>
+ <FormattedMessage
+ id='admin.ldap.nicknameAttrDesc'
+ defaultMessage='(Optional) The attribute in the LDAP server that will be used to populate the nickname of users in Mattermost.'
+ />
+ </p>
+ </div>
+ </div>
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
htmlFor='EmailAttribute'
>
<FormattedMessage
diff --git a/webapp/components/admin_console/legal_and_support_settings.jsx b/webapp/components/admin_console/legal_and_support_settings.jsx
index bbbb3713c..9f72f5fdf 100644
--- a/webapp/components/admin_console/legal_and_support_settings.jsx
+++ b/webapp/components/admin_console/legal_and_support_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/license_settings.jsx b/webapp/components/admin_console/license_settings.jsx
index 20e2fc83a..f2c511e44 100644
--- a/webapp/components/admin_console/license_settings.jsx
+++ b/webapp/components/admin_console/license_settings.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
@@ -54,10 +54,7 @@ class LicenseSettings extends React.Component {
$('#upload-button').button('loading');
- const formData = new FormData();
- formData.append('license', file, file.name);
-
- Client.uploadLicenseFile(formData,
+ Client.uploadLicenseFile(file,
() => {
Utils.clearFileInput(element[0]);
$('#upload-button').button('reset');
diff --git a/webapp/components/admin_console/log_settings.jsx b/webapp/components/admin_console/log_settings.jsx
index 5aa3ca1e0..061c2b6e3 100644
--- a/webapp/components/admin_console/log_settings.jsx
+++ b/webapp/components/admin_console/log_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/privacy_settings.jsx b/webapp/components/admin_console/privacy_settings.jsx
index a312dddca..5045a6d31 100644
--- a/webapp/components/admin_console/privacy_settings.jsx
+++ b/webapp/components/admin_console/privacy_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/rate_settings.jsx b/webapp/components/admin_console/rate_settings.jsx
index f3fb1742c..de7a40e6b 100644
--- a/webapp/components/admin_console/rate_settings.jsx
+++ b/webapp/components/admin_console/rate_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/reset_password_modal.jsx b/webapp/components/admin_console/reset_password_modal.jsx
index f80c740e3..5133f3f28 100644
--- a/webapp/components/admin_console/reset_password_modal.jsx
+++ b/webapp/components/admin_console/reset_password_modal.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import {Modal} from 'react-bootstrap';
@@ -40,12 +40,9 @@ class ResetPasswordModal extends React.Component {
this.setState({serverError: null});
- var data = {};
- data.new_password = password;
- data.name = this.props.team.name;
- data.user_id = this.props.user.id;
-
- Client.resetPassword(data,
+ Client.adminResetPassword(
+ this.props.user.id,
+ password,
() => {
this.props.onModalSubmit(ReactDOM.findDOMNode(this.refs.password).value);
},
@@ -159,4 +156,4 @@ ResetPasswordModal.propTypes = {
onModalDismissed: React.PropTypes.func
};
-export default injectIntl(ResetPasswordModal); \ No newline at end of file
+export default injectIntl(ResetPasswordModal);
diff --git a/webapp/components/admin_console/service_settings.jsx b/webapp/components/admin_console/service_settings.jsx
index 2c3f4081c..90b6a39b4 100644
--- a/webapp/components/admin_console/service_settings.jsx
+++ b/webapp/components/admin_console/service_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
diff --git a/webapp/components/admin_console/sql_settings.jsx b/webapp/components/admin_console/sql_settings.jsx
index 33bb2cece..f2e005b83 100644
--- a/webapp/components/admin_console/sql_settings.jsx
+++ b/webapp/components/admin_console/sql_settings.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import crypto from 'crypto';
diff --git a/webapp/components/admin_console/team_settings.jsx b/webapp/components/admin_console/team_settings.jsx
index 6c9828351..bbb7ec3c4 100644
--- a/webapp/components/admin_console/team_settings.jsx
+++ b/webapp/components/admin_console/team_settings.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import $ from 'jquery';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -42,6 +42,7 @@ class TeamSettings extends React.Component {
this.handleImageSubmit = this.handleImageSubmit.bind(this);
this.uploading = false;
+ this.timestamp = 0;
this.state = {
saveNeeded: false,
@@ -53,7 +54,7 @@ class TeamSettings extends React.Component {
componentWillMount() {
if (global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.CustomBrand === 'true') {
- $.get('/api/v1/admin/get_brand_image').done(() => this.setState({brandImageExists: true}));
+ $.get(Client.getAdminRoute() + '/get_brand_image').done(() => this.setState({brandImageExists: true}));
}
}
@@ -89,6 +90,7 @@ class TeamSettings extends React.Component {
if (element.prop('files').length > 0) {
this.setState({fileSelected: true, brandImage: element.prop('files')[0]});
}
+ $('#upload-button').button('reset');
}
handleSubmit(e) {
@@ -100,8 +102,8 @@ class TeamSettings extends React.Component {
config.TeamSettings.RestrictCreationToDomains = this.refs.RestrictCreationToDomains.value.trim();
config.TeamSettings.EnableTeamCreation = this.refs.EnableTeamCreation.checked;
config.TeamSettings.EnableUserCreation = this.refs.EnableUserCreation.checked;
+ config.TeamSettings.EnableOpenServer = this.refs.EnableOpenServer.checked;
config.TeamSettings.RestrictTeamNames = this.refs.RestrictTeamNames.checked;
- config.TeamSettings.EnableTeamListing = this.refs.EnableTeamListing.checked;
if (this.refs.EnableCustomBrand) {
config.TeamSettings.EnableCustomBrand = this.refs.EnableCustomBrand.checked;
@@ -155,6 +157,7 @@ class TeamSettings extends React.Component {
Client.uploadBrandImage(this.state.brandImage,
() => {
$('#upload-button').button('complete');
+ this.timestamp = Utils.getTimestamp();
this.setState({brandImageExists: true, brandImage: null});
this.uploading = false;
},
@@ -193,7 +196,7 @@ class TeamSettings extends React.Component {
img = (
<img
className='brand-img'
- src='/api/v1/admin/get_brand_image'
+ src={Client.getAdminRoute() + '/get_brand_image?t=' + this.timestamp}
/>
);
} else {
@@ -537,6 +540,53 @@ class TeamSettings extends React.Component {
<div className='form-group'>
<label
className='control-label col-sm-4'
+ htmlFor='EnableOpenServer'
+ >
+ <FormattedMessage
+ id='admin.team.openServerTitle'
+ defaultMessage='Enable Open Server: '
+ />
+ </label>
+ <div className='col-sm-8'>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableOpenServer'
+ value='true'
+ ref='EnableOpenServer'
+ defaultChecked={this.props.config.TeamSettings.EnableOpenServer}
+ onChange={this.handleChange}
+ />
+ <FormattedMessage
+ id='admin.team.true'
+ defaultMessage='true'
+ />
+ </label>
+ <label className='radio-inline'>
+ <input
+ type='radio'
+ name='EnableOpenServer'
+ value='false'
+ defaultChecked={!this.props.config.TeamSettings.EnableOpenServer}
+ onChange={this.handleChange}
+ />
+ <FormattedMessage
+ id='admin.team.false'
+ defaultMessage='false'
+ />
+ </label>
+ <p className='help-text'>
+ <FormattedMessage
+ id='admin.team.openServerDescription'
+ defaultMessage='When true, anyone can signup for a user account on this server without the need to be invited.'
+ />
+ </p>
+ </div>
+ </div>
+
+ <div className='form-group'>
+ <label
+ className='control-label col-sm-4'
htmlFor='RestrictCreationToDomains'
>
<FormattedMessage
@@ -610,53 +660,6 @@ class TeamSettings extends React.Component {
</div>
</div>
- <div className='form-group'>
- <label
- className='control-label col-sm-4'
- htmlFor='EnableTeamListing'
- >
- <FormattedMessage
- id='admin.team.dirTitle'
- defaultMessage='Enable Team Directory: '
- />
- </label>
- <div className='col-sm-8'>
- <label className='radio-inline'>
- <input
- type='radio'
- name='EnableTeamListing'
- value='true'
- ref='EnableTeamListing'
- defaultChecked={this.props.config.TeamSettings.EnableTeamListing}
- onChange={this.handleChange}
- />
- <FormattedMessage
- id='admin.team.true'
- defaultMessage='true'
- />
- </label>
- <label className='radio-inline'>
- <input
- type='radio'
- name='EnableTeamListing'
- value='false'
- defaultChecked={!this.props.config.TeamSettings.EnableTeamListing}
- onChange={this.handleChange}
- />
- <FormattedMessage
- id='admin.team.false'
- defaultMessage='false'
- />
- </label>
- <p className='help-text'>
- <FormattedMessage
- id='admin.team.dirDesc'
- defaultMessage='When true, teams that are configured to show in team directory will show on main page inplace of creating a new team.'
- />
- </p>
- </div>
- </div>
-
{brand}
<div className='form-group'>
diff --git a/webapp/components/admin_console/team_users.jsx b/webapp/components/admin_console/team_users.jsx
index 8b37bd237..2b0e6af0a 100644
--- a/webapp/components/admin_console/team_users.jsx
+++ b/webapp/components/admin_console/team_users.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import LoadingScreen from '../loading_screen.jsx';
import UserItem from './user_item.jsx';
import ResetPasswordModal from './reset_password_modal.jsx';
diff --git a/webapp/components/admin_console/user_item.jsx b/webapp/components/admin_console/user_item.jsx
index 5bd05d063..b8f21d77e 100644
--- a/webapp/components/admin_console/user_item.jsx
+++ b/webapp/components/admin_console/user_item.jsx
@@ -1,13 +1,13 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import UserStore from 'stores/user_store.jsx';
import ConfirmModal from '../confirm_modal.jsx';
import TeamStore from 'stores/team_store.jsx';
-import {FormattedMessage} from 'react-intl';
+import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
import React from 'react';
import {browserHistory} from 'react-router';
@@ -22,6 +22,7 @@ export default class UserItem extends React.Component {
this.handleMakeAdmin = this.handleMakeAdmin.bind(this);
this.handleMakeSystemAdmin = this.handleMakeSystemAdmin.bind(this);
this.handleResetPassword = this.handleResetPassword.bind(this);
+ this.handleResetMfa = this.handleResetMfa.bind(this);
this.handleDemote = this.handleDemote.bind(this);
this.handleDemoteSubmit = this.handleDemoteSubmit.bind(this);
this.handleDemoteCancel = this.handleDemoteCancel.bind(this);
@@ -40,12 +41,9 @@ export default class UserItem extends React.Component {
if (this.props.user.id === me.id) {
this.handleDemote(this.props.user, '');
} else {
- const data = {
- user_id: this.props.user.id,
- new_roles: ''
- };
-
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ '',
() => {
this.props.refreshProfiles();
},
@@ -86,12 +84,9 @@ export default class UserItem extends React.Component {
if (this.props.user.id === me.id) {
this.handleDemote(this.props.user, 'admin');
} else {
- const data = {
- user_id: this.props.user.id,
- new_roles: 'admin'
- };
-
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ 'admin',
() => {
this.props.refreshProfiles();
},
@@ -104,12 +99,10 @@ export default class UserItem extends React.Component {
handleMakeSystemAdmin(e) {
e.preventDefault();
- const data = {
- user_id: this.props.user.id,
- new_roles: 'system_admin'
- };
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ 'system_admin',
() => {
this.props.refreshProfiles();
},
@@ -124,6 +117,19 @@ export default class UserItem extends React.Component {
this.props.doPasswordReset(this.props.user);
}
+ handleResetMfa(e) {
+ e.preventDefault();
+
+ Client.adminResetMfa(this.props.user.id,
+ () => {
+ this.props.refreshProfiles();
+ },
+ (err) => {
+ this.setState({serverError: err.message});
+ }
+ );
+ }
+
handleDemote(user, role) {
this.setState({
serverError: this.state.serverError,
@@ -143,12 +149,9 @@ export default class UserItem extends React.Component {
}
handleDemoteSubmit() {
- const data = {
- user_id: this.props.user.id,
- new_roles: this.state.role
- };
-
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ this.state.role,
() => {
this.setState({
serverError: null,
@@ -211,10 +214,15 @@ export default class UserItem extends React.Component {
const email = user.email;
let showMakeMember = user.roles === 'admin' || user.roles === 'system_admin';
- let showMakeAdmin = user.roles === '' || user.roles === 'system_admin';
+
+ //let showMakeAdmin = user.roles === '' || user.roles === 'system_admin';
+ let showMakeAdmin = false;
+
let showMakeSystemAdmin = user.roles === '' || user.roles === 'admin';
let showMakeActive = false;
let showMakeNotActive = user.roles !== 'system_admin';
+ let mfaEnabled = global.window.mm_license.IsLicensed === 'true' && global.window.mm_license.MFA === 'true' && global.window.mm_config.EnableMultifactorAuthentication === 'true';
+ let showMfaReset = mfaEnabled && user.mfa_active;
if (user.delete_at > 0) {
currentRoles = (
@@ -319,6 +327,64 @@ export default class UserItem extends React.Component {
</li>
);
}
+
+ let mfaReset = null;
+ if (showMfaReset) {
+ mfaReset = (
+ <li role='presentation'>
+ <a
+ role='menuitem'
+ href='#'
+ onClick={this.handleResetMfa}
+ >
+ <FormattedMessage
+ id='admin.user_item.resetMfa'
+ defaultMessage='Remove MFA'
+ />
+ </a>
+ </li>
+ );
+ }
+
+ let mfaActiveText;
+ if (mfaEnabled) {
+ if (user.mfa_active) {
+ mfaActiveText = (
+ <FormattedHTMLMessage
+ id='admin.user_item.mfaYes'
+ defaultMessage=', <strong>MFA</strong>: Yes'
+ />
+ );
+ } else {
+ mfaActiveText = (
+ <FormattedHTMLMessage
+ id='admin.user_item.mfaNo'
+ defaultMessage=', <strong>MFA</strong>: No'
+ />
+ );
+ }
+ }
+
+ let authServiceText;
+ if (user.auth_service) {
+ authServiceText = (
+ <FormattedHTMLMessage
+ id='admin.user_item.authServiceNotEmail'
+ defaultMessage=', <strong>Sign-in Method:</strong> {service}'
+ values={{
+ service: Utils.toTitleCase(user.auth_service)
+ }}
+ />
+ );
+ } else {
+ authServiceText = (
+ <FormattedHTMLMessage
+ id='admin.user_item.authServiceEmail'
+ defaultMessage=', <strong>Sign-in Method:</strong> Email'
+ />
+ );
+ }
+
const me = UserStore.getCurrentUser();
let makeDemoteModal = null;
if (this.props.user.id === me.id) {
@@ -368,13 +434,23 @@ export default class UserItem extends React.Component {
<div className='more-modal__row'>
<img
className='more-modal__image pull-left'
- src={`/api/v1/users/${user.id}/image?time=${user.update_at}`}
+ src={`${Client.getUsersRoute()}/${user.id}/image?time=${user.update_at}`}
height='36'
width='36'
/>
<div className='more-modal__details'>
<div className='more-modal__name'>{Utils.getDisplayName(user)}</div>
- <div className='more-modal__description'>{email}</div>
+ <div className='more-modal__description'>
+ <FormattedHTMLMessage
+ id='admin.user_item.emailTitle'
+ defaultMessage='<strong>Email:</strong> {email}'
+ values={{
+ email
+ }}
+ />
+ {authServiceText}
+ {mfaActiveText}
+ </div>
</div>
<div className='more-modal__actions'>
<div className='dropdown member-drop'>
@@ -397,6 +473,7 @@ export default class UserItem extends React.Component {
{makeActive}
{makeNotActive}
{makeSystemAdmin}
+ {mfaReset}
<li role='presentation'>
<a
role='menuitem'
diff --git a/webapp/components/authorize.jsx b/webapp/components/authorize.jsx
index 01b37f439..b18469568 100644
--- a/webapp/components/authorize.jsx
+++ b/webapp/components/authorize.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
diff --git a/webapp/components/backstage/add_command.jsx b/webapp/components/backstage/add_command.jsx
index 2eb7bdb21..ba9ac4e79 100644
--- a/webapp/components/backstage/add_command.jsx
+++ b/webapp/components/backstage/add_command.jsx
@@ -89,6 +89,8 @@ export default class AddCommand extends React.Component {
/>
)
});
+
+ return;
}
if (!command.url) {
@@ -101,12 +103,14 @@ export default class AddCommand extends React.Component {
/>
)
});
+
+ return;
}
AsyncClient.addCommand(
command,
() => {
- browserHistory.push('/settings/integrations/commands');
+ browserHistory.push('/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands');
},
(err) => {
this.setState({
@@ -251,7 +255,7 @@ export default class AddCommand extends React.Component {
return (
<div className='backstage-content row'>
<BackstageHeader>
- <Link to={'/settings/integrations/commands'}>
+ <Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands'}>
<FormattedMessage
id='installed_command.header'
defaultMessage='Slash Commands'
@@ -482,7 +486,7 @@ export default class AddCommand extends React.Component {
<FormError errors={[this.state.serverError, this.state.clientError]}/>
<Link
className='btn btn-sm'
- to={'/settings/integrations/commands'}
+ to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands'}
>
<FormattedMessage
id='add_command.cancel'
diff --git a/webapp/components/backstage/add_incoming_webhook.jsx b/webapp/components/backstage/add_incoming_webhook.jsx
index f68a263be..0f0d49ea7 100644
--- a/webapp/components/backstage/add_incoming_webhook.jsx
+++ b/webapp/components/backstage/add_incoming_webhook.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import {browserHistory} from 'react-router';
+import * as Utils from 'utils/utils.jsx';
import BackstageHeader from './backstage_header.jsx';
import ChannelSelect from 'components/channel_select.jsx';
@@ -69,7 +70,7 @@ export default class AddIncomingWebhook extends React.Component {
AsyncClient.addIncomingHook(
hook,
() => {
- browserHistory.push('/settings/integrations/incoming_webhooks');
+ browserHistory.push('/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks');
},
(err) => {
this.setState({
@@ -102,7 +103,7 @@ export default class AddIncomingWebhook extends React.Component {
return (
<div className='backstage-content'>
<BackstageHeader>
- <Link to={'/settings/integrations/incoming_webhooks'}>
+ <Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks'}>
<FormattedMessage
id='installed_incoming_webhooks.header'
defaultMessage='Incoming Webhooks'
diff --git a/webapp/components/backstage/add_outgoing_webhook.jsx b/webapp/components/backstage/add_outgoing_webhook.jsx
index ff5e90e07..245df1604 100644
--- a/webapp/components/backstage/add_outgoing_webhook.jsx
+++ b/webapp/components/backstage/add_outgoing_webhook.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import {browserHistory} from 'react-router';
+import * as Utils from 'utils/utils.jsx';
import BackstageHeader from './backstage_header.jsx';
import ChannelSelect from 'components/channel_select.jsx';
@@ -109,7 +110,7 @@ export default class AddOutgoingWebhook extends React.Component {
AsyncClient.addOutgoingHook(
hook,
() => {
- browserHistory.push('/settings/integrations/outgoing_webhooks');
+ browserHistory.push('/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks');
},
(err) => {
this.setState({
@@ -154,7 +155,7 @@ export default class AddOutgoingWebhook extends React.Component {
return (
<div className='backstage-content'>
<BackstageHeader>
- <Link to={'/settings/integrations/outgoing_webhooks'}>
+ <Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks'}>
<FormattedMessage
id='installed_outgoing_webhooks.header'
defaultMessage='Outgoing Webhooks'
@@ -273,7 +274,7 @@ export default class AddOutgoingWebhook extends React.Component {
<FormError errors={[this.state.serverError, this.state.clientError]}/>
<Link
className='btn btn-sm'
- to={'/settings/integrations/outgoing_webhooks'}
+ to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks'}
>
<FormattedMessage
id='add_outgoing_webhook.cancel'
diff --git a/webapp/components/backstage/backstage_navbar.jsx b/webapp/components/backstage/backstage_navbar.jsx
index d2d2da1ed..8352296b7 100644
--- a/webapp/components/backstage/backstage_navbar.jsx
+++ b/webapp/components/backstage/backstage_navbar.jsx
@@ -46,7 +46,7 @@ export default class BackstageNavbar extends React.Component {
<div className='backstage-navbar row'>
<Link
className='backstage-navbar__back'
- to={`/${this.state.team.display_name}/channels/town-square`}
+ to={`/${this.state.team.name}/channels/town-square`}
>
<i className='fa fa-angle-left'/>
<span>
diff --git a/webapp/components/backstage/backstage_sidebar.jsx b/webapp/components/backstage/backstage_sidebar.jsx
index eb84709a3..6f8e0b86a 100644
--- a/webapp/components/backstage/backstage_sidebar.jsx
+++ b/webapp/components/backstage/backstage_sidebar.jsx
@@ -3,6 +3,7 @@
import React from 'react';
+import * as Utils from 'utils/utils.jsx';
import BackstageCategory from './backstage_category.jsx';
import BackstageSection from './backstage_section.jsx';
import {FormattedMessage} from 'react-intl';
@@ -14,7 +15,7 @@ export default class BackstageSidebar extends React.Component {
<ul>
<BackstageCategory
name='integrations'
- parentLink={'/settings'}
+ parentLink={'/' + Utils.getTeamNameFromUrl() + '/settings'}
icon='fa-link'
title={
<FormattedMessage
diff --git a/webapp/components/backstage/installed_commands.jsx b/webapp/components/backstage/installed_commands.jsx
index 3527a574b..8b0cd59c8 100644
--- a/webapp/components/backstage/installed_commands.jsx
+++ b/webapp/components/backstage/installed_commands.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import IntegrationStore from 'stores/integration_store.jsx';
+import * as Utils from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
import InstalledCommand from './installed_command.jsx';
@@ -84,7 +85,7 @@ export default class InstalledCommands extends React.Component {
defaultMessage='Add Slash Command'
/>
}
- addLink='/settings/integrations/commands/add'
+ addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands/add'}
>
{commands}
</InstalledIntegrations>
diff --git a/webapp/components/backstage/installed_incoming_webhook.jsx b/webapp/components/backstage/installed_incoming_webhook.jsx
index 58d318310..afa6e9958 100644
--- a/webapp/components/backstage/installed_incoming_webhook.jsx
+++ b/webapp/components/backstage/installed_incoming_webhook.jsx
@@ -90,6 +90,17 @@ export default class InstalledIncomingWebhook extends React.Component {
</span>
</div>
{description}
+ <div className='item-details__row'>
+ <span className='item-details__url'>
+ <FormattedMessage
+ id='installed_integrations.url'
+ defaultMessage='URL: {url}'
+ values={{
+ url: Utils.getWindowLocationOrigin() + '/hooks/' + incomingWebhook.id
+ }}
+ />
+ </span>
+ </div>
<div className='tem-details__row'>
<span className='item-details__creation'>
<FormattedMessage
diff --git a/webapp/components/backstage/installed_incoming_webhooks.jsx b/webapp/components/backstage/installed_incoming_webhooks.jsx
index de7154afe..0d6f900d1 100644
--- a/webapp/components/backstage/installed_incoming_webhooks.jsx
+++ b/webapp/components/backstage/installed_incoming_webhooks.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import IntegrationStore from 'stores/integration_store.jsx';
+import * as Utils from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
import InstalledIncomingWebhook from './installed_incoming_webhook.jsx';
@@ -76,7 +77,7 @@ export default class InstalledIncomingWebhooks extends React.Component {
defaultMessage='Add Incoming Webhook'
/>
}
- addLink='/settings/integrations/incoming_webhooks/add'
+ addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks/add'}
>
{incomingWebhooks}
</InstalledIntegrations>
diff --git a/webapp/components/backstage/installed_outgoing_webhooks.jsx b/webapp/components/backstage/installed_outgoing_webhooks.jsx
index 15d927a41..98992b081 100644
--- a/webapp/components/backstage/installed_outgoing_webhooks.jsx
+++ b/webapp/components/backstage/installed_outgoing_webhooks.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
import IntegrationStore from 'stores/integration_store.jsx';
+import * as Utils from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
import InstalledOutgoingWebhook from './installed_outgoing_webhook.jsx';
@@ -82,7 +83,7 @@ export default class InstalledOutgoingWebhooks extends React.Component {
defaultMessage='Add Outgoing Webhook'
/>
}
- addLink='/settings/integrations/outgoing_webhooks/add'
+ addLink={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks/add'}
>
{outgoingWebhooks}
</InstalledIntegrations>
diff --git a/webapp/components/backstage/integrations.jsx b/webapp/components/backstage/integrations.jsx
index 71232ea45..fdd75026a 100644
--- a/webapp/components/backstage/integrations.jsx
+++ b/webapp/components/backstage/integrations.jsx
@@ -5,6 +5,7 @@ import React from 'react';
import {FormattedMessage} from 'react-intl';
import IntegrationOption from './integration_option.jsx';
+import * as Utils from 'utils/utils.jsx';
import WebhookIcon from 'images/webhook_icon.jpg';
@@ -29,7 +30,7 @@ export default class Integrations extends React.Component {
defaultMessage='Incoming webhooks allow external integrations to send messages'
/>
}
- link={'/settings/integrations/incoming_webhooks'}
+ link={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/incoming_webhooks'}
/>
);
}
@@ -51,7 +52,7 @@ export default class Integrations extends React.Component {
defaultMessage='Outgoing webhooks allow external integrations to receive and respond to messages'
/>
}
- link={'/settings/integrations/outgoing_webhooks'}
+ link={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/outgoing_webhooks'}
/>
);
}
@@ -73,7 +74,7 @@ export default class Integrations extends React.Component {
defaultMessage='Slash commands send events to an external integration'
/>
}
- link={'/settings/integrations/commands'}
+ link={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations/commands'}
/>
);
}
diff --git a/webapp/components/channel_header.jsx b/webapp/components/channel_header.jsx
index 16d9ea536..c82f59299 100644
--- a/webapp/components/channel_header.jsx
+++ b/webapp/components/channel_header.jsx
@@ -25,7 +25,7 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import * as Utils from 'utils/utils.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import {FormattedMessage} from 'react-intl';
diff --git a/webapp/components/channel_info_modal.jsx b/webapp/components/channel_info_modal.jsx
index c7f9f9f79..4c16dda90 100644
--- a/webapp/components/channel_info_modal.jsx
+++ b/webapp/components/channel_info_modal.jsx
@@ -3,33 +3,26 @@
import * as Utils from 'utils/utils.jsx';
-import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
-
+import {FormattedMessage} from 'react-intl';
import {Modal} from 'react-bootstrap';
-const holders = defineMessages({
- notFound: {
- id: 'channel_info.notFound',
- defaultMessage: 'No Channel Found'
- }
-});
-
import React from 'react';
-class ChannelInfoModal extends React.Component {
+export default class ChannelInfoModal extends React.Component {
render() {
- const {formatMessage} = this.props.intl;
let channel = this.props.channel;
if (!channel) {
+ const notFound = Utils.localizeMessage('channel_info.notFound', 'No Channel Found');
+
channel = {
- display_name: formatMessage(holders.notFound),
- name: formatMessage(holders.notFound),
- purpose: formatMessage(holders.notFound),
- id: formatMessage(holders.notFound)
+ display_name: notFound,
+ name: notFound,
+ purpose: notFound,
+ id: notFound
};
}
- const channelURL = Utils.getShortenedTeamURL() + channel.name;
+ const channelURL = Utils.getTeamURLFromAddressBar() + '/channels/' + channel.name;
return (
<Modal
@@ -97,10 +90,7 @@ class ChannelInfoModal extends React.Component {
}
ChannelInfoModal.propTypes = {
- intl: intlShape.isRequired,
show: React.PropTypes.bool.isRequired,
onHide: React.PropTypes.func.isRequired,
channel: React.PropTypes.object.isRequired
-};
-
-export default injectIntl(ChannelInfoModal); \ No newline at end of file
+}; \ No newline at end of file
diff --git a/webapp/components/channel_invite_button.jsx b/webapp/components/channel_invite_button.jsx
index 1fcd461ea..ed013bb26 100644
--- a/webapp/components/channel_invite_button.jsx
+++ b/webapp/components/channel_invite_button.jsx
@@ -4,7 +4,7 @@
import React from 'react';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
import SpinnerButton from 'components/spinner_button.jsx';
@@ -37,13 +37,9 @@ export default class ChannelInviteButton extends React.Component {
addingUser: true
});
- const data = {
- user_id: this.props.user.id
- };
-
Client.addChannelMember(
this.props.channel.id,
- data,
+ this.props.user.id,
() => {
this.setState({
addingUser: false
diff --git a/webapp/components/channel_members_modal.jsx b/webapp/components/channel_members_modal.jsx
index 67be2ef50..ecea891bb 100644
--- a/webapp/components/channel_members_modal.jsx
+++ b/webapp/components/channel_members_modal.jsx
@@ -9,7 +9,7 @@ import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import {FormattedMessage} from 'react-intl';
@@ -97,12 +97,9 @@ export default class ChannelMembersModal extends React.Component {
handleRemove(user) {
const userId = user.id;
- const data = {};
- data.user_id = userId;
-
Client.removeChannelMember(
ChannelStore.getCurrentId(),
- data,
+ userId,
() => {
const memberList = this.state.memberList.slice();
for (let i = 0; i < memberList.length; i++) {
diff --git a/webapp/components/channel_notifications_modal.jsx b/webapp/components/channel_notifications_modal.jsx
index 564776876..112c07ad0 100644
--- a/webapp/components/channel_notifications_modal.jsx
+++ b/webapp/components/channel_notifications_modal.jsx
@@ -6,7 +6,7 @@ import {Modal} from 'react-bootstrap';
import SettingItemMin from './setting_item_min.jsx';
import SettingItemMax from './setting_item_max.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import {FormattedMessage} from 'react-intl';
@@ -60,7 +60,7 @@ export default class ChannelNotificationsModal extends React.Component {
data.desktop = notifyLevel;
//TODO: This should be moved to event_helpers
- Client.updateNotifyProps(data,
+ Client.updateChannelNotifyProps(data,
() => {
// YUCK
var member = ChannelStore.getMember(channelId);
@@ -252,7 +252,7 @@ export default class ChannelNotificationsModal extends React.Component {
};
//TODO: This should be fixed, moved to event_helpers
- Client.updateNotifyProps(data,
+ Client.updateChannelNotifyProps(data,
() => {
// Yuck...
var member = ChannelStore.getMember(channelId);
diff --git a/webapp/components/channel_select.jsx b/webapp/components/channel_select.jsx
index 8622d1f57..238cfa1ae 100644
--- a/webapp/components/channel_select.jsx
+++ b/webapp/components/channel_select.jsx
@@ -54,7 +54,7 @@ export default class ChannelSelect extends React.Component {
];
this.state.channels.forEach((channel) => {
- if (channel.type !== Constants.DM_CHANNEL) {
+ if (channel.type === Constants.OPEN_CHANNEL) {
options.push(
<option
key={channel.id}
diff --git a/webapp/components/claim/claim.jsx b/webapp/components/claim/claim.jsx
index 5cfb04af3..0197e1677 100644
--- a/webapp/components/claim/claim.jsx
+++ b/webapp/components/claim/claim.jsx
@@ -1,8 +1,6 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import TeamStore from 'stores/team_store.jsx';
-
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router';
@@ -13,40 +11,15 @@ export default class Claim extends React.Component {
constructor(props) {
super(props);
- this.onTeamChange = this.onTeamChange.bind(this);
- this.updateStateFromStores = this.updateStateFromStores.bind(this);
-
this.state = {};
}
componentWillMount() {
this.setState({
email: this.props.location.query.email,
newType: this.props.location.query.new_type,
- oldType: this.props.location.query.old_type,
- teamName: this.props.params.team,
- teamDisplayName: ''
- });
- this.updateStateFromStores();
- }
- componentDidMount() {
- TeamStore.addChangeListener(this.onTeamChange);
- }
- componentWillUnmount() {
- TeamStore.removeChangeListener(this.onTeamChange);
- }
- updateStateFromStores() {
- const team = TeamStore.getByName(this.state.teamName);
- let displayName = '';
- if (team) {
- displayName = team.display_name;
- }
- this.setState({
- teamDisplayName: displayName
+ oldType: this.props.location.query.old_type
});
}
- onTeamChange() {
- this.updateStateFromStores();
- }
render() {
return (
<div>
@@ -66,8 +39,6 @@ export default class Claim extends React.Component {
/>
<div id='claim'>
{React.cloneElement(this.props.children, {
- teamName: this.state.teamName,
- teamDisplayName: this.state.teamDisplayName,
currentType: this.state.oldType,
newType: this.state.newType,
email: this.state.email
@@ -83,7 +54,6 @@ export default class Claim extends React.Component {
Claim.defaultProps = {
};
Claim.propTypes = {
- params: React.PropTypes.object.isRequired,
location: React.PropTypes.object.isRequired,
children: React.PropTypes.node
};
diff --git a/webapp/components/claim/components/email_to_ldap.jsx b/webapp/components/claim/components/email_to_ldap.jsx
index 1ceb42a27..fbf26cade 100644
--- a/webapp/components/claim/components/email_to_ldap.jsx
+++ b/webapp/components/claim/components/email_to_ldap.jsx
@@ -2,12 +2,11 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
export default class EmailToLDAP extends React.Component {
constructor(props) {
@@ -45,17 +44,14 @@ export default class EmailToLDAP extends React.Component {
state.error = null;
this.setState(state);
- var postData = {};
- postData.email_password = password;
- postData.ldap_id = ldapId;
- postData.ldap_password = ldapPassword;
- postData.email = this.props.email;
- postData.team_name = this.props.teamName;
-
- Client.emailToLDAP(postData,
+ Client.emailToLdap(
+ this.props.email,
+ password,
+ ldapId,
+ ldapPassword,
(data) => {
if (data.follow_link) {
- browserHistory.push(data.follow_link);
+ window.location.href = data.follow_link;
}
},
(error) => {
@@ -74,6 +70,20 @@ export default class EmailToLDAP extends React.Component {
formClass += ' has-error';
}
+ let loginPlaceholder;
+ if (global.window.mm_config.LdapLoginFieldName) {
+ loginPlaceholder = global.window.mm_config.LdapLoginFieldName;
+ } else {
+ loginPlaceholder = Utils.localizeMessage('claim.email_to_ldap.ldapId', 'LDAP ID');
+ }
+
+ let passwordPlaceholder;
+ if (global.window.mm_config.LdapPasswordFieldName) {
+ passwordPlaceholder = global.window.mm_config.LdapPasswordFieldName;
+ } else {
+ passwordPlaceholder = Utils.localizeMessage('claim.email_to_ldap.ldapPwd', 'LDAP Password');
+ }
+
return (
<div>
<h3>
@@ -98,9 +108,8 @@ export default class EmailToLDAP extends React.Component {
<p>
<FormattedMessage
id='claim.email_to_ldap.enterPwd'
- defaultMessage='Enter the password for your {team} {site} email account'
+ defaultMessage='Enter the password for your {site} email account'
values={{
- team: this.props.teamDisplayName,
site: global.window.mm_config.SiteName
}}
/>
@@ -125,10 +134,6 @@ export default class EmailToLDAP extends React.Component {
<FormattedMessage
id='claim.email_to_ldap.enterLdapPwd'
defaultMessage='Enter the ID and password for your LDAP account'
- values={{
- team: this.props.teamDisplayName,
- site: global.window.mm_config.SiteName
- }}
/>
</p>
<div className={formClass}>
@@ -138,7 +143,7 @@ export default class EmailToLDAP extends React.Component {
name='ldapId'
ref='ldapid'
autoComplete='off'
- placeholder={Utils.localizeMessage('claim.email_to_ldap.ldapId', 'LDAP ID')}
+ placeholder={loginPlaceholder}
spellCheck='false'
/>
</div>
@@ -149,7 +154,7 @@ export default class EmailToLDAP extends React.Component {
name='ldapPassword'
ref='ldappassword'
autoComplete='off'
- placeholder={Utils.localizeMessage('claim.email_to_ldap.ldapPwd', 'LDAP Password')}
+ placeholder={passwordPlaceholder}
spellCheck='false'
/>
</div>
@@ -172,7 +177,5 @@ export default class EmailToLDAP extends React.Component {
EmailToLDAP.defaultProps = {
};
EmailToLDAP.propTypes = {
- email: React.PropTypes.string,
- teamName: React.PropTypes.string,
- teamDisplayName: React.PropTypes.string
+ email: React.PropTypes.string
};
diff --git a/webapp/components/claim/components/email_to_oauth.jsx b/webapp/components/claim/components/email_to_oauth.jsx
index f4376067a..1fd284bed 100644
--- a/webapp/components/claim/components/email_to_oauth.jsx
+++ b/webapp/components/claim/components/email_to_oauth.jsx
@@ -2,12 +2,11 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
export default class EmailToOAuth extends React.Component {
constructor(props) {
@@ -31,16 +30,13 @@ export default class EmailToOAuth extends React.Component {
state.error = null;
this.setState(state);
- var postData = {};
- postData.password = password;
- postData.email = this.props.email;
- postData.team_name = this.props.teamName;
- postData.service = this.props.newType;
-
- Client.emailToOAuth(postData,
+ Client.emailToOAuth(
+ this.props.email,
+ password,
+ this.props.newType,
(data) => {
if (data.follow_link) {
- browserHistory.push(data.follow_link);
+ window.location.href = data.follow_link;
}
},
(error) => {
@@ -94,9 +90,8 @@ export default class EmailToOAuth extends React.Component {
<p>
<FormattedMessage
id='claim.email_to_oauth.enterPwd'
- defaultMessage='Enter the password for your {team} {site} account'
+ defaultMessage='Enter the password for your {site} account'
values={{
- team: this.props.teamDisplayName,
site: global.window.mm_config.SiteName
}}
/>
@@ -134,7 +129,5 @@ EmailToOAuth.defaultProps = {
};
EmailToOAuth.propTypes = {
newType: React.PropTypes.string,
- email: React.PropTypes.string,
- teamName: React.PropTypes.string,
- teamDisplayName: React.PropTypes.string
+ email: React.PropTypes.string
};
diff --git a/webapp/components/claim/components/ldap_to_email.jsx b/webapp/components/claim/components/ldap_to_email.jsx
index ed8a314bd..a10cefd6f 100644
--- a/webapp/components/claim/components/ldap_to_email.jsx
+++ b/webapp/components/claim/components/ldap_to_email.jsx
@@ -2,12 +2,11 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
import ReactDOM from 'react-dom';
import {FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
export default class LDAPToEmail extends React.Component {
constructor(props) {
@@ -45,16 +44,13 @@ export default class LDAPToEmail extends React.Component {
state.error = null;
this.setState(state);
- var postData = {};
- postData.email_password = password;
- postData.ldap_password = ldapPassword;
- postData.email = this.props.email;
- postData.team_name = this.props.teamName;
-
- Client.ldapToEmail(postData,
+ Client.ldapToEmail(
+ this.props.email,
+ password,
+ ldapPassword,
(data) => {
if (data.follow_link) {
- browserHistory.push(data.follow_link);
+ window.location.href = data.follow_link;
}
},
(error) => {
@@ -73,6 +69,13 @@ export default class LDAPToEmail extends React.Component {
formClass += ' has-error';
}
+ let passwordPlaceholder;
+ if (global.window.mm_config.LdapPasswordFieldName) {
+ passwordPlaceholder = global.window.mm_config.LdapPasswordFieldName;
+ } else {
+ passwordPlaceholder = Utils.localizeMessage('claim.ldap_to_email.ldapPwd', 'LDAP Password');
+ }
+
return (
<div>
<h3>
@@ -100,9 +103,9 @@ export default class LDAPToEmail extends React.Component {
<p>
<FormattedMessage
id='claim.ldap_to_email.enterLdapPwd'
- defaultMessage='Enter your LDAP password for your {team} {site} email account'
+ defaultMessage='Enter your {ldapPassword} for your {site} email account'
values={{
- team: this.props.teamDisplayName,
+ ldapPassword: passwordPlaceholder,
site: global.window.mm_config.SiteName
}}
/>
@@ -113,7 +116,7 @@ export default class LDAPToEmail extends React.Component {
className='form-control'
name='ldapPassword'
ref='ldappassword'
- placeholder={Utils.localizeMessage('claim.ldap_to_email.ldapPwd', 'LDAP Password')}
+ placeholder={passwordPlaceholder}
spellCheck='false'
/>
</div>
@@ -162,7 +165,5 @@ export default class LDAPToEmail extends React.Component {
LDAPToEmail.defaultProps = {
};
LDAPToEmail.propTypes = {
- email: React.PropTypes.string,
- teamName: React.PropTypes.string,
- teamDisplayName: React.PropTypes.string
+ email: React.PropTypes.string
};
diff --git a/webapp/components/claim/components/oauth_to_email.jsx b/webapp/components/claim/components/oauth_to_email.jsx
index 72e0500a9..7fd18aaa6 100644
--- a/webapp/components/claim/components/oauth_to_email.jsx
+++ b/webapp/components/claim/components/oauth_to_email.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
import ReactDOM from 'react-dom';
@@ -38,12 +38,9 @@ export default class OAuthToEmail extends React.Component {
state.error = null;
this.setState(state);
- var postData = {};
- postData.password = password;
- postData.email = this.props.email;
- postData.team_name = this.props.teamName;
-
- Client.oauthToEmail(postData,
+ Client.oauthToEmail(
+ this.props.email,
+ password,
(data) => {
if (data.follow_link) {
browserHistory.push(data.follow_link);
@@ -87,10 +84,9 @@ export default class OAuthToEmail extends React.Component {
</p>
<p>
<FormattedMessage
- id='claim.oauth_to_email_newPwd'
- defaultMessage='Enter a new password for your {team} {site} account'
+ id='claim.oauth_to_email.enterNewPwd'
+ defaultMessage='Enter a new password for your {site} account'
values={{
- team: this.props.teamDisplayName,
site: global.window.mm_config.SiteName
}}
/>
@@ -137,8 +133,6 @@ export default class OAuthToEmail extends React.Component {
OAuthToEmail.defaultProps = {
};
OAuthToEmail.propTypes = {
- teamName: React.PropTypes.string,
- teamDisplayName: React.PropTypes.string,
currentType: React.PropTypes.string,
email: React.PropTypes.string
};
diff --git a/webapp/components/create_comment.jsx b/webapp/components/create_comment.jsx
index a91c03d58..e8fa59165 100644
--- a/webapp/components/create_comment.jsx
+++ b/webapp/components/create_comment.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import UserStore from 'stores/user_store.jsx';
@@ -148,7 +148,6 @@ class CreateComment extends React.Component {
Client.createPost(
post,
- ChannelStore.getCurrent(),
(data) => {
AsyncClient.getPosts(this.props.channelId);
diff --git a/webapp/components/create_post.jsx b/webapp/components/create_post.jsx
index 232537d8b..9bbc44f38 100644
--- a/webapp/components/create_post.jsx
+++ b/webapp/components/create_post.jsx
@@ -11,7 +11,7 @@ import TutorialTip from './tutorial/tutorial_tip.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -172,7 +172,7 @@ class CreatePost extends React.Component {
GlobalActions.emitUserPostedEvent(post);
this.setState({messageText: '', submitting: false, postError: null, previews: [], serverError: null});
- Client.createPost(post, channel,
+ Client.createPost(post,
(data) => {
AsyncClient.getPosts();
diff --git a/webapp/components/signup_team_complete/components/team_signup_display_name_page.jsx b/webapp/components/create_team/components/display_name.jsx
index 111fc6835..e33eee1bc 100644
--- a/webapp/components/signup_team_complete/components/team_signup_display_name_page.jsx
+++ b/webapp/components/create_team/components/display_name.jsx
@@ -3,7 +3,8 @@
import ReactDOM from 'react-dom';
import * as utils from 'utils/utils.jsx';
-import * as client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
+import {Link} from 'react-router';
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
@@ -11,11 +12,11 @@ import logoImage from 'images/logo.png';
const holders = defineMessages({
required: {
- id: 'team_signup_display_name.required',
+ id: 'create_team_display_name.required',
defaultMessage: 'This field is required'
},
charLength: {
- id: 'team_signup_display_name.charLength',
+ id: 'create_team_display_name.charLength',
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
}
});
@@ -26,16 +27,11 @@ class TeamSignupDisplayNamePage extends React.Component {
constructor(props) {
super(props);
- this.submitBack = this.submitBack.bind(this);
this.submitNext = this.submitNext.bind(this);
this.state = {};
}
- submitBack(e) {
- e.preventDefault();
- this.props.state.wizard = 'welcome';
- this.props.updateParent(this.props.state);
- }
+
submitNext(e) {
e.preventDefault();
@@ -54,12 +50,14 @@ class TeamSignupDisplayNamePage extends React.Component {
this.props.state.team.name = utils.cleanUpUrlable(displayName);
this.props.updateParent(this.props.state);
}
+
handleFocus(e) {
e.preventDefault();
e.currentTarget.select();
}
+
render() {
- client.track('signup', 'signup_team_02_name');
+ Client.track('signup', 'signup_team_02_name');
var nameError = null;
var nameDivClass = 'form-group';
@@ -77,7 +75,7 @@ class TeamSignupDisplayNamePage extends React.Component {
/>
<h2>
<FormattedMessage
- id='team_signup_display_name.teamName'
+ id='create_team_display_name.teamName'
defaultMessage='Team Name'
/>
</h2>
@@ -101,7 +99,7 @@ class TeamSignupDisplayNamePage extends React.Component {
</div>
<div>
<FormattedMessage
- id='team_signup_display_name.nameHelp'
+ id='create_team_display_name.nameHelp'
defaultMessage='Name your team in any language. Your team name shows in menus and headings.'
/>
</div>
@@ -111,20 +109,17 @@ class TeamSignupDisplayNamePage extends React.Component {
onClick={this.submitNext}
>
<FormattedMessage
- id='team_signup_display_name.next'
+ id='create_team_display_name.next'
defaultMessage='Next'
/><i className='glyphicon glyphicon-chevron-right'></i>
</button>
<div className='margin--extra'>
- <a
- href='#'
- onClick={this.submitBack}
- >
+ <Link to='/select_team'>
<FormattedMessage
- id='team_signup_display_name.back'
+ id='create_team_display_name.back'
defaultMessage='Back to previous step'
/>
- </a>
+ </Link>
</div>
</form>
</div>
diff --git a/webapp/components/signup_team_complete/components/team_signup_url_page.jsx b/webapp/components/create_team/components/team_url.jsx
index b2ab57285..025103141 100644
--- a/webapp/components/signup_team_complete/components/team_signup_url_page.jsx
+++ b/webapp/components/create_team/components/team_url.jsx
@@ -4,8 +4,11 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
import Constants from 'utils/constants.jsx';
+import {browserHistory} from 'react-router';
import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
@@ -13,30 +16,30 @@ import logoImage from 'images/logo.png';
const holders = defineMessages({
required: {
- id: 'team_signup_url.required',
+ id: 'create_team_url.required',
defaultMessage: 'This field is required'
},
regex: {
- id: 'team_signup_url.regex',
+ id: 'create_team_url.regex',
defaultMessage: "Use only lower case letters, numbers and dashes. Must start with a letter and can't end in a dash."
},
charLength: {
- id: 'team_signup_url.charLength',
+ id: 'create_team_url.charLength',
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
},
taken: {
- id: 'team_signup_url.taken',
+ id: 'create_team_url.taken',
defaultMessage: 'URL is taken or contains a reserved word'
},
unavailable: {
- id: 'team_signup_url.unavailable',
+ id: 'create_team_url.unavailable',
defaultMessage: 'This URL is unavailable. Please try another.'
}
});
import React from 'react';
-class TeamSignupUrlPage extends React.Component {
+class TeamUrl extends React.Component {
constructor(props) {
super(props);
@@ -48,7 +51,7 @@ class TeamSignupUrlPage extends React.Component {
}
submitBack(e) {
e.preventDefault();
- this.props.state.wizard = 'team_display_name';
+ this.props.state.wizard = 'display_name';
this.props.updateParent(this.props.state);
}
submitNext(e) {
@@ -81,25 +84,39 @@ class TeamSignupUrlPage extends React.Component {
}
}
+ $('#finish-button').button('loading');
+ var teamSignup = JSON.parse(JSON.stringify(this.props.state));
+ teamSignup.team.type = 'O';
+ teamSignup.team.name = name;
+
Client.findTeamByName(name,
- (data) => {
- if (data) {
- this.setState({nameError: formatMessage(holders.unavailable)});
- } else {
- if (global.window.mm_config.SendEmailNotifications === 'true') {
- this.props.state.wizard = 'send_invites';
- } else {
- this.props.state.wizard = 'username';
- }
- this.props.state.team.type = 'O';
-
- this.props.state.team.name = name;
- this.props.updateParent(this.props.state);
- }
- },
- (err) => {
- this.setState({nameError: err.message});
- }
+ (findTeam) => {
+ if (findTeam) {
+ this.setState({nameError: formatMessage(holders.unavailable)});
+ $('#finish-button').button('reset');
+ } else {
+ Client.createTeam(teamSignup.team,
+ (team) => {
+ Client.track('signup', 'signup_team_08_complete');
+ $('#sign-up-button').button('reset');
+ TeamStore.saveTeam(team);
+ TeamStore.appendTeamMember({team_id: team.id, user_id: UserStore.getCurrentId(), roles: 'admin'});
+ TeamStore.emitChange();
+ browserHistory.push('/' + team.name + '/channels/town-square');
+ },
+ (err) => {
+ this.setState({nameError: err.message});
+ $('#finish-button').button('reset');
+ }
+ );
+
+ $('#finish-button').button('reset');
+ }
+ },
+ (err) => {
+ this.setState({nameError: err.message});
+ $('#finish-button').button('reset');
+ }
);
}
handleFocus(e) {
@@ -130,7 +147,7 @@ class TeamSignupUrlPage extends React.Component {
/>
<h2>
<FormattedMessage
- id='team_signup_url.teamUrl'
+ id='create_team_url.teamUrl'
defaultMessage='Team URL'
/>
</h2>
@@ -163,13 +180,13 @@ class TeamSignupUrlPage extends React.Component {
</div>
<p>
<FormattedMessage
- id='team_signup_url.webAddress'
+ id='create_team_url.webAddress'
defaultMessage='Choose the web address of your new team:'
/>
</p>
<ul className='color--light'>
<FormattedHTMLMessage
- id='team_signup_url.hint'
+ id='create_team_url.hint'
defaultMessage="<li>Short and memorable is best</li>
<li>Use lowercase letters, numbers and dashes</li>
<li>Must start with a letter and can't end in a dash</li>"
@@ -177,13 +194,14 @@ class TeamSignupUrlPage extends React.Component {
</ul>
<button
type='submit'
+ id='finish-button'
className='btn btn-primary margin--extra'
onClick={this.submitNext}
>
<FormattedMessage
- id='team_signup_url.next'
- defaultMessage='Next'
- /><i className='glyphicon glyphicon-chevron-right'></i>
+ id='create_team_password.finish'
+ defaultMessage='Finish'
+ />
</button>
<div className='margin--extra'>
<a
@@ -191,7 +209,7 @@ class TeamSignupUrlPage extends React.Component {
onClick={this.submitBack}
>
<FormattedMessage
- id='team_signup_url.back'
+ id='create_team_url.back'
defaultMessage='Back to previous step'
/>
</a>
@@ -202,10 +220,10 @@ class TeamSignupUrlPage extends React.Component {
}
}
-TeamSignupUrlPage.propTypes = {
+TeamUrl.propTypes = {
intl: intlShape.isRequired,
state: React.PropTypes.object,
updateParent: React.PropTypes.func
};
-export default injectIntl(TeamSignupUrlPage);
+export default injectIntl(TeamUrl);
diff --git a/webapp/components/create_team/create_team.jsx b/webapp/components/create_team/create_team.jsx
new file mode 100644
index 000000000..8a119a122
--- /dev/null
+++ b/webapp/components/create_team/create_team.jsx
@@ -0,0 +1,72 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import ErrorBar from 'components/error_bar.jsx';
+
+import {FormattedMessage} from 'react-intl';
+import {browserHistory, Link} from 'react-router';
+
+import React from 'react';
+
+export default class CreateTeam extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.submit = this.submit.bind(this);
+ this.updateParent = this.updateParent.bind(this);
+
+ const state = {};
+ state.team = {};
+ state.wizard = 'display_name';
+ this.state = state;
+ }
+
+ submit() {
+ // todo fill in
+ }
+
+ componentDidMount() {
+ browserHistory.push('/create_team/display_name');
+ }
+
+ updateParent(state) {
+ this.setState(state);
+ browserHistory.push('/create_team/' + state.wizard);
+ }
+
+ render() {
+ return (
+ <div>
+ <ErrorBar/>
+ <div className='signup-header'>
+ <Link to='/select_team'>
+ <span className='fa fa-chevron-left'/>
+ <FormattedMessage
+ id='web.header.back'
+ />
+ </Link>
+ </div>
+ <div className='col-sm-12'>
+ <div className='signup-team__container'>
+ <h1>{global.window.mm_config.SiteName}</h1>
+ <h4 className='color--light'>
+ <FormattedMessage
+ id='web.root.singup_info'
+ />
+ </h4>
+ <div className='signup__content'>
+ {React.cloneElement(this.props.children, {
+ state: this.state,
+ updateParent: this.updateParent
+ })}
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
+CreateTeam.propTypes = {
+ children: React.PropTypes.node
+};
diff --git a/webapp/components/delete_channel_modal.jsx b/webapp/components/delete_channel_modal.jsx
index 244472a56..222b72c41 100644
--- a/webapp/components/delete_channel_modal.jsx
+++ b/webapp/components/delete_channel_modal.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {Modal} from 'react-bootstrap';
import TeamStore from 'stores/team_store.jsx';
import Constants from 'utils/constants.jsx';
diff --git a/webapp/components/delete_post_modal.jsx b/webapp/components/delete_post_modal.jsx
index 0dbdc2b43..b2aea6590 100644
--- a/webapp/components/delete_post_modal.jsx
+++ b/webapp/components/delete_post_modal.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import PostStore from 'stores/post_store.jsx';
import ModalStore from 'stores/modal_store.jsx';
import {Modal} from 'react-bootstrap';
diff --git a/webapp/components/do_verify_email.jsx b/webapp/components/do_verify_email.jsx
index c3be111ed..fe4d61a72 100644
--- a/webapp/components/do_verify_email.jsx
+++ b/webapp/components/do_verify_email.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import {FormattedMessage} from 'react-intl';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import LoadingScreen from './loading_screen.jsx';
import {browserHistory, Link} from 'react-router';
@@ -25,14 +25,14 @@ export default class DoVerifyEmail extends React.Component {
const email = this.props.location.query.email;
Client.verifyEmail(
+ uid,
+ hid,
() => {
browserHistory.push('/' + teamName + '/login?extra=verified&email=' + email);
},
(err) => {
this.setState({verifyStatus: 'failure', serverError: err.message});
- },
- uid,
- hid
+ }
);
}
render() {
diff --git a/webapp/components/edit_channel_header_modal.jsx b/webapp/components/edit_channel_header_modal.jsx
index 35a5fb9dc..6a7cccebb 100644
--- a/webapp/components/edit_channel_header_modal.jsx
+++ b/webapp/components/edit_channel_header_modal.jsx
@@ -3,7 +3,7 @@
import ReactDOM from 'react-dom';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import * as Utils from 'utils/utils.jsx';
diff --git a/webapp/components/edit_channel_purpose_modal.jsx b/webapp/components/edit_channel_purpose_modal.jsx
index 31cbdd240..a4779d022 100644
--- a/webapp/components/edit_channel_purpose_modal.jsx
+++ b/webapp/components/edit_channel_purpose_modal.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
@@ -49,12 +49,9 @@ export default class EditChannelPurposeModal extends React.Component {
return;
}
- const data = {
- channel_id: this.props.channel.id,
- channel_purpose: ReactDOM.findDOMNode(this.refs.purpose).value.trim()
- };
-
- Client.updateChannelPurpose(data,
+ Client.updateChannelPurpose(
+ this.props.channel.id,
+ ReactDOM.findDOMNode(this.refs.purpose).value.trim(),
() => {
AsyncClient.getChannel(this.props.channel.id);
diff --git a/webapp/components/edit_post_modal.jsx b/webapp/components/edit_post_modal.jsx
index caf9a0ee5..bc67a34f9 100644
--- a/webapp/components/edit_post_modal.jsx
+++ b/webapp/components/edit_post_modal.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import Textbox from './textbox.jsx';
@@ -33,20 +33,25 @@ class EditPostModal extends React.Component {
this.handleEdit = this.handleEdit.bind(this);
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.handleKeyDown = this.handleKeyDown.bind(this);
this.onPreferenceChange = this.onPreferenceChange.bind(this);
- this.state = {editText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
+ this.state = {editText: '', originalText: '', title: '', post_id: '', channel_id: '', comments: 0, refocusId: ''};
}
handleEdit() {
var updatedPost = {};
updatedPost.message = this.state.editText.trim();
+ if (updatedPost.message === this.state.originalText.trim()) {
+ // no changes so just close the modal
+ $('#edit_post').modal('hide');
+ return;
+ }
+
if (updatedPost.message.length === 0) {
var tempState = this.state;
- delete tempState.editText;
+ Reflect.deleteProperty(tempState, 'editText');
BrowserStore.setItem('edit_state_transfer', tempState);
$('#edit_post').modal('hide');
GlobalActions.showDeletePostModal(PostStore.getPost(this.state.channel_id, this.state.post_id), this.state.comments);
@@ -79,12 +84,10 @@ class EditPostModal extends React.Component {
this.handleEdit(e);
}
}
- handleUserInput(e) {
- this.setState({editText: e.target.value});
- }
handleEditPostEvent(options) {
this.setState({
editText: options.message || '',
+ originalText: options.message || '',
title: options.title || '',
post_id: options.postId || '',
channel_id: options.channelId || '',
@@ -108,7 +111,7 @@ class EditPostModal extends React.Component {
var self = this;
$(ReactDOM.findDOMNode(this.refs.modal)).on('hidden.bs.modal', () => {
- self.setState({editText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''});
+ self.setState({editText: '', originalText: '', title: '', channel_id: '', post_id: '', comments: 0, refocusId: '', error: ''});
});
$(ReactDOM.findDOMNode(this.refs.modal)).on('show.bs.modal', (e) => {
@@ -116,7 +119,15 @@ class EditPostModal extends React.Component {
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-refocusid')});
+ self.setState({
+ editText: $(button).attr('data-message'),
+ originalText: $(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-refocusid')
+ });
});
$(ReactDOM.findDOMNode(this.refs.modal)).on('shown.bs.modal', () => {
@@ -163,17 +174,17 @@ class EditPostModal extends React.Component {
aria-label='Close'
onClick={this.handleEditClose}
>
- <span aria-hidden='true'>&times;</span>
+ <span aria-hidden='true'>{'×'}</span>
</button>
- <h4 className='modal-title'>
- <FormattedMessage
- id='edit_post.edit'
- defaultMessage='Edit {title}'
- values={{
- title: this.state.title
- }}
- />
- </h4>
+ <h4 className='modal-title'>
+ <FormattedMessage
+ id='edit_post.edit'
+ defaultMessage='Edit {title}'
+ values={{
+ title: this.state.title
+ }}
+ />
+ </h4>
</div>
<div className='edit-modal-body modal-body'>
<Textbox
diff --git a/webapp/components/error_bar.jsx b/webapp/components/error_bar.jsx
index 572f96e02..7257ffe94 100644
--- a/webapp/components/error_bar.jsx
+++ b/webapp/components/error_bar.jsx
@@ -29,8 +29,8 @@ export default class ErrorBar extends React.Component {
}
componentWillMount() {
- if (global.window.mm_config.SendEmailNotifications === 'false') {
- ErrorStore.storeLastError({message: Utils.localizeMessage('error_bar.preview_mode', 'Preview Mode: Email notifications have not been configured')});
+ if (!ErrorStore.getIgnoreEmailPreview() && global.window.mm_config.SendEmailNotifications === 'false') {
+ ErrorStore.storeLastError({email_preview: true, message: Utils.localizeMessage('error_bar.preview_mode', 'Preview Mode: Email notifications have not been configured')});
this.onErrorChange();
}
}
diff --git a/webapp/components/file_attachment.jsx b/webapp/components/file_attachment.jsx
index ccd4070aa..4a040a35b 100644
--- a/webapp/components/file_attachment.jsx
+++ b/webapp/components/file_attachment.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import {intlShape, injectIntl, defineMessages} from 'react-intl';
@@ -100,7 +100,7 @@ class FileAttachment extends React.Component {
getFileInfoFromName(name) {
var fileInfo = utils.splitFileLocation(name);
- fileInfo.path = utils.getWindowLocationOrigin() + '/api/v1/files/get' + fileInfo.path;
+ fileInfo.path = utils.getWindowLocationOrigin() + Client.getFilesRoute() + '/get' + fileInfo.path;
return fileInfo;
}
diff --git a/webapp/components/file_upload.jsx b/webapp/components/file_upload.jsx
index 8d2ec5ac8..03a8a8128 100644
--- a/webapp/components/file_upload.jsx
+++ b/webapp/components/file_upload.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import 'jquery-dragster/jquery.dragster.js';
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -49,9 +49,9 @@ class FileUpload extends React.Component {
fileUploadSuccess(channelId, data) {
this.props.onFileUpload(data.filenames, data.client_ids, channelId);
- var requests = this.state.requests;
+ const requests = JSON.parse(JSON.stringify(this.state.requests));
for (var j = 0; j < data.client_ids.length; j++) {
- delete requests[data.client_ids[j]];
+ Reflect.deleteProperty(requests, data.client_ids[j]);
}
this.setState({requests});
}
@@ -64,13 +64,13 @@ class FileUpload extends React.Component {
// clear any existing errors
this.props.onUploadError(null);
- var channelId = this.props.channelId || ChannelStore.getCurrentId();
+ const channelId = this.props.channelId || ChannelStore.getCurrentId();
- var uploadsRemaining = Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId);
- var numUploads = 0;
+ const uploadsRemaining = Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId);
+ let numUploads = 0;
// keep track of how many files have been too large
- var tooLargeFiles = [];
+ const tooLargeFiles = [];
for (let i = 0; i < files.length && numUploads < uploadsRemaining; i++) {
if (files[i].size > Constants.MAX_FILE_SIZE) {
@@ -81,18 +81,15 @@ class FileUpload extends React.Component {
// generate a unique id that can be used by other components to refer back to this upload
const clientId = Utils.generateId();
- // prepare data to be uploaded
- var formData = new FormData();
- formData.append('channel_id', channelId);
- formData.append('files', files[i], files[i].name);
- formData.append('client_ids', clientId);
-
- var request = Client.uploadFile(formData,
+ const request = Client.uploadFile(files[i],
+ files[i].name,
+ channelId,
+ clientId,
this.fileUploadSuccess.bind(this, channelId),
this.fileUploadFail.bind(this, clientId)
);
- var requests = this.state.requests;
+ const requests = this.state.requests;
requests[clientId] = request;
this.setState({requests});
@@ -231,8 +228,6 @@ class FileUpload extends React.Component {
// generate a unique id that can be used by other components to refer back to this file upload
var clientId = Utils.generateId();
- var formData = new FormData();
- formData.append('channel_id', channelId);
var d = new Date();
var hour;
if (d.getHours() < 10) {
@@ -247,16 +242,17 @@ class FileUpload extends React.Component {
min = String(d.getMinutes());
}
- var name = formatMessage(holders.pasted) + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext;
- formData.append('files', file, name);
- formData.append('client_ids', clientId);
+ const name = formatMessage(holders.pasted) + d.getFullYear() + '-' + d.getMonth() + '-' + d.getDate() + ' ' + hour + '-' + min + '.' + ext;
- var request = Client.uploadFile(formData,
+ const request = Client.uploadFile(file,
+ name,
+ channelId,
+ clientId,
self.fileUploadSuccess.bind(self, channelId),
self.fileUploadFail.bind(self, clientId)
);
- var requests = self.state.requests;
+ const requests = self.state.requests;
requests[clientId] = request;
self.setState({requests});
@@ -280,13 +276,13 @@ class FileUpload extends React.Component {
}
cancelUpload(clientId) {
- var requests = this.state.requests;
- var request = requests[clientId];
+ const requests = JSON.parse(JSON.stringify(this.state.requests));
+ const request = requests[clientId];
if (request) {
request.abort();
- delete requests[clientId];
+ Reflect.deleteProperty(requests, clientId);
this.setState({requests});
}
}
diff --git a/webapp/components/filtered_user_list.jsx b/webapp/components/filtered_user_list.jsx
index bd6c49714..5aa0bd96c 100644
--- a/webapp/components/filtered_user_list.jsx
+++ b/webapp/components/filtered_user_list.jsx
@@ -113,6 +113,7 @@ class FilteredUserList extends React.Component {
>
<UserList
users={users}
+ teamMembers={this.props.teamMembers}
actions={this.props.actions}
actionProps={this.props.actionProps}
/>
@@ -124,6 +125,7 @@ class FilteredUserList extends React.Component {
FilteredUserList.defaultProps = {
users: [],
+ teamMembers: [],
actions: [],
actionProps: {}
};
@@ -131,6 +133,7 @@ FilteredUserList.defaultProps = {
FilteredUserList.propTypes = {
intl: intlShape.isRequired,
users: React.PropTypes.arrayOf(React.PropTypes.object),
+ teamMembers: React.PropTypes.arrayOf(React.PropTypes.object),
actions: React.PropTypes.arrayOf(React.PropTypes.func),
actionProps: React.PropTypes.object,
style: React.PropTypes.object
diff --git a/webapp/components/not_logged_in.jsx b/webapp/components/header_footer_template.jsx
index 4beee6259..ce2f59541 100644
--- a/webapp/components/not_logged_in.jsx
+++ b/webapp/components/header_footer_template.jsx
@@ -9,12 +9,12 @@ import {Link} from 'react-router';
export default class NotLoggedIn extends React.Component {
componentDidMount() {
- $('body').attr('class', 'sticky');
- $('#root').attr('class', 'container-fluid');
+ $('body').addClass('sticky');
+ $('#root').addClass('container-fluid');
}
componentWillUnmount() {
- $('body').attr('class', '');
- $('#root').attr('class', '');
+ $('body').removeClass('sticky');
+ $('#root').removeClass('container-fluid');
}
render() {
return (
diff --git a/webapp/components/invite_member_modal.jsx b/webapp/components/invite_member_modal.jsx
index 17cec7aad..4ac620f08 100644
--- a/webapp/components/invite_member_modal.jsx
+++ b/webapp/components/invite_member_modal.jsx
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom';
import * as utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
import ModalStore from 'stores/modal_store.jsx';
import UserStore from 'stores/user_store.jsx';
diff --git a/webapp/components/logged_in.jsx b/webapp/components/logged_in.jsx
index 1dcb6b0aa..3941dd12c 100644
--- a/webapp/components/logged_in.jsx
+++ b/webapp/components/logged_in.jsx
@@ -2,39 +2,17 @@
// See License.txt for license information.
import $ from 'jquery';
+import LoadingScreen from 'components/loading_screen.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as GlobalActions from 'action_creators/global_actions.jsx';
import UserStore from 'stores/user_store.jsx';
-import ChannelStore from 'stores/channel_store.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import * as Utils from 'utils/utils.jsx';
-import Constants from 'utils/constants.jsx';
-const TutorialSteps = Constants.TutorialSteps;
-const Preferences = Constants.Preferences;
-import ErrorBar from 'components/error_bar.jsx';
import * as Websockets from 'action_creators/websocket_actions.jsx';
-import LoadingScreen from 'components/loading_screen.jsx';
+import Constants from 'utils/constants.jsx';
import {browserHistory} from 'react-router';
-import SidebarRight from 'components/sidebar_right.jsx';
-import SidebarRightMenu from 'components/sidebar_right_menu.jsx';
-import Navbar from 'components/navbar.jsx';
-
-// Modals
-import GetPostLinkModal from 'components/get_post_link_modal.jsx';
-import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal.jsx';
-import EditPostModal from 'components/edit_post_modal.jsx';
-import DeletePostModal from 'components/delete_post_modal.jsx';
-import MoreChannelsModal from 'components/more_channels.jsx';
-import TeamSettingsModal from 'components/team_settings_modal.jsx';
-import RemovedFromChannelModal from 'components/removed_from_channel_modal.jsx';
-import RegisterAppModal from 'components/register_app_modal.jsx';
-import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
-import InviteMemberModal from 'components/invite_member_modal.jsx';
-import SelectTeamModal from 'components/admin_console/select_team_modal.jsx';
-
const CLIENT_STATUS_INTERVAL = 30000;
const BACKSPACE_CHAR = 8;
@@ -45,19 +23,22 @@ export default class LoggedIn extends React.Component {
super(params);
this.onUserChanged = this.onUserChanged.bind(this);
+ this.setupUser = this.setupUser.bind(this);
this.state = {
- user: null,
- profiles: null
+ user: UserStore.getCurrentUser()
};
+
+ if (this.state.user) {
+ this.setupUser(this.state.user);
+ }
}
+
isValidState() {
- return this.state.user != null && this.state.profiles != null;
+ return this.state.user != null;
}
- onUserChanged() {
- // Grab the current user
- const user = UserStore.getCurrentUser();
+ setupUser(user) {
// Update segment indentify
if (global.window.mm_config.SegmentDeveloperKey != null && global.window.mm_config.SegmentDeveloperKey !== '') {
global.window.analytics.identify(user.id, {
@@ -65,7 +46,6 @@ export default class LoggedIn extends React.Component {
email: user.email,
createdAt: user.create_at,
username: user.username,
- team_id: user.team_id,
id: user.id
});
}
@@ -78,25 +58,19 @@ export default class LoggedIn extends React.Component {
Utils.applyTheme(Constants.THEMES.default);
}
}
+ }
- // Go to tutorial if we are first arrivign
- const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
- if (tutorialStep <= TutorialSteps.INTRO_SCREENS) {
- browserHistory.push(Utils.getTeamURLFromAddressBar() + '/tutorial');
- }
-
- // Get profiles
- const profiles = UserStore.getProfiles();
+ onUserChanged() {
+ // Grab the current user
+ const user = UserStore.getCurrentUser();
+ this.setupUser(user);
this.setState({
- user,
- profiles
+ user
});
}
- componentWillMount() {
- // Emit view action
- GlobalActions.viewLoggedIn();
+ componentWillMount() {
// Listen for user
UserStore.addChangeListener(this.onUserChanged);
@@ -116,7 +90,7 @@ export default class LoggedIn extends React.Component {
}
console.log('detected logout from a different tab'); //eslint-disable-line no-console
- browserHistory.push('/' + this.props.params.team);
+ browserHistory.push('/');
}
if (e.originalEvent.key === '__login__' && e.originalEvent.storageArea === localStorage && e.originalEvent.newValue) {
@@ -170,18 +144,6 @@ export default class LoggedIn extends React.Component {
$('body').addClass('ios');
}
- // Set up tracking for whether the window is active
- window.isActive = true;
- $(window).on('focus', () => {
- AsyncClient.updateLastViewedAt();
- ChannelStore.resetCounts(ChannelStore.getCurrentId());
- ChannelStore.emitChange();
- window.isActive = true;
- });
- $(window).on('blur', () => {
- window.isActive = false;
- });
-
// if preferences have already been stored in local storage do not wait until preference store change is fired and handled in channel.jsx
const selectedFont = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'selected_font', Constants.DEFAULT_FONT);
Utils.applyFont(selectedFont);
@@ -193,13 +155,11 @@ export default class LoggedIn extends React.Component {
}
});
}
+
componentWillUnmount() {
$('#root').attr('class', '');
clearInterval(this.intervalId);
- $(window).off('focus');
- $(window).off('blur');
-
Websockets.close();
UserStore.removeChangeListener(this.onUserChanged);
@@ -211,75 +171,18 @@ export default class LoggedIn extends React.Component {
$(window).off('keydown.preventBackspace');
}
+
render() {
if (!this.isValidState()) {
return <LoadingScreen/>;
}
- let content = [];
- if (this.props.children) {
- content = this.props.children;
- } else {
- content.push(
- this.props.navbar
- );
- content.push(
- this.props.sidebar
- );
- content.push(
- <div
- key='inner-wrap'
- className='inner-wrap channel__wrap'
- >
- <div className='row header'>
- <div id='navbar'>
- <Navbar/>
- </div>
- </div>
- <div className='row main'>
- {React.cloneElement(this.props.center, {
- user: this.state.user,
- profiles: this.state.profiles
- })}
- </div>
- </div>
- );
- }
- return (
- <div className='channel-view'>
- <ErrorBar/>
- <div className='container-fluid'>
- <SidebarRight/>
- <SidebarRightMenu/>
- {content}
-
- <GetPostLinkModal/>
- <GetTeamInviteLinkModal/>
- <InviteMemberModal/>
- <ImportThemeModal/>
- <TeamSettingsModal/>
- <MoreChannelsModal/>
- <EditPostModal/>
- <DeletePostModal/>
- <RemovedFromChannelModal/>
- <RegisterAppModal/>
- <SelectTeamModal/>
- </div>
- </div>
- );
+ return React.cloneElement(this.props.children, {
+ user: this.state.user
+ });
}
}
-LoggedIn.defaultProps = {
-};
-
LoggedIn.propTypes = {
- children: React.PropTypes.oneOfType([
- React.PropTypes.arrayOf(React.PropTypes.element),
- React.PropTypes.element
- ]),
- navbar: React.PropTypes.element,
- sidebar: React.PropTypes.element,
- center: React.PropTypes.element,
- params: React.PropTypes.object
+ children: React.PropTypes.object
};
diff --git a/webapp/components/login/login.jsx b/webapp/components/login/login.jsx
index a3dadbf36..c5955a1f4 100644
--- a/webapp/components/login/login.jsx
+++ b/webapp/components/login/login.jsx
@@ -5,12 +5,14 @@ import LoginEmail from './components/login_email.jsx';
import LoginUsername from './components/login_username.jsx';
import LoginLdap from './components/login_ldap.jsx';
import LoginMfa from './components/login_mfa.jsx';
+import ErrorBar from 'components/error_bar.jsx';
-import TeamStore from 'stores/team_store.jsx';
+import * as GlobalActions from '../../action_creators/global_actions.jsx';
import UserStore from 'stores/user_store.jsx';
+import Client from 'utils/web_client.jsx';
import * as TextFormatting from 'utils/text_formatting.jsx';
-import * as Client from 'utils/client.jsx';
+
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
@@ -18,40 +20,24 @@ import {FormattedMessage} from 'react-intl';
import {browserHistory, Link} from 'react-router';
import React from 'react';
+import logoImage from 'images/logo.png';
export default class Login extends React.Component {
constructor(props) {
super(props);
- this.getStateFromStores = this.getStateFromStores.bind(this);
- this.onTeamChange = this.onTeamChange.bind(this);
this.preSubmit = this.preSubmit.bind(this);
this.submit = this.submit.bind(this);
+ this.finishSignin = this.finishSignin.bind(this);
- const state = this.getStateFromStores();
- state.doneCheckLogin = false;
+ const state = {};
+ state.showMfa = false;
this.state = state;
}
componentDidMount() {
- TeamStore.addChangeListener(this.onTeamChange);
- Client.getMeLoggedIn((data) => {
- if (data && data.logged_in !== 'false') {
- browserHistory.push('/' + this.props.params.team + '/channels/town-square');
- } else {
- this.setState({doneCheckLogin: true}); //eslint-disable-line react/no-did-mount-set-state
- }
- });
- }
- componentWillUnmount() {
- TeamStore.removeChangeListener(this.onTeamChange);
- }
- getStateFromStores() {
- return {
- currentTeam: TeamStore.getByName(this.props.params.team)
- };
- }
- onTeamChange() {
- this.setState(this.getStateFromStores());
+ if (UserStore.getCurrentUser()) {
+ browserHistory.push('/select_team');
+ }
}
preSubmit(method, loginId, password) {
if (global.window.mm_config.EnableMultifactorAuthentication !== 'true') {
@@ -59,7 +45,7 @@ export default class Login extends React.Component {
return;
}
- Client.checkMfa(method, this.state.currentTeam.name, loginId,
+ Client.checkMfa(method, loginId,
(data) => {
if (data.mfa_required === 'true') {
this.setState({showMfa: true, method, loginId, password});
@@ -78,27 +64,41 @@ export default class Login extends React.Component {
}
);
}
+ finishSignin() {
+ GlobalActions.emitInitialLoad(
+ () => {
+ browserHistory.push('/select_team');
+ }
+ );
+ }
+
submit(method, loginId, password, token) {
this.setState({showMfa: false, serverEmailError: null, serverUsernameError: null, serverLdapError: null});
- const team = this.state.currentTeam.name;
-
if (method === Constants.EMAIL_SERVICE) {
- Client.loginByEmail(team, loginId, password, token,
+ Client.webLogin(
+ loginId,
+ null,
+ password,
+ token,
() => {
UserStore.setLastEmail(loginId);
- browserHistory.push('/' + team + '/channels/town-square');
+ this.finishSignin();
},
(err) => {
if (err.id === 'api.user.login.not_verified.app_error') {
- browserHistory.push('/should_verify_email?teamname=' + encodeURIComponent(team) + '&email=' + encodeURIComponent(loginId));
+ browserHistory.push('/should_verify_email?&email=' + encodeURIComponent(loginId));
return;
}
this.setState({serverEmailError: err.message});
}
);
} else if (method === Constants.USERNAME_SERVICE) {
- Client.loginByUsername(team, loginId, password, token,
+ Client.webLogin(
+ null,
+ loginId,
+ password,
+ token,
() => {
UserStore.setLastUsername(loginId);
@@ -106,7 +106,7 @@ export default class Login extends React.Component {
if (redirect) {
browserHistory.push(decodeURIComponent(redirect));
} else {
- browserHistory.push('/' + team + '/channels/town-square');
+ this.finishSignin();
}
},
(err) => {
@@ -120,13 +120,16 @@ export default class Login extends React.Component {
}
);
} else if (method === Constants.LDAP_SERVICE) {
- Client.loginByLdap(team, loginId, password, token,
+ Client.loginByLdap(
+ loginId,
+ password,
+ token,
() => {
const redirect = Utils.getUrlParameter('redirect');
if (redirect) {
browserHistory.push(decodeURIComponent(redirect));
} else {
- browserHistory.push('/' + team + '/channels/town-square');
+ this.finishSignin();
}
},
(err) => {
@@ -144,7 +147,7 @@ export default class Login extends React.Component {
return (
<div>
<img
- src='/api/v1/admin/get_brand_image'
+ src={Client.getAdminRoute() + '/get_brand_image'}
/>
<p dangerouslySetInnerHTML={{__html: TextFormatting.formatText(text)}}/>
</div>
@@ -153,7 +156,7 @@ export default class Login extends React.Component {
return null;
}
- createLoginOptions(currentTeam) {
+ createLoginOptions() {
const extraParam = Utils.getUrlParameter('extra');
let extraBox = '';
if (extraParam) {
@@ -187,10 +190,19 @@ export default class Login extends React.Component {
/>
</div>
);
+ } else if (extraParam === Constants.PASSWORD_CHANGE) {
+ extraBox = (
+ <div className='alert alert-success'>
+ <i className='fa fa-check'/>
+ <FormattedMessage
+ id='login.passwordChanged'
+ defaultMessage=' Password updated successfully'
+ />
+ </div>
+ );
}
}
- const teamName = currentTeam.name;
const ldapEnabled = global.window.mm_config.EnableLdap === 'true';
const gitlabSigninEnabled = global.window.mm_config.EnableSignUpWithGitLab === 'true';
const googleSigninEnabled = global.window.mm_config.EnableSignUpWithGoogle === 'true';
@@ -200,10 +212,10 @@ export default class Login extends React.Component {
const oauthLogins = [];
if (gitlabSigninEnabled) {
oauthLogins.push(
- <Link
+ <a
className='btn btn-custom-login gitlab'
key='gitlab'
- to={'/api/v1/oauth/gitlab/login?team=' + encodeURIComponent(teamName)}
+ href={Client.getOAuthRoute() + '/gitlab/login'}
>
<span className='icon'/>
<span>
@@ -212,7 +224,7 @@ export default class Login extends React.Component {
defaultMessage='with GitLab'
/>
</span>
- </Link>
+ </a>
);
}
@@ -221,7 +233,7 @@ export default class Login extends React.Component {
<Link
className='btn btn-custom-login google'
key='google'
- to={'/api/v1/oauth/google/login?team=' + encodeURIComponent(teamName)}
+ to={Client.getOAuthRoute() + '/google/login'}
>
<span className='icon'/>
<span>
@@ -238,7 +250,6 @@ export default class Login extends React.Component {
if (emailSigninEnabled) {
emailLogin = (
<LoginEmail
- teamName={teamName}
serverError={this.state.serverEmailError}
submit={this.preSubmit}
/>
@@ -263,7 +274,6 @@ export default class Login extends React.Component {
if (usernameSigninEnabled) {
usernameLogin = (
<LoginUsername
- teamName={teamName}
serverError={this.state.serverUsernameError}
submit={this.preSubmit}
/>
@@ -288,7 +298,6 @@ export default class Login extends React.Component {
if (ldapEnabled) {
ldapLogin = (
<LoginLdap
- teamName={teamName}
serverError={this.state.serverLdapError}
submit={this.preSubmit}
/>
@@ -309,34 +318,31 @@ export default class Login extends React.Component {
}
}
- let userSignUp;
- if (currentTeam.allow_open_invite) {
- userSignUp = (
- <div>
- <span>
+ const userSignUp = (
+ <div>
+ <span>
+ <FormattedMessage
+ id='login.noAccount'
+ defaultMessage="Don't have an account? "
+ />
+ <Link
+ to={'/signup_user_complete'}
+ className='signup-team-login'
+ >
<FormattedMessage
- id='login.noAccount'
- defaultMessage="Don't have an account? "
+ id='login.create'
+ defaultMessage='Create one now'
/>
- <Link
- to={'/signup_user_complete/?id=' + currentTeam.invite_id}
- className='signup-team-login'
- >
- <FormattedMessage
- id='login.create'
- defaultMessage='Create one now'
- />
- </Link>
- </span>
- </div>
- );
- }
+ </Link>
+ </span>
+ </div>
+ );
let forgotPassword;
if (usernameSigninEnabled || emailSigninEnabled) {
forgotPassword = (
<div className='form-group'>
- <Link to={'/' + teamName + '/reset_password'}>
+ <Link to={'/reset_password'}>
<FormattedMessage
id='login.forgot'
defaultMessage='I forgot my password'
@@ -346,23 +352,6 @@ export default class Login extends React.Component {
);
}
- let teamSignUp;
- if (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp()) {
- teamSignUp = (
- <div className='margin--extra'>
- <Link
- to='/'
- className='signup-team-login'
- >
- <FormattedMessage
- id='login.createTeam'
- defaultMessage='Create a new team'
- />
- </Link>
- </div>
- );
- }
-
return (
<div>
{extraBox}
@@ -372,16 +361,10 @@ export default class Login extends React.Component {
{ldapLogin}
{userSignUp}
{forgotPassword}
- {teamSignUp}
</div>
);
}
render() {
- const currentTeam = this.state.currentTeam;
- if (currentTeam == null || !this.state.doneCheckLogin) {
- return <div/>;
- }
-
let content;
let customContent;
let customClass;
@@ -395,7 +378,7 @@ export default class Login extends React.Component {
/>
);
} else {
- content = this.createLoginOptions(currentTeam);
+ content = this.createLoginOptions();
customContent = this.createCustomLogin();
if (customContent) {
customClass = 'branded';
@@ -404,36 +387,23 @@ export default class Login extends React.Component {
return (
<div>
- <div className='signup-header'>
- <Link to='/'>
- <span className='fa fa-chevron-left'/>
- <FormattedMessage
- id='web.header.back'
- />
- </Link>
- </div>
+ <ErrorBar/>
<div className='col-sm-12'>
<div className={'signup-team__container ' + customClass}>
<div className='signup__markdown'>
{customContent}
</div>
+ <img
+ className='signup-team-logo'
+ src={logoImage}
+ />
+ <h1>{global.window.mm_config.SiteName}</h1>
+ <h4 className='color--light'>
+ <FormattedMessage
+ id='web.root.singup_info'
+ />
+ </h4>
<div className='signup__content'>
- <h5 className='margin--less'>
- <FormattedMessage
- id='login.signTo'
- defaultMessage='Sign in to:'
- />
- </h5>
- <h2 className='signup-team__name'>{currentTeam.display_name}</h2>
- <h2 className='signup-team__subdomain'>
- <FormattedMessage
- id='login.on'
- defaultMessage='on {siteName}'
- values={{
- siteName: global.window.mm_config.SiteName
- }}
- />
- </h2>
{content}
</div>
</div>
diff --git a/webapp/components/member_list_team.jsx b/webapp/components/member_list_team.jsx
index bb5eee496..d0714e942 100644
--- a/webapp/components/member_list_team.jsx
+++ b/webapp/components/member_list_team.jsx
@@ -4,6 +4,8 @@
import FilteredUserList from './filtered_user_list.jsx';
import TeamMembersDropdown from './team_members_dropdown.jsx';
import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
import React from 'react';
@@ -13,18 +15,23 @@ export default class MemberListTeam extends React.Component {
this.getUsers = this.getUsers.bind(this);
this.onChange = this.onChange.bind(this);
+ this.onTeamChange = this.onTeamChange.bind(this);
this.state = {
- users: this.getUsers()
+ users: this.getUsers(),
+ teamMembers: TeamStore.getMembersForTeam()
};
}
componentDidMount() {
UserStore.addChangeListener(this.onChange);
+ TeamStore.addChangeListener(this.onTeamChange);
+ AsyncClient.getTeamMembers(TeamStore.getCurrentId());
}
componentWillUnmount() {
UserStore.removeChangeListener(this.onChange);
+ TeamStore.removeChangeListener(this.onTeamChange);
}
getUsers() {
@@ -46,11 +53,18 @@ export default class MemberListTeam extends React.Component {
});
}
+ onTeamChange() {
+ this.setState({
+ teamMembers: TeamStore.getMembersForTeam()
+ });
+ }
+
render() {
return (
<FilteredUserList
style={this.props.style}
users={this.state.users}
+ teamMembers={this.state.teamMembers}
actions={[TeamMembersDropdown]}
/>
);
diff --git a/webapp/components/more_channels.jsx b/webapp/components/more_channels.jsx
index 5ccf9c11e..3ab05341b 100644
--- a/webapp/components/more_channels.jsx
+++ b/webapp/components/more_channels.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
-import * as client from 'utils/client.jsx';
+import client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import LoadingScreen from './loading_screen.jsx';
diff --git a/webapp/components/navbar.jsx b/webapp/components/navbar.jsx
index e4e64c12e..919a72d0a 100644
--- a/webapp/components/navbar.jsx
+++ b/webapp/components/navbar.jsx
@@ -18,7 +18,7 @@ import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
import TeamStore from 'stores/team_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
diff --git a/webapp/components/navbar_dropdown.jsx b/webapp/components/navbar_dropdown.jsx
index da1ae237e..19b99a14d 100644
--- a/webapp/components/navbar_dropdown.jsx
+++ b/webapp/components/navbar_dropdown.jsx
@@ -6,6 +6,7 @@ import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
+import TeamStore from 'stores/team_store.jsx';
import AboutBuildModal from './about_build_modal.jsx';
import TeamMembersModal from './team_members_modal.jsx';
import ToggleModalButton from './toggle_modal_button.jsx';
@@ -25,10 +26,13 @@ export default class NavbarDropdown extends React.Component {
this.handleAboutModal = this.handleAboutModal.bind(this);
this.aboutModalDismissed = this.aboutModalDismissed.bind(this);
+ this.onTeamChange = this.onTeamChange.bind(this);
this.state = {
showUserSettingsModal: false,
- showAboutModal: false
+ showAboutModal: false,
+ teams: TeamStore.getAll(),
+ teamMembers: TeamStore.getTeamMembers()
};
}
handleAboutModal() {
@@ -37,6 +41,7 @@ export default class NavbarDropdown extends React.Component {
aboutModalDismissed() {
this.setState({showAboutModal: false});
}
+
componentDidMount() {
$(ReactDOM.findDOMNode(this.refs.dropdown)).on('hide.bs.dropdown', () => {
$('.sidebar--left .dropdown-menu').scrollTop(0);
@@ -45,10 +50,22 @@ export default class NavbarDropdown extends React.Component {
this.blockToggle = false;
}, 100);
});
+
+ TeamStore.addChangeListener(this.onTeamChange);
+ }
+
+ onTeamChange() {
+ this.setState({
+ teams: TeamStore.getAll(),
+ teamMembers: TeamStore.getTeamMembers()
+ });
}
+
componentWillUnmount() {
$(ReactDOM.findDOMNode(this.refs.dropdown)).off('hide.bs.dropdown');
+ TeamStore.removeChangeListener(this.onTeamChange);
}
+
render() {
var teamLink = '';
var inviteLink = '';
@@ -130,7 +147,7 @@ export default class NavbarDropdown extends React.Component {
if (isAdmin || window.EnableAdminOnlyIntegrations !== 'true') {
integrationsLink = (
<li>
- <Link to={'/settings/integrations'}>
+ <Link to={'/' + Utils.getTeamNameFromUrl() + '/settings/integrations'}>
<FormattedMessage
id='navbar_dropdown.integrations'
defaultMessage='Integrations'
@@ -163,8 +180,7 @@ export default class NavbarDropdown extends React.Component {
<li key='newTeam_li'>
<Link
key='newTeam_a'
- target='_blank'
- to={Utils.getWindowLocationOrigin() + '/signup_team'}
+ to='/create_team'
>
<FormattedMessage
id='navbar_dropdown.create'
@@ -175,6 +191,34 @@ export default class NavbarDropdown extends React.Component {
);
}
+ if (this.state.teamMembers && this.state.teamMembers.length > 0) {
+ teams.push(
+ <li
+ key='teamDiv'
+ className='divider'
+ ></li>
+ );
+
+ for (var index in this.state.teamMembers) {
+ if (this.state.teamMembers.hasOwnProperty(index)) {
+ var teamMember = this.state.teamMembers[index];
+ var team = this.state.teams[teamMember.team_id];
+
+ if (team.name !== this.props.teamName) {
+ teams.push(
+ <li key={'team_' + team.name}>
+ <Link
+ to={'/' + team.name + '/channels/town-square'}
+ >
+ {team.display_name}
+ </Link>
+ </li>
+ );
+ }
+ }
+ }
+ }
+
let helpLink = null;
if (global.window.mm_config.HelpLink) {
helpLink = (
@@ -245,12 +289,15 @@ export default class NavbarDropdown extends React.Component {
{inviteLink}
{teamLink}
<li>
- <Link to={'/' + this.props.teamName + '/logout'}>
+ <a
+ href='#'
+ onClick={GlobalActions.emitUserLoggedOutEvent}
+ >
<FormattedMessage
id='navbar_dropdown.logout'
defaultMessage='Logout'
/>
- </Link>
+ </a>
</li>
{adminDivider}
{teamSettings}
diff --git a/webapp/components/needs_team.jsx b/webapp/components/needs_team.jsx
index f624b1ebc..59797f086 100644
--- a/webapp/components/needs_team.jsx
+++ b/webapp/components/needs_team.jsx
@@ -1,22 +1,156 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
+import React from 'react';
+
+import $ from 'jquery';
+
+import {browserHistory} from 'react-router';
+import * as Utils from 'utils/utils.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import UserStore from 'stores/user_store.jsx';
+import PreferenceStore from 'stores/preference_store.jsx';
+import ChannelStore from 'stores/channel_store.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
+import Constants from 'utils/constants.jsx';
+const TutorialSteps = Constants.TutorialSteps;
+const Preferences = Constants.Preferences;
-import React from 'react';
+import ErrorBar from 'components/error_bar.jsx';
+import SidebarRight from 'components/sidebar_right.jsx';
+import SidebarRightMenu from 'components/sidebar_right_menu.jsx';
+import Navbar from 'components/navbar.jsx';
+
+// Modals
+import GetPostLinkModal from 'components/get_post_link_modal.jsx';
+import GetTeamInviteLinkModal from 'components/get_team_invite_link_modal.jsx';
+import EditPostModal from 'components/edit_post_modal.jsx';
+import DeletePostModal from 'components/delete_post_modal.jsx';
+import MoreChannelsModal from 'components/more_channels.jsx';
+import TeamSettingsModal from 'components/team_settings_modal.jsx';
+import RemovedFromChannelModal from 'components/removed_from_channel_modal.jsx';
+import RegisterAppModal from 'components/register_app_modal.jsx';
+import ImportThemeModal from 'components/user_settings/import_theme_modal.jsx';
+import InviteMemberModal from 'components/invite_member_modal.jsx';
+import SelectTeamModal from 'components/admin_console/select_team_modal.jsx';
export default class NeedsTeam extends React.Component {
+ constructor(params) {
+ super(params);
+
+ this.onChanged = this.onChanged.bind(this);
+
+ this.state = {
+ profiles: UserStore.getProfiles(),
+ team: TeamStore.getCurrent()
+ };
+ }
+
+ onChanged() {
+ this.setState({
+ profiles: UserStore.getProfiles(),
+ team: TeamStore.getCurrent()
+ });
+ }
+
componentWillMount() {
- GlobalActions.loadTeamRequiredPage();
+ UserStore.addChangeListener(this.onChanged);
+ TeamStore.addChangeListener(this.onChanged);
+
+ // Emit view action
+ GlobalActions.viewLoggedIn();
+
+ // Go to tutorial if we are first arrivign
+ const tutorialStep = PreferenceStore.getInt(Preferences.TUTORIAL_STEP, UserStore.getCurrentId(), 999);
+ if (tutorialStep <= TutorialSteps.INTRO_SCREENS) {
+ browserHistory.push(Utils.getTeamURLFromAddressBar() + '/tutorial');
+ }
+
+ // Set up tracking for whether the window is active
+ window.isActive = true;
+ $(window).on('focus', () => {
+ AsyncClient.updateLastViewedAt();
+ ChannelStore.resetCounts(ChannelStore.getCurrentId());
+ ChannelStore.emitChange();
+ window.isActive = true;
+ });
+ $(window).on('blur', () => {
+ window.isActive = false;
+ });
+ }
+
+ componentWillUnmount() {
+ UserStore.removeChangeListener(this.onChanged);
+ TeamStore.addChangeListener(this.onChanged);
+ $(window).off('focus');
+ $(window).off('blur');
}
+
render() {
- return this.props.children;
+ let content = [];
+ if (this.props.children) {
+ content = this.props.children;
+ } else {
+ content.push(
+ this.props.navbar
+ );
+ content.push(
+ this.props.sidebar
+ );
+ content.push(
+ <div
+ key='inner-wrap'
+ className='inner-wrap channel__wrap'
+ >
+ <div className='row header'>
+ <div id='navbar'>
+ <Navbar/>
+ </div>
+ </div>
+ <div className='row main'>
+ {React.cloneElement(this.props.center, {
+ user: this.props.user,
+ profiles: this.state.profiles,
+ team: this.state.team
+ })}
+ </div>
+ </div>
+ );
+ }
+ return (
+ <div className='channel-view'>
+ <ErrorBar/>
+ <div className='container-fluid'>
+ <SidebarRight/>
+ <SidebarRightMenu/>
+ {content}
+
+ <GetPostLinkModal/>
+ <GetTeamInviteLinkModal/>
+ <InviteMemberModal/>
+ <ImportThemeModal/>
+ <TeamSettingsModal/>
+ <MoreChannelsModal/>
+ <EditPostModal/>
+ <DeletePostModal/>
+ <RemovedFromChannelModal/>
+ <RegisterAppModal/>
+ <SelectTeamModal/>
+ </div>
+ </div>
+ );
}
}
-NeedsTeam.defaultProps = {
-};
-
NeedsTeam.propTypes = {
- children: React.PropTypes.object
+ children: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.element),
+ React.PropTypes.element
+ ]),
+ navbar: React.PropTypes.element,
+ sidebar: React.PropTypes.element,
+ center: React.PropTypes.element,
+ params: React.PropTypes.object,
+ user: React.PropTypes.object
};
diff --git a/webapp/components/new_channel_flow.jsx b/webapp/components/new_channel_flow.jsx
index 82494dac0..7019da4aa 100644
--- a/webapp/components/new_channel_flow.jsx
+++ b/webapp/components/new_channel_flow.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import UserStore from 'stores/user_store.jsx';
import NewChannelModal from './new_channel_modal.jsx';
@@ -106,11 +106,7 @@ class NewChannelFlow extends React.Component {
(data) => {
Client.getChannel(
data.id,
- (data2, textStatus, xhr) => {
- if (xhr.status === 304 || !data2) {
- return;
- }
-
+ (data2) => {
AppDispatcher.handleServerAction({
type: ActionTypes.RECEIVED_CHANNEL,
channel: data2.channel,
diff --git a/webapp/components/notify_counts.jsx b/webapp/components/notify_counts.jsx
index acc64dfb0..9238c8736 100644
--- a/webapp/components/notify_counts.jsx
+++ b/webapp/components/notify_counts.jsx
@@ -32,17 +32,22 @@ export default class NotifyCounts extends React.Component {
this.onListenerChange = this.onListenerChange.bind(this);
this.state = getCountsStateFromStores();
+ this.mounted = false;
}
componentDidMount() {
+ this.mounted = true;
ChannelStore.addChangeListener(this.onListenerChange);
}
componentWillUnmount() {
+ this.mounted = false;
ChannelStore.removeChangeListener(this.onListenerChange);
}
onListenerChange() {
- var newState = getCountsStateFromStores();
- if (!utils.areObjectsEqual(newState, this.state)) {
- this.setState(newState);
+ if (this.mounted) {
+ var newState = getCountsStateFromStores();
+ if (!utils.areObjectsEqual(newState, this.state)) {
+ this.setState(newState);
+ }
}
}
render() {
diff --git a/webapp/components/password_reset_form.jsx b/webapp/components/password_reset_form.jsx
index 863420902..23b8952cc 100644
--- a/webapp/components/password_reset_form.jsx
+++ b/webapp/components/password_reset_form.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
@@ -40,16 +40,12 @@ class PasswordResetForm extends React.Component {
error: null
});
- const data = {};
- data.new_password = password;
- data.hash = this.props.location.query.h;
- data.data = this.props.location.query.d;
- data.name = this.props.params.team;
-
- Client.resetPassword(data,
+ Client.resetPassword(
+ this.props.location.query.code,
+ password,
() => {
this.setState({error: null});
- browserHistory.push('/' + this.props.params.team + '/login');
+ browserHistory.push('/login?extra=' + Constants.PASSWORD_CHANGE);
},
(err) => {
this.setState({error: err.message});
diff --git a/webapp/components/password_reset_send_link.jsx b/webapp/components/password_reset_send_link.jsx
index e3ab8949e..65d9439bd 100644
--- a/webapp/components/password_reset_send_link.jsx
+++ b/webapp/components/password_reset_send_link.jsx
@@ -4,7 +4,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
-import * as client from 'utils/client.jsx';
+import client from 'utils/web_client.jsx';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
@@ -43,10 +43,8 @@ class PasswordResetSendLink extends React.Component {
error: ''
});
- var data = {};
- data.email = email;
- data.name = this.props.params.team;
- client.sendPasswordReset(data,
+ client.sendPasswordReset(
+ email,
() => {
this.setState({
error: null,
diff --git a/webapp/components/popover_list_members.jsx b/webapp/components/popover_list_members.jsx
index 8c3c381af..387c37ab5 100644
--- a/webapp/components/popover_list_members.jsx
+++ b/webapp/components/popover_list_members.jsx
@@ -7,6 +7,7 @@ import UserStore from 'stores/user_store.jsx';
import {Popover, Overlay} from 'react-bootstrap';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
import {browserHistory} from 'react-router';
@@ -97,7 +98,7 @@ export default class PopoverListMembers extends React.Component {
className='more-modal__image'
width='26px'
height='26px'
- src={`/api/v1/users/${m.id}/image?time=${m.update_at}`}
+ src={`${Client.getUsersRoute()}/${m.id}/image?time=${m.update_at}`}
/>
<div className='more-modal__details'>
<div
diff --git a/webapp/components/post.jsx b/webapp/components/post.jsx
index 7fabec741..ae3fa9c98 100644
--- a/webapp/components/post.jsx
+++ b/webapp/components/post.jsx
@@ -10,7 +10,7 @@ import ChannelStore from 'stores/channel_store.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
@@ -48,7 +48,7 @@ export default class Post extends React.Component {
e.preventDefault();
var post = this.props.post;
- Client.createPost(post, post.channel_id,
+ Client.createPost(post,
(data) => {
AsyncClient.getPosts();
diff --git a/webapp/components/register_app_modal.jsx b/webapp/components/register_app_modal.jsx
index c632233cf..82a095c75 100644
--- a/webapp/components/register_app_modal.jsx
+++ b/webapp/components/register_app_modal.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import ModalStore from 'stores/modal_store.jsx';
import {Modal} from 'react-bootstrap';
diff --git a/webapp/components/rename_channel_modal.jsx b/webapp/components/rename_channel_modal.jsx
index 3e47847e7..ed045da91 100644
--- a/webapp/components/rename_channel_modal.jsx
+++ b/webapp/components/rename_channel_modal.jsx
@@ -3,7 +3,7 @@
import ReactDOM from 'react-dom';
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import Constants from 'utils/constants.jsx';
diff --git a/webapp/components/rhs_comment.jsx b/webapp/components/rhs_comment.jsx
index 53170ee15..709865dc1 100644
--- a/webapp/components/rhs_comment.jsx
+++ b/webapp/components/rhs_comment.jsx
@@ -9,7 +9,7 @@ import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
import FileAttachmentList from './file_attachment_list.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
var ActionTypes = Constants.ActionTypes;
import * as TextFormatting from 'utils/text_formatting.jsx';
@@ -43,7 +43,7 @@ class RhsComment extends React.Component {
e.preventDefault();
var post = this.props.post;
- Client.createPost(post, post.channel_id,
+ Client.createPost(post,
(data) => {
AsyncClient.getPosts(post.channel_id);
@@ -261,7 +261,7 @@ class RhsComment extends React.Component {
<div className='post__content'>
<div className='post__img'>
<img
- src={'/api/v1/users/' + post.user_id + '/image?time=' + timestamp}
+ src={Client.getUsersRoute() + '/' + post.user_id + '/image?time=' + timestamp}
height='36'
width='36'
/>
diff --git a/webapp/components/rhs_header_post.jsx b/webapp/components/rhs_header_post.jsx
index 189ee0acb..493040800 100644
--- a/webapp/components/rhs_header_post.jsx
+++ b/webapp/components/rhs_header_post.jsx
@@ -3,6 +3,7 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import Constants from 'utils/constants.jsx';
+import * as GlobalActions from 'action_creators/global_actions.jsx';
import {FormattedMessage} from 'react-intl';
@@ -21,16 +22,7 @@ export default class RhsHeaderPost extends React.Component {
}
handleClose(e) {
e.preventDefault();
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_SEARCH,
- results: null
- });
-
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECEIVED_POST_SELECTED,
- postId: null
- });
+ GlobalActions.emitCloseRightHandSide();
}
handleBack(e) {
e.preventDefault();
diff --git a/webapp/components/root.jsx b/webapp/components/root.jsx
index 59364d085..0adbc7f04 100644
--- a/webapp/components/root.jsx
+++ b/webapp/components/root.jsx
@@ -1,10 +1,10 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import $ from 'jquery';
+//import $ from 'jquery';
+//import Client from 'utils/web_client.jsx';
+
import * as GlobalActions from 'action_creators/global_actions.jsx';
-import * as Client from 'utils/client.jsx';
-import BrowserStore from 'stores/browser_store.jsx';
import LocalizationStore from 'stores/localization_store.jsx';
import {IntlProvider} from 'react-intl';
@@ -14,6 +14,7 @@ import React from 'react';
import FastClick from 'fastclick';
import {browserHistory} from 'react-router';
+import UserStore from 'stores/user_store.jsx';
export default class Root extends React.Component {
constructor(props) {
@@ -29,15 +30,16 @@ export default class Root extends React.Component {
localizationChanged() {
this.setState({locale: LocalizationStore.getLocale(), translations: LocalizationStore.getTranslations()});
}
+
redirectIfNecessary(props) {
if (props.location.pathname === '/') {
- Client.getMeLoggedIn((data) => {
- if (!data || data.logged_in === 'false') {
- browserHistory.push('/signup_team');
- } else {
- browserHistory.push('/' + data.team_name + '/channels/town-square');
- }
- });
+ if (UserStore.getNoAccounts()) {
+ browserHistory.push('/signup_user_complete');
+ } else if (UserStore.getCurrentUser()) {
+ browserHistory.push('/select_team');
+ } else {
+ browserHistory.push('/login');
+ }
}
}
componentWillReceiveProps(newProps) {
@@ -47,28 +49,6 @@ export default class Root extends React.Component {
// Setup localization listener
LocalizationStore.addChangeListener(this.localizationChanged);
- // Browser store check version
- BrowserStore.checkVersion();
-
- window.onerror = (msg, url, line, column, stack) => {
- var l = {};
- l.level = 'ERROR';
- l.message = 'msg: ' + msg + ' row: ' + line + ' col: ' + column + ' stack: ' + stack + ' url: ' + url;
-
- $.ajax({
- url: '/api/v1/admin/log_client',
- dataType: 'json',
- contentType: 'application/json',
- type: 'POST',
- data: JSON.stringify(l)
- });
-
- if (window.mm_config.EnableDeveloper === 'true') {
- window.ErrorStore.storeLastError({message: 'DEVELOPER MODE: A javascript error has occured. Please use the javascript console to capture and report the error (row: ' + line + ' col: ' + column + ').'});
- window.ErrorStore.emitChange();
- }
- };
-
// Ya....
/*eslint-disable */
if (window.mm_config.SegmentDeveloperKey != null && window.mm_config.SegmentDeveloperKey !== "") {
@@ -76,11 +56,7 @@ export default class Root extends React.Component {
analytics.load(window.mm_config.SegmentDeveloperKey);
analytics.page();
}}();
- } else {
- global.window.analytics = {};
- global.window.analytics.page = function(){};
- global.window.analytics.track = function(){};
- }
+ }
/*eslint-enable */
// Fastclick
diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx
index caaf0f844..1156ac0f1 100644
--- a/webapp/components/search_bar.jsx
+++ b/webapp/components/search_bar.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import ReactDOM from 'react-dom';
-import * as client from 'utils/client.jsx';
+import client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import SearchStore from 'stores/search_store.jsx';
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
diff --git a/webapp/components/select_team/select_team.jsx b/webapp/components/select_team/select_team.jsx
new file mode 100644
index 000000000..5804a641e
--- /dev/null
+++ b/webapp/components/select_team/select_team.jsx
@@ -0,0 +1,257 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import UserStore from 'stores/user_store.jsx';
+import TeamStore from 'stores/team_store.jsx';
+import * as Utils from 'utils/utils.jsx';
+import ErrorBar from 'components/error_bar.jsx';
+import LoadingScreen from 'components/loading_screen.jsx';
+import Client from 'utils/web_client.jsx';
+import * as AsyncClient from 'utils/async_client.jsx';
+import * as GlobalActions from 'action_creators/global_actions.jsx';
+
+import * as TextFormatting from 'utils/text_formatting.jsx';
+
+import {Link} from 'react-router';
+
+import {FormattedMessage} from 'react-intl';
+
+//import {browserHistory, Link} from 'react-router';
+
+import React from 'react';
+import logoImage from 'images/logo.png';
+
+export default class Login extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.onTeamChange = this.onTeamChange.bind(this);
+
+ const state = this.getStateFromStores(false);
+ this.state = state;
+ }
+
+ componentDidMount() {
+ TeamStore.addChangeListener(this.onTeamChange);
+ AsyncClient.getAllTeamListings();
+ }
+
+ componentWillUnmount() {
+ TeamStore.removeChangeListener(this.onTeamChange);
+ }
+
+ onTeamChange() {
+ this.setState(this.getStateFromStores(true));
+ }
+
+ getStateFromStores(loaded) {
+ return {
+ teams: TeamStore.getAll(),
+ teamMembers: TeamStore.getTeamMembers(),
+ teamListings: TeamStore.getTeamListings(),
+ loaded
+ };
+ }
+
+ createCustomLogin() {
+ if (global.window.mm_license.IsLicensed === 'true' &&
+ global.window.mm_license.CustomBrand === 'true' &&
+ global.window.mm_config.EnableCustomBrand === 'true') {
+ const text = global.window.mm_config.CustomBrandText || '';
+
+ return (
+ <div>
+ <img
+ src={Client.getAdminRoute() + '/get_brand_image'}
+ />
+ <p dangerouslySetInnerHTML={{__html: TextFormatting.formatText(text)}}/>
+ </div>
+ );
+ }
+
+ return null;
+ }
+
+ render() {
+ var content;
+
+ let customClass;
+ const customContent = this.createCustomLogin();
+ if (customContent) {
+ customClass = 'branded';
+ }
+
+ var teamContents = [];
+ var isAlreadyMember = new Map();
+
+ for (var index in this.state.teamMembers) {
+ if (this.state.teamMembers.hasOwnProperty(index)) {
+ var teamMember = this.state.teamMembers[index];
+ var team = this.state.teams[teamMember.team_id];
+ isAlreadyMember[teamMember.team_id] = true;
+ teamContents.push(
+ <div
+ key={'team_' + team.name}
+ className='signup-team-dir'
+ >
+ <Link
+ to={'/' + team.name + '/channels/town-square'}
+ >
+ <span className='signup-team-dir__name'>{team.display_name}</span>
+ <span
+ className='glyphicon glyphicon-menu-right right signup-team-dir__arrow'
+ aria-hidden='true'
+ />
+ </Link>
+ </div>
+ );
+ }
+ }
+
+ if (!teamContents || teamContents.length === 0) {
+ teamContents = (
+ <div className='signup-team-dir-err'>
+ <div>
+ <FormattedMessage
+ id='signup_team.no_teams'
+ defaultMessage='You do not appear to be a member of any team. Please ask your administrator for an invite, join an open team if one exists or possibly create a new team.'
+ />
+ </div>
+ </div>
+ );
+ }
+
+ content = (
+ <div className='signup__content'>
+ <h4>
+ <FormattedMessage
+ id='signup_team.choose'
+ defaultMessage='Teams you are a member of:'
+ />
+ </h4>
+ <div className='signup-team-all'>
+ {teamContents}
+ </div>
+ </div>
+ );
+
+ var openTeamContents = [];
+
+ for (var id in this.state.teamListings) {
+ if (this.state.teamListings.hasOwnProperty(id) && !isAlreadyMember[id]) {
+ var openTeam = this.state.teamListings[id];
+ openTeamContents.push(
+ <div
+ key={'team_' + openTeam.name}
+ className='signup-team-dir'
+ >
+ <Link
+ to={`/signup_user_complete/?id=${openTeam.invite_id}`}
+ >
+ <span className='signup-team-dir__name'>{openTeam.display_name}</span>
+ <span
+ className='glyphicon glyphicon-menu-right right signup-team-dir__arrow'
+ aria-hidden='true'
+ />
+ </Link>
+ </div>
+ );
+ }
+ }
+
+ var openContent;
+ if (openTeamContents.length > 0) {
+ openContent = (
+ <div className='signup__content'>
+ <h4>
+ <FormattedMessage
+ id='signup_team.join_open'
+ defaultMessage='Open teams you can join: '
+ />
+ </h4>
+ <div className='signup-team-all'>
+ {openTeamContents}
+ </div>
+ </div>
+ );
+ }
+
+ if (!this.state.loaded) {
+ openContent = <LoadingScreen/>;
+ }
+
+ var isSystemAdmin = Utils.isSystemAdmin(UserStore.getCurrentUser().roles);
+
+ let teamSignUp;
+ if (isSystemAdmin || (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp())) {
+ teamSignUp = (
+ <div className='margin--extra'>
+ <Link
+ to='/create_team'
+ className='signup-team-login'
+ >
+ <FormattedMessage
+ id='login.createTeam'
+ defaultMessage='Create a new team'
+ />
+ </Link>
+ </div>
+ );
+ }
+
+ let adminConsoleLink;
+ if (isSystemAdmin) {
+ adminConsoleLink = (
+ <div className='margin--extra'>
+ <Link
+ to='/admin_console'
+ className='signup-team-login'
+ >
+ <FormattedMessage
+ id='navbar_dropdown.console'
+ defaultMessage='System Console'
+ />
+ </Link>
+ </div>
+ );
+ }
+
+ return (
+ <div>
+ <ErrorBar/>
+ <div className='signup-header'>
+ <a
+ href='#'
+ onClick={GlobalActions.emitUserLoggedOutEvent}
+ >
+ <span className='fa fa-chevron-left'/>
+ <FormattedMessage
+ id='navbar_dropdown.logout'
+ />
+ </a>
+ </div>
+ <div className='col-sm-12'>
+ <div className={'signup-team__container ' + customClass}>
+ <div className='signup__markdown'>
+ {customContent}
+ </div>
+ <img
+ className='signup-team-logo'
+ src={logoImage}
+ />
+ <h1>{global.window.mm_config.SiteName}</h1>
+ <h4 className='color--light'>
+ <FormattedMessage
+ id='web.root.singup_info'
+ />
+ </h4>
+ {content}
+ {openContent}
+ {teamSignUp}
+ {adminConsoleLink}
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
diff --git a/webapp/components/should_verify_email.jsx b/webapp/components/should_verify_email.jsx
index 5103452b0..a95101ba1 100644
--- a/webapp/components/should_verify_email.jsx
+++ b/webapp/components/should_verify_email.jsx
@@ -2,7 +2,7 @@
// See License.txt for license information.
import {FormattedMessage} from 'react-intl';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
import {Link} from 'react-router';
@@ -18,19 +18,19 @@ export default class ShouldVerifyEmail extends React.Component {
};
}
handleResend() {
- const teamName = this.props.location.query.teamname;
const email = this.props.location.query.email;
this.setState({resendStatus: 'sending'});
- Client.resendVerification(() => {
- this.setState({resendStatus: 'success'});
- },
- () => {
- this.setState({resendStatus: 'failure'});
- },
- teamName,
- email);
+ Client.resendVerification(
+ email,
+ () => {
+ this.setState({resendStatus: 'success'});
+ },
+ () => {
+ this.setState({resendStatus: 'failure'});
+ }
+ );
}
render() {
let resendConfirm = '';
diff --git a/webapp/components/sidebar_header.jsx b/webapp/components/sidebar_header.jsx
index ec3a03d17..143a3458a 100644
--- a/webapp/components/sidebar_header.jsx
+++ b/webapp/components/sidebar_header.jsx
@@ -7,6 +7,7 @@ import NavbarDropdown from './navbar_dropdown.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import * as Utils from 'utils/utils.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
const Preferences = Constants.Preferences;
@@ -61,7 +62,7 @@ export default class SidebarHeader extends React.Component {
profilePicture = (
<img
className='user__picture'
- src={'/api/v1/users/' + me.id + '/image?time=' + me.update_at}
+ src={Client.getUsersRoute() + '/' + me.id + '/image?time=' + me.update_at}
/>
);
}
diff --git a/webapp/components/sidebar_right_menu.jsx b/webapp/components/sidebar_right_menu.jsx
index c7e6577fc..42bc7ce53 100644
--- a/webapp/components/sidebar_right_menu.jsx
+++ b/webapp/components/sidebar_right_menu.jsx
@@ -228,13 +228,16 @@ export default class SidebarRightMenu extends React.Component {
{manageLink}
{consoleLink}
<li>
- <Link to={Utils.getTeamURLFromAddressBar() + '/logout'}>
+ <a
+ href='#'
+ onClick={GlobalActions.emitUserLoggedOutEvent}
+ >
<i className='fa fa-sign-out'></i>
<FormattedMessage
id='sidebar_right_menu.logout'
defaultMessage='Logout'
/>
- </Link>
+ </a>
</li>
<li className='divider'></li>
{helpLink}
diff --git a/webapp/components/signup_team.jsx b/webapp/components/signup_team.jsx
deleted file mode 100644
index 634aa6e68..000000000
--- a/webapp/components/signup_team.jsx
+++ /dev/null
@@ -1,235 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ChoosePage from './team_signup_choose_auth.jsx';
-import EmailSignUpPage from './team_signup_with_email.jsx';
-import SSOSignupPage from './team_signup_with_sso.jsx';
-import LdapSignUpPage from './team_signup_with_ldap.jsx';
-import Constants from 'utils/constants.jsx';
-import TeamStore from 'stores/team_store.jsx';
-import * as AsyncClient from 'utils/async_client.jsx';
-
-import {FormattedMessage} from 'react-intl';
-
-import React from 'react';
-import {Link} from 'react-router';
-
-import logoImage from 'images/logo.png';
-
-export default class TeamSignUp extends React.Component {
- constructor(props) {
- super(props);
-
- this.updatePage = this.updatePage.bind(this);
- this.onTeamUpdate = this.onTeamUpdate.bind(this);
-
- var count = 0;
-
- if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
- count = count + 1;
- }
-
- if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
- count = count + 1;
- }
-
- if (global.window.mm_config.EnableLdap === 'true') {
- count = count + 1;
- }
-
- if (count > 1) {
- this.state = {page: 'choose'};
- } else if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
- this.state = {page: 'email'};
- } else if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
- this.state = {page: 'gitlab'};
- } else if (global.window.mm_config.EnableLdap === 'true') {
- this.state = {page: 'ldap'};
- } else {
- this.state = {page: 'none'};
- }
- }
-
- updatePage(page) {
- this.setState({page});
- }
-
- componentWillMount() {
- if (global.window.mm_config.EnableTeamListing === 'true') {
- AsyncClient.getAllTeams();
- this.onTeamUpdate();
- }
- }
-
- componentDidMount() {
- TeamStore.addChangeListener(this.onTeamUpdate);
- }
-
- componentWillUnmount() {
- TeamStore.removeChangeListener(this.onTeamUpdate);
- }
-
- onTeamUpdate() {
- this.setState({
- teams: TeamStore.getAll()
- });
- }
-
- render() {
- let teamListing = null;
-
- if (global.window.mm_config.EnableTeamListing === 'true') {
- if (this.state.teams == null) {
- teamListing = (<div/>);
- } else if (this.state.teams.length === 0) {
- if (global.window.mm_config.EnableTeamCreation !== 'true') {
- teamListing = (
- <div>
- <FormattedMessage
- id='signup_team.noTeams'
- defaultMessage='There are no teams included in the Team Directory and team creation has been disabled.'
- />
- </div>
- );
- }
- } else {
- teamListing = (
- <div>
- <h4>
- <FormattedMessage
- id='signup_team.choose'
- defaultMessage='Choose a Team'
- />
- </h4>
- <div className='signup-team-all'>
- {
- Object.values(this.state.teams).map((team) => {
- if (team.allow_team_listing) {
- return (
- <div
- key={'team_' + team.name}
- className='signup-team-dir'
- >
- <Link
- to={'/' + team.name}
- >
- <span className='signup-team-dir__name'>{team.display_name}</span>
- <span
- className='glyphicon glyphicon-menu-right right signup-team-dir__arrow'
- aria-hidden='true'
- />
- </Link>
- </div>
- );
- }
- return null;
- })
- }
- </div>
- <h4>
- <FormattedMessage
- id='signup_team.createTeam'
- defaultMessage='Or Create a Team'
- />
- </h4>
- </div>
- );
- }
- }
-
- let signupMethod = null;
- let goBack = (
- <div className='signup-header'>
- <a
- href='#'
- onClick={
- (e) => {
- e.preventDefault();
- this.updatePage('choose');
- }
- }
- >
- <span className='fa fa-chevron-left'/>
- <FormattedMessage
- id='web.header.back'
- />
- </a>
- </div>
- );
-
- if (global.window.mm_config.EnableTeamCreation !== 'true') {
- if (teamListing == null) {
- signupMethod = (
- <FormattedMessage
- id='signup_team.disabled'
- defaultMessage='Team creation has been disabled. Please contact an administrator for access.'
- />
- );
- }
- } else if (this.state.page === 'choose') {
- signupMethod = (
- <ChoosePage
- updatePage={this.updatePage}
- />
- );
- goBack = null;
- } else if (this.state.page === 'email') {
- signupMethod = (
- <div>
- <EmailSignUpPage/>
- </div>
- );
- } else if (this.state.page === 'ldap') {
- return (
- <div>
- {teamListing}
- <LdapSignUpPage/>
- </div>
- );
- } else if (this.state.page === 'gitlab') {
- signupMethod = (
- <SSOSignupPage service={Constants.GITLAB_SERVICE}/>
- );
- } else if (this.state.page === 'google') {
- signupMethod = (
- <SSOSignupPage service={Constants.GOOGLE_SERVICE}/>
- );
- } else if (this.state.page === 'none') {
- signupMethod = (
- <FormattedMessage
- id='signup_team.none'
- defaultMessage='No team creation method has been enabled. Please contact an administrator for access.'
- />
- );
- goBack = null;
- }
-
- return (
- <div>
- {goBack}
- <div className='col-sm-12'>
- <div className='signup-team__container'>
- <img
- className='signup-team-logo'
- src={logoImage}
- />
- <h1>{global.window.mm_config.SiteName}</h1>
- <h4 className='color--light'>
- <FormattedMessage
- id='web.root.singup_info'
- />
- </h4>
- <div id='signup-team'>
- {teamListing}
- {signupMethod}
- </div>
- </div>
- </div>
- </div>
- );
- }
-}
-
-TeamSignUp.propTypes = {
-};
-
diff --git a/webapp/components/signup_team_complete/components/signup_team_complete.jsx b/webapp/components/signup_team_complete/components/signup_team_complete.jsx
index 95b41dbde..00fdafe5f 100644
--- a/webapp/components/signup_team_complete/components/signup_team_complete.jsx
+++ b/webapp/components/signup_team_complete/components/signup_team_complete.jsx
@@ -74,6 +74,7 @@ export default class SignupTeamComplete extends React.Component {
SignupTeamComplete.defaultProps = {
};
+
SignupTeamComplete.propTypes = {
location: React.PropTypes.object,
children: React.PropTypes.node
diff --git a/webapp/components/signup_team_complete/components/team_signup_email_item.jsx b/webapp/components/signup_team_complete/components/team_signup_email_item.jsx
deleted file mode 100644
index c3903ca85..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_email_item.jsx
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import * as Utils from 'utils/utils.jsx';
-
-import {intlShape, injectIntl, defineMessages} from 'react-intl';
-
-const holders = defineMessages({
- validEmail: {
- id: 'team_signup_email.validEmail',
- defaultMessage: 'Please enter a valid email address'
- },
- different: {
- id: 'team_signup_email.different',
- defaultMessage: 'Please use a different email than the one used at signup'
- },
- address: {
- id: 'team_signup_email.address',
- defaultMessage: 'Email Address'
- }
-});
-
-import React from 'react';
-
-class TeamSignupEmailItem extends React.Component {
- constructor(props) {
- super(props);
-
- this.getValue = this.getValue.bind(this);
- this.validate = this.validate.bind(this);
-
- this.state = {};
- }
- getValue() {
- return ReactDOM.findDOMNode(this.refs.email).value.trim();
- }
- validate(teamEmail) {
- const {formatMessage} = this.props.intl;
- const email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
-
- if (!email) {
- return true;
- }
-
- if (!Utils.isEmail(email)) {
- this.setState({emailError: formatMessage(holders.validEmail)});
- return false;
- } else if (email === teamEmail) {
- this.setState({emailError: formatMessage(holders.different)});
- return false;
- }
-
- this.setState({emailError: ''});
- return true;
- }
- render() {
- let emailError = null;
- let emailDivClass = 'form-group';
- if (this.state.emailError) {
- emailError = <label className='control-label'>{this.state.emailError}</label>;
- emailDivClass += ' has-error';
- }
-
- return (
- <div className={emailDivClass}>
- <input
- autoFocus={this.props.focus}
- type='email'
- ref='email'
- className='form-control'
- placeholder={this.props.intl.formatMessage(holders.address)}
- defaultValue={this.props.email}
- maxLength='128'
- spellCheck='false'
- />
- {emailError}
- </div>
- );
- }
-}
-
-TeamSignupEmailItem.propTypes = {
- intl: intlShape.isRequired,
- focus: React.PropTypes.bool,
- email: React.PropTypes.string
-};
-
-export default injectIntl(TeamSignupEmailItem, {withRef: true});
diff --git a/webapp/components/signup_team_complete/components/team_signup_finished.jsx b/webapp/components/signup_team_complete/components/team_signup_finished.jsx
deleted file mode 100644
index 9fbb8473a..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_finished.jsx
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {FormattedMessage} from 'react-intl';
-
-import React from 'react';
-
-export default class FinishedPage extends React.Component {
- render() {
- return (
- <FormattedMessage
- id='signup_team_complete.completed'
- defaultMessage="You've already completed the signup process for this invitation or this invitation has expired."
- />
- );
- }
-}
diff --git a/webapp/components/signup_team_complete/components/team_signup_password_page.jsx b/webapp/components/signup_team_complete/components/team_signup_password_page.jsx
deleted file mode 100644
index 7b8b49e0c..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_password_page.jsx
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import ReactDOM from 'react-dom';
-import * as Client from 'utils/client.jsx';
-import BrowserStore from 'stores/browser_store.jsx';
-import UserStore from 'stores/user_store.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
-
-import logoImage from 'images/logo.png';
-
-const holders = defineMessages({
- passwordError: {
- id: 'team_signup_password.passwordError',
- defaultMessage: 'Please enter at least {chars} characters'
- },
- creating: {
- id: 'team_signup_password.creating',
- defaultMessage: 'Creating team...'
- }
-});
-
-import React from 'react';
-
-class TeamSignupPasswordPage extends React.Component {
- constructor(props) {
- super(props);
-
- this.submitBack = this.submitBack.bind(this);
- this.submitNext = this.submitNext.bind(this);
-
- this.state = {};
- }
- submitBack(e) {
- e.preventDefault();
- this.props.state.wizard = 'username';
- this.props.updateParent(this.props.state);
- }
- submitNext(e) {
- e.preventDefault();
-
- var password = ReactDOM.findDOMNode(this.refs.password).value.trim();
- if (!password || password.length < Constants.MIN_PASSWORD_LENGTH) {
- this.setState({passwordError: this.props.intl.formatMessage(holders.passwordError, {chars: Constants.MIN_PASSWORD_LENGTH})});
- return;
- }
-
- this.setState({passwordError: null, serverError: null});
- $('#finish-button').button('loading');
- var teamSignup = JSON.parse(JSON.stringify(this.props.state));
- teamSignup.user.password = password;
- teamSignup.user.allow_marketing = true;
- delete teamSignup.wizard;
-
- Client.createTeamFromSignup(teamSignup,
- () => {
- Client.track('signup', 'signup_team_08_complete');
-
- var props = this.props;
-
- Client.loginByEmail(
- teamSignup.team.name,
- teamSignup.team.email,
- teamSignup.user.password,
- '', // No MFA Token
- () => {
- UserStore.setLastEmail(teamSignup.team.email);
- if (this.props.hash > 0) {
- BrowserStore.setGlobalItem(this.props.hash, JSON.stringify({wizard: 'finished'}));
- }
-
- $('#sign-up-button').button('reset');
- props.state.wizard = 'finished';
- props.updateParent(props.state, true);
-
- browserHistory.push('/' + teamSignup.team.name + '/channels/town-square');
- },
- (err) => {
- if (err.id === 'api.user.login.not_verified.app_error') {
- browserHistory.push('/should_verify_email?email=' + encodeURIComponent(teamSignup.team.email) + '&teamname=' + encodeURIComponent(teamSignup.team.name));
- } else {
- this.setState({serverError: err.message});
- $('#finish-button').button('reset');
- }
- }
- );
- },
- (err) => {
- this.setState({serverError: err.message});
- $('#finish-button').button('reset');
- }
- );
- }
- render() {
- Client.track('signup', 'signup_team_07_password');
-
- var passwordError = null;
- var passwordDivStyle = 'form-group';
- if (this.state.passwordError) {
- passwordError = <div className='form-group has-error'><label className='control-label'>{this.state.passwordError}</label></div>;
- passwordDivStyle = ' has-error';
- }
-
- var serverError = null;
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- return (
- <div>
- <form>
- <img
- className='signup-team-logo'
- src={logoImage}
- />
- <h2 className='margin--less'>
- <FormattedMessage
- id='team_signup_password.yourPassword'
- defaultMessage='Your password'
- />
- </h2>
- <h5 className='color--light'>
- <FormattedMessage
- id='team_signup_password.selectPassword'
- defaultMessage="Select a password that you'll use to login with your email address:"
- />
- </h5>
- <div className='inner__content margin--extra'>
- <h5><strong>
- <FormattedMessage
- id='team_signup_password.email'
- defaultMessage='Email'
- />
- </strong></h5>
- <div className='block--gray form-group'>{this.props.state.team.email}</div>
- <div className={passwordDivStyle}>
- <div className='row'>
- <div className='col-sm-11'>
- <h5><strong>
- <FormattedMessage
- id='team_signup_password.choosePwd'
- defaultMessage='Choose your password'
- />
- </strong></h5>
- <input
- autoFocus={true}
- type='password'
- ref='password'
- className='form-control'
- placeholder=''
- maxLength='128'
- spellCheck='false'
- />
- <span className='color--light help-block'>
- <FormattedMessage
- id='team_signup_password.hint'
- defaultMessage='Passwords must contain {min} to {max} characters. Your password will be strongest if it contains a mix of symbols, numbers, and upper and lowercase characters.'
- values={{
- min: Constants.MIN_PASSWORD_LENGTH,
- max: Constants.MAX_PASSWORD_LENGTH
- }}
- />
- </span>
- </div>
- </div>
- {passwordError}
- {serverError}
- </div>
- </div>
- <div className='form-group'>
- <button
- type='submit'
- className='btn btn-primary margin--extra'
- id='finish-button'
- data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> ' + this.props.intl.formatMessage(holders.creating)}
- onClick={this.submitNext}
- >
- <FormattedMessage
- id='team_signup_password.finish'
- defaultMessage='Finish'
- />
- </button>
- </div>
- <p>
- <FormattedHTMLMessage
- id='team_signup_password.agreement'
- defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}."
- values={{
- siteName: global.window.mm_config.SiteName
- }}
- />
- </p>
- <div className='margin--extra'>
- <a
- href='#'
- onClick={this.submitBack}
- >
- <FormattedMessage
- id='team_signup_password.back'
- defaultMessage='Back to previous step'
- />
- </a>
- </div>
- </form>
- </div>
- );
- }
-}
-
-TeamSignupPasswordPage.defaultProps = {
- state: {},
- hash: ''
-};
-TeamSignupPasswordPage.propTypes = {
- intl: intlShape.isRequired,
- state: React.PropTypes.object,
- hash: React.PropTypes.string,
- updateParent: React.PropTypes.func
-};
-
-export default injectIntl(TeamSignupPasswordPage);
diff --git a/webapp/components/signup_team_complete/components/team_signup_send_invites_page.jsx b/webapp/components/signup_team_complete/components/team_signup_send_invites_page.jsx
deleted file mode 100644
index db060b6b9..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_send_invites_page.jsx
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import EmailItem from './team_signup_email_item.jsx';
-import * as Client from 'utils/client.jsx';
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-import logoImage from 'images/logo.png';
-
-import React from 'react';
-
-export default class TeamSignupSendInvitesPage extends React.Component {
- constructor(props) {
- super(props);
- this.submitBack = this.submitBack.bind(this);
- this.submitNext = this.submitNext.bind(this);
- this.submitAddInvite = this.submitAddInvite.bind(this);
- this.submitSkip = this.submitSkip.bind(this);
- this.keySubmit = this.keySubmit.bind(this);
- this.state = {
- emailEnabled: global.window.mm_config.SendEmailNotifications === 'true'
- };
- }
- submitBack(e) {
- e.preventDefault();
- this.props.state.wizard = 'team_url';
-
- this.props.updateParent(this.props.state);
- }
- submitNext(e) {
- e.preventDefault();
-
- var valid = true;
-
- if (this.state.emailEnabled) {
- var emails = [];
-
- for (var i = 0; i < this.props.state.invites.length; i++) {
- if (this.refs['email_' + i].getWrappedInstance().validate(this.props.state.team.email)) {
- emails.push(this.refs['email_' + i].getWrappedInstance().getValue());
- } else {
- valid = false;
- }
- }
-
- if (valid) {
- this.props.state.invites = emails;
- }
- }
-
- if (valid) {
- this.props.state.wizard = 'username';
- this.props.updateParent(this.props.state);
- }
- }
- submitAddInvite(e) {
- e.preventDefault();
- this.props.state.wizard = 'send_invites';
- if (!this.props.state.invites) {
- this.props.state.invites = [];
- }
- this.props.state.invites.push('');
- this.props.updateParent(this.props.state);
- }
- submitSkip(e) {
- e.preventDefault();
- this.props.state.wizard = 'username';
- this.props.updateParent(this.props.state);
- }
- keySubmit(e) {
- if (e && e.keyCode === 13) {
- this.submitNext(e);
- }
- }
- componentDidMount() {
- if (!this.state.emailEnabled) {
- // Must use keypress not keyup due to event chain of pressing enter
- $('body').keypress(this.keySubmit);
- }
- }
- componentWillUnmount() {
- if (!this.state.emailEnabled) {
- $('body').off('keypress', this.keySubmit);
- }
- }
- render() {
- Client.track('signup', 'signup_team_05_send_invites');
-
- var content = null;
- var bottomContent = null;
-
- if (this.state.emailEnabled) {
- var emails = [];
-
- for (var i = 0; i < this.props.state.invites.length; i++) {
- if (i === 0) {
- emails.push(
- <EmailItem
- focus={true}
- key={i}
- ref={'email_' + i}
- email={this.props.state.invites[i]}
- />
- );
- } else {
- emails.push(
- <EmailItem
- focus={false}
- key={i}
- ref={'email_' + i}
- email={this.props.state.invites[i]}
- />
- );
- }
- }
-
- content = (
- <div>
- {emails}
- <div className='form-group text-right'>
- <a
- href='#'
- onClick={this.submitAddInvite}
- >
- <FormattedMessage
- id='team_signup_send_invites.addInvitation'
- defaultMessage='Add Invitation'
- />
- </a>
- </div>
- </div>
- );
-
- bottomContent = (
- <p className='color--light'>
- <FormattedHTMLMessage
- id='team_signup_send_invites.prefer'
- defaultMessage='if you prefer, you can invite team members later<br /> and '
- />
- <a
- href='#'
- onClick={this.submitSkip}
- >
- <FormattedMessage
- id='team_signup_send_invites.skip'
- defaultMessage='skip this step '
- />
- </a>
- <FormattedMessage
- id='team_signup_send_invites.forNow'
- defaultMessage='for now.'
- />
- </p>
- );
- } else {
- content = (
- <div className='form-group color--light'>
- <FormattedMessage
- id='team_signup_send_invites.disabled'
- defaultMessage='Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.'
- />
- </div>
- );
- }
-
- return (
- <div>
- <form>
- <img
- className='signup-team-logo'
- src={logoImage}
- />
- <h2>
- <FormattedMessage
- id='team_signup_send_invites.title'
- defaultMessage='Invite Team Members'
- />
- </h2>
- {content}
- <div className='form-group'>
- <button
- type='submit'
- className='btn-primary btn'
- onClick={this.submitNext}
- >
- <FormattedMessage
- id='team_signup_send_invites.next'
- defaultMessage='Next'
- /><i className='glyphicon glyphicon-chevron-right'/>
- </button>
- </div>
- </form>
- {bottomContent}
- <div className='margin--extra'>
- <a
- href='#'
- onClick={this.submitBack}
- >
- <FormattedMessage
- id='team_signup_send_invites.back'
- defaultMessage='Back to previous step'
- />
- </a>
- </div>
- </div>
- );
- }
-}
-
-TeamSignupSendInvitesPage.propTypes = {
- state: React.PropTypes.object.isRequired,
- updateParent: React.PropTypes.func.isRequired
-};
diff --git a/webapp/components/signup_team_complete/components/team_signup_username_page.jsx b/webapp/components/signup_team_complete/components/team_signup_username_page.jsx
deleted file mode 100644
index b79c1179f..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_username_page.jsx
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
-
-import logoImage from 'images/logo.png';
-
-const holders = defineMessages({
- reserved: {
- id: 'team_signup_username.reserved',
- defaultMessage: 'This username is reserved, please choose a new one.'
- },
- invalid: {
- id: 'team_signup_username.invalid',
- defaultMessage: 'Username must begin with a letter, and contain between {min} to {max} characters in total, which may be numbers, lowercase letters, or any of the symbols \'.\', \'-\', or \'_\''
- }
-});
-
-import React from 'react';
-
-class TeamSignupUsernamePage extends React.Component {
- constructor(props) {
- super(props);
-
- this.submitBack = this.submitBack.bind(this);
- this.submitNext = this.submitNext.bind(this);
-
- this.state = {};
- }
- submitBack(e) {
- e.preventDefault();
- if (global.window.mm_config.SendEmailNotifications === 'true') {
- this.props.state.wizard = 'send_invites';
- } else {
- this.props.state.wizard = 'team_url';
- }
-
- this.props.updateParent(this.props.state);
- }
- submitNext(e) {
- e.preventDefault();
-
- const {formatMessage} = this.props.intl;
- 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.') { //this should be change to some kind of ID
- this.setState({nameError: formatMessage(holders.reserved)});
- return;
- } else if (usernameError) {
- this.setState({nameError: formatMessage(holders.invalid, {min: Constants.MIN_USERNAME_LENGTH, max: Constants.MAX_USERNAME_LENGTH})});
- return;
- }
-
- this.props.state.wizard = 'password';
- this.props.state.user.username = name;
- this.props.updateParent(this.props.state);
- }
- render() {
- Client.track('signup', 'signup_team_06_username');
-
- var nameError = null;
- var nameHelpText = (
- <span className='color--light help-block'>
- <FormattedMessage
- id='team_signup_username.hint'
- defaultMessage="Usernames must begin with a letter and contain between {min} to {max} characters made up of lowercase letters, numbers, and the symbols '.', '-' and '_'"
- values={{
- min: Constants.MIN_USERNAME_LENGTH,
- max: Constants.MAX_USERNAME_LENGTH
- }}
- />
- </span>
- );
- var nameDivClass = 'form-group';
- if (this.state.nameError) {
- nameError = <label className='control-label'>{this.state.nameError}</label>;
- nameHelpText = '';
- nameDivClass += ' has-error';
- }
-
- return (
- <div>
- <form>
- <img
- className='signup-team-logo'
- src={logoImage}
- />
- <h2 className='margin--less'>
- <FormattedMessage
- id='team_signup_username.username'
- defaultMessage='Your username'
- />
- </h2>
- <h5 className='color--light'>
- <FormattedMessage
- id='team_signup_username.memorable'
- defaultMessage='Select a memorable username that makes it easy for teammates to identify you:'
- />
- </h5>
- <div className='inner__content margin--extra'>
- <div className={nameDivClass}>
- <div className='row'>
- <div className='col-sm-11'>
- <h5><strong>
- <FormattedMessage
- id='team_signup_username.chooseUsername'
- defaultMessage='Choose your username'
- />
- </strong></h5>
- <input
- autoFocus={true}
- type='text'
- ref='name'
- className='form-control'
- placeholder=''
- defaultValue={this.props.state.user.username}
- maxLength={Constants.MAX_USERNAME_LENGTH}
- spellCheck='false'
- />
- {nameHelpText}
- </div>
- </div>
- {nameError}
- </div>
- </div>
- <button
- type='submit'
- className='btn btn-primary margin--extra'
- onClick={this.submitNext}
- >
- <FormattedMessage
- id='team_signup_username.next'
- defaultMessage='Next'
- />
- <i className='glyphicon glyphicon-chevron-right'></i>
- </button>
- <div className='margin--extra'>
- <a
- href='#'
- onClick={this.submitBack}
- >
- <FormattedMessage
- id='team_signup_username.back'
- defaultMessage='Back to previous step'
- />
- </a>
- </div>
- </form>
- </div>
- );
- }
-}
-
-TeamSignupUsernamePage.defaultProps = {
- state: null
-};
-TeamSignupUsernamePage.propTypes = {
- intl: intlShape.isRequired,
- state: React.PropTypes.object,
- updateParent: React.PropTypes.func
-};
-
-export default injectIntl(TeamSignupUsernamePage);
diff --git a/webapp/components/signup_team_complete/components/team_signup_welcome_page.jsx b/webapp/components/signup_team_complete/components/team_signup_welcome_page.jsx
deleted file mode 100644
index 15b708128..000000000
--- a/webapp/components/signup_team_complete/components/team_signup_welcome_page.jsx
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
-import BrowserStore from 'stores/browser_store.jsx';
-
-import {injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-
-import {browserHistory} from 'react-router';
-
-import logoImage from 'images/logo.png';
-
-const holders = defineMessages({
- storageError: {
- id: 'team_signup_welcome.storageError',
- defaultMessage: 'This service requires local storage to be enabled. Please enable it or exit private browsing.'
- },
- validEmailError: {
- id: 'team_signup_welcome.validEmailError',
- defaultMessage: 'Please enter a valid email address'
- },
- address: {
- id: 'team_signup_welcome.address',
- defaultMessage: 'Email Address'
- }
-});
-
-import React from 'react';
-
-class TeamSignupWelcomePage extends React.Component {
- constructor(props) {
- super(props);
-
- this.submitNext = this.submitNext.bind(this);
- this.handleDiffEmail = this.handleDiffEmail.bind(this);
- this.handleDiffSubmit = this.handleDiffSubmit.bind(this);
- this.handleKeyPress = this.handleKeyPress.bind(this);
-
- this.state = {useDiff: false};
-
- document.addEventListener('keyup', this.handleKeyPress, false);
- }
- submitNext(e) {
- if (!BrowserStore.isLocalStorageSupported()) {
- this.setState({storageError: this.props.intl.formatMessage(holders.storageError)});
- return;
- }
- e.preventDefault();
- this.props.state.wizard = 'team_display_name';
- this.props.updateParent(this.props.state);
- }
- handleDiffEmail(e) {
- e.preventDefault();
- this.setState({useDiff: true});
- }
- handleDiffSubmit(e) {
- e.preventDefault();
-
- const {formatMessage} = this.props.intl;
- var state = {useDiff: true, serverError: ''};
-
- var email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
- if (!email || !Utils.isEmail(email)) {
- state.emailError = formatMessage(holders.validEmailError);
- this.setState(state);
- return;
- } else if (!BrowserStore.isLocalStorageSupported()) {
- state.emailError = formatMessage(holders.storageError);
- this.setState(state);
- return;
- }
- state.emailError = '';
-
- Client.signupTeam(email,
- function success(data) {
- if (data.follow_link) {
- browserHistory.push(data.follow_link);
- } else {
- this.props.state.wizard = 'finished';
- this.props.updateParent(this.props.state);
- browserHistory.push('/signup_team_confirm/?email=' + encodeURIComponent(email));
- }
- }.bind(this),
- function error(err) {
- let errorMsg = err.message;
-
- if (err.detailed_error.indexOf('Invalid RCPT TO address provided') >= 0) {
- errorMsg = formatMessage(holders.validEmailError);
- }
-
- this.setState({emailError: '', serverError: errorMsg});
- }.bind(this)
- );
- }
- handleKeyPress(event) {
- if (event.keyCode === 13) {
- if (this.state.useDiff) {
- this.handleDiffSubmit(event);
- } else {
- this.submitNext(event);
- }
- }
- }
- componentWillUnmount() {
- document.removeEventListener('keyup', this.handleKeyPress, false);
- }
- render() {
- Client.track('signup', 'signup_team_01_welcome');
-
- var storageError = null;
- if (this.state.storageError) {
- storageError = <label className='control-label'>{this.state.storageError}</label>;
- }
-
- var emailError = null;
- var emailDivClass = 'form-group';
- if (this.state.emailError) {
- emailError = <label className='control-label'>{this.state.emailError}</label>;
- emailDivClass += ' has-error';
- }
-
- var serverError = null;
- if (this.state.serverError) {
- serverError = (
- <div className='form-group has-error'>
- <label className='control-label'>{this.state.serverError}</label>
- </div>
- );
- }
-
- var differentEmailLinkClass = '';
- var emailDivContainerClass = 'hidden';
- if (this.state.useDiff) {
- differentEmailLinkClass = 'hidden';
- emailDivContainerClass = '';
- }
-
- return (
- <div>
- <img
- className='signup-team-logo'
- src={logoImage}
- />
- <h3 className='sub-heading'>
- <FormattedMessage
- id='team_signup_welcome.welcome'
- defaultMessage='Welcome to:'
- />
- </h3>
- <h1 className='margin--top-none'>{global.window.mm_config.SiteName}</h1>
- <p className='margin--less'>
- <FormattedMessage
- id='team_signup_welcome.lets'
- defaultMessage="Let's set up your new team"
- />
- </p>
- <div>
- <FormattedMessage
- id='team_signup_welcome.confirm'
- defaultMessage='Please confirm your email address:'
- />
- <br/>
- <div className='inner__content'>
- <div className='block--gray'>{this.props.state.team.email}</div>
- </div>
- </div>
- <p className='margin--extra color--light'>
- <FormattedHTMLMessage
- id='team_signup_welcome.admin'
- defaultMessage='Your account will administer the new team site. <br />
- You can add other administrators later.'
- />
- </p>
- <div className='form-group'>
- <button
- className='btn-primary btn form-group'
- type='submit'
- onClick={this.submitNext}
- >
- <i className='glyphicon glyphicon-ok'></i>
- <FormattedMessage
- id='team_signup_welcome.yes'
- defaultMessage='Yes, this address is correct'
- />
- </button>
- {storageError}
- </div>
- <hr/>
- <div className={emailDivContainerClass}>
- <div className={emailDivClass}>
- <div className='row'>
- <div className='col-sm-9'>
- <input
- type='email'
- ref='email'
- className='form-control'
- placeholder={this.props.intl.formatMessage(holders.address)}
- maxLength='128'
- spellCheck='false'
- />
- </div>
- </div>
- {emailError}
- </div>
- {serverError}
- <button
- className='btn btn-md btn-primary'
- type='button'
- onClick={this.handleDiffSubmit}
- >
- <FormattedMessage
- id='team_signup_welcome.instead'
- defaultMessage='Use this instead'
- />
- </button>
- </div>
- <a
- href='#'
- onClick={this.handleDiffEmail}
- className={differentEmailLinkClass}
- >
- <FormattedMessage
- id='team_signup_welcome.different'
- defaultMessage='Use a different email'
- />
- </a>
- </div>
- );
- }
-}
-
-TeamSignupWelcomePage.defaultProps = {
- state: {}
-};
-TeamSignupWelcomePage.propTypes = {
- intl: intlShape.isRequired,
- updateParent: React.PropTypes.func.isRequired,
- state: React.PropTypes.object
-};
-
-export default injectIntl(TeamSignupWelcomePage);
diff --git a/webapp/components/signup_team_confirm.jsx b/webapp/components/signup_team_confirm.jsx
deleted file mode 100644
index 117a0b068..000000000
--- a/webapp/components/signup_team_confirm.jsx
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
-import {Link} from 'react-router';
-
-import React from 'react';
-
-export default class SignupTeamConfirm extends React.Component {
- render() {
- return (
- <div>
- <div className='signup-header'>
- <Link to='/'>
- <span className='fa fa-chevron-left'/>
- <FormattedMessage
- id='web.header.back'
- />
- </Link>
- </div>
- <div className='col-sm-12'>
- <div classNameName='signup-team__container'>
- <h3>
- <FormattedMessage
- id='signup_team_confirm.title'
- defaultMessage='Sign up Complete'
- />
- </h3>
- <p>
- <FormattedHTMLMessage
- id='signup_team_confirm.checkEmail'
- defaultMessage='Please check your email: <strong>{email}</strong><br />Your email contains a link to set up your team'
- values={{
- email: this.props.location.query.email
- }}
- />
- </p>
- </div>
- </div>
- </div>
- );
- }
-}
-
-SignupTeamConfirm.defaultProps = {
-};
-SignupTeamConfirm.propTypes = {
- location: React.PropTypes.object
-};
diff --git a/webapp/components/signup_user_complete.jsx b/webapp/components/signup_user_complete.jsx
index 9e821289b..666e72e13 100644
--- a/webapp/components/signup_user_complete.jsx
+++ b/webapp/components/signup_user_complete.jsx
@@ -3,12 +3,13 @@
import LoadingScreen from 'components/loading_screen.jsx';
import LoginLdap from 'components/login/components/login_ldap.jsx';
+import * as GlobalActions from 'action_creators/global_actions.jsx';
import BrowserStore from 'stores/browser_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import {FormattedMessage, FormattedHTMLMessage} from 'react-intl';
@@ -24,7 +25,6 @@ class SignupUserComplete extends React.Component {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
- this.inviteInfoRecieved = this.inviteInfoRecieved.bind(this);
this.handleLdapSignup = this.handleLdapSignup.bind(this);
this.state = {
@@ -34,7 +34,10 @@ class SignupUserComplete extends React.Component {
email: '',
teamDisplayName: '',
teamName: '',
- teamId: ''
+ teamId: '',
+ openServer: false,
+ loading: true,
+ inviteId: ''
};
}
componentWillMount() {
@@ -46,19 +49,91 @@ class SignupUserComplete extends React.Component {
let teamDisplayName = '';
let teamName = '';
let teamId = '';
+ let openServer = false;
+ let loading = true;
+
+ if ((inviteId && inviteId.length > 0) || (hash && hash.length > 0)) {
+ // if we are already logged in then attempt to just join the team
+ if (UserStore.getCurrentUser()) {
+ loading = true;
+ Client.addUserToTeamFromInvite(
+ data,
+ hash,
+ inviteId,
+ () => {
+ GlobalActions.emitInitialLoad(
+ () => {
+ browserHistory.push('/select_team');
+ }
+ );
+ },
+ (err) => {
+ this.setState({
+ noOpenServerError: true,
+ serverError: err.message,
+ loading: false
+ });
+ }
+ );
+ } else if (hash) {
+ // If we have a hash in the url then we are attempting to access a private team
+ const parsedData = JSON.parse(data);
+ usedBefore = BrowserStore.getGlobalItem(hash);
+ email = parsedData.email;
+ teamDisplayName = parsedData.display_name;
+ teamName = parsedData.name;
+ teamId = parsedData.id;
+ loading = false;
+ } else {
+ loading = true;
+ Client.getInviteInfo(
+ inviteId,
+ (inviteData) => {
+ if (!inviteData) {
+ return;
+ }
- // If we have a hash in the url then we are attempting to access a private team
- if (hash) {
- const parsedData = JSON.parse(data);
- usedBefore = BrowserStore.getGlobalItem(hash);
- email = parsedData.email;
- teamDisplayName = parsedData.display_name;
- teamName = parsedData.name;
- teamId = parsedData.id;
+ this.setState({
+ serverError: null,
+ teamDisplayName: inviteData.display_name,
+ teamName: inviteData.name,
+ teamId: inviteData.id,
+ loading: false
+ });
+ },
+ () => {
+ this.setState({
+ noOpenServerError: true,
+ loading: false,
+ serverError:
+ <FormattedMessage
+ id='signup_user_completed.invalid_invite'
+ defaultMessage='The invite link was invalid. Please speak with your Administrator to receive an invitation.'
+ />
+ });
+ }
+ );
+
+ data = '';
+ hash = '';
+ }
+ } else if (global.window.mm_config.EnableOpenServer === 'true' || UserStore.getNoAccounts()) {
+ // If this is the first account then let them create an account anyway.
+ // The server will verify it's the first account before allowing creation.
+ // Of if the server is open then we don't care.
+ openServer = true;
+ loading = false;
} else {
- Client.getInviteInfo(this.inviteInfoRecieved, null, inviteId);
- data = '';
- hash = '';
+ loading = false;
+ this.setState({
+ noOpenServerError: true,
+ serverError:
+ <FormattedMessage
+ id='signup_user_completed.no_open_server'
+ defaultMessage='This server does not allow open signups. Please speak with your Administrator to receive an invitation.'
+ />,
+ loading: false
+ });
}
this.setState({
@@ -68,29 +143,25 @@ class SignupUserComplete extends React.Component {
email,
teamDisplayName,
teamName,
- teamId
- });
- }
- inviteInfoRecieved(data) {
- if (!data) {
- return;
- }
-
- this.setState({
- teamDisplayName: data.display_name,
- teamName: data.name,
- teamId: data.id
+ teamId,
+ openServer,
+ inviteId,
+ loading
});
}
handleLdapSignup(method, loginId, password, token) {
- Client.loginByLdap(this.state.teamName, loginId, password, token,
+ Client.loginByLdap(loginId, password, token,
() => {
const redirect = Utils.getUrlParameter('redirect');
if (redirect) {
browserHistory.push(decodeURIComponent(redirect));
} else {
- browserHistory.push('/' + this.state.teamName + '/channels/town-square');
+ GlobalActions.emitInitialLoad(
+ () => {
+ browserHistory.push('/select_team');
+ }
+ );
}
},
(err) => {
@@ -187,28 +258,34 @@ class SignupUserComplete extends React.Component {
});
const user = {
- team_id: this.state.teamId,
email: providedEmail,
username: providedUsername,
password: providedPassword,
allow_marketing: true
};
- Client.createUser(user, this.state.data, this.state.hash,
+ Client.createUserWithInvite(user,
+ this.state.data,
+ this.state.hash,
+ this.state.inviteId,
() => {
Client.track('signup', 'signup_user_02_complete');
-
- Client.loginByEmail(
- this.state.teamName,
+ Client.login(
user.email,
+ null,
user.password,
- '', // No MFA Token
+ '',
() => {
UserStore.setLastEmail(user.email);
if (this.state.hash > 0) {
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
}
- browserHistory.push('/' + this.state.teamName + '/channels/town-square');
+
+ GlobalActions.emitInitialLoad(
+ () => {
+ browserHistory.push('/select_team');
+ }
+ );
},
(err) => {
if (err.id === 'api.user.login.not_verified.app_error') {
@@ -239,9 +316,7 @@ class SignupUserComplete extends React.Component {
);
}
- // If we haven't got a team id yet we are waiting for
- // the client so just show the standard loading screen
- if (this.state.teamId === '') {
+ if (this.state.loading) {
return (<LoadingScreen/>);
}
@@ -349,7 +424,7 @@ class SignupUserComplete extends React.Component {
<a
className='btn btn-custom-login gitlab'
key='gitlab'
- href={'/api/v1/oauth/gitlab/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)}
+ href={Client.getOAuthRoute() + '/gitlab/signup' + window.location.search}
>
<span className='icon'/>
<span>
@@ -367,7 +442,7 @@ class SignupUserComplete extends React.Component {
<a
className='btn btn-custom-login google'
key='google'
- href={'/api/v1/oauth/google/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)}
+ href={Client.getOAuthRoute() + '/google/signup' + window.location.search + '&team=' + encodeURIComponent(this.state.teamName)}
>
<span className='icon'/>
<span>
@@ -497,12 +572,33 @@ class SignupUserComplete extends React.Component {
);
}
+ let terms = (
+ <p>
+ <FormattedHTMLMessage
+ id='create_team.agreement'
+ defaultMessage="By proceeding to create your account and use {siteName}, you agree to our <a href='/static/help/terms.html'>Terms of Service</a> and <a href='/static/help/privacy.html'>Privacy Policy</a>. If you do not agree, you cannot use {siteName}."
+ values={{
+ siteName: global.window.mm_config.SiteName
+ }}
+ />
+ </p>
+ );
+
+ if (this.state.noOpenServerError) {
+ signupMessage = null;
+ ldapSignup = null;
+ emailSignup = null;
+ terms = null;
+ }
+
return (
<div>
<div className='signup-header'>
<Link to='/'>
- <span classNameNameName='fa fa-chevron-left'/>
- <FormattedMessage id='web.header.back'/>
+ <span className='fa fa-chevron-left'/>
+ <FormattedMessage
+ id='web.header.back'
+ />
</Link>
</div>
<div className='col-sm-12'>
@@ -511,22 +607,12 @@ class SignupUserComplete extends React.Component {
className='signup-team-logo'
src={logoImage}
/>
- <h5 className='margin--less'>
- <FormattedMessage
- id='signup_user_completed.welcome'
- defaultMessage='Welcome to:'
- />
- </h5>
- <h2 className='signup-team__name'>{this.state.teamName}</h2>
- <h2 className='signup-team__subdomain'>
+ <h1>{global.window.mm_config.SiteName}</h1>
+ <h4 className='color--light'>
<FormattedMessage
- id='signup_user_completed.onSite'
- defaultMessage='on {siteName}'
- values={{
- siteName: global.window.mm_config.SiteName
- }}
+ id='web.root.singup_info'
/>
- </h2>
+ </h4>
<h4 className='color--light'>
<FormattedMessage
id='signup_user_completed.lets'
@@ -537,6 +623,7 @@ class SignupUserComplete extends React.Component {
{ldapSignup}
{emailSignup}
{serverError}
+ {terms}
</div>
</div>
</div>
diff --git a/webapp/components/suggestion/at_mention_provider.jsx b/webapp/components/suggestion/at_mention_provider.jsx
index 90ec6e660..79ac8aaf1 100644
--- a/webapp/components/suggestion/at_mention_provider.jsx
+++ b/webapp/components/suggestion/at_mention_provider.jsx
@@ -4,6 +4,7 @@
import SuggestionStore from 'stores/suggestion_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as Utils from 'utils/utils.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
@@ -42,7 +43,7 @@ class AtMentionSuggestion extends React.Component {
icon = (
<img
className='mention__image'
- src={'/api/v1/users/' + item.id + '/image?time=' + item.update_at}
+ src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.update_at}
/>
);
}
diff --git a/webapp/components/suggestion/search_user_provider.jsx b/webapp/components/suggestion/search_user_provider.jsx
index eeaee68a7..b7234469a 100644
--- a/webapp/components/suggestion/search_user_provider.jsx
+++ b/webapp/components/suggestion/search_user_provider.jsx
@@ -3,6 +3,7 @@
import SuggestionStore from 'stores/suggestion_store.jsx';
import UserStore from 'stores/user_store.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
@@ -22,7 +23,7 @@ class SearchUserSuggestion extends React.Component {
>
<img
className='profile-img rounded'
- src={'/api/v1/users/' + item.id + '/image?time=' + item.update_at}
+ src={Client.getUsersRoute() + '/' + item.id + '/image?time=' + item.update_at}
/>
<i className='fa fa fa-plus-square'></i>{item.username}
</div>
diff --git a/webapp/components/team_export_tab.jsx b/webapp/components/team_export_tab.jsx
index 9bd5785a0..37f886aab 100644
--- a/webapp/components/team_export_tab.jsx
+++ b/webapp/components/team_export_tab.jsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
diff --git a/webapp/components/team_general_tab.jsx b/webapp/components/team_general_tab.jsx
index c27e8ca59..1f783fe9f 100644
--- a/webapp/components/team_general_tab.jsx
+++ b/webapp/components/team_general_tab.jsx
@@ -5,7 +5,7 @@ import $ from 'jquery';
import SettingItemMin from './setting_item_min.jsx';
import SettingItemMax from './setting_item_max.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import TeamStore from 'stores/team_store.jsx';
@@ -42,7 +42,7 @@ const holders = defineMessages({
},
openInviteTitle: {
id: 'general_tab.openInviteTitle',
- defaultMessage: 'Allow anyone to sign-up from login page'
+ defaultMessage: 'Allow anyone to join this team'
},
codeTitle: {
id: 'general_tab.codeTitle',
@@ -68,7 +68,6 @@ class GeneralTab extends React.Component {
this.handleNameSubmit = this.handleNameSubmit.bind(this);
this.handleInviteIdSubmit = this.handleInviteIdSubmit.bind(this);
this.handleOpenInviteSubmit = this.handleOpenInviteSubmit.bind(this);
- this.handleTeamListingSubmit = this.handleTeamListingSubmit.bind(this);
this.handleClose = this.handleClose.bind(this);
this.onUpdateNameSection = this.onUpdateNameSection.bind(this);
this.updateName = this.updateName.bind(this);
@@ -76,8 +75,6 @@ class GeneralTab extends React.Component {
this.updateInviteId = this.updateInviteId.bind(this);
this.onUpdateOpenInviteSection = this.onUpdateOpenInviteSection.bind(this);
this.handleOpenInviteRadio = this.handleOpenInviteRadio.bind(this);
- this.onUpdateTeamListingSection = this.onUpdateTeamListingSection.bind(this);
- this.handleTeamListingRadio = this.handleTeamListingRadio.bind(this);
this.handleGenerateInviteId = this.handleGenerateInviteId.bind(this);
this.state = this.setupInitialState(props);
@@ -96,12 +93,19 @@ class GeneralTab extends React.Component {
name: team.display_name,
invite_id: team.invite_id,
allow_open_invite: team.allow_open_invite,
- allow_team_listing: team.allow_team_listing,
serverError: '',
clientError: ''
};
}
+ componentWillReceiveProps(nextProps) {
+ this.setState({
+ name: nextProps.team.display_name,
+ invite_id: nextProps.team.invite_id,
+ allow_open_invite: nextProps.team.allow_open_invite
+ });
+ }
+
handleGenerateInviteId(e) {
e.preventDefault();
@@ -117,14 +121,6 @@ class GeneralTab extends React.Component {
this.setState({allow_open_invite: openInvite});
}
- handleTeamListingRadio(listing) {
- if (global.window.mm_config.EnableTeamListing !== 'true' && listing) {
- this.setState({clientError: this.props.intl.formatMessage(holders.dirDisabled)});
- } else {
- this.setState({allow_team_listing: listing});
- }
- }
-
handleOpenInviteSubmit(e) {
e.preventDefault();
@@ -145,26 +141,6 @@ class GeneralTab extends React.Component {
);
}
- handleTeamListingSubmit(e) {
- e.preventDefault();
-
- var state = {serverError: '', clientError: ''};
-
- var data = this.props.team;
- data.allow_team_listing = this.state.allow_team_listing;
- Client.updateTeam(data,
- (team) => {
- TeamStore.saveTeam(team);
- TeamStore.emitChange();
- this.updateSection('');
- },
- (err) => {
- state.serverError = err.message;
- this.setState(state);
- }
- );
- }
-
handleNameSubmit(e) {
e.preventDefault();
@@ -239,12 +215,6 @@ class GeneralTab extends React.Component {
);
}
- componentWillReceiveProps(newProps) {
- if (newProps.team && newProps.teamDisplayName) {
- this.setState({name: newProps.teamDisplayName});
- }
- }
-
handleClose() {
this.updateSection('');
}
@@ -284,15 +254,6 @@ class GeneralTab extends React.Component {
}
}
- onUpdateTeamListingSection(e) {
- e.preventDefault();
- if (this.props.activeSection === 'team_listing') {
- this.updateSection('');
- } else {
- this.updateSection('team_listing');
- }
- }
-
updateName(e) {
e.preventDefault();
this.setState({name: e.target.value});
@@ -313,105 +274,8 @@ class GeneralTab extends React.Component {
serverError = this.state.serverError;
}
- const enableTeamListing = global.window.mm_config.EnableTeamListing === 'true';
const {formatMessage} = this.props.intl;
- let teamListingSection;
- if (this.props.activeSection === 'team_listing') {
- const inputs = [];
- let submitHandle = null;
-
- if (enableTeamListing) {
- submitHandle = this.handleTeamListingSubmit;
-
- inputs.push(
- <div key='userTeamListingOptions'>
- <div className='radio'>
- <label>
- <input
- name='userTeamListingOptions'
- type='radio'
- defaultChecked={this.state.allow_team_listing}
- onChange={this.handleTeamListingRadio.bind(this, true)}
- />
- <FormattedMessage
- id='general_tab.yes'
- defaultMessage='Yes'
- />
- </label>
- <br/>
- </div>
- <div className='radio'>
- <label>
- <input
- ref='teamListingRadioNo'
- name='userTeamListingOptions'
- type='radio'
- defaultChecked={!this.state.allow_team_listing}
- onChange={this.handleTeamListingRadio.bind(this, false)}
- />
- <FormattedMessage
- id='general_tab.no'
- defaultMessage='No'
- />
- </label>
- <br/>
- </div>
- <div>
- <br/>
- <FormattedMessage
- id='general_tab.includeDirDesc'
- defaultMessage='Including this team will display the team name from the Team Directory section of the Home Page, and provide a link to the sign-in page.'
- />
- </div>
- </div>
- );
- } else {
- inputs.push(
- <div key='userTeamListingOptions'>
- <div>
- <br/>
- <FormattedMessage
- id='general_tab.dirContact'
- defaultMessage='Contact your system administrator to turn on the team directory on the system home page.'
- />
- </div>
- </div>
- );
- }
-
- teamListingSection = (
- <SettingItemMax
- title={formatMessage(holders.includeDirTitle)}
- inputs={inputs}
- submit={submitHandle}
- server_error={serverError}
- client_error={clientError}
- updateSection={this.onUpdateTeamListingSection}
- />
- );
- } else {
- let describe = '';
-
- if (enableTeamListing) {
- if (this.state.allow_team_listing === true) {
- describe = formatMessage(holders.yes);
- } else {
- describe = formatMessage(holders.no);
- }
- } else {
- describe = formatMessage(holders.dirOff);
- }
-
- teamListingSection = (
- <SettingItemMin
- title={formatMessage(holders.includeDirTitle)}
- describe={describe}
- updateSection={this.onUpdateTeamListingSection}
- />
- );
- }
-
let openInviteSection;
if (this.props.activeSection === 'open_invite') {
const inputs = [
@@ -450,7 +314,7 @@ class GeneralTab extends React.Component {
<br/>
<FormattedMessage
id='general_tab.openInviteDesc'
- defaultMessage='When allowed, a link to account creation will be included on the sign-in page of this team and allow any visitor to sign-up.'
+ defaultMessage='When allowed, a link to this team will be including on the landing page allowing anyone with an account to join this team.'
/>
</div>
</div>
@@ -639,8 +503,6 @@ class GeneralTab extends React.Component {
<div className='divider-light'/>
{openInviteSection}
<div className='divider-light'/>
- {teamListingSection}
- <div className='divider-light'/>
{inviteSection}
<div className='divider-dark'/>
</div>
diff --git a/webapp/components/team_members_dropdown.jsx b/webapp/components/team_members_dropdown.jsx
index ad82a2280..251c2ce3b 100644
--- a/webapp/components/team_members_dropdown.jsx
+++ b/webapp/components/team_members_dropdown.jsx
@@ -3,7 +3,7 @@
import UserStore from 'stores/user_store.jsx';
import ChannelStore from 'stores/channel_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
import ConfirmModal from './confirm_modal.jsx';
@@ -38,11 +38,9 @@ export default class TeamMembersDropdown extends React.Component {
if (this.props.user.id === me.id) {
this.handleDemote(this.props.user, '');
} else {
- const data = {
- user_id: this.props.user.id,
- new_roles: ''
- };
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ '',
() => {
AsyncClient.getProfiles();
},
@@ -79,12 +77,9 @@ export default class TeamMembersDropdown extends React.Component {
if (this.props.user.id === me.id) {
this.handleDemote(this.props.user, 'admin');
} else {
- const data = {
- user_id: this.props.user.id,
- new_roles: 'admin'
- };
-
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ 'admin',
() => {
AsyncClient.getProfiles();
},
@@ -94,12 +89,13 @@ export default class TeamMembersDropdown extends React.Component {
);
}
}
- handleDemote(user, role) {
+ handleDemote(user, role, newRole) {
this.setState({
serverError: this.state.serverError,
showDemoteModal: true,
user,
- role
+ role,
+ newRole
});
}
handleDemoteCancel() {
@@ -107,16 +103,14 @@ export default class TeamMembersDropdown extends React.Component {
serverError: null,
showDemoteModal: false,
user: null,
- role: null
+ role: null,
+ newRole: null
});
}
handleDemoteSubmit() {
- const data = {
- user_id: this.props.user.id,
- new_roles: this.state.role
- };
-
- Client.updateRoles(data,
+ Client.updateRoles(
+ this.props.user.id,
+ this.state.newRole,
() => {
const teamUrl = TeamStore.getCurrentTeamUrl();
if (teamUrl) {
@@ -140,6 +134,7 @@ export default class TeamMembersDropdown extends React.Component {
);
}
+ const teamMember = this.props.teamMember;
const user = this.props.user;
let currentRoles = (
<FormattedMessage
@@ -168,8 +163,10 @@ export default class TeamMembersDropdown extends React.Component {
}
}
- let showMakeMember = user.roles === 'admin' || user.roles === 'system_admin';
- let showMakeAdmin = user.roles === '' || user.roles === 'system_admin';
+ let showMakeMember = teamMember.roles === 'admin' || user.roles === 'system_admin';
+
+ //let showMakeAdmin = teamMember.roles === '' && user.roles !== 'system_admin';
+ let showMakeAdmin = false;
let showMakeActive = false;
let showMakeNotActive = user.roles !== 'system_admin';
@@ -331,5 +328,6 @@ export default class TeamMembersDropdown extends React.Component {
}
TeamMembersDropdown.propTypes = {
- user: React.PropTypes.object.isRequired
+ user: React.PropTypes.object.isRequired,
+ teamMember: React.PropTypes.object.isRequired
};
diff --git a/webapp/components/team_settings.jsx b/webapp/components/team_settings.jsx
index dc303059d..210d1f541 100644
--- a/webapp/components/team_settings.jsx
+++ b/webapp/components/team_settings.jsx
@@ -25,6 +25,7 @@ export default class TeamSettings extends React.Component {
}
onChange() {
var team = TeamStore.getCurrent();
+
if (!Utils.areObjectsEqual(this.state.team, team)) {
this.setState({team});
}
diff --git a/webapp/components/team_signup_choose_auth.jsx b/webapp/components/team_signup_choose_auth.jsx
deleted file mode 100644
index 7a4ce972a..000000000
--- a/webapp/components/team_signup_choose_auth.jsx
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import {FormattedMessage} from 'react-intl';
-
-import React from 'react';
-
-export default class ChooseAuthPage extends React.Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
- render() {
- var buttons = [];
- if (global.window.mm_config.EnableSignUpWithGitLab === 'true') {
- buttons.push(
- <a
- className='btn btn-custom-login gitlab btn-full'
- key='gitlab'
- href='#'
- onClick={
- function clickGit(e) {
- e.preventDefault();
- this.props.updatePage('gitlab');
- }.bind(this)
- }
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='choose_auth_page.gitlabCreate'
- defaultMessage='Create new team with GitLab Account'
- />
- </span>
- </a>
- );
- }
-
- if (global.window.mm_config.EnableSignUpWithGoogle === 'true') {
- buttons.push(
- <a
- className='btn btn-custom-login google btn-full'
- key='google'
- href='#'
- onClick={
- (e) => {
- e.preventDefault();
- this.props.updatePage('google');
- }
- }
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='choose_auth_page.googleCreate'
- defaultMessage='Create new team with Google Apps Account'
- />
- </span>
- </a>
- );
- }
-
- if (global.window.mm_config.EnableLdap === 'true') {
- buttons.push(
- <a
- className='btn btn-custom-login ldap btn-full'
- key='ldap'
- href='#'
- onClick={
- (e) => {
- e.preventDefault();
- this.props.updatePage('ldap');
- }
- }
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='choose_auth_page.ldapCreate'
- defaultMessage='Create new team with LDAP Account'
- />
- </span>
- </a>
- );
- }
-
- if (global.window.mm_config.EnableSignUpWithEmail === 'true') {
- buttons.push(
- <a
- className='btn btn-custom-login email btn-full'
- key='email'
- href='#'
- onClick={
- function clickEmail(e) {
- e.preventDefault();
- this.props.updatePage('email');
- }.bind(this)
- }
- >
- <span className='fa fa-envelope'/>
- <span>
- <FormattedMessage
- id='choose_auth_page.emailCreate'
- defaultMessage='Create new team with email address'
- />
- </span>
- </a>
- );
- }
-
- if (buttons.length === 0) {
- buttons = (
- <span>
- <FormattedMessage
- id='choose_auth_page.noSignup'
- defaultMessage='No sign-up methods configured, please contact your system administrator.'
- />
- </span>
- );
- }
-
- return (
- <div>
- {buttons}
- </div>
- );
- }
-}
-
-ChooseAuthPage.propTypes = {
- updatePage: React.PropTypes.func
-};
diff --git a/webapp/components/team_signup_with_email.jsx b/webapp/components/team_signup_with_email.jsx
deleted file mode 100644
index 90a6e9773..000000000
--- a/webapp/components/team_signup_with_email.jsx
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
-
-import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
-
-const holders = defineMessages({
- emailError: {
- id: 'email_signup.emailError',
- defaultMessage: 'Please enter a valid email address'
- },
- address: {
- id: 'email_signup.address',
- defaultMessage: 'Email Address'
- }
-});
-
-import React from 'react';
-
-class EmailSignUpPage extends React.Component {
- constructor() {
- super();
-
- this.handleSubmit = this.handleSubmit.bind(this);
-
- this.state = {};
- }
- handleSubmit(e) {
- e.preventDefault();
- const team = {};
- const state = {serverError: null};
- let isValid = true;
-
- team.email = ReactDOM.findDOMNode(this.refs.email).value.trim().toLowerCase();
- if (!team.email || !Utils.isEmail(team.email)) {
- state.emailError = this.props.intl.formatMessage(holders.emailError);
- isValid = false;
- } else {
- state.emailError = null;
- }
-
- if (!isValid) {
- this.setState(state);
- return;
- }
-
- Client.signupTeam(team.email,
- (data) => {
- if (data.follow_link) {
- browserHistory.push(data.follow_link);
- } else {
- browserHistory.push(`/signup_team_confirm/?email=${encodeURIComponent(team.email)}`);
- }
- },
- (err) => {
- state.serverError = err.message;
- this.setState(state);
- }
- );
- }
- render() {
- let serverError = null;
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- let emailError = null;
- if (this.state.emailError) {
- emailError = <div className='form-group has-error'><label className='control-label'>{this.state.emailError}</label></div>;
- }
-
- return (
- <form
- role='form'
- onSubmit={this.handleSubmit}
- >
- <div className='form-group'>
- <input
- autoFocus={true}
- type='email'
- ref='email'
- className='form-control'
- placeholder={this.props.intl.formatMessage(holders.address)}
- maxLength='128'
- spellCheck='false'
- />
- {emailError}
- </div>
- <div className='form-group'>
- <button
- className='btn btn-md btn-primary'
- type='submit'
- >
- <FormattedMessage
- id='email_signup.createTeam'
- defaultMessage='Create Team'
- />
- </button>
- {serverError}
- </div>
- </form>
- );
- }
-}
-
-EmailSignUpPage.defaultProps = {
-};
-EmailSignUpPage.propTypes = {
- intl: intlShape.isRequired
-};
-
-export default injectIntl(EmailSignUpPage);
diff --git a/webapp/components/team_signup_with_ldap.jsx b/webapp/components/team_signup_with_ldap.jsx
deleted file mode 100644
index 9d812e8ee..000000000
--- a/webapp/components/team_signup_with_ldap.jsx
+++ /dev/null
@@ -1,231 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import $ from 'jquery';
-import ReactDOM from 'react-dom';
-import * as utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
-
-import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
-import {browserHistory} from 'react-router';
-
-const holders = defineMessages({
- team_error: {
- id: 'ldap_signup.team_error',
- defaultMessage: 'Please enter a team name'
- },
- length_error: {
- id: 'ldap_signup.length_error',
- defaultMessage: 'Name must be 3 or more characters up to a maximum of 15'
- },
- teamName: {
- id: 'ldap_signup.teamName',
- defaultMessage: 'Enter name of new team'
- },
- badTeam: {
- id: 'login_ldap.badTeam',
- defaultMessage: 'Bad team name'
- },
- idReq: {
- id: 'login_ldap.idlReq',
- defaultMessage: 'An LDAP ID is required'
- },
- pwdReq: {
- id: 'login_ldap.pwdReq',
- defaultMessage: 'An LDAP password is required'
- },
- username: {
- id: 'login_ldap.username',
- defaultMessage: 'LDAP Username'
- },
- pwd: {
- id: 'login_ldap.pwd',
- defaultMessage: 'LDAP Password'
- }
-});
-
-import React from 'react';
-
-class LdapSignUpPage extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleSubmit = this.handleSubmit.bind(this);
- this.valueChange = this.valueChange.bind(this);
-
- this.state = {name: '', id: '', password: ''};
- }
-
- handleSubmit(e) {
- e.preventDefault();
- const {formatMessage} = this.props.intl;
- var teamSignup = {};
- teamSignup.user = {};
- teamSignup.team = {};
- var state = this.state;
- state.serverError = null;
-
- teamSignup.team.display_name = this.state.name;
-
- if (!teamSignup.team.display_name) {
- state.serverError = formatMessage(holders.team_error);
- this.setState(state);
- return;
- }
-
- if (teamSignup.team.display_name.length <= 2) {
- state.serverError = formatMessage(holders.length_error);
- this.setState(state);
- return;
- }
-
- const id = this.refs.id.value.trim();
- if (!id) {
- state.serverError = formatMessage(holders.idReq);
- this.setState(state);
- return;
- }
-
- const password = this.refs.password.value.trim();
- if (!password) {
- state.serverError = formatMessage(holders.pwdReq);
- this.setState(state);
- return;
- }
-
- state.serverError = '';
- this.setState(state);
-
- teamSignup.team.name = utils.cleanUpUrlable(teamSignup.team.display_name);
- teamSignup.team.type = 'O';
-
- teamSignup.user.username = ReactDOM.findDOMNode(this.refs.id).value.trim();
- teamSignup.user.password = ReactDOM.findDOMNode(this.refs.password).value.trim();
- teamSignup.user.allow_marketing = true;
- teamSignup.user.ldap = true;
- teamSignup.user.auth_service = 'ldap';
-
- $('#ldap-button').button('loading');
-
- Client.createTeamWithLdap(teamSignup,
- () => {
- Client.track('signup', 'signup_team_ldap_complete');
-
- Client.loginByLdap(teamSignup.team.name, id, password,
- () => {
- browserHistory.push('/' + teamSignup.team.name + '/channels/town-square');
- },
- (err) => {
- $('#ldap-button').button('reset');
- this.setState({serverError: err.message});
- }
- );
- },
- (err) => {
- $('#ldap-button').button('reset');
- this.setState({serverError: err.message});
- }
- );
- }
-
- valueChange() {
- this.setState({
- name: ReactDOM.findDOMNode(this.refs.teamname).value.trim(),
- id: ReactDOM.findDOMNode(this.refs.id).value.trim(),
- password: ReactDOM.findDOMNode(this.refs.password).value.trim()
- });
- }
-
- render() {
- const {formatMessage} = this.props.intl;
- var nameError = null;
- var nameDivClass = 'form-group';
- if (this.state.nameError) {
- nameError = <label className='control-label'>{this.state.nameError}</label>;
- nameDivClass += ' has-error';
- }
-
- var serverError = null;
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- var disabled = false;
- if (this.state.name.length <= 2) {
- disabled = true;
- }
-
- if (this.state.id.length <= 1) {
- disabled = true;
- }
-
- if (this.state.password.length <= 1) {
- disabled = true;
- }
-
- return (
- <form
- role='form'
- onSubmit={this.handleSubmit}
- >
- <div className={nameDivClass}>
- <input
- autoFocus={true}
- type='text'
- ref='teamname'
- className='form-control'
- placeholder={this.props.intl.formatMessage(holders.teamName)}
- maxLength='128'
- onChange={this.valueChange}
- spellCheck='false'
- />
- {nameError}
- </div>
- <div className={nameDivClass}>
- <input
- className='form-control'
- ref='id'
- placeholder={formatMessage(holders.username)}
- spellCheck='false'
- onChange={this.valueChange}
- />
- </div>
- <div className={nameDivClass}>
- <input
- type='password'
- className='form-control'
- ref='password'
- placeholder={formatMessage(holders.pwd)}
- spellCheck='false'
- onChange={this.valueChange}
- />
- </div>
- <div className='form-group'>
- <a
- className='btn btn-custom-login ldap btn-full'
- key='ldap'
- id='ldap-button'
- href='#'
- onClick={this.handleSubmit}
- disabled={disabled}
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='ldap_signup.ldap'
- defaultMessage='Create team with LDAP Account'
- />
- </span>
- </a>
- {serverError}
- </div>
- </form>
- );
- }
-}
-
-LdapSignUpPage.propTypes = {
- intl: intlShape.isRequired
-};
-
-export default injectIntl(LdapSignUpPage);
diff --git a/webapp/components/team_signup_with_sso.jsx b/webapp/components/team_signup_with_sso.jsx
deleted file mode 100644
index 78396eea8..000000000
--- a/webapp/components/team_signup_with_sso.jsx
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-import ReactDOM from 'react-dom';
-import * as utils from 'utils/utils.jsx';
-import * as client from 'utils/client.jsx';
-import Constants from 'utils/constants.jsx';
-
-import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
-
-const holders = defineMessages({
- team_error: {
- id: 'sso_signup.team_error',
- defaultMessage: 'Please enter a team name'
- },
- length_error: {
- id: 'sso_signup.length_error',
- defaultMessage: 'Name must be 3 or more characters up to a maximum of 15'
- },
- teamName: {
- id: 'sso_signup.teamName',
- defaultMessage: 'Enter name of new team'
- }
-});
-
-import React from 'react';
-import {browserHistory} from 'react-router';
-
-class SSOSignUpPage extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleSubmit = this.handleSubmit.bind(this);
- this.nameChange = this.nameChange.bind(this);
-
- this.state = {name: ''};
- }
- handleSubmit(e) {
- e.preventDefault();
- const {formatMessage} = this.props.intl;
- var team = {};
- var state = this.state;
- state.nameError = null;
- state.serverError = null;
-
- team.display_name = this.state.name;
-
- if (!team.display_name) {
- state.nameError = formatMessage(holders.team_error);
- this.setState(state);
- return;
- }
-
- if (team.display_name.length <= 2) {
- state.nameError = formatMessage(holders.length_error);
- this.setState(state);
- return;
- }
-
- team.name = utils.cleanUpUrlable(team.display_name);
- team.type = 'O';
-
- client.createTeamWithSSO(team,
- this.props.service,
- (data) => {
- if (data.follow_link) {
- window.location.href = data.follow_link;
- } else {
- browserHistory.push('/' + team.name + '/channels/town-square');
- }
- },
- (err) => {
- state.serverError = err.message;
- this.setState(state);
- }
- );
- }
- nameChange() {
- this.setState({name: ReactDOM.findDOMNode(this.refs.teamname).value.trim()});
- }
- render() {
- var nameError = null;
- var nameDivClass = 'form-group';
- if (this.state.nameError) {
- nameError = <label className='control-label'>{this.state.nameError}</label>;
- nameDivClass += ' has-error';
- }
-
- var serverError = null;
- if (this.state.serverError) {
- serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
- }
-
- var disabled = false;
- if (this.state.name.length <= 2) {
- disabled = true;
- }
-
- var button = null;
-
- if (this.props.service === Constants.GITLAB_SERVICE) {
- button = (
- <a
- className='btn btn-custom-login gitlab btn-full'
- key='gitlab'
- href='#'
- onClick={this.handleSubmit}
- disabled={disabled}
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='sso_signup.gitlab'
- defaultMessage='Create team with GitLab Account'
- />
- </span>
- </a>
- );
- } else if (this.props.service === Constants.GOOGLE_SERVICE) {
- button = (
- <a
- className='btn btn-custom-login google btn-full'
- key='google'
- href='#'
- onClick={this.handleSubmit}
- disabled={disabled}
- >
- <span className='icon'/>
- <span>
- <FormattedMessage
- id='sso_signup.google'
- defaultMessage='Create team with Google Apps Account'
- />
- </span>
- </a>
- );
- }
-
- return (
- <form
- role='form'
- onSubmit={this.handleSubmit}
- >
- <div className={nameDivClass}>
- <input
- autoFocus={true}
- type='text'
- ref='teamname'
- className='form-control'
- placeholder={this.props.intl.formatMessage(holders.teamName)}
- maxLength='128'
- onChange={this.nameChange}
- spellCheck='false'
- />
- {nameError}
- </div>
- <div className='form-group'>
- {button}
- {serverError}
- </div>
- </form>
- );
- }
-}
-
-SSOSignUpPage.defaultProps = {
- service: ''
-};
-SSOSignUpPage.propTypes = {
- intl: intlShape.isRequired,
- service: React.PropTypes.string
-};
-
-export default injectIntl(SSOSignUpPage);
diff --git a/webapp/components/toggle_modal_button.jsx b/webapp/components/toggle_modal_button.jsx
index de225493c..69bdbbda0 100644
--- a/webapp/components/toggle_modal_button.jsx
+++ b/webapp/components/toggle_modal_button.jsx
@@ -15,7 +15,8 @@ export default class ModalToggleButton extends React.Component {
};
}
- show() {
+ show(e) {
+ e.preventDefault();
this.setState({show: true});
}
@@ -29,10 +30,10 @@ export default class ModalToggleButton extends React.Component {
// allow callers to provide an onClick which will be called before the modal is shown
let clickHandler = this.show;
if (onClick) {
- clickHandler = () => {
+ clickHandler = (e) => {
onClick();
- this.show();
+ this.show(e);
};
}
diff --git a/webapp/components/user_list.jsx b/webapp/components/user_list.jsx
index 3652723be..626cb3cf5 100644
--- a/webapp/components/user_list.jsx
+++ b/webapp/components/user_list.jsx
@@ -13,10 +13,18 @@ export default class UserList extends React.Component {
let content;
if (users.length > 0) {
content = users.map((user) => {
+ var teamMember;
+ for (var index in this.props.teamMembers) {
+ if (this.props.teamMembers[index].user_id === user.id) {
+ teamMember = this.props.teamMembers[index];
+ }
+ }
+
return (
<UserListRow
key={user.id}
user={user}
+ teamMember={teamMember}
actions={this.props.actions}
actionProps={this.props.actionProps}
/>
@@ -48,12 +56,14 @@ export default class UserList extends React.Component {
UserList.defaultProps = {
users: [],
+ teamMembers: [],
actions: [],
actionProps: {}
};
UserList.propTypes = {
users: React.PropTypes.arrayOf(React.PropTypes.object),
+ teamMembers: React.PropTypes.arrayOf(React.PropTypes.object),
actions: React.PropTypes.arrayOf(React.PropTypes.func),
actionProps: React.PropTypes.object
};
diff --git a/webapp/components/user_list_row.jsx b/webapp/components/user_list_row.jsx
index f6fd91688..a7838ec32 100644
--- a/webapp/components/user_list_row.jsx
+++ b/webapp/components/user_list_row.jsx
@@ -4,9 +4,10 @@
import Constants from 'utils/constants.jsx';
import PreferenceStore from 'stores/preference_store.jsx';
import * as Utils from 'utils/utils.jsx';
+import Client from 'utils/web_client.jsx';
import React from 'react';
-export default function UserListRow({user, actions, actionProps}) {
+export default function UserListRow({user, teamMember, actions, actionProps}) {
const nameFormat = PreferenceStore.get(Constants.Preferences.CATEGORY_DISPLAY_SETTINGS, 'name_format', '');
let name = user.username;
@@ -21,6 +22,7 @@ export default function UserListRow({user, actions, actionProps}) {
<Action
key={index.toString()}
user={user}
+ teamMember={teamMember}
{...actionProps}
/>
);
@@ -35,7 +37,7 @@ export default function UserListRow({user, actions, actionProps}) {
className='more-modal__image'
width='38'
height='38'
- src={`/api/v1/users/${user.id}/image?time=${user.update_at}`}
+ src={`${Client.getUsersRoute()}/${user.id}/image?time=${user.update_at}`}
/>
<div
className='more-modal__details'
@@ -57,12 +59,17 @@ export default function UserListRow({user, actions, actionProps}) {
}
UserListRow.defaultProps = {
+ teamMember: {
+ team_id: '',
+ roles: ''
+ },
actions: [],
actionProps: {}
};
UserListRow.propTypes = {
user: React.PropTypes.object.isRequired,
+ teamMember: React.PropTypes.object.isRequired,
actions: React.PropTypes.arrayOf(React.PropTypes.func),
actionProps: React.PropTypes.object
};
diff --git a/webapp/components/user_profile.jsx b/webapp/components/user_profile.jsx
index d83ab7454..04b4f99a4 100644
--- a/webapp/components/user_profile.jsx
+++ b/webapp/components/user_profile.jsx
@@ -2,6 +2,7 @@
// See License.txt for license information.
import * as Utils from 'utils/utils.jsx';
+import Client from 'utils/web_client.jsx';
import {FormattedMessage} from 'react-intl';
@@ -28,7 +29,7 @@ export default class UserProfile extends React.Component {
if (this.props.user) {
name = Utils.displayUsername(this.props.user.id);
email = this.props.user.email;
- profileImg = '/api/v1/users/' + this.props.user.id + '/image?time=' + this.props.user.update_at;
+ profileImg = Client.getUsersRoute() + '/' + this.props.user.id + '/image?time=' + this.props.user.update_at;
}
if (this.props.overwriteName) {
diff --git a/webapp/components/user_settings/import_theme_modal.jsx b/webapp/components/user_settings/import_theme_modal.jsx
index 2fc75ca13..32da296bf 100644
--- a/webapp/components/user_settings/import_theme_modal.jsx
+++ b/webapp/components/user_settings/import_theme_modal.jsx
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom';
import ModalStore from 'stores/modal_store.jsx';
import UserStore from 'stores/user_store.jsx';
import * as Utils from 'utils/utils.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import {Modal} from 'react-bootstrap';
import AppDispatcher from '../../dispatcher/app_dispatcher.jsx';
diff --git a/webapp/components/user_settings/manage_languages.jsx b/webapp/components/user_settings/manage_languages.jsx
index 094eaa127..bbf3a2e40 100644
--- a/webapp/components/user_settings/manage_languages.jsx
+++ b/webapp/components/user_settings/manage_languages.jsx
@@ -3,7 +3,7 @@
import SettingItemMax from '../setting_item_max.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as I18n from 'i18n/i18n.jsx';
import * as GlobalActions from 'action_creators/global_actions.jsx';
diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general.jsx
index eddbc1efe..c6a05d1ee 100644
--- a/webapp/components/user_settings/user_settings_general.jsx
+++ b/webapp/components/user_settings/user_settings_general.jsx
@@ -9,7 +9,7 @@ import SettingPicture from '../setting_picture.jsx';
import UserStore from 'stores/user_store.jsx';
import ErrorStore from 'stores/error_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import Constants from 'utils/constants.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
@@ -225,11 +225,9 @@ class UserSettingsGeneralTab extends React.Component {
return;
}
- var formData = new FormData();
- formData.append('image', picture, picture.name);
this.setState({loadingPicture: true});
- Client.uploadProfileImage(formData,
+ Client.uploadProfileImage(picture,
() => {
this.submitActive = false;
AsyncClient.getMe();
@@ -781,7 +779,7 @@ class UserSettingsGeneralTab extends React.Component {
<SettingPicture
title={formatMessage(holders.profilePicture)}
submit={this.submitPicture}
- src={'/api/v1/users/' + user.id + '/image?time=' + user.last_picture_update}
+ src={Client.getUsersRoute() + '/' + user.id + '/image?time=' + user.last_picture_update}
server_error={serverError}
client_error={clientError}
updateSection={(e) => {
diff --git a/webapp/components/user_settings/user_settings_notifications.jsx b/webapp/components/user_settings/user_settings_notifications.jsx
index b119c42f9..fa84ce2d6 100644
--- a/webapp/components/user_settings/user_settings_notifications.jsx
+++ b/webapp/components/user_settings/user_settings_notifications.jsx
@@ -8,7 +8,7 @@ import SettingItemMax from '../setting_item_max.jsx';
import UserStore from 'stores/user_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
diff --git a/webapp/components/user_settings/user_settings_security.jsx b/webapp/components/user_settings/user_settings_security.jsx
index ff5a898a9..f28e34197 100644
--- a/webapp/components/user_settings/user_settings_security.jsx
+++ b/webapp/components/user_settings/user_settings_security.jsx
@@ -10,7 +10,7 @@ import ToggleModalButton from '../toggle_modal_button.jsx';
import TeamStore from 'stores/team_store.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as AsyncClient from 'utils/async_client.jsx';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
@@ -96,12 +96,10 @@ class SecurityTab extends React.Component {
return;
}
- var data = {};
- data.user_id = user.id;
- data.current_password = currentPassword;
- data.new_password = newPassword;
-
- Client.updatePassword(data,
+ Client.updatePassword(
+ user.id,
+ currentPassword,
+ newPassword,
() => {
this.props.updateSection('');
AsyncClient.getMe();
@@ -120,11 +118,9 @@ class SecurityTab extends React.Component {
);
}
activateMfa() {
- const data = {};
- data.activate = true;
- data.token = this.state.mfaToken;
-
- Client.updateMfa(data,
+ Client.updateMfa(
+ this.state.mfaToken,
+ true,
() => {
this.props.updateSection('');
AsyncClient.getMe();
@@ -224,7 +220,7 @@ class SecurityTab extends React.Component {
<div className='col-sm-7'>
<img
className='qr-code-img'
- src={'/api/v1/users/generate_mfa_qr?time=' + this.props.user.update_at}
+ src={Client.getUsersRoute() + '/generate_mfa_qr?time=' + this.props.user.update_at}
/>
</div>
<br/>
@@ -531,9 +527,9 @@ class SecurityTab extends React.Component {
if (global.window.mm_config.EnableSignUpWithEmail === 'true' && user.auth_service !== '') {
let link;
if (user.auth_service === Constants.LDAP_SERVICE) {
- link = '/' + teamName + '/claim/ldap_to_email?email=' + encodeURIComponent(user.email);
+ link = '/claim/ldap_to_email?email=' + encodeURIComponent(user.email);
} else {
- link = '/' + teamName + '/claim/oauth_to_email?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service;
+ link = '/claim/oauth_to_email?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service;
}
emailOption = (
@@ -558,7 +554,7 @@ class SecurityTab extends React.Component {
<div>
<Link
className='btn btn-primary'
- to={'/' + teamName + '/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE}
+ to={'/claim/email_to_oauth?email=' + encodeURIComponent(user.email) + '&old_type=' + user.auth_service + '&new_type=' + Constants.GITLAB_SERVICE}
>
<FormattedMessage
id='user.settings.security.switchGitlab'
@@ -594,7 +590,7 @@ class SecurityTab extends React.Component {
<div>
<Link
className='btn btn-primary'
- to={'/' + teamName + '/claim/email_to_ldap?email=' + encodeURIComponent(user.email)}
+ to={'/claim/email_to_ldap?email=' + encodeURIComponent(user.email)}
>
<FormattedMessage
id='user.settings.security.switchLdap'
@@ -660,6 +656,13 @@ class SecurityTab extends React.Component {
defaultMessage='GitLab SSO'
/>
);
+ } else if (this.props.user.auth_service === Constants.LDAP_SERVICE) {
+ describe = (
+ <FormattedMessage
+ id='user.settings.security.ldap'
+ defaultMessage='LDAP'
+ />
+ );
}
return (
diff --git a/webapp/components/user_settings/user_settings_theme.jsx b/webapp/components/user_settings/user_settings_theme.jsx
index 14991037d..f19538f71 100644
--- a/webapp/components/user_settings/user_settings_theme.jsx
+++ b/webapp/components/user_settings/user_settings_theme.jsx
@@ -11,7 +11,7 @@ import SettingItemMax from '../setting_item_max.jsx';
import UserStore from 'stores/user_store.jsx';
import AppDispatcher from '../../dispatcher/app_dispatcher.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import Constants from 'utils/constants.jsx';
diff --git a/webapp/components/view_image.jsx b/webapp/components/view_image.jsx
index 3d3107d92..bd4aeaa41 100644
--- a/webapp/components/view_image.jsx
+++ b/webapp/components/view_image.jsx
@@ -3,7 +3,7 @@
import $ from 'jquery';
import * as AsyncClient from 'utils/async_client.jsx';
-import * as Client from 'utils/client.jsx';
+import Client from 'utils/web_client.jsx';
import * as Utils from 'utils/utils.jsx';
import AudioVideoPreview from './audio_video_preview.jsx';
import Constants from 'utils/constants.jsx';