From 229967aa33c0ffeef1cc59be3fc614d9efd95d48 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 14 Sep 2020 15:16:29 +0100 Subject: [PATCH 1/9] Retry joinRoom up to 5 times in the case of a 504 GATEWAY TIMEOUT --- src/stores/RoomViewStore.tsx | 25 +++++++++++++++++++------ src/utils/promise.ts | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index a0f0fb8f68..be1141fa1e 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -18,6 +18,7 @@ limitations under the License. import React from "react"; import {Store} from 'flux/utils'; +import {MatrixError} from "matrix-js-sdk/src/http-api"; import dis from '../dispatcher/dispatcher'; import {MatrixClientPeg} from '../MatrixClientPeg'; @@ -26,6 +27,9 @@ import Modal from '../Modal'; import { _t } from '../languageHandler'; import { getCachedRoomIDForAlias, storeRoomAliasInCache } from '../RoomAliasCache'; import {ActionPayload} from "../dispatcher/payloads"; +import {retry} from "../utils/promise"; + +const NUM_JOIN_RETRY = 5; const INITIAL_STATE = { // Whether we're joining the currently viewed room (see isJoining()) @@ -259,24 +263,32 @@ class RoomViewStore extends Store { }); } - private joinRoom(payload: ActionPayload) { + private async joinRoom(payload: ActionPayload) { this.setState({ joining: true, }); - MatrixClientPeg.get().joinRoom( - this.state.roomAlias || this.state.roomId, payload.opts, - ).then(() => { + + const cli = MatrixClientPeg.get(); + const address = this.state.roomAlias || this.state.roomId; + try { + await retry(() => 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 // have come down the sync stream yet, and that's the point at which we'd consider the user joined to the // room. dis.dispatch({ action: 'join_room_ready' }); - }, (err) => { + } catch (err) { dis.dispatch({ action: 'join_room_error', err: err, }); + let msg = err.message ? err.message : JSON.stringify(err); console.log("Failed to join room:", msg); + if (err.name === "ConnectionError") { msg = _t("There was an error joining the room"); } else if (err.errcode === 'M_INCOMPATIBLE_ROOM_VERSION') { @@ -296,12 +308,13 @@ class RoomViewStore extends Store { } } } + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Failed to join room', '', ErrorDialog, { title: _t("Failed to join room"), description: msg, }); - }); + } } private getInvitingUserId(roomId: string): string { diff --git a/src/utils/promise.ts b/src/utils/promise.ts index d3ae2c3d1b..f828ddfdaf 100644 --- a/src/utils/promise.ts +++ b/src/utils/promise.ts @@ -68,3 +68,21 @@ export function allSettled(promises: Promise[]): Promise(fn: () => Promise, 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; +} From d3c84e25f5287f7793f9faa723bf88520d6a861a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 16 Sep 2020 14:45:34 +0100 Subject: [PATCH 2/9] UI Feature Flag: Identity server --- src/components/views/dialogs/InviteDialog.js | 85 ++++++++++++++----- .../tabs/user/GeneralUserSettingsTab.js | 11 ++- src/settings/Settings.ts | 4 + src/settings/UIFeature.ts | 1 + 4 files changed, 76 insertions(+), 25 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index 80d8f1fc2c..3347a1381f 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -38,6 +38,8 @@ import {Action} from "../../../dispatcher/actions"; import {DefaultTagID} from "../../../stores/room-list/models"; import RoomListStore from "../../../stores/room-list/RoomListStore"; 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. /* eslint-disable camelcase */ @@ -549,7 +551,7 @@ export default class InviteDialog extends React.PureComponent { if (this.state.filterText.startsWith('@')) { // Assume mxid newMember = new DirectoryMember({user_id: this.state.filterText, display_name: null, avatar_url: null}); - } else { + } else if (SettingsStore.getValue(UIFeature.IdentityServer)) { // Assume email newMember = new ThreepidMember(this.state.filterText); } @@ -734,7 +736,7 @@ export default class InviteDialog extends React.PureComponent { this.setState({tryingIdentityServer: true}); 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 // to a real account. this.setState({ @@ -1037,7 +1039,9 @@ export default class InviteDialog extends React.PureComponent { } _renderIdentityServerWarning() { - if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer) { + if (!this.state.tryingIdentityServer || this.state.canUseIdentityServer || + !SettingsStore.getValue(UIFeature.IdentityServer) + ) { return null; } @@ -1086,22 +1090,41 @@ export default class InviteDialog extends React.PureComponent { let buttonText; let goButtonFn; + const identityServersEnabled = SettingsStore.getValue(UIFeature.IdentityServer); + const userId = MatrixClientPeg.get().getUserId(); if (this.props.kind === KIND_DM) { title = _t("Direct Messages"); - helpText = _t( + + if (identityServersEnabled) { + helpText = _t( "Start a conversation with someone using their name, username (like ) or email address.", {}, {userId: () => { - return {userId}; - }}, - ); + return ( + {userId} + ); + }}, + ); + } else { + helpText = _t( + "Start a conversation with someone using their name or username (like ).", + {}, + {userId: () => { + return ( + {userId} + ); + }}, + ); + } + if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName(); - helpText = _t( - "Start a conversation with someone using their name, username (like ) or email address. " + - "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click " + - "here.", + + helpText = + { helpText } {_t( + "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, " + + "click here", {communityName}, { userId: () => { return ( @@ -1120,23 +1143,39 @@ export default class InviteDialog extends React.PureComponent { >{sub} ); }, - }, - ); + })} + ; } buttonText = _t("Go"); goButtonFn = this._startDm; } else { // KIND_INVITE title = _t("Invite to this room"); - helpText = _t( - "Invite someone using their name, username (like ), email address or share this room.", - {}, - { - userId: () => - {userId}, - a: (sub) => - {sub}, - }, - ); + + if (identityServersEnabled) { + helpText = _t( + "Invite someone using their name, username (like ), email address or " + + "share this room.", + {}, + { + userId: () => + {userId}, + a: (sub) => + {sub}, + }, + ); + } else { + helpText = _t( + "Invite someone using their name, username (like ) or share this room.", + {}, + { + userId: () => + {userId}, + a: (sub) => + {sub}, + }, + ); + } + buttonText = _t("Invite"); goButtonFn = this._inviteUsers; } diff --git a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js index 42e12077f2..40fd57d311 100644 --- a/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/GeneralUserSettingsTab.js @@ -386,14 +386,21 @@ export default class GeneralUserSettingsTab extends React.Component { width="18" height="18" alt={_t("Warning")} /> : null; + let discoverySection; + if (SettingsStore.getValue(UIFeature.IdentityServer)) { + discoverySection = <> +
{discoWarning} {_t("Discovery")}
+ {this._renderDiscoverySection()} + ; + } + return (
{_t("General")}
{this._renderProfileSection()} {this._renderAccountSection()} {this._renderLanguageSection()} -
{discoWarning} {_t("Discovery")}
- {this._renderDiscoverySection()} + { discoverySection } {this._renderIntegrationManagerSection() /* Has its own title */}
{_t("Deactivate account")}
{this._renderManagementSection()} diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index b35fa3db13..a18d0f2187 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -622,4 +622,8 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_UI_FEATURE, default: true, }, + [UIFeature.IdentityServer]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, }; diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts index 99196e5d30..4de1d954d1 100644 --- a/src/settings/UIFeature.ts +++ b/src/settings/UIFeature.ts @@ -18,4 +18,5 @@ limitations under the License. export enum UIFeature { URLPreviews = "UIFeature.urlPreviews", Widgets = "UIFeature.widgets", + IdentityServer = "UIFeature.identityServer", } From 1c44f15d2d4457127852fc82ae8c2c8dc28156db Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 16 Sep 2020 14:54:30 +0100 Subject: [PATCH 3/9] i18n --- src/components/views/dialogs/InviteDialog.js | 6 +++--- src/i18n/strings/en_EN.json | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index 3347a1381f..86411c43da 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -1098,9 +1098,9 @@ export default class InviteDialog extends React.PureComponent { if (identityServersEnabled) { helpText = _t( - "Start a conversation with someone using their name, username (like ) or email address.", - {}, - {userId: () => { + "Start a conversation with someone using their name, username (like ) or email address.", + {}, + {userId: () => { return ( {userId} ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4414077005..7c5212444c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -832,8 +832,8 @@ "Account management": "Account management", "Deactivating your account is a permanent action - be careful!": "Deactivating your account is a permanent action - be careful!", "Deactivate Account": "Deactivate Account", - "General": "General", "Discovery": "Discovery", + "General": "General", "Deactivate account": "Deactivate account", "Legal": "Legal", "Credits": "Credits", @@ -1732,9 +1732,11 @@ "Recently Direct Messaged": "Recently Direct Messaged", "Direct Messages": "Direct Messages", "Start a conversation with someone using their name, username (like ) or email address.": "Start a conversation with someone using their name, username (like ) or email address.", - "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.", + "Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).", + "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", "Invite someone using their name, username (like ), email address or share this room.": "Invite someone using their name, username (like ), email address or share this room.", + "Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.", "a new master key signature": "a new master key signature", "a new cross-signing key signature": "a new cross-signing key signature", "a device cross-signing signature": "a device cross-signing signature", From aa25bad68955bdab93f8e83f6cb06cf66dde6c7a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 16 Sep 2020 14:57:46 +0100 Subject: [PATCH 4/9] tidy --- src/components/views/dialogs/InviteDialog.js | 51 ++++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index 86411c43da..f66de67a1d 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -1108,9 +1108,9 @@ export default class InviteDialog extends React.PureComponent { ); } else { helpText = _t( - "Start a conversation with someone using their name or username (like ).", - {}, - {userId: () => { + "Start a conversation with someone using their name or username (like ).", + {}, + {userId: () => { return ( {userId} ); @@ -1120,30 +1120,29 @@ export default class InviteDialog extends React.PureComponent { if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { const communityName = CommunityPrototypeStore.instance.getSelectedCommunityName(); - - helpText = - { helpText } {_t( - "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, " + - "click here", + const inviteText = _t("This won't invite them to %(communityName)s. " + + "To invite someone to %(communityName)s, click here", {communityName}, { - userId: () => { - return ( - {userId} - ); - }, - a: (sub) => { - return ( - {sub} - ); - }, - })} + userId: () => { + return ( + {userId} + ); + }, + a: (sub) => { + return ( + {sub} + ); + }, + }); + helpText = + { helpText } {inviteText} ; } buttonText = _t("Go"); From feb37878d85f723039d737f8ffdf451706c9b9f4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 16 Sep 2020 15:04:13 +0100 Subject: [PATCH 5/9] tidy --- src/components/views/dialogs/InviteDialog.js | 35 ++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/components/views/dialogs/InviteDialog.js b/src/components/views/dialogs/InviteDialog.js index f66de67a1d..73101056f3 100644 --- a/src/components/views/dialogs/InviteDialog.js +++ b/src/components/views/dialogs/InviteDialog.js @@ -1123,24 +1123,25 @@ export default class InviteDialog extends React.PureComponent { const inviteText = _t("This won't invite them to %(communityName)s. " + "To invite someone to %(communityName)s, click here", {communityName}, { - userId: () => { - return ( - {userId} - ); + userId: () => { + return ( + {userId} + ); + }, + a: (sub) => { + return ( + {sub} + ); + }, }, - a: (sub) => { - return ( - {sub} - ); - }, - }); + ); helpText = { helpText } {inviteText} ; From c11abb74e0020610f1af696b463d64a44e9ddaf9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 16 Sep 2020 16:06:17 +0100 Subject: [PATCH 6/9] UI Feature Flag: Share dialog QR code and social icons --- res/css/views/dialogs/_ShareDialog.scss | 5 +- src/components/views/dialogs/ShareDialog.tsx | 53 ++++++++++++-------- src/settings/Settings.ts | 8 +++ src/settings/UIFeature.ts | 2 + 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/res/css/views/dialogs/_ShareDialog.scss b/res/css/views/dialogs/_ShareDialog.scss index c343b872fd..ce3fdd021f 100644 --- a/res/css/views/dialogs/_ShareDialog.scss +++ b/res/css/views/dialogs/_ShareDialog.scss @@ -71,9 +71,12 @@ limitations under the License. margin-right: 64px; } +.mx_ShareDialog_qrcode_container + .mx_ShareDialog_social_container { + width: 299px; +} + .mx_ShareDialog_social_container { display: inline-block; - width: 299px; } .mx_ShareDialog_social_icon { diff --git a/src/components/views/dialogs/ShareDialog.tsx b/src/components/views/dialogs/ShareDialog.tsx index e849f7efe3..1569977d58 100644 --- a/src/components/views/dialogs/ShareDialog.tsx +++ b/src/components/views/dialogs/ShareDialog.tsx @@ -32,6 +32,8 @@ import {copyPlaintext, selectText} from "../../../utils/strings"; import StyledCheckbox from '../elements/StyledCheckbox'; import AccessibleTooltipButton from '../elements/AccessibleTooltipButton'; import { IDialogProps } from "./IDialogProps"; +import SettingsStore from "../../../settings/SettingsStore"; +import {UIFeature} from "../../../settings/UIFeature"; const socials = [ { @@ -197,6 +199,35 @@ export default class ShareDialog extends React.PureComponent { const matrixToUrl = this.getUrl(); const encodedUrl = encodeURIComponent(matrixToUrl); + const showQrCode = SettingsStore.getValue(UIFeature.ShareQRCode); + const showSocials = SettingsStore.getValue(UIFeature.ShareSocial); + + let qrSocialSection; + if (showQrCode || showSocials) { + qrSocialSection = <> +
+
+ { showQrCode &&
+ +
} + { showSocials &&
+ { socials.map((social) => ( + + {social.name} + + )) } +
} +
+ ; + } + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return { />
{ checkbox } -
- -
-
- -
-
- { socials.map((social) => ( - - {social.name} - - )) } -
-
+ { qrSocialSection } ; } diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index b35fa3db13..3731125f09 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -622,4 +622,12 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_UI_FEATURE, default: true, }, + [UIFeature.ShareQRCode]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, + [UIFeature.ShareSocial]: { + supportedLevels: LEVELS_UI_FEATURE, + default: true, + }, }; diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts index 99196e5d30..c4825dbbba 100644 --- a/src/settings/UIFeature.ts +++ b/src/settings/UIFeature.ts @@ -18,4 +18,6 @@ limitations under the License. export enum UIFeature { URLPreviews = "UIFeature.urlPreviews", Widgets = "UIFeature.widgets", + ShareQRCode = "UIFeature.shareQrCode", + ShareSocial = "UIFeature.shareSocial", } From d340dd58d1f4828f45dbf243d436bb21f32e1dca Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 17 Sep 2020 11:55:10 +0100 Subject: [PATCH 7/9] UI Feature Flag: Registration, Password Reset, Deactivate --- res/css/views/auth/_Welcome.scss | 6 ++++++ src/components/structures/MatrixChat.tsx | 10 ++++++---- src/components/structures/auth/Login.js | 4 +++- src/components/views/auth/Welcome.js | 8 +++++++- .../settings/tabs/user/GeneralUserSettingsTab.js | 11 +++++++++-- src/settings/Settings.ts | 12 ++++++++++++ src/settings/UIFeature.ts | 3 +++ 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/res/css/views/auth/_Welcome.scss b/res/css/views/auth/_Welcome.scss index 9043289184..f0e2b3de33 100644 --- a/res/css/views/auth/_Welcome.scss +++ b/res/css/views/auth/_Welcome.scss @@ -18,6 +18,12 @@ limitations under the License. display: flex; flex-direction: column; align-items: center; + + &.mx_WelcomePage_registrationDisabled { + .mx_ButtonCreateAccount { + display: none; + } + } } .mx_Welcome .mx_AuthBody_language { diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 1875d80fa4..26d1941574 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -79,6 +79,7 @@ import { SettingLevel } from "../../settings/SettingLevel"; import { leaveRoomBehaviour } from "../../utils/membership"; import CreateCommunityPrototypeDialog from "../views/dialogs/CreateCommunityPrototypeDialog"; import ThreepidInviteStore, { IThreepidInvite, IThreepidInviteWireFormat } from "../../stores/ThreepidInviteStore"; +import {UIFeature} from "../../settings/UIFeature"; /** constants for MatrixChat.state.view */ export enum Views { @@ -1942,7 +1943,7 @@ export default class MatrixChat extends React.PureComponent { render() { const fragmentAfterLogin = this.getFragmentAfterLogin(); - let view; + let view = null; if (this.state.view === Views.LOADING) { const Spinner = sdk.getComponent('elements.Spinner'); @@ -2021,7 +2022,7 @@ export default class MatrixChat extends React.PureComponent { } else if (this.state.view === Views.WELCOME) { const Welcome = sdk.getComponent('auth.Welcome'); view = ; - } 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 email = ThreepidInviteStore.instance.pickBestInvite()?.toEmail; view = ( @@ -2039,7 +2040,7 @@ export default class MatrixChat extends React.PureComponent { {...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'); view = ( { /> ); } else if (this.state.view === Views.LOGIN) { + const showPasswordReset = SettingsStore.getValue(UIFeature.PasswordReset); const Login = sdk.getComponent('structures.auth.Login'); view = ( { onRegisterClick={this.onRegisterClick} fallbackHsUrl={this.getFallbackHsUrl()} defaultDeviceDisplayName={this.props.defaultDeviceDisplayName} - onForgotPasswordClick={this.onForgotPasswordClick} + onForgotPasswordClick={showPasswordReset ? this.onForgotPasswordClick : undefined} onServerConfigChange={this.onServerConfigChange} fragmentAfterLogin={fragmentAfterLogin} {...this.getServerProperties()} diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index a20bf0dd0a..118eed59e3 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -28,6 +28,8 @@ import classNames from "classnames"; import AuthPage from "../../views/auth/AuthPage"; import SSOButton from "../../views/elements/SSOButton"; import PlatformPeg from '../../../PlatformPeg'; +import SettingsStore from "../../../settings/SettingsStore"; +import {UIFeature} from "../../../settings/UIFeature"; // For validating phone numbers without country codes 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")} } ; - } else { + } else if (SettingsStore.getValue(UIFeature.Registration)) { footer = ( { _t('Create account') } diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 5a30a02490..21032f4f1a 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -15,10 +15,14 @@ limitations under the License. */ import React from 'react'; +import classNames from "classnames"; + import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import {_td} from "../../../languageHandler"; +import SettingsStore from "../../../settings/SettingsStore"; +import {UIFeature} from "../../../settings/UIFeature"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -39,7 +43,9 @@ export default class Welcome extends React.PureComponent { return ( -
+
: null; + let accountManagementSection; + if (SettingsStore.getValue(UIFeature.Deactivate)) { + accountManagementSection = <> +
{_t("Deactivate account")}
+ {this._renderManagementSection()} + ; + } + return (
{_t("General")}
@@ -395,8 +403,7 @@ export default class GeneralUserSettingsTab extends React.Component {
{discoWarning} {_t("Discovery")}
{this._renderDiscoverySection()} {this._renderIntegrationManagerSection() /* Has its own title */} -
{_t("Deactivate account")}
- {this._renderManagementSection()} + { accountManagementSection }
); } diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 21b3935c3e..f7a1b6655c 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -626,4 +626,16 @@ export const SETTINGS: {[setting: string]: ISetting} = { supportedLevels: LEVELS_UI_FEATURE, 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, + }, }; diff --git a/src/settings/UIFeature.ts b/src/settings/UIFeature.ts index dddef82df1..71821917bf 100644 --- a/src/settings/UIFeature.ts +++ b/src/settings/UIFeature.ts @@ -19,4 +19,7 @@ export enum UIFeature { URLPreviews = "UIFeature.urlPreviews", Widgets = "UIFeature.widgets", Feedback = "UIFeature.feedback", + Registration = "UIFeature.registration", + PasswordReset = "UIFeature.passwordReset", + Deactivate = "UIFeature.deactivate", } From f52b267bd39a19872a0ff3300925f0ce9e403123 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 17 Sep 2020 12:07:17 +0100 Subject: [PATCH 8/9] i18n --- src/i18n/strings/en_EN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b2b4e01202..d91fe475df 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -832,9 +832,9 @@ "Account management": "Account management", "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", "Legal": "Legal", "Credits": "Credits", "For help with using %(brand)s, click
here.": "For help with using %(brand)s, click here.", From 25171347a094074e93a6ff0184fd4b40f7060ee0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 17 Sep 2020 13:57:47 +0100 Subject: [PATCH 9/9] i18n --- src/i18n/strings/en_EN.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index d91fe475df..4c2a55d09e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -833,8 +833,8 @@ "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", + "General": "General", "Legal": "Legal", "Credits": "Credits", "For help with using %(brand)s, click here.": "For help with using %(brand)s, click here.", @@ -1732,9 +1732,11 @@ "Recently Direct Messaged": "Recently Direct Messaged", "Direct Messages": "Direct Messages", "Start a conversation with someone using their name, username (like ) or email address.": "Start a conversation with someone using their name, username (like ) or email address.", - "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.": "Start a conversation with someone using their name, username (like ) or email address. This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here.", + "Start a conversation with someone using their name or username (like ).": "Start a conversation with someone using their name or username (like ).", + "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here": "This won't invite them to %(communityName)s. To invite someone to %(communityName)s, click here", "Go": "Go", "Invite someone using their name, username (like ), email address or share this room.": "Invite someone using their name, username (like ), email address or share this room.", + "Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.", "a new master key signature": "a new master key signature", "a new cross-signing key signature": "a new cross-signing key signature", "a device cross-signing signature": "a device cross-signing signature",