Merge remote-tracking branch 'origin/develop' into dbkr/e2e_backups
This commit is contained in:
commit
8ccaf53d20
47 changed files with 2578 additions and 205 deletions
|
@ -23,6 +23,8 @@ import request from 'browser-request';
|
|||
import { _t } from '../../languageHandler';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
import sdk from '../../index';
|
||||
import { MatrixClient } from 'matrix-js-sdk';
|
||||
import dis from '../../dispatcher';
|
||||
|
||||
class HomePage extends React.Component {
|
||||
static displayName = 'HomePage';
|
||||
|
@ -37,6 +39,10 @@ class HomePage extends React.Component {
|
|||
homePageUrl: PropTypes.string,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||
};
|
||||
|
||||
state = {
|
||||
iframeSrc: '',
|
||||
page: '',
|
||||
|
@ -85,10 +91,47 @@ class HomePage extends React.Component {
|
|||
this._unmounted = true;
|
||||
}
|
||||
|
||||
onLoginClick() {
|
||||
dis.dispatch({ action: 'start_login' });
|
||||
}
|
||||
|
||||
onRegisterClick() {
|
||||
dis.dispatch({ action: 'start_registration' });
|
||||
}
|
||||
|
||||
render() {
|
||||
let guestWarning = "";
|
||||
if (this.context.matrixClient.isGuest()) {
|
||||
guestWarning = (
|
||||
<div className="mx_HomePage_guest_warning">
|
||||
<img src="img/warning.svg" width="24" height="23" />
|
||||
<div>
|
||||
<div>
|
||||
{ _t("You are currently using Riot anonymously as a guest.") }
|
||||
</div>
|
||||
<div>
|
||||
{ _t(
|
||||
'If you would like to create a Matrix account you can <a>register</a> now.',
|
||||
{},
|
||||
{ 'a': (sub) => <a href="#" onClick={this.onRegisterClick}>{ sub }</a> },
|
||||
) }
|
||||
</div>
|
||||
<div>
|
||||
{ _t(
|
||||
'If you already have a Matrix account you can <a>log in</a> instead.',
|
||||
{},
|
||||
{ 'a': (sub) => <a href="#" onClick={this.onLoginClick}>{ sub }</a> },
|
||||
) }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (this.state.iframeSrc) {
|
||||
return (
|
||||
<div className="mx_HomePage">
|
||||
{ guestWarning }
|
||||
<iframe src={ this.state.iframeSrc } />
|
||||
</div>
|
||||
);
|
||||
|
@ -96,6 +139,7 @@ class HomePage extends React.Component {
|
|||
const GeminiScrollbarWrapper = sdk.getComponent("elements.GeminiScrollbarWrapper");
|
||||
return (
|
||||
<GeminiScrollbarWrapper autoshow={true} className="mx_HomePage">
|
||||
{ guestWarning }
|
||||
<div className="mx_HomePage_body" dangerouslySetInnerHTML={{ __html: this.state.page }}>
|
||||
</div>
|
||||
</GeminiScrollbarWrapper>
|
||||
|
|
|
@ -68,6 +68,11 @@ export default React.createClass({
|
|||
// If true, poll to see if the auth flow has been completed
|
||||
// out-of-band
|
||||
poll: PropTypes.bool,
|
||||
|
||||
// If true, components will be told that the 'Continue' button
|
||||
// is managed by some other party and should not be managed by
|
||||
// the component itself.
|
||||
continueIsManaged: PropTypes.bool,
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
|
@ -128,6 +133,12 @@ export default React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
tryContinue: function() {
|
||||
if (this.refs.stageComponent && this.refs.stageComponent.tryContinue) {
|
||||
this.refs.stageComponent.tryContinue();
|
||||
}
|
||||
},
|
||||
|
||||
_authStateUpdated: function(stageType, stageState) {
|
||||
const oldStage = this.state.authStage;
|
||||
this.setState({
|
||||
|
@ -192,6 +203,7 @@ export default React.createClass({
|
|||
fail={this._onAuthStageFailed}
|
||||
setEmailSid={this._setEmailSid}
|
||||
makeRegistrationUrl={this.props.makeRegistrationUrl}
|
||||
showContinue={!this.props.continueIsManaged}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -82,6 +82,8 @@ const SIMPLE_SETTINGS = [
|
|||
{ id: "TagPanel.disableTagPanel" },
|
||||
{ id: "enableWidgetScreenshots" },
|
||||
{ id: "RoomSubList.showEmpty" },
|
||||
{ id: "pinMentionedRooms" },
|
||||
{ id: "pinUnreadRooms" },
|
||||
{ id: "showDeveloperTools" },
|
||||
];
|
||||
|
||||
|
|
|
@ -84,7 +84,10 @@ module.exports = React.createClass({
|
|||
// letting you do that login type
|
||||
this._stepRendererMap = {
|
||||
'm.login.password': this._renderPasswordStep,
|
||||
'm.login.cas': this._renderCasStep,
|
||||
|
||||
// CAS and SSO are the same thing, modulo the url we link to
|
||||
'm.login.cas': () => this._renderSsoStep(this._loginLogic.getSsoLoginUrl("cas")),
|
||||
'm.login.sso': () => this._renderSsoStep(this._loginLogic.getSsoLoginUrl("sso")),
|
||||
};
|
||||
|
||||
this._initLoginLogic();
|
||||
|
@ -186,10 +189,6 @@ module.exports = React.createClass({
|
|||
}).done();
|
||||
},
|
||||
|
||||
onCasLogin: function() {
|
||||
this._loginLogic.redirectToCas();
|
||||
},
|
||||
|
||||
_onLoginAsGuestClick: function() {
|
||||
const self = this;
|
||||
self.setState({
|
||||
|
@ -403,10 +402,9 @@ module.exports = React.createClass({
|
|||
);
|
||||
},
|
||||
|
||||
_renderCasStep: function() {
|
||||
const CasLogin = sdk.getComponent('login.CasLogin');
|
||||
_renderSsoStep: function(url) {
|
||||
return (
|
||||
<CasLogin onSubmit={this.onCasLogin} />
|
||||
<a href={url} className="mx_Login_sso_link">{ _t('Sign in with single sign-on') }</a>
|
||||
);
|
||||
},
|
||||
|
||||
|
|
71
src/components/views/dialogs/CryptoStoreTooNewDialog.js
Normal file
71
src/components/views/dialogs/CryptoStoreTooNewDialog.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Copyright 2018 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 React from 'react';
|
||||
import sdk from '../../../index';
|
||||
import dis from '../../../dispatcher';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Modal from '../../../Modal';
|
||||
|
||||
export default (props) => {
|
||||
const _onLogoutClicked = () => {
|
||||
const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
|
||||
Modal.createTrackedDialog('Logout e2e db too new', '', QuestionDialog, {
|
||||
title: _t("Sign out"),
|
||||
description: _t(
|
||||
"To avoid losing your chat history, you must export your room keys " +
|
||||
"before logging out. You will need to go back to the newer version of " +
|
||||
"Riot to do this",
|
||||
),
|
||||
button: _t("Sign out"),
|
||||
focus: false,
|
||||
onFinished: (doLogout) => {
|
||||
if (doLogout) {
|
||||
dis.dispatch({action: 'logout'});
|
||||
props.onFinished();
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const description =
|
||||
_t("You've previously used a newer version of Riot on %(host)s. " +
|
||||
"To use this version again with end to end encryption, you will " +
|
||||
"need to sign out and back in again. ",
|
||||
{host: props.host},
|
||||
);
|
||||
|
||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
|
||||
return (<BaseDialog className="mx_CryptoStoreTooNewDialog"
|
||||
contentId='mx_Dialog_content'
|
||||
title={_t("Incompatible Database")}
|
||||
hasCancel={false}
|
||||
onFinished={props.onFinished}
|
||||
>
|
||||
<div className="mx_Dialog_content" id='mx_Dialog_content'>
|
||||
{ description }
|
||||
</div>
|
||||
<DialogButtons primaryButton={_t('Continue With Encryption Disabled')}
|
||||
hasCancel={false}
|
||||
onPrimaryButtonClick={props.onFinished}
|
||||
>
|
||||
<button onClick={_onLogoutClicked} >
|
||||
{ _t('Sign out') }
|
||||
</button>
|
||||
</DialogButtons>
|
||||
</BaseDialog>);
|
||||
};
|
|
@ -101,6 +101,9 @@ export default React.createClass({
|
|||
},
|
||||
|
||||
onSubmit: function(ev) {
|
||||
if (this.refs.uiAuth) {
|
||||
this.refs.uiAuth.tryContinue();
|
||||
}
|
||||
this.setState({
|
||||
doingUIAuth: true,
|
||||
});
|
||||
|
@ -217,6 +220,8 @@ export default React.createClass({
|
|||
onAuthFinished={this._onUIAuthFinished}
|
||||
inputs={{}}
|
||||
poll={true}
|
||||
ref="uiAuth"
|
||||
continueIsManaged={true}
|
||||
/>;
|
||||
}
|
||||
const inputClasses = classnames({
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
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 React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { _t } from '../../../languageHandler';
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'CasLogin',
|
||||
|
||||
propTypes: {
|
||||
onSubmit: PropTypes.func, // fn()
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.props.onSubmit}>{ _t("Sign in with CAS") }</button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
});
|
|
@ -222,6 +222,7 @@ export const TermsAuthEntry = React.createClass({
|
|||
stageParams: PropTypes.object.isRequired,
|
||||
errorText: PropTypes.string,
|
||||
busy: PropTypes.bool,
|
||||
showContinue: PropTypes.bool,
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
|
@ -275,19 +276,30 @@ export const TermsAuthEntry = React.createClass({
|
|||
});
|
||||
},
|
||||
|
||||
_trySubmit: function(policyId) {
|
||||
tryContinue: function() {
|
||||
this._trySubmit();
|
||||
},
|
||||
|
||||
_togglePolicy: function(policyId) {
|
||||
const newToggles = {};
|
||||
let allChecked = true;
|
||||
for (const policy of this.state.policies) {
|
||||
let checked = this.state.toggledPolicies[policy.id];
|
||||
if (policy.id === policyId) checked = !checked;
|
||||
|
||||
newToggles[policy.id] = checked;
|
||||
}
|
||||
this.setState({"toggledPolicies": newToggles});
|
||||
},
|
||||
|
||||
_trySubmit: function() {
|
||||
let allChecked = true;
|
||||
for (const policy of this.state.policies) {
|
||||
let checked = this.state.toggledPolicies[policy.id];
|
||||
allChecked = allChecked && checked;
|
||||
}
|
||||
|
||||
this.setState({"toggledPolicies": newToggles});
|
||||
if (allChecked) this.props.submitAuthDict({type: TermsAuthEntry.LOGIN_TYPE});
|
||||
else this.setState({errorText: _t("Please review and accept all of the homeserver's policies")});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -303,27 +315,35 @@ export const TermsAuthEntry = React.createClass({
|
|||
allChecked = allChecked && checked;
|
||||
|
||||
checkboxes.push(
|
||||
<label key={"policy_checkbox_" + policy.id}>
|
||||
<input type="checkbox" onClick={() => this._trySubmit(policy.id)} checked={checked} />
|
||||
<label key={"policy_checkbox_" + policy.id} className="mx_InteractiveAuthEntryComponents_termsPolicy">
|
||||
<input type="checkbox" onClick={() => this._togglePolicy(policy.id)} checked={checked} />
|
||||
<a href={policy.url} target="_blank" rel="noopener">{ policy.name }</a>
|
||||
</label>,
|
||||
);
|
||||
}
|
||||
|
||||
let errorSection;
|
||||
if (this.props.errorText) {
|
||||
if (this.props.errorText || this.state.errorText) {
|
||||
errorSection = (
|
||||
<div className="error" role="alert">
|
||||
{ this.props.errorText }
|
||||
{ this.props.errorText || this.state.errorText }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let submitButton;
|
||||
if (this.props.showContinue !== false) {
|
||||
// XXX: button classes
|
||||
submitButton = <button className="mx_InteractiveAuthEntryComponents_termsSubmit mx_UserSettings_button"
|
||||
onClick={this._trySubmit} disabled={!allChecked}>{_t("Accept")}</button>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{_t("Please review and accept the policies of this homeserver:")}</p>
|
||||
{ checkboxes }
|
||||
{ errorSection }
|
||||
{ submitButton }
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
@ -278,6 +278,7 @@ export default class MImageBody extends React.Component {
|
|||
|
||||
let img = null;
|
||||
let placeholder = null;
|
||||
let gifLabel = null;
|
||||
|
||||
// e2e image hasn't been decrypted yet
|
||||
if (content.file !== undefined && this.state.decryptedUrl === null) {
|
||||
|
@ -302,11 +303,14 @@ export default class MImageBody extends React.Component {
|
|||
onMouseLeave={this.onImageLeave} />;
|
||||
}
|
||||
|
||||
if (this._isGif() && !SettingsStore.getValue("autoplayGifsAndVideos") && !this.state.hover) {
|
||||
gifLabel = <p className="mx_MImageBody_gifLabel">GIF</p>;
|
||||
}
|
||||
|
||||
const thumbnail = (
|
||||
<div className="mx_MImageBody_thumbnail_container" style={{ maxHeight: maxHeight + "px" }} >
|
||||
{ /* Calculate aspect ratio, using %padding will size _container correctly */ }
|
||||
<div style={{ paddingBottom: (100 * infoHeight / infoWidth) + '%' }} />
|
||||
|
||||
{ showPlaceholder &&
|
||||
<div className="mx_MImageBody_thumbnail" style={{
|
||||
// Constrain width here so that spinner appears central to the loaded thumbnail
|
||||
|
@ -320,6 +324,7 @@ export default class MImageBody extends React.Component {
|
|||
|
||||
<div style={{display: !showPlaceholder ? undefined : 'none'}}>
|
||||
{ img }
|
||||
{ gifLabel }
|
||||
</div>
|
||||
|
||||
{ this.state.hover && this.getTooltip() }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue