Merge branch 'develop' into luke/fix-restrict-power-level-options

This commit is contained in:
Luke Barnard 2017-11-14 13:08:31 +00:00
commit 12d9f05883
16 changed files with 517 additions and 249 deletions

View file

@ -287,6 +287,9 @@ module.exports = React.createClass({
this._windowWidth = 10000;
this.handleResize();
window.addEventListener('resize', this.handleResize);
// check we have the right tint applied for this theme
Tinter.tint();
},
componentDidMount: function() {
@ -883,7 +886,7 @@ module.exports = React.createClass({
*/
_onSetTheme: function(theme) {
if (!theme) {
theme = 'light';
theme = this.props.config.default_theme || 'light';
}
// look for the stylesheet elements.
@ -912,6 +915,10 @@ module.exports = React.createClass({
});
styleElements[theme].disabled = false;
Tinter.setTheme(theme);
const colors = Tinter.getCurrentColors();
Tinter.tint(colors[0], colors[1]);
if (theme === 'dark') {
// abuse the tinter to change all the SVG's #fff to #2d2d2d
// XXX: obviously this shouldn't be hardcoded here.

View file

@ -183,6 +183,11 @@ const THEMES = [
label: _td('Dark theme'),
value: 'dark',
},
{
id: 'theme',
label: _td('Status.im theme'),
value: 'status',
},
];
const IgnoredUser = React.createClass({
@ -204,7 +209,7 @@ const IgnoredUser = React.createClass({
render: function() {
return (
<li>
<AccessibleButton onClick={this._onUnignoreClick} className="mx_UserSettings_button mx_UserSettings_buttonSmall">
<AccessibleButton onClick={this._onUnignoreClick} className="mx_textButton">
{ _t("Unignore") }
</AccessibleButton>
{ this.props.userId }
@ -283,7 +288,7 @@ module.exports = React.createClass({
const syncedSettings = UserSettingsStore.getSyncedSettings();
if (!syncedSettings.theme) {
syncedSettings.theme = 'light';
syncedSettings.theme = SdkConfig.get().default_theme || 'light';
}
this._syncedSettings = syncedSettings;

View file

@ -17,13 +17,13 @@ limitations under the License.
'use strict';
const React = require('react');
import React from 'react';
import { _t } from '../../../languageHandler';
const sdk = require('../../../index');
const Modal = require("../../../Modal");
const MatrixClientPeg = require('../../../MatrixClientPeg');
import sdk from '../../../index';
import Modal from "../../../Modal";
import MatrixClientPeg from "../../../MatrixClientPeg";
const PasswordReset = require("../../../PasswordReset");
import PasswordReset from "../../../PasswordReset";
module.exports = React.createClass({
displayName: 'ForgotPassword',
@ -154,6 +154,7 @@ module.exports = React.createClass({
},
render: function() {
const LoginPage = sdk.getComponent("login.LoginPage");
const LoginHeader = sdk.getComponent("login.LoginHeader");
const LoginFooter = sdk.getComponent("login.LoginFooter");
const ServerConfig = sdk.getComponent("login.ServerConfig");
@ -165,7 +166,7 @@ module.exports = React.createClass({
resetPasswordJsx = <Spinner />;
} else if (this.state.progress === "sent_email") {
resetPasswordJsx = (
<div>
<div className="mx_Login_prompt">
{ _t("An email has been sent to %(emailAddress)s. Once you've followed the link it contains, click below.", { emailAddress: this.state.email }) }
<br />
<input className="mx_Login_submit" type="button" onClick={this.onVerify}
@ -174,7 +175,7 @@ module.exports = React.createClass({
);
} else if (this.state.progress === "complete") {
resetPasswordJsx = (
<div>
<div className="mx_Login_prompt">
<p>{ _t('Your password has been reset') }.</p>
<p>{ _t('You have been logged out of all devices and will no longer receive push notifications. To re-enable notifications, sign in again on each device') }.</p>
<input className="mx_Login_submit" type="button" onClick={this.props.onComplete}
@ -182,6 +183,20 @@ module.exports = React.createClass({
</div>
);
} else {
let serverConfigSection;
if (!config.disable_custom_urls) {
serverConfigSection = (
<ServerConfig ref="serverConfig"
withToggleButton={true}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={0} />
);
}
resetPasswordJsx = (
<div>
<div className="mx_Login_prompt">
@ -209,16 +224,7 @@ module.exports = React.createClass({
<br />
<input className="mx_Login_submit" type="submit" value={_t('Send Reset Email')} />
</form>
<ServerConfig ref="serverConfig"
withToggleButton={true}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={0} />
<div className="mx_Login_error">
</div>
{ serverConfigSection }
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
{ _t('Return to login screen') }
</a>
@ -233,12 +239,12 @@ module.exports = React.createClass({
return (
<div className="mx_Login">
<LoginPage>
<div className="mx_Login_box">
<LoginHeader />
{ resetPasswordJsx }
</div>
</div>
</LoginPage>
);
},
});

View file

@ -24,6 +24,7 @@ import sdk from '../../../index';
import Login from '../../../Login';
import UserSettingsStore from '../../../UserSettingsStore';
import PlatformPeg from '../../../PlatformPeg';
import SdkConfig from '../../../SdkConfig';
// For validating phone numbers without country codes
const PHONE_NUMBER_REGEX = /^[0-9\(\)\-\s]*$/;
@ -105,7 +106,22 @@ module.exports = React.createClass({
if (error.httpStatus == 400 && usingEmail) {
errorText = _t('This Home Server does not support login using email address.');
} else if (error.httpStatus === 401 || error.httpStatus === 403) {
errorText = _t('Incorrect username and/or password.');
if (SdkConfig.get().disable_custom_urls) {
errorText = (
<div>
<div>{ _t('Incorrect username and/or password.') }</div>
<div className="mx_Login_smallError">
{ _t('Please note you are logging into the %(hs)s server, not matrix.org.',
{
hs: this.props.defaultHsUrl.replace(/^https?:\/\//, '')
})
}
</div>
</div>
);
} else {
errorText = _t('Incorrect username and/or password.');
}
} else {
// other errors, not specific to doing a password login
errorText = this._errorTextFromError(error);
@ -329,6 +345,7 @@ module.exports = React.createClass({
render: function() {
const Loader = sdk.getComponent("elements.Spinner");
const LoginPage = sdk.getComponent("login.LoginPage");
const LoginHeader = sdk.getComponent("login.LoginHeader");
const LoginFooter = sdk.getComponent("login.LoginFooter");
const ServerConfig = sdk.getComponent("login.ServerConfig");
@ -343,43 +360,69 @@ module.exports = React.createClass({
}
let returnToAppJsx;
/*
// with the advent of ILAG I don't think we need this any more
if (this.props.onCancelClick) {
returnToAppJsx =
<a className="mx_Login_create" onClick={this.props.onCancelClick} href="#">
{ _t('Return to app') }
</a>;
}
*/
if (!SdkConfig.get().disable_custom_urls) {
serverConfig = <ServerConfig ref="serverConfig"
withToggleButton={true}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} />;
}
let serverConfig;
let header;
// FIXME: remove status.im theme tweaks
const theme = UserSettingsStore.getTheme();
if (theme !== "status") {
header = <h2>{ _t('Sign in') }</h2>;
}
else {
if (!this.state.errorText) {
header = <h2>{ _t('Sign in to get started') }</h2>;
}
}
let errorTextSection;
if (this.state.errorText) {
errorTextSection = (
<div className="mx_Login_error">
{ this.state.errorText }
</div>
);
}
return (
<div className="mx_Login">
<LoginPage>
<div className="mx_Login_box">
<LoginHeader />
<div>
<h2>{ _t('Sign in') }
{ loader }
</h2>
{ header }
{ errorTextSection }
{ this.componentForStep(this.state.currentFlow) }
<ServerConfig ref="serverConfig"
withToggleButton={true}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000} />
<div className="mx_Login_error">
{ this.state.errorText }
</div>
{ serverConfig }
<a className="mx_Login_create" onClick={this.props.onRegisterClick} href="#">
{ _t('Create an account') }
</a>
{ loginAsGuestJsx }
{ returnToAppJsx }
{ this._renderLanguageSetting() }
{ !SdkConfig.get().disable_login_language_selector ? this._renderLanguageSetting() : '' }
<LoginFooter />
</div>
</div>
</div>
</LoginPage>
);
},
});

View file

@ -59,9 +59,10 @@ module.exports = React.createClass({
render: function() {
const ChangeDisplayName = sdk.getComponent('settings.ChangeDisplayName');
const ChangeAvatar = sdk.getComponent('settings.ChangeAvatar');
const LoginPage = sdk.getComponent('login.LoginPage');
const LoginHeader = sdk.getComponent('login.LoginHeader');
return (
<div className="mx_Login">
<LoginPage>
<div className="mx_Login_box">
<LoginHeader />
<div className="mx_Login_profile">
@ -74,7 +75,7 @@ module.exports = React.createClass({
{ this.state.errorString }
</div>
</div>
</div>
</LoginPage>
);
},
});

View file

@ -26,6 +26,8 @@ import MatrixClientPeg from '../../../MatrixClientPeg';
import RegistrationForm from '../../views/login/RegistrationForm';
import RtsClient from '../../../RtsClient';
import { _t } from '../../../languageHandler';
import UserSettingsStore from '../../../UserSettingsStore';
import SdkConfig from '../../../SdkConfig';
const MIN_PASSWORD_LENGTH = 6;
@ -322,10 +324,13 @@ module.exports = React.createClass({
render: function() {
const LoginHeader = sdk.getComponent('login.LoginHeader');
const LoginFooter = sdk.getComponent('login.LoginFooter');
const LoginPage = sdk.getComponent('login.LoginPage');
const InteractiveAuth = sdk.getComponent('structures.InteractiveAuth');
const Spinner = sdk.getComponent("elements.Spinner");
const ServerConfig = sdk.getComponent('views.login.ServerConfig');
const theme = UserSettingsStore.getTheme();
let registerBody;
if (this.state.doingUIAuth) {
registerBody = (
@ -344,9 +349,19 @@ module.exports = React.createClass({
} else if (this.state.busy || this.state.teamServerBusy) {
registerBody = <Spinner />;
} else {
let errorSection;
if (this.state.errorText) {
errorSection = <div className="mx_Login_error">{ this.state.errorText }</div>;
let serverConfigSection;
if (!SdkConfig.get().disable_custom_urls) {
serverConfigSection = (
<ServerConfig ref="serverConfig"
withToggleButton={true}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000}
/>
);
}
registerBody = (
<div>
@ -362,21 +377,14 @@ module.exports = React.createClass({
onRegisterClick={this.onFormSubmit}
onTeamSelected={this.onTeamSelected}
/>
{ errorSection }
<ServerConfig ref="serverConfig"
withToggleButton={true}
customHsUrl={this.props.customHsUrl}
customIsUrl={this.props.customIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={1000}
/>
{ serverConfigSection }
</div>
);
}
let returnToAppJsx;
/*
// with the advent of ILAG I don't think we need this any more
if (this.props.onCancelClick) {
returnToAppJsx = (
<a className="mx_Login_create" onClick={this.props.onCancelClick} href="#">
@ -384,8 +392,32 @@ module.exports = React.createClass({
</a>
);
}
*/
let header;
let errorText;
// FIXME: remove hardcoded Status team tweaks at some point
if (theme === 'status' && this.state.errorText) {
header = <div className="mx_Login_error">{ this.state.errorText }</div>;
}
else {
header = <h2>{ _t('Create an account') }</h2>;
if (this.state.errorText) {
errorText = <div className="mx_Login_error">{ this.state.errorText }</div>;
}
}
let signIn;
if (!this.state.doingUIAuth) {
signIn = (
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
{ theme === 'status' ? _t('Sign in') : _t('I already have an account') }
</a>
);
}
return (
<div className="mx_Login">
<LoginPage>
<div className="mx_Login_box">
<LoginHeader
icon={this.state.teamSelected ?
@ -393,15 +425,14 @@ module.exports = React.createClass({
this.state.teamSelected.domain + "/icon.png" :
null}
/>
<h2>{ _t('Create an account') }</h2>
{ header }
{ registerBody }
<a className="mx_Login_create" onClick={this.props.onLoginClick} href="#">
{ _t('I already have an account') }
</a>
{ signIn }
{ errorText }
{ returnToAppJsx }
<LoginFooter />
</div>
</div>
</LoginPage>
);
},
});

View file

@ -0,0 +1,59 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
import UserSettingsStore from '../../../UserSettingsStore';
const React = require('react');
module.exports = React.createClass({
displayName: 'LoginPage',
render: function() {
// FIXME: this should be turned into a proper skin with a StatusLoginPage component
if (UserSettingsStore.getTheme() === 'status') {
return (
<div className="mx_StatusLogin">
<div className="mx_StatusLogin_brand">
<img src="themes/status/img/logo.svg" alt="Status" width="221" height="53" />
</div>
<div className="mx_StatusLogin_content">
<div className="mx_StatusLogin_header">
<h1>Status Community Chat</h1>
<div className="mx_StatusLogin_subtitle">
A safer, decentralised communication
platform <a href="https://riot.im">powered by Riot</a>
</div>
</div>
{ this.props.children }
<div className="mx_StatusLogin_footer">
<p>This channel is for our development community.</p>
<p>Interested in SNT and discussions on the cryptocurrency market?</p>
<p><a href="https://t.me/StatusNetworkChat" target="_blank" className="mx_StatusLogin_footer_cta">Join Telegram Chat</a></p>
</div>
</div>
</div>
);
} else {
return (
<div className="mx_Login">
{ this.props.children }
</div>
);
}
},
});

View file

@ -20,7 +20,7 @@ import classNames from 'classnames';
import sdk from '../../../index';
import { _t } from '../../../languageHandler';
import {field_input_incorrect} from '../../../UiEffects';
import SdkConfig from '../../../SdkConfig';
/**
* A pure UI component which displays a username/password form.
@ -144,7 +144,10 @@ class PasswordLogin extends React.Component {
type="text"
name="username" // make it a little easier for browser's remember-password
onChange={this.onUsernameChanged}
placeholder={_t('User name')}
placeholder={ SdkConfig.get().disable_custom_urls ?
_t("Username on %(hs)s", {
hs: this.props.hsUrl.replace(/^https?:\/\//, '')
}) : _t("User name")}
value={this.state.username}
autoFocus
disabled={disabled}
@ -210,9 +213,9 @@ class PasswordLogin extends React.Component {
const loginField = this.renderLoginField(this.state.loginType, matrixIdText === '');
return (
<div>
<form onSubmit={this.onSubmitForm}>
let loginType;
if (!SdkConfig.get().disable_3pid_login) {
loginType = (
<div className="mx_Login_type_container">
<label className="mx_Login_type_label">{ _t('Sign in with') }</label>
<Dropdown
@ -225,6 +228,13 @@ class PasswordLogin extends React.Component {
<span key={PasswordLogin.LOGIN_FIELD_PHONE}>{ _t('Phone') }</span>
</Dropdown>
</div>
);
}
return (
<div>
<form onSubmit={this.onSubmitForm}>
{ loginType }
{ loginField }
<input className={pwFieldClass} ref={(e) => {this._passwordField = e;}} type="password"
name="password"

View file

@ -22,6 +22,8 @@ import Email from '../../../email';
import { looksValid as phoneNumberLooksValid } from '../../../phonenumber';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';
import UserSettingsStore from '../../../UserSettingsStore';
import SdkConfig from '../../../SdkConfig';
const FIELD_EMAIL = 'field_email';
const FIELD_PHONE_COUNTRY = 'field_phone_country';
@ -122,7 +124,7 @@ module.exports = React.createClass({
password: this.refs.password.value.trim(),
email: email,
phoneCountry: this.state.phoneCountry,
phoneNumber: this.refs.phoneNumber.value.trim(),
phoneNumber: this.refs.phoneNumber ? this.refs.phoneNumber.value.trim() : '',
});
if (promise) {
@ -180,7 +182,7 @@ module.exports = React.createClass({
this.markFieldValid(field_id, emailValid, "RegistrationForm.ERR_EMAIL_INVALID");
break;
case FIELD_PHONE_NUMBER:
const phoneNumber = this.refs.phoneNumber.value;
const phoneNumber = this.refs.phoneNumber ? this.refs.phoneNumber.value : '';
const phoneNumberValid = phoneNumber === '' || phoneNumberLooksValid(phoneNumber);
this.markFieldValid(field_id, phoneNumberValid, "RegistrationForm.ERR_PHONE_NUMBER_INVALID");
break;
@ -273,10 +275,14 @@ module.exports = React.createClass({
render: function() {
const self = this;
const theme = UserSettingsStore.getTheme();
// FIXME: remove hardcoded Status team tweaks at some point
const emailPlaceholder = theme === 'status' ? _t("Email address") : _t("Email address (optional)");
const emailSection = (
<div>
<input type="text" ref="email"
autoFocus={true} placeholder={_t("Email address (optional)")}
autoFocus={true} placeholder={ emailPlaceholder }
defaultValue={this.props.defaultEmail}
className={this._classForField(FIELD_EMAIL, 'mx_Login_field')}
onBlur={function() {self.validateField(FIELD_EMAIL);}}
@ -306,28 +312,31 @@ module.exports = React.createClass({
}
const CountryDropdown = sdk.getComponent('views.login.CountryDropdown');
const phoneSection = (
<div className="mx_Login_phoneSection">
<CountryDropdown ref="phone_country" onOptionChange={this._onPhoneCountryChange}
className="mx_Login_phoneCountry mx_Login_field_prefix"
value={this.state.phoneCountry}
isSmall={true}
showPrefix={true}
/>
<input type="text" ref="phoneNumber"
placeholder={_t("Mobile phone number (optional)")}
defaultValue={this.props.defaultPhoneNumber}
className={this._classForField(
FIELD_PHONE_NUMBER,
'mx_Login_phoneNumberField',
'mx_Login_field',
'mx_Login_field_has_prefix',
)}
onBlur={function() {self.validateField(FIELD_PHONE_NUMBER);}}
value={self.state.phoneNumber}
/>
</div>
);
let phoneSection;
if (!SdkConfig.get().disable_3pid_login) {
phoneSection = (
<div className="mx_Login_phoneSection">
<CountryDropdown ref="phone_country" onOptionChange={this._onPhoneCountryChange}
className="mx_Login_phoneCountry mx_Login_field_prefix"
value={this.state.phoneCountry}
isSmall={true}
showPrefix={true}
/>
<input type="text" ref="phoneNumber"
placeholder={_t("Mobile phone number (optional)")}
defaultValue={this.props.defaultPhoneNumber}
className={this._classForField(
FIELD_PHONE_NUMBER,
'mx_Login_phoneNumberField',
'mx_Login_field',
'mx_Login_field_has_prefix',
)}
onBlur={function() {self.validateField(FIELD_PHONE_NUMBER);}}
value={self.state.phoneNumber}
/>
</div>
);
}
const registerButton = (
<input className="mx_Login_submit" type="submit" value={_t("Register")} />

View file

@ -25,7 +25,7 @@ import dis from '../../../dispatcher';
const ROOM_COLORS = [
// magic room default values courtesy of Ribot
["#76cfa6", "#eaf5f0"],
[Tinter.getKeyRgb()[0], Tinter.getKeyRgb()[1]],
["#81bddb", "#eaf1f4"],
["#bd79cb", "#f3eaf5"],
["#c65d94", "#f5eaef"],