summaryrefslogtreecommitdiffstats
path: root/web/react
diff options
context:
space:
mode:
Diffstat (limited to 'web/react')
-rw-r--r--web/react/components/admin_console/admin_controller.jsx3
-rw-r--r--web/react/components/admin_console/admin_sidebar.jsx10
-rw-r--r--web/react/components/admin_console/email_settings.jsx2
-rw-r--r--web/react/components/admin_console/jobs_settings.jsx2
-rw-r--r--web/react/components/admin_console/logs.jsx88
-rw-r--r--web/react/components/authorize.jsx72
-rw-r--r--web/react/components/change_url_modal.jsx2
-rw-r--r--web/react/components/email_verify.jsx6
-rw-r--r--web/react/components/find_team.jsx7
-rw-r--r--web/react/components/get_link_modal.jsx5
-rw-r--r--web/react/components/invite_member_modal.jsx99
-rw-r--r--web/react/components/login.jsx7
-rw-r--r--web/react/components/navbar_dropdown.jsx5
-rw-r--r--web/react/components/new_channel_modal.jsx2
-rw-r--r--web/react/components/password_reset_form.jsx3
-rw-r--r--web/react/components/popover_list_members.jsx2
-rw-r--r--web/react/components/post_list.jsx6
-rw-r--r--web/react/components/register_app_modal.jsx249
-rw-r--r--web/react/components/search_bar.jsx4
-rw-r--r--web/react/components/setting_item_max.jsx2
-rw-r--r--web/react/components/setting_picture.jsx4
-rw-r--r--web/react/components/sidebar.jsx78
-rw-r--r--web/react/components/sidebar_header.jsx3
-rw-r--r--web/react/components/sidebar_right_menu.jsx5
-rw-r--r--web/react/components/signup_team_complete.jsx10
-rw-r--r--web/react/components/signup_user_complete.jsx11
-rw-r--r--web/react/components/team_general_tab.jsx9
-rw-r--r--web/react/components/team_signup_allowed_domains_page.jsx143
-rw-r--r--web/react/components/team_signup_choose_auth.jsx7
-rw-r--r--web/react/components/team_signup_display_name_page.jsx5
-rw-r--r--web/react/components/team_signup_password_page.jsx5
-rw-r--r--web/react/components/team_signup_send_invites_page.jsx18
-rw-r--r--web/react/components/team_signup_url_page.jsx13
-rw-r--r--web/react/components/team_signup_username_page.jsx3
-rw-r--r--web/react/components/team_signup_welcome_page.jsx3
-rw-r--r--web/react/components/team_signup_with_email.jsx3
-rw-r--r--web/react/components/team_signup_with_sso.jsx5
-rw-r--r--web/react/components/unread_channel_indicator.jsx35
-rw-r--r--web/react/components/user_profile.jsx3
-rw-r--r--web/react/components/user_settings.jsx10
-rw-r--r--web/react/components/user_settings_appearance.jsx17
-rw-r--r--web/react/components/user_settings_developer.jsx93
-rw-r--r--web/react/components/user_settings_general.jsx3
-rw-r--r--web/react/components/user_settings_modal.jsx11
-rw-r--r--web/react/components/user_settings_notifications.jsx3
-rw-r--r--web/react/components/view_image.jsx3
-rw-r--r--web/react/package.json7
-rw-r--r--web/react/pages/authorize.jsx21
-rw-r--r--web/react/pages/channel.jsx34
-rw-r--r--web/react/pages/home.jsx6
-rw-r--r--web/react/pages/login.jsx8
-rw-r--r--web/react/pages/password_reset.jsx12
-rw-r--r--web/react/pages/signup_team.jsx8
-rw-r--r--web/react/pages/signup_team_complete.jsx8
-rw-r--r--web/react/pages/signup_user_complete.jsx16
-rw-r--r--web/react/pages/verify.jsx8
-rw-r--r--web/react/stores/admin_store.jsx58
-rw-r--r--web/react/stores/config_store.jsx69
-rw-r--r--web/react/stores/post_store.jsx1
-rw-r--r--web/react/utils/async_client.jsx52
-rw-r--r--web/react/utils/client.jsx46
-rw-r--r--web/react/utils/config.js48
-rw-r--r--web/react/utils/constants.jsx4
-rw-r--r--web/react/utils/text_formatting.jsx4
-rw-r--r--web/react/utils/utils.jsx7
65 files changed, 925 insertions, 571 deletions
diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx
index bb43af802..68984c9e0 100644
--- a/web/react/components/admin_console/admin_controller.jsx
+++ b/web/react/components/admin_console/admin_controller.jsx
@@ -4,6 +4,7 @@
var AdminSidebar = require('./admin_sidebar.jsx');
var EmailTab = require('./email_settings.jsx');
var JobsTab = require('./jobs_settings.jsx');
+var LogsTab = require('./logs.jsx');
var Navbar = require('../../components/navbar.jsx');
export default class AdminController extends React.Component {
@@ -28,6 +29,8 @@ export default class AdminController extends React.Component {
tab = <EmailTab />;
} else if (this.state.selected === 'job_settings') {
tab = <JobsTab />;
+ } else if (this.state.selected === 'logs') {
+ tab = <LogsTab />;
}
return (
diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx
index 6b3be89d0..a04bceef5 100644
--- a/web/react/components/admin_console/admin_sidebar.jsx
+++ b/web/react/components/admin_console/admin_sidebar.jsx
@@ -83,7 +83,15 @@ export default class AdminSidebar extends React.Component {
{'Email Settings'}
</a>
</li>
- <li><a href='#'>{'Other Settings'}</a></li>
+ <li>
+ <a
+ href='#'
+ className={this.isSelected('logs')}
+ onClick={this.handleClick.bind(null, 'logs')}
+ >
+ {'Logs'}
+ </a>
+ </li>
</ul>
</li>
<li>
diff --git a/web/react/components/admin_console/email_settings.jsx b/web/react/components/admin_console/email_settings.jsx
index 3c53a8ee1..e8fb25858 100644
--- a/web/react/components/admin_console/email_settings.jsx
+++ b/web/react/components/admin_console/email_settings.jsx
@@ -300,7 +300,7 @@ export default class EmailSettings extends React.Component {
type='submit'
className='btn btn-primary'
>
- {'Submit'}
+ {'Save'}
</button>
</div>
</div>
diff --git a/web/react/components/admin_console/jobs_settings.jsx b/web/react/components/admin_console/jobs_settings.jsx
index 34ec9693d..0b4fc4185 100644
--- a/web/react/components/admin_console/jobs_settings.jsx
+++ b/web/react/components/admin_console/jobs_settings.jsx
@@ -172,7 +172,7 @@ export default class Jobs extends React.Component {
type='submit'
className='btn btn-primary'
>
- {'Submit'}
+ {'Save'}
</button>
</div>
</div>
diff --git a/web/react/components/admin_console/logs.jsx b/web/react/components/admin_console/logs.jsx
new file mode 100644
index 000000000..d7de76a94
--- /dev/null
+++ b/web/react/components/admin_console/logs.jsx
@@ -0,0 +1,88 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var AdminStore = require('../../stores/admin_store.jsx');
+var LoadingScreen = require('../loading_screen.jsx');
+var AsyncClient = require('../../utils/async_client.jsx');
+
+export default class Logs extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.onLogListenerChange = this.onLogListenerChange.bind(this);
+ this.reload = this.reload.bind(this);
+
+ this.state = {
+ logs: AdminStore.getLogs()
+ };
+ }
+
+ componentDidMount() {
+ AdminStore.addLogChangeListener(this.onLogListenerChange);
+ AsyncClient.getLogs();
+ }
+ componentWillUnmount() {
+ AdminStore.removeLogChangeListener(this.onLogListenerChange);
+ }
+ onLogListenerChange() {
+ this.setState({
+ logs: AdminStore.getLogs()
+ });
+ }
+
+ reload() {
+ AdminStore.saveLogs(null);
+ this.setState({
+ logs: null
+ });
+
+ AsyncClient.getLogs();
+ }
+
+ render() {
+ var content = null;
+
+ if (this.state.logs === null) {
+ content = <LoadingScreen />;
+ } else {
+ content = [];
+
+ for (var i = 0; i < this.state.logs.length; i++) {
+ var style = {
+ whiteSpace: 'nowrap',
+ fontFamily: 'monospace'
+ };
+
+ if (this.state.logs[i].indexOf('[EROR]') > 0) {
+ style.color = 'red';
+ }
+
+ content.push(<br key={'br_' + i} />);
+ content.push(
+ <span
+ key={'log_' + i}
+ style={style}
+ >
+ {this.state.logs[i]}
+ </span>
+ );
+ }
+ }
+
+ return (
+ <div className='panel'>
+ <h3>{'Server Logs'}</h3>
+ <button
+ type='submit'
+ className='btn btn-primary'
+ onClick={this.reload}
+ >
+ {'Reload'}
+ </button>
+ <div className='log__panel'>
+ {content}
+ </div>
+ </div>
+ );
+ }
+} \ No newline at end of file
diff --git a/web/react/components/authorize.jsx b/web/react/components/authorize.jsx
new file mode 100644
index 000000000..dd4479ad4
--- /dev/null
+++ b/web/react/components/authorize.jsx
@@ -0,0 +1,72 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Client = require('../utils/client.jsx');
+
+export default class Authorize extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleAllow = this.handleAllow.bind(this);
+ this.handleDeny = this.handleDeny.bind(this);
+
+ this.state = {};
+ }
+ handleAllow() {
+ const responseType = this.props.responseType;
+ const clientId = this.props.clientId;
+ const redirectUri = this.props.redirectUri;
+ const state = this.props.state;
+ const scope = this.props.scope;
+
+ Client.allowOAuth2(responseType, clientId, redirectUri, state, scope,
+ (data) => {
+ if (data.redirect) {
+ window.location.replace(data.redirect);
+ }
+ },
+ () => {}
+ );
+ }
+ handleDeny() {
+ window.location.replace(this.props.redirectUri + '?error=access_denied');
+ }
+ render() {
+ return (
+ <div className='authorize-box'>
+ <div className='authorize-inner'>
+ <h3>{'An application would like to connect to your '}{this.props.teamName}{' account'}</h3>
+ <label>{'The app '}{this.props.appName}{' would like the ability to access and modify your basic information.'}</label>
+ <br/>
+ <br/>
+ <label>{'Allow '}{this.props.appName}{' access?'}</label>
+ <br/>
+ <button
+ type='submit'
+ className='btn authorize-btn'
+ onClick={this.handleDeny}
+ >
+ {'Deny'}
+ </button>
+ <button
+ type='submit'
+ className='btn btn-primary authorize-btn'
+ onClick={this.handleAllow}
+ >
+ {'Allow'}
+ </button>
+ </div>
+ </div>
+ );
+ }
+}
+
+Authorize.propTypes = {
+ appName: React.PropTypes.string,
+ teamName: React.PropTypes.string,
+ responseType: React.PropTypes.string,
+ clientId: React.PropTypes.string,
+ redirectUri: React.PropTypes.string,
+ state: React.PropTypes.string,
+ scope: React.PropTypes.string
+};
diff --git a/web/react/components/change_url_modal.jsx b/web/react/components/change_url_modal.jsx
index 28fa70c1f..3553e1107 100644
--- a/web/react/components/change_url_modal.jsx
+++ b/web/react/components/change_url_modal.jsx
@@ -159,7 +159,7 @@ ChangeUrlModal.defaultProps = {
title: 'Change URL',
desciption: '',
urlLabel: 'URL',
- submitButtonText: 'Submit',
+ submitButtonText: 'Save',
currentURL: '',
serverError: ''
};
diff --git a/web/react/components/email_verify.jsx b/web/react/components/email_verify.jsx
index 95948c8dd..92123956f 100644
--- a/web/react/components/email_verify.jsx
+++ b/web/react/components/email_verify.jsx
@@ -1,8 +1,6 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-import {config} from '../utils/config.js';
-
export default class EmailVerify extends React.Component {
constructor(props) {
super(props);
@@ -19,10 +17,10 @@ export default class EmailVerify extends React.Component {
var body = '';
var resend = '';
if (this.props.isVerified === 'true') {
- title = config.SiteName + ' Email Verified';
+ title = global.window.config.SiteName + ' Email Verified';
body = <p>Your email has been verified! Click <a href={this.props.teamURL + '?email=' + this.props.userEmail}>here</a> to log in.</p>;
} else {
- title = config.SiteName + ' Email Not Verified';
+ title = global.window.config.SiteName + ' Email Not Verified';
body = <p>Please verify your email address. Check your inbox for an email.</p>;
resend = (
<button
diff --git a/web/react/components/find_team.jsx b/web/react/components/find_team.jsx
index 52988886c..eb2683a88 100644
--- a/web/react/components/find_team.jsx
+++ b/web/react/components/find_team.jsx
@@ -3,7 +3,6 @@
var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx');
-import {strings} from '../utils/config.js';
export default class FindTeam extends React.Component {
constructor(props) {
@@ -51,8 +50,8 @@ export default class FindTeam extends React.Component {
if (this.state.sent) {
return (
<div>
- <h4>{'Find Your ' + utils.toTitleCase(strings.Team)}</h4>
- <p>{'An email was sent with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
+ <h4>{'Find Your team'}</h4>
+ <p>{'An email was sent with links to any teams to which you are a member.'}</p>
</div>
);
}
@@ -61,7 +60,7 @@ export default class FindTeam extends React.Component {
<div>
<h4>Find Your Team</h4>
<form onSubmit={this.handleSubmit}>
- <p>{'Get an email with links to any ' + strings.TeamPlural + ' to which you are a member.'}</p>
+ <p>{'Get an email with links to any teams to which you are a member.'}</p>
<div className='form-group'>
<label className='control-label'>Email</label>
<div className={emailErrorClass}>
diff --git a/web/react/components/get_link_modal.jsx b/web/react/components/get_link_modal.jsx
index 1f25ea0b7..5d8b13f00 100644
--- a/web/react/components/get_link_modal.jsx
+++ b/web/react/components/get_link_modal.jsx
@@ -2,7 +2,6 @@
// See License.txt for license information.
var UserStore = require('../stores/user_store.jsx');
-import {strings} from '../utils/config.js';
export default class GetLinkModal extends React.Component {
constructor(props) {
@@ -76,9 +75,9 @@ export default class GetLinkModal extends React.Component {
</div>
<div className='modal-body'>
<p>
- Send {strings.Team + 'mates'} the link below for them to sign-up to this {strings.Team} site.
+ Send teammates the link below for them to sign-up to this team site.
<br /><br />
- Be careful not to share this link publicly, since anyone with the link can join your {strings.Team}.
+ Be careful not to share this link publicly, since anyone with the link can join your team.
</p>
<textarea
className='form-control no-resize'
diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx
index c1cfa7800..650a72516 100644
--- a/web/react/components/invite_member_modal.jsx
+++ b/web/react/components/invite_member_modal.jsx
@@ -2,11 +2,9 @@
// See License.txt for license information.
var utils = require('../utils/utils.jsx');
-var ConfigStore = require('../stores/config_store.jsx');
var Client = require('../utils/client.jsx');
var UserStore = require('../stores/user_store.jsx');
var ConfirmModal = require('./confirm_modal.jsx');
-import {config} from '../utils/config.js';
export default class InviteMemberModal extends React.Component {
constructor(props) {
@@ -23,7 +21,7 @@ export default class InviteMemberModal extends React.Component {
emailErrors: {},
firstNameErrors: {},
lastNameErrors: {},
- emailEnabled: !ConfigStore.getSettingAsBoolean('ByPassEmail', false)
+ emailEnabled: !global.window.config.ByPassEmail
};
}
@@ -79,23 +77,9 @@ export default class InviteMemberModal extends React.Component {
emailErrors[index] = '';
}
- if (config.AllowInviteNames) {
- invite.firstName = React.findDOMNode(this.refs['first_name' + index]).value.trim();
- if (!invite.firstName && config.RequireInviteNames) {
- firstNameErrors[index] = 'This is a required field';
- valid = false;
- } else {
- firstNameErrors[index] = '';
- }
+ invite.firstName = React.findDOMNode(this.refs['first_name' + index]).value.trim();
- invite.lastName = React.findDOMNode(this.refs['last_name' + index]).value.trim();
- if (!invite.lastName && config.RequireInviteNames) {
- lastNameErrors[index] = 'This is a required field';
- valid = false;
- } else {
- lastNameErrors[index] = '';
- }
- }
+ invite.lastName = React.findDOMNode(this.refs['last_name' + index]).value.trim();
invites.push(invite);
}
@@ -143,10 +127,8 @@ export default class InviteMemberModal extends React.Component {
for (var i = 0; i < inviteIds.length; i++) {
var index = inviteIds[i];
React.findDOMNode(this.refs['email' + index]).value = '';
- if (config.AllowInviteNames) {
- React.findDOMNode(this.refs['first_name' + index]).value = '';
- React.findDOMNode(this.refs['last_name' + index]).value = '';
- }
+ React.findDOMNode(this.refs['first_name' + index]).value = '';
+ React.findDOMNode(this.refs['last_name' + index]).value = '';
}
this.setState({
@@ -210,44 +192,43 @@ export default class InviteMemberModal extends React.Component {
}
var nameFields = null;
- if (config.AllowInviteNames) {
- var firstNameClass = 'form-group';
- if (firstNameError) {
- firstNameClass += ' has-error';
- }
- var lastNameClass = 'form-group';
- if (lastNameError) {
- lastNameClass += ' has-error';
- }
- nameFields = (<div className='row--invite'>
- <div className='col-sm-6'>
- <div className={firstNameClass}>
- <input
- type='text'
- className='form-control'
- ref={'first_name' + index}
- placeholder='First name'
- maxLength='64'
- disabled={!this.state.emailEnabled}
- />
- {firstNameError}
- </div>
+
+ var firstNameClass = 'form-group';
+ if (firstNameError) {
+ firstNameClass += ' has-error';
+ }
+ var lastNameClass = 'form-group';
+ if (lastNameError) {
+ lastNameClass += ' has-error';
+ }
+ nameFields = (<div className='row--invite'>
+ <div className='col-sm-6'>
+ <div className={firstNameClass}>
+ <input
+ type='text'
+ className='form-control'
+ ref={'first_name' + index}
+ placeholder='First name'
+ maxLength='64'
+ disabled={!this.state.emailEnabled}
+ />
+ {firstNameError}
</div>
- <div className='col-sm-6'>
- <div className={lastNameClass}>
- <input
- type='text'
- className='form-control'
- ref={'last_name' + index}
- placeholder='Last name'
- maxLength='64'
- disabled={!this.state.emailEnabled}
- />
- {lastNameError}
- </div>
+ </div>
+ <div className='col-sm-6'>
+ <div className={lastNameClass}>
+ <input
+ type='text'
+ className='form-control'
+ ref={'last_name' + index}
+ placeholder='Last name'
+ maxLength='64'
+ disabled={!this.state.emailEnabled}
+ />
+ {lastNameError}
</div>
- </div>);
- }
+ </div>
+ </div>);
inviteSections[index] = (
<div key={'key' + index}>
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index b20c62833..ffc07a4dd 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -6,7 +6,6 @@ const Client = require('../utils/client.jsx');
const UserStore = require('../stores/user_store.jsx');
const BrowserStore = require('../stores/browser_store.jsx');
const Constants = require('../utils/constants.jsx');
-import {config, strings} from '../utils/config.js';
export default class Login extends React.Component {
constructor(props) {
@@ -177,7 +176,7 @@ export default class Login extends React.Component {
<div className='signup-team__container'>
<h5 className='margin--less'>Sign in to:</h5>
<h2 className='signup-team__name'>{teamDisplayName}</h2>
- <h2 className='signup-team__subdomain'>on {config.SiteName}</h2>
+ <h2 className='signup-team__subdomain'>on {global.window.config.SiteName}</h2>
<form onSubmit={this.handleSubmit}>
<div className={'form-group' + errorClass}>
{serverError}
@@ -185,11 +184,11 @@ export default class Login extends React.Component {
{loginMessage}
{emailSignup}
<div className='form-group margin--extra form-group--small'>
- <span><a href='/find_team'>{'Find other ' + strings.TeamPlural}</a></span>
+ <span><a href='/find_team'>{'Find other teams'}</a></span>
</div>
{forgotPassword}
<div className='margin--extra'>
- <span>{'Want to create your own ' + strings.Team + '? '}
+ <span>{'Want to create your own team? '}
<a
href='/'
className='signup-team-login'
diff --git a/web/react/components/navbar_dropdown.jsx b/web/react/components/navbar_dropdown.jsx
index 99cdfa1ad..b7566cfb9 100644
--- a/web/react/components/navbar_dropdown.jsx
+++ b/web/react/components/navbar_dropdown.jsx
@@ -7,7 +7,6 @@ var UserStore = require('../stores/user_store.jsx');
var TeamStore = require('../stores/team_store.jsx');
var Constants = require('../utils/constants.jsx');
-import {config} from '../utils/config.js';
function getStateFromStores() {
return {teams: UserStore.getTeams(), currentTeam: TeamStore.getCurrent()};
@@ -188,7 +187,7 @@ export default class NavbarDropdown extends React.Component {
<li>
<a
target='_blank'
- href={config.HelpLink}
+ href='/static/help/help.html'
>
Help
</a>
@@ -196,7 +195,7 @@ export default class NavbarDropdown extends React.Component {
<li>
<a
target='_blank'
- href={config.ReportProblemLink}
+ href='/static/help/report_problem.html'
>
Report a Problem
</a>
diff --git a/web/react/components/new_channel_modal.jsx b/web/react/components/new_channel_modal.jsx
index 2bf645dc5..f3fb8da2a 100644
--- a/web/react/components/new_channel_modal.jsx
+++ b/web/react/components/new_channel_modal.jsx
@@ -127,7 +127,7 @@ export default class NewChannelModal extends React.Component {
href='#'
onClick={this.props.onChangeURLPressed}
>
- {'change this URL'}
+ {'Edit'}
</a>
{')'}
</p>
diff --git a/web/react/components/password_reset_form.jsx b/web/react/components/password_reset_form.jsx
index 1b579efbc..dae582627 100644
--- a/web/react/components/password_reset_form.jsx
+++ b/web/react/components/password_reset_form.jsx
@@ -2,7 +2,6 @@
// See License.txt for license information.
var client = require('../utils/client.jsx');
-import {config} from '../utils/config.js';
export default class PasswordResetForm extends React.Component {
constructor(props) {
@@ -62,7 +61,7 @@ export default class PasswordResetForm extends React.Component {
<div className='signup-team__container'>
<h3>Password Reset</h3>
<form onSubmit={this.handlePasswordReset}>
- <p>{'Enter a new password for your ' + this.props.teamDisplayName + ' ' + config.SiteName + ' account.'}</p>
+ <p>{'Enter a new password for your ' + this.props.teamDisplayName + ' ' + global.window.config.SiteName + ' account.'}</p>
<div className={formClass}>
<input
type='password'
diff --git a/web/react/components/popover_list_members.jsx b/web/react/components/popover_list_members.jsx
index fb9522afb..ec873dd00 100644
--- a/web/react/components/popover_list_members.jsx
+++ b/web/react/components/popover_list_members.jsx
@@ -25,7 +25,7 @@ export default class PopoverListMembers extends React.Component {
$('#member_popover').popover({placement: 'bottom', trigger: 'click', html: true});
$('body').on('click', function onClick(e) {
- if ($(e.target.parentNode.parentNode)[0] !== $('#member_popover')[0] && $(e.target).parents('.popover.in').length === 0) {
+ if (e.target.parentNode && $(e.target.parentNode.parentNode)[0] !== $('#member_popover')[0] && $(e.target).parents('.popover.in').length === 0) {
$('#member_popover').popover('hide');
}
});
diff --git a/web/react/components/post_list.jsx b/web/react/components/post_list.jsx
index e6aa3f8df..faa5e5f0b 100644
--- a/web/react/components/post_list.jsx
+++ b/web/react/components/post_list.jsx
@@ -15,8 +15,6 @@ var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
-import {strings} from '../utils/config.js';
-
export default class PostList extends React.Component {
constructor(props) {
super(props);
@@ -347,7 +345,7 @@ export default class PostList extends React.Component {
return (
<div className='channel-intro'>
- <p className='channel-intro-text'>{'This is the start of your private message history with this ' + strings.Team + 'mate. Private messages and files shared here are not shown to people outside this area.'}</p>
+ <p className='channel-intro-text'>{'This is the start of your private message history with this teammate. Private messages and files shared here are not shown to people outside this area.'}</p>
</div>
);
}
@@ -369,7 +367,7 @@ export default class PostList extends React.Component {
<p className='channel-intro__content'>
Welcome to {channel.display_name}!
<br/><br/>
- This is the first channel {strings.Team}mates see when they
+ This is the first channel teammates see when they
<br/>
sign up - use it for posting updates everyone needs to know.
<br/><br/>
diff --git a/web/react/components/register_app_modal.jsx b/web/react/components/register_app_modal.jsx
new file mode 100644
index 000000000..3dd5c094e
--- /dev/null
+++ b/web/react/components/register_app_modal.jsx
@@ -0,0 +1,249 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Client = require('../utils/client.jsx');
+
+export default class RegisterAppModal extends React.Component {
+ constructor() {
+ super();
+
+ this.register = this.register.bind(this);
+ this.onHide = this.onHide.bind(this);
+ this.save = this.save.bind(this);
+
+ this.state = {clientId: '', clientSecret: '', saved: false};
+ }
+ componentDidMount() {
+ $(React.findDOMNode(this)).on('hide.bs.modal', this.onHide);
+ }
+ register() {
+ var state = this.state;
+ state.serverError = null;
+
+ var app = {};
+
+ var name = this.refs.name.getDOMNode().value;
+ if (!name || name.length === 0) {
+ state.nameError = 'Application name must be filled in.';
+ this.setState(state);
+ return;
+ }
+ state.nameError = null;
+ app.name = name;
+
+ var homepage = this.refs.homepage.getDOMNode().value;
+ if (!homepage || homepage.length === 0) {
+ state.homepageError = 'Homepage must be filled in.';
+ this.setState(state);
+ return;
+ }
+ state.homepageError = null;
+ app.homepage = homepage;
+
+ var desc = this.refs.desc.getDOMNode().value;
+ app.description = desc;
+
+ var rawCallbacks = this.refs.callback.getDOMNode().value.trim();
+ if (!rawCallbacks || rawCallbacks.length === 0) {
+ state.callbackError = 'At least one callback URL must be filled in.';
+ this.setState(state);
+ return;
+ }
+ state.callbackError = null;
+ app.callback_urls = rawCallbacks.split('\n');
+
+ Client.registerOAuthApp(app,
+ (data) => {
+ state.clientId = data.id;
+ state.clientSecret = data.client_secret;
+ this.setState(state);
+ },
+ (err) => {
+ state.serverError = err.message;
+ this.setState(state);
+ }
+ );
+ }
+ onHide(e) {
+ if (!this.state.saved && this.state.clientId !== '') {
+ e.preventDefault();
+ return;
+ }
+
+ this.setState({clientId: '', clientSecret: '', saved: false});
+ }
+ save() {
+ this.setState({saved: this.refs.save.getDOMNode().checked});
+ }
+ render() {
+ var nameError;
+ if (this.state.nameError) {
+ nameError = <div className='form-group has-error'><label className='control-label'>{this.state.nameError}</label></div>;
+ }
+ var homepageError;
+ if (this.state.homepageError) {
+ homepageError = <div className='form-group has-error'><label className='control-label'>{this.state.homepageError}</label></div>;
+ }
+ var callbackError;
+ if (this.state.callbackError) {
+ callbackError = <div className='form-group has-error'><label className='control-label'>{this.state.callbackError}</label></div>;
+ }
+ var serverError;
+ if (this.state.serverError) {
+ serverError = <div className='form-group has-error'><label className='control-label'>{this.state.serverError}</label></div>;
+ }
+
+ var body = '';
+ if (this.state.clientId === '') {
+ body = (
+ <div className='form-group user-settings'>
+ <h3>{'Register a New Application'}</h3>
+ <br/>
+ <label className='col-sm-4 control-label'>{'Application Name'}</label>
+ <div className='col-sm-7'>
+ <input
+ ref='name'
+ className='form-control'
+ type='text'
+ placeholder='Required'
+ />
+ {nameError}
+ </div>
+ <br/>
+ <br/>
+ <label className='col-sm-4 control-label'>{'Homepage URL'}</label>
+ <div className='col-sm-7'>
+ <input
+ ref='homepage'
+ className='form-control'
+ type='text'
+ placeholder='Required'
+ />
+ {homepageError}
+ </div>
+ <br/>
+ <br/>
+ <label className='col-sm-4 control-label'>{'Description'}</label>
+ <div className='col-sm-7'>
+ <input
+ ref='desc'
+ className='form-control'
+ type='text'
+ placeholder='Optional'
+ />
+ </div>
+ <br/>
+ <br/>
+ <label className='col-sm-4 control-label'>{'Callback URL'}</label>
+ <div className='col-sm-7'>
+ <textarea
+ ref='callback'
+ className='form-control'
+ type='text'
+ placeholder='Required'
+ rows='5'
+ />
+ {callbackError}
+ </div>
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ {serverError}
+ <a
+ className='btn btn-sm theme pull-right'
+ href='#'
+ data-dismiss='modal'
+ aria-label='Close'
+ >
+ {'Cancel'}
+ </a>
+ <a
+ className='btn btn-sm btn-primary pull-right'
+ onClick={this.register}
+ >
+ {'Register'}
+ </a>
+ </div>
+ );
+ } else {
+ var btnClass = ' disabled';
+ if (this.state.saved) {
+ btnClass = '';
+ }
+
+ body = (
+ <div className='form-group user-settings'>
+ <h3>{'Your Application Credentials'}</h3>
+ <br/>
+ <br/>
+ <label className='col-sm-12 control-label'>{'Client ID: '}{this.state.clientId}</label>
+ <label className='col-sm-12 control-label'>{'Client Secret: '}{this.state.clientSecret}</label>
+ <br/>
+ <br/>
+ <br/>
+ <br/>
+ <strong>{'Save these somewhere SAFE and SECURE. We can retrieve your Client Id if you lose it, but your Client Secret will be lost forever if you were to lose it.'}</strong>
+ <br/>
+ <br/>
+ <div className='checkbox'>
+ <label>
+ <input
+ ref='save'
+ type='checkbox'
+ checked={this.state.saved}
+ onClick={this.save}
+ >
+ {'I have saved both my Client Id and Client Secret somewhere safe'}
+ </input>
+ </label>
+ </div>
+ <a
+ className={'btn btn-sm btn-primary pull-right' + btnClass}
+ href='#'
+ data-dismiss='modal'
+ aria-label='Close'
+ >
+ {'Close'}
+ </a>
+ </div>
+ );
+ }
+
+ return (
+ <div
+ className='modal fade'
+ ref='modal'
+ id='register_app'
+ role='dialog'
+ aria-hidden='true'
+ >
+ <div className='modal-dialog'>
+ <div className='modal-content'>
+ <div className='modal-header'>
+ <button
+ type='button'
+ className='close'
+ data-dismiss='modal'
+ aria-label='Close'
+ >
+ <span aria-hidden='true'>{'x'}</span>
+ </button>
+ <h4
+ className='modal-title'
+ ref='title'
+ >
+ {'Developer Applications'}
+ </h4>
+ </div>
+ <div className='modal-body'>
+ {body}
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+}
+
diff --git a/web/react/components/search_bar.jsx b/web/react/components/search_bar.jsx
index 006d15459..77166fef9 100644
--- a/web/react/components/search_bar.jsx
+++ b/web/react/components/search_bar.jsx
@@ -75,6 +75,9 @@ export default class SearchBar extends React.Component {
PostStore.emitSearchTermChange(false);
this.setState({searchTerm: term});
}
+ handleMouseInput(e) {
+ e.preventDefault();
+ }
handleUserFocus(e) {
e.target.select();
$('.search-bar__container').addClass('focused');
@@ -140,6 +143,7 @@ export default class SearchBar extends React.Component {
value={this.state.searchTerm}
onFocus={this.handleUserFocus}
onChange={this.handleUserInput}
+ onMouseUp={this.handleMouseInput}
/>
{isSearching}
</form>
diff --git a/web/react/components/setting_item_max.jsx b/web/react/components/setting_item_max.jsx
index b1bab1d48..1bffa7c79 100644
--- a/web/react/components/setting_item_max.jsx
+++ b/web/react/components/setting_item_max.jsx
@@ -26,7 +26,7 @@ export default class SettingItemMax extends React.Component {
href='#'
onClick={this.props.submit}
>
- Submit
+ Save
</a>
);
}
diff --git a/web/react/components/setting_picture.jsx b/web/react/components/setting_picture.jsx
index a53112651..ddad4fd53 100644
--- a/web/react/components/setting_picture.jsx
+++ b/web/react/components/setting_picture.jsx
@@ -1,8 +1,6 @@
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
// See License.txt for license information.
-import {config} from '../utils/config.js';
-
export default class SettingPicture extends React.Component {
constructor(props) {
super(props);
@@ -81,7 +79,7 @@ export default class SettingPicture extends React.Component {
>Save</a>
);
}
- var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + config.ProfileWidth + 'px in width and ' + config.ProfileHeight + 'px height.';
+ var helpText = 'Upload a profile picture in either JPG or PNG format, at least ' + global.window.config.ProfileWidth + 'px in width and ' + global.window.config.ProfileHeight + 'px height.';
var self = this;
return (
diff --git a/web/react/components/sidebar.jsx b/web/react/components/sidebar.jsx
index 977fecb5c..87007edcc 100644
--- a/web/react/components/sidebar.jsx
+++ b/web/react/components/sidebar.jsx
@@ -13,6 +13,7 @@ var SidebarHeader = require('./sidebar_header.jsx');
var SearchBox = require('./search_bar.jsx');
var Constants = require('../utils/constants.jsx');
var NewChannelFlow = require('./new_channel_flow.jsx');
+var UnreadChannelIndicator = require('./unread_channel_indicator.jsx');
export default class Sidebar extends React.Component {
constructor(props) {
@@ -153,6 +154,16 @@ export default class Sidebar extends React.Component {
$(window).on('resize', this.onResize);
}
+ shouldComponentUpdate(nextProps, nextState) {
+ if (!Utils.areStatesEqual(nextProps, this.props)) {
+ return true;
+ }
+
+ if (!Utils.areStatesEqual(nextState, this.state)) {
+ return true;
+ }
+ return false;
+ }
componentDidUpdate() {
this.updateTitle();
this.updateUnreadIndicators();
@@ -274,15 +285,16 @@ export default class Sidebar extends React.Component {
this.updateUnreadIndicators();
}
updateUnreadIndicators() {
- var container = $(React.findDOMNode(this.refs.container));
+ const container = $(React.findDOMNode(this.refs.container));
+
+ var showTopUnread = false;
+ var showBottomUnread = false;
if (this.firstUnreadChannel) {
var firstUnreadElement = $(React.findDOMNode(this.refs[this.firstUnreadChannel]));
if (firstUnreadElement.position().top + firstUnreadElement.height() < 0) {
- $(React.findDOMNode(this.refs.topUnreadIndicator)).css('display', 'initial');
- } else {
- $(React.findDOMNode(this.refs.topUnreadIndicator)).css('display', 'none');
+ showTopUnread = true;
}
}
@@ -290,11 +302,14 @@ export default class Sidebar extends React.Component {
var lastUnreadElement = $(React.findDOMNode(this.refs[this.lastUnreadChannel]));
if (lastUnreadElement.position().top > container.height()) {
- $(React.findDOMNode(this.refs.bottomUnreadIndicator)).css('display', 'initial');
- } else {
- $(React.findDOMNode(this.refs.bottomUnreadIndicator)).css('display', 'none');
+ showBottomUnread = true;
}
}
+
+ this.setState({
+ showTopUnread,
+ showBottomUnread
+ });
}
createChannelElement(channel, index) {
var members = this.state.members;
@@ -348,6 +363,11 @@ export default class Sidebar extends React.Component {
);
}
+ var badgeClass;
+ if (msgCount > 0) {
+ badgeClass = 'has-badge';
+ }
+
// set up status icon for direct message channels
var status = null;
if (channel.type === 'D') {
@@ -408,7 +428,7 @@ export default class Sidebar extends React.Component {
className={linkClass}
>
<a
- className={'sidebar-channel ' + titleClass}
+ className={'sidebar-channel ' + titleClass + ' ' + badgeClass}
href={href}
onClick={handleClick}
>
@@ -427,19 +447,13 @@ export default class Sidebar extends React.Component {
this.lastUnreadChannel = null;
// create elements for all 3 types of channels
- var channelItems = this.state.channels.filter(
- function filterPublicChannels(channel) {
- return channel.type === 'O';
- }
- ).map(this.createChannelElement);
+ const publicChannels = this.state.channels.filter((channel) => channel.type === 'O');
+ const publicChannelItems = publicChannels.map(this.createChannelElement);
- var privateChannelItems = this.state.channels.filter(
- function filterPrivateChannels(channel) {
- return channel.type === 'P';
- }
- ).map(this.createChannelElement);
+ const privateChannels = this.state.channels.filter((channel) => channel.type === 'P');
+ const privateChannelItems = privateChannels.map(this.createChannelElement);
- var directMessageItems = this.state.showDirectChannels.map(this.createChannelElement);
+ const directMessageItems = this.state.showDirectChannels.map(this.createChannelElement);
// update the favicon to show if there are any notifications
var link = document.createElement('link');
@@ -493,20 +507,16 @@ export default class Sidebar extends React.Component {
/>
<SearchBox />
- <div
- ref='topUnreadIndicator'
- className='nav-pills__unread-indicator nav-pills__unread-indicator-top'
- style={{display: 'none'}}
- >
- Unread post(s) above
- </div>
- <div
- ref='bottomUnreadIndicator'
- className='nav-pills__unread-indicator nav-pills__unread-indicator-bottom'
- style={{display: 'none'}}
- >
- Unread post(s) below
- </div>
+ <UnreadChannelIndicator
+ show={this.state.showTopUnread}
+ extraClass='nav-pills__unread-indicator-top'
+ text={'Unread post(s) above'}
+ />
+ <UnreadChannelIndicator
+ show={this.state.showBottomUnread}
+ extraClass='nav-pills__unread-indicator-bottom'
+ text={'Unread post(s) below'}
+ />
<div
ref='container'
@@ -526,7 +536,7 @@ export default class Sidebar extends React.Component {
</a>
</h4>
</li>
- {channelItems}
+ {publicChannelItems}
<li>
<a
href='#'
diff --git a/web/react/components/sidebar_header.jsx b/web/react/components/sidebar_header.jsx
index 0056d7a2f..959411f1e 100644
--- a/web/react/components/sidebar_header.jsx
+++ b/web/react/components/sidebar_header.jsx
@@ -3,7 +3,6 @@
var NavbarDropdown = require('./navbar_dropdown.jsx');
var UserStore = require('../stores/user_store.jsx');
-import {config} from '../utils/config.js';
export default class SidebarHeader extends React.Component {
constructor(props) {
@@ -59,7 +58,7 @@ export default class SidebarHeader extends React.Component {
}
SidebarHeader.defaultProps = {
- teamDisplayName: config.SiteName,
+ teamDisplayName: global.window.config.SiteName,
teamType: ''
};
SidebarHeader.propTypes = {
diff --git a/web/react/components/sidebar_right_menu.jsx b/web/react/components/sidebar_right_menu.jsx
index bd10a6ef1..5ecd502ba 100644
--- a/web/react/components/sidebar_right_menu.jsx
+++ b/web/react/components/sidebar_right_menu.jsx
@@ -4,7 +4,6 @@
var UserStore = require('../stores/user_store.jsx');
var client = require('../utils/client.jsx');
var utils = require('../utils/utils.jsx');
-import {config} from '../utils/config.js';
export default class SidebarRightMenu extends React.Component {
constructor(props) {
@@ -75,8 +74,8 @@ export default class SidebarRightMenu extends React.Component {
}
var siteName = '';
- if (config.SiteName != null) {
- siteName = config.SiteName;
+ if (global.window.config.SiteName != null) {
+ siteName = global.window.config.SiteName;
}
var teamDisplayName = siteName;
if (this.props.teamDisplayName) {
diff --git a/web/react/components/signup_team_complete.jsx b/web/react/components/signup_team_complete.jsx
index dc0d1d376..9c03c5c2f 100644
--- a/web/react/components/signup_team_complete.jsx
+++ b/web/react/components/signup_team_complete.jsx
@@ -4,7 +4,6 @@
var WelcomePage = require('./team_signup_welcome_page.jsx');
var TeamDisplayNamePage = require('./team_signup_display_name_page.jsx');
var TeamURLPage = require('./team_signup_url_page.jsx');
-var AllowedDomainsPage = require('./team_signup_allowed_domains_page.jsx');
var SendInivtesPage = require('./team_signup_send_invites_page.jsx');
var UsernamePage = require('./team_signup_username_page.jsx');
var PasswordPage = require('./team_signup_password_page.jsx');
@@ -70,15 +69,6 @@ export default class SignupTeamComplete extends React.Component {
);
}
- if (this.state.wizard === 'allowed_domains') {
- return (
- <AllowedDomainsPage
- state={this.state}
- updateParent={this.updateParent}
- />
- );
- }
-
if (this.state.wizard === 'send_invites') {
return (
<SendInivtesPage
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index 6e71eae32..19c3b2d22 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -6,7 +6,6 @@ var client = require('../utils/client.jsx');
var UserStore = require('../stores/user_store.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
var Constants = require('../utils/constants.jsx');
-import {config} from '../utils/config.js';
export default class SignupUserComplete extends React.Component {
constructor(props) {
@@ -136,7 +135,7 @@ export default class SignupUserComplete extends React.Component {
// set up the email entry and hide it if an email was provided
var yourEmailIs = '';
if (this.state.user.email) {
- yourEmailIs = <span>Your email address is {this.state.user.email}. You'll use this address to sign in to {config.SiteName}.</span>;
+ yourEmailIs = <span>Your email address is {this.state.user.email}. You'll use this address to sign in to {global.window.config.SiteName}.</span>;
}
var emailContainerStyle = 'margin--extra';
@@ -237,11 +236,6 @@ export default class SignupUserComplete extends React.Component {
);
}
- var termsDisclaimer = null;
- if (config.ShowTermsDuringSignup) {
- termsDisclaimer = <p>By creating an account and using Mattermost you are agreeing to our <a href={config.TermsLink}>Terms of Service</a>. If you do not agree, you cannot use this service.</p>;
- }
-
return (
<div>
<form>
@@ -251,12 +245,11 @@ export default class SignupUserComplete extends React.Component {
/>
<h5 className='margin--less'>Welcome to:</h5>
<h2 className='signup-team__name'>{this.props.teamDisplayName}</h2>
- <h2 className='signup-team__subdomain'>on {config.SiteName}</h2>
+ <h2 className='signup-team__subdomain'>on {global.window.config.SiteName}</h2>
<h4 className='color--light'>Let's create your account</h4>
{signupMessage}
{emailSignup}
{serverError}
- {termsDisclaimer}
</form>
</div>
);
diff --git a/web/react/components/team_general_tab.jsx b/web/react/components/team_general_tab.jsx
index 25139bb95..ca438df78 100644
--- a/web/react/components/team_general_tab.jsx
+++ b/web/react/components/team_general_tab.jsx
@@ -6,7 +6,6 @@ const SettingItemMax = require('./setting_item_max.jsx');
const Client = require('../utils/client.jsx');
const Utils = require('../utils/utils.jsx');
-import {strings} from '../utils/config.js';
export default class GeneralTab extends React.Component {
constructor(props) {
@@ -30,7 +29,7 @@ export default class GeneralTab extends React.Component {
state.clientError = 'This field is required';
valid = false;
} else if (name === this.props.teamDisplayName) {
- state.clientError = 'Please choose a new name for your ' + strings.Team;
+ state.clientError = 'Please choose a new name for your team';
valid = false;
} else {
state.clientError = '';
@@ -99,7 +98,7 @@ export default class GeneralTab extends React.Component {
if (this.props.activeSection === 'name') {
let inputs = [];
- let teamNameLabel = Utils.toTitleCase(strings.Team) + ' Name';
+ let teamNameLabel = 'Team Name';
if (Utils.isMobile()) {
teamNameLabel = '';
}
@@ -123,7 +122,7 @@ export default class GeneralTab extends React.Component {
nameSection = (
<SettingItemMax
- title={`${Utils.toTitleCase(strings.Team)} Name`}
+ title={`Team Name`}
inputs={inputs}
submit={this.handleNameSubmit}
server_error={serverError}
@@ -136,7 +135,7 @@ export default class GeneralTab extends React.Component {
nameSection = (
<SettingItemMin
- title={`${Utils.toTitleCase(strings.Team)} Name`}
+ title={`Team Name`}
describe={describe}
updateSection={this.onUpdateSection}
/>
diff --git a/web/react/components/team_signup_allowed_domains_page.jsx b/web/react/components/team_signup_allowed_domains_page.jsx
deleted file mode 100644
index 721fa142a..000000000
--- a/web/react/components/team_signup_allowed_domains_page.jsx
+++ /dev/null
@@ -1,143 +0,0 @@
-// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-var Client = require('../utils/client.jsx');
-import {strings} from '../utils/config.js';
-
-export default class TeamSignupAllowedDomainsPage 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 = 'team_url';
- this.props.updateParent(this.props.state);
- }
- submitNext(e) {
- e.preventDefault();
-
- if (React.findDOMNode(this.refs.open_network).checked) {
- this.props.state.wizard = 'send_invites';
- this.props.state.team.type = 'O';
- this.props.updateParent(this.props.state);
- return;
- }
-
- if (React.findDOMNode(this.refs.allow).checked) {
- var name = React.findDOMNode(this.refs.name).value.trim();
- var domainRegex = /^\w+\.\w+$/;
- if (!name) {
- this.setState({nameError: 'This field is required'});
- return;
- }
-
- if (!name.trim().match(domainRegex)) {
- this.setState({nameError: 'The domain doesn\'t appear valid'});
- return;
- }
-
- this.props.state.wizard = 'send_invites';
- this.props.state.team.allowed_domains = name;
- this.props.state.team.type = 'I';
- this.props.updateParent(this.props.state);
- } else {
- this.props.state.wizard = 'send_invites';
- this.props.state.team.type = 'I';
- this.props.updateParent(this.props.state);
- }
- }
- render() {
- Client.track('signup', 'signup_team_04_allow_domains');
-
- 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='/static/images/logo.png'
- />
- <h2>Email Domain</h2>
- <p>
- <div className='checkbox'>
- <label>
- <input
- type='checkbox'
- ref='allow'
- defaultChecked={true}
- />
- {' Allow sign up and ' + strings.Team + ' discovery with a ' + strings.Company + ' email address.'}
- </label>
- </div>
- </p>
- <p>{'Check this box to allow your ' + strings.Team + ' members to sign up using their ' + strings.Company + ' email addresses if you share the same domain--otherwise, you need to invite everyone yourself.'}</p>
- <h4>{'Your ' + strings.Team + '\'s domain for emails'}</h4>
- <div className={nameDivClass}>
- <div className='row'>
- <div className='col-sm-9'>
- <div className='input-group'>
- <span className='input-group-addon'>@</span>
- <input
- type='text'
- ref='name'
- className='form-control'
- placeholder=''
- maxLength='128'
- defaultValue={this.props.state.team.allowed_domains}
- autoFocus={true}
- onFocus={this.handleFocus}
- />
- </div>
- </div>
- </div>
- {nameError}
- </div>
- <p>To allow signups from multiple domains, separate each with a comma.</p>
- <p>
- <div className='checkbox'>
- <label>
- <input
- type='checkbox'
- ref='open_network'
- defaultChecked={this.props.state.team.type === 'O'}
- /> Allow anyone to signup to this domain without an invitation.</label>
- </div>
- </p>
- <button
- type='button'
- className='btn btn-default'
- onClick={this.submitBack}
- >
- <i className='glyphicon glyphicon-chevron-left'></i> Back
- </button>&nbsp;
- <button
- type='submit'
- className='btn-primary btn'
- onClick={this.submitNext}
- >
- Next<i className='glyphicon glyphicon-chevron-right'></i>
- </button>
- </form>
- </div>
- );
- }
-}
-
-TeamSignupAllowedDomainsPage.defaultProps = {
- state: {}
-};
-TeamSignupAllowedDomainsPage.propTypes = {
- state: React.PropTypes.object,
- updateParent: React.PropTypes.func
-};
diff --git a/web/react/components/team_signup_choose_auth.jsx b/web/react/components/team_signup_choose_auth.jsx
index acce6ab49..d3107c5c7 100644
--- a/web/react/components/team_signup_choose_auth.jsx
+++ b/web/react/components/team_signup_choose_auth.jsx
@@ -2,7 +2,6 @@
// See License.txt for license information.
var Constants = require('../utils/constants.jsx');
-import {strings} from '../utils/config.js';
export default class ChooseAuthPage extends React.Component {
constructor(props) {
@@ -24,7 +23,7 @@ export default class ChooseAuthPage extends React.Component {
}
>
<span className='icon' />
- <span>Create new {strings.Team} with GitLab Account</span>
+ <span>Create new team with GitLab Account</span>
</a>
);
}
@@ -42,7 +41,7 @@ export default class ChooseAuthPage extends React.Component {
}
>
<span className='fa fa-envelope' />
- <span>Create new {strings.Team} with email address</span>
+ <span>Create new team with email address</span>
</a>
);
}
@@ -55,7 +54,7 @@ export default class ChooseAuthPage extends React.Component {
<div>
{buttons}
<div className='form-group margin--extra-2x'>
- <span><a href='/find_team'>{'Find my ' + strings.Team}</a></span>
+ <span><a href='/find_team'>{'Find my team'}</a></span>
</div>
</div>
);
diff --git a/web/react/components/team_signup_display_name_page.jsx b/web/react/components/team_signup_display_name_page.jsx
index 1849f8222..c0d0ed366 100644
--- a/web/react/components/team_signup_display_name_page.jsx
+++ b/web/react/components/team_signup_display_name_page.jsx
@@ -3,7 +3,6 @@
var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx');
-import {strings} from '../utils/config.js';
export default class TeamSignupDisplayNamePage extends React.Component {
constructor(props) {
@@ -54,7 +53,7 @@ export default class TeamSignupDisplayNamePage extends React.Component {
className='signup-team-logo'
src='/static/images/logo.png'
/>
- <h2>{utils.toTitleCase(strings.Team) + ' Name'}</h2>
+ <h2>{'Team Name'}</h2>
<div className={nameDivClass}>
<div className='row'>
<div className='col-sm-9'>
@@ -73,7 +72,7 @@ export default class TeamSignupDisplayNamePage extends React.Component {
{nameError}
</div>
<div>
- {'Name your ' + strings.Team + ' in any language. Your ' + strings.Team + ' name shows in menus and headings.'}
+ {'Name your team in any language. Your team name shows in menus and headings.'}
</div>
<button
type='submit'
diff --git a/web/react/components/team_signup_password_page.jsx b/web/react/components/team_signup_password_page.jsx
index aa402846b..b26d9f6ce 100644
--- a/web/react/components/team_signup_password_page.jsx
+++ b/web/react/components/team_signup_password_page.jsx
@@ -4,7 +4,6 @@
var Client = require('../utils/client.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
var UserStore = require('../stores/user_store.jsx');
-import {strings, config} from '../utils/config.js';
export default class TeamSignupPasswordPage extends React.Component {
constructor(props) {
@@ -123,13 +122,13 @@ export default class TeamSignupPasswordPage extends React.Component {
type='submit'
className='btn btn-primary margin--extra'
id='finish-button'
- data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Creating ' + strings.Team + '...'}
+ data-loading-text={'<span class=\'glyphicon glyphicon-refresh glyphicon-refresh-animate\'></span> Creating team...'}
onClick={this.submitNext}
>
Finish
</button>
</div>
- <p>By proceeding to create your account and use {config.SiteName}, you agree to our <a href={config.TermsLink}>Terms of Service</a> and <a href={config.PrivacyLink}>Privacy Policy</a>. If you do not agree, you cannot use {config.SiteName}.</p>
+ <p>By proceeding to create your account and use {global.window.config.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 {global.window.config.SiteName}.</p>
<div className='margin--extra'>
<a
href='#'
diff --git a/web/react/components/team_signup_send_invites_page.jsx b/web/react/components/team_signup_send_invites_page.jsx
index 11a9980d7..41ac98303 100644
--- a/web/react/components/team_signup_send_invites_page.jsx
+++ b/web/react/components/team_signup_send_invites_page.jsx
@@ -2,10 +2,7 @@
// See License.txt for license information.
var EmailItem = require('./team_signup_email_item.jsx');
-var Utils = require('../utils/utils.jsx');
-var ConfigStore = require('../stores/config_store.jsx');
var Client = require('../utils/client.jsx');
-import {strings, config} from '../utils/config.js';
export default class TeamSignupSendInvitesPage extends React.Component {
constructor(props) {
@@ -16,7 +13,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
this.submitSkip = this.submitSkip.bind(this);
this.keySubmit = this.keySubmit.bind(this);
this.state = {
- emailEnabled: !ConfigStore.getSettingAsBoolean('ByPassEmail', false)
+ emailEnabled: !global.window.config.ByPassEmail
};
if (!this.state.emailEnabled) {
@@ -26,12 +23,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
}
submitBack(e) {
e.preventDefault();
-
- if (config.AllowSignupDomainsWizard) {
- this.props.state.wizard = 'allowed_domains';
- } else {
- this.props.state.wizard = 'team_url';
- }
+ this.props.state.wizard = 'team_url';
this.props.updateParent(this.props.state);
}
@@ -138,7 +130,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
bottomContent = (
<p className='color--light'>
- {'if you prefer, you can invite ' + strings.Team + ' members later'}
+ {'if you prefer, you can invite team members later'}
<br />
{' and '}
<a
@@ -153,7 +145,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
} else {
content = (
<div className='form-group color--light'>
- {'Email is currently disabled for your ' + strings.Team + ', and emails cannot be sent. Contact your system administrator to enable email and email invitations.'}
+ {'Email is currently disabled for your team, and emails cannot be sent. Contact your system administrator to enable email and email invitations.'}
</div>
);
}
@@ -165,7 +157,7 @@ export default class TeamSignupSendInvitesPage extends React.Component {
className='signup-team-logo'
src='/static/images/logo.png'
/>
- <h2>{'Invite ' + Utils.toTitleCase(strings.Team) + ' Members'}</h2>
+ <h2>{'Invite Team Members'}</h2>
{content}
<div className='form-group'>
<button
diff --git a/web/react/components/team_signup_url_page.jsx b/web/react/components/team_signup_url_page.jsx
index ffe9d9fe8..1b722d611 100644
--- a/web/react/components/team_signup_url_page.jsx
+++ b/web/react/components/team_signup_url_page.jsx
@@ -4,7 +4,6 @@
const Utils = require('../utils/utils.jsx');
const Client = require('../utils/client.jsx');
const Constants = require('../utils/constants.jsx');
-import {strings, config} from '../utils/config.js';
export default class TeamSignupUrlPage extends React.Component {
constructor(props) {
@@ -51,12 +50,8 @@ export default class TeamSignupUrlPage extends React.Component {
Client.findTeamByName(name,
function success(data) {
if (!data) {
- if (config.AllowSignupDomainsWizard) {
- this.props.state.wizard = 'allowed_domains';
- } else {
- this.props.state.wizard = 'send_invites';
- this.props.state.team.type = 'O';
- }
+ this.props.state.wizard = 'send_invites';
+ this.props.state.team.type = 'O';
this.props.state.team.name = name;
this.props.updateParent(this.props.state);
@@ -97,7 +92,7 @@ export default class TeamSignupUrlPage extends React.Component {
className='signup-team-logo'
src='/static/images/logo.png'
/>
- <h2>{`${Utils.toTitleCase(strings.Team)} URL`}</h2>
+ <h2>{`Team URL`}</h2>
<div className={nameDivClass}>
<div className='row'>
<div className='col-sm-11'>
@@ -124,7 +119,7 @@ export default class TeamSignupUrlPage extends React.Component {
</div>
{nameError}
</div>
- <p>{`Choose the web address of your new ${strings.Team}:`}</p>
+ <p>{`Choose the web address of your new team:`}</p>
<ul className='color--light'>
<li>Short and memorable is best</li>
<li>Use lowercase letters, numbers and dashes</li>
diff --git a/web/react/components/team_signup_username_page.jsx b/web/react/components/team_signup_username_page.jsx
index 984c7afab..0053b011d 100644
--- a/web/react/components/team_signup_username_page.jsx
+++ b/web/react/components/team_signup_username_page.jsx
@@ -3,7 +3,6 @@
var Utils = require('../utils/utils.jsx');
var Client = require('../utils/client.jsx');
-import {strings} from '../utils/config.js';
export default class TeamSignupUsernamePage extends React.Component {
constructor(props) {
@@ -55,7 +54,7 @@ export default class TeamSignupUsernamePage extends React.Component {
src='/static/images/logo.png'
/>
<h2 className='margin--less'>Your username</h2>
- <h5 className='color--light'>{'Select a memorable username that makes it easy for ' + strings.Team + 'mates to identify you:'}</h5>
+ <h5 className='color--light'>{'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'>
diff --git a/web/react/components/team_signup_welcome_page.jsx b/web/react/components/team_signup_welcome_page.jsx
index 43b7aea0e..626c6a17b 100644
--- a/web/react/components/team_signup_welcome_page.jsx
+++ b/web/react/components/team_signup_welcome_page.jsx
@@ -4,7 +4,6 @@
var Utils = require('../utils/utils.jsx');
var Client = require('../utils/client.jsx');
var BrowserStore = require('../stores/browser_store.jsx');
-import {config} from '../utils/config.js';
export default class TeamSignupWelcomePage extends React.Component {
constructor(props) {
@@ -112,7 +111,7 @@ export default class TeamSignupWelcomePage extends React.Component {
src='/static/images/logo.png'
/>
<h3 className='sub-heading'>Welcome to:</h3>
- <h1 className='margin--top-none'>{config.SiteName}</h1>
+ <h1 className='margin--top-none'>{global.window.config.SiteName}</h1>
</p>
<p className='margin--less'>Let's set up your new team</p>
<p>
diff --git a/web/react/components/team_signup_with_email.jsx b/web/react/components/team_signup_with_email.jsx
index d75736bd3..4fb1c0d01 100644
--- a/web/react/components/team_signup_with_email.jsx
+++ b/web/react/components/team_signup_with_email.jsx
@@ -3,7 +3,6 @@
const Utils = require('../utils/utils.jsx');
const Client = require('../utils/client.jsx');
-import {strings} from '../utils/config.js';
export default class EmailSignUpPage extends React.Component {
constructor() {
@@ -70,7 +69,7 @@ export default class EmailSignUpPage extends React.Component {
</button>
</div>
<div className='form-group margin--extra-2x'>
- <span><a href='/find_team'>{`Find my ${strings.Team}`}</a></span>
+ <span><a href='/find_team'>{`Find my team`}</a></span>
</div>
</form>
);
diff --git a/web/react/components/team_signup_with_sso.jsx b/web/react/components/team_signup_with_sso.jsx
index 521c21733..2849b4cbb 100644
--- a/web/react/components/team_signup_with_sso.jsx
+++ b/web/react/components/team_signup_with_sso.jsx
@@ -4,7 +4,6 @@
var utils = require('../utils/utils.jsx');
var client = require('../utils/client.jsx');
var Constants = require('../utils/constants.jsx');
-import {strings} from '../utils/config.js';
export default class SSOSignUpPage extends React.Component {
constructor(props) {
@@ -84,7 +83,7 @@ export default class SSOSignUpPage extends React.Component {
disabled={disabled}
>
<span className='icon'/>
- <span>Create {strings.Team} with GitLab Account</span>
+ <span>Create team with GitLab Account</span>
</a>
);
}
@@ -111,7 +110,7 @@ export default class SSOSignUpPage extends React.Component {
{serverError}
</div>
<div className='form-group margin--extra-2x'>
- <span><a href='/find_team'>{'Find my ' + strings.Team}</a></span>
+ <span><a href='/find_team'>{'Find my team'}</a></span>
</div>
</form>
);
diff --git a/web/react/components/unread_channel_indicator.jsx b/web/react/components/unread_channel_indicator.jsx
new file mode 100644
index 000000000..12a67633e
--- /dev/null
+++ b/web/react/components/unread_channel_indicator.jsx
@@ -0,0 +1,35 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+// Indicator for the left sidebar which indicate if there's unread posts in a channel that is not shown
+// because it is either above or below the screen
+export default class UnreadChannelIndicator extends React.Component {
+ constructor(props) {
+ super(props);
+ }
+ render() {
+ let displayValue = 'none';
+ if (this.props.show) {
+ displayValue = 'initial';
+ }
+ return (
+ <div
+ className={'nav-pills__unread-indicator ' + this.props.extraClass}
+ style={{display: displayValue}}
+ >
+ {this.props.text}
+ </div>
+ );
+ }
+}
+
+UnreadChannelIndicator.defaultProps = {
+ show: false,
+ extraClass: '',
+ text: ''
+};
+UnreadChannelIndicator.propTypes = {
+ show: React.PropTypes.bool,
+ extraClass: React.PropTypes.string,
+ text: React.PropTypes.string
+};
diff --git a/web/react/components/user_profile.jsx b/web/react/components/user_profile.jsx
index 739084053..7cfac69e7 100644
--- a/web/react/components/user_profile.jsx
+++ b/web/react/components/user_profile.jsx
@@ -3,7 +3,6 @@
var Utils = require('../utils/utils.jsx');
var UserStore = require('../stores/user_store.jsx');
-import {config} from '../utils/config.js';
var id = 0;
@@ -58,7 +57,7 @@ export default class UserProfile extends React.Component {
}
var dataContent = '<img class="user-popover__image" src="/api/v1/users/' + this.state.profile.id + '/image?time=' + this.state.profile.update_at + '" height="128" width="128" />';
- if (!config.ShowEmail) {
+ if (!global.window.config.ShowEmailAddress) {
dataContent += '<div class="text-nowrap">Email not shared</div>';
} else {
dataContent += '<div data-toggle="tooltip" title="' + this.state.profile.email + '"><a href="mailto:' + this.state.profile.email + '" class="text-nowrap text-lowercase user-popover__email">' + this.state.profile.email + '</a></div>';
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index 2a607b3e0..48b499068 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -7,6 +7,7 @@ var NotificationsTab = require('./user_settings_notifications.jsx');
var SecurityTab = require('./user_settings_security.jsx');
var GeneralTab = require('./user_settings_general.jsx');
var AppearanceTab = require('./user_settings_appearance.jsx');
+var DeveloperTab = require('./user_settings_developer.jsx');
export default class UserSettings extends React.Component {
constructor(props) {
@@ -76,6 +77,15 @@ export default class UserSettings extends React.Component {
/>
</div>
);
+ } else if (this.props.activeTab === 'developer') {
+ return (
+ <div>
+ <DeveloperTab
+ activeSection={this.props.activeSection}
+ updateSection={this.props.updateSection}
+ />
+ </div>
+ );
}
return <div/>;
diff --git a/web/react/components/user_settings_appearance.jsx b/web/react/components/user_settings_appearance.jsx
index 3afdd7349..3df013d03 100644
--- a/web/react/components/user_settings_appearance.jsx
+++ b/web/react/components/user_settings_appearance.jsx
@@ -6,7 +6,8 @@ var SettingItemMin = require('./setting_item_min.jsx');
var SettingItemMax = require('./setting_item_max.jsx');
var Client = require('../utils/client.jsx');
var Utils = require('../utils/utils.jsx');
-import {config} from '../utils/config.js';
+
+var ThemeColors = ['#2389d7', '#008a17', '#dc4fad', '#ac193d', '#0072c6', '#d24726', '#ff8f32', '#82ba00', '#03b3b2', '#008299', '#4617b4', '#8c0095', '#004b8b', '#004b8b', '#570000', '#380000', '#585858', '#000000'];
export default class UserSettingsAppearance extends React.Component {
constructor(props) {
@@ -21,8 +22,8 @@ export default class UserSettingsAppearance extends React.Component {
getStateFromStores() {
var user = UserStore.getCurrentUser();
var theme = '#2389d7';
- if (config.ThemeColors != null) {
- theme = config.ThemeColors[0];
+ if (ThemeColors != null) {
+ theme = ThemeColors[0];
}
if (user.props && user.props.theme) {
theme = user.props.theme;
@@ -83,18 +84,18 @@ export default class UserSettingsAppearance extends React.Component {
var themeSection;
var self = this;
- if (config.ThemeColors != null) {
+ if (ThemeColors != null) {
if (this.props.activeSection === 'theme') {
var themeButtons = [];
- for (var i = 0; i < config.ThemeColors.length; i++) {
+ for (var i = 0; i < ThemeColors.length; i++) {
themeButtons.push(
<button
- key={config.ThemeColors[i] + 'key' + i}
- ref={config.ThemeColors[i]}
+ key={ThemeColors[i] + 'key' + i}
+ ref={ThemeColors[i]}
type='button'
className='btn btn-lg color-btn'
- style={{backgroundColor: config.ThemeColors[i]}}
+ style={{backgroundColor: ThemeColors[i]}}
onClick={this.updateTheme}
/>
);
diff --git a/web/react/components/user_settings_developer.jsx b/web/react/components/user_settings_developer.jsx
new file mode 100644
index 000000000..1b04149dc
--- /dev/null
+++ b/web/react/components/user_settings_developer.jsx
@@ -0,0 +1,93 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var SettingItemMin = require('./setting_item_min.jsx');
+var SettingItemMax = require('./setting_item_max.jsx');
+
+export default class DeveloperTab extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {};
+ }
+ register() {
+ $('#user_settings1').modal('hide');
+ $('#register_app').modal('show');
+ }
+ render() {
+ var appSection;
+ var self = this;
+ if (this.props.activeSection === 'app') {
+ var inputs = [];
+
+ inputs.push(
+ <div className='form-group'>
+ <div className='col-sm-7'>
+ <a
+ className='btn btn-sm btn-primary'
+ onClick={this.register}
+ >
+ {'Register New Application'}
+ </a>
+ </div>
+ </div>
+ );
+
+ appSection = (
+ <SettingItemMax
+ title='Applications (Preview)'
+ inputs={inputs}
+ updateSection={function updateSection(e) {
+ self.props.updateSection('');
+ e.preventDefault();
+ }}
+ />
+ );
+ } else {
+ appSection = (
+ <SettingItemMin
+ title='Applications (Preview)'
+ describe='Open to register a new third-party application'
+ updateSection={function updateSection() {
+ self.props.updateSection('app');
+ }}
+ />
+ );
+ }
+
+ return (
+ <div>
+ <div className='modal-header'>
+ <button
+ type='button'
+ className='close'
+ data-dismiss='modal'
+ aria-label='Close'
+ >
+ <span aria-hidden='true'>{'x'}</span>
+ </button>
+ <h4
+ className='modal-title'
+ ref='title'
+ >
+ <i className='modal-back'></i>{'Developer Settings'}
+ </h4>
+ </div>
+ <div className='user-settings'>
+ <h3 className='tab-header'>{'Developer Settings'}</h3>
+ <div className='divider-dark first'/>
+ {appSection}
+ <div className='divider-dark'/>
+ </div>
+ </div>
+ );
+ }
+}
+
+DeveloperTab.defaultProps = {
+ activeSection: ''
+};
+DeveloperTab.propTypes = {
+ activeSection: React.PropTypes.string,
+ updateSection: React.PropTypes.func
+};
diff --git a/web/react/components/user_settings_general.jsx b/web/react/components/user_settings_general.jsx
index dd0abc8a5..66cde6ca2 100644
--- a/web/react/components/user_settings_general.jsx
+++ b/web/react/components/user_settings_general.jsx
@@ -2,7 +2,6 @@
// See License.txt for license information.
var UserStore = require('../stores/user_store.jsx');
-var ConfigStore = require('../stores/config_store.jsx');
var SettingItemMin = require('./setting_item_min.jsx');
var SettingItemMax = require('./setting_item_max.jsx');
var SettingPicture = require('./setting_picture.jsx');
@@ -209,7 +208,7 @@ export default class UserSettingsGeneralTab extends React.Component {
}
setupInitialState(props) {
var user = props.user;
- var emailEnabled = !ConfigStore.getSettingAsBoolean('ByPassEmail', false);
+ var emailEnabled = !global.window.config.ByPassEmail;
return {username: user.username, firstName: user.first_name, lastName: user.last_name, nickname: user.nickname,
email: user.email, picture: null, loadingPicture: false, emailEnabled: emailEnabled};
}
diff --git a/web/react/components/user_settings_modal.jsx b/web/react/components/user_settings_modal.jsx
index 7ec75e000..67a4d0041 100644
--- a/web/react/components/user_settings_modal.jsx
+++ b/web/react/components/user_settings_modal.jsx
@@ -17,8 +17,8 @@ export default class UserSettingsModal extends React.Component {
$('body').on('click', '.modal-back', function changeDisplay() {
$(this).closest('.modal-dialog').removeClass('display--content');
});
- $('body').on('click', '.modal-header .close', function closeModal() {
- setTimeout(function finishClose() {
+ $('body').on('click', '.modal-header .close', () => {
+ setTimeout(() => {
$('.modal-dialog.display--content').removeClass('display--content');
}, 500);
});
@@ -35,6 +35,9 @@ export default class UserSettingsModal extends React.Component {
tabs.push({name: 'security', uiName: 'Security', icon: 'glyphicon glyphicon-lock'});
tabs.push({name: 'notifications', uiName: 'Notifications', icon: 'glyphicon glyphicon-exclamation-sign'});
tabs.push({name: 'appearance', uiName: 'Appearance', icon: 'glyphicon glyphicon-wrench'});
+ if (global.window.config.EnableOAuthServiceProvider === 'true') {
+ tabs.push({name: 'developer', uiName: 'Developer', icon: 'glyphicon glyphicon-th'});
+ }
return (
<div
@@ -54,13 +57,13 @@ export default class UserSettingsModal extends React.Component {
data-dismiss='modal'
aria-label='Close'
>
- <span aria-hidden='true'>&times;</span>
+ <span aria-hidden='true'>{'x'}</span>
</button>
<h4
className='modal-title'
ref='title'
>
- Account Settings
+ {'Account Settings'}
</h4>
</div>
<div className='modal-body'>
diff --git a/web/react/components/user_settings_notifications.jsx b/web/react/components/user_settings_notifications.jsx
index 33db1a332..dadbb669b 100644
--- a/web/react/components/user_settings_notifications.jsx
+++ b/web/react/components/user_settings_notifications.jsx
@@ -8,7 +8,6 @@ var client = require('../utils/client.jsx');
var AsyncClient = require('../utils/async_client.jsx');
var utils = require('../utils/utils.jsx');
var assign = require('object-assign');
-import {config} from '../utils/config.js';
function getNotificationsStateFromStores() {
var user = UserStore.getCurrentUser();
@@ -415,7 +414,7 @@ export default class NotificationsTab extends React.Component {
</label>
<br/>
</div>
- <div><br/>{'Email notifications are sent for mentions and private messages after you have been away from ' + config.SiteName + ' for 5 minutes.'}</div>
+ <div><br/>{'Email notifications are sent for mentions and private messages after you have been away from ' + global.window.config.SiteName + ' for 5 minutes.'}</div>
</div>
);
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index 8d3495e3b..f7c980396 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -3,7 +3,6 @@
var Client = require('../utils/client.jsx');
var Utils = require('../utils/utils.jsx');
-import {config} from '../utils/config.js';
export default class ViewImageModal extends React.Component {
constructor(props) {
@@ -301,7 +300,7 @@ export default class ViewImageModal extends React.Component {
}
var publicLink = '';
- if (config.AllowPublicLink) {
+ if (global.window.config.AllowPublicLink) {
publicLink = (
<div>
<a
diff --git a/web/react/package.json b/web/react/package.json
index 11d60376d..04e0f6bab 100644
--- a/web/react/package.json
+++ b/web/react/package.json
@@ -8,7 +8,8 @@
"keymirror": "0.1.1",
"object-assign": "3.0.0",
"react-zeroclipboard-mixin": "0.1.0",
- "twemoji": "1.4.1"
+ "twemoji": "1.4.1",
+ "babel-runtime": "5.8.24"
},
"devDependencies": {
"browserify": "11.0.1",
@@ -26,8 +27,8 @@
},
"browserify": {
"transform": [
- "babelify",
- "envify"
+ ["babelify", { "optional": ["runtime"] }],
+ "envify"
]
},
"jest": {
diff --git a/web/react/pages/authorize.jsx b/web/react/pages/authorize.jsx
new file mode 100644
index 000000000..db42c8266
--- /dev/null
+++ b/web/react/pages/authorize.jsx
@@ -0,0 +1,21 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var Authorize = require('../components/authorize.jsx');
+
+function setupAuthorizePage(teamName, appName, responseType, clientId, redirectUri, scope, state) {
+ React.render(
+ <Authorize
+ teamName={teamName}
+ appName={appName}
+ responseType={responseType}
+ clientId={clientId}
+ redirectUri={redirectUri}
+ scope={scope}
+ state={state}
+ />,
+ document.getElementById('authorize')
+ );
+}
+
+global.window.setup_authorize_page = setupAuthorizePage;
diff --git a/web/react/pages/channel.jsx b/web/react/pages/channel.jsx
index e70b51865..43493de45 100644
--- a/web/react/pages/channel.jsx
+++ b/web/react/pages/channel.jsx
@@ -33,24 +33,21 @@ var AccessHistoryModal = require('../components/access_history_modal.jsx');
var ActivityLogModal = require('../components/activity_log_modal.jsx');
var RemovedFromChannelModal = require('../components/removed_from_channel_modal.jsx');
var FileUploadOverlay = require('../components/file_upload_overlay.jsx');
-
-var AsyncClient = require('../utils/async_client.jsx');
+var RegisterAppModal = require('../components/register_app_modal.jsx');
var Constants = require('../utils/constants.jsx');
var ActionTypes = Constants.ActionTypes;
-function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
- AsyncClient.getConfig();
-
+function setupChannelPage(props) {
AppDispatcher.handleViewAction({
type: ActionTypes.CLICK_CHANNEL,
- name: channelName,
- id: channelId
+ name: props.ChannelName,
+ id: props.ChannelId
});
AppDispatcher.handleViewAction({
type: ActionTypes.CLICK_TEAM,
- id: teamId
+ id: props.TeamId
});
// ChannelLoader must be rendered first
@@ -65,14 +62,14 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
);
React.render(
- <Navbar teamDisplayName={teamName} />,
+ <Navbar teamDisplayName={props.TeamDisplayName} />,
document.getElementById('navbar')
);
React.render(
<Sidebar
- teamDisplayName={teamName}
- teamType={teamType}
+ teamDisplayName={props.TeamDisplayName}
+ teamType={props.TeamType}
/>,
document.getElementById('sidebar-left')
);
@@ -88,17 +85,17 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
);
React.render(
- <TeamSettingsModal teamDisplayName={teamName} />,
+ <TeamSettingsModal teamDisplayName={props.TeamDisplayName} />,
document.getElementById('team_settings_modal')
);
React.render(
- <TeamMembersModal teamDisplayName={teamName} />,
+ <TeamMembersModal teamDisplayName={props.TeamDisplayName} />,
document.getElementById('team_members_modal')
);
React.render(
- <MemberInviteModal teamType={teamType} />,
+ <MemberInviteModal teamType={props.TeamType} />,
document.getElementById('invite_member_modal')
);
@@ -184,8 +181,8 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
React.render(
<SidebarRightMenu
- teamDisplayName={teamName}
- teamType={teamType}
+ teamDisplayName={props.TeamDisplayName}
+ teamType={props.TeamType}
/>,
document.getElementById('sidebar-menu')
);
@@ -226,6 +223,11 @@ function setupChannelPage(teamName, teamType, teamId, channelName, channelId) {
/>,
document.getElementById('file_upload_overlay')
);
+
+ React.render(
+ <RegisterAppModal />,
+ document.getElementById('register_app_modal')
+ );
}
global.window.setup_channel_page = setupChannelPage;
diff --git a/web/react/pages/home.jsx b/web/react/pages/home.jsx
index 18553542c..2299c306e 100644
--- a/web/react/pages/home.jsx
+++ b/web/react/pages/home.jsx
@@ -4,12 +4,12 @@
var ChannelStore = require('../stores/channel_store.jsx');
var Constants = require('../utils/constants.jsx');
-function setupHomePage(teamURL) {
+function setupHomePage(props) {
var last = ChannelStore.getLastVisitedName();
if (last == null || last.length === 0) {
- window.location = teamURL + '/channels/' + Constants.DEFAULT_CHANNEL;
+ window.location = props.TeamURL + '/channels/' + Constants.DEFAULT_CHANNEL;
} else {
- window.location = teamURL + '/channels/' + last;
+ window.location = props.TeamURL + '/channels/' + last;
}
}
diff --git a/web/react/pages/login.jsx b/web/react/pages/login.jsx
index 424ae0e84..830f622fa 100644
--- a/web/react/pages/login.jsx
+++ b/web/react/pages/login.jsx
@@ -3,12 +3,12 @@
var Login = require('../components/login.jsx');
-function setupLoginPage(teamDisplayName, teamName, authServices) {
+function setupLoginPage(props) {
React.render(
<Login
- teamDisplayName={teamDisplayName}
- teamName={teamName}
- authServices={authServices}
+ teamDisplayName={props.TeamDisplayName}
+ teamName={props.TeamName}
+ authServices={props.AuthServices}
/>,
document.getElementById('login')
);
diff --git a/web/react/pages/password_reset.jsx b/web/react/pages/password_reset.jsx
index 2ca468bea..b7bfdcd5e 100644
--- a/web/react/pages/password_reset.jsx
+++ b/web/react/pages/password_reset.jsx
@@ -3,14 +3,14 @@
var PasswordReset = require('../components/password_reset.jsx');
-function setupPasswordResetPage(isReset, teamDisplayName, teamName, hash, data) {
+function setupPasswordResetPage(props) {
React.render(
<PasswordReset
- isReset={isReset}
- teamDisplayName={teamDisplayName}
- teamName={teamName}
- hash={hash}
- data={data}
+ isReset={props.IsReset}
+ teamDisplayName={props.TeamDisplayName}
+ teamName={props.TeamName}
+ hash={props.Hash}
+ data={props.Data}
/>,
document.getElementById('reset')
);
diff --git a/web/react/pages/signup_team.jsx b/web/react/pages/signup_team.jsx
index e9e803aa4..427daf577 100644
--- a/web/react/pages/signup_team.jsx
+++ b/web/react/pages/signup_team.jsx
@@ -3,12 +3,8 @@
var SignupTeam = require('../components/signup_team.jsx');
-var AsyncClient = require('../utils/async_client.jsx');
-
-function setupSignupTeamPage(authServices) {
- AsyncClient.getConfig();
-
- var services = JSON.parse(authServices);
+function setupSignupTeamPage(props) {
+ var services = JSON.parse(props.AuthServices);
React.render(
<SignupTeam services={services} />,
diff --git a/web/react/pages/signup_team_complete.jsx b/web/react/pages/signup_team_complete.jsx
index 72f9992a8..ec77e6602 100644
--- a/web/react/pages/signup_team_complete.jsx
+++ b/web/react/pages/signup_team_complete.jsx
@@ -3,12 +3,12 @@
var SignupTeamComplete = require('../components/signup_team_complete.jsx');
-function setupSignupTeamCompletePage(email, data, hash) {
+function setupSignupTeamCompletePage(props) {
React.render(
<SignupTeamComplete
- email={email}
- hash={hash}
- data={data}
+ email={props.Email}
+ hash={props.Hash}
+ data={props.Data}
/>,
document.getElementById('signup-team-complete')
);
diff --git a/web/react/pages/signup_user_complete.jsx b/web/react/pages/signup_user_complete.jsx
index eaf93a61c..112aaa3f2 100644
--- a/web/react/pages/signup_user_complete.jsx
+++ b/web/react/pages/signup_user_complete.jsx
@@ -3,16 +3,16 @@
var SignupUserComplete = require('../components/signup_user_complete.jsx');
-function setupSignupUserCompletePage(email, name, uiName, id, data, hash, authServices) {
+function setupSignupUserCompletePage(props) {
React.render(
<SignupUserComplete
- teamId={id}
- teamName={name}
- teamDisplayName={uiName}
- email={email}
- hash={hash}
- data={data}
- authServices={authServices}
+ teamId={props.TeamId}
+ teamName={props.TeamName}
+ teamDisplayName={props.TeamDisplayName}
+ email={props.Email}
+ hash={props.Hash}
+ data={props.Data}
+ authServices={props.AuthServices}
/>,
document.getElementById('signup-user-complete')
);
diff --git a/web/react/pages/verify.jsx b/web/react/pages/verify.jsx
index 7077b40b8..e48471bbd 100644
--- a/web/react/pages/verify.jsx
+++ b/web/react/pages/verify.jsx
@@ -3,12 +3,12 @@
var EmailVerify = require('../components/email_verify.jsx');
-global.window.setupVerifyPage = function setupVerifyPage(isVerified, teamURL, userEmail) {
+global.window.setupVerifyPage = function setupVerifyPage(props) {
React.render(
<EmailVerify
- isVerified={isVerified}
- teamURL={teamURL}
- userEmail={userEmail}
+ isVerified={props.IsVerified}
+ teamURL={props.TeamURL}
+ userEmail={props.UserEmail}
/>,
document.getElementById('verify')
);
diff --git a/web/react/stores/admin_store.jsx b/web/react/stores/admin_store.jsx
new file mode 100644
index 000000000..591b52d05
--- /dev/null
+++ b/web/react/stores/admin_store.jsx
@@ -0,0 +1,58 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
+var EventEmitter = require('events').EventEmitter;
+
+var Constants = require('../utils/constants.jsx');
+var ActionTypes = Constants.ActionTypes;
+
+var LOG_CHANGE_EVENT = 'log_change';
+
+class AdminStoreClass extends EventEmitter {
+ constructor() {
+ super();
+
+ this.logs = null;
+
+ this.emitLogChange = this.emitLogChange.bind(this);
+ this.addLogChangeListener = this.addLogChangeListener.bind(this);
+ this.removeLogChangeListener = this.removeLogChangeListener.bind(this);
+ }
+
+ emitLogChange() {
+ this.emit(LOG_CHANGE_EVENT);
+ }
+
+ addLogChangeListener(callback) {
+ this.on(LOG_CHANGE_EVENT, callback);
+ }
+
+ removeLogChangeListener(callback) {
+ this.removeListener(LOG_CHANGE_EVENT, callback);
+ }
+
+ getLogs() {
+ return this.logs;
+ }
+
+ saveLogs(logs) {
+ this.logs = logs;
+ }
+}
+
+var AdminStore = new AdminStoreClass();
+
+AdminStoreClass.dispatchToken = AppDispatcher.register((payload) => {
+ var action = payload.action;
+
+ switch (action.type) {
+ case ActionTypes.RECIEVED_LOGS:
+ AdminStore.saveLogs(action.logs);
+ AdminStore.emitLogChange();
+ break;
+ default:
+ }
+});
+
+export default AdminStore;
diff --git a/web/react/stores/config_store.jsx b/web/react/stores/config_store.jsx
deleted file mode 100644
index b397937be..000000000
--- a/web/react/stores/config_store.jsx
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-var AppDispatcher = require('../dispatcher/app_dispatcher.jsx');
-var EventEmitter = require('events').EventEmitter;
-
-var BrowserStore = require('../stores/browser_store.jsx');
-
-var Constants = require('../utils/constants.jsx');
-var ActionTypes = Constants.ActionTypes;
-
-var CHANGE_EVENT = 'change';
-
-class ConfigStoreClass extends EventEmitter {
- constructor() {
- super();
-
- this.emitChange = this.emitChange.bind(this);
- this.addChangeListener = this.addChangeListener.bind(this);
- this.removeChangeListener = this.removeChangeListener.bind(this);
- this.getSetting = this.getSetting.bind(this);
- this.getSettingAsBoolean = this.getSettingAsBoolean.bind(this);
- this.updateStoredSettings = this.updateStoredSettings.bind(this);
- }
- emitChange() {
- this.emit(CHANGE_EVENT);
- }
- addChangeListener(callback) {
- this.on(CHANGE_EVENT, callback);
- }
- removeChangeListener(callback) {
- this.removeListener(CHANGE_EVENT, callback);
- }
- getSetting(key, defaultValue) {
- return BrowserStore.getItem('config_' + key, defaultValue);
- }
- getSettingAsBoolean(key, defaultValue) {
- var value = this.getSetting(key, defaultValue);
-
- if (typeof value !== 'string') {
- return Boolean(value);
- }
-
- return value === 'true';
- }
- updateStoredSettings(settings) {
- for (let key in settings) {
- if (settings.hasOwnProperty(key)) {
- BrowserStore.setItem('config_' + key, settings[key]);
- }
- }
- }
-}
-
-var ConfigStore = new ConfigStoreClass();
-
-ConfigStore.dispatchToken = AppDispatcher.register(function registry(payload) {
- var action = payload.action;
-
- switch (action.type) {
- case ActionTypes.RECIEVED_CONFIG:
- ConfigStore.updateStoredSettings(action.settings);
- ConfigStore.emitChange();
- break;
- default:
- }
-});
-
-export default ConfigStore;
diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx
index 5ffe65021..29ce47300 100644
--- a/web/react/stores/post_store.jsx
+++ b/web/react/stores/post_store.jsx
@@ -297,6 +297,7 @@ class PostStoreClass extends EventEmitter {
post.message = '(message deleted)';
post.state = Constants.POST_DELETED;
+ post.filenames = [];
posts[post.id] = post;
this.storeUnseenDeletedPosts(post.channel_id, posts);
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
index 6ccef0506..3e23e5c33 100644
--- a/web/react/utils/async_client.jsx
+++ b/web/react/utils/async_client.jsx
@@ -319,6 +319,32 @@ export function getAudits() {
);
}
+export function getLogs() {
+ if (isCallInProgress('getLogs')) {
+ return;
+ }
+
+ callTracker.getLogs = utils.getTimestamp();
+ client.getLogs(
+ (data, textStatus, xhr) => {
+ callTracker.getLogs = 0;
+
+ if (xhr.status === 304 || !data) {
+ return;
+ }
+
+ AppDispatcher.handleServerAction({
+ type: ActionTypes.RECIEVED_LOGS,
+ logs: data
+ });
+ },
+ (err) => {
+ callTracker.getLogs = 0;
+ dispatchError(err, 'getLogs');
+ }
+ );
+}
+
export function findTeams(email) {
if (isCallInProgress('findTeams_' + email)) {
return;
@@ -556,28 +582,4 @@ export function getMyTeam() {
dispatchError(err, 'getMyTeam');
}
);
-}
-
-export function getConfig() {
- if (isCallInProgress('getConfig')) {
- return;
- }
-
- callTracker.getConfig = utils.getTimestamp();
- client.getConfig(
- function getConfigSuccess(data, textStatus, xhr) {
- callTracker.getConfig = 0;
-
- if (data && xhr.status !== 304) {
- AppDispatcher.handleServerAction({
- type: ActionTypes.RECIEVED_CONFIG,
- settings: data
- });
- }
- },
- function getConfigFailure(err) {
- callTracker.getConfig = 0;
- dispatchError(err, 'getConfig');
- }
- );
-}
+} \ No newline at end of file
diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx
index 51fd16474..ba3042d78 100644
--- a/web/react/utils/client.jsx
+++ b/web/react/utils/client.jsx
@@ -14,8 +14,6 @@ export function trackPage() {
}
function handleError(methodName, xhr, status, err) {
- var LTracker = global.window.LTracker || [];
-
var e = null;
try {
e = JSON.parse(xhr.responseText);
@@ -39,7 +37,6 @@ function handleError(methodName, xhr, status, err) {
console.error(msg); //eslint-disable-line no-console
console.error(e); //eslint-disable-line no-console
- LTracker.push(msg);
track('api', 'api_weberror', methodName, 'message', msg);
@@ -294,6 +291,20 @@ export function getAudits(userId, success, error) {
});
}
+export function getLogs(success, error) {
+ $.ajax({
+ url: '/api/v1/admin/logs',
+ dataType: 'json',
+ contentType: 'application/json',
+ type: 'GET',
+ success: success,
+ error: function onError(xhr, status, err) {
+ var e = handleError('getLogs', xhr, status, err);
+ error(e);
+ }
+ });
+}
+
export function getMeSynchronous(success, error) {
var currentUser = null;
$.ajax({
@@ -977,16 +988,35 @@ export function updateValetFeature(data, success, error) {
track('api', 'api_teams_update_valet_feature');
}
-export function getConfig(success, error) {
+export function registerOAuthApp(app, success, error) {
$.ajax({
- url: '/api/v1/config/get_all',
+ url: '/api/v1/oauth/register',
dataType: 'json',
+ contentType: 'application/json',
+ type: 'POST',
+ data: JSON.stringify(app),
+ success: success,
+ error: (xhr, status, err) => {
+ const e = handleError('registerApp', xhr, status, err);
+ error(e);
+ }
+ });
+
+ module.exports.track('api', 'api_apps_register');
+}
+
+export function allowOAuth2(responseType, clientId, redirectUri, state, scope, success, error) {
+ $.ajax({
+ url: '/api/v1/oauth/allow?response_type=' + responseType + '&client_id=' + clientId + '&redirect_uri=' + redirectUri + '&scope=' + scope + '&state=' + state,
+ dataType: 'json',
+ contentType: 'application/json',
type: 'GET',
- ifModified: true,
success: success,
- error: function onError(xhr, status, err) {
- var e = handleError('getConfig', xhr, status, err);
+ error: (xhr, status, err) => {
+ const e = handleError('allowOAuth2', xhr, status, err);
error(e);
}
});
+
+ module.exports.track('api', 'api_users_allow_oauth2');
}
diff --git a/web/react/utils/config.js b/web/react/utils/config.js
deleted file mode 100644
index c7d1aa2bc..000000000
--- a/web/react/utils/config.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
-// See License.txt for license information.
-
-export var config = {
-
- // Loggly configs
- LogglyWriteKey: '',
- LogglyConsoleErrors: true,
-
- // Segment configs
- SegmentWriteKey: '',
-
- // Feature switches
- AllowPublicLink: true,
- AllowInviteNames: true,
- RequireInviteNames: false,
- AllowSignupDomainsWizard: false,
-
- // Google Developer Key (for Youtube API links)
- // Leave blank to disable
- GoogleDeveloperKey: '',
-
- // Privacy switches
- ShowEmail: true,
-
- // Links
- TermsLink: '/static/help/configure_links.html',
- PrivacyLink: '/static/help/configure_links.html',
- AboutLink: '/static/help/configure_links.html',
- HelpLink: '/static/help/configure_links.html',
- ReportProblemLink: '/static/help/configure_links.html',
- HomeLink: '',
-
- // Toggle whether or not users are shown a message about agreeing to the Terms of Service during the signup process
- ShowTermsDuringSignup: false,
-
- ThemeColors: ['#2389d7', '#008a17', '#dc4fad', '#ac193d', '#0072c6', '#d24726', '#ff8f32', '#82ba00', '#03b3b2', '#008299', '#4617b4', '#8c0095', '#004b8b', '#004b8b', '#570000', '#380000', '#585858', '#000000']
-};
-
-// Flavor strings
-export var strings = {
- Team: 'team',
- TeamPlural: 'teams',
- Company: 'company',
- CompanyPlural: 'companies'
-};
-
-global.window.config = config;
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index 7ead079d7..03e4635b5 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -34,7 +34,9 @@ module.exports = {
CLICK_TEAM: null,
RECIEVED_TEAM: null,
- RECIEVED_CONFIG: null
+ RECIEVED_CONFIG: null,
+
+ RECIEVED_LOGS: null
}),
PayloadSources: keyMirror({
diff --git a/web/react/utils/text_formatting.jsx b/web/react/utils/text_formatting.jsx
index 2c67d7a46..2025e16da 100644
--- a/web/react/utils/text_formatting.jsx
+++ b/web/react/utils/text_formatting.jsx
@@ -56,7 +56,7 @@ function autolinkUrls(text, tokens) {
const linkText = match.getMatchedText();
let url = linkText;
- if (!url.startsWith('http')) {
+ if (!url.lastIndexOf('http', 0) === 0) {
url = `http://${linkText}`;
}
@@ -160,7 +160,7 @@ function autolinkHashtags(text, tokens) {
var newTokens = new Map();
for (const [alias, token] of tokens) {
- if (token.originalText.startsWith('#')) {
+ if (token.originalText.lastIndexOf('#', 0) === 0) {
const index = tokens.size + newTokens.size;
const newAlias = `__MM_HASHTAG${index}__`;
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 85c6137a7..032cf4ff4 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -9,7 +9,6 @@ var ActionTypes = Constants.ActionTypes;
var AsyncClient = require('./async_client.jsx');
var client = require('./client.jsx');
var Autolinker = require('autolinker');
-import {config} from '../utils/config.js';
export function isEmail(email) {
var regex = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/;
@@ -295,12 +294,12 @@ function getYoutubeEmbed(link) {
$('.post-list-holder-by-time').scrollTop($('.post-list-holder-by-time')[0].scrollHeight);
}
- if (config.GoogleDeveloperKey) {
+ if (global.window.config.GoogleDeveloperKey) {
$.ajax({
async: true,
url: 'https://www.googleapis.com/youtube/v3/videos',
type: 'GET',
- data: {part: 'snippet', id: youtubeId, key: config.GoogleDeveloperKey},
+ data: {part: 'snippet', id: youtubeId, key: global.window.config.GoogleDeveloperKey},
success: success
});
}
@@ -934,6 +933,6 @@ export function getTeamURLFromAddressBar() {
export function getShortenedTeamURL() {
const teamURL = getTeamURLFromAddressBar();
if (teamURL.length > 24) {
- return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length - 1) + '/';
+ return teamURL.substring(0, 10) + '...' + teamURL.substring(teamURL.length - 12, teamURL.length) + '/';
}
}