From f324f676d37ae5d330beedc77268bbb954fe2cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:14:53 +0100 Subject: [PATCH 01/66] EventIndex: Add a method to get the current disk usage of the index. --- src/indexing/BaseEventIndexManager.js | 7 +++++++ src/indexing/EventIndex.js | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js index 5e8ca668ad..733dc05dd6 100644 --- a/src/indexing/BaseEventIndexManager.js +++ b/src/indexing/BaseEventIndexManager.js @@ -117,6 +117,13 @@ export default class BaseEventIndexManager { throw new Error("Unimplemented"); } + /** + * Get the disk usage of the index + */ + async indexSize(): Promise { + throw new Error("Unimplemented"); + } + /** * Commit the previously queued up events to the index. * diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index c912e31fa5..ae738e5d4d 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -406,4 +406,9 @@ export default class EventIndex { const indexManager = PlatformPeg.get().getEventIndexingManager(); return indexManager.searchEventIndex(searchArgs); } + + async indexSize() { + const indexManager = PlatformPeg.get().getEventIndexingManager(); + return indexManager.indexSize(); + } } From b7b66cfd9aad22f3a00e3b3126a708d1d81e0447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:15:55 +0100 Subject: [PATCH 02/66] EventIndex: Use the sleep method from our utils. --- src/indexing/EventIndex.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index ae738e5d4d..f034df888c 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -16,6 +16,7 @@ limitations under the License. import PlatformPeg from "../PlatformPeg"; import {MatrixClientPeg} from "../MatrixClientPeg"; +import {sleep} from "../utils/promise"; /* * Event indexing class that wraps the platform specific event indexing. @@ -180,12 +181,6 @@ export default class EventIndex { } async crawlerFunc() { - // TODO either put this in a better place or find a library provided - // method that does this. - const sleep = async (ms) => { - return new Promise(resolve => setTimeout(resolve, ms)); - }; - let cancelled = false; console.log("EventIndex: Started crawler function"); From 47156351a6d9ffe9ee2110c63c8667fc043c8936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:25:34 +0100 Subject: [PATCH 03/66] EventIndex: Use a setting for the crawler sleep time. --- src/indexing/EventIndex.js | 24 ++++++++++++++++++++---- src/settings/Settings.js | 5 +++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index f034df888c..1e15fcaa5a 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -16,6 +16,8 @@ limitations under the License. import PlatformPeg from "../PlatformPeg"; import {MatrixClientPeg} from "../MatrixClientPeg"; +import SettingsStore from '../settings/SettingsStore'; +import {SettingLevel} from "../settings/SettingsStore"; import {sleep} from "../utils/promise"; /* @@ -24,9 +26,9 @@ import {sleep} from "../utils/promise"; export default class EventIndex { constructor() { this.crawlerCheckpoints = []; - // The time that the crawler will wait between /rooms/{room_id}/messages - // requests - this._crawlerTimeout = 3000; + // The time in ms that the crawler will wait loop iterations if there + // have not been any checkpoints to consume in the last iteration. + this._crawlerIdleTime = 5000; // The maximum number of events our crawler should fetch in a single // crawl. this._eventsPerCrawl = 100; @@ -194,11 +196,22 @@ export default class EventIndex { cancelled = true; }; + let idle = false; + while (!cancelled) { // This is a low priority task and we don't want to spam our // homeserver with /messages requests so we set a hefty timeout // here. - await sleep(this._crawlerTimeout); + let sleepTime = SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'); + + // Don't let the user configure a lower sleep time than 100 ms. + sleepTime = Math.max(sleepTime, 100); + + if (idle) { + sleepTime = this._crawlerIdleTime; + } + + await sleep(sleepTime); console.log("EventIndex: Running the crawler loop."); @@ -211,9 +224,12 @@ export default class EventIndex { /// There is no checkpoint available currently, one may appear if // a sync with limited room timelines happens, so go back to sleep. if (checkpoint === undefined) { + idle = true; continue; } + idle = false; + console.log("EventIndex: crawling using checkpoint", checkpoint); // We have a checkpoint, let us fetch some messages, again, very diff --git a/src/settings/Settings.js b/src/settings/Settings.js index eacf63e55d..e967becf98 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -486,4 +486,9 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: RIGHT_PANEL_PHASES.GroupMemberList, }, + "crawlerSleepTime": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("How long should the crawler wait between requests"), + default: 3000, + } }; From 0132c3bbe3521ecd2af39bfd526ea41048791619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:31:16 +0100 Subject: [PATCH 04/66] EventIndex: Start the crawler only if it's configured to start. --- src/indexing/EventIndex.js | 4 +++- src/settings/Settings.js | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 1e15fcaa5a..c907e769b5 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -120,7 +120,9 @@ export default class EventIndex { if (eventIndexWasEmpty) await addInitialCheckpoints(); // Start our crawler. - this.startCrawler(); + if (SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling')) { + this.startCrawler(); + } return; } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index e967becf98..1c65c38167 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -490,5 +490,10 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, displayName: _td("How long should the crawler wait between requests"), default: 3000, + }, + "enableCrawling" : { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td("How long should the crawler wait between requests"), + default: true, } }; From 4fe7752f3cd9d52b97d212afc49fc46c60d318d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:37:07 +0100 Subject: [PATCH 05/66] EventIndex: Add a method to gather the currently crawled rooms. --- src/indexing/EventIndex.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index c907e769b5..1b17cc6d87 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -33,6 +33,7 @@ export default class EventIndex { // crawl. this._eventsPerCrawl = 100; this._crawler = null; + this._currentCheckpoint = null; this.liveEventsForIndex = new Set(); } @@ -213,6 +214,8 @@ export default class EventIndex { sleepTime = this._crawlerIdleTime; } + this._currentCheckpoint = null; + await sleep(sleepTime); console.log("EventIndex: Running the crawler loop."); @@ -230,6 +233,8 @@ export default class EventIndex { continue; } + this._currentCheckpoint = checkpoint; + idle = false; console.log("EventIndex: crawling using checkpoint", checkpoint); @@ -424,4 +429,31 @@ export default class EventIndex { const indexManager = PlatformPeg.get().getEventIndexingManager(); return indexManager.indexSize(); } + + currentlyCrawledRooms() { + let crawlingRooms = new Set(); + let totalRooms = new Set(); + + this.crawlerCheckpoints.forEach((checkpoint, index) => { + crawlingRooms.add(checkpoint.roomId); + }); + + if (this._currentCheckpoint !== null) { + crawlingRooms.add(this._currentCheckpoint.roomId); + } + + const client = MatrixClientPeg.get(); + const rooms = client.getRooms(); + + const isRoomEncrypted = (room) => { + return client.isRoomEncrypted(room.roomId); + }; + + const encryptedRooms = rooms.filter(isRoomEncrypted); + encryptedRooms.forEach((room, index) => { + totalRooms.add(room.roomId); + }); + + return {crawlingRooms, totalRooms} + } } From 928bb69b116fbfb3041d6b2538080b37f503e7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:37:53 +0100 Subject: [PATCH 06/66] EventIndexPeg: Add a helper method to easily start the crawler. --- src/indexing/EventIndexPeg.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index 3746591b1f..a63756ab4e 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -69,6 +69,11 @@ class EventIndexPeg { return this.index; } + start() { + if (this.index === null) return; + this.index.startCrawler(); + } + stop() { if (this.index === null) return; this.index.stopCrawler(); From 2fe36037371fc723d4d7219e884b8fb77298a8ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:39:45 +0100 Subject: [PATCH 07/66] utils: Add an utility function to format bytes. --- src/utils/FormattingUtils.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/utils/FormattingUtils.js b/src/utils/FormattingUtils.js index 1fd7d00feb..9016d62cfb 100644 --- a/src/utils/FormattingUtils.js +++ b/src/utils/FormattingUtils.js @@ -30,6 +30,22 @@ export function formatCount(count) { return (count / 1000000000).toFixed(1) + "B"; // 10B is enough for anyone, right? :S } +/** + * format a size in bytes into a human readable form + * e.g: 1024 -> 1.00 KB + */ +export function formatBytes(bytes, decimals = 2) { + if (bytes === 0) return '0 Bytes'; + + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; +} + /** * format a key into groups of 4 characters, for easier visual inspection * From c397de18bdea962ca8dca8f2f1a98c26aa29941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 13:43:47 +0100 Subject: [PATCH 08/66] PreferencesUserSettingsTab: Add initial event indexing preferences. --- .../tabs/user/PreferencesUserSettingsTab.js | 91 +++++++++++++++++++ src/i18n/strings/en_EN.json | 9 ++ 2 files changed, 100 insertions(+) diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index db5b95cb4c..d1fed21a1f 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -23,6 +23,8 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; +import EventIndexPeg from "../../../../../indexing/EventIndexPeg"; +import {formatBytes} from "../../../../../utils/FormattingUtils"; export default class PreferencesUserSettingsTab extends React.Component { static COMPOSER_SETTINGS = [ @@ -70,6 +72,13 @@ export default class PreferencesUserSettingsTab extends React.Component { alwaysShowMenuBarSupported: false, minimizeToTray: true, minimizeToTraySupported: false, + eventIndexSize: 0, + crawlingRooms: 0, + totalCrawlingRooms: 0, + eventIndexingEnabled: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), + crawlerSleepTime: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), autocompleteDelay: SettingsStore.getValueAt(SettingLevel.DEVICE, 'autocompleteDelay').toString(10), readMarkerInViewThresholdMs: @@ -100,6 +109,19 @@ export default class PreferencesUserSettingsTab extends React.Component { minimizeToTray = await platform.getMinimizeToTrayEnabled(); } + let eventIndexSize = 0; + let crawlingRooms = 0; + let totalCrawlingRooms = 0; + + let eventIndex = EventIndexPeg.get(); + + if (eventIndex !== null) { + eventIndexSize = await eventIndex.indexSize(); + let crawledRooms = eventIndex.currentlyCrawledRooms(); + crawlingRooms = crawledRooms.crawlingRooms.size; + totalCrawlingRooms = crawledRooms.totalRooms.size; + } + this.setState({ autoLaunch, autoLaunchSupported, @@ -107,6 +129,9 @@ export default class PreferencesUserSettingsTab extends React.Component { alwaysShowMenuBar, minimizeToTraySupported, minimizeToTray, + eventIndexSize, + crawlingRooms, + totalCrawlingRooms, }); } @@ -137,6 +162,20 @@ export default class PreferencesUserSettingsTab extends React.Component { SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.value); }; + _onEventIndexingEnabledChange = (checked) => { + SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); + + if (checked) EventIndexPeg.start(); + else EventIndexPeg.stop(); + + this.setState({eventIndexingEnabled: checked}); + } + + _onCrawlerSleepTimeChange = (e) => { + this.setState({crawlerSleepTime: e.target.value}); + SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); + } + _renderGroup(settingIds) { const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag"); return settingIds.map(i => ); @@ -167,9 +206,61 @@ export default class PreferencesUserSettingsTab extends React.Component { label={_t('Show tray icon and minimize window to it on close')} />; } + let eventIndexingSettings = null; + let crawlerState; + + if (!this.state.eventIndexingEnabled) { + crawlerState =
{_t("Message downloader is stopped.")}
; + } + else if (this.state.crawlingRooms === 0) { + crawlerState =
{_t("Message downloader is currently idle.")}
; + } else { + crawlerState = ( +
{_t( + "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", + { crawlingRooms: this.state.crawlingRooms, + totalRooms: this.state.totalCrawlingRooms, + })} +
+ ); + } + + if (EventIndexPeg.get() !== null) { + eventIndexingSettings = ( +
+ {_t("Encrypted search")} + { + _t( "To enable search in encrypted rooms, Riot needs to run " + + "a background process to download historical messages " + + "from those rooms to your computer." + ) + } +
+ {_t("Message disk usage:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {crawlerState}
+
+ + + + +
+ ); + } + return (
{_t("Preferences")}
+ + {eventIndexingSettings} +
{_t("Composer")} {this._renderGroup(PreferencesUserSettingsTab.COMPOSER_SETTINGS)} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f8b17db7c5..aa8583cf8d 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -415,6 +415,7 @@ "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)", "Send read receipts for messages (requires compatible homeserver to disable)": "Send read receipts for messages (requires compatible homeserver to disable)", "Show previews/thumbnails for images": "Show previews/thumbnails for images", + "How long should the crawler wait between requests": "How long should the crawler wait between requests", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", "Uploading report": "Uploading report", @@ -731,6 +732,14 @@ "Start automatically after system login": "Start automatically after system login", "Always show the window menu bar": "Always show the window menu bar", "Show tray icon and minimize window to it on close": "Show tray icon and minimize window to it on close", + "Message downloader is stopped.": "Message downloader is stopped.", + "Message downloader is currently idle.": "Message downloader is currently idle.", + "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.": "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", + "Encrypted search": "Encrypted search", + "To enable search in encrypted rooms, Riot needs to run a background process to download historical messages from those rooms to your computer.": "To enable search in encrypted rooms, Riot needs to run a background process to download historical messages from those rooms to your computer.", + "Message disk usage:": "Message disk usage:", + "Enable message downloading": "Enable message downloading", + "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", "Preferences": "Preferences", "Composer": "Composer", "Timeline": "Timeline", From 3c46a563914f0347ebdfed3f80161ea86b4e841b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 26 Nov 2019 15:06:04 +0100 Subject: [PATCH 09/66] EventIndex: Fix some lint errors. --- .../settings/tabs/user/PreferencesUserSettingsTab.js | 11 +++++------ src/indexing/EventIndex.js | 6 +++--- src/settings/Settings.js | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index d1fed21a1f..e47f591dcb 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -113,11 +113,11 @@ export default class PreferencesUserSettingsTab extends React.Component { let crawlingRooms = 0; let totalCrawlingRooms = 0; - let eventIndex = EventIndexPeg.get(); + const eventIndex = EventIndexPeg.get(); if (eventIndex !== null) { eventIndexSize = await eventIndex.indexSize(); - let crawledRooms = eventIndex.currentlyCrawledRooms(); + const crawledRooms = eventIndex.currentlyCrawledRooms(); crawlingRooms = crawledRooms.crawlingRooms.size; totalCrawlingRooms = crawledRooms.totalRooms.size; } @@ -211,8 +211,7 @@ export default class PreferencesUserSettingsTab extends React.Component { if (!this.state.eventIndexingEnabled) { crawlerState =
{_t("Message downloader is stopped.")}
; - } - else if (this.state.crawlingRooms === 0) { + } else if (this.state.crawlingRooms === 0) { crawlerState =
{_t("Message downloader is currently idle.")}
; } else { crawlerState = ( @@ -231,8 +230,8 @@ export default class PreferencesUserSettingsTab extends React.Component { {_t("Encrypted search")} { _t( "To enable search in encrypted rooms, Riot needs to run " + - "a background process to download historical messages " + - "from those rooms to your computer." + "a background process to download historical messages " + + "from those rooms to your computer.", ) }
diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 1b17cc6d87..0d7f43b839 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -431,8 +431,8 @@ export default class EventIndex { } currentlyCrawledRooms() { - let crawlingRooms = new Set(); - let totalRooms = new Set(); + const crawlingRooms = new Set(); + const totalRooms = new Set(); this.crawlerCheckpoints.forEach((checkpoint, index) => { crawlingRooms.add(checkpoint.roomId); @@ -454,6 +454,6 @@ export default class EventIndex { totalRooms.add(room.roomId); }); - return {crawlingRooms, totalRooms} + return {crawlingRooms, totalRooms}; } } diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 1c65c38167..817adcfc4d 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -491,9 +491,9 @@ export const SETTINGS = { displayName: _td("How long should the crawler wait between requests"), default: 3000, }, - "enableCrawling" : { + "enableCrawling": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, displayName: _td("How long should the crawler wait between requests"), default: true, - } + }, }; From 3b99f7565dbbf453eb615f9034db2dfd574c9128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 17 Jan 2020 17:10:59 +0100 Subject: [PATCH 10/66] PreferencesUserSettingsTab: Move the event index UI into a separate component. --- .../views/settings/EventIndexPanel.js | 131 ++++++++++++++++++ .../tabs/user/PreferencesUserSettingsTab.js | 90 +----------- 2 files changed, 134 insertions(+), 87 deletions(-) create mode 100644 src/components/views/settings/EventIndexPanel.js diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js new file mode 100644 index 0000000000..98ba83f62b --- /dev/null +++ b/src/components/views/settings/EventIndexPanel.js @@ -0,0 +1,131 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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 * as sdk from '../../../index'; +import { _t } from '../../../languageHandler'; +import Modal from '../../../Modal'; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; +import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; +import Field from "../elements/Field"; +import {formatBytes} from "../../../utils/FormattingUtils"; +import EventIndexPeg from "../../../indexing/EventIndexPeg"; + +export default class EventIndexPanel extends React.Component { + constructor() { + super(); + + this.state = { + eventIndexSize: 0, + crawlingRooms: 0, + totalCrawlingRooms: 0, + eventIndexingEnabled: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), + crawlerSleepTime: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), + }; + } + + async componentWillMount(): void { + let eventIndexSize = 0; + let crawlingRooms = 0; + let totalCrawlingRooms = 0; + + const eventIndex = EventIndexPeg.get(); + + if (eventIndex !== null) { + eventIndexSize = await eventIndex.indexSize(); + const crawledRooms = eventIndex.currentlyCrawledRooms(); + crawlingRooms = crawledRooms.crawlingRooms.size; + totalCrawlingRooms = crawledRooms.totalRooms.size; + } + + this.setState({ + eventIndexSize, + crawlingRooms, + totalCrawlingRooms, + }); + } + + _onEventIndexingEnabledChange = (checked) => { + SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); + + if (checked) EventIndexPeg.start(); + else EventIndexPeg.stop(); + + this.setState({eventIndexingEnabled: checked}); + } + + _onCrawlerSleepTimeChange = (e) => { + this.setState({crawlerSleepTime: e.target.value}); + SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); + } + + render() { + let eventIndexingSettings = null; + let crawlerState; + + if (!this.state.eventIndexingEnabled) { + crawlerState =
{_t("Message downloader is stopped.")}
; + } else if (this.state.crawlingRooms === 0) { + crawlerState =
{_t("Message downloader is currently idle.")}
; + } else { + crawlerState = ( +
{_t( + "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", + { crawlingRooms: this.state.crawlingRooms, + totalRooms: this.state.totalCrawlingRooms, + })} +
+ ); + } + + if (EventIndexPeg.get() !== null) { + eventIndexingSettings = ( +
+ {_t("Encrypted search")} + { + _t( "To enable search in encrypted rooms, Riot needs to run " + + "a background process to download historical messages " + + "from those rooms to your computer.", + ) + } +
+ {_t("Message disk usage:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {crawlerState}
+
+ + + + +
+ ); + } + + return eventIndexingSettings; + } +} diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index e47f591dcb..5ecafcc5ae 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -23,7 +23,6 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; -import EventIndexPeg from "../../../../../indexing/EventIndexPeg"; import {formatBytes} from "../../../../../utils/FormattingUtils"; export default class PreferencesUserSettingsTab extends React.Component { @@ -72,13 +71,6 @@ export default class PreferencesUserSettingsTab extends React.Component { alwaysShowMenuBarSupported: false, minimizeToTray: true, minimizeToTraySupported: false, - eventIndexSize: 0, - crawlingRooms: 0, - totalCrawlingRooms: 0, - eventIndexingEnabled: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), - crawlerSleepTime: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), autocompleteDelay: SettingsStore.getValueAt(SettingLevel.DEVICE, 'autocompleteDelay').toString(10), readMarkerInViewThresholdMs: @@ -109,19 +101,6 @@ export default class PreferencesUserSettingsTab extends React.Component { minimizeToTray = await platform.getMinimizeToTrayEnabled(); } - let eventIndexSize = 0; - let crawlingRooms = 0; - let totalCrawlingRooms = 0; - - const eventIndex = EventIndexPeg.get(); - - if (eventIndex !== null) { - eventIndexSize = await eventIndex.indexSize(); - const crawledRooms = eventIndex.currentlyCrawledRooms(); - crawlingRooms = crawledRooms.crawlingRooms.size; - totalCrawlingRooms = crawledRooms.totalRooms.size; - } - this.setState({ autoLaunch, autoLaunchSupported, @@ -129,9 +108,6 @@ export default class PreferencesUserSettingsTab extends React.Component { alwaysShowMenuBar, minimizeToTraySupported, minimizeToTray, - eventIndexSize, - crawlingRooms, - totalCrawlingRooms, }); } @@ -162,26 +138,14 @@ export default class PreferencesUserSettingsTab extends React.Component { SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.value); }; - _onEventIndexingEnabledChange = (checked) => { - SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); - - if (checked) EventIndexPeg.start(); - else EventIndexPeg.stop(); - - this.setState({eventIndexingEnabled: checked}); - } - - _onCrawlerSleepTimeChange = (e) => { - this.setState({crawlerSleepTime: e.target.value}); - SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); - } - _renderGroup(settingIds) { const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag"); return settingIds.map(i => ); } render() { + const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel'); + let autoLaunchOption = null; if (this.state.autoLaunchSupported) { autoLaunchOption = ; } - let eventIndexingSettings = null; - let crawlerState; - - if (!this.state.eventIndexingEnabled) { - crawlerState =
{_t("Message downloader is stopped.")}
; - } else if (this.state.crawlingRooms === 0) { - crawlerState =
{_t("Message downloader is currently idle.")}
; - } else { - crawlerState = ( -
{_t( - "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", - { crawlingRooms: this.state.crawlingRooms, - totalRooms: this.state.totalCrawlingRooms, - })} -
- ); - } - - if (EventIndexPeg.get() !== null) { - eventIndexingSettings = ( -
- {_t("Encrypted search")} - { - _t( "To enable search in encrypted rooms, Riot needs to run " + - "a background process to download historical messages " + - "from those rooms to your computer.", - ) - } -
- {_t("Message disk usage:")} {formatBytes(this.state.eventIndexSize, 0)}
- {crawlerState}
-
- - - - -
- ); - } - return (
{_t("Preferences")}
- {eventIndexingSettings} +
{_t("Composer")} From 695b8aff5b4672d3af70db317c023f84c9968aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 17 Jan 2020 17:14:55 +0100 Subject: [PATCH 11/66] EventIndexPanel: Reword the enable/disable setting. --- src/components/views/settings/EventIndexPanel.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 98ba83f62b..bade2d8735 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -114,7 +114,7 @@ export default class EventIndexPanel extends React.Component { + label={_t('Download and index encrypted messages')} /> Date: Mon, 20 Jan 2020 17:42:24 +0100 Subject: [PATCH 12/66] EventIndexPanel: Get more stats for our indexer, not just the size. --- .../views/settings/EventIndexPanel.js | 40 +++++++++++++------ src/i18n/strings/en_EN.json | 18 +++++---- src/indexing/BaseEventIndexManager.js | 13 +++++- src/indexing/EventIndex.js | 27 ++++++++++++- 4 files changed, 74 insertions(+), 24 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index bade2d8735..f8c61e092d 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -35,6 +35,9 @@ export default class EventIndexPanel extends React.Component { eventIndexSize: 0, crawlingRooms: 0, totalCrawlingRooms: 0, + eventCount: 0, + roomCount: 0, + currentRoom: null, eventIndexingEnabled: SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), crawlerSleepTime: @@ -44,22 +47,35 @@ export default class EventIndexPanel extends React.Component { async componentWillMount(): void { let eventIndexSize = 0; + let roomCount = 0; + let eventCount = 0; let crawlingRooms = 0; let totalCrawlingRooms = 0; + let currentRoom = null; const eventIndex = EventIndexPeg.get(); if (eventIndex !== null) { - eventIndexSize = await eventIndex.indexSize(); + const stats = await eventIndex.getStats(); + eventIndexSize = stats.size; + roomCount = stats.roomCount; + eventCount = stats.eventCount; + const crawledRooms = eventIndex.currentlyCrawledRooms(); crawlingRooms = crawledRooms.crawlingRooms.size; totalCrawlingRooms = crawledRooms.totalRooms.size; + + const room = eventIndex.currentRoom(); + if (room) currentRoom = room.name; } this.setState({ eventIndexSize, crawlingRooms, totalCrawlingRooms, + eventCount, + roomCount, + currentRoom, }); } @@ -82,16 +98,15 @@ export default class EventIndexPanel extends React.Component { let crawlerState; if (!this.state.eventIndexingEnabled) { - crawlerState =
{_t("Message downloader is stopped.")}
; - } else if (this.state.crawlingRooms === 0) { - crawlerState =
{_t("Message downloader is currently idle.")}
; + crawlerState =
{_t("Message search for encrypted rooms is disabled.")}
; + } else if (this.state.currentRoom === null) { + crawlerState =
{_t("Not currently downloading messages for any room.")}
; } else { crawlerState = (
{_t( - "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", - { crawlingRooms: this.state.crawlingRooms, - totalRooms: this.state.totalCrawlingRooms, - })} + "Downloading mesages for %(currentRoom)s.", + { currentRoom: this.state.currentRoom } + )}
); } @@ -101,13 +116,14 @@ export default class EventIndexPanel extends React.Component {
{_t("Encrypted search")} { - _t( "To enable search in encrypted rooms, Riot needs to run " + - "a background process to download historical messages " + - "from those rooms to your computer.", + _t( "Riot is securely caching encrypted messages locally for them" + + "to appear in search results:" ) }
- {_t("Message disk usage:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {_t("Indexed messages:")} {this.state.eventCount}
+ {_t("Number of rooms:")} {this.state.roomCount}
{crawlerState}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 1d1636bfb2..a968c145d9 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -554,6 +554,16 @@ "Failed to set display name": "Failed to set display name", "Disable Notifications": "Disable Notifications", "Enable Notifications": "Enable Notifications", + "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", + "Not currently downloading messages for any room.": "Not currently downloading messages for any room.", + "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", + "Encrypted search": "Encrypted search", + "Riot is securely caching encrypted messages locally for themto appear in search results:": "Riot is securely caching encrypted messages locally for themto appear in search results:", + "Space used:": "Space used:", + "Indexed messages:": "Indexed messages:", + "Number of rooms:": "Number of rooms:", + "Download and index encrypted messages": "Download and index encrypted messages", + "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", "The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.", @@ -732,14 +742,6 @@ "Start automatically after system login": "Start automatically after system login", "Always show the window menu bar": "Always show the window menu bar", "Show tray icon and minimize window to it on close": "Show tray icon and minimize window to it on close", - "Message downloader is stopped.": "Message downloader is stopped.", - "Message downloader is currently idle.": "Message downloader is currently idle.", - "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.": "Currently downloading mesages in %(crawlingRooms)s of %(totalRooms)s rooms.", - "Encrypted search": "Encrypted search", - "To enable search in encrypted rooms, Riot needs to run a background process to download historical messages from those rooms to your computer.": "To enable search in encrypted rooms, Riot needs to run a background process to download historical messages from those rooms to your computer.", - "Message disk usage:": "Message disk usage:", - "Download and index encrypted messages": "Download and index encrypted messages", - "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", "Preferences": "Preferences", "Composer": "Composer", "Timeline": "Timeline", diff --git a/src/indexing/BaseEventIndexManager.js b/src/indexing/BaseEventIndexManager.js index 733dc05dd6..819b3e65a7 100644 --- a/src/indexing/BaseEventIndexManager.js +++ b/src/indexing/BaseEventIndexManager.js @@ -67,6 +67,12 @@ export interface HistoricEvent { profile: MatrixProfile; } +export interface IndexStats { + size: number; + event_count: number; + room_count: number; +} + /** * Base class for classes that provide platform-specific event indexing. * @@ -118,9 +124,12 @@ export default class BaseEventIndexManager { } /** - * Get the disk usage of the index + * Get statistical information of the index. + * + * @return {Promise} A promise that will resolve to the index + * statistics. */ - async indexSize(): Promise { + async getStats(): Promise { throw new Error("Unimplemented"); } diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 0d7f43b839..d00a0530ba 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -425,9 +425,9 @@ export default class EventIndex { return indexManager.searchEventIndex(searchArgs); } - async indexSize() { + async getStats() { const indexManager = PlatformPeg.get().getEventIndexingManager(); - return indexManager.indexSize(); + return indexManager.getStats(); } currentlyCrawledRooms() { @@ -456,4 +456,27 @@ export default class EventIndex { return {crawlingRooms, totalRooms}; } + + /** + * Get the room that we are currently crawling. + * + * @returns A MatrixRoom that is being currently crawled, null if no room is + * currently being crawled. + */ + currentRoom() { + if (this._currentCheckpoint === null && this.crawlerCheckpoints.length === 0) { + console.log("EventIndex: No current nor any checkpoint"); + return null; + } + + const client = MatrixClientPeg.get(); + + if (this._currentCheckpoint !== null) { + console.log("EventIndex: Current checkpoint available"); + return client.getRoom(this._currentCheckpoint.roomId); + } else { + console.log("EventIndex: No current but have checkpoint available"); + return client.getRoom(this.crawlerCheckpoints[0].roomId); + } + } } From 8de149704e52c4b1872b32efb899bdd5fd0b6707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 20 Jan 2020 17:43:55 +0100 Subject: [PATCH 13/66] EventIndexPanel: Dynamically update the indexer stats. --- .../views/settings/EventIndexPanel.js | 25 +++++++++++++++++++ src/indexing/EventIndex.js | 23 ++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index f8c61e092d..b777957a3a 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -45,6 +45,29 @@ export default class EventIndexPanel extends React.Component { }; } + async updateCurrentRoom(room) { + const eventIndex = EventIndexPeg.get(); + const stats = await eventIndex.getStats(); + let currentRoom = null; + + if (room) currentRoom = room.name; + + this.setState({ + eventIndexSize: stats.size, + roomCount: stats.roomCount, + eventCount: stats.eventCount, + currentRoom: currentRoom, + }); + } + + componentWillUnmount(): void { + const eventIndex = EventIndexPeg.get(); + + if (eventIndex !== null) { + eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom.bind(this)); + } + } + async componentWillMount(): void { let eventIndexSize = 0; let roomCount = 0; @@ -56,6 +79,8 @@ export default class EventIndexPanel extends React.Component { const eventIndex = EventIndexPeg.get(); if (eventIndex !== null) { + eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this)); + const stats = await eventIndex.getStats(); eventIndexSize = stats.size; roomCount = stats.roomCount; diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index d00a0530ba..5676636eed 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -19,6 +19,7 @@ import {MatrixClientPeg} from "../MatrixClientPeg"; import SettingsStore from '../settings/SettingsStore'; import {SettingLevel} from "../settings/SettingsStore"; import {sleep} from "../utils/promise"; +import {EventEmitter} from "events"; /* * Event indexing class that wraps the platform specific event indexing. @@ -35,6 +36,7 @@ export default class EventIndex { this._crawler = null; this._currentCheckpoint = null; this.liveEventsForIndex = new Set(); + this._eventEmitter = new EventEmitter(); } async init() { @@ -185,6 +187,10 @@ export default class EventIndex { indexManager.addEventToIndex(e, profile); } + emitNewCheckpoint() { + this._eventEmitter.emit("changedCheckpoint", this.currentRoom()); + } + async crawlerFunc() { let cancelled = false; @@ -214,7 +220,10 @@ export default class EventIndex { sleepTime = this._crawlerIdleTime; } - this._currentCheckpoint = null; + if (this._currentCheckpoint !== null) { + this._currentCheckpoint = null; + this.emitNewCheckpoint(); + } await sleep(sleepTime); @@ -234,6 +243,7 @@ export default class EventIndex { } this._currentCheckpoint = checkpoint; + this.emitNewCheckpoint(); idle = false; @@ -465,18 +475,23 @@ export default class EventIndex { */ currentRoom() { if (this._currentCheckpoint === null && this.crawlerCheckpoints.length === 0) { - console.log("EventIndex: No current nor any checkpoint"); return null; } const client = MatrixClientPeg.get(); if (this._currentCheckpoint !== null) { - console.log("EventIndex: Current checkpoint available"); return client.getRoom(this._currentCheckpoint.roomId); } else { - console.log("EventIndex: No current but have checkpoint available"); return client.getRoom(this.crawlerCheckpoints[0].roomId); } } + + on(eventName, callback) { + this._eventEmitter.on(eventName, callback); + } + + removeListener(eventName, callback) { + this._eventEmitter.removeListener(eventName, callback); + } } From 4913d579e37c5bcb0c39d6291fb1e43110c4ffc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 09:24:20 +0100 Subject: [PATCH 14/66] EventIndexPanel: Reword the crawler state if no room is being crawled. --- src/components/views/settings/EventIndexPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index b777957a3a..b3c75cd336 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -125,7 +125,7 @@ export default class EventIndexPanel extends React.Component { if (!this.state.eventIndexingEnabled) { crawlerState =
{_t("Message search for encrypted rooms is disabled.")}
; } else if (this.state.currentRoom === null) { - crawlerState =
{_t("Not currently downloading messages for any room.")}
; + crawlerState =
{_t("Not downloading messages for any room.")}
; } else { crawlerState = (
{_t( From 908a00a13dc936d9bab61c165d9fe941999f8924 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 10:06:04 +0100 Subject: [PATCH 15/66] EventIndexPanel: Move the panel from the preferences to the security tab. --- src/components/views/settings/EventIndexPanel.js | 14 ++++++++++++-- .../tabs/user/PreferencesUserSettingsTab.js | 4 ---- .../settings/tabs/user/SecurityUserSettingsTab.js | 9 +++++++++ src/i18n/strings/en_EN.json | 5 +++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index b3c75cd336..5b8029a09a 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -138,8 +138,7 @@ export default class EventIndexPanel extends React.Component { if (EventIndexPeg.get() !== null) { eventIndexingSettings = ( -
- {_t("Encrypted search")} +
{ _t( "Riot is securely caching encrypted messages locally for them" + "to appear in search results:" @@ -165,6 +164,17 @@ export default class EventIndexPanel extends React.Component { onChange={this._onCrawlerSleepTimeChange} />
); + } else { + eventIndexingSettings = ( +
+ { + _t( "Riot can't securely cache encrypted messages locally" + + "while running in a web browser. Use Riot Desktop for" + + "encrypted messages to appear in search results." + ) + } +
+ ); } return eventIndexingSettings; diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index 5ecafcc5ae..8cbaba037d 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -144,8 +144,6 @@ export default class PreferencesUserSettingsTab extends React.Component { } render() { - const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel'); - let autoLaunchOption = null; if (this.state.autoLaunchSupported) { autoLaunchOption =
{_t("Preferences")}
- -
{_t("Composer")} {this._renderGroup(PreferencesUserSettingsTab.COMPOSER_SETTINGS)} diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 5eadfc234a..8ef9983efd 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -242,6 +242,7 @@ export default class SecurityUserSettingsTab extends React.Component { render() { const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel'); const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag'); + const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel'); const KeyBackupPanel = sdk.getComponent('views.settings.KeyBackupPanel'); const keyBackup = ( @@ -253,6 +254,13 @@ export default class SecurityUserSettingsTab extends React.Component {
); + const eventIndex = ( +
+ {_t("Encrypted search")} + +
+ ); + // XXX: There's no such panel in the current cross-signing designs, but // it's useful to have for testing the feature. If there's no interest // in having advanced details here once all flows are implemented, we @@ -281,6 +289,7 @@ export default class SecurityUserSettingsTab extends React.Component {
{keyBackup} + {eventIndex} {crossSigning} {this._renderCurrentDeviceInfo()}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a968c145d9..f78e3594ee 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -555,15 +555,15 @@ "Disable Notifications": "Disable Notifications", "Enable Notifications": "Enable Notifications", "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", - "Not currently downloading messages for any room.": "Not currently downloading messages for any room.", + "Not downloading messages for any room.": "Not downloading messages for any room.", "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", - "Encrypted search": "Encrypted search", "Riot is securely caching encrypted messages locally for themto appear in search results:": "Riot is securely caching encrypted messages locally for themto appear in search results:", "Space used:": "Space used:", "Indexed messages:": "Indexed messages:", "Number of rooms:": "Number of rooms:", "Download and index encrypted messages": "Download and index encrypted messages", "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", + "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", "The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.", @@ -759,6 +759,7 @@ "Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites", "Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites", "Key backup": "Key backup", + "Encrypted search": "Encrypted search", "Cross-signing": "Cross-signing", "Security & Privacy": "Security & Privacy", "Devices": "Devices", From 6b85284632fad2d83f38d9f71959e8afcac1a76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 13:20:30 +0100 Subject: [PATCH 16/66] EventIndexPanel: Move the bulk of the event index info into a modal. --- .../dialogs/eventindex/ManageEventIndex.js | 226 ++++++++++++++++++ .../views/settings/EventIndexPanel.js | 93 ++----- src/i18n/strings/en_EN.json | 25 +- 3 files changed, 259 insertions(+), 85 deletions(-) create mode 100644 src/async-components/views/dialogs/eventindex/ManageEventIndex.js diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js new file mode 100644 index 0000000000..23aa61c33a --- /dev/null +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -0,0 +1,226 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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 * as sdk from '../../../../index'; +import {MatrixClientPeg} from '../../../../MatrixClientPeg'; +import PropTypes from 'prop-types'; +import { _t } from '../../../../languageHandler'; + +import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import LabelledToggleSwitch from "../../../../components/views/elements/LabelledToggleSwitch"; +import Field from "../../../../components/views/elements/Field"; +import {formatBytes} from "../../../../utils/FormattingUtils"; +import EventIndexPeg from "../../../../indexing/EventIndexPeg"; +import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; + + +/* + * Walks the user through the process of creating an e2e key backup + * on the server. + */ +export default class ManageEventIndex extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + } + + constructor(props) { + super(props); + + this.state = { + eventIndexSize: 0, + crawlingRooms: 0, + totalCrawlingRooms: 0, + eventCount: 0, + roomCount: 0, + currentRoom: null, + eventIndexingEnabled: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), + crawlerSleepTime: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), + }; + + } + + async updateCurrentRoom(room) { + const eventIndex = EventIndexPeg.get(); + const stats = await eventIndex.getStats(); + let currentRoom = null; + + if (room) currentRoom = room.name; + + this.setState({ + eventIndexSize: stats.size, + roomCount: stats.roomCount, + eventCount: stats.eventCount, + currentRoom: currentRoom, + }); + } + + componentWillUnmount(): void { + const eventIndex = EventIndexPeg.get(); + + if (eventIndex !== null) { + eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom.bind(this)); + } + } + + async componentWillMount(): void { + let eventIndexSize = 0; + let roomCount = 0; + let eventCount = 0; + let crawlingRooms = 0; + let totalCrawlingRooms = 0; + let currentRoom = null; + + const eventIndex = EventIndexPeg.get(); + + if (eventIndex !== null) { + eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this)); + + const stats = await eventIndex.getStats(); + eventIndexSize = stats.size; + roomCount = stats.roomCount; + eventCount = stats.eventCount; + + const crawledRooms = eventIndex.currentlyCrawledRooms(); + crawlingRooms = crawledRooms.crawlingRooms.size; + totalCrawlingRooms = crawledRooms.totalRooms.size; + + const room = eventIndex.currentRoom(); + if (room) currentRoom = room.name; + } + + this.setState({ + eventIndexSize, + crawlingRooms, + totalCrawlingRooms, + eventCount, + roomCount, + currentRoom, + }); + } + + _onEventIndexingEnabledChange = (checked) => { + SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); + + if (checked) EventIndexPeg.start(); + else EventIndexPeg.stop(); + + this.setState({eventIndexingEnabled: checked}); + } + + _onCrawlerSleepTimeChange = (e) => { + this.setState({crawlerSleepTime: e.target.value}); + SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); + } + + _onDisable = () => { + this.props.onFinished(false); + } + + _onDone = () => { + this.props.onFinished(true); + } + + render() { + let eventIndexingSettings = null; + let crawlerState; + + if (!this.state.eventIndexingEnabled) { + crawlerState =
{_t("Message search for encrypted rooms is disabled.")}
; + } else if (this.state.currentRoom === null) { + crawlerState =
{_t("Not downloading messages for any room.")}
; + } else { + crawlerState = ( +
{_t( + "Downloading mesages for %(currentRoom)s.", + { currentRoom: this.state.currentRoom } + )} +
+ ); + } + + if (EventIndexPeg.get() !== null) { + eventIndexingSettings = ( +
+ { + _t( "Riot is securely caching encrypted messages locally for them " + + "to appear in search results:" + ) + } +
+ {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {_t("Indexed messages:")} {this.state.eventCount}
+ {_t("Number of rooms:")} {this.state.roomCount}
+ {crawlerState}
+
+ + + + +
+ ); + } else { + eventIndexingSettings = ( +
+ { + _t( "Riot can't securely cache encrypted messages locally" + + "while running in a web browser. Use Riot Desktop for" + + "encrypted messages to appear in search results." + ) + } +
+ ); + } + + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + let buttons; + + buttons =
+
+ + {_t("Disable")} + + + {_t("Done")} + +
+
; + + return ( + {}} + title={_t("Message search")} + > +
+ {eventIndexingSettings} +
+
+ {buttons} +
+
+ ); + } +} diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 5b8029a09a..fd3facbc6b 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -21,6 +21,7 @@ import classNames from 'classnames'; import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; +import AccessibleButton from "../elements/AccessibleButton"; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import Field from "../elements/Field"; @@ -33,30 +34,17 @@ export default class EventIndexPanel extends React.Component { this.state = { eventIndexSize: 0, - crawlingRooms: 0, - totalCrawlingRooms: 0, - eventCount: 0, roomCount: 0, - currentRoom: null, - eventIndexingEnabled: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), - crawlerSleepTime: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), }; } async updateCurrentRoom(room) { const eventIndex = EventIndexPeg.get(); const stats = await eventIndex.getStats(); - let currentRoom = null; - - if (room) currentRoom = room.name; this.setState({ eventIndexSize: stats.size, roomCount: stats.roomCount, - eventCount: stats.eventCount, - currentRoom: currentRoom, }); } @@ -71,10 +59,6 @@ export default class EventIndexPanel extends React.Component { async componentWillMount(): void { let eventIndexSize = 0; let roomCount = 0; - let eventCount = 0; - let crawlingRooms = 0; - let totalCrawlingRooms = 0; - let currentRoom = null; const eventIndex = EventIndexPeg.get(); @@ -84,84 +68,41 @@ export default class EventIndexPanel extends React.Component { const stats = await eventIndex.getStats(); eventIndexSize = stats.size; roomCount = stats.roomCount; - eventCount = stats.eventCount; - - const crawledRooms = eventIndex.currentlyCrawledRooms(); - crawlingRooms = crawledRooms.crawlingRooms.size; - totalCrawlingRooms = crawledRooms.totalRooms.size; - - const room = eventIndex.currentRoom(); - if (room) currentRoom = room.name; } this.setState({ eventIndexSize, - crawlingRooms, - totalCrawlingRooms, - eventCount, roomCount, - currentRoom, }); } - _onEventIndexingEnabledChange = (checked) => { - SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); + _onManage = async () => { + Modal.createTrackedDialogAsync('Message search', 'Message search', + import('../../../async-components/views/dialogs/eventindex/ManageEventIndex'), + { + onFinished: () => {}, + }, null, /* priority = */ false, /* static = */ true, + ); - if (checked) EventIndexPeg.start(); - else EventIndexPeg.stop(); - - this.setState({eventIndexingEnabled: checked}); - } - - _onCrawlerSleepTimeChange = (e) => { - this.setState({crawlerSleepTime: e.target.value}); - SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); } render() { let eventIndexingSettings = null; - let crawlerState; - - if (!this.state.eventIndexingEnabled) { - crawlerState =
{_t("Message search for encrypted rooms is disabled.")}
; - } else if (this.state.currentRoom === null) { - crawlerState =
{_t("Not downloading messages for any room.")}
; - } else { - crawlerState = ( -
{_t( - "Downloading mesages for %(currentRoom)s.", - { currentRoom: this.state.currentRoom } - )} -
- ); - } if (EventIndexPeg.get() !== null) { eventIndexingSettings = (
- { - _t( "Riot is securely caching encrypted messages locally for them" + - "to appear in search results:" - ) - }
- {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
- {_t("Indexed messages:")} {this.state.eventCount}
- {_t("Number of rooms:")} {this.state.roomCount}
- {crawlerState}
+ {_t( "Securely cache encrypted messages locally for them " + + "to appear in search results, using ") + } {formatBytes(this.state.eventIndexSize, 0)} + {_t( " to store messages from ")} {this.state.roomCount} {_t("rooms.")} +
+
+ + {_t("Manage")} +
- - - -
); } else { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f78e3594ee..6b1eda0b0c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -554,15 +554,10 @@ "Failed to set display name": "Failed to set display name", "Disable Notifications": "Disable Notifications", "Enable Notifications": "Enable Notifications", - "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", - "Not downloading messages for any room.": "Not downloading messages for any room.", - "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", - "Riot is securely caching encrypted messages locally for themto appear in search results:": "Riot is securely caching encrypted messages locally for themto appear in search results:", - "Space used:": "Space used:", - "Indexed messages:": "Indexed messages:", - "Number of rooms:": "Number of rooms:", - "Download and index encrypted messages": "Download and index encrypted messages", - "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", + "Securely cache encrypted messages locally for them to appear in search results, using ": "Securely cache encrypted messages locally for them to appear in search results, using ", + " to store messages from ": " to store messages from ", + "rooms.": "rooms.", + "Manage": "Manage", "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", @@ -2040,6 +2035,18 @@ "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "This device has detected that your recovery passphrase and key for Secure Messages have been removed.", "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.", "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", + "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", + "Not downloading messages for any room.": "Not downloading messages for any room.", + "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", + "Riot is securely caching encrypted messages locally for them to appear in search results:": "Riot is securely caching encrypted messages locally for them to appear in search results:", + "Space used:": "Space used:", + "Indexed messages:": "Indexed messages:", + "Number of rooms:": "Number of rooms:", + "Download and index encrypted messages": "Download and index encrypted messages", + "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", + "Disable or enable": "Disable or enable", + "Disable": "Disable", + "Message search": "Message search", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" From 8e26268079ca83954a78336859b679bb0937b533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 13:38:20 +0100 Subject: [PATCH 17/66] SecurityUserSettingsTab: Rename encrypted search section. --- .../views/settings/tabs/user/SecurityUserSettingsTab.js | 2 +- src/i18n/strings/en_EN.json | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 8ef9983efd..7b22dd15e2 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -256,7 +256,7 @@ export default class SecurityUserSettingsTab extends React.Component { const eventIndex = (
- {_t("Encrypted search")} + {_t("Message search")}
); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6b1eda0b0c..b2ac55ba04 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -754,7 +754,7 @@ "Accept all %(invitedRooms)s invites": "Accept all %(invitedRooms)s invites", "Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites", "Key backup": "Key backup", - "Encrypted search": "Encrypted search", + "Message search": "Message search", "Cross-signing": "Cross-signing", "Security & Privacy": "Security & Privacy", "Devices": "Devices", @@ -2044,9 +2044,7 @@ "Number of rooms:": "Number of rooms:", "Download and index encrypted messages": "Download and index encrypted messages", "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", - "Disable or enable": "Disable or enable", "Disable": "Disable", - "Message search": "Message search", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" From a2892f5b02a8998a7d19985b59f65d246d99c99f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 16:40:32 +0100 Subject: [PATCH 18/66] EventIndex: Fix some lint issues. --- src/components/views/settings/EventIndexPanel.js | 9 +-------- .../settings/tabs/user/PreferencesUserSettingsTab.js | 1 - src/indexing/EventIndex.js | 4 ++-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index fd3facbc6b..8ed4b114e7 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -15,16 +15,10 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import classNames from 'classnames'; -import * as sdk from '../../../index'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; import AccessibleButton from "../elements/AccessibleButton"; -import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; -import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; -import Field from "../elements/Field"; import {formatBytes} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; @@ -83,7 +77,6 @@ export default class EventIndexPanel extends React.Component { onFinished: () => {}, }, null, /* priority = */ false, /* static = */ true, ); - } render() { @@ -111,7 +104,7 @@ export default class EventIndexPanel extends React.Component { { _t( "Riot can't securely cache encrypted messages locally" + "while running in a web browser. Use Riot Desktop for" + - "encrypted messages to appear in search results." + "encrypted messages to appear in search results.", ) }
diff --git a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js index 8cbaba037d..bd1b7c2ca4 100644 --- a/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.js @@ -23,7 +23,6 @@ import SettingsStore from "../../../../../settings/SettingsStore"; import Field from "../../../elements/Field"; import * as sdk from "../../../../.."; import PlatformPeg from "../../../../../PlatformPeg"; -import {formatBytes} from "../../../../../utils/FormattingUtils"; export default class PreferencesUserSettingsTab extends React.Component { static COMPOSER_SETTINGS = [ diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 5676636eed..435f67447d 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -470,8 +470,8 @@ export default class EventIndex { /** * Get the room that we are currently crawling. * - * @returns A MatrixRoom that is being currently crawled, null if no room is - * currently being crawled. + * @returns {Room} A MatrixRoom that is being currently crawled, null + * if no room is currently being crawled. */ currentRoom() { if (this._currentCheckpoint === null && this.crawlerCheckpoints.length === 0) { From 47ea453abfbd6ac5ce7f4e474d84eb7c8a3d4083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 21 Jan 2020 16:58:41 +0100 Subject: [PATCH 19/66] ManageEventIndex: Fix a couple of lint issues. --- .../views/dialogs/eventindex/ManageEventIndex.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 23aa61c33a..8623856b2e 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -16,7 +16,6 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../../index'; -import {MatrixClientPeg} from '../../../../MatrixClientPeg'; import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; @@ -52,7 +51,6 @@ export default class ManageEventIndex extends React.Component { crawlerSleepTime: SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), }; - } async updateCurrentRoom(room) { @@ -146,10 +144,8 @@ export default class ManageEventIndex extends React.Component { crawlerState =
{_t("Not downloading messages for any room.")}
; } else { crawlerState = ( -
{_t( - "Downloading mesages for %(currentRoom)s.", - { currentRoom: this.state.currentRoom } - )} +
+ {_t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom })}
); } @@ -159,7 +155,7 @@ export default class ManageEventIndex extends React.Component {
{ _t( "Riot is securely caching encrypted messages locally for them " + - "to appear in search results:" + "to appear in search results:", ) }
@@ -188,7 +184,7 @@ export default class ManageEventIndex extends React.Component { { _t( "Riot can't securely cache encrypted messages locally" + "while running in a web browser. Use Riot Desktop for" + - "encrypted messages to appear in search results." + "encrypted messages to appear in search results.", ) }
@@ -196,9 +192,7 @@ export default class ManageEventIndex extends React.Component { } const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - let buttons; - - buttons =
+ const buttons =
{_t("Disable")} From 4627e3b2825c5b547d1ccfe249ac74b75d5497d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 11:02:44 +0100 Subject: [PATCH 20/66] EventIndex: Refactor out the addInitialCheckpoints method. --- src/indexing/EventIndex.js | 94 +++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 435f67447d..09abb5d209 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -70,62 +70,62 @@ export default class EventIndex { client.removeListener('Room.timelineReset', this.onTimelineReset); } + /** Get crawler checkpoints for the encrypted rooms and store them in the index. + */ + async addInitialCheckpoints() { + const indexManager = PlatformPeg.get().getEventIndexingManager(); + const client = MatrixClientPeg.get(); + const rooms = client.getRooms(); + + const isRoomEncrypted = (room) => { + return client.isRoomEncrypted(room.roomId); + }; + + // We only care to crawl the encrypted rooms, non-encrypted. + // rooms can use the search provided by the homeserver. + const encryptedRooms = rooms.filter(isRoomEncrypted); + + console.log("EventIndex: Adding initial crawler checkpoints"); + + // Gather the prev_batch tokens and create checkpoints for + // our message crawler. + await Promise.all(encryptedRooms.map(async (room) => { + const timeline = room.getLiveTimeline(); + const token = timeline.getPaginationToken("b"); + + console.log("EventIndex: Got token for indexer", + room.roomId, token); + + const backCheckpoint = { + roomId: room.roomId, + token: token, + direction: "b", + }; + + const forwardCheckpoint = { + roomId: room.roomId, + token: token, + direction: "f", + }; + + await indexManager.addCrawlerCheckpoint(backCheckpoint); + await indexManager.addCrawlerCheckpoint(forwardCheckpoint); + this.crawlerCheckpoints.push(backCheckpoint); + this.crawlerCheckpoints.push(forwardCheckpoint); + })); + } + onSync = async (state, prevState, data) => { const indexManager = PlatformPeg.get().getEventIndexingManager(); if (prevState === "PREPARED" && state === "SYNCING") { - const addInitialCheckpoints = async () => { - const client = MatrixClientPeg.get(); - const rooms = client.getRooms(); - - const isRoomEncrypted = (room) => { - return client.isRoomEncrypted(room.roomId); - }; - - // We only care to crawl the encrypted rooms, non-encrypted. - // rooms can use the search provided by the homeserver. - const encryptedRooms = rooms.filter(isRoomEncrypted); - - console.log("EventIndex: Adding initial crawler checkpoints"); - - // Gather the prev_batch tokens and create checkpoints for - // our message crawler. - await Promise.all(encryptedRooms.map(async (room) => { - const timeline = room.getLiveTimeline(); - const token = timeline.getPaginationToken("b"); - - console.log("EventIndex: Got token for indexer", - room.roomId, token); - - const backCheckpoint = { - roomId: room.roomId, - token: token, - direction: "b", - }; - - const forwardCheckpoint = { - roomId: room.roomId, - token: token, - direction: "f", - }; - - await indexManager.addCrawlerCheckpoint(backCheckpoint); - await indexManager.addCrawlerCheckpoint(forwardCheckpoint); - this.crawlerCheckpoints.push(backCheckpoint); - this.crawlerCheckpoints.push(forwardCheckpoint); - })); - }; - // If our indexer is empty we're most likely running Riot the // first time with indexing support or running it with an // initial sync. Add checkpoints to crawl our encrypted rooms. const eventIndexWasEmpty = await indexManager.isEventIndexEmpty(); - if (eventIndexWasEmpty) await addInitialCheckpoints(); + if (eventIndexWasEmpty) await this.addInitialCheckpoints(); - // Start our crawler. - if (SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling')) { - this.startCrawler(); - } + this.startCrawler(); return; } From 5fd121d2afdf7b18ebff311b2221539a492fd20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 11:44:56 +0100 Subject: [PATCH 21/66] ManageEventIndex: Remove the unused stats. --- .../dialogs/eventindex/ManageEventIndex.js | 10 ------- src/indexing/EventIndex.js | 27 ------------------- 2 files changed, 37 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 8623856b2e..d9a0cdcb5d 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -41,8 +41,6 @@ export default class ManageEventIndex extends React.Component { this.state = { eventIndexSize: 0, - crawlingRooms: 0, - totalCrawlingRooms: 0, eventCount: 0, roomCount: 0, currentRoom: null, @@ -80,8 +78,6 @@ export default class ManageEventIndex extends React.Component { let eventIndexSize = 0; let roomCount = 0; let eventCount = 0; - let crawlingRooms = 0; - let totalCrawlingRooms = 0; let currentRoom = null; const eventIndex = EventIndexPeg.get(); @@ -94,18 +90,12 @@ export default class ManageEventIndex extends React.Component { roomCount = stats.roomCount; eventCount = stats.eventCount; - const crawledRooms = eventIndex.currentlyCrawledRooms(); - crawlingRooms = crawledRooms.crawlingRooms.size; - totalCrawlingRooms = crawledRooms.totalRooms.size; - const room = eventIndex.currentRoom(); if (room) currentRoom = room.name; } this.setState({ eventIndexSize, - crawlingRooms, - totalCrawlingRooms, eventCount, roomCount, currentRoom, diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 09abb5d209..a10f4aff71 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -440,33 +440,6 @@ export default class EventIndex { return indexManager.getStats(); } - currentlyCrawledRooms() { - const crawlingRooms = new Set(); - const totalRooms = new Set(); - - this.crawlerCheckpoints.forEach((checkpoint, index) => { - crawlingRooms.add(checkpoint.roomId); - }); - - if (this._currentCheckpoint !== null) { - crawlingRooms.add(this._currentCheckpoint.roomId); - } - - const client = MatrixClientPeg.get(); - const rooms = client.getRooms(); - - const isRoomEncrypted = (room) => { - return client.isRoomEncrypted(room.roomId); - }; - - const encryptedRooms = rooms.filter(isRoomEncrypted); - encryptedRooms.forEach((room, index) => { - totalRooms.add(room.roomId); - }); - - return {crawlingRooms, totalRooms}; - } - /** * Get the room that we are currently crawling. * From 0d545ed3359a665860354e750c114bffbf36b425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 11:47:49 +0100 Subject: [PATCH 22/66] EventIndexPeg: Small refactor and change the init logic. This changes the way the event index is initialized, if it's disabled in the settings it will not be initialized at all, before only the crawler loop was not being started. --- src/indexing/EventIndexPeg.js | 57 +++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index a63756ab4e..c8c8cbefe9 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -21,17 +21,19 @@ limitations under the License. import PlatformPeg from "../PlatformPeg"; import EventIndex from "../indexing/EventIndex"; -import SettingsStore from '../settings/SettingsStore'; +import SettingsStore, {SettingLevel} from '../settings/SettingsStore'; class EventIndexPeg { constructor() { this.index = null; + this._supportIsInstalled = false; } /** - * Create a new EventIndex and initialize it if the platform supports it. + * Initialize the EventIndexPeg and if event indexing is enabled initialize + * the event index. * - * @return {Promise} A promise that will resolve to true if an + * @return {Promise} A promise that will resolve to true if an * EventIndex was successfully initialized, false otherwise. */ async init() { @@ -40,12 +42,32 @@ class EventIndexPeg { } const indexManager = PlatformPeg.get().getEventIndexingManager(); - if (!indexManager || await indexManager.supportsEventIndexing() !== true) { - console.log("EventIndex: Platform doesn't support event indexing,", - "not initializing."); + if (!indexManager) { + console.log("EventIndex: Platform doesn't support event indexing, not initializing."); return false; } + this._supportIsInstalled = await indexManager.supportsEventIndexing(); + + if (!this.supportIsInstalled()) { + console.log("EventIndex: Event indexing isn't installed for the platform, not initializing."); + return false; + } + + if (!SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing')) { + console.log("EventIndex: Event indexing is disabled, not initializing"); + return false; + } + + return this.initEventIndex(); + } + + /* Initialize the event index. + * + * @returns {boolean} True if the event index was succesfully initialized, + * false otherwise. + */ + async initEventIndex() { const index = new EventIndex(); try { @@ -60,6 +82,29 @@ class EventIndexPeg { return true; } + /** + * Check if the current platform has support for event indexing. + * + * @return {boolean} True if it has support, false otherwise. Note that this + * does not mean that support is installed. + */ + platformHasSupport(): boolean { + return PlatformPeg.get().getEventIndexingManager() !== null; + } + + /** + * Check if event indexing support is installed for the platfrom. + * + * Event indexing might require additional optional modules to be installed, + * this tells us if those are installed. Note that this should only be + * called after the init() method was called. + * + * @return {boolean} True if support is installed, false otherwise. + */ + supportIsInstalled(): boolean { + return this._supportIsInstalled; + } + /** * Get the current event index. * From 9bee024da71b7faa06b3c1cec379b0c692d9b895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 12:24:06 +0100 Subject: [PATCH 23/66] ManageEventIndex: Remove some useless divs and add the enable case. --- .../dialogs/eventindex/ManageEventIndex.js | 69 ++++++++++--------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index d9a0cdcb5d..754d1b8516 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -116,7 +116,11 @@ export default class ManageEventIndex extends React.Component { SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); } - _onDisable = () => { + _onDisable = async () => { + this.props.onFinished(false); + } + + _onEnable = async () => { this.props.onFinished(false); } @@ -126,17 +130,16 @@ export default class ManageEventIndex extends React.Component { render() { let eventIndexingSettings = null; + let buttons; let crawlerState; if (!this.state.eventIndexingEnabled) { - crawlerState =
{_t("Message search for encrypted rooms is disabled.")}
; + crawlerState = _t("Message search for encrypted rooms is disabled."); } else if (this.state.currentRoom === null) { - crawlerState =
{_t("Not downloading messages for any room.")}
; + crawlerState = _t("Not downloading messages for any room."); } else { crawlerState = ( -
- {_t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom })} -
+ _t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom }) ); } @@ -154,18 +157,30 @@ export default class ManageEventIndex extends React.Component { {_t("Number of rooms:")} {this.state.roomCount}
{crawlerState}
+
+ ); - - - + buttons = ( +
+ + {_t("Disable")} + + + {_t("Done")} + +
+ ); + } else if (!this.state.eventIndexingEnabled && this.state.eventIndexingInstalled) { + eventIndexingSettings = ( +
+ {_t( "Securely cache encrypted messages locally for them to appear in search results.")} +
+ ); + buttons = ( +
+ + {_t("Enable")} +
); } else { @@ -182,28 +197,14 @@ export default class ManageEventIndex extends React.Component { } const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const buttons =
-
- - {_t("Disable")} - - - {_t("Done")} - -
-
; return ( {}} + onFinished={this.props.onFinished} title={_t("Message search")} > -
- {eventIndexingSettings} -
-
- {buttons} -
+ {eventIndexingSettings} + {buttons}
); } From 4953f32cbae89967bfbea894a8d25740a3b7124a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 12:24:54 +0100 Subject: [PATCH 24/66] ManageEventIndex: Rename the enable crawler setting. --- .../views/dialogs/eventindex/ManageEventIndex.js | 2 +- src/settings/Settings.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 754d1b8516..76e41fe4b8 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -45,7 +45,7 @@ export default class ManageEventIndex extends React.Component { roomCount: 0, currentRoom: null, eventIndexingEnabled: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableCrawling'), + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), crawlerSleepTime: SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), }; diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 817adcfc4d..68b26dbae1 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -491,9 +491,9 @@ export const SETTINGS = { displayName: _td("How long should the crawler wait between requests"), default: 3000, }, - "enableCrawling": { + "enableEventIndexing": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, - displayName: _td("How long should the crawler wait between requests"), + displayName: _td("Enable message search in encrypted rooms"), default: true, }, }; From 947ea9823d6bb22ea57ed854e4e5ace81673bb0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 13:32:27 +0100 Subject: [PATCH 25/66] Settings: Remove the crawler sleep time setting. --- .../views/dialogs/eventindex/ManageEventIndex.js | 16 ---------------- src/indexing/EventIndex.js | 3 ++- src/settings/Settings.js | 5 ----- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 76e41fe4b8..be7df25381 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -46,8 +46,6 @@ export default class ManageEventIndex extends React.Component { currentRoom: null, eventIndexingEnabled: SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), - crawlerSleepTime: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'), }; } @@ -102,20 +100,6 @@ export default class ManageEventIndex extends React.Component { }); } - _onEventIndexingEnabledChange = (checked) => { - SettingsStore.setValue("enableCrawling", null, SettingLevel.DEVICE, checked); - - if (checked) EventIndexPeg.start(); - else EventIndexPeg.stop(); - - this.setState({eventIndexingEnabled: checked}); - } - - _onCrawlerSleepTimeChange = (e) => { - this.setState({crawlerSleepTime: e.target.value}); - SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value); - } - _onDisable = async () => { this.props.onFinished(false); } diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index a10f4aff71..6d38f1683f 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -30,6 +30,7 @@ export default class EventIndex { // The time in ms that the crawler will wait loop iterations if there // have not been any checkpoints to consume in the last iteration. this._crawlerIdleTime = 5000; + this._crawlerSleepTime = 3000; // The maximum number of events our crawler should fetch in a single // crawl. this._eventsPerCrawl = 100; @@ -211,7 +212,7 @@ export default class EventIndex { // This is a low priority task and we don't want to spam our // homeserver with /messages requests so we set a hefty timeout // here. - let sleepTime = SettingsStore.getValueAt(SettingLevel.DEVICE, 'crawlerSleepTime'); + let sleepTime = this._crawlerSleepTime; // Don't let the user configure a lower sleep time than 100 ms. sleepTime = Math.max(sleepTime, 100); diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 68b26dbae1..44f38f232f 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -486,11 +486,6 @@ export const SETTINGS = { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, default: RIGHT_PANEL_PHASES.GroupMemberList, }, - "crawlerSleepTime": { - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, - displayName: _td("How long should the crawler wait between requests"), - default: 3000, - }, "enableEventIndexing": { supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, displayName: _td("Enable message search in encrypted rooms"), From 4aa0658ac8e36f671fc6d715091cfc392e311ebf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 13:33:09 +0100 Subject: [PATCH 26/66] SecurityUserSettingsTab: Put the event index settings behind the feature flag. --- .../settings/tabs/user/SecurityUserSettingsTab.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js index 7b22dd15e2..eb5f346714 100644 --- a/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/SecurityUserSettingsTab.js @@ -254,12 +254,15 @@ export default class SecurityUserSettingsTab extends React.Component {
); - const eventIndex = ( -
- {_t("Message search")} - -
- ); + let eventIndex; + if (SettingsStore.isFeatureEnabled("feature_event_indexing")) { + eventIndex = ( +
+ {_t("Message search")} + +
+ ); + } // XXX: There's no such panel in the current cross-signing designs, but // it's useful to have for testing the feature. If there's no interest From 64c4ad2eb9474dbacd681954682f677fb97d71cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 13:33:55 +0100 Subject: [PATCH 27/66] ManageEventIndex: Hook up the disable event index button. --- .../dialogs/eventindex/DisableEventIndex.js | 74 +++++++++++++++++++ .../dialogs/eventindex/ManageEventIndex.js | 6 +- src/i18n/strings/en_EN.json | 8 +- 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 src/async-components/views/dialogs/eventindex/DisableEventIndex.js diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js new file mode 100644 index 0000000000..159f8b3d95 --- /dev/null +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -0,0 +1,74 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +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 * as sdk from '../../../../index'; +import PropTypes from 'prop-types'; +import { _t } from '../../../../languageHandler'; + +import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; +import LabelledToggleSwitch from "../../../../components/views/elements/LabelledToggleSwitch"; +import Field from "../../../../components/views/elements/Field"; +import {formatBytes} from "../../../../utils/FormattingUtils"; +import EventIndexPeg from "../../../../indexing/EventIndexPeg"; +import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; + + +/* + * Walks the user through the process of creating an e2e key backup + * on the server. + */ +export default class ManageEventIndex extends React.Component { + static propTypes = { + onFinished: PropTypes.func.isRequired, + } + + constructor(props) { + super(props); + + this.state = { + eventIndexingEnabled: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), + }; + } + + _onDisable = async () => { + const eventIndex = EventIndexPeg.get(); + await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false); + await EventIndexPeg.deleteEventIndex(); + this.props.onFinished(true); + } + + render() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); + + return ( + + {_t("If disabled, messages form encrypted rooms won't appear in search results")} + + + ); + } +} diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index be7df25381..cf0e2bccc6 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -19,6 +19,7 @@ import * as sdk from '../../../../index'; import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; +import Modal from '../../../../Modal'; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; import LabelledToggleSwitch from "../../../../components/views/elements/LabelledToggleSwitch"; import Field from "../../../../components/views/elements/Field"; @@ -101,7 +102,10 @@ export default class ManageEventIndex extends React.Component { } _onDisable = async () => { - this.props.onFinished(false); + Modal.createTrackedDialogAsync("Disable message search", "Disable message search", + import("./DisableEventIndex"), + null, null, /* priority = */ false, /* static = */ true, + ); } _onEnable = async () => { diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index b2ac55ba04..31ba5581f3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -416,6 +416,7 @@ "Send read receipts for messages (requires compatible homeserver to disable)": "Send read receipts for messages (requires compatible homeserver to disable)", "Show previews/thumbnails for images": "Show previews/thumbnails for images", "How long should the crawler wait between requests": "How long should the crawler wait between requests", + "Enable message search in encrypted rooms": "Enable message search in encrypted rooms", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", "Uploading report": "Uploading report", @@ -2035,6 +2036,8 @@ "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "This device has detected that your recovery passphrase and key for Secure Messages have been removed.", "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.", "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", + "If disabled, messages form encrypted rooms won't appear in search results": "If disabled, messages form encrypted rooms won't appear in search results", + "Disable": "Disable", "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", "Not downloading messages for any room.": "Not downloading messages for any room.", "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", @@ -2042,9 +2045,8 @@ "Space used:": "Space used:", "Indexed messages:": "Indexed messages:", "Number of rooms:": "Number of rooms:", - "Download and index encrypted messages": "Download and index encrypted messages", - "Message downloading sleep time(ms)": "Message downloading sleep time(ms)", - "Disable": "Disable", + "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", + "Enable": "Enable", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" From c251031dfbf2d432e6818f4c70c0f228f9a15eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 14:25:47 +0100 Subject: [PATCH 28/66] DisableEventIndex: Return back to the user settings after disabling. --- .../views/dialogs/eventindex/DisableEventIndex.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js index 159f8b3d95..3dcbeab454 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import * as sdk from '../../../../index'; import PropTypes from 'prop-types'; +import dis from "../../../../dispatcher"; import { _t } from '../../../../languageHandler'; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; @@ -49,7 +50,8 @@ export default class ManageEventIndex extends React.Component { const eventIndex = EventIndexPeg.get(); await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false); await EventIndexPeg.deleteEventIndex(); - this.props.onFinished(true); + this.props.onFinished(); + dis.dispatch({ action: 'view_user_settings' }); } render() { From 5ac37c8694f8f42c6cadef7225195b35eaea5cd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 14:26:35 +0100 Subject: [PATCH 29/66] ManageEventIndex: Remove the enable button, that one goes somewhere else. --- .../dialogs/eventindex/ManageEventIndex.js | 86 ++++++------------- 1 file changed, 25 insertions(+), 61 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index cf0e2bccc6..76fee228bf 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -45,8 +45,6 @@ export default class ManageEventIndex extends React.Component { eventCount: 0, roomCount: 0, currentRoom: null, - eventIndexingEnabled: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), }; } @@ -108,22 +106,14 @@ export default class ManageEventIndex extends React.Component { ); } - _onEnable = async () => { - this.props.onFinished(false); - } - _onDone = () => { this.props.onFinished(true); } render() { - let eventIndexingSettings = null; - let buttons; let crawlerState; - if (!this.state.eventIndexingEnabled) { - crawlerState = _t("Message search for encrypted rooms is disabled."); - } else if (this.state.currentRoom === null) { + if (this.state.currentRoom === null) { crawlerState = _t("Not downloading messages for any room."); } else { crawlerState = ( @@ -131,58 +121,32 @@ export default class ManageEventIndex extends React.Component { ); } - if (EventIndexPeg.get() !== null) { - eventIndexingSettings = ( -
- { - _t( "Riot is securely caching encrypted messages locally for them " + - "to appear in search results:", - ) - } -
- {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
- {_t("Indexed messages:")} {this.state.eventCount}
- {_t("Number of rooms:")} {this.state.roomCount}
- {crawlerState}
-
+ const eventIndexingSettings = ( +
+ { + _t( "Riot is securely caching encrypted messages locally for them " + + "to appear in search results:", + ) + } +
+ {_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
+ {_t("Indexed messages:")} {this.state.eventCount}
+ {_t("Number of rooms:")} {this.state.roomCount}
+ {crawlerState}
- ); +
+ ); - buttons = ( -
- - {_t("Disable")} - - - {_t("Done")} - -
- ); - } else if (!this.state.eventIndexingEnabled && this.state.eventIndexingInstalled) { - eventIndexingSettings = ( -
- {_t( "Securely cache encrypted messages locally for them to appear in search results.")} -
- ); - buttons = ( -
- - {_t("Enable")} - -
- ); - } else { - eventIndexingSettings = ( -
- { - _t( "Riot can't securely cache encrypted messages locally" + - "while running in a web browser. Use Riot Desktop for" + - "encrypted messages to appear in search results.", - ) - } -
- ); - } + const buttons = ( +
+ + {_t("Disable")} + + + {_t("Done")} + +
+ ); const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); From 981acec0d2030efabec4cf4959aab352f0637c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 14:27:46 +0100 Subject: [PATCH 30/66] EventIndexPanel: Show the enable button if event indexing is disabled. --- .../views/settings/EventIndexPanel.js | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 8ed4b114e7..7cd0dbe753 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -18,6 +18,7 @@ import React from 'react'; import { _t } from '../../../languageHandler'; import Modal from '../../../Modal'; +import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; import {formatBytes} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; @@ -29,6 +30,8 @@ export default class EventIndexPanel extends React.Component { this.state = { eventIndexSize: 0, roomCount: 0, + eventIndexingEnabled: + SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), }; } @@ -51,10 +54,15 @@ export default class EventIndexPanel extends React.Component { } async componentWillMount(): void { + this.updateState(); + } + + async updateState() { let eventIndexSize = 0; let roomCount = 0; const eventIndex = EventIndexPeg.get(); + const eventIndexingEnabled = SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'); if (eventIndex !== null) { eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this)); @@ -67,6 +75,7 @@ export default class EventIndexPanel extends React.Component { this.setState({ eventIndexSize, roomCount, + eventIndexingEnabled, }); } @@ -79,6 +88,14 @@ export default class EventIndexPanel extends React.Component { ); } + _onEnable = async () => { + await EventIndexPeg.initEventIndex(); + await EventIndexPeg.get().addInitialCheckpoints(); + await EventIndexPeg.get().startCrawler(); + await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, true); + await this.updateState(); + } + render() { let eventIndexingSettings = null; @@ -98,12 +115,25 @@ export default class EventIndexPanel extends React.Component {
); + } else if (!this.state.eventIndexingEnabled && EventIndexPeg.supportIsInstalled()) { + eventIndexingSettings = ( +
+
+ {_t( "Securely cache encrypted messages locally for them to appear in search results.")} +
+
+ + {_t("Enable")} + +
+
+ ); } else { eventIndexingSettings = (
{ - _t( "Riot can't securely cache encrypted messages locally" + - "while running in a web browser. Use Riot Desktop for" + + _t( "Riot can't securely cache encrypted messages locally " + + "while running in a web browser. Use Riot Desktop for " + "encrypted messages to appear in search results.", ) } From 3073ce55883dc96b2ed88ad1e586920a4fd2f4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 15:05:40 +0100 Subject: [PATCH 31/66] DisableEventIndex: Set the correct button kind and add a spinner. --- .../dialogs/eventindex/DisableEventIndex.js | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js index 3dcbeab454..6d0f9a43e8 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -41,12 +41,15 @@ export default class ManageEventIndex extends React.Component { super(props); this.state = { - eventIndexingEnabled: - SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'), + disabling: false, }; } _onDisable = async () => { + this.setState({ + disabling: true, + }); + const eventIndex = EventIndexPeg.get(); await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false); await EventIndexPeg.deleteEventIndex(); @@ -64,12 +67,15 @@ export default class ManageEventIndex extends React.Component { title={_t("Are you sure?")} > {_t("If disabled, messages form encrypted rooms won't appear in search results")} - +
+ + {_t("Cancel")} + + + {_t("Disable")} + + {this.state.enabling ? :
} +
); } From 251661388a9dee3d3f9ce394820ebb3fbd607513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 15:06:10 +0100 Subject: [PATCH 32/66] ManageEventIndex: Set the button kind to danger. --- .../views/dialogs/eventindex/ManageEventIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 76fee228bf..b53b4810aa 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -139,7 +139,7 @@ export default class ManageEventIndex extends React.Component { const buttons = (
- + {_t("Disable")} From a5a149933a0dd98e7ca86d08a382a9ff6b0cc48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 15:06:38 +0100 Subject: [PATCH 33/66] EventIndexPanel: Add a spinner when the index is being enabled. --- .../views/settings/EventIndexPanel.js | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 7cd0dbe753..f93ab489c7 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import { _t } from '../../../languageHandler'; +import * as sdk from '../../../index'; import Modal from '../../../Modal'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; @@ -28,6 +29,7 @@ export default class EventIndexPanel extends React.Component { super(); this.state = { + enabling: false, eventIndexSize: 0, roomCount: 0, eventIndexingEnabled: @@ -58,11 +60,12 @@ export default class EventIndexPanel extends React.Component { } async updateState() { - let eventIndexSize = 0; - let roomCount = 0; - const eventIndex = EventIndexPeg.get(); const eventIndexingEnabled = SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'); + const enabling = false; + + let eventIndexSize = 0; + let roomCount = 0; if (eventIndex !== null) { eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this)); @@ -73,6 +76,7 @@ export default class EventIndexPanel extends React.Component { } this.setState({ + enabling, eventIndexSize, roomCount, eventIndexingEnabled, @@ -89,6 +93,10 @@ export default class EventIndexPanel extends React.Component { } _onEnable = async () => { + this.setState({ + enabling: true, + }); + await EventIndexPeg.initEventIndex(); await EventIndexPeg.get().addInitialCheckpoints(); await EventIndexPeg.get().startCrawler(); @@ -98,6 +106,7 @@ export default class EventIndexPanel extends React.Component { render() { let eventIndexingSettings = null; + const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); if (EventIndexPeg.get() !== null) { eventIndexingSettings = ( @@ -119,12 +128,15 @@ export default class EventIndexPanel extends React.Component { eventIndexingSettings = (
- {_t( "Securely cache encrypted messages locally for them to appear in search results.")} + {_t( "Securely cache encrypted messages locally for them to " + + "appear in search results.")}
- + {_t("Enable")} + {this.state.enabling ? :
}
); From 381fe95f67919457cd1cdfa75ba7dd895dd69b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Thu, 23 Jan 2020 15:22:26 +0100 Subject: [PATCH 34/66] EventIndex: Fix some lint errors. --- .../views/dialogs/eventindex/DisableEventIndex.js | 6 +----- .../views/dialogs/eventindex/ManageEventIndex.js | 3 --- src/indexing/EventIndex.js | 2 -- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js index 6d0f9a43e8..064f55edc0 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -21,9 +21,6 @@ import dis from "../../../../dispatcher"; import { _t } from '../../../../languageHandler'; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; -import LabelledToggleSwitch from "../../../../components/views/elements/LabelledToggleSwitch"; -import Field from "../../../../components/views/elements/Field"; -import {formatBytes} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; @@ -50,7 +47,6 @@ export default class ManageEventIndex extends React.Component { disabling: true, }); - const eventIndex = EventIndexPeg.get(); await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false); await EventIndexPeg.deleteEventIndex(); this.props.onFinished(); @@ -59,7 +55,7 @@ export default class ManageEventIndex extends React.Component { render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent("views.elements.DialogButtons"); + const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); return ( Date: Thu, 23 Jan 2020 15:32:43 +0100 Subject: [PATCH 35/66] Update the translation file. --- src/i18n/strings/en_EN.json | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 31ba5581f3..3973ae442e 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -415,7 +415,6 @@ "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)", "Send read receipts for messages (requires compatible homeserver to disable)": "Send read receipts for messages (requires compatible homeserver to disable)", "Show previews/thumbnails for images": "Show previews/thumbnails for images", - "How long should the crawler wait between requests": "How long should the crawler wait between requests", "Enable message search in encrypted rooms": "Enable message search in encrypted rooms", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", @@ -559,7 +558,9 @@ " to store messages from ": " to store messages from ", "rooms.": "rooms.", "Manage": "Manage", - "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locallywhile running in a web browser. Use Riot Desktop forencrypted messages to appear in search results.", + "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", + "Enable": "Enable", + "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", "The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.", @@ -2038,15 +2039,12 @@ "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", "If disabled, messages form encrypted rooms won't appear in search results": "If disabled, messages form encrypted rooms won't appear in search results", "Disable": "Disable", - "Message search for encrypted rooms is disabled.": "Message search for encrypted rooms is disabled.", "Not downloading messages for any room.": "Not downloading messages for any room.", "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", "Riot is securely caching encrypted messages locally for them to appear in search results:": "Riot is securely caching encrypted messages locally for them to appear in search results:", "Space used:": "Space used:", "Indexed messages:": "Indexed messages:", "Number of rooms:": "Number of rooms:", - "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", - "Enable": "Enable", "Failed to set direct chat tag": "Failed to set direct chat tag", "Failed to remove tag %(tagName)s from room": "Failed to remove tag %(tagName)s from room", "Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room" From 86a098fcd983d546b18f1a1eba9e2d1e1f1e6f4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:35:31 +0100 Subject: [PATCH 36/66] DisableEventIndex: Remove a blank line and rewrite a doc comment. --- .../views/dialogs/eventindex/DisableEventIndex.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js index 064f55edc0..5720c26e40 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -24,10 +24,8 @@ import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; - /* - * Walks the user through the process of creating an e2e key backup - * on the server. + * Allows the user to disable the Event Index. */ export default class ManageEventIndex extends React.Component { static propTypes = { From d30fd3eac04ecedd1bbd8dda8b0a38b49f77444d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:39:56 +0100 Subject: [PATCH 37/66] DisableEventIndex: Rename the class. --- .../views/dialogs/eventindex/DisableEventIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js index 5720c26e40..820bcbe047 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndex.js @@ -27,7 +27,7 @@ import AccessibleButton from "../../../../components/views/elements/AccessibleBu /* * Allows the user to disable the Event Index. */ -export default class ManageEventIndex extends React.Component { +export default class DisableEventIndexDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, } From 4ea2d4f90eff09481a75366740274cecb5326b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:45:29 +0100 Subject: [PATCH 38/66] ManageEventIndex: Rewrite the docs and rename the dialog class. --- .../views/dialogs/eventindex/ManageEventIndex.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index d0f3c2cf50..5d75f9b168 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -24,12 +24,10 @@ import {formatBytes} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; - /* - * Walks the user through the process of creating an e2e key backup - * on the server. + * Allows the user to introspect the event index state and disable it. */ -export default class ManageEventIndex extends React.Component { +export default class ManageEventIndexDialog extends React.Component { static propTypes = { onFinished: PropTypes.func.isRequired, } From f763ae3c7bec35d78097249e58859cb55bfaadda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:50:58 +0100 Subject: [PATCH 39/66] DisableEventIndex: Rename the file to contain the Dialog suffix. --- .../{DisableEventIndex.js => DisableEventIndexDialog.js} | 0 .../views/dialogs/eventindex/ManageEventIndex.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/async-components/views/dialogs/eventindex/{DisableEventIndex.js => DisableEventIndexDialog.js} (100%) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndex.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js similarity index 100% rename from src/async-components/views/dialogs/eventindex/DisableEventIndex.js rename to src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js index 5d75f9b168..c9c4fc8ae6 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndex.js @@ -96,7 +96,7 @@ export default class ManageEventIndexDialog extends React.Component { _onDisable = async () => { Modal.createTrackedDialogAsync("Disable message search", "Disable message search", - import("./DisableEventIndex"), + import("./DisableEventIndexDialog"), null, null, /* priority = */ false, /* static = */ true, ); } From 93facca47963ce17ae706f80150333a98ff4dfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:54:46 +0100 Subject: [PATCH 40/66] ManageEventIndex: Rename the file to contain the Dialog suffix. --- .../{ManageEventIndex.js => ManageEventIndexDialog.js} | 0 src/components/views/settings/EventIndexPanel.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/async-components/views/dialogs/eventindex/{ManageEventIndex.js => ManageEventIndexDialog.js} (100%) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndex.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js similarity index 100% rename from src/async-components/views/dialogs/eventindex/ManageEventIndex.js rename to src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index f93ab489c7..785ce2a4ca 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -85,7 +85,7 @@ export default class EventIndexPanel extends React.Component { _onManage = async () => { Modal.createTrackedDialogAsync('Message search', 'Message search', - import('../../../async-components/views/dialogs/eventindex/ManageEventIndex'), + import('../../../async-components/views/dialogs/eventindex/ManageEventIndexDialog'), { onFinished: () => {}, }, null, /* priority = */ false, /* static = */ true, From b59863781f703997058ab8bd4af9acab349d8e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:58:17 +0100 Subject: [PATCH 41/66] DisableEventIndexDialog: Fix a typo. --- .../views/dialogs/eventindex/DisableEventIndexDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 820bcbe047..7f46b54f65 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -60,7 +60,7 @@ export default class DisableEventIndexDialog extends React.Component { onFinished={this.props.onFinished} title={_t("Are you sure?")} > - {_t("If disabled, messages form encrypted rooms won't appear in search results")} + {_t("If disabled, messages from encrypted rooms won't appear in search results.")}
{_t("Cancel")} From 72a58d0c2c274ee6b7a874205e3a8ee13ade4f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 09:59:26 +0100 Subject: [PATCH 42/66] DisableEventIndexDialog: Properly indent the content of the BaseDialog. --- .../eventindex/DisableEventIndexDialog.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 7f46b54f65..7097ffb3bf 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -60,16 +60,16 @@ export default class DisableEventIndexDialog extends React.Component { onFinished={this.props.onFinished} title={_t("Are you sure?")} > - {_t("If disabled, messages from encrypted rooms won't appear in search results.")} -
- - {_t("Cancel")} - - - {_t("Disable")} - - {this.state.enabling ? :
} -
+ {_t("If disabled, messages from encrypted rooms won't appear in search results.")} +
+ + {_t("Cancel")} + + + {_t("Disable")} + + {this.state.enabling ? :
} +
); } From cba7764784e1b60365cfcac0ea8f5ea3310dcaa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:00:28 +0100 Subject: [PATCH 43/66] DisableEventIndexDialog: Use the DialogButtons element for the buttons. --- .../eventindex/DisableEventIndexDialog.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 7097ffb3bf..2e0f97c705 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -53,7 +53,8 @@ export default class DisableEventIndexDialog extends React.Component { render() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const InlineSpinner = sdk.getComponent('elements.InlineSpinner'); + const Spinner = sdk.getComponent('elements.Spinner'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( {_t("If disabled, messages from encrypted rooms won't appear in search results.")} -
- - {_t("Cancel")} - - - {_t("Disable")} - - {this.state.enabling ? :
} -
+ {this.state.disabling ? :
} + + ); } From 71024d14188cb70965eb69b64c7f8fcf384a39eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:03:40 +0100 Subject: [PATCH 44/66] ManageEventIndexDialog: Properly indent the content of the BaseDialog. --- .../views/dialogs/eventindex/ManageEventIndexDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index c9c4fc8ae6..f435cf050f 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -150,8 +150,8 @@ export default class ManageEventIndexDialog extends React.Component { onFinished={this.props.onFinished} title={_t("Message search")} > - {eventIndexingSettings} - {buttons} + {eventIndexingSettings} + {buttons} ); } From 128c0b73004e27cb6d5ff16da01f48a99785d72b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:11:53 +0100 Subject: [PATCH 45/66] ManageEventIndexDialog: Use formatCount to format the message and room count. --- .../views/dialogs/eventindex/ManageEventIndexDialog.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index f435cf050f..a8fc7dce3a 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; import Modal from '../../../../Modal'; -import {formatBytes} from "../../../../utils/FormattingUtils"; +import {formatBytes, formatCount} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; @@ -125,8 +125,8 @@ export default class ManageEventIndexDialog extends React.Component { }
{_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
- {_t("Indexed messages:")} {this.state.eventCount}
- {_t("Number of rooms:")} {this.state.roomCount}
+ {_t("Indexed messages:")} {formatCount(this.state.eventCount)}
+ {_t("Number of rooms:")} {formatCount(this.state.roomCount)}
{crawlerState}
From 660240e2c047a964f2556cd2d63145f15ddc963e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:13:09 +0100 Subject: [PATCH 46/66] EventIndexPanel: Use formatCount to format the room count. --- src/components/views/settings/EventIndexPanel.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 785ce2a4ca..13063d9305 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -21,7 +21,7 @@ import * as sdk from '../../../index'; import Modal from '../../../Modal'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; -import {formatBytes} from "../../../utils/FormattingUtils"; +import {formatBytes, formatCount} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; export default class EventIndexPanel extends React.Component { @@ -115,7 +115,7 @@ export default class EventIndexPanel extends React.Component { {_t( "Securely cache encrypted messages locally for them " + "to appear in search results, using ") } {formatBytes(this.state.eventIndexSize, 0)} - {_t( " to store messages from ")} {this.state.roomCount} {_t("rooms.")} + {_t( " to store messages from ")} {formatCount(this.state.roomCount)} {_t("rooms.")}
From d9e933c915534456fead4641841e5b5ff9632a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:15:57 +0100 Subject: [PATCH 47/66] EventIndex: Style fixes for the docstrings. --- src/indexing/EventIndex.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index d466c6acba..53f47148b9 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -69,7 +69,8 @@ export default class EventIndex { client.removeListener('Room.timelineReset', this.onTimelineReset); } - /** Get crawler checkpoints for the encrypted rooms and store them in the index. + /** + * Get crawler checkpoints for the encrypted rooms and store them in the index. */ async addInitialCheckpoints() { const indexManager = PlatformPeg.get().getEventIndexingManager(); @@ -80,7 +81,7 @@ export default class EventIndex { return client.isRoomEncrypted(room.roomId); }; - // We only care to crawl the encrypted rooms, non-encrypted. + // We only care to crawl the encrypted rooms, non-encrypted // rooms can use the search provided by the homeserver. const encryptedRooms = rooms.filter(isRoomEncrypted); From 825b6f7b7d6848b4963dcbfc335c829779dfd40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:16:49 +0100 Subject: [PATCH 48/66] EventIndexPeg: Style fix for a docstring. --- src/indexing/EventIndexPeg.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/indexing/EventIndexPeg.js b/src/indexing/EventIndexPeg.js index c8c8cbefe9..067aea3a7f 100644 --- a/src/indexing/EventIndexPeg.js +++ b/src/indexing/EventIndexPeg.js @@ -62,7 +62,8 @@ class EventIndexPeg { return this.initEventIndex(); } - /* Initialize the event index. + /** + * Initialize the event index. * * @returns {boolean} True if the event index was succesfully initialized, * false otherwise. From 6f919eaeec0aaf96bd5cea50e9a714f3b2c023d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:27:56 +0100 Subject: [PATCH 49/66] DisableEventIndexDialog: Use the correct spinner. --- .../views/dialogs/eventindex/DisableEventIndexDialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 2e0f97c705..f031c5a11f 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -62,7 +62,7 @@ export default class DisableEventIndexDialog extends React.Component { title={_t("Are you sure?")} > {_t("If disabled, messages from encrypted rooms won't appear in search results.")} - {this.state.disabling ? :
} + {this.state.disabling ? :
} Date: Fri, 24 Jan 2020 11:28:33 +0100 Subject: [PATCH 50/66] EventIndex: Subclass the event emitter instead of putting one in a property. --- src/indexing/EventIndex.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 53f47148b9..85e75cfc82 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -22,8 +22,9 @@ import {EventEmitter} from "events"; /* * Event indexing class that wraps the platform specific event indexing. */ -export default class EventIndex { +export default class EventIndex extends EventEmitter { constructor() { + super(); this.crawlerCheckpoints = []; // The time in ms that the crawler will wait loop iterations if there // have not been any checkpoints to consume in the last iteration. @@ -35,7 +36,6 @@ export default class EventIndex { this._crawler = null; this._currentCheckpoint = null; this.liveEventsForIndex = new Set(); - this._eventEmitter = new EventEmitter(); } async init() { @@ -188,7 +188,7 @@ export default class EventIndex { } emitNewCheckpoint() { - this._eventEmitter.emit("changedCheckpoint", this.currentRoom()); + this.emit("changedCheckpoint", this.currentRoom()); } async crawlerFunc() { @@ -459,12 +459,4 @@ export default class EventIndex { return client.getRoom(this.crawlerCheckpoints[0].roomId); } } - - on(eventName, callback) { - this._eventEmitter.on(eventName, callback); - } - - removeListener(eventName, callback) { - this._eventEmitter.removeListener(eventName, callback); - } } From ffe5d411db9a7ae02ead2f5e78a8741be08ec5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:44:56 +0100 Subject: [PATCH 51/66] EventIndexPanel: Add a link to the download page of Riot Desktop. --- src/components/views/settings/EventIndexPanel.js | 8 ++++++-- src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 13063d9305..a6f21fa114 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -145,8 +145,12 @@ export default class EventIndexPanel extends React.Component {
{ _t( "Riot can't securely cache encrypted messages locally " + - "while running in a web browser. Use Riot Desktop for " + - "encrypted messages to appear in search results.", + "while running in a web browser. Use Riot Desktop " + + "for encrypted messages to appear in search results.", + {}, + { + 'riotLink': (sub) => {sub}, + } ) }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 3973ae442e..fceb299131 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -560,7 +560,7 @@ "Manage": "Manage", "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", "Enable": "Enable", - "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.", + "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", "The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.", @@ -2037,7 +2037,7 @@ "This device has detected that your recovery passphrase and key for Secure Messages have been removed.": "This device has detected that your recovery passphrase and key for Secure Messages have been removed.", "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.": "If you did this accidentally, you can setup Secure Messages on this device which will re-encrypt this device's message history with a new recovery method.", "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", - "If disabled, messages form encrypted rooms won't appear in search results": "If disabled, messages form encrypted rooms won't appear in search results", + "If disabled, messages from encrypted rooms won't appear in search results.": "If disabled, messages from encrypted rooms won't appear in search results.", "Disable": "Disable", "Not downloading messages for any room.": "Not downloading messages for any room.", "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", From 0c3d507455bbf77d956e2f6c303e08ef6d9d8c2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:46:46 +0100 Subject: [PATCH 52/66] EventIndex: Cancel the crawler early after a message request. If we're cancelling the crawler nowadays this means that we're likely deleting the index. Processing these messages is wasted effort in that case so break early. --- src/indexing/EventIndex.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 85e75cfc82..723d516a29 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -266,6 +266,11 @@ export default class EventIndex extends EventEmitter { continue; } + if (cancelled) { + this.crawlerCheckpoints.push(checkpoint); + break; + } + if (res.chunk.length === 0) { console.log("EventIndex: Done with the checkpoint", checkpoint); // We got to the start/end of our timeline, lets just From ee133a9c715559e33c058c58ce8776574816fafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:56:19 +0100 Subject: [PATCH 53/66] DisableEventIndexDialog: Remove an unused import. --- .../views/dialogs/eventindex/DisableEventIndexDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index f031c5a11f..c2b7e2933e 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -22,7 +22,6 @@ import { _t } from '../../../../languageHandler'; import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; -import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; /* * Allows the user to disable the Event Index. From 029369a04bd08f2fdb8944ff72be50e79050784a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 11:56:43 +0100 Subject: [PATCH 54/66] EventIndexPanel: Small style fix. --- src/components/views/settings/EventIndexPanel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index a6f21fa114..5edc25bbab 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -150,7 +150,7 @@ export default class EventIndexPanel extends React.Component { {}, { 'riotLink': (sub) => {sub}, - } + }, ) }
From 97d55f63a362194ce5d9cc6d9bb92f78e1c63157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 15:25:27 +0100 Subject: [PATCH 55/66] DisableEventIndexDialog: Remove the incorrect class on the dialog. --- .../views/dialogs/eventindex/DisableEventIndexDialog.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index c2b7e2933e..81920eab7a 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -56,10 +56,7 @@ export default class DisableEventIndexDialog extends React.Component { const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( - + {_t("If disabled, messages from encrypted rooms won't appear in search results.")} {this.state.disabling ? :
} Date: Fri, 24 Jan 2020 15:26:24 +0100 Subject: [PATCH 56/66] DisableEventIndexDialog: Use a self-closing tag for the buttons. --- .../views/dialogs/eventindex/DisableEventIndexDialog.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 81920eab7a..13278217de 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -65,8 +65,7 @@ export default class DisableEventIndexDialog extends React.Component { primaryButtonClass="danger" onCancel={this.props.onFinished} disabled={this.state.disabling} - > - + /> ); } From 47999c2e468ea98ec5ea99c527b48b7ac54c3fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 15:26:54 +0100 Subject: [PATCH 57/66] EventIndexPanel: Add a separate message for the case where Seshat is missing. --- src/components/views/settings/EventIndexPanel.js | 16 ++++++++++++++++ src/i18n/strings/en_EN.json | 1 + 2 files changed, 17 insertions(+) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 5edc25bbab..321f45699b 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -140,6 +140,22 @@ export default class EventIndexPanel extends React.Component {
); + } else if (EventIndexPeg.platformHasSupport() && !EventIndexPeg.supportIsInstalled()) { + eventIndexingSettings = ( +
+ { + _t( "Riot is missing some components required for securely " + + "caching encrypted messages locally. If you'd like to " + + "experiment with this feature, build a custom Riot Desktop " + + "with search components added.", + {}, + { + 'nativeLink': (sub) => {sub}, + }, + ) + } +
+ ); } else { eventIndexingSettings = (
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index fceb299131..419aecd528 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -560,6 +560,7 @@ "Manage": "Manage", "Securely cache encrypted messages locally for them to appear in search results.": "Securely cache encrypted messages locally for them to appear in search results.", "Enable": "Enable", + "Riot is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom Riot Desktop with search components added.": "Riot is missing some components required for securely caching encrypted messages locally. If you'd like to experiment with this feature, build a custom Riot Desktop with search components added.", "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.": "Riot can't securely cache encrypted messages locally while running in a web browser. Use Riot Desktop for encrypted messages to appear in search results.", "Connecting to integration manager...": "Connecting to integration manager...", "Cannot connect to integration manager": "Cannot connect to integration manager", From 2d8477aaa69ac35c451c8a47691a0372cb635175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:13:55 +0100 Subject: [PATCH 58/66] FormattingUtils: Add a formatCountLong method. --- src/utils/FormattingUtils.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/utils/FormattingUtils.js b/src/utils/FormattingUtils.js index 9016d62cfb..b932214530 100644 --- a/src/utils/FormattingUtils.js +++ b/src/utils/FormattingUtils.js @@ -30,6 +30,15 @@ export function formatCount(count) { return (count / 1000000000).toFixed(1) + "B"; // 10B is enough for anyone, right? :S } +/** + * Format a count showing the whole number but making it a bit more readable. + * e.g: 1000 => 1,000 + */ +export function formatCountLong(count) { + const formatter = new Intl.NumberFormat(); + return formatter.format(count) +} + /** * format a size in bytes into a human readable form * e.g: 1024 -> 1.00 KB From ddea7415c7bd954343efc98322a00326b5c1d2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:15:06 +0100 Subject: [PATCH 59/66] EventIndexPanel: Use formatCountLong to format the event and room counts. --- .../views/dialogs/eventindex/ManageEventIndexDialog.js | 6 +++--- src/components/views/settings/EventIndexPanel.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index a8fc7dce3a..66cd89f4ab 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -20,7 +20,7 @@ import PropTypes from 'prop-types'; import { _t } from '../../../../languageHandler'; import Modal from '../../../../Modal'; -import {formatBytes, formatCount} from "../../../../utils/FormattingUtils"; +import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; @@ -125,8 +125,8 @@ export default class ManageEventIndexDialog extends React.Component { }
{_t("Space used:")} {formatBytes(this.state.eventIndexSize, 0)}
- {_t("Indexed messages:")} {formatCount(this.state.eventCount)}
- {_t("Number of rooms:")} {formatCount(this.state.roomCount)}
+ {_t("Indexed messages:")} {formatCountLong(this.state.eventCount)}
+ {_t("Number of rooms:")} {formatCountLong(this.state.roomCount)}
{crawlerState}
diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 321f45699b..851f86f3d4 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -21,7 +21,7 @@ import * as sdk from '../../../index'; import Modal from '../../../Modal'; import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore"; import AccessibleButton from "../elements/AccessibleButton"; -import {formatBytes, formatCount} from "../../../utils/FormattingUtils"; +import {formatBytes, formatCountLong} from "../../../utils/FormattingUtils"; import EventIndexPeg from "../../../indexing/EventIndexPeg"; export default class EventIndexPanel extends React.Component { @@ -115,7 +115,8 @@ export default class EventIndexPanel extends React.Component { {_t( "Securely cache encrypted messages locally for them " + "to appear in search results, using ") } {formatBytes(this.state.eventIndexSize, 0)} - {_t( " to store messages from ")} {formatCount(this.state.roomCount)} {_t("rooms.")} + {_t( " to store messages from ")} + {formatCountLong(this.state.roomCount)} {_t("rooms.")}
From cd225943ea7a504d8e9ff09eefa6aa098514ee2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:22:09 +0100 Subject: [PATCH 60/66] EventIndexPanel: Shorten a overly long line. --- src/components/views/settings/EventIndexPanel.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 851f86f3d4..479a995bc8 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -142,6 +142,12 @@ export default class EventIndexPanel extends React.Component {
); } else if (EventIndexPeg.platformHasSupport() && !EventIndexPeg.supportIsInstalled()) { + const nativeLink = ( + "https://github.com/vector-im/riot-web/blob/develop/" + + "docs/native-node-modules.md#" + + "adding-seshat-for-search-in-e2e-encrypted-rooms" + ); + eventIndexingSettings = (
{ @@ -151,7 +157,7 @@ export default class EventIndexPanel extends React.Component { "with search components added.", {}, { - 'nativeLink': (sub) => {sub}, + 'nativeLink': (sub) => {sub}, }, ) } From 5d3b916a89bb0c04b38fa24a5e360c93ff178d9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:46:46 +0100 Subject: [PATCH 61/66] DialogButtons: Allow setting the cancel button class with a prop. --- src/components/views/elements/DialogButtons.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/DialogButtons.js b/src/components/views/elements/DialogButtons.js index 4e47e73052..2cb25d9c9c 100644 --- a/src/components/views/elements/DialogButtons.js +++ b/src/components/views/elements/DialogButtons.js @@ -40,6 +40,10 @@ export default createReactClass({ // should there be a cancel button? default: true hasCancel: PropTypes.bool, + // The class of the cancel button, only used if a cancel button is + // enabled + cancelButtonClass: PropTypes.node, + // onClick handler for the cancel button. onCancel: PropTypes.func, @@ -69,8 +73,10 @@ export default createReactClass({ primaryButtonClassName += " " + this.props.primaryButtonClass; } let cancelButton; + if (this.props.cancelButton || this.props.hasCancel) { - cancelButton = ; } From 3208ac60c7b6ea453448ada43e08441a371d6758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:47:29 +0100 Subject: [PATCH 62/66] ManageEventIndexDialog: Override the Disable button class to be danger. --- .../eventindex/ManageEventIndexDialog.js | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index 66cd89f4ab..5f6f4985da 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -132,18 +132,8 @@ export default class ManageEventIndexDialog extends React.Component {
); - const buttons = ( -
- - {_t("Disable")} - - - {_t("Done")} - -
- ); - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); return ( {eventIndexingSettings} - {buttons} + ); } From 9f3e5ab1db15b0aa4cf6d45528e9a0f2323f85a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 24 Jan 2020 16:52:26 +0100 Subject: [PATCH 63/66] ManageEventIndexDialog: Remove an unused import. --- .../views/dialogs/eventindex/ManageEventIndexDialog.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index 5f6f4985da..5c82cc0391 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -22,7 +22,6 @@ import { _t } from '../../../../languageHandler'; import Modal from '../../../../Modal'; import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils"; import EventIndexPeg from "../../../../indexing/EventIndexPeg"; -import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; /* * Allows the user to introspect the event index state and disable it. From 7e0ab2f0a309157af8c953c88ef183b610e4fce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 27 Jan 2020 15:28:43 +0100 Subject: [PATCH 64/66] DisableEventIndexDialog: Turn the cancel button red. --- res/css/_common.scss | 5 +++++ .../views/dialogs/eventindex/DisableEventIndexDialog.js | 1 + 2 files changed, 6 insertions(+) diff --git a/res/css/_common.scss b/res/css/_common.scss index 51d985efb7..77284d0a14 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -414,6 +414,11 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { color: $accent-fg-color; } +.mx_Dialog button.warning, .mx_Dialog input[type="submit"].warning { + border: solid 1px $warning-color; + color: $warning-color; +} + .mx_Dialog button:disabled, .mx_Dialog input[type="submit"]:disabled { background-color: $light-fg-color; border: solid 1px $light-fg-color; diff --git a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js index 13278217de..120b086ef6 100644 --- a/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js @@ -63,6 +63,7 @@ export default class DisableEventIndexDialog extends React.Component { primaryButton={_t('Disable')} onPrimaryButtonClick={this._onDisable} primaryButtonClass="danger" + cancelButtonClass="warning" onCancel={this.props.onFinished} disabled={this.state.disabling} /> From e38f1191a52880ee5b80ee3c68feb02831a8bdda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 27 Jan 2020 15:50:14 +0100 Subject: [PATCH 65/66] ManageEventIndex: Clarify that we're currently not downloading any messages. --- .../views/dialogs/eventindex/ManageEventIndexDialog.js | 2 +- src/i18n/strings/en_EN.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js index 5c82cc0391..b7ea87b1b2 100644 --- a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js +++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js @@ -108,7 +108,7 @@ export default class ManageEventIndexDialog extends React.Component { let crawlerState; if (this.state.currentRoom === null) { - crawlerState = _t("Not downloading messages for any room."); + crawlerState = _t("Not currently downloading messages for any room."); } else { crawlerState = ( _t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom }) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 419aecd528..e6e4ad3ed3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2040,7 +2040,7 @@ "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.": "If you didn't remove the recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings.", "If disabled, messages from encrypted rooms won't appear in search results.": "If disabled, messages from encrypted rooms won't appear in search results.", "Disable": "Disable", - "Not downloading messages for any room.": "Not downloading messages for any room.", + "Not currently downloading messages for any room.": "Not currently downloading messages for any room.", "Downloading mesages for %(currentRoom)s.": "Downloading mesages for %(currentRoom)s.", "Riot is securely caching encrypted messages locally for them to appear in search results:": "Riot is securely caching encrypted messages locally for them to appear in search results:", "Space used:": "Space used:", From ab8ea5226647fcfdcaa7a352f3c711d2d5c536ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 27 Jan 2020 16:50:33 +0100 Subject: [PATCH 66/66] EventIndexPanel: Make sure links get opened in a new tab. --- src/components/views/settings/EventIndexPanel.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/views/settings/EventIndexPanel.js b/src/components/views/settings/EventIndexPanel.js index 479a995bc8..68faa53e53 100644 --- a/src/components/views/settings/EventIndexPanel.js +++ b/src/components/views/settings/EventIndexPanel.js @@ -157,7 +157,8 @@ export default class EventIndexPanel extends React.Component { "with search components added.", {}, { - 'nativeLink': (sub) => {sub}, + 'nativeLink': (sub) => {sub}, }, ) } @@ -172,7 +173,8 @@ export default class EventIndexPanel extends React.Component { "for encrypted messages to appear in search results.", {}, { - 'riotLink': (sub) => {sub}, + 'riotLink': (sub) => {sub}, }, ) }