Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into t3chguy/fix/15178
Conflicts: src/settings/Settings.ts src/settings/UIFeature.tspull/21833/head
commit
c904b4f416
|
@ -18,6 +18,12 @@ limitations under the License.
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
|
&.mx_WelcomePage_registrationDisabled {
|
||||||
|
.mx_ButtonCreateAccount {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Welcome .mx_AuthBody_language {
|
.mx_Welcome .mx_AuthBody_language {
|
||||||
|
|
|
@ -71,9 +71,12 @@ limitations under the License.
|
||||||
margin-right: 64px;
|
margin-right: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mx_ShareDialog_qrcode_container + .mx_ShareDialog_social_container {
|
||||||
|
width: 299px;
|
||||||
|
}
|
||||||
|
|
||||||
.mx_ShareDialog_social_container {
|
.mx_ShareDialog_social_container {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 299px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_ShareDialog_social_icon {
|
.mx_ShareDialog_social_icon {
|
||||||
|
|
|
@ -1947,7 +1947,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const fragmentAfterLogin = this.getFragmentAfterLogin();
|
const fragmentAfterLogin = this.getFragmentAfterLogin();
|
||||||
let view;
|
let view = null;
|
||||||
|
|
||||||
if (this.state.view === Views.LOADING) {
|
if (this.state.view === Views.LOADING) {
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
const Spinner = sdk.getComponent('elements.Spinner');
|
||||||
|
@ -2026,7 +2026,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
} else if (this.state.view === Views.WELCOME) {
|
} else if (this.state.view === Views.WELCOME) {
|
||||||
const Welcome = sdk.getComponent('auth.Welcome');
|
const Welcome = sdk.getComponent('auth.Welcome');
|
||||||
view = <Welcome />;
|
view = <Welcome />;
|
||||||
} else if (this.state.view === Views.REGISTER) {
|
} else if (this.state.view === Views.REGISTER && SettingsStore.getValue(UIFeature.Registration)) {
|
||||||
const Registration = sdk.getComponent('structures.auth.Registration');
|
const Registration = sdk.getComponent('structures.auth.Registration');
|
||||||
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
const email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail;
|
||||||
view = (
|
view = (
|
||||||
|
@ -2044,7 +2044,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
{...this.getServerProperties()}
|
{...this.getServerProperties()}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.FORGOT_PASSWORD) {
|
} else if (this.state.view === Views.FORGOT_PASSWORD && SettingsStore.getValue(UIFeature.PasswordReset)) {
|
||||||
const ForgotPassword = sdk.getComponent('structures.auth.ForgotPassword');
|
const ForgotPassword = sdk.getComponent('structures.auth.ForgotPassword');
|
||||||
view = (
|
view = (
|
||||||
<ForgotPassword
|
<ForgotPassword
|
||||||
|
@ -2055,6 +2055,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.state.view === Views.LOGIN) {
|
} else if (this.state.view === Views.LOGIN) {
|
||||||
|
const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset);
|
||||||
const Login = sdk.getComponent('structures.auth.Login');
|
const Login = sdk.getComponent('structures.auth.Login');
|
||||||
view = (
|
view = (
|
||||||
<Login
|
<Login
|
||||||
|
@ -2063,7 +2064,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
onRegisterClick={this.onRegisterClick}
|
onRegisterClick={this.onRegisterClick}
|
||||||
fallbackHsUrl={this.getFallbackHsUrl()}
|
fallbackHsUrl={this.getFallbackHsUrl()}
|
||||||
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
defaultDeviceDisplayName={this.props.defaultDeviceDisplayName}
|
||||||
onForgotPasswordClick={this.onForgotPasswordClick}
|
onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined}
|
||||||
onServerConfigChange={this.onServerConfigChange}
|
onServerConfigChange={this.onServerConfigChange}
|
||||||
fragmentAfterLogin={fragmentAfterLogin}
|
fragmentAfterLogin={fragmentAfterLogin}
|
||||||
{...this.getServerProperties()}
|
{...this.getServerProperties()}
|
||||||
|
|
|
@ -28,6 +28,8 @@ import classNames from "classnames";
|
||||||
import AuthPage from "../../views/auth/AuthPage";
|
import AuthPage from "../../views/auth/AuthPage";
|
||||||
import SSOButton from "../../views/elements/SSOButton";
|
import SSOButton from "../../views/elements/SSOButton";
|
||||||
import PlatformPeg from '../../../PlatformPeg';
|
import PlatformPeg from '../../../PlatformPeg';
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import {UIFeature} from "../../../settings/UIFeature";
|
||||||
|
|
||||||
// For validating phone numbers without country codes
|
// For validating phone numbers without country codes
|
||||||
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
|
const PHONE_NUMBER_REGEX = /^[0-9()\-\s]*$/;
|
||||||
|
@ -679,7 +681,7 @@ export default class LoginComponent extends React.Component {
|
||||||
{_t("If you've joined lots of rooms, this might take a while")}
|
{_t("If you've joined lots of rooms, this might take a while")}
|
||||||
</div> }
|
</div> }
|
||||||
</div>;
|
</div>;
|
||||||
} else {
|
} else if (SettingsStore.getValue(UIFeature.Registration)) {
|
||||||
footer = (
|
footer = (
|
||||||
<a className="mx_AuthBody_changeFlow" onClick={this.onTryRegisterClick} href="#">
|
<a className="mx_AuthBody_changeFlow" onClick={this.onTryRegisterClick} href="#">
|
||||||
{ _t('Create account') }
|
{ _t('Create account') }
|
||||||
|
|
|
@ -15,10 +15,14 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import SdkConfig from '../../../SdkConfig';
|
import SdkConfig from '../../../SdkConfig';
|
||||||
import AuthPage from "./AuthPage";
|
import AuthPage from "./AuthPage";
|
||||||
import {_td} from "../../../languageHandler";
|
import {_td} from "../../../languageHandler";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import {UIFeature} from "../../../settings/UIFeature";
|
||||||
|
|
||||||
// translatable strings for Welcome pages
|
// translatable strings for Welcome pages
|
||||||
_td("Sign in with SSO");
|
_td("Sign in with SSO");
|
||||||
|
@ -39,7 +43,9 @@ export default class Welcome extends React.PureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthPage>
|
<AuthPage>
|
||||||
<div className="mx_Welcome">
|
<div className={classNames("mx_Welcome", {
|
||||||
|
mx_WelcomePage_registrationDisabled: !SettingsStore.getValue(UIFeature.Registration),
|
||||||
|
})}>
|
||||||
<EmbeddedPage
|
<EmbeddedPage
|
||||||
className="mx_WelcomePage"
|
className="mx_WelcomePage"
|
||||||
url={pageUrl}
|
url={pageUrl}
|
||||||
|
|
|
@ -38,6 +38,8 @@ import {Action} from "../../../dispatcher/actions";
|
||||||
import {DefaultTagID} from "../../../stores/room-list/models";
|
import {DefaultTagID} from "../../../stores/room-list/models";
|
||||||
import RoomListStore from "../../../stores/room-list/RoomListStore";
|
import RoomListStore from "../../../stores/room-list/RoomListStore";
|
||||||
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
|
import {CommunityPrototypeStore} from "../../../stores/CommunityPrototypeStore";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import {UIFeature} from "../../../settings/UIFeature";
|
||||||
|
|
||||||
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
@ -549,7 +551,7 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
if (this.state.filterText.startsWith('@')) {
|
if (this.state.filterText.startsWith('@')) {
|
||||||
// Assume mxid
|
// Assume mxid
|
||||||
newMember = new DirectoryMember({user_id: this.state.filterText, display_name: null, avatar_url: null});
|
newMember = new DirectoryMember({user_id: this.state.filterText, display_name: null, avatar_url: null});
|
||||||
} else {
|
} else if (SettingsStore.getValue(UIFeature.IdentityServer)) {
|
||||||
// Assume email
|
// Assume email
|
||||||
newMember = new ThreepidMember(this.state.filterText);
|
newMember = new ThreepidMember(this.state.filterText);
|
||||||
}
|
}
|
||||||
|
@ -734,7 +736,7 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
this.setState({tryingIdentityServer: true});
|
this.setState({tryingIdentityServer: true});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (term.indexOf('@') > 0 && Email.looksValid(term)) {
|
if (term.indexOf('@') > 0 && Email.looksValid(term) && SettingsStore.getValue(UIFeature.IdentityServer)) {
|
||||||
// Start off by suggesting the plain email while we try and resolve it
|
// Start off by suggesting the plain email while we try and resolve it
|
||||||
// to a real account.
|
// to a real account.
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -1037,7 +1039,9 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderIdentityServerWarning() {
|
_renderIdentityServerWarning() {
|
||||||
if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer) {
|
if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer ||
|
||||||
|
!SettingsStore.getValue(UIFeature.IdentityServer)
|
||||||
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1086,22 +1090,38 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
let buttonText;
|
let buttonText;
|
||||||
let goButtonFn;
|
let goButtonFn;
|
||||||
|
|
||||||
|
const identityServersEnabled = SettingsStore.getValue(UIFeature.IdentityServer);
|
||||||
|
|
||||||
const userId = MatrixClientPeg.get().getUserId();
|
const userId = MatrixClientPeg.get().getUserId();
|
||||||
if (this.props.kind === KIND_DM) {
|
if (this.props.kind === KIND_DM) {
|
||||||
title = _t("Direct Messages");
|
title = _t("Direct Messages");
|
||||||
helpText = _t(
|
|
||||||
"Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
if (identityServersEnabled) {
|
||||||
{},
|
helpText = _t(
|
||||||
{userId: () => {
|
"Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
||||||
return <a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>;
|
{},
|
||||||
}},
|
{userId: () => {
|
||||||
);
|
return (
|
||||||
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>
|
||||||
|
);
|
||||||
|
}},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
helpText = _t(
|
||||||
|
"Start a conversation with someone using their name or username (like <userId/>).",
|
||||||
|
{},
|
||||||
|
{userId: () => {
|
||||||
|
return (
|
||||||
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>
|
||||||
|
);
|
||||||
|
}},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
|
if (CommunityPrototypeStore.instance.getSelectedCommunityId()) {
|
||||||
const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
|
const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName();
|
||||||
helpText = _t(
|
const inviteText = _t("This won't invite them to %(communityName)s. " +
|
||||||
"Start a conversation with someone using their name, username (like <userId/>) or email address. " +
|
"To invite someone to %(communityName)s, click <a>here</a>",
|
||||||
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click " +
|
|
||||||
"<a>here</a>.",
|
|
||||||
{communityName}, {
|
{communityName}, {
|
||||||
userId: () => {
|
userId: () => {
|
||||||
return (
|
return (
|
||||||
|
@ -1122,21 +1142,40 @@ export default class InviteDialog extends React.PureComponent {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
helpText = <React.Fragment>
|
||||||
|
{ helpText } {inviteText}
|
||||||
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
buttonText = _t("Go");
|
buttonText = _t("Go");
|
||||||
goButtonFn = this._startDm;
|
goButtonFn = this._startDm;
|
||||||
} else { // KIND_INVITE
|
} else { // KIND_INVITE
|
||||||
title = _t("Invite to this room");
|
title = _t("Invite to this room");
|
||||||
helpText = _t(
|
|
||||||
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
|
if (identityServersEnabled) {
|
||||||
{},
|
helpText = _t(
|
||||||
{
|
"Invite someone using their name, username (like <userId/>), email address or " +
|
||||||
userId: () =>
|
"<a>share this room</a>.",
|
||||||
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>,
|
{},
|
||||||
a: (sub) =>
|
{
|
||||||
<a href={makeRoomPermalink(this.props.roomId)} rel="noreferrer noopener" target="_blank">{sub}</a>,
|
userId: () =>
|
||||||
},
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>,
|
||||||
);
|
a: (sub) =>
|
||||||
|
<a href={makeRoomPermalink(this.props.roomId)} rel="noreferrer noopener" target="_blank">{sub}</a>,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
helpText = _t(
|
||||||
|
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
userId: () =>
|
||||||
|
<a href={makeUserPermalink(userId)} rel="noreferrer noopener" target="_blank">{userId}</a>,
|
||||||
|
a: (sub) =>
|
||||||
|
<a href={makeRoomPermalink(this.props.roomId)} rel="noreferrer noopener" target="_blank">{sub}</a>,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
buttonText = _t("Invite");
|
buttonText = _t("Invite");
|
||||||
goButtonFn = this._inviteUsers;
|
goButtonFn = this._inviteUsers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,8 @@ import {copyPlaintext, selectText} from "../../../utils/strings";
|
||||||
import StyledCheckbox from '../elements/StyledCheckbox';
|
import StyledCheckbox from '../elements/StyledCheckbox';
|
||||||
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
|
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
|
||||||
import { IDialogProps } from "./IDialogProps";
|
import { IDialogProps } from "./IDialogProps";
|
||||||
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
|
import {UIFeature} from "../../../settings/UIFeature";
|
||||||
|
|
||||||
const socials = [
|
const socials = [
|
||||||
{
|
{
|
||||||
|
@ -197,6 +199,35 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
||||||
const matrixToUrl = this.getUrl();
|
const matrixToUrl = this.getUrl();
|
||||||
const encodedUrl = encodeURIComponent(matrixToUrl);
|
const encodedUrl = encodeURIComponent(matrixToUrl);
|
||||||
|
|
||||||
|
const showQrCode = SettingsStore.getValue(UIFeature.ShareQRCode);
|
||||||
|
const showSocials = SettingsStore.getValue(UIFeature.ShareSocial);
|
||||||
|
|
||||||
|
let qrSocialSection;
|
||||||
|
if (showQrCode || showSocials) {
|
||||||
|
qrSocialSection = <>
|
||||||
|
<hr />
|
||||||
|
<div className="mx_ShareDialog_split">
|
||||||
|
{ showQrCode && <div className="mx_ShareDialog_qrcode_container">
|
||||||
|
<QRCode data={matrixToUrl} width={256} />
|
||||||
|
</div> }
|
||||||
|
{ showSocials && <div className="mx_ShareDialog_social_container">
|
||||||
|
{ socials.map((social) => (
|
||||||
|
<a
|
||||||
|
rel="noreferrer noopener"
|
||||||
|
target="_blank"
|
||||||
|
key={social.name}
|
||||||
|
title={social.name}
|
||||||
|
href={social.url(encodedUrl)}
|
||||||
|
className="mx_ShareDialog_social_icon"
|
||||||
|
>
|
||||||
|
<img src={social.img} alt={social.name} height={64} width={64} />
|
||||||
|
</a>
|
||||||
|
)) }
|
||||||
|
</div> }
|
||||||
|
</div>
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
|
||||||
return <BaseDialog
|
return <BaseDialog
|
||||||
title={title}
|
title={title}
|
||||||
|
@ -220,27 +251,7 @@ export default class ShareDialog extends React.PureComponent<IProps, IState> {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{ checkbox }
|
{ checkbox }
|
||||||
<hr />
|
{ qrSocialSection }
|
||||||
|
|
||||||
<div className="mx_ShareDialog_split">
|
|
||||||
<div className="mx_ShareDialog_qrcode_container">
|
|
||||||
<QRCode data={matrixToUrl} width={256} />
|
|
||||||
</div>
|
|
||||||
<div className="mx_ShareDialog_social_container">
|
|
||||||
{ socials.map((social) => (
|
|
||||||
<a
|
|
||||||
rel="noreferrer noopener"
|
|
||||||
target="_blank"
|
|
||||||
key={social.name}
|
|
||||||
title={social.name}
|
|
||||||
href={social.url(encodedUrl)}
|
|
||||||
className="mx_ShareDialog_social_icon"
|
|
||||||
>
|
|
||||||
<img src={social.img} alt={social.name} height={64} width={64} />
|
|
||||||
</a>
|
|
||||||
)) }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</BaseDialog>;
|
</BaseDialog>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -386,17 +386,31 @@ export default class GeneralUserSettingsTab extends React.Component {
|
||||||
width="18" height="18" alt={_t("Warning")} />
|
width="18" height="18" alt={_t("Warning")} />
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
let accountManagementSection;
|
||||||
|
if (SettingsStore.getValue(UIFeature.Deactivate)) {
|
||||||
|
accountManagementSection = <>
|
||||||
|
<div className="mx_SettingsTab_heading">{_t("Deactivate account")}</div>
|
||||||
|
{this._renderManagementSection()}
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let discoverySection;
|
||||||
|
if (SettingsStore.getValue(UIFeature.IdentityServer)) {
|
||||||
|
discoverySection = <>
|
||||||
|
<div className="mx_SettingsTab_heading">{discoWarning} {_t("Discovery")}</div>
|
||||||
|
{this._renderDiscoverySection()}
|
||||||
|
</>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_SettingsTab">
|
<div className="mx_SettingsTab">
|
||||||
<div className="mx_SettingsTab_heading">{_t("General")}</div>
|
<div className="mx_SettingsTab_heading">{_t("General")}</div>
|
||||||
{this._renderProfileSection()}
|
{this._renderProfileSection()}
|
||||||
{this._renderAccountSection()}
|
{this._renderAccountSection()}
|
||||||
{this._renderLanguageSection()}
|
{this._renderLanguageSection()}
|
||||||
<div className="mx_SettingsTab_heading">{discoWarning} {_t("Discovery")}</div>
|
{ discoverySection }
|
||||||
{this._renderDiscoverySection()}
|
|
||||||
{this._renderIntegrationManagerSection() /* Has its own title */}
|
{this._renderIntegrationManagerSection() /* Has its own title */}
|
||||||
<div className="mx_SettingsTab_heading">{_t("Deactivate account")}</div>
|
{ accountManagementSection }
|
||||||
{this._renderManagementSection()}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -832,9 +832,9 @@
|
||||||
"Account management": "Account management",
|
"Account management": "Account management",
|
||||||
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
|
"Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!",
|
||||||
"Deactivate Account": "Deactivate Account",
|
"Deactivate Account": "Deactivate Account",
|
||||||
"General": "General",
|
|
||||||
"Discovery": "Discovery",
|
|
||||||
"Deactivate account": "Deactivate account",
|
"Deactivate account": "Deactivate account",
|
||||||
|
"Discovery": "Discovery",
|
||||||
|
"General": "General",
|
||||||
"Legal": "Legal",
|
"Legal": "Legal",
|
||||||
"Credits": "Credits",
|
"Credits": "Credits",
|
||||||
"For help with using %(brand)s, click <a>here</a>.": "For help with using %(brand)s, click <a>here</a>.",
|
"For help with using %(brand)s, click <a>here</a>.": "For help with using %(brand)s, click <a>here</a>.",
|
||||||
|
@ -1732,9 +1732,11 @@
|
||||||
"Recently Direct Messaged": "Recently Direct Messaged",
|
"Recently Direct Messaged": "Recently Direct Messaged",
|
||||||
"Direct Messages": "Direct Messages",
|
"Direct Messages": "Direct Messages",
|
||||||
"Start a conversation with someone using their name, username (like <userId/>) or email address.": "Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
"Start a conversation with someone using their name, username (like <userId/>) or email address.": "Start a conversation with someone using their name, username (like <userId/>) or email address.",
|
||||||
"Start a conversation with someone using their name, username (like <userId/>) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>.": "Start a conversation with someone using their name, username (like <userId/>) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>.",
|
"Start a conversation with someone using their name or username (like <userId/>).": "Start a conversation with someone using their name or username (like <userId/>).",
|
||||||
|
"This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click <a>here</a>",
|
||||||
"Go": "Go",
|
"Go": "Go",
|
||||||
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
|
"Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>), email address or <a>share this room</a>.",
|
||||||
|
"Invite someone using their name, username (like <userId/>) or <a>share this room</a>.": "Invite someone using their name, username (like <userId/>) or <a>share this room</a>.",
|
||||||
"a new master key signature": "a new master key signature",
|
"a new master key signature": "a new master key signature",
|
||||||
"a new cross-signing key signature": "a new cross-signing key signature",
|
"a new cross-signing key signature": "a new cross-signing key signature",
|
||||||
"a device cross-signing signature": "a device cross-signing signature",
|
"a device cross-signing signature": "a device cross-signing signature",
|
||||||
|
|
|
@ -631,6 +631,30 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
||||||
supportedLevels: LEVELS_UI_FEATURE,
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
[UIFeature.Registration]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
[UIFeature.PasswordReset]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
[UIFeature.Deactivate]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
[UIFeature.ShareQRCode]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
[UIFeature.ShareSocial]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
[UIFeature.IdentityServer]: {
|
||||||
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
[UIFeature.Flair]: {
|
[UIFeature.Flair]: {
|
||||||
supportedLevels: LEVELS_UI_FEATURE,
|
supportedLevels: LEVELS_UI_FEATURE,
|
||||||
default: true,
|
default: true,
|
||||||
|
|
|
@ -20,5 +20,11 @@ export enum UIFeature {
|
||||||
Widgets = "UIFeature.widgets",
|
Widgets = "UIFeature.widgets",
|
||||||
Voip = "UIFeature.voip",
|
Voip = "UIFeature.voip",
|
||||||
Feedback = "UIFeature.feedback",
|
Feedback = "UIFeature.feedback",
|
||||||
|
Registration = "UIFeature.registration",
|
||||||
|
PasswordReset = "UIFeature.passwordReset",
|
||||||
|
Deactivate = "UIFeature.deactivate",
|
||||||
|
ShareQRCode = "UIFeature.shareQrCode",
|
||||||
|
ShareSocial = "UIFeature.shareSocial",
|
||||||
|
IdentityServer = "UIFeature.identityServer",
|
||||||
Flair = "UIFeature.flair",
|
Flair = "UIFeature.flair",
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {Store} from 'flux/utils';
|
import {Store} from 'flux/utils';
|
||||||
|
import {MatrixError} from "matrix-js-sdk/src/http-api";
|
||||||
|
|
||||||
import dis from '../dispatcher/dispatcher';
|
import dis from '../dispatcher/dispatcher';
|
||||||
import {MatrixClientPeg} from '../MatrixClientPeg';
|
import {MatrixClientPeg} from '../MatrixClientPeg';
|
||||||
|
@ -26,6 +27,9 @@ import Modal from '../Modal';
|
||||||
import { _t } from '../languageHandler';
|
import { _t } from '../languageHandler';
|
||||||
import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache';
|
import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache';
|
||||||
import {ActionPayload} from "../dispatcher/payloads";
|
import {ActionPayload} from "../dispatcher/payloads";
|
||||||
|
import {retry} from "../utils/promise";
|
||||||
|
|
||||||
|
const NUM_JOIN_RETRY = 5;
|
||||||
|
|
||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
// Whether we're joining the currently viewed room (see isJoining())
|
// Whether we're joining the currently viewed room (see isJoining())
|
||||||
|
@ -259,24 +263,32 @@ class RoomViewStore extends Store<ActionPayload> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private joinRoom(payload: ActionPayload) {
|
private async joinRoom(payload: ActionPayload) {
|
||||||
this.setState({
|
this.setState({
|
||||||
joining: true,
|
joining: true,
|
||||||
});
|
});
|
||||||
MatrixClientPeg.get().joinRoom(
|
|
||||||
this.state.roomAlias || this.state.roomId, payload.opts,
|
const cli = MatrixClientPeg.get();
|
||||||
).then(() => {
|
const address = this.state.roomAlias || this.state.roomId;
|
||||||
|
try {
|
||||||
|
await retry<void, MatrixError>(() => cli.joinRoom(address, payload.opts), NUM_JOIN_RETRY, (err) => {
|
||||||
|
// if we received a Gateway timeout then retry
|
||||||
|
return err.httpStatus === 504;
|
||||||
|
});
|
||||||
|
|
||||||
// We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not
|
// We do *not* clear the 'joining' flag because the Room object and/or our 'joined' member event may not
|
||||||
// have come down the sync stream yet, and that's the point at which we'd consider the user joined to the
|
// have come down the sync stream yet, and that's the point at which we'd consider the user joined to the
|
||||||
// room.
|
// room.
|
||||||
dis.dispatch({ action: 'join_room_ready' });
|
dis.dispatch({ action: 'join_room_ready' });
|
||||||
}, (err) => {
|
} catch (err) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'join_room_error',
|
action: 'join_room_error',
|
||||||
err: err,
|
err: err,
|
||||||
});
|
});
|
||||||
|
|
||||||
let msg = err.message ? err.message : JSON.stringify(err);
|
let msg = err.message ? err.message : JSON.stringify(err);
|
||||||
console.log("Failed to join room:", msg);
|
console.log("Failed to join room:", msg);
|
||||||
|
|
||||||
if (err.name === "ConnectionError") {
|
if (err.name === "ConnectionError") {
|
||||||
msg = _t("There was an error joining the room");
|
msg = _t("There was an error joining the room");
|
||||||
} else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') {
|
} else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') {
|
||||||
|
@ -296,12 +308,13 @@ class RoomViewStore extends Store<ActionPayload> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
||||||
Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, {
|
||||||
title: _t("Failed to join room"),
|
title: _t("Failed to join room"),
|
||||||
description: msg,
|
description: msg,
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getInvitingUserId(roomId: string): string {
|
private getInvitingUserId(roomId: string): string {
|
||||||
|
|
|
@ -68,3 +68,21 @@ export function allSettled<T>(promises: Promise<T>[]): Promise<Array<ISettledFul
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper method to retry a Promise a given number of times or until a predicate fails
|
||||||
|
export async function retry<T, E extends Error>(fn: () => Promise<T>, num: number, predicate?: (e: E) => boolean) {
|
||||||
|
let lastErr: E;
|
||||||
|
for (let i = 0; i < num; i++) {
|
||||||
|
try {
|
||||||
|
const v = await fn();
|
||||||
|
// If `await fn()` throws then we won't reach here
|
||||||
|
return v;
|
||||||
|
} catch (err) {
|
||||||
|
if (predicate && !predicate(err)) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
lastErr = err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw lastErr;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue