Merge branch 'poljar/seshat-ui-pr' into develop
This commit is contained in:
commit
e2dd2bd950
13 changed files with 672 additions and 61 deletions
|
@ -43,6 +43,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,
|
||||
|
||||
|
@ -72,12 +76,14 @@ export default createReactClass({
|
|||
primaryButtonClassName += " " + this.props.primaryButtonClass;
|
||||
}
|
||||
let cancelButton;
|
||||
|
||||
if (this.props.cancelButton || this.props.hasCancel) {
|
||||
cancelButton = <button
|
||||
// important: the default type is 'submit' and this button comes before the
|
||||
// primary in the DOM so will get form submissions unless we make it not a submit.
|
||||
type="button"
|
||||
onClick={this._onCancelClick}
|
||||
className={this.props.cancelButtonClass}
|
||||
disabled={this.props.disabled}
|
||||
>
|
||||
{ this.props.cancelButton || _t("Cancel") }
|
||||
|
|
187
src/components/views/settings/EventIndexPanel.js
Normal file
187
src/components/views/settings/EventIndexPanel.js
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
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 { _t } from '../../../languageHandler';
|
||||
import * as sdk from '../../../index';
|
||||
import Modal from '../../../Modal';
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import {formatBytes, formatCountLong} from "../../../utils/FormattingUtils";
|
||||
import EventIndexPeg from "../../../indexing/EventIndexPeg";
|
||||
|
||||
export default class EventIndexPanel extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
enabling: false,
|
||||
eventIndexSize: 0,
|
||||
roomCount: 0,
|
||||
eventIndexingEnabled:
|
||||
SettingsStore.getValueAt(SettingLevel.DEVICE, 'enableEventIndexing'),
|
||||
};
|
||||
}
|
||||
|
||||
async updateCurrentRoom(room) {
|
||||
const eventIndex = EventIndexPeg.get();
|
||||
const stats = await eventIndex.getStats();
|
||||
|
||||
this.setState({
|
||||
eventIndexSize: stats.size,
|
||||
roomCount: stats.roomCount,
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
const eventIndex = EventIndexPeg.get();
|
||||
|
||||
if (eventIndex !== null) {
|
||||
eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
async componentWillMount(): void {
|
||||
this.updateState();
|
||||
}
|
||||
|
||||
async updateState() {
|
||||
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));
|
||||
|
||||
const stats = await eventIndex.getStats();
|
||||
eventIndexSize = stats.size;
|
||||
roomCount = stats.roomCount;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
enabling,
|
||||
eventIndexSize,
|
||||
roomCount,
|
||||
eventIndexingEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
_onManage = async () => {
|
||||
Modal.createTrackedDialogAsync('Message search', 'Message search',
|
||||
import('../../../async-components/views/dialogs/eventindex/ManageEventIndexDialog'),
|
||||
{
|
||||
onFinished: () => {},
|
||||
}, null, /* priority = */ false, /* static = */ true,
|
||||
);
|
||||
}
|
||||
|
||||
_onEnable = async () => {
|
||||
this.setState({
|
||||
enabling: true,
|
||||
});
|
||||
|
||||
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;
|
||||
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
|
||||
|
||||
if (EventIndexPeg.get() !== null) {
|
||||
eventIndexingSettings = (
|
||||
<div>
|
||||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{_t( "Securely cache encrypted messages locally for them " +
|
||||
"to appear in search results, using ")
|
||||
} {formatBytes(this.state.eventIndexSize, 0)}
|
||||
{_t( " to store messages from ")}
|
||||
{formatCountLong(this.state.roomCount)} {_t("rooms.")}
|
||||
</div>
|
||||
<div>
|
||||
<AccessibleButton kind="primary" onClick={this._onManage}>
|
||||
{_t("Manage")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (!this.state.eventIndexingEnabled && EventIndexPeg.supportIsInstalled()) {
|
||||
eventIndexingSettings = (
|
||||
<div>
|
||||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{_t( "Securely cache encrypted messages locally for them to " +
|
||||
"appear in search results.")}
|
||||
</div>
|
||||
<div>
|
||||
<AccessibleButton kind="primary" disabled={this.state.enabling}
|
||||
onClick={this._onEnable}>
|
||||
{_t("Enable")}
|
||||
</AccessibleButton>
|
||||
{this.state.enabling ? <InlineSpinner /> : <div />}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} 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 = (
|
||||
<div>
|
||||
{
|
||||
_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 <nativeLink>search components added</nativeLink>.",
|
||||
{},
|
||||
{
|
||||
'nativeLink': (sub) => <a href={nativeLink} target="_blank"
|
||||
rel="noopener">{sub}</a>,
|
||||
},
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
eventIndexingSettings = (
|
||||
<div>
|
||||
{
|
||||
_t( "Riot can't securely cache encrypted messages locally " +
|
||||
"while running in a web browser. Use <riotLink>Riot Desktop</riotLink> " +
|
||||
"for encrypted messages to appear in search results.",
|
||||
{},
|
||||
{
|
||||
'riotLink': (sub) => <a href="https://riot.im/download/desktop"
|
||||
target="_blank" rel="noopener">{sub}</a>,
|
||||
},
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return eventIndexingSettings;
|
||||
}
|
||||
}
|
|
@ -170,6 +170,7 @@ export default class PreferencesUserSettingsTab extends React.Component {
|
|||
return (
|
||||
<div className="mx_SettingsTab mx_PreferencesUserSettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{_t("Preferences")}</div>
|
||||
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Composer")}</span>
|
||||
{this._renderGroup(PreferencesUserSettingsTab.COMPOSER_SETTINGS)}
|
||||
|
|
|
@ -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,16 @@ export default class SecurityUserSettingsTab extends React.Component {
|
|||
</div>
|
||||
);
|
||||
|
||||
let eventIndex;
|
||||
if (SettingsStore.isFeatureEnabled("feature_event_indexing")) {
|
||||
eventIndex = (
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Message search")}</span>
|
||||
<EventIndexPanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 +292,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
|||
</div>
|
||||
</div>
|
||||
{keyBackup}
|
||||
{eventIndex}
|
||||
{crossSigning}
|
||||
{this._renderCurrentDeviceInfo()}
|
||||
<div className='mx_SettingsTab_section'>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue