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
Этот коммит содержится в:
136
webapp/components/create_team/components/display_name.jsx
Обычный файл
136
webapp/components/create_team/components/display_name.jsx
Обычный файл
@@ -0,0 +1,136 @@
|
||||
// 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 Client from 'utils/web_client.jsx';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'react-intl';
|
||||
|
||||
import logoImage from 'images/logo.png';
|
||||
|
||||
const holders = defineMessages({
|
||||
required: {
|
||||
id: 'create_team_display_name.required',
|
||||
defaultMessage: 'This field is required'
|
||||
},
|
||||
charLength: {
|
||||
id: 'create_team_display_name.charLength',
|
||||
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class TeamSignupDisplayNamePage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.submitNext = this.submitNext.bind(this);
|
||||
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
submitNext(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
var displayName = ReactDOM.findDOMNode(this.refs.name).value.trim();
|
||||
if (!displayName) {
|
||||
this.setState({nameError: formatMessage(holders.required)});
|
||||
return;
|
||||
} else if (displayName.length < 4 || displayName.length > 15) {
|
||||
this.setState({nameError: formatMessage(holders.charLength)});
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.state.wizard = 'team_url';
|
||||
this.props.state.team.display_name = displayName;
|
||||
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');
|
||||
|
||||
var nameError = null;
|
||||
var nameDivClass = 'form-group';
|
||||
if (this.state.nameError) {
|
||||
nameError = <label className='control-label'>{this.state.nameError}</label>;
|
||||
nameDivClass += ' has-error';
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src={logoImage}
|
||||
/>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id='create_team_display_name.teamName'
|
||||
defaultMessage='Team Name'
|
||||
/>
|
||||
</h2>
|
||||
<div className={nameDivClass}>
|
||||
<div className='row'>
|
||||
<div className='col-sm-9'>
|
||||
<input
|
||||
type='text'
|
||||
ref='name'
|
||||
className='form-control'
|
||||
placeholder=''
|
||||
maxLength='128'
|
||||
defaultValue={this.props.state.team.display_name}
|
||||
autoFocus={true}
|
||||
onFocus={this.handleFocus}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{nameError}
|
||||
</div>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id='create_team_display_name.nameHelp'
|
||||
defaultMessage='Name your team in any language. Your team name shows in menus and headings.'
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type='submit'
|
||||
className='btn btn-primary margin--extra'
|
||||
onClick={this.submitNext}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='create_team_display_name.next'
|
||||
defaultMessage='Next'
|
||||
/><i className='glyphicon glyphicon-chevron-right'></i>
|
||||
</button>
|
||||
<div className='margin--extra'>
|
||||
<Link to='/select_team'>
|
||||
<FormattedMessage
|
||||
id='create_team_display_name.back'
|
||||
defaultMessage='Back to previous step'
|
||||
/>
|
||||
</Link>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TeamSignupDisplayNamePage.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
state: React.PropTypes.object,
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
export default injectIntl(TeamSignupDisplayNamePage);
|
||||
229
webapp/components/create_team/components/team_url.jsx
Обычный файл
229
webapp/components/create_team/components/team_url.jsx
Обычный файл
@@ -0,0 +1,229 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import $ from 'jquery';
|
||||
import ReactDOM from 'react-dom';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import 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';
|
||||
|
||||
import logoImage from 'images/logo.png';
|
||||
|
||||
const holders = defineMessages({
|
||||
required: {
|
||||
id: 'create_team_url.required',
|
||||
defaultMessage: 'This field is required'
|
||||
},
|
||||
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: 'create_team_url.charLength',
|
||||
defaultMessage: 'Name must be 4 or more characters up to a maximum of 15'
|
||||
},
|
||||
taken: {
|
||||
id: 'create_team_url.taken',
|
||||
defaultMessage: 'URL is taken or contains a reserved word'
|
||||
},
|
||||
unavailable: {
|
||||
id: 'create_team_url.unavailable',
|
||||
defaultMessage: 'This URL is unavailable. Please try another.'
|
||||
}
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
|
||||
class TeamUrl extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.submitBack = this.submitBack.bind(this);
|
||||
this.submitNext = this.submitNext.bind(this);
|
||||
this.handleFocus = this.handleFocus.bind(this);
|
||||
|
||||
this.state = {nameError: ''};
|
||||
}
|
||||
submitBack(e) {
|
||||
e.preventDefault();
|
||||
this.props.state.wizard = 'display_name';
|
||||
this.props.updateParent(this.props.state);
|
||||
}
|
||||
submitNext(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const {formatMessage} = this.props.intl;
|
||||
const name = ReactDOM.findDOMNode(this.refs.name).value.trim();
|
||||
if (!name) {
|
||||
this.setState({nameError: formatMessage(holders.required)});
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanedName = Utils.cleanUpUrlable(name);
|
||||
|
||||
const urlRegex = /^[a-z]+([a-z\-0-9]+|(__)?)[a-z0-9]+$/g;
|
||||
if (cleanedName !== name || !urlRegex.test(name)) {
|
||||
this.setState({nameError: formatMessage(holders.regex)});
|
||||
return;
|
||||
} else if (cleanedName.length < 4 || cleanedName.length > 15) {
|
||||
this.setState({nameError: formatMessage(holders.charLength)});
|
||||
return;
|
||||
}
|
||||
|
||||
if (global.window.mm_config.RestrictTeamNames === 'true') {
|
||||
for (let index = 0; index < Constants.RESERVED_TEAM_NAMES.length; index++) {
|
||||
if (cleanedName.indexOf(Constants.RESERVED_TEAM_NAMES[index]) === 0) {
|
||||
this.setState({nameError: formatMessage(holders.taken)});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#finish-button').button('loading');
|
||||
var teamSignup = JSON.parse(JSON.stringify(this.props.state));
|
||||
teamSignup.team.type = 'O';
|
||||
teamSignup.team.name = name;
|
||||
|
||||
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) {
|
||||
e.preventDefault();
|
||||
|
||||
e.currentTarget.select();
|
||||
}
|
||||
render() {
|
||||
$('body').tooltip({selector: '[data-toggle=tooltip]', trigger: 'hover click'});
|
||||
|
||||
Client.track('signup', 'signup_team_03_url');
|
||||
|
||||
let nameError = null;
|
||||
let nameDivClass = 'form-group';
|
||||
if (this.state.nameError) {
|
||||
nameError = <label className='control-label'>{this.state.nameError}</label>;
|
||||
nameDivClass += ' has-error';
|
||||
}
|
||||
|
||||
const title = `${Utils.getWindowLocationOrigin()}/`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form>
|
||||
<img
|
||||
className='signup-team-logo'
|
||||
src={logoImage}
|
||||
/>
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id='create_team_url.teamUrl'
|
||||
defaultMessage='Team URL'
|
||||
/>
|
||||
</h2>
|
||||
<div className={nameDivClass}>
|
||||
<div className='row'>
|
||||
<div className='col-sm-11'>
|
||||
<div className='input-group input-group--limit'>
|
||||
<span
|
||||
data-toggle='tooltip'
|
||||
title={title}
|
||||
className='input-group-addon'
|
||||
>
|
||||
{title}
|
||||
</span>
|
||||
<input
|
||||
type='text'
|
||||
ref='name'
|
||||
className='form-control'
|
||||
placeholder=''
|
||||
maxLength='128'
|
||||
defaultValue={this.props.state.team.name}
|
||||
autoFocus={true}
|
||||
onFocus={this.handleFocus}
|
||||
spellCheck='false'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{nameError}
|
||||
</div>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='create_team_url.webAddress'
|
||||
defaultMessage='Choose the web address of your new team:'
|
||||
/>
|
||||
</p>
|
||||
<ul className='color--light'>
|
||||
<FormattedHTMLMessage
|
||||
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>"
|
||||
/>
|
||||
</ul>
|
||||
<button
|
||||
type='submit'
|
||||
id='finish-button'
|
||||
className='btn btn-primary margin--extra'
|
||||
onClick={this.submitNext}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='create_team_password.finish'
|
||||
defaultMessage='Finish'
|
||||
/>
|
||||
</button>
|
||||
<div className='margin--extra'>
|
||||
<a
|
||||
href='#'
|
||||
onClick={this.submitBack}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='create_team_url.back'
|
||||
defaultMessage='Back to previous step'
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TeamUrl.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
state: React.PropTypes.object,
|
||||
updateParent: React.PropTypes.func
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
Ссылка в новой задаче
Block a user