From 482745323264a125ba7839175b80c1174b03a832 Mon Sep 17 00:00:00 2001 From: "Khoa, Le Ngoc" Date: Tue, 2 Feb 2016 16:04:25 +0700 Subject: Added help text indicating valid email required when user sign up from link. --- web/react/components/signup_user_complete.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'web/react') diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index 47ec58e98..bea10f0a4 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -150,9 +150,18 @@ class SignupUserComplete extends React.Component { // set up error labels var emailError = null; + var emailHelpText = ( + + + + ); var emailDivStyle = 'form-group'; if (this.state.emailError) { emailError = ; + emailHelpText = ''; emailDivStyle += ' has-error'; } @@ -232,6 +241,7 @@ class SignupUserComplete extends React.Component { spellCheck='false' /> {emailError} + {emailHelpText} ); -- cgit v1.2.3-1-g7c22 From 4d70e1246bd12ee167525d9f92d673b617d4039b Mon Sep 17 00:00:00 2001 From: "Khoa, Le Ngoc" Date: Tue, 2 Feb 2016 16:29:14 +0700 Subject: Fixed Eslint validation. --- web/react/components/signup_user_complete.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'web/react') diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx index bea10f0a4..98a832542 100644 --- a/web/react/components/signup_user_complete.jsx +++ b/web/react/components/signup_user_complete.jsx @@ -154,8 +154,8 @@ class SignupUserComplete extends React.Component { + defaultMessage='Valid email required for sign-up' + /> ); var emailDivStyle = 'form-group'; -- cgit v1.2.3-1-g7c22 From 3d03bdf2f1af5385c2150544977fbba89650b1ee Mon Sep 17 00:00:00 2001 From: JoramWilander Date: Tue, 2 Feb 2016 08:41:02 -0500 Subject: Added extra system-wide statistics for EE --- web/react/components/admin_console/analytics.jsx | 274 ++++++++++++++------- .../components/admin_console/doughnut_chart.jsx | 77 ++++++ .../components/admin_console/statistic_count.jsx | 37 +++ .../components/admin_console/system_analytics.jsx | 36 ++- .../components/admin_console/team_analytics.jsx | 3 +- 5 files changed, 342 insertions(+), 85 deletions(-) create mode 100644 web/react/components/admin_console/doughnut_chart.jsx create mode 100644 web/react/components/admin_console/statistic_count.jsx (limited to 'web/react') diff --git a/web/react/components/admin_console/analytics.jsx b/web/react/components/admin_console/analytics.jsx index a22c26c34..0a159d2e3 100644 --- a/web/react/components/admin_console/analytics.jsx +++ b/web/react/components/admin_console/analytics.jsx @@ -4,11 +4,60 @@ import * as Utils from '../../utils/utils.jsx'; import Constants from '../../utils/constants.jsx'; import LineChart from './line_chart.jsx'; +import DoughnutChart from './doughnut_chart.jsx'; +import StatisticCount from './statistic_count.jsx'; var Tooltip = ReactBootstrap.Tooltip; var OverlayTrigger = ReactBootstrap.OverlayTrigger; -import {FormattedMessage} from 'mm-intl'; +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +const holders = defineMessages({ + analyticsTotalUsers: { + id: 'admin.analytics.totalUsers', + defaultMessage: 'Total Users' + }, + analyticsPublicChannels: { + id: 'admin.analytics.publicChannels', + defaultMessage: 'Public Channels' + }, + analyticsPrivateGroups: { + id: 'admin.analytics.privateGroups', + defaultMessage: 'Private Groups' + }, + analyticsTotalPosts: { + id: 'admin.analytics.totalPosts', + defaultMessage: 'Total Posts' + }, + analyticsFilePosts: { + id: 'admin.analytics.totalFilePosts', + defaultMessage: 'Posts with Files' + }, + analyticsHashtagPosts: { + id: 'admin.analytics.totalHashtagPosts', + defaultMessage: 'Posts with Hashtags' + }, + analyticsIncomingHooks: { + id: 'admin.analytics.totalIncomingWebhooks', + defaultMessage: 'Incoming Webhooks' + }, + analyticsOutgoingHooks: { + id: 'admin.analytics.totalOutgoingWebhooks', + defaultMessage: 'Outgoing Webhooks' + }, + analyticsChannelTypes: { + id: 'admin.analytics.channelTypes', + defaultMessage: 'Channel Types' + }, + analyticsTextPosts: { + id: 'admin.analytics.textPosts', + defaultMessage: 'Posts with Text-only' + }, + analyticsPostTypes: { + id: 'admin.analytics.postTypes', + defaultMessage: 'Posts, Files and Hashtags' + } +}); export default class Analytics extends React.Component { constructor(props) { @@ -18,6 +67,8 @@ export default class Analytics extends React.Component { } render() { // in the future, break down these into smaller components + const {formatMessage} = this.props.intl; + var serverError = ''; if (this.props.serverError) { serverError =
; @@ -30,77 +81,129 @@ export default class Analytics extends React.Component { /> ); - var totalCount = ( -
-
-
- -
-
{this.props.uniqueUserCount == null ? loading : this.props.uniqueUserCount}
+ let firstRow; + let extraGraphs; + if (this.props.showAdvanced) { + firstRow = ( +
+ + + +
-
- ); + ); - var openChannelCount = ( -
-
-
- -
-
{this.props.channelOpenCount == null ? loading : this.props.channelOpenCount}
-
-
- ); + const channelTypeData = [ + { + value: this.props.channelOpenCount, + color: '#46BFBD', + highlight: '#5AD3D1', + label: formatMessage(holders.analyticsPublicChannels) + }, + { + value: this.props.channelPrivateCount, + color: '#FDB45C', + highlight: '#FFC870', + label: formatMessage(holders.analyticsPrivateGroups) + } + ]; - var openPrivateCount = ( -
-
-
- -
-
{this.props.channelPrivateCount == null ? loading : this.props.channelPrivateCount}
-
-
- ); + const postTypeData = [ + { + value: this.props.filePostCount, + color: '#46BFBD', + highlight: '#5AD3D1', + label: formatMessage(holders.analyticsFilePosts) + }, + { + value: this.props.filePostCount, + color: '#F7464A', + highlight: '#FF5A5E', + label: formatMessage(holders.analyticsHashtagPosts) + }, + { + value: this.props.postCount - this.props.filePostCount - this.props.hashtagPostCount, + color: '#FDB45C', + highlight: '#FFC870', + label: formatMessage(holders.analyticsTextPosts) + } + ]; - var postCount = ( -
-
-
- -
-
{this.props.postCount == null ? loading : this.props.postCount}
+ extraGraphs = ( +
+ +
-
- ); + ); + } else { + firstRow = ( +
+ + + + +
+ ); + } - var postCountsByDay = ( -
-
-
- + let postCountsByDay; + if (this.props.postCountsDay == null) { + postCountsByDay = ( +
+
+
+ +
+
{loading}
-
{loading}
-
- ); - - if (this.props.postCountsDay != null) { + ); + } else { let content; if (this.props.postCountsDay.labels.length === 0) { content = ( @@ -137,21 +240,22 @@ export default class Analytics extends React.Component { ); } - var usersWithPostsByDay = ( -
-
-
- + let usersWithPostsByDay; + if (this.props.userCountsWithPostsDay == null) { + usersWithPostsByDay = ( +
+
+
+ +
+
{loading}
-
{loading}
-
- ); - - if (this.props.userCountsWithPostsDay != null) { + ); + } else { let content; if (this.props.userCountsWithPostsDay.labels.length === 0) { content = ( @@ -312,12 +416,8 @@ export default class Analytics extends React.Component { /> {serverError} -
- {totalCount} - {postCount} - {openChannelCount} - {openPrivateCount} -
+ {firstRow} + {extraGraphs}
{postCountsByDay}
@@ -347,10 +447,16 @@ Analytics.defaultProps = { }; Analytics.propTypes = { + intl: intlShape.isRequired, title: React.PropTypes.string, channelOpenCount: React.PropTypes.number, channelPrivateCount: React.PropTypes.number, postCount: React.PropTypes.number, + showAdvanced: React.PropTypes.bool, + filePostCount: React.PropTypes.number, + hashtagPostCount: React.PropTypes.number, + incomingWebhookCount: React.PropTypes.number, + outgoingWebhookCount: React.PropTypes.number, postCountsDay: React.PropTypes.object, userCountsWithPostsDay: React.PropTypes.object, recentActiveUsers: React.PropTypes.array, @@ -358,3 +464,5 @@ Analytics.propTypes = { uniqueUserCount: React.PropTypes.number, serverError: React.PropTypes.string }; + +export default injectIntl(Analytics); diff --git a/web/react/components/admin_console/doughnut_chart.jsx b/web/react/components/admin_console/doughnut_chart.jsx new file mode 100644 index 000000000..e2dc01528 --- /dev/null +++ b/web/react/components/admin_console/doughnut_chart.jsx @@ -0,0 +1,77 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {FormattedMessage} from 'mm-intl'; + +export default class DoughnutChart extends React.Component { + constructor(props) { + super(props); + + this.initChart = this.initChart.bind(this); + this.chart = null; + } + + componentDidMount() { + this.initChart(this.props); + } + + componentWillReceiveProps(nextProps) { + if (this.chart) { + this.chart.destroy(); + this.initChart(nextProps); + } + } + + componentWillUnmount() { + if (this.chart) { + this.chart.destroy(); + } + } + + initChart(props) { + var el = ReactDOM.findDOMNode(this.refs.canvas); + var ctx = el.getContext('2d'); + this.chart = new Chart(ctx).Doughnut(props.data, props.options || {}); //eslint-disable-line new-cap + } + + render() { + let content; + if (this.props.data == null) { + content = ( + + ); + } else { + content = ( + + ); + } + + return ( +
+
+
+ {this.props.title} +
+
+ {content} +
+
+
+ ); + } +} + +DoughnutChart.propTypes = { + title: React.PropTypes.string, + width: React.PropTypes.string, + height: React.PropTypes.string, + data: React.PropTypes.array, + options: React.PropTypes.object +}; diff --git a/web/react/components/admin_console/statistic_count.jsx b/web/react/components/admin_console/statistic_count.jsx new file mode 100644 index 000000000..57af0ed1b --- /dev/null +++ b/web/react/components/admin_console/statistic_count.jsx @@ -0,0 +1,37 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import {FormattedMessage} from 'mm-intl'; + +export default class StatisticCount extends React.Component { + constructor(props) { + super(props); + } + + render() { + let loading = ( + + ); + + return ( +
+
+
+ {this.props.title} + +
+
{this.props.count == null ? loading : this.props.count}
+
+
+ ); + } +} + +StatisticCount.propTypes = { + title: React.PropTypes.string.isRequired, + icon: React.PropTypes.string.isRequired, + count: React.PropTypes.number +}; diff --git a/web/react/components/admin_console/system_analytics.jsx b/web/react/components/admin_console/system_analytics.jsx index 2dd833fb2..f983db177 100644 --- a/web/react/components/admin_console/system_analytics.jsx +++ b/web/react/components/admin_console/system_analytics.jsx @@ -140,6 +140,34 @@ class SystemAnalytics extends React.Component { this.setState({serverError: err.message}); } ); + + if (global.window.mm_license.IsLicensed === 'true') { + Client.getSystemAnalytics( + 'extra_counts', + (data) => { + for (var index in data) { + if (data[index].name === 'file_post_count') { + this.setState({file_post_count: data[index].value}); + } + + if (data[index].name === 'hashtag_post_count') { + this.setState({hashtag_post_count: data[index].value}); + } + + if (data[index].name === 'incoming_webhook_count') { + this.setState({incoming_webhook_count: data[index].value}); + } + + if (data[index].name === 'outgoing_webhook_count') { + this.setState({outgoing_webhook_count: data[index].value}); + } + } + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } } componentWillReceiveProps() { @@ -160,10 +188,16 @@ class SystemAnalytics extends React.Component { return (
Date: Tue, 2 Feb 2016 12:51:40 -0500 Subject: Updated post help link --- web/react/components/textbox.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'web/react') diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx index bb383aca1..00e5ace98 100644 --- a/web/react/components/textbox.jsx +++ b/web/react/components/textbox.jsx @@ -129,13 +129,6 @@ export default class Textbox extends React.Component { this.resize(); } - showHelp(e) { - e.preventDefault(); - e.target.blur(); - - global.window.open('/docs/Messaging'); - } - render() { let previewLink = null; if (Utils.isFeatureEnabled(PreReleaseFeatures.MARKDOWN_PREVIEW)) { @@ -194,7 +187,8 @@ export default class Textbox extends React.Component {
{previewLink} Date: Mon, 1 Feb 2016 14:30:16 -0800 Subject: Changed clock icon in repeat posts to simple timestamp --- web/react/components/post.jsx | 1 + web/react/components/post_header.jsx | 7 +++++-- web/react/components/post_info.jsx | 7 +++++-- web/react/components/time_since.jsx | 17 ++++++++++++++--- web/react/utils/constants.jsx | 3 ++- 5 files changed, 27 insertions(+), 8 deletions(-) (limited to 'web/react') diff --git a/web/react/components/post.jsx b/web/react/components/post.jsx index 695d7daef..53fe7fb5d 100644 --- a/web/react/components/post.jsx +++ b/web/react/components/post.jsx @@ -214,6 +214,7 @@ export default class Post extends React.Component { commentCount={commentCount} handleCommentClick={this.handleCommentClick} isLastComment={this.props.isLastComment} + sameUser={this.props.sameUser} /> @@ -62,11 +63,13 @@ export default class PostHeader extends React.Component { PostHeader.defaultProps = { post: null, commentCount: 0, - isLastComment: false + isLastComment: false, + sameUser: false }; PostHeader.propTypes = { post: React.PropTypes.object, commentCount: React.PropTypes.number, isLastComment: React.PropTypes.bool, - handleCommentClick: React.PropTypes.func + handleCommentClick: React.PropTypes.func, + sameUser: React.PropTypes.bool }; diff --git a/web/react/components/post_info.jsx b/web/react/components/post_info.jsx index 2bff675a9..0fb9d7f4a 100644 --- a/web/react/components/post_info.jsx +++ b/web/react/components/post_info.jsx @@ -220,6 +220,7 @@ export default class PostInfo extends React.Component {
  • @@ -251,12 +252,14 @@ PostInfo.defaultProps = { post: null, commentCount: 0, isLastComment: false, - allowReply: false + allowReply: false, + sameUser: false }; PostInfo.propTypes = { post: React.PropTypes.object, commentCount: React.PropTypes.number, isLastComment: React.PropTypes.bool, allowReply: React.PropTypes.string, - handleCommentClick: React.PropTypes.func + handleCommentClick: React.PropTypes.func, + sameUser: React.PropTypes.bool }; diff --git a/web/react/components/time_since.jsx b/web/react/components/time_since.jsx index 32947bd60..0b549b1e6 100644 --- a/web/react/components/time_since.jsx +++ b/web/react/components/time_since.jsx @@ -14,7 +14,7 @@ export default class TimeSince extends React.Component { componentDidMount() { this.intervalId = setInterval(() => { this.forceUpdate(); - }, 30000); + }, Constants.TIME_SINCE_UPDATE_INTERVAL); } componentWillUnmount() { clearInterval(this.intervalId); @@ -23,6 +23,14 @@ export default class TimeSince extends React.Component { const displayDate = Utils.displayDate(this.props.eventTime); const displayTime = Utils.displayTime(this.props.eventTime); + if (this.props.sameUser) { + return ( + + ); + } + const tooltip = ( {displayDate + ' at ' + displayTime} @@ -42,10 +50,13 @@ export default class TimeSince extends React.Component { ); } } + TimeSince.defaultProps = { - eventTime: 0 + eventTime: 0, + sameUser: false }; TimeSince.propTypes = { - eventTime: React.PropTypes.number.isRequired + eventTime: React.PropTypes.number.isRequired, + sameUser: React.PropTypes.bool }; diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx index e1a4b8a8a..ad0e4b2fe 100644 --- a/web/react/utils/constants.jsx +++ b/web/react/utils/constants.jsx @@ -462,5 +462,6 @@ export default { MIN_USERNAME_LENGTH: 3, MAX_USERNAME_LENGTH: 15, MIN_PASSWORD_LENGTH: 5, - MAX_PASSWORD_LENGTH: 50 + MAX_PASSWORD_LENGTH: 50, + TIME_SINCE_UPDATE_INTERVAL: 30000 }; -- cgit v1.2.3-1-g7c22 From b013f02209c7c128a35d1c54f2d4a7d6a9701f72 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Wed, 13 Jan 2016 14:58:49 -0800 Subject: Added ability to sign in via username; separated email sign in and sign up config settings --- .../components/admin_console/email_settings.jsx | 84 ++++++++++ web/react/components/login.jsx | 15 +- web/react/components/login_username.jsx | 181 +++++++++++++++++++++ web/react/stores/user_store.jsx | 10 ++ web/react/utils/client.jsx | 22 +++ 5 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 web/react/components/login_username.jsx (limited to 'web/react') diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx index ce3c8cd12..17f25a04c 100644 --- a/web/react/components/admin_console/email_settings.jsx +++ b/web/react/components/admin_console/email_settings.jsx @@ -112,6 +112,8 @@ class EmailSettings extends React.Component { buildConfig() { var config = this.props.config; config.EmailSettings.EnableSignUpWithEmail = ReactDOM.findDOMNode(this.refs.allowSignUpWithEmail).checked; + config.EmailSettings.EnableSignInWithEmail = ReactDOM.findDOMNode(this.refs.allowSignInWithEmail).checked; + config.EmailSettings.EnableSignInWithUsername = ReactDOM.findDOMNode(this.refs.allowSignInWithUsername).checked; config.EmailSettings.SendEmailNotifications = ReactDOM.findDOMNode(this.refs.sendEmailNotifications).checked; config.EmailSettings.SendPushNotifications = ReactDOM.findDOMNode(this.refs.sendPushNotifications).checked; config.EmailSettings.RequireEmailVerification = ReactDOM.findDOMNode(this.refs.requireEmailVerification).checked; @@ -317,6 +319,88 @@ class EmailSettings extends React.Component {
  • +
    + +
    + + +

    + +

    +
    +
    + +
    + +
    + + +

    + +

    +
    +
    +
    - ); + ); } if (global.window.mm_config.EnableSignUpWithGoogle === 'true') { @@ -87,7 +88,7 @@ export default class Login extends React.Component { } let emailSignup; - if (global.window.mm_config.EnableSignUpWithEmail === 'true') { + if (global.window.mm_config.EnableSignInWithEmail === 'true') { emailSignup = ( + ); + } + return (
    @@ -210,6 +220,7 @@ export default class Login extends React.Component { {extraBox} {loginMessage} {emailSignup} + {usernameLogin} {ldapLogin} {userSignUp} {findTeams} diff --git a/web/react/components/login_username.jsx b/web/react/components/login_username.jsx new file mode 100644 index 000000000..f787490fa --- /dev/null +++ b/web/react/components/login_username.jsx @@ -0,0 +1,181 @@ +// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +import * as Utils from '../utils/utils.jsx'; +import * as Client from '../utils/client.jsx'; +import UserStore from '../stores/user_store.jsx'; + +import {injectIntl, intlShape, defineMessages, FormattedMessage} from 'mm-intl'; + +var holders = defineMessages({ + badTeam: { + id: 'login_username.badTeam', + defaultMessage: 'Bad team name' + }, + usernameReq: { + id: 'login_username.usernameReq', + defaultMessage: 'A username is required' + }, + pwdReq: { + id: 'login_username.pwdReq', + defaultMessage: 'A password is required' + }, + verifyEmailError: { + id: 'login_username.verifyEmailError', + defaultMessage: 'Please verify your email address. Check your inbox for an email.' + }, + userNotFoundError: { + id: 'login_username.userNotFoundError', + defaultMessage: "We couldn't find an existing account matching your username for this team." + }, + username: { + id: 'login_username.username', + defaultMessage: 'Username' + }, + pwd: { + id: 'login_username.pwd', + defaultMessage: 'Password' + } +}); + +export default class LoginUsername extends React.Component { + constructor(props) { + super(props); + + this.handleSubmit = this.handleSubmit.bind(this); + + this.state = { + serverError: '' + }; + } + handleSubmit(e) { + e.preventDefault(); + const {formatMessage} = this.props.intl; + var state = {}; + + const name = this.props.teamName; + if (!name) { + state.serverError = formatMessage(holders.badTeam); + this.setState(state); + return; + } + + const username = this.refs.username.value.trim(); + if (!username) { + state.serverError = formatMessage(holders.usernameReq); + this.setState(state); + return; + } + + const password = this.refs.password.value.trim(); + if (!password) { + state.serverError = formatMessage(holders.pwdReq); + this.setState(state); + return; + } + + state.serverError = ''; + this.setState(state); + + Client.loginByUsername(name, username, password, + () => { + UserStore.setLastUsername(username); + + const redirect = Utils.getUrlParameter('redirect'); + if (redirect) { + window.location.href = decodeURIComponent(redirect); + } else { + window.location.href = '/' + name + '/channels/town-square'; + } + }, + (err) => { + if (err.message === 'api.user.login.not_verified.app_error') { + state.serverError = formatMessage(holders.verifyEmailError); + } else if (err.message === 'store.sql_user.get_by_username.app_error') { + state.serverError = formatMessage(holders.userNotFoundError); + } else { + state.serverError = err.message; + } + + this.valid = false; + this.setState(state); + } + ); + } + render() { + let serverError; + let errorClass = ''; + if (this.state.serverError) { + serverError = ; + errorClass = ' has-error'; + } + + let priorUsername = UserStore.getLastUsername(); + let focusUsername = false; + let focusPassword = false; + if (priorUsername === '') { + focusUsername = true; + } else { + focusPassword = true; + } + + const emailParam = Utils.getUrlParameter('email'); + if (emailParam) { + priorUsername = decodeURIComponent(emailParam); + } + + const {formatMessage} = this.props.intl; + return ( +
    +
    +
    + {serverError} +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    + ); + } +} +LoginUsername.defaultProps = { +}; + +LoginUsername.propTypes = { + intl: intlShape.isRequired, + teamName: React.PropTypes.string.isRequired +}; + +export default injectIntl(LoginUsername); diff --git a/web/react/stores/user_store.jsx b/web/react/stores/user_store.jsx index 3e1871180..b97a0d87b 100644 --- a/web/react/stores/user_store.jsx +++ b/web/react/stores/user_store.jsx @@ -38,6 +38,8 @@ class UserStoreClass extends EventEmitter { this.setCurrentUser = this.setCurrentUser.bind(this); this.getLastEmail = this.getLastEmail.bind(this); this.setLastEmail = this.setLastEmail.bind(this); + this.getLastUsername = this.getLastUsername.bind(this); + this.setLastUsername = this.setLastUsername.bind(this); this.hasProfile = this.hasProfile.bind(this); this.getProfile = this.getProfile.bind(this); this.getProfileByUsername = this.getProfileByUsername.bind(this); @@ -159,6 +161,14 @@ class UserStoreClass extends EventEmitter { BrowserStore.setGlobalItem('last_email', email); } + getLastUsername() { + return BrowserStore.getGlobalItem('last_username', ''); + } + + setLastUsername(username) { + BrowserStore.setGlobalItem('last_username', username); + } + hasProfile(userId) { return this.getProfiles()[userId] != null; } diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index 09cd4162a..c4b1bc061 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -305,6 +305,28 @@ export function loginByEmail(name, email, password, success, error) { }); } +export function loginByUsername(name, username, password, success, error) { + $.ajax({ + url: '/api/v1/users/login', + dataType: 'json', + contentType: 'application/json', + type: 'POST', + data: JSON.stringify({name, username, password}), + success: function onSuccess(data, textStatus, xhr) { + track('api', 'api_users_login_success', data.team_id, 'username', data.username); + sessionStorage.removeItem(data.id + '_last_error'); + BrowserStore.signalLogin(); + success(data, textStatus, xhr); + }, + error: function onError(xhr, status, err) { + track('api', 'api_users_login_fail', name, 'username', username); + + var e = handleError('loginByUsername', xhr, status, err); + error(e); + } + }); +} + export function loginByLdap(teamName, id, password, success, error) { $.ajax({ url: '/api/v1/users/login_ldap', -- cgit v1.2.3-1-g7c22 From 70e0618f629122891e9bcfe358def061042bef49 Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Mon, 1 Feb 2016 09:28:23 -0800 Subject: Fixed React invalid prop warning in Team Settings --- web/react/components/team_general_tab.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx index 0656d3b03..0a1b02853 100644 --- a/web/react/components/team_general_tab.jsx +++ b/web/react/components/team_general_tab.jsx @@ -575,6 +575,8 @@ class GeneralTab extends React.Component {
    ); + const nameExtraInfo = {formatMessage(holders.teamNameInfo)}; + nameSection = ( ); } else { -- cgit v1.2.3-1-g7c22 From eeb1c1b5b827cc20ae32449bfc8c227152ba1a9d Mon Sep 17 00:00:00 2001 From: Reed Garmsen Date: Fri, 29 Jan 2016 13:29:43 -0800 Subject: Properly disable the get team link functionality when user creation is disabled --- web/react/components/get_link_modal.jsx | 23 +++++++++++++++------- .../components/get_team_invite_link_modal.jsx | 12 ++++++++++- 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'web/react') diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx index 3fc71ff96..de3387a35 100644 --- a/web/react/components/get_link_modal.jsx +++ b/web/react/components/get_link_modal.jsx @@ -41,6 +41,8 @@ export default class GetLinkModal extends React.Component { } render() { + const userCreationEnabled = global.window.mm_config.EnableUserCreation === 'true'; + let helpText = null; if (this.props.helpText) { helpText = ( @@ -53,7 +55,7 @@ export default class GetLinkModal extends React.Component { } let copyLink = null; - if (document.queryCommandSupported('copy')) { + if (userCreationEnabled && document.queryCommandSupported('copy')) { copyLink = (