Merge branch 'develop' into travis/settings/delete-the-old

This commit is contained in:
Travis Ralston 2019-02-06 11:02:21 -07:00
commit b2c161c7c1
13 changed files with 227 additions and 139 deletions

View file

@ -97,7 +97,6 @@ module.exports = {
"new-cap": ["warn"],
"key-spacing": ["warn"],
"prefer-const": ["warn"],
"arrow-parens": "off",
// crashes currently: https://github.com/eslint/eslint/issues/6274
"generator-star-spacing": "off",

View file

@ -100,7 +100,8 @@ limitations under the License.
top 0.25s ease-out 0s,
background-color 0.25s ease-out 0s;
font-size: 10px;
top: -14px;
top: -13px;
padding: 0 2px;
background-color: $field-focused-label-bg-color;
}

View file

@ -199,9 +199,10 @@ const LeftPanel = React.createClass({
},
);
const searchBox = !this.props.collapsed ?
<SearchBox onSearch={ this.onSearch } onCleared={ this.onSearchCleared } /> :
undefined;
const searchBox = (<SearchBox
onSearch={ this.onSearch }
onCleared={ this.onSearchCleared }
collapsed={this.props.collapsed} />);
return (
<div className={containerClasses}>

View file

@ -1647,11 +1647,6 @@ export default React.createClass({
this.showScreen("forgot_password");
},
onReturnToAppClick: function() {
// treat it the same as if the user had completed the login
this._onLoggedIn();
},
// returns a promise which resolves to the new MatrixClient
onRegistered: function(credentials) {
// XXX: This should be in state or ideally store(s) because we risk not
@ -1862,7 +1857,6 @@ export default React.createClass({
sessionId={this.state.register_session_id}
idSid={this.state.register_id_sid}
email={this.props.startingFragmentQueryParams.email}
referrer={this.props.startingFragmentQueryParams.referrer}
defaultServerDiscoveryError={this.state.defaultServerDiscoveryError}
defaultHsUrl={this.getDefaultHsUrl()}
defaultIsUrl={this.getDefaultIsUrl()}
@ -1870,11 +1864,8 @@ export default React.createClass({
customHsUrl={this.getCurrentHsUrl()}
customIsUrl={this.getCurrentIsUrl()}
makeRegistrationUrl={this._makeRegistrationUrl}
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
onLoggedIn={this.onRegistered}
onLoginClick={this.onLoginClick}
onRegisterClick={this.onRegisterClick}
onCancelClick={MatrixClientPeg.get() ? this.onReturnToAppClick : null}
onServerConfigChange={this.onServerConfigChange}
/>
);
@ -1911,7 +1902,6 @@ export default React.createClass({
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
onForgotPasswordClick={this.onForgotPasswordClick}
enableGuest={this.props.enableGuest}
onCancelClick={MatrixClientPeg.get() ? this.onReturnToAppClick : null}
onServerConfigChange={this.onServerConfigChange}
/>
);

View file

@ -642,14 +642,13 @@ module.exports = React.createClass({
updateTimelineMinHeight: function() {
const scrollPanel = this.refs.scrollPanel;
const whoIsTyping = this.refs.whoIsTyping;
const isTypingVisible = whoIsTyping && whoIsTyping.isVisible();
if (scrollPanel) {
if (isTypingVisible) {
const isAtBottom = scrollPanel.isAtBottom();
const whoIsTyping = this.refs.whoIsTyping;
const isTypingVisible = whoIsTyping && whoIsTyping.isVisible();
if (isAtBottom && isTypingVisible) {
scrollPanel.blockShrinking();
} else {
scrollPanel.clearBlockShrinking();
}
}
},

View file

@ -169,6 +169,10 @@ module.exports = React.createClass({
//
// This will also re-check the fill state, in case the paginate was inadequate
this.checkScroll();
if (!this.isAtBottom()) {
this.clearBlockShrinking();
}
},
componentWillUnmount: function() {

View file

@ -71,7 +71,7 @@ module.exports = React.createClass({
function() {
this.props.onSearch(this.refs.search.value);
},
100,
500,
),
_onKeyDown: function(ev) {
@ -95,8 +95,13 @@ module.exports = React.createClass({
},
render: function() {
const TintableSvg = sdk.getComponent('elements.TintableSvg');
// check for collapsed here and
// not at parent so we keep
// searchTerm in our state
// when collapsing and expanding
if (this.props.collapsed) {
return null;
}
const clearButton = this.state.searchTerm.length > 0 ?
(<AccessibleButton key="button"
className="mx_SearchBox_closeButton"

View file

@ -26,19 +26,18 @@ import Login from '../../../Login';
import SdkConfig from '../../../SdkConfig';
import { messageForResourceLimitError } from '../../../utils/ErrorUtils';
import { AutoDiscovery } from "matrix-js-sdk";
import * as ServerType from '../../views/auth/ServerTypeSelector';
// For validating phone numbers without country codes
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
// Phases
// Show controls to configure server details
const PHASE_SERVER_DETAILS = 0;
// Show the appropriate login flow(s) for the server
const PHASE_LOGIN = 1;
const PHASE_LOGIN = 0;
// Show controls to configure server details
const PHASE_SERVER_DETAILS = 1;
// Disable phases for now, pending UX discussion on WK discovery
const PHASES_ENABLED = false;
// Enable phases for login
const PHASES_ENABLED = true;
// These are used in several places, and come from the js-sdk's autodiscovery
// stuff. We define them here so that they'll be picked up by i18n.
@ -77,7 +76,6 @@ module.exports = React.createClass({
// login shouldn't care how password recovery is done.
onForgotPasswordClick: PropTypes.func,
onCancelClick: PropTypes.func,
onServerConfigChange: PropTypes.func.isRequired,
},
@ -87,7 +85,6 @@ module.exports = React.createClass({
errorText: null,
loginIncorrect: false,
serverType: null,
enteredHsUrl: this.props.customHsUrl || this.props.defaultHsUrl,
enteredIsUrl: this.props.customIsUrl || this.props.defaultIsUrl,
@ -97,7 +94,7 @@ module.exports = React.createClass({
phoneNumber: "",
// Phase of the overall login dialog.
phase: PHASE_SERVER_DETAILS,
phase: PHASE_LOGIN,
// The current login flow, such as password, SSO, etc.
currentFlow: "m.login.password",
@ -263,11 +260,6 @@ module.exports = React.createClass({
username: username,
discoveryError: null,
});
// If the free server type is selected, we don't show server details at all,
// so it doesn't make sense to try .well-known discovery.
if (this.state.serverType === ServerType.FREE) {
return;
}
if (username[0] === "@") {
const serverName = username.split(':').slice(1).join(':');
try {
@ -323,39 +315,6 @@ module.exports = React.createClass({
});
},
onServerTypeChange(type) {
this.setState({
serverType: type,
});
// When changing server types, set the HS / IS URLs to reasonable defaults for the
// the new type.
switch (type) {
case ServerType.FREE: {
const { hsUrl, isUrl } = ServerType.TYPES.FREE;
this.onServerConfigChange({
hsUrl,
isUrl,
});
// Move directly to the login phase since the server details are fixed.
this.setState({
phase: PHASE_LOGIN,
});
break;
}
case ServerType.PREMIUM:
case ServerType.ADVANCED:
this.onServerConfigChange({
hsUrl: this.props.defaultHsUrl,
isUrl: this.props.defaultIsUrl,
});
this.setState({
phase: PHASE_SERVER_DETAILS,
});
break;
}
},
onRegisterClick: function(ev) {
ev.preventDefault();
ev.stopPropagation();
@ -391,14 +350,6 @@ module.exports = React.createClass({
try {
const discovery = await AutoDiscovery.findClientConfig(serverName);
// The server type may have changed while discovery began in the background.
// If it has become the free server type which doesn't show server details,
// ignore discovery results.
if (this.state.serverType === ServerType.FREE) {
this.setState({findingHomeserver: false});
return;
}
const state = discovery["m.homeserver"].state;
if (state !== AutoDiscovery.SUCCESS && state !== AutoDiscovery.PROMPT) {
this.setState({
@ -554,43 +505,20 @@ module.exports = React.createClass({
return errorText;
},
renderServerComponentForStep() {
const ServerTypeSelector = sdk.getComponent("auth.ServerTypeSelector");
renderServerComponent() {
const ServerConfig = sdk.getComponent("auth.ServerConfig");
const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
// TODO: May need to adjust the behavior of this config option
if (SdkConfig.get()['disable_custom_urls']) {
return null;
}
// If we're on a different phase, we only show the server type selector,
// which is always shown if we allow custom URLs at all.
if (PHASES_ENABLED && this.state.phase !== PHASE_SERVER_DETAILS) {
return <div>
<ServerTypeSelector
defaultHsUrl={this.props.defaultHsUrl}
onChange={this.onServerTypeChange}
/>
</div>;
// TODO: ...
return null;
}
let serverDetails = null;
switch (this.state.serverType) {
case ServerType.FREE:
break;
case ServerType.PREMIUM:
serverDetails = <ModularServerConfig
customHsUrl={this.state.enteredHsUrl}
defaultHsUrl={this.props.defaultHsUrl}
defaultIsUrl={this.props.defaultIsUrl}
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={250}
/>;
break;
case ServerType.ADVANCED:
serverDetails = <ServerConfig
const serverDetails = <ServerConfig
customHsUrl={this.state.enteredHsUrl}
customIsUrl={this.state.enteredIsUrl}
defaultHsUrl={this.props.defaultHsUrl}
@ -598,8 +526,6 @@ module.exports = React.createClass({
onServerConfigChange={this.onServerConfigChange}
delayTimeMs={250}
/>;
break;
}
let nextButton = null;
if (PHASES_ENABLED) {
@ -611,10 +537,6 @@ module.exports = React.createClass({
}
return <div>
<ServerTypeSelector
defaultHsUrl={this.props.defaultHsUrl}
onChange={this.onServerTypeChange}
/>
{serverDetails}
{nextButton}
</div>;
@ -643,13 +565,8 @@ module.exports = React.createClass({
_renderPasswordStep: function() {
const PasswordLogin = sdk.getComponent('auth.PasswordLogin');
let onEditServerDetailsClick = null;
// If custom URLs are allowed and we haven't selected the Free server type, wire
// up the server details edit link.
if (
PHASES_ENABLED &&
!SdkConfig.get()['disable_custom_urls'] &&
this.state.serverType !== ServerType.FREE
) {
// If custom URLs are allowed, wire up the server details edit link.
if (PHASES_ENABLED && !SdkConfig.get()['disable_custom_urls']) {
onEditServerDetailsClick = this.onEditServerDetailsClick;
}
return (
@ -718,11 +635,11 @@ module.exports = React.createClass({
<AuthHeader />
<AuthBody>
<h2>
{_t('Sign in to your account')}
{_t('Sign in')}
{loader}
</h2>
{ errorTextSection }
{ this.renderServerComponentForStep() }
{ this.renderServerComponent() }
{ this.renderLoginComponentForStep() }
<a className="mx_AuthBody_changeFlow" onClick={this.onRegisterClick} href="#">
{ _t('Create account') }

View file

@ -54,21 +54,17 @@ module.exports = React.createClass({
defaultIsUrl: PropTypes.string,
brand: PropTypes.string,
email: PropTypes.string,
referrer: PropTypes.string,
// An error passed along from higher up explaining that something
// went wrong when finding the defaultHsUrl.
defaultServerDiscoveryError: PropTypes.string,
defaultDeviceDisplayName: PropTypes.string,
// registration shouldn't know or care how login is done.
onLoginClick: PropTypes.func.isRequired,
onCancelClick: PropTypes.func,
onServerConfigChange: PropTypes.func.isRequired,
},
getInitialState: function() {
const customURLsAllowed = !SdkConfig.get()['disable_custom_urls'];
return {
busy: false,
errorText: null,
@ -90,6 +86,8 @@ module.exports = React.createClass({
serverType: null,
hsUrl: this.props.customHsUrl,
isUrl: this.props.customIsUrl,
// Phase of the overall registration dialog.
phase: customURLsAllowed ? PHASE_SERVER_DETAILS : PHASE_REGISTRATION,
flows: null,
};
},
@ -367,7 +365,6 @@ module.exports = React.createClass({
const ModularServerConfig = sdk.getComponent("auth.ModularServerConfig");
const AccessibleButton = sdk.getComponent("elements.AccessibleButton");
// TODO: May need to adjust the behavior of this config option
if (SdkConfig.get()['disable_custom_urls']) {
return null;
}

View file

@ -249,10 +249,10 @@ class PasswordLogin extends React.Component {
</span>;
}
let yourMatrixAccountText = _t('Your account');
let signInToText = _t('Sign in');
try {
const parsedHsUrl = new URL(this.props.hsUrl);
yourMatrixAccountText = _t('Your %(serverName)s account', {
signInToText = _t('Sign in to %(serverName)s', {
serverName: parsedHsUrl.hostname,
});
} catch (e) {
@ -264,7 +264,7 @@ class PasswordLogin extends React.Component {
editLink = <a className="mx_AuthBody_editServerDetails"
href="#" onClick={this.props.onEditServerDetailsClick}
>
{_t('Edit')}
{_t('Change')}
</a>;
}
@ -297,7 +297,7 @@ class PasswordLogin extends React.Component {
return (
<div>
<h3>
{yourMatrixAccountText}
{signInToText}
{editLink}
</h3>
<form onSubmit={this.onSubmitForm}>

View file

@ -1182,6 +1182,9 @@
"Sign in with": "Sign in with",
"Phone": "Phone",
"Sign in": "Sign in",
"Sign in to %(serverName)s": "Sign in to %(serverName)s",
"Change": "Change",
"Sign in with": "Sign in with",
"If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?",
"Create your account": "Create your account",
"Create your %(serverName)s account": "Create your %(serverName)s account",
@ -1362,7 +1365,6 @@
"Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.": "Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
"Sign in with single sign-on": "Sign in with single sign-on",
"Try the app first": "Try the app first",
"Sign in to your account": "Sign in to your account",
"Create account": "Create account",
"Failed to fetch avatar URL": "Failed to fetch avatar URL",
"Set a display name:": "Set a display name:",

View file

@ -0,0 +1,90 @@
/*
Copyright 2019 New Vector 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.
*/
import expect from 'expect';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-dom/test-utils';
import sdk from 'matrix-react-sdk';
import SdkConfig from '../../../../src/SdkConfig';
import * as TestUtils from '../../../test-utils';
const Login = sdk.getComponent(
'structures.auth.Login',
);
describe('Login', function() {
let parentDiv;
beforeEach(function() {
TestUtils.beforeEach(this);
parentDiv = document.createElement('div');
document.body.appendChild(parentDiv);
});
afterEach(function() {
sinon.restore();
ReactDOM.unmountComponentAtNode(parentDiv);
parentDiv.remove();
});
function render() {
return ReactDOM.render(<Login
defaultHsUrl="https://matrix.org"
defaultIsUrl="https://vector.im"
onLoggedIn={() => {}}
onRegisterClick={() => {}}
onServerConfigChange={() => {}}
/>, parentDiv);
}
it('should show form with change server link', function() {
const root = render();
const form = ReactTestUtils.findRenderedComponentWithType(
root,
sdk.getComponent('auth.PasswordLogin'),
);
expect(form).toBeTruthy();
const changeServerLink = ReactTestUtils.findRenderedDOMComponentWithClass(
root,
'mx_AuthBody_editServerDetails',
);
expect(changeServerLink).toBeTruthy();
});
it('should show form without change server link when custom URLs disabled', function() {
sinon.stub(SdkConfig, "get").returns({
disable_custom_urls: true,
});
const root = render();
const form = ReactTestUtils.findRenderedComponentWithType(
root,
sdk.getComponent('auth.PasswordLogin'),
);
expect(form).toBeTruthy();
const changeServerLinks = ReactTestUtils.scryRenderedDOMComponentsWithClass(
root,
'mx_AuthBody_editServerDetails',
);
expect(changeServerLinks).toHaveLength(0);
});
});

View file

@ -0,0 +1,83 @@
/*
Copyright 2019 New Vector 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.
*/
import expect from 'expect';
import sinon from 'sinon';
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-dom/test-utils';
import sdk from 'matrix-react-sdk';
import SdkConfig from '../../../../src/SdkConfig';
import * as TestUtils from '../../../test-utils';
const Registration = sdk.getComponent(
'structures.auth.Registration',
);
describe('Registration', function() {
let parentDiv;
beforeEach(function() {
TestUtils.beforeEach(this);
parentDiv = document.createElement('div');
document.body.appendChild(parentDiv);
});
afterEach(function() {
sinon.restore();
ReactDOM.unmountComponentAtNode(parentDiv);
parentDiv.remove();
});
function render() {
return ReactDOM.render(<Registration
defaultHsUrl="https://matrix.org"
defaultIsUrl="https://vector.im"
makeRegistrationUrl={() => {}}
onLoggedIn={() => {}}
onLoginClick={() => {}}
onServerConfigChange={() => {}}
/>, parentDiv);
}
it('should show server type selector', function() {
const root = render();
const selector = ReactTestUtils.findRenderedComponentWithType(
root,
sdk.getComponent('auth.ServerTypeSelector'),
);
expect(selector).toBeTruthy();
});
it('should show form when custom URLs disabled', function() {
sinon.stub(SdkConfig, "get").returns({
disable_custom_urls: true,
});
const root = render();
// Set non-empty flows to get past the loading spinner
root.setState({
flows: [],
});
const form = ReactTestUtils.findRenderedComponentWithType(
root,
sdk.getComponent('auth.RegistrationForm'),
);
expect(form).toBeTruthy();
});
});