Merge branches 'develop' and 't3chguy/alpha_room_list' of github.com:matrix-org/matrix-react-sdk into t3chguy/alpha_room_list

pull/21833/head
Michael Telatynski 2020-02-21 11:18:45 +00:00
commit e6d8c4a576
22 changed files with 256 additions and 119 deletions

View File

@ -1,3 +1,37 @@
Changes in [2.1.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.1.1) (2020-02-19)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.1.0...v2.1.1)
* show spinner while loading local aliases
[\#4090](https://github.com/matrix-org/matrix-react-sdk/pull/4090)
* Don't index key verification events.
[\#4083](https://github.com/matrix-org/matrix-react-sdk/pull/4083)
* Get rid of dependence on usercontent.riot.im
[\#4046](https://github.com/matrix-org/matrix-react-sdk/pull/4046)
* also detect aliases using new /aliases endpoint for room access settings
[\#4089](https://github.com/matrix-org/matrix-react-sdk/pull/4089)
* get local aliases from /aliases in room settings
[\#4086](https://github.com/matrix-org/matrix-react-sdk/pull/4086)
* Start verification sessions in an E2E DM where possible
[\#4080](https://github.com/matrix-org/matrix-react-sdk/pull/4080)
* Only show supported verification methods
[\#4077](https://github.com/matrix-org/matrix-react-sdk/pull/4077)
* Use local echo in VerificationRequest for accepting/declining a verification
request
[\#4072](https://github.com/matrix-org/matrix-react-sdk/pull/4072)
* Report installed PWA, touch input status in rageshakes, analytics
[\#4078](https://github.com/matrix-org/matrix-react-sdk/pull/4078)
* refactor event grouping into separate helper classes
[\#4059](https://github.com/matrix-org/matrix-react-sdk/pull/4059)
* Find existing requests when starting a new verification request
[\#4070](https://github.com/matrix-org/matrix-react-sdk/pull/4070)
* Always speak the full text of the typing indicator when it updates.
[\#4074](https://github.com/matrix-org/matrix-react-sdk/pull/4074)
* Fix escaped markdown passing backslashes through
[\#4008](https://github.com/matrix-org/matrix-react-sdk/pull/4008)
* Move the sidebar to below the sidebar tab buttons for screen readers.
[\#4071](https://github.com/matrix-org/matrix-react-sdk/pull/4071)
Changes in [2.1.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.1.0) (2020-02-17)
===================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.1.0-rc.2...v2.1.0)

View File

@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
"version": "2.1.0",
"version": "2.1.1",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {

View File

@ -35,7 +35,7 @@ do
fi
done
exec ./node_modules/matrix-js-sdk/release.sh -z "$@"
./node_modules/matrix-js-sdk/release.sh -z "$@"
release="${1#v}"
prerelease=0

View File

@ -32,7 +32,7 @@ import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientB
import * as StorageManager from './utils/StorageManager';
import IdentityAuthClient from './IdentityAuthClient';
import { crossSigningCallbacks } from './CrossSigningManager';
import {SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
interface MatrixClientCreds {
homeserverUrl: string,
@ -221,7 +221,6 @@ class _MatrixClientPeg {
verificationMethods: [
verificationMethods.SAS,
SHOW_QR_CODE_METHOD,
SCAN_QR_CODE_METHOD, // XXX: We don't actually support scanning yet!
verificationMethods.RECIPROCATE_QR_CODE,
],
unstableClientRelationAggregation: true,

View File

@ -153,10 +153,12 @@ const Notifier = {
},
start: function() {
this.boundOnEvent = this.onEvent.bind(this);
this.boundOnSyncStateChange = this.onSyncStateChange.bind(this);
this.boundOnRoomReceipt = this.onRoomReceipt.bind(this);
this.boundOnEventDecrypted = this.onEventDecrypted.bind(this);
// do not re-bind in the case of repeated call
this.boundOnEvent = this.boundOnEvent || this.onEvent.bind(this);
this.boundOnSyncStateChange = this.boundOnSyncStateChange || this.onSyncStateChange.bind(this);
this.boundOnRoomReceipt = this.boundOnRoomReceipt || this.onRoomReceipt.bind(this);
this.boundOnEventDecrypted = this.boundOnEventDecrypted || this.onEventDecrypted.bind(this);
MatrixClientPeg.get().on('event', this.boundOnEvent);
MatrixClientPeg.get().on('Room.receipt', this.boundOnRoomReceipt);
MatrixClientPeg.get().on('Event.decrypted', this.boundOnEventDecrypted);
@ -166,7 +168,7 @@ const Notifier = {
},
stop: function() {
if (MatrixClientPeg.get() && this.boundOnRoomTimeline) {
if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener('Event', this.boundOnEvent);
MatrixClientPeg.get().removeListener('Room.receipt', this.boundOnRoomReceipt);
MatrixClientPeg.get().removeListener('Event.decrypted', this.boundOnEventDecrypted);

View File

@ -46,9 +46,18 @@ export default class ManageEventIndexDialog extends React.Component {
};
}
async updateCurrentRoom(room) {
updateCurrentRoom = async (room) => {
const eventIndex = EventIndexPeg.get();
const stats = await eventIndex.getStats();
let stats;
try {
stats = await eventIndex.getStats();
} catch {
// This call may fail if sporadically, not a huge issue as we will
// try later again and probably succeed.
return;
}
let currentRoom = null;
if (room) currentRoom = room.name;
@ -63,13 +72,13 @@ export default class ManageEventIndexDialog extends React.Component {
roomCount: roomCount,
currentRoom: currentRoom,
});
}
};
componentWillUnmount(): void {
const eventIndex = EventIndexPeg.get();
if (eventIndex !== null) {
eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom.bind(this));
eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom);
}
}
@ -83,14 +92,21 @@ export default class ManageEventIndexDialog extends React.Component {
const eventIndex = EventIndexPeg.get();
if (eventIndex !== null) {
eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this));
eventIndex.on("changedCheckpoint", this.updateCurrentRoom);
try {
const stats = await eventIndex.getStats();
eventIndexSize = stats.size;
eventCount = stats.eventCount;
} catch {
// This call may fail if sporadically, not a huge issue as we
// will try later again in the updateCurrentRoom call and
// probably succeed.
}
const stats = await eventIndex.getStats();
const roomStats = eventIndex.crawlingRooms();
eventIndexSize = stats.size;
crawlingRoomsCount = roomStats.crawlingRooms.size;
roomCount = roomStats.totalRooms.size;
eventCount = stats.eventCount;
const room = eventIndex.currentRoom();
if (room) currentRoom = room.name;

View File

@ -95,8 +95,8 @@ const FilePanel = createReactClass({
// this could be made more general in the future or the filter logic
// could be fixed.
if (EventIndexPeg.get() !== null) {
client.on('Room.timeline', this.onRoomTimeline.bind(this));
client.on('Event.decrypted', this.onEventDecrypted.bind(this));
client.on('Room.timeline', this.onRoomTimeline);
client.on('Event.decrypted', this.onEventDecrypted);
}
},
@ -107,8 +107,8 @@ const FilePanel = createReactClass({
if (!MatrixClientPeg.get().isRoomEncrypted(this.props.roomId)) return;
if (EventIndexPeg.get() !== null) {
client.removeListener('Room.timeline', this.onRoomTimeline.bind(this));
client.removeListener('Event.decrypted', this.onEventDecrypted.bind(this));
client.removeListener('Room.timeline', this.onRoomTimeline);
client.removeListener('Event.decrypted', this.onEventDecrypted);
}
},

View File

@ -65,6 +65,7 @@ import { ThemeWatcher } from "../../theme";
import { storeRoomAliasInCache } from '../../RoomAliasCache';
import { defer } from "../../utils/promise";
import ToastStore from "../../stores/ToastStore";
import * as StorageManager from "../../utils/StorageManager";
/** constants for MatrixChat.state.view */
export const VIEWS = {
@ -1193,6 +1194,8 @@ export default createReactClass({
} else {
this._showScreenAfterLogin();
}
StorageManager.tryPersistStorage();
},
_showScreenAfterLogin: function() {

View File

@ -92,6 +92,7 @@ export default class RightPanel extends React.Component {
// not mounted in time to get the dispatch.
// Until then, let this code serve as a warning from history.
if (
rps.roomPanelPhaseParams.member &&
userForPanel.userId === rps.roomPanelPhaseParams.member.userId &&
rps.roomPanelPhaseParams.verificationRequest
) {

View File

@ -414,11 +414,16 @@ export default createReactClass({
}
// XXX: if we use room ID, we should also include a server where the event can be found (other than in the domain of the event ID)
const permalinkButton = (
<MenuItem className="mx_MessageContextMenu_field">
<a href={permalink} target="_blank" rel="noopener" onClick={this.onPermalinkClick} tabIndex={-1}>
{ mxEvent.isRedacted() || mxEvent.getType() !== 'm.room.message'
? _t('Share Permalink') : _t('Share Message') }
</a>
<MenuItem
element="a"
className="mx_MessageContextMenu_field"
onClick={this.onPermalinkClick}
href={permalink}
target="_blank"
rel="noopener"
>
{ mxEvent.isRedacted() || mxEvent.getType() !== 'm.room.message'
? _t('Share Permalink') : _t('Share Message') }
</MenuItem>
);
@ -436,16 +441,15 @@ export default createReactClass({
isUrlPermitted(mxEvent.event.content.external_url)
) {
externalURLButton = (
<MenuItem className="mx_MessageContextMenu_field">
<a
href={mxEvent.event.content.external_url}
target="_blank"
rel="noopener"
onClick={this.closeMenu}
tabIndex={-1}
>
{ _t('Source URL') }
</a>
<MenuItem
element="a"
className="mx_MessageContextMenu_field"
target="_blank"
rel="noopener"
onClick={this.closeMenu}
href={mxEvent.event.content.external_url}
>
{ _t('Source URL') }
</MenuItem>
);
}

View File

@ -27,7 +27,7 @@ import {verificationMethods} from 'matrix-js-sdk/src/crypto';
import {ensureDMExists} from "../../../createRoom";
import dis from "../../../dispatcher";
import SettingsStore from '../../../settings/SettingsStore';
import {SCAN_QR_CODE_METHOD, SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
import {SHOW_QR_CODE_METHOD} from "matrix-js-sdk/src/crypto/verification/QRCode";
import VerificationQREmojiOptions from "../verification/VerificationQREmojiOptions";
const MODE_LEGACY = 'legacy';
@ -135,7 +135,6 @@ export default class DeviceVerifyDialog extends React.Component {
this._request = await client.requestVerification(this.props.userId, [
verificationMethods.SAS,
SHOW_QR_CODE_METHOD,
SCAN_QR_CODE_METHOD,
verificationMethods.RECIPROCATE_QR_CODE,
]);

View File

@ -26,10 +26,15 @@ export default class VerificationRequestDialog extends React.Component {
onFinished: PropTypes.func.isRequired,
};
constructor(...args) {
super(...args);
this.onFinished = this.onFinished.bind(this);
}
render() {
const BaseDialog = sdk.getComponent("views.dialogs.BaseDialog");
const EncryptionPanel = sdk.getComponent("views.right_panel.EncryptionPanel");
return <BaseDialog className="mx_InfoDialog" onFinished={this.props.onFinished}
return <BaseDialog className="mx_InfoDialog" onFinished={this.onFinished}
contentId="mx_Dialog_content"
title={_t("Verification Request")}
hasCancel={true}
@ -42,4 +47,9 @@ export default class VerificationRequestDialog extends React.Component {
/>
</BaseDialog>;
}
onFinished() {
this.props.verificationRequest.cancel();
this.props.onFinished();
}
}

View File

@ -128,7 +128,8 @@ const Pill = createReactClass({
case Pill.TYPE_ROOM_MENTION: {
const localRoom = resourceId[0] === '#' ?
MatrixClientPeg.get().getRooms().find((r) => {
return r.getAliases().includes(resourceId);
return r.getCanonicalAlias() === resourceId ||
r.getAliases().includes(resourceId);
}) : MatrixClientPeg.get().getRoom(resourceId);
room = localRoom;
if (!localRoom) {

View File

@ -91,6 +91,7 @@ export default class AliasSettings extends React.Component {
remoteDomains: [], // [ domain.com, foobar.com ]
canonicalAlias: null, // #canonical:domain.com
updatingCanonicalAlias: false,
localAliasesLoading: true,
};
if (props.canonicalAliasEvent) {
@ -102,28 +103,32 @@ export default class AliasSettings extends React.Component {
async componentWillMount() {
const cli = MatrixClientPeg.get();
if (await cli.doesServerSupportUnstableFeature("org.matrix.msc2432")) {
const response = await cli.unstableGetLocalAliases(this.props.roomId);
const localAliases = response.aliases;
const localDomain = cli.getDomain();
const domainToAliases = Object.assign(
{},
// FIXME, any localhost alt_aliases will be ignored as they are overwritten by localAliases
this.aliasesToDictionary(this._getAltAliases()),
{[localDomain]: localAliases || []},
);
const remoteDomains = Object.keys(domainToAliases).filter((domain) => {
return domain !== localDomain && domainToAliases[domain].length > 0;
});
this.setState({ domainToAliases, remoteDomains });
} else {
const state = {};
const localDomain = cli.getDomain();
state.domainToAliases = this.aliasEventsToDictionary(this.props.aliasEvents || []);
state.remoteDomains = Object.keys(state.domainToAliases).filter((domain) => {
return domain !== localDomain && state.domainToAliases[domain].length > 0;
});
this.setState(state);
try {
if (await cli.doesServerSupportUnstableFeature("org.matrix.msc2432")) {
const response = await cli.unstableGetLocalAliases(this.props.roomId);
const localAliases = response.aliases;
const localDomain = cli.getDomain();
const domainToAliases = Object.assign(
{},
// FIXME, any localhost alt_aliases will be ignored as they are overwritten by localAliases
this.aliasesToDictionary(this._getAltAliases()),
{[localDomain]: localAliases || []},
);
const remoteDomains = Object.keys(domainToAliases).filter((domain) => {
return domain !== localDomain && domainToAliases[domain].length > 0;
});
this.setState({ domainToAliases, remoteDomains });
} else {
const state = {};
const localDomain = cli.getDomain();
state.domainToAliases = this.aliasEventsToDictionary(this.props.aliasEvents || []);
state.remoteDomains = Object.keys(state.domainToAliases).filter((domain) => {
return domain !== localDomain && state.domainToAliases[domain].length > 0;
});
this.setState(state);
}
} finally {
this.setState({localAliasesLoading: false});
}
}
@ -302,26 +307,34 @@ export default class AliasSettings extends React.Component {
);
}
let localAliasesList;
if (this.state.localAliasesLoading) {
const Spinner = sdk.getComponent("elements.Spinner");
localAliasesList = <Spinner />;
} else {
localAliasesList = <EditableAliasesList
id="roomAliases"
className={"mx_RoomSettings_localAliases"}
items={this.state.domainToAliases[localDomain] || []}
newItem={this.state.newAlias}
onNewItemChanged={this.onNewAliasChanged}
canRemove={this.props.canSetAliases}
canEdit={this.props.canSetAliases}
onItemAdded={this.onLocalAliasAdded}
onItemRemoved={this.onLocalAliasDeleted}
itemsLabel={_t('Local addresses for this room:')}
noItemsLabel={_t('This room has no local addresses')}
placeholder={_t(
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
)}
domain={localDomain}
/>;
}
return (
<div className='mx_AliasSettings'>
{canonicalAliasSection}
<EditableAliasesList
id="roomAliases"
className={"mx_RoomSettings_localAliases"}
items={this.state.domainToAliases[localDomain] || []}
newItem={this.state.newAlias}
onNewItemChanged={this.onNewAliasChanged}
canRemove={this.props.canSetAliases}
canEdit={this.props.canSetAliases}
onItemAdded={this.onLocalAliasAdded}
onItemRemoved={this.onLocalAliasDeleted}
itemsLabel={_t('Local addresses for this room:')}
noItemsLabel={_t('This room has no local addresses')}
placeholder={_t(
'New address (e.g. #foo:%(localDomain)s)', {localDomain: localDomain},
)}
domain={localDomain}
/>
{localAliasesList}
{remoteAliasesSection}
</div>
);

View File

@ -37,21 +37,29 @@ export default class EventIndexPanel extends React.Component {
};
}
async updateCurrentRoom(room) {
updateCurrentRoom = async (room) => {
const eventIndex = EventIndexPeg.get();
const stats = await eventIndex.getStats();
let stats;
try {
stats = await eventIndex.getStats();
} catch {
// This call may fail if sporadically, not a huge issue as we will
// try later again and probably succeed.
return;
}
this.setState({
eventIndexSize: stats.size,
roomCount: stats.roomCount,
});
}
};
componentWillUnmount(): void {
const eventIndex = EventIndexPeg.get();
if (eventIndex !== null) {
eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom.bind(this));
eventIndex.removeListener("changedCheckpoint", this.updateCurrentRoom);
}
}
@ -68,11 +76,17 @@ export default class EventIndexPanel extends React.Component {
let roomCount = 0;
if (eventIndex !== null) {
eventIndex.on("changedCheckpoint", this.updateCurrentRoom.bind(this));
eventIndex.on("changedCheckpoint", this.updateCurrentRoom);
const stats = await eventIndex.getStats();
eventIndexSize = stats.size;
roomCount = stats.roomCount;
try {
const stats = await eventIndex.getStats();
eventIndexSize = stats.size;
roomCount = stats.roomCount;
} catch {
// This call may fail if sporadically, not a huge issue as we
// will try later again in the updateCurrentRoom call and
// probably succeed.
}
}
this.setState({

View File

@ -107,20 +107,20 @@ export default class RolesRoomSettingsTab extends React.Component {
};
componentDidMount(): void {
MatrixClientPeg.get().on("RoomState.members", this._onRoomMembership.bind(this));
MatrixClientPeg.get().on("RoomState.members", this._onRoomMembership);
}
componentWillUnmount(): void {
const client = MatrixClientPeg.get();
if (client) {
client.removeListener("RoomState.members", this._onRoomMembership.bind(this));
client.removeListener("RoomState.members", this._onRoomMembership);
}
}
_onRoomMembership(event, state, member) {
_onRoomMembership = (event, state, member) => {
if (state.roomId !== this.props.roomId) return;
this.forceUpdate();
}
};
_populateDefaultPlEvents(eventsSection, stateLevel, eventsLevel) {
for (const desiredEvent of Object.keys(plEventsToShow)) {

View File

@ -240,6 +240,33 @@ export default class EventIndex extends EventEmitter {
this.crawlerCheckpoints.push(backwardsCheckpoint);
}
/**
* Check if an event should be added to the event index.
*
* Most notably we filter events for which decryption failed, are redacted
* or aren't of a type that we know how to index.
*
* @param {MatrixEvent} ev The event that should checked.
* @returns {bool} Returns true if the event can be indexed, false
* otherwise.
*/
isValidEvent(ev) {
const isUsefulType = ["m.room.message", "m.room.name", "m.room.topic"].includes(ev.getType());
const validEventType = isUsefulType && !ev.isRedacted() && !ev.isDecryptionFailure();
let validMsgType = true;
if (ev.getType() === "m.room.message" && !ev.isRedacted()) {
// Expand this if there are more invalid msgtypes.
const msgtype = ev.getContent().msgtype;
if (!msgtype) validMsgType = false;
else validMsgType = !msgtype.startsWith("m.key.verification");
}
return validEventType && validMsgType;
}
/**
* Queue up live events to be added to the event index.
*
@ -248,10 +275,7 @@ export default class EventIndex extends EventEmitter {
async addLiveEventToIndex(ev) {
const indexManager = PlatformPeg.get().getEventIndexingManager();
if (["m.room.message", "m.room.name", "m.room.topic"]
.indexOf(ev.getType()) == -1) {
return;
}
if (!this.isValidEvent(ev)) return;
const jsonEvent = ev.toJSON();
const e = ev.isEncrypted() ? jsonEvent.decrypted : jsonEvent;
@ -407,22 +431,11 @@ export default class EventIndex extends EventEmitter {
// Let us wait for all the events to get decrypted.
await Promise.all(decryptionPromises);
// We filter out events for which decryption failed, are redacted
// or aren't of a type that we know how to index.
const isValidEvent = (value) => {
return ([
"m.room.message",
"m.room.name",
"m.room.topic",
].indexOf(value.getType()) >= 0
&& !value.isRedacted() && !value.isDecryptionFailure()
);
};
// TODO if there are no events at this point we're missing a lot
// decryption keys, do we want to retry this checkpoint at a later
// stage?
const filteredEvents = matrixEvents.filter(isValidEvent);
const filteredEvents = matrixEvents.filter(this.isValidEvent);
// Let us convert the events back into a format that EventIndex can
// consume.

View File

@ -54,14 +54,14 @@ export class IntegrationManagers {
startWatching(): void {
this.stopWatching();
this._client = MatrixClientPeg.get();
this._client.on("accountData", this._onAccountData.bind(this));
this._client.on("accountData", this._onAccountData);
this._compileManagers();
setInterval(() => this._setupHomeserverManagers(), HS_MANAGERS_REFRESH_INTERVAL);
}
stopWatching(): void {
if (!this._client) return;
this._client.removeListener("accountData", this._onAccountData.bind(this));
this._client.removeListener("accountData", this._onAccountData);
if (this._wellknownRefreshTimerId !== null) clearInterval(this._wellknownRefreshTimerId);
}
@ -136,11 +136,11 @@ export class IntegrationManagers {
this._primaryManager = null; // reset primary
}
_onAccountData(ev: MatrixEvent): void {
_onAccountData = (ev: MatrixEvent): void => {
if (ev.getType() === 'm.widgets') {
this._compileManagers();
}
}
};
hasManager(): boolean {
return this._managers.length > 0;

View File

@ -61,7 +61,7 @@ export class Mjolnir {
setup() {
if (!MatrixClientPeg.get()) return;
this._updateLists(SettingsStore.getValue("mjolnirRooms"));
MatrixClientPeg.get().on("RoomState.events", this._onEvent.bind(this));
MatrixClientPeg.get().on("RoomState.events", this._onEvent);
}
stop() {
@ -76,7 +76,7 @@ export class Mjolnir {
}
if (!MatrixClientPeg.get()) return;
MatrixClientPeg.get().removeListener("RoomState.events", this._onEvent.bind(this));
MatrixClientPeg.get().removeListener("RoomState.events", this._onEvent);
}
async getOrCreatePersonalList(): Promise<BanList> {
@ -130,13 +130,13 @@ export class Mjolnir {
this._lists = this._lists.filter(b => b.roomId !== roomId);
}
_onEvent(event) {
_onEvent = (event) => {
if (!MatrixClientPeg.get()) return;
if (!this._roomIds.includes(event.getRoomId())) return;
if (!ALL_RULE_TYPES.includes(event.getType())) return;
this._updateLists(this._roomIds);
}
};
_onListsChanged(settingName, roomId, atLevel, newValue) {
// We know that ban lists are only recorded at one level so we don't need to re-eval them

View File

@ -106,6 +106,25 @@ export default async function sendBugReport(bugReportEndpoint, opts) {
body.append('enabled_labs', enabledLabs.join(', '));
}
// add storage persistence/quota information
if (navigator.storage && navigator.storage.persisted) {
try {
body.append("storageManager_persisted", await navigator.storage.persisted());
} catch (e) {}
}
if (navigator.storage && navigator.storage.estimate) {
try {
const estimate = await navigator.storage.estimate();
body.append("storageManager_quota", estimate.quota);
body.append("storageManager_usage", estimate.usage);
if (estimate.usageDetails) {
Object.keys(estimate.usageDetails).forEach(k => {
body.append(`storageManager_usage_${k}`, estimate.usageDetails[k]);
});
}
} catch (e) {}
}
if (opts.sendLogs) {
progressCallback(_t("Collecting logs"));
const logs = await rageshake.getLogsForReport();

View File

@ -43,6 +43,16 @@ function track(action) {
Analytics.trackEvent("StorageManager", action);
}
export function tryPersistStorage() {
if (navigator.storage && navigator.storage.persist) {
navigator.storage.persist().then(persistent => {
console.log("StorageManager: Persistent?", persistent);
});
} else {
console.log("StorageManager: Persistence unsupported");
}
}
export async function checkConsistency() {
log("Checking storage consistency");
log(`Local storage supported? ${!!localStorage}`);

View File

@ -5760,10 +5760,9 @@ mathml-tag-names@^2.0.1:
resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.1.tgz#6dff66c99d55ecf739ca53c492e626f1d12a33cc"
integrity sha512-pWB896KPGSGkp1XtyzRBftpTzwSOL0Gfk0wLvxt4f2mgzjY19o0LxJ3U25vNWTzsh7da+KTbuXQoQ3lOJZ8WHw==
matrix-js-sdk@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-5.0.0.tgz#dcbab35f1afdb35ef0364eb232e78e0fb7dc2a5b"
integrity sha512-A/aeE2Zn2OHq1n/9wIHCszrQZ7oXfThUHWi5Kz7illVCPUJ3JrZ31XVvx02k6vBasDcUtjAfZblHdTVN62cWLw==
"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop":
version "5.0.1"
resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/a998006842ae558f02819ca84fbaad43685cc10b"
dependencies:
"@babel/runtime" "^7.8.3"
another-json "^0.2.0"