From 9ca1e875a326cb00fe690f33ec352068bc358bcf Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 6 Feb 2019 14:11:09 -0700 Subject: [PATCH 01/21] Fix firefox scrolling settings tabs differently Fixes https://github.com/vector-im/riot-web/issues/8408 --- res/css/structures/_TabbedView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/res/css/structures/_TabbedView.scss b/res/css/structures/_TabbedView.scss index cbd2870cba..fb4df53d52 100644 --- a/res/css/structures/_TabbedView.scss +++ b/res/css/structures/_TabbedView.scss @@ -85,6 +85,7 @@ limitations under the License. flex-grow: 1; display: flex; flex-direction: column; + min-height: 0; // firefox } .mx_TabbedView_tabPanelContent { From 2e852da72ef11e66ecbabd7d97925eca1867a0b7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 6 Feb 2019 15:06:15 -0700 Subject: [PATCH 02/21] Actually change power levels when they are changed --- .../settings/tabs/RolesRoomSettingsTab.js | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/components/views/settings/tabs/RolesRoomSettingsTab.js b/src/components/views/settings/tabs/RolesRoomSettingsTab.js index 776ce9f01a..2195017782 100644 --- a/src/components/views/settings/tabs/RolesRoomSettingsTab.js +++ b/src/components/views/settings/tabs/RolesRoomSettingsTab.js @@ -113,6 +113,39 @@ export default class RolesRoomSettingsTab extends React.Component { } } + _onPowerLevelsChanged = (value, powerLevelKey) => { + const client = MatrixClientPeg.get(); + const room = client.getRoom(this.props.roomId); + let plContent = room.currentState.getStateEvents('m.room.power_levels', '').getContent() || {}; + + // Clone the power levels just in case + plContent = Object.assign({}, plContent); + + const eventsLevelPrefix = "event_levels_"; + + value = parseInt(value); + + if (powerLevelKey.startsWith(eventsLevelPrefix)) { + // deep copy "events" object, Object.assign itself won't deep copy + plContent["events"] = Object.assign({}, plContent["events"] || {}); + plContent["events"][powerLevelKey.slice(eventsLevelPrefix.length)] = value; + } else { + const keyPath = powerLevelKey.split('.'); + let parentObj; + let currentObj = plContent; + for (const key of keyPath) { + if (!currentObj[key]) { + currentObj[key] = {}; + } + parentObj = currentObj; + currentObj = currentObj[key]; + } + parentObj[keyPath[keyPath.length - 1]] = value; + } + + client.sendStateEvent(this.props.roomId, "m.room.power_levels", plContent); + }; + render() { const PowerSelector = sdk.getComponent('elements.PowerSelector'); @@ -272,12 +305,12 @@ export default class RolesRoomSettingsTab extends React.Component { controlled={false} disabled={!canChangeLevels || currentUserLevel < value} powerLevelKey={key} // Will be sent as the second parameter to `onChange` - onChange={this.onPowerLevelsChanged} + onChange={this._onPowerLevelsChanged} /> ; }); - const eventPowerSelectors = Object.keys(eventsLevels).map(function(eventType, i) { + const eventPowerSelectors = Object.keys(eventsLevels).map((eventType, i) => { let label = plEventsToLabels[eventType]; if (label) { label = _t(label); @@ -296,7 +329,7 @@ export default class RolesRoomSettingsTab extends React.Component { controlled={false} disabled={!canChangeLevels || currentUserLevel < eventsLevels[eventType]} powerLevelKey={"event_levels_" + eventType} - onChange={self.onPowerLevelsChanged} + onChange={this._onPowerLevelsChanged} /> ); From f79b777dd4a6839df6d904fe0e8c9aef5bf2e044 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 7 Feb 2019 14:39:47 +0000 Subject: [PATCH 03/21] Trust on decrypt Add support for trust-on-decrypt (API change, recognise flag on isKeyBackupTrusted). Catch rejection on wrong passphrase / recovery key. Fix remembering whether we are restoring with key or passphrase. Requires https://github.com/matrix-org/matrix-js-sdk/pull/836 --- .../keybackup/RestoreKeyBackupDialog.js | 51 +++++++++---------- .../views/settings/KeyBackupPanel.js | 10 +++- src/i18n/strings/en_EN.json | 8 +-- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index e5b82baa92..9393f8f526 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -88,7 +88,7 @@ export default React.createClass({ }); try { const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword( - this.state.passPhrase, undefined, undefined, this.state.backupInfo.version, + this.state.passPhrase, undefined, undefined, this.state.backupInfo, ); this.setState({ loading: false, @@ -107,11 +107,11 @@ export default React.createClass({ this.setState({ loading: true, restoreError: null, - restoreType: RESTORE_TYPE_PASSPHRASE, + restoreType: RESTORE_TYPE_RECOVERYKEY, }); try { const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey( - this.state.recoveryKey, undefined, undefined, this.state.backupInfo.version, + this.state.recoveryKey, undefined, undefined, this.state.backupInfo, ); this.setState({ loading: false, @@ -185,32 +185,31 @@ export default React.createClass({ title = _t("Error"); content = _t("Unable to load backup status"); } else if (this.state.restoreError) { - title = _t("Error"); - content = _t("Unable to restore backup"); + if (this.state.restoreError.errcode === MatrixClientPeg.get().RESTORE_BACKUP_ERROR_BAD_KEY) { + if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) { + title = _t("Recovery Key Mismatch"); + content =
+

{_t( + "Backup could not be decrypted with this key: " + + "please verify that you entered the correct recovery key.", + )}

+
; + } else { + title = _t("Incorrect Recovery Passphrase"); + content =
+

{_t( + "Backup could not be decrypted with this passphrase: " + + "please verify that you entered the correct recovery passphrase.", + )}

+
; + } + } else { + title = _t("Error"); + content = _t("Unable to restore backup"); + } } else if (this.state.backupInfo === null) { title = _t("Error"); content = _t("No backup found!"); - } else if ( - this.state.recoverInfo && - this.state.recoverInfo.imported === 0 && - this.state.recoverInfo.total > 0 - ) { - title = _t("Error Restoring Backup"); - if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) { - content =
-

{_t( - "Backup could not be decrypted with this key: " + - "please verify that you entered the correct recovery key.", - )}

-
; - } else { - content =
-

{_t( - "Backup could not be decrypted with this passphrase: " + - "please verify that you entered the correct recovery passphrase.", - )}

-
; - } } else if (this.state.recoverInfo) { title = _t("Backup Restored"); let failedToDecrypt; diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index 15856a75f3..f6369c0ade 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -250,13 +250,19 @@ export default class KeyBackupPanel extends React.PureComponent { backupSigStatuses = _t("Backup is not signed by any of your devices"); } + let trustedLocally; + if (this.state.backupSigStatus.trusted_locally) { + trustedLocally = _t("This backup is trusted because it has been restored on this device"); + } + return
{_t("Backup version: ")}{this.state.backupInfo.version}
{_t("Algorithm: ")}{this.state.backupInfo.algorithm}
{clientBackupStatus}
{uploadStatus} -
{backupSigStatuses}

-
+
{backupSigStatuses}
+
{trustedLocally}
+

{ _t("Restore backup") }     diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b586d2f8f7..c181d40148 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -385,6 +385,7 @@ "Backup has an invalid signature from unverified device ": "Backup has an invalid signature from unverified device ", "Verify...": "Verify...", "Backup is not signed by any of your devices": "Backup is not signed by any of your devices", + "This backup is trusted because it has been restored on this device": "This backup is trusted because it has been restored on this device", "Backup version: ": "Backup version: ", "Algorithm: ": "Algorithm: ", "Restore backup": "Restore backup", @@ -1095,11 +1096,12 @@ "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", "Unknown devices": "Unknown devices", "Unable to load backup status": "Unable to load backup status", + "Recovery Key Mismatch": "Recovery Key Mismatch", + "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.", + "Incorrect Recovery Passphrase": "Incorrect Recovery Passphrase", + "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.", "Unable to restore backup": "Unable to restore backup", "No backup found!": "No backup found!", - "Error Restoring Backup": "Error Restoring Backup", - "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.": "Backup could not be decrypted with this key: please verify that you entered the correct recovery key.", - "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.": "Backup could not be decrypted with this passphrase: please verify that you entered the correct recovery passphrase.", "Backup Restored": "Backup Restored", "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!", "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys", From 35d9c02ecd4108f1740a2c62c0c9120448345f07 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 15:28:22 +0000 Subject: [PATCH 04/21] throttle custom tags updating in LLP --- src/stores/CustomRoomTagStore.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js index 3e109aef2d..ddcb30de78 100644 --- a/src/stores/CustomRoomTagStore.js +++ b/src/stores/CustomRoomTagStore.js @@ -17,6 +17,7 @@ import dis from '../dispatcher'; import * as RoomNotifs from '../RoomNotifs'; import RoomListStore from './RoomListStore'; import EventEmitter from 'events'; +import * as _ from "lodash"; const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/; @@ -49,7 +50,14 @@ class CustomRoomTagStore extends EventEmitter { super(); // Initialise state this._state = {tags: {}}; - + // as RoomListStore gets updated by every timeline event + // throttle this to only run every 500ms + this._getUpdatedTags = _.throttle( + this._getUpdatedTags, 500, { + leading: true, + trailing: true, + }, + ); this._roomListStoreToken = RoomListStore.addListener(() => { this._setState({tags: this._getUpdatedTags()}); }); From c0b9d9938576ce4a852f89866399259cf9abb515 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 16:03:12 +0000 Subject: [PATCH 05/21] only import throttle fn --- src/stores/CustomRoomTagStore.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js index ddcb30de78..9795abadc6 100644 --- a/src/stores/CustomRoomTagStore.js +++ b/src/stores/CustomRoomTagStore.js @@ -17,7 +17,7 @@ import dis from '../dispatcher'; import * as RoomNotifs from '../RoomNotifs'; import RoomListStore from './RoomListStore'; import EventEmitter from 'events'; -import * as _ from "lodash"; +import { throttle } from "lodash"; const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/; @@ -52,7 +52,7 @@ class CustomRoomTagStore extends EventEmitter { this._state = {tags: {}}; // as RoomListStore gets updated by every timeline event // throttle this to only run every 500ms - this._getUpdatedTags = _.throttle( + this._getUpdatedTags = throttle( this._getUpdatedTags, 500, { leading: true, trailing: true, From 3a924d05b5e986619d0d20aed3b64ac8a0a76cb2 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 7 Feb 2019 17:01:55 +0000 Subject: [PATCH 06/21] Remove click-to-verify from SAS The click-each-pair to verify was hard to discover, so remove it --- res/css/_components.scss | 2 +- res/css/views/elements/_HexVerify.scss | 34 ------ src/components/views/elements/HexVerify.js | 103 ------------------ .../views/verification/VerificationShowSas.js | 20 +--- 4 files changed, 5 insertions(+), 154 deletions(-) delete mode 100644 res/css/views/elements/_HexVerify.scss delete mode 100644 src/components/views/elements/HexVerify.js diff --git a/res/css/_components.scss b/res/css/_components.scss index fe331504f2..c82dedc069 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -77,7 +77,6 @@ @import "./views/elements/_Dropdown.scss"; @import "./views/elements/_EditableItemList.scss"; @import "./views/elements/_Field.scss"; -@import "./views/elements/_HexVerify.scss"; @import "./views/elements/_ImageView.scss"; @import "./views/elements/_InlineSpinner.scss"; @import "./views/elements/_ManageIntegsButton.scss"; @@ -156,6 +155,7 @@ @import "./views/settings/tabs/_SecuritySettingsTab.scss"; @import "./views/settings/tabs/_SettingsTab.scss"; @import "./views/settings/tabs/_VoiceSettingsTab.scss"; +@import "./views/verification/_VerificationShowSas.scss"; @import "./views/voip/_CallView.scss"; @import "./views/voip/_IncomingCallbox.scss"; @import "./views/voip/_VideoView.scss"; diff --git a/res/css/views/elements/_HexVerify.scss b/res/css/views/elements/_HexVerify.scss deleted file mode 100644 index 3f3ee4b7ea..0000000000 --- a/res/css/views/elements/_HexVerify.scss +++ /dev/null @@ -1,34 +0,0 @@ -/* -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. -*/ - -.mx_HexVerify { - text-align: center; -} - -.mx_HexVerify_pair { - display: inline-block; - font-weight: bold; - padding-left: 3px; - padding-right: 3px; -} - -.mx_HexVerify_pair_verified { - color: $accent-color; -} - -.mx_HexVerify_pair:hover{ - color: $accent-color; -} diff --git a/src/components/views/elements/HexVerify.js b/src/components/views/elements/HexVerify.js deleted file mode 100644 index 86ead3adc1..0000000000 --- a/src/components/views/elements/HexVerify.js +++ /dev/null @@ -1,103 +0,0 @@ -/* -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 React from "react"; -import PropTypes from "prop-types"; -import classnames from 'classnames'; - -import sdk from '../../../index'; - -class HexVerifyPair extends React.Component { - static propTypes = { - text: PropTypes.string.isRequired, - index: PropTypes.number, - verified: PropTypes.bool, - onChange: PropTypes.func.isRequired, - } - - _onClick = () => { - this.setState({verified: !this.props.verified}); - this.props.onChange(this.props.index, !this.props.verified); - } - - render() { - const classNames = { - mx_HexVerify_pair: true, - mx_HexVerify_pair_verified: this.props.verified, - }; - const AccessibleButton = sdk.getComponent('views.elements.AccessibleButton'); - return - {this.props.text} - ; - } -} - -/* - * Helps a user verify a hexadecimal code matches one displayed - * elsewhere (eg. on a different device) - */ -export default class HexVerify extends React.Component { - static propTypes = { - text: PropTypes.string.isRequired, - onVerifiedStateChange: PropTypes.func, - } - - static defaultProps = { - onVerifiedStateChange: function() {}, - } - - constructor(props) { - super(props); - this.state = { - pairsVerified: [], - }; - for (let i = 0; i < props.text.length; i += 2) { - this.state.pairsVerified.push(false); - } - } - - _onPairChange = (index, newVal) => { - const oldVerified = this.state.pairsVerified.reduce((acc, val) => { - return acc && val; - }, true); - const newPairsVerified = this.state.pairsVerified.slice(0); - newPairsVerified[index] = newVal; - const newVerified = newPairsVerified.reduce((acc, val) => { - return acc && val; - }, true); - this.setState({pairsVerified: newPairsVerified}); - if (oldVerified !== newVerified) { - this.props.onVerifiedStateChange(newVerified); - } - } - - render() { - const pairs = []; - - for (let i = 0; i < this.props.text.length / 2; ++i) { - pairs.push(); - } - return
- {pairs} -
; - } -} diff --git a/src/components/views/verification/VerificationShowSas.js b/src/components/views/verification/VerificationShowSas.js index 6f3209989e..0224571d9e 100644 --- a/src/components/views/verification/VerificationShowSas.js +++ b/src/components/views/verification/VerificationShowSas.js @@ -28,19 +28,11 @@ export default class VerificationShowSas extends React.Component { constructor() { super(); - this.state = { - sasVerified: false, - }; - } - - _onVerifiedStateChange = (newVal) => { - this.setState({sasVerified: newVal}); } render() { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - const HexVerify = sdk.getComponent('views.elements.HexVerify'); - return
+ return

{_t( "Verify this user by confirming the following number appears on their screen.", )}

@@ -48,15 +40,11 @@ export default class VerificationShowSas extends React.Component { "For maximum security, we recommend you do this in person or use another " + "trusted means of communication.", )}

- -

{_t( - "To continue, click on each pair to confirm it's correct.", - )}

+
+ {this.props.sas} +
From d4ed0bc03818f829e4b9e6d666af66f04c4a5b5e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 17:08:40 +0000 Subject: [PATCH 07/21] make sure scroller doesn't overflow parent --- res/css/structures/_CustomRoomTagPanel.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/res/css/structures/_CustomRoomTagPanel.scss b/res/css/structures/_CustomRoomTagPanel.scss index f02421db2c..45961d7be1 100644 --- a/res/css/structures/_CustomRoomTagPanel.scss +++ b/res/css/structures/_CustomRoomTagPanel.scss @@ -21,7 +21,11 @@ limitations under the License. .mx_CustomRoomTagPanel { background-color: $tagpanel-bg-color; - max-height: 40%; + max-height: 40vh; +} + +.mx_CustomRoomTagPanel_scroller { + max-height: inherit; } .mx_CustomRoomTagPanel .mx_AccessibleButton { From 4728ddf5155c90b3d8832baeeaf6e6ea883983f8 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 7 Feb 2019 17:53:41 +0000 Subject: [PATCH 08/21] Forgot the CSS file --- .../verification/_VerificationShowSas.scss | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 res/css/views/verification/_VerificationShowSas.scss diff --git a/res/css/views/verification/_VerificationShowSas.scss b/res/css/views/verification/_VerificationShowSas.scss new file mode 100644 index 0000000000..32ccf6b0bb --- /dev/null +++ b/res/css/views/verification/_VerificationShowSas.scss @@ -0,0 +1,22 @@ +/* +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. +*/ + +.mx_VerificationShowSas_sas { + text-align: center; + font-weight: bold; + padding-left: 3px; + padding-right: 3px; +} From e8533beafb08a2b4378f48029ecc2c98bb047ba6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 18:04:30 +0000 Subject: [PATCH 09/21] guard custom tags with feature flag --- src/components/structures/LeftPanel.js | 5 ++++- src/components/views/rooms/RoomList.js | 14 +++++++++----- src/i18n/strings/en_EN.json | 1 + src/settings/Settings.js | 6 ++++++ src/stores/CustomRoomTagStore.js | 6 ++++++ src/stores/RoomListStore.js | 4 +++- 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/components/structures/LeftPanel.js b/src/components/structures/LeftPanel.js index 0ae9b032d1..bd49f8acd4 100644 --- a/src/components/structures/LeftPanel.js +++ b/src/components/structures/LeftPanel.js @@ -190,10 +190,13 @@ const LeftPanel = React.createClass({ const tagPanelEnabled = SettingsStore.getValue("TagPanel.enableTagPanel"); let tagPanelContainer; + + const isCustomTagsEnabled = SettingsStore.isFeatureEnabled("feature_custom_tags"); + if (tagPanelEnabled) { tagPanelContainer = (
- + { isCustomTagsEnabled ? : undefined }
); } diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index 8418ab6d6f..e1a3c397e6 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -172,11 +172,14 @@ module.exports = React.createClass({ this._delayedRefreshRoomList(); }); - this._customTagStoreToken = CustomRoomTagStore.addListener(() => { - this.setState({ - customTags: CustomRoomTagStore.getTags(), + + if (SettingsStore.isFeatureEnabled("feature_custom_tags")) { + this._customTagStoreToken = CustomRoomTagStore.addListener(() => { + this.setState({ + customTags: CustomRoomTagStore.getTags(), + }); }); - }); + } this.refreshRoomList(); @@ -728,7 +731,8 @@ module.exports = React.createClass({ ]; const tagSubLists = Object.keys(this.state.lists) .filter((tagName) => { - return this.state.customTags[tagName] && !tagName.match(STANDARD_TAGS_REGEX); + return (!this.state.customTags || this.state.customTags[tagName]) && + !tagName.match(STANDARD_TAGS_REGEX); }).map((tagName) => { return { list: this.state.lists[tagName], diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b586d2f8f7..a5b04f1981 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -264,6 +264,7 @@ "Failed to join room": "Failed to join room", "Message Pinning": "Message Pinning", "Custom user status messages": "Custom user status messages", + "Group & filter rooms by custom tags (refresh to apply changes)": "Group & filter rooms by custom tags (refresh to apply changes)", "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "Backup of encryption keys to server": "Backup of encryption keys to server", "Render simple counters in room header": "Render simple counters in room header", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index c5de7298de..d9363315f5 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -100,6 +100,12 @@ export const SETTINGS = { default: false, controller: new CustomStatusController(), }, + "feature_custom_tags": { + isFeature: true, + displayName: _td("Group & filter rooms by custom tags (refresh to apply changes)"), + supportedLevels: LEVELS_FEATURE, + default: false, + }, "feature_lazyloading": { isFeature: true, displayName: _td("Increase performance by only loading room members on first view"), diff --git a/src/stores/CustomRoomTagStore.js b/src/stores/CustomRoomTagStore.js index 9795abadc6..0f7f99aad9 100644 --- a/src/stores/CustomRoomTagStore.js +++ b/src/stores/CustomRoomTagStore.js @@ -18,6 +18,7 @@ import * as RoomNotifs from '../RoomNotifs'; import RoomListStore from './RoomListStore'; import EventEmitter from 'events'; import { throttle } from "lodash"; +import SettingsStore from "../settings/SettingsStore"; const STANDARD_TAGS_REGEX = /^(m\.(favourite|lowpriority|server_notice)|im\.vector\.fake\.(invite|recent|direct|archived))$/; @@ -50,6 +51,7 @@ class CustomRoomTagStore extends EventEmitter { super(); // Initialise state this._state = {tags: {}}; + // as RoomListStore gets updated by every timeline event // throttle this to only run every 500ms this._getUpdatedTags = throttle( @@ -133,6 +135,10 @@ class CustomRoomTagStore extends EventEmitter { } _getUpdatedTags() { + if (!SettingsStore.isFeatureEnabled("feature_custom_tags")) { + return; + } + const newTagNames = Object.keys(RoomListStore.getRoomLists()) .filter((tagName) => { return !tagName.match(STANDARD_TAGS_REGEX); diff --git a/src/stores/RoomListStore.js b/src/stores/RoomListStore.js index 61e17821bd..d98adc5cae 100644 --- a/src/stores/RoomListStore.js +++ b/src/stores/RoomListStore.js @@ -202,6 +202,8 @@ class RoomListStore extends Store { // If somehow we dispatched a RoomListActions.tagRoom.failure before a MatrixActions.sync if (!this._matrixClient) return; + const isCustomTagsEnabled = SettingsStore.isFeatureEnabled("feature_custom_tags"); + this._matrixClient.getRooms().forEach((room, index) => { const myUserId = this._matrixClient.getUserId(); const membership = room.getMyMembership(); @@ -226,7 +228,7 @@ class RoomListStore extends Store { // ignore any m. tag names we don't know about tagNames = tagNames.filter((t) => { - return !t.startsWith('m.') || lists[t] !== undefined; + return (isCustomTagsEnabled && !t.startsWith('m.')) || lists[t] !== undefined; }); if (tagNames.length) { From ac4ab11985f9065b1f602577d03714fb47daee30 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 18:24:07 +0000 Subject: [PATCH 10/21] remove ll feature flag, it's time! --- src/MatrixClientPeg.js | 9 +----- .../views/settings/tabs/LabsSettingsTab.js | 7 ----- src/settings/Settings.js | 7 ----- .../controllers/LazyLoadingController.js | 29 ------------------- 4 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 src/settings/controllers/LazyLoadingController.js diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 882a913452..f283eb84a5 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -135,14 +135,7 @@ class MatrixClientPeg { const opts = utils.deepCopy(this.opts); // the react sdk doesn't work without this, so don't allow opts.pendingEventOrdering = "detached"; - - const LAZY_LOADING_FEATURE = "feature_lazyloading"; - if (SettingsStore.isFeatureEnabled(LAZY_LOADING_FEATURE)) { - const userId = this.matrixClient.credentials.userId; - if (phasedRollOutExpiredForUser(userId, LAZY_LOADING_FEATURE, Date.now())) { - opts.lazyLoadMembers = true; - } - } + opts.lazyLoadMembers = true; // Connect the matrix client to the dispatcher MatrixActionCreators.start(this.matrixClient); diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js index fc64c1bd04..66cce30a3a 100644 --- a/src/components/views/settings/tabs/LabsSettingsTab.js +++ b/src/components/views/settings/tabs/LabsSettingsTab.js @@ -53,13 +53,6 @@ export class LabsSettingToggle extends React.Component { } _onChange = async (checked) => { - if (this.props.featureId === "feature_lazyloading") { - const confirmed = await this._onLazyLoadChanging(checked); - if (!confirmed) { - return; - } - } - await SettingsStore.setFeatureEnabled(this.props.featureId, checked); this.forceUpdate(); }; diff --git a/src/settings/Settings.js b/src/settings/Settings.js index c5de7298de..bcc79f62a4 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -100,13 +100,6 @@ export const SETTINGS = { default: false, controller: new CustomStatusController(), }, - "feature_lazyloading": { - isFeature: true, - displayName: _td("Increase performance by only loading room members on first view"), - supportedLevels: LEVELS_FEATURE, - controller: new LazyLoadingController(), - default: true, - }, "feature_keybackup": { isFeature: true, displayName: _td("Backup of encryption keys to server"), diff --git a/src/settings/controllers/LazyLoadingController.js b/src/settings/controllers/LazyLoadingController.js deleted file mode 100644 index 90f095c9ca..0000000000 --- a/src/settings/controllers/LazyLoadingController.js +++ /dev/null @@ -1,29 +0,0 @@ -/* -Copyright 2018 New Vector - -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 SettingController from "./SettingController"; -import MatrixClientPeg from "../../MatrixClientPeg"; -import PlatformPeg from "../../PlatformPeg"; - -export default class LazyLoadingController extends SettingController { - async onChange(level, roomId, newValue) { - if (!PlatformPeg.get()) return; - - MatrixClientPeg.get().stopClient(); - await MatrixClientPeg.get().store.deleteAllData(); - PlatformPeg.get().reload(); - } -} From 8c32f88c1c257b9fc7828a8ed434c7ce4627fdca Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 18:45:00 +0000 Subject: [PATCH 11/21] remove homeserver ll check on toggling lab setting --- .../views/settings/tabs/LabsSettingsTab.js | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js index 66cce30a3a..89239db2f8 100644 --- a/src/components/views/settings/tabs/LabsSettingsTab.js +++ b/src/components/views/settings/tabs/LabsSettingsTab.js @@ -28,30 +28,6 @@ export class LabsSettingToggle extends React.Component { featureId: PropTypes.string.isRequired, }; - async _onLazyLoadChanging(enabling) { - // don't prevent turning LL off when not supported - if (enabling) { - const supported = await MatrixClientPeg.get().doesServerSupportLazyLoading(); - if (!supported) { - await new Promise((resolve) => { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - Modal.createDialog(QuestionDialog, { - title: _t("Lazy loading members not supported"), - description: -
- { _t("Lazy loading is not supported by your " + - "current homeserver.") } -
, - button: _t("OK"), - onFinished: resolve, - }); - }); - return false; - } - } - return true; - } - _onChange = async (checked) => { await SettingsStore.setFeatureEnabled(this.props.featureId, checked); this.forceUpdate(); From cf7e1f9d88648ee3b8cd9dfbc1096dc337adfc40 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 7 Feb 2019 18:47:08 +0000 Subject: [PATCH 12/21] remove import as well --- src/settings/Settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/settings/Settings.js b/src/settings/Settings.js index bcc79f62a4..833bdc7f8c 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -21,7 +21,6 @@ import { NotificationBodyEnabledController, NotificationsEnabledController, } from "./controllers/NotificationControllers"; -import LazyLoadingController from "./controllers/LazyLoadingController"; import CustomStatusController from "./controllers/CustomStatusController"; // These are just a bunch of helper arrays to avoid copy/pasting a bunch of times From 89a842232005db561ea135970242d0f76a7749b6 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 7 Feb 2019 11:54:13 -0700 Subject: [PATCH 13/21] Ensure toggle switches listen to property changes They do local echo on changes to avoid jumping back and forth while requests are ongoing, however some areas modify the checked state after the toggle has mounted. Fixes https://github.com/vector-im/riot-web/issues/8432 --- src/components/views/elements/ToggleSwitch.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/views/elements/ToggleSwitch.js b/src/components/views/elements/ToggleSwitch.js index 19c87aab56..0d8b3d042f 100644 --- a/src/components/views/elements/ToggleSwitch.js +++ b/src/components/views/elements/ToggleSwitch.js @@ -38,6 +38,12 @@ export default class ToggleSwitch extends React.Component { }; } + componentWillReceiveProps(nextProps) { + if (nextProps.checked !== this.state.checked) { + this.setState({checked: nextProps.checked}); + } + } + _onClick = (e) => { e.stopPropagation(); e.preventDefault(); From 5d4406cbabaf27168fffe2138cf4b9568ef585fd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 7 Feb 2019 12:14:58 -0700 Subject: [PATCH 14/21] Render join rules and guest access changes in the timeline Fixes https://github.com/vector-im/riot-web/issues/8435 --- src/TextForEvent.js | 34 +++++++++++++++++++++++++ src/components/views/rooms/EventTile.js | 2 ++ src/i18n/strings/en_EN.json | 6 +++++ 3 files changed, 42 insertions(+) diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 2a37295f83..241fefe5bb 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -134,6 +134,38 @@ function textForTombstoneEvent(ev) { return _t('%(senderDisplayName)s upgraded this room.', {senderDisplayName}); } +function textForJoinRulesEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + switch (ev.getContent().join_rule) { + case "public": + return _t('%(senderDisplayName)s made the room public to whoever knows the link.', {senderDisplayName}); + case "invite": + return _t('%(senderDisplayName)s made the room invite only.', {senderDisplayName}); + default: + // The spec supports "knock" and "private", however nothing implements these. + return _t('%(senderDisplayName)s changed the join rules to %(rule)s', { + senderDisplayName, + rule: ev.getContent().join_rule, + }); + } +} + +function textForGuestAccessEvent(ev) { + const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); + switch (ev.getContent().guest_access) { + case "can_join": + return _t('%(senderDisplayName)s has allowed guests to join the room.', {senderDisplayName}); + case "forbidden": + return _t('%(senderDisplayName)s has prevented guests from joining the room.', {senderDisplayName}); + default: + // There's no other options we can expect, however just for safety's sake we'll do this. + return _t('%(senderDisplayName)s changed guest access to %(rule)s', { + senderDisplayName, + rule: ev.getContent().guest_access, + }); + } +} + function textForServerACLEvent(ev) { const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender(); const prevContent = ev.getPrevContent(); @@ -439,6 +471,8 @@ const stateHandlers = { 'm.room.pinned_events': textForPinnedEvent, 'm.room.server_acl': textForServerACLEvent, 'm.room.tombstone': textForTombstoneEvent, + 'm.room.join_rules': textForJoinRulesEvent, + 'm.room.guest_access': textForGuestAccessEvent, 'im.vector.modular.widgets': textForWidgetEvent, }; diff --git a/src/components/views/rooms/EventTile.js b/src/components/views/rooms/EventTile.js index e4a6695ff5..8520d804e0 100644 --- a/src/components/views/rooms/EventTile.js +++ b/src/components/views/rooms/EventTile.js @@ -63,6 +63,8 @@ const stateEventTileTypes = { 'm.room.server_acl': 'messages.TextualEvent', 'im.vector.modular.widgets': 'messages.TextualEvent', 'm.room.tombstone': 'messages.TextualEvent', + 'm.room.join_rules': 'messages.TextualEvent', + 'm.room.guest_access': 'messages.TextualEvent', }; function getHandlerTile(ev) { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b586d2f8f7..ab69a93ac2 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -186,6 +186,12 @@ "%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s removed the room name.", "%(senderDisplayName)s changed the room name to %(roomName)s.": "%(senderDisplayName)s changed the room name to %(roomName)s.", "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s upgraded this room.", + "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s made the room public to whoever knows the link.", + "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s made the room invite only.", + "%(senderDisplayName)s changed the join rules to %(rule)s": "%(senderDisplayName)s changed the join rules to %(rule)s", + "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s has allowed guests to join the room.", + "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s has prevented guests from joining the room.", + "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s changed guest access to %(rule)s", "%(senderDisplayName)s sent an image.": "%(senderDisplayName)s sent an image.", "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|other": "%(senderName)s added %(addedAddresses)s as addresses for this room.", "%(senderName)s added %(count)s %(addedAddresses)s as addresses for this room.|one": "%(senderName)s added %(addedAddresses)s as an address for this room.", From f66c92b1fd069052fbf6f1016f768a6e6c516c93 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 7 Feb 2019 14:01:34 -0700 Subject: [PATCH 15/21] Local echo on room access settings Includes a fix for the aliases warning appearing at the wrong time. Fixes https://github.com/vector-im/riot-web/issues/8406 Fixes https://github.com/vector-im/riot-web/issues/8434 --- .../settings/tabs/SecurityRoomSettingsTab.js | 77 +++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/src/components/views/settings/tabs/SecurityRoomSettingsTab.js b/src/components/views/settings/tabs/SecurityRoomSettingsTab.js index df6648c4a6..593e8151d2 100644 --- a/src/components/views/settings/tabs/SecurityRoomSettingsTab.js +++ b/src/components/views/settings/tabs/SecurityRoomSettingsTab.js @@ -27,8 +27,27 @@ export default class SecurityRoomSettingsTab extends React.Component { roomId: PropTypes.string.isRequired, }; + constructor() { + super(); + + this.state = { + joinRule: "invite", + guestAccess: "can_join", + history: "shared", + encrypted: false, + }; + } + componentWillMount(): void { MatrixClientPeg.get().on("RoomState.events", this._onStateEvent); + + const room = MatrixClientPeg.get().getRoom(this.props.roomId); + const state = room.currentState; + const joinRule = state.getStateEvents("m.room.join_rules", "").getContent()['join_rule']; + const guestAccess = state.getStateEvents("m.room.guest_access", "").getContent()['guest_access']; + const history = state.getStateEvents("m.room.history_visibility", "").getContent()['history_visibility']; + const encrypted = MatrixClientPeg.get().isRoomEncrypted(this.props.roomId); + this.setState({joinRule, guestAccess, history, encrypted}); } componentWillUnmount(): void { @@ -46,19 +65,37 @@ export default class SecurityRoomSettingsTab extends React.Component { }; _onEncryptionChange = (e) => { + const beforeEncrypted = this.state.encrypted; + this.setState({encrypted: true}); MatrixClientPeg.get().sendStateEvent( this.props.roomId, "m.room.encryption", { algorithm: "m.megolm.v1.aes-sha2" }, - ); + ).catch((e) => { + console.error(e); + this.setState({encrypted: beforeEncrypted}); + }); }; _fixGuestAccess = (e) => { e.preventDefault(); e.stopPropagation(); + const joinRule = "invite"; + const guestAccess = "can_join"; + + const beforeJoinRule = this.state.joinRule; + const beforeGuestAccess = this.state.guestAccess; + this.setState({joinRule, guestAccess}); + const client = MatrixClientPeg.get(); - client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: "invite"}, ""); - client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: "can_join"}, ""); + client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, "").catch((e) => { + console.error(e); + this.setState({joinRule: beforeJoinRule}); + }); + client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, "").catch((e) => { + console.error(e); + this.setState({guestAccess: beforeGuestAccess}); + }); }; _onRoomAccessRadioToggle = (ev) => { @@ -92,24 +129,39 @@ export default class SecurityRoomSettingsTab extends React.Component { break; } + const beforeJoinRule = this.state.joinRule; + const beforeGuestAccess = this.state.guestAccess; + this.setState({joinRule, guestAccess}); + const client = MatrixClientPeg.get(); - client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, ""); - client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, ""); + client.sendStateEvent(this.props.roomId, "m.room.join_rules", {join_rule: joinRule}, "").catch((e) => { + console.error(e); + this.setState({joinRule: beforeJoinRule}); + }); + client.sendStateEvent(this.props.roomId, "m.room.guest_access", {guest_access: guestAccess}, "").catch((e) => { + console.error(e); + this.setState({guestAccess: beforeGuestAccess}); + }); }; _onHistoryRadioToggle = (ev) => { + const beforeHistory = this.state.history; + this.setState({history: ev.target.value}); MatrixClientPeg.get().sendStateEvent(this.props.roomId, "m.room.history_visibility", { history_visibility: ev.target.value, - }, ""); + }, "").catch((e) => { + console.error(e); + this.setState({history: beforeHistory}); + }); }; _renderRoomAccess() { const client = MatrixClientPeg.get(); const room = client.getRoom(this.props.roomId); - const joinRule = room.currentState.getStateEvents("m.room.join_rules", "").getContent()['join_rule']; - const guestAccess = room.currentState.getStateEvents("m.room.guest_access", "").getContent()['guest_access']; + const joinRule = this.state.joinRule; + const guestAccess = this.state.guestAccess; const aliasEvents = room.currentState.getStateEvents("m.room.aliases") || []; - const hasAliases = aliasEvents.includes((ev) => (ev.getContent().aliases || []).length); + const hasAliases = !!aliasEvents.find((ev) => (ev.getContent().aliases || []).length > 0); const canChangeAccess = room.currentState.mayClientSendStateEvent("m.room.join_rules", client) && room.currentState.mayClientSendStateEvent("m.room.guest_access", client); @@ -170,9 +222,8 @@ export default class SecurityRoomSettingsTab extends React.Component { _renderHistory() { const client = MatrixClientPeg.get(); - const room = client.getRoom(this.props.roomId); - const state = room.currentState; - const history = state.getStateEvents("m.room.history_visibility", "").getContent()['history_visibility']; + const history = this.state.history; + const state = client.getRoom(this.props.roomId).currentState; const canChangeHistory = state.mayClientSendStateEvent('m.room.history_visibility', client); return ( @@ -218,7 +269,7 @@ export default class SecurityRoomSettingsTab extends React.Component { const client = MatrixClientPeg.get(); const room = client.getRoom(this.props.roomId); - const isEncrypted = client.isRoomEncrypted(this.props.roomId); + const isEncrypted = this.state.encrypted; const hasEncryptionPermission = room.currentState.mayClientSendStateEvent("m.room.encryption", client); const canEnableEncryption = !isEncrypted && hasEncryptionPermission; From 2bcb54e749fd0d6cbe3dfb14038cbc46f0198cc2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 8 Feb 2019 09:29:11 +0000 Subject: [PATCH 16/21] remove strings from removed code --- src/i18n/strings/en_EN.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b586d2f8f7..edbd7bca4d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -264,7 +264,6 @@ "Failed to join room": "Failed to join room", "Message Pinning": "Message Pinning", "Custom user status messages": "Custom user status messages", - "Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view", "Backup of encryption keys to server": "Backup of encryption keys to server", "Render simple counters in room header": "Render simple counters in room header", "Two-way device verification using short text": "Two-way device verification using short text", @@ -476,8 +475,6 @@ "Identity Server is": "Identity Server is", "Access Token:": "Access Token:", "click to reveal": "click to reveal", - "Lazy loading members not supported": "Lazy loading members not supported", - "Lazy loading is not supported by your current homeserver.": "Lazy loading is not supported by your current homeserver.", "Labs": "Labs", "Notifications": "Notifications", "Start automatically after system login": "Start automatically after system login", From 748040268a2a0d91073454961978ef2e4c218fcd Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 8 Feb 2019 09:59:24 +0000 Subject: [PATCH 17/21] remove unused imports --- src/components/views/settings/tabs/LabsSettingsTab.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/views/settings/tabs/LabsSettingsTab.js b/src/components/views/settings/tabs/LabsSettingsTab.js index 89239db2f8..e06f87460b 100644 --- a/src/components/views/settings/tabs/LabsSettingsTab.js +++ b/src/components/views/settings/tabs/LabsSettingsTab.js @@ -18,9 +18,7 @@ import React from 'react'; import {_t} from "../../../../languageHandler"; import PropTypes from "prop-types"; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; -import MatrixClientPeg from "../../../../MatrixClientPeg"; import LabelledToggleSwitch from "../../elements/LabelledToggleSwitch"; -const Modal = require("../../../../Modal"); const sdk = require("../../../../index"); export class LabsSettingToggle extends React.Component { From d1e2418b750562d8989be58f391472ce4e1f1480 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 8 Feb 2019 10:43:39 +0000 Subject: [PATCH 18/21] Use error constant from the class --- .../views/dialogs/keybackup/RestoreKeyBackupDialog.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js index 9393f8f526..712d8d2b4e 100644 --- a/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js +++ b/src/components/views/dialogs/keybackup/RestoreKeyBackupDialog.js @@ -19,6 +19,8 @@ import sdk from '../../../../index'; import MatrixClientPeg from '../../../../MatrixClientPeg'; import Modal from '../../../../Modal'; +import { MatrixClient } from 'matrix-js-sdk'; + import { _t } from '../../../../languageHandler'; const RESTORE_TYPE_PASSPHRASE = 0; @@ -185,7 +187,7 @@ export default React.createClass({ title = _t("Error"); content = _t("Unable to load backup status"); } else if (this.state.restoreError) { - if (this.state.restoreError.errcode === MatrixClientPeg.get().RESTORE_BACKUP_ERROR_BAD_KEY) { + if (this.state.restoreError.errcode === MatrixClient.RESTORE_BACKUP_ERROR_BAD_KEY) { if (this.state.restoreType === RESTORE_TYPE_RECOVERYKEY) { title = _t("Recovery Key Mismatch"); content =
From e805df7b4cfd22719fe4eb092ab1cf02b6bb58ff Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 8 Feb 2019 10:46:38 +0000 Subject: [PATCH 19/21] Use fewer brs --- .../views/settings/KeyBackupPanel.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js index f6369c0ade..cbbca42927 100644 --- a/src/components/views/settings/KeyBackupPanel.js +++ b/src/components/views/settings/KeyBackupPanel.js @@ -256,19 +256,20 @@ export default class KeyBackupPanel extends React.PureComponent { } return
- {_t("Backup version: ")}{this.state.backupInfo.version}
- {_t("Algorithm: ")}{this.state.backupInfo.algorithm}
- {clientBackupStatus}
+
{_t("Backup version: ")}{this.state.backupInfo.version}
+
{_t("Algorithm: ")}{this.state.backupInfo.algorithm}
+
{clientBackupStatus}
{uploadStatus}
{backupSigStatuses}
{trustedLocally}
-

- - { _t("Restore backup") } -     - - { _t("Delete backup") } - +

+ + { _t("Restore backup") } +     + + { _t("Delete backup") } + +

; } else { return
From 2eff03ba78c0f9ac6c028de5059b9546b1e49526 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 8 Feb 2019 12:03:58 +0000 Subject: [PATCH 20/21] fix whitespace --- src/components/views/rooms/RoomList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/RoomList.js b/src/components/views/rooms/RoomList.js index e1a3c397e6..56eb4b713d 100644 --- a/src/components/views/rooms/RoomList.js +++ b/src/components/views/rooms/RoomList.js @@ -731,7 +731,7 @@ module.exports = React.createClass({ ]; const tagSubLists = Object.keys(this.state.lists) .filter((tagName) => { - return (!this.state.customTags || this.state.customTags[tagName]) && + return (!this.state.customTags || this.state.customTags[tagName]) && !tagName.match(STANDARD_TAGS_REGEX); }).map((tagName) => { return { From 85cfd48744e30f4f3d0c0b9b3a5e24baf18ba72e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 8 Feb 2019 09:15:12 -0700 Subject: [PATCH 21/21] join rules -> join rule --- src/TextForEvent.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TextForEvent.js b/src/TextForEvent.js index 241fefe5bb..ac0af82ff1 100644 --- a/src/TextForEvent.js +++ b/src/TextForEvent.js @@ -143,7 +143,7 @@ function textForJoinRulesEvent(ev) { return _t('%(senderDisplayName)s made the room invite only.', {senderDisplayName}); default: // The spec supports "knock" and "private", however nothing implements these. - return _t('%(senderDisplayName)s changed the join rules to %(rule)s', { + return _t('%(senderDisplayName)s changed the join rule to %(rule)s', { senderDisplayName, rule: ev.getContent().join_rule, }); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ab69a93ac2..244db0aca9 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -188,7 +188,7 @@ "%(senderDisplayName)s upgraded this room.": "%(senderDisplayName)s upgraded this room.", "%(senderDisplayName)s made the room public to whoever knows the link.": "%(senderDisplayName)s made the room public to whoever knows the link.", "%(senderDisplayName)s made the room invite only.": "%(senderDisplayName)s made the room invite only.", - "%(senderDisplayName)s changed the join rules to %(rule)s": "%(senderDisplayName)s changed the join rules to %(rule)s", + "%(senderDisplayName)s changed the join rule to %(rule)s": "%(senderDisplayName)s changed the join rule to %(rule)s", "%(senderDisplayName)s has allowed guests to join the room.": "%(senderDisplayName)s has allowed guests to join the room.", "%(senderDisplayName)s has prevented guests from joining the room.": "%(senderDisplayName)s has prevented guests from joining the room.", "%(senderDisplayName)s changed guest access to %(rule)s": "%(senderDisplayName)s changed guest access to %(rule)s",