PLT-2057 User as a first class object (#2648)
* Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding TeamMember to system * Fixing all unit tests on the backend * Fixing merge conflicts * Fixing merge conflict * Adding javascript unit tests * Adding client side unit test * Cleaning up the clint side tests * Fixing msg * Adding more client side unit tests * Adding more using tests * Adding last bit of client side unit tests and adding make cmd * Fixing bad merge * Fixing libraries * Updating to new client side API * Fixing borken unit test * Fixing unit tests * ugg...trying to beat gofmt * ugg...trying to beat gofmt * Cleaning up remainder of the server side routes * Adding inital load api * Increased coverage of webhook unit tests (#2660) * Adding loading ... to root html * Fixing bad merge * Removing explicit content type so superagent will guess corectly (#2685) * Fixing merge and unit tests * Adding create team UI * Fixing signup flows * Adding LDAP unit tests and enterprise unit test helper (#2702) * Add the ability to reset MFA from the commandline (#2706) * Fixing compliance unit tests * Fixing client side tests * Adding open server to system console * Moving websocket connection * Fixing unit test * Fixing unit tests * Fixing unit tests * Adding nickname and more LDAP unit tests (#2717) * Adding join open teams * Cleaning up all TODOs in the code * Fixing web sockets * Removing unused webockets file * PLT-2533 Add the ability to reset a user's MFA from the system console (#2715) * Add the ability to reset a user's MFA from the system console * Add client side unit test for adminResetMfa * Reorganizing authentication to fix LDAP error message (#2723) * Fixing failing unit test * Initial upgrade db code * Adding upgrade script * Fixing upgrade script after running on core * Update OAuth and Claim routes to work with user model changes (#2739) * Fixing perminant deletion. Adding ability to delete all user and the entire database (#2740) * Fixing team invite ldap login call (#2741) * Fixing bluebar and some img stuff * Fix all the different file upload web utils (#2743) * Fixing invalid session redirect (#2744) * Redirect on bad channel name (#2746) * Fixing a bunch of issue and removing dead code * Patch to fix error message on leave channel (#2747) * Setting EnableOpenServer to false by default * Fixing config * Fixing upgrade * Fixing reported bugs * Bug fixes for PLT-2057 * PLT-2563 Redo password recovery to use a database table (#2745) * Redo password recovery to use a database table * Update reset password audits * Split out admin and user reset password APIs to be separate * Delete password recovery when user is permanently deleted * Consolidate password resetting into a single function * Removed private channels as an option for outgoing webhooks (#2752) * PLT-2577/PLT-2552 Fixes for backstage (#2753) * Added URL to incoming webhook list * Fixed client functions for adding/removing integrations * Disallowed slash commands without trigger words * Fixed clientside handling of errors on AddCommand page * Minor auth cleanup (#2758) * Changed EditPostModal to just close if you save without making any changes (#2759) * Renamed client -> Client in async_client.jsx and fixed eslint warnings (#2756) * Fixed url in channel info modal (#2755) * Fixing reported issues * Moving to version 3 of the apis * Fixing command unit tests (#2760) * Adding team admins * Fixing DM issue * Fixing eslint error * Properly set EditPostModal's originalText state in all cases (#2762) * Update client config check to assume features is defined if server is licensed (#2772) * Fixing url link * Fixing issue with websocket crashing when sending messages to different teams
Этот коммит содержится в:
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -438,6 +439,35 @@ class LdapSettings extends React.Component {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<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'
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
export default injectIntl(ResetPasswordModal);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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 {
|
||||
@@ -534,6 +537,53 @@ class TeamSettings extends React.Component {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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'
|
||||
@@ -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'>
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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,39 +11,14 @@ 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: ''
|
||||
oldType: this.props.location.query.old_type
|
||||
});
|
||||
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
|
||||
});
|
||||
}
|
||||
onTeamChange() {
|
||||
this.updateStateFromStores();
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
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';
|
||||
$('#finish-button').button('loading');
|
||||
var teamSignup = JSON.parse(JSON.stringify(this.props.state));
|
||||
teamSignup.team.type = 'O';
|
||||
teamSignup.team.name = name;
|
||||
|
||||
this.props.state.team.name = name;
|
||||
this.props.updateParent(this.props.state);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
this.setState({nameError: err.message});
|
||||
}
|
||||
Client.findTeamByName(name,
|
||||
(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);
|
||||
72
webapp/components/create_team/create_team.jsx
Обычный файл
72
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
|
||||
};
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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'>×</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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 (
|
||||
@@ -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';
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
}
|
||||
isValidState() {
|
||||
return this.state.user != null && this.state.profiles != null;
|
||||
}
|
||||
onUserChanged() {
|
||||
// Grab the current user
|
||||
const user = UserStore.getCurrentUser();
|
||||
|
||||
if (this.state.user) {
|
||||
this.setupUser(this.state.user);
|
||||
}
|
||||
}
|
||||
|
||||
isValidState() {
|
||||
return this.state.user != null;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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]}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1,22 +1,156 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as GlobalActions from 'action_creators/global_actions.jsx';
|
||||
|
||||
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 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 {
|
||||
componentWillMount() {
|
||||
GlobalActions.loadTeamRequiredPage();
|
||||
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() {
|
||||
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
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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'
|
||||
/>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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';
|
||||
|
||||
257
webapp/components/select_team/select_team.jsx
Обычный файл
257
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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 = '';
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 = {
|
||||
};
|
||||
|
||||
@@ -74,6 +74,7 @@ export default class SignupTeamComplete extends React.Component {
|
||||
|
||||
SignupTeamComplete.defaultProps = {
|
||||
};
|
||||
|
||||
SignupTeamComplete.propTypes = {
|
||||
location: React.PropTypes.object,
|
||||
children: React.PropTypes.node
|
||||
|
||||
@@ -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});
|
||||
@@ -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."
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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
|
||||
};
|
||||
@@ -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 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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'>
|
||||
<h1>{global.window.mm_config.SiteName}</h1>
|
||||
<h4 className='color--light'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.welcome'
|
||||
defaultMessage='Welcome to:'
|
||||
id='web.root.singup_info'
|
||||
/>
|
||||
</h5>
|
||||
<h2 className='signup-team__name'>{this.state.teamName}</h2>
|
||||
<h2 className='signup-team__subdomain'>
|
||||
<FormattedMessage
|
||||
id='signup_user_completed.onSite'
|
||||
defaultMessage='on {siteName}'
|
||||
values={{
|
||||
siteName: global.window.mm_config.SiteName
|
||||
}}
|
||||
/>
|
||||
</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>
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -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);
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user