diff --git a/res/css/_common.scss b/res/css/_common.scss
index b92a618504..e062e0bd73 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -428,6 +428,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, .mx_Dialog_buttons button:disabled, .mx_Dialog_buttons 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
new file mode 100644
index 0000000000..120b086ef6
--- /dev/null
+++ b/src/async-components/views/dialogs/eventindex/DisableEventIndexDialog.js
@@ -0,0 +1,73 @@
+/*
+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 dis from "../../../../dispatcher";
+import { _t } from '../../../../languageHandler';
+
+import SettingsStore, {SettingLevel} from "../../../../settings/SettingsStore";
+import EventIndexPeg from "../../../../indexing/EventIndexPeg";
+
+/*
+ * Allows the user to disable the Event Index.
+ */
+export default class DisableEventIndexDialog extends React.Component {
+ static propTypes = {
+ onFinished: PropTypes.func.isRequired,
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ disabling: false,
+ };
+ }
+
+ _onDisable = async () => {
+ this.setState({
+ disabling: true,
+ });
+
+ await SettingsStore.setValue('enableEventIndexing', null, SettingLevel.DEVICE, false);
+ await EventIndexPeg.deleteEventIndex();
+ this.props.onFinished();
+ dis.dispatch({ action: 'view_user_settings' });
+ }
+
+ render() {
+ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
+ 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.")}
+ {this.state.disabling ? : }
+
+
+ );
+ }
+}
diff --git a/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js
new file mode 100644
index 0000000000..b7ea87b1b2
--- /dev/null
+++ b/src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.js
@@ -0,0 +1,154 @@
+/*
+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 Modal from '../../../../Modal';
+import {formatBytes, formatCountLong} from "../../../../utils/FormattingUtils";
+import EventIndexPeg from "../../../../indexing/EventIndexPeg";
+
+/*
+ * Allows the user to introspect the event index state and disable it.
+ */
+export default class ManageEventIndexDialog extends React.Component {
+ static propTypes = {
+ onFinished: PropTypes.func.isRequired,
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ eventIndexSize: 0,
+ eventCount: 0,
+ roomCount: 0,
+ currentRoom: null,
+ };
+ }
+
+ 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 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 room = eventIndex.currentRoom();
+ if (room) currentRoom = room.name;
+ }
+
+ this.setState({
+ eventIndexSize,
+ eventCount,
+ roomCount,
+ currentRoom,
+ });
+ }
+
+ _onDisable = async () => {
+ Modal.createTrackedDialogAsync("Disable message search", "Disable message search",
+ import("./DisableEventIndexDialog"),
+ null, null, /* priority = */ false, /* static = */ true,
+ );
+ }
+
+ _onDone = () => {
+ this.props.onFinished(true);
+ }
+
+ render() {
+ let crawlerState;
+
+ if (this.state.currentRoom === null) {
+ crawlerState = _t("Not currently downloading messages for any room.");
+ } else {
+ crawlerState = (
+ _t("Downloading mesages for %(currentRoom)s.", { currentRoom: this.state.currentRoom })
+ );
+ }
+
+ const eventIndexingSettings = (
+