Merge branch 'develop' into t3chguy/dedup-icons

This commit is contained in:
Michael Telatynski
2024-10-08 10:46:33 +01:00
committed by GitHub
55 changed files with 207 additions and 306 deletions
+1 -1
View File
@@ -74,7 +74,7 @@
"@babel/runtime": "^7.12.5",
"@matrix-org/analytics-events": "^0.26.0",
"@matrix-org/emojibase-bindings": "^1.1.2",
"@matrix-org/matrix-wysiwyg": "2.37.9",
"@vector-im/matrix-wysiwyg": "2.37.13",
"@matrix-org/react-sdk-module-api": "^2.4.0",
"@matrix-org/spec": "^1.7.0",
"@sentry/browser": "^8.0.0",
+1 -18
View File
@@ -85,9 +85,7 @@ export default class DeviceListener {
public start(matrixClient: MatrixClient): void {
this.running = true;
this.client = matrixClient;
this.client.on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
this.client.on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
this.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
this.client.on(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged);
this.client.on(ClientEvent.AccountData, this.onAccountData);
@@ -109,9 +107,7 @@ export default class DeviceListener {
public stop(): void {
this.running = false;
if (this.client) {
this.client.removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
this.client.removeListener(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
this.client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
this.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged);
this.client.removeListener(ClientEvent.AccountData, this.onAccountData);
@@ -170,7 +166,7 @@ export default class DeviceListener {
return await getUserDeviceIds(cli, cli.getSafeUserId());
}
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
private onDevicesUpdated = async (users: string[], initialFetch?: boolean): Promise<void> => {
if (!this.client) return;
// If we didn't know about *any* devices before (ie. it's fresh login),
// then they are all pre-existing devices, so ignore this and set the
@@ -180,19 +176,6 @@ export default class DeviceListener {
const myUserId = this.client.getSafeUserId();
if (users.includes(myUserId)) await this.ensureDeviceIdsAtStartPopulated();
// No need to do a recheck here: we just need to get a snapshot of our devices
// before we download any new ones.
};
private onDevicesUpdated = (users: string[]): void => {
if (!this.client) return;
if (!users.includes(this.client.getSafeUserId())) return;
this.recheck();
};
private onDeviceVerificationChanged = (userId: string): void => {
if (!this.client) return;
if (userId !== this.client.getUserId()) return;
this.recheck();
};
+2
View File
@@ -43,6 +43,7 @@ import { formatList } from "./utils/FormattingUtils";
import SdkConfig from "./SdkConfig";
import { Features } from "./settings/Settings";
import { setDeviceIsolationMode } from "./settings/controllers/DeviceIsolationModeController.ts";
import { ReadyWatchingStore } from "./stores/ReadyWatchingStore.ts";
export interface IMatrixClientCreds {
homeserverUrl: string;
@@ -309,6 +310,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
MatrixActionCreators.start(this.matrixClient);
MatrixClientBackedSettingsHandler.matrixClient = this.matrixClient;
MatrixClientBackedController.matrixClient = this.matrixClient;
ReadyWatchingStore.matrixClient = this.matrixClient;
return opts;
}
-17
View File
@@ -82,7 +82,6 @@ import Spinner from "../views/elements/Spinner";
import QuestionDialog from "../views/dialogs/QuestionDialog";
import UserSettingsDialog from "../views/dialogs/UserSettingsDialog";
import CreateRoomDialog from "../views/dialogs/CreateRoomDialog";
import KeySignatureUploadFailedDialog from "../views/dialogs/KeySignatureUploadFailedDialog";
import IncomingSasDialog from "../views/dialogs/IncomingSasDialog";
import CompleteSecurity from "./auth/CompleteSecurity";
import Welcome from "../views/auth/Welcome";
@@ -1629,18 +1628,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
room.setBlacklistUnverifiedDevices(blacklistEnabled);
}
});
cli.on(CryptoEvent.Warning, (type) => {
switch (type) {
case "CRYPTO_WARNING_OLD_VERSION_DETECTED":
Modal.createDialog(ErrorDialog, {
title: _t("encryption|old_version_detected_title"),
description: _t("encryption|old_version_detected_description", {
brand: SdkConfig.get().brand,
}),
});
break;
}
});
cli.on(CryptoEvent.KeyBackupFailed, async (errcode): Promise<void> => {
let haveNewVersion: boolean | undefined;
let newVersionInfo: KeyBackupInfo | null = null;
@@ -1674,10 +1661,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
});
cli.on(CryptoEvent.KeySignatureUploadFailure, (failures, source, continuation) => {
Modal.createDialog(KeySignatureUploadFailedDialog, { failures, source, continuation });
});
cli.on(CryptoEvent.VerificationRequestReceived, (request) => {
if (request.verifier) {
Modal.createDialog(
-10
View File
@@ -428,7 +428,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
context.client.on(RoomStateEvent.Update, this.onRoomStateUpdate);
context.client.on(RoomEvent.MyMembership, this.onMyMembership);
context.client.on(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
context.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
context.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
context.client.on(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
context.client.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
@@ -974,7 +973,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.context.client.removeListener(RoomEvent.MyMembership, this.onMyMembership);
this.context.client.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
this.context.client.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatus);
this.context.client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.context.client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
this.context.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSigningKeysChanged);
this.context.client.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
@@ -1438,14 +1436,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
);
};
private onDeviceVerificationChanged = (userId: string): void => {
const room = this.state.room;
if (!room?.currentState.getMember(userId)) {
return;
}
this.updateE2EStatus(room);
};
private onUserVerificationChanged = (userId: string): void => {
const room = this.state.room;
if (!room || !room.currentState.getMember(userId)) {
@@ -1,117 +0,0 @@
/*
Copyright 2024 New Vector Ltd.
Copyright 2020 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import React, { useState, useCallback, useRef } from "react";
import { _t } from "../../../languageHandler";
import SdkConfig from "../../../SdkConfig";
import BaseDialog from "./BaseDialog";
import DialogButtons from "../elements/DialogButtons";
import Spinner from "../elements/Spinner";
interface IProps {
failures: Record<
string,
Record<
string,
{
errcode: string;
error: string;
}
>
>;
source: string;
continuation: (opts: { shouldEmit: boolean }) => Promise<void>;
onFinished(): void;
}
const KeySignatureUploadFailedDialog: React.FC<IProps> = ({ failures, source, continuation, onFinished }) => {
const RETRIES = 2;
const [retry, setRetry] = useState(RETRIES);
const [cancelled, setCancelled] = useState(false);
const [retrying, setRetrying] = useState(false);
const [success, setSuccess] = useState(false);
const onCancel = useRef(onFinished);
const causes = new Map([
["_afterCrossSigningLocalKeyChange", _t("encryption|key_signature_upload_failed_master_key_signature")],
["checkOwnCrossSigningTrust", _t("encryption|key_signature_upload_failed_cross_signing_key_signature")],
["setDeviceVerification", _t("encryption|key_signature_upload_failed_device_cross_signing_key_signature")],
]);
const defaultCause = _t("encryption|key_signature_upload_failed_key_signature");
const onRetry = useCallback(async (): Promise<void> => {
try {
setRetrying(true);
const cancel = new Promise((resolve, reject) => {
onCancel.current = reject;
}).finally(() => {
setCancelled(true);
});
await Promise.race([continuation({ shouldEmit: false }), cancel]);
setSuccess(true);
} catch (e) {
setRetry((r) => r - 1);
} finally {
onCancel.current = onFinished;
setRetrying(false);
}
}, [continuation, onFinished]);
let body;
if (!success && !cancelled && retry > 0) {
const reason = causes.get(source) || defaultCause;
const brand = SdkConfig.get().brand;
body = (
<div>
<p>{_t("encryption|key_signature_upload_failed_body", { brand })}</p>
<p>{reason}</p>
{retrying && <Spinner />}
<pre>{JSON.stringify(failures, null, 2)}</pre>
<DialogButtons
primaryButton="Retry"
hasCancel={true}
onPrimaryButtonClick={onRetry}
onCancel={onCancel.current}
primaryDisabled={retrying}
/>
</div>
);
} else {
let text = _t("encryption|key_signature_upload_completed");
if (!success) {
text = cancelled
? _t("encryption|key_signature_upload_cancelled")
: _t("encryption|key_signature_upload_failed");
}
body = (
<div>
<span>{text}</span>
<DialogButtons primaryButton={_t("action|ok")} hasCancel={false} onPrimaryButtonClick={onFinished} />
</div>
);
}
return (
<BaseDialog
title={
success
? _t("encryption|key_signature_upload_success_title")
: _t("encryption|key_signature_upload_failed_title")
}
fixedWidth={false}
onFinished={() => {}}
>
{body}
</BaseDialog>
);
};
export default KeySignatureUploadFailedDialog;
+37 -20
View File
@@ -190,25 +190,42 @@ export default class MessageEvent extends React.Component<IProps> implements IMe
}
}
return BodyType ? (
<BodyType
ref={this.body}
mxEvent={this.props.mxEvent}
highlights={this.props.highlights}
highlightLink={this.props.highlightLink}
showUrlPreview={this.props.showUrlPreview}
forExport={this.props.forExport}
maxImageHeight={this.props.maxImageHeight}
replacingEventId={this.props.replacingEventId}
editState={this.props.editState}
onHeightChanged={this.props.onHeightChanged}
onMessageAllowed={this.onTileUpdate}
permalinkCreator={this.props.permalinkCreator}
mediaEventHelper={this.mediaHelper}
getRelationsForEvent={this.props.getRelationsForEvent}
isSeeingThroughMessageHiddenForModeration={this.props.isSeeingThroughMessageHiddenForModeration}
inhibitInteraction={this.props.inhibitInteraction}
/>
) : null;
const hasCaption =
[MsgType.Image, MsgType.File, MsgType.Audio, MsgType.Video].includes(msgtype as MsgType) &&
content.filename &&
content.filename !== content.body;
const bodyProps: IBodyProps = {
ref: this.body,
mxEvent: this.props.mxEvent,
highlights: this.props.highlights,
highlightLink: this.props.highlightLink,
showUrlPreview: this.props.showUrlPreview,
forExport: this.props.forExport,
maxImageHeight: this.props.maxImageHeight,
replacingEventId: this.props.replacingEventId,
editState: this.props.editState,
onHeightChanged: this.props.onHeightChanged,
onMessageAllowed: this.onTileUpdate,
permalinkCreator: this.props.permalinkCreator,
mediaEventHelper: this.mediaHelper,
getRelationsForEvent: this.props.getRelationsForEvent,
isSeeingThroughMessageHiddenForModeration: this.props.isSeeingThroughMessageHiddenForModeration,
inhibitInteraction: this.props.inhibitInteraction,
};
if (hasCaption) {
return <CaptionBody {...bodyProps} WrappedBodyType={BodyType} />;
}
return BodyType ? <BodyType {...bodyProps} /> : null;
}
}
const CaptionBody: React.FunctionComponent<IBodyProps & { WrappedBodyType: React.ComponentType<IBodyProps> }> = ({
WrappedBodyType,
...props
}) => (
<div className="mx_EventTile_content">
<WrappedBodyType {...props} />
<TextualBody {...{ ...props, ref: undefined }} />
</div>
);
@@ -556,6 +556,9 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
const content = mxEvent.getContent();
const isNotice = content.msgtype === MsgType.Notice;
const isEmote = content.msgtype === MsgType.Emote;
const isCaption = [MsgType.Image, MsgType.File, MsgType.Audio, MsgType.Video].includes(
content.msgtype as MsgType,
);
const willHaveWrapper =
this.props.replacingEventId || this.props.isSeeingThroughMessageHiddenForModeration || isEmote;
@@ -635,6 +638,14 @@ export default class TextualBody extends React.Component<IBodyProps, IState> {
</div>
);
}
if (isCaption) {
return (
<div className="mx_MTextBody mx_EventTile_caption" onClick={this.onBodyLinkClick}>
{body}
{widgets}
</div>
);
}
return (
<div className="mx_MTextBody mx_EventTile_content" onClick={this.onBodyLinkClick}>
{body}
@@ -1381,22 +1381,16 @@ export const useDevices = (userId: string): IDevice[] | undefined | null => {
if (!users.includes(userId)) return;
updateDevices();
};
const onDeviceVerificationChanged = (_userId: string, deviceId: string): void => {
if (_userId !== userId) return;
updateDevices();
};
const onUserTrustStatusChanged = (_userId: string, trustLevel: UserVerificationStatus): void => {
if (_userId !== userId) return;
updateDevices();
};
cli.on(CryptoEvent.DevicesUpdated, onDevicesUpdated);
cli.on(CryptoEvent.DeviceVerificationChanged, onDeviceVerificationChanged);
cli.on(CryptoEvent.UserTrustStatusChanged, onUserTrustStatusChanged);
// Handle being unmounted
return () => {
cancel = true;
cli.removeListener(CryptoEvent.DevicesUpdated, onDevicesUpdated);
cli.removeListener(CryptoEvent.DeviceVerificationChanged, onDeviceVerificationChanged);
cli.removeListener(CryptoEvent.UserTrustStatusChanged, onUserTrustStatusChanged);
};
}, [cli, userId]);
-8
View File
@@ -385,7 +385,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
this.suppressReadReceiptAnimation = false;
const client = MatrixClientPeg.safeGet();
if (!this.props.forExport) {
client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
client.on(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
this.props.mxEvent.on(MatrixEventEvent.Decrypted, this.onDecrypted);
this.props.mxEvent.on(MatrixEventEvent.Replaced, this.onReplaced);
@@ -425,7 +424,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
public componentWillUnmount(): void {
const client = MatrixClientPeg.get();
if (client) {
client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserVerificationChanged);
client.removeListener(RoomEvent.Receipt, this.onRoomReceipt);
const room = client.getRoom(this.props.mxEvent.getRoomId());
@@ -564,12 +562,6 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
this.forceUpdate(this.props.onHeightChanged);
};
private onDeviceVerificationChanged = (userId: string, device: string): void => {
if (userId === this.props.mxEvent.getSender()) {
this.verifyEvent();
}
};
private onUserVerificationChanged = (userId: string, _trustStatus: UserVerificationStatus): void => {
if (userId === this.props.mxEvent.getSender()) {
this.verifyEvent();
@@ -9,7 +9,6 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { RoomMember, RoomStateEvent, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
@@ -62,7 +61,6 @@ export default class MemberTile extends React.Component<IProps, IState> {
});
if (isRoomEncrypted) {
cli.on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
cli.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
this.updateE2EStatus();
} else {
// Listen for room to become encrypted
@@ -77,7 +75,6 @@ export default class MemberTile extends React.Component<IProps, IState> {
if (cli) {
cli.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
cli.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
cli.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
}
}
@@ -100,11 +97,6 @@ export default class MemberTile extends React.Component<IProps, IState> {
this.updateE2EStatus();
};
private onDeviceVerificationChanged = (userId: string, deviceId: string, deviceInfo: DeviceInfo): void => {
if (userId !== this.props.member.userId) return;
this.updateE2EStatus();
};
private async updateE2EStatus(): Promise<void> {
const cli = MatrixClientPeg.safeGet();
const { userId } = this.props.member;
@@ -10,7 +10,7 @@ import React, { ComponentProps, lazy, Suspense } from "react";
import { ISendEventResponse } from "matrix-js-sdk/src/matrix";
// we need to import the types for TS, but do not import the sendMessage
// function to avoid importing from "@matrix-org/matrix-wysiwyg"
// function to avoid importing from "@vector-im/matrix-wysiwyg"
import { SendMessageParams } from "./utils/message";
import { retry } from "../../../../utils/promise";
@@ -55,7 +55,7 @@ export const dynamicImportConversionFunctions = async (): Promise<{
*/
plainToRich(plain: string, inMessageFormat: boolean): Promise<string>;
}> => {
const { richToPlain, plainToRich } = await retry(() => import("@matrix-org/matrix-wysiwyg"), RETRY_COUNT);
const { richToPlain, plainToRich } = await retry(() => import("@vector-im/matrix-wysiwyg"), RETRY_COUNT);
return { richToPlain, plainToRich };
};
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { MouseEventHandler, ReactNode } from "react";
import { FormattingFunctions, AllActionStates, ActionState } from "@matrix-org/matrix-wysiwyg";
import { FormattingFunctions, AllActionStates, ActionState } from "@vector-im/matrix-wysiwyg";
import classNames from "classnames";
import BoldIcon from "@vector-im/compound-design-tokens/assets/web/icons/bold";
import BulletedListIcon from "@vector-im/compound-design-tokens/assets/web/icons/list-bulleted";
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { FormattingFunctions } from "@vector-im/matrix-wysiwyg";
import React, { ChangeEvent, useState } from "react";
import { _t } from "../../../../../languageHandler";
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import React, { ForwardedRef, forwardRef, FunctionComponent } from "react";
import { FormattingFunctions, MappedSuggestion } from "@matrix-org/matrix-wysiwyg";
import { FormattingFunctions, MappedSuggestion } from "@vector-im/matrix-wysiwyg";
import { logger } from "matrix-js-sdk/src/logger";
import { useRoomContext } from "../../../../../contexts/RoomContext";
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React, { memo, MutableRefObject, ReactNode, useEffect, useMemo, useRef } from "react";
import { IEventRelation } from "matrix-js-sdk/src/matrix";
import { EMOTICON_TO_EMOJI } from "@matrix-org/emojibase-bindings";
import { useWysiwyg, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { useWysiwyg, FormattingFunctions } from "@vector-im/matrix-wysiwyg";
import classNames from "classnames";
import Autocomplete from "../../Autocomplete";
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { Wysiwyg, WysiwygEvent } from "@matrix-org/matrix-wysiwyg";
import { Wysiwyg, WysiwygEvent } from "@vector-im/matrix-wysiwyg";
import { useCallback } from "react";
import { IEventRelation, MatrixClient } from "matrix-js-sdk/src/matrix";
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import { KeyboardEvent, RefObject, SyntheticEvent, useCallback, useRef, useState } from "react";
import { AllowedMentionAttributes, MappedSuggestion } from "@matrix-org/matrix-wysiwyg";
import { AllowedMentionAttributes, MappedSuggestion } from "@vector-im/matrix-wysiwyg";
import { IEventRelation } from "matrix-js-sdk/src/matrix";
import { useSettingValue } from "../../../../../hooks/useSettings";
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
*/
import { EMOTICON_TO_EMOJI } from "@matrix-org/emojibase-bindings";
import { AllowedMentionAttributes, MappedSuggestion } from "@matrix-org/matrix-wysiwyg";
import { AllowedMentionAttributes, MappedSuggestion } from "@vector-im/matrix-wysiwyg";
import { SyntheticEvent, useState, SetStateAction } from "react";
import { logger } from "matrix-js-sdk/src/logger";
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import { MutableRefObject, RefObject } from "react";
import { IEventRelation, MatrixClient } from "matrix-js-sdk/src/matrix";
import { WysiwygEvent } from "@matrix-org/matrix-wysiwyg";
import { WysiwygEvent } from "@vector-im/matrix-wysiwyg";
import { TimelineRenderingType } from "../../../../../contexts/RoomContext";
import { IRoomState } from "../../../../structures/RoomView";
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { AllowedMentionAttributes, MappedSuggestion } from "@matrix-org/matrix-wysiwyg";
import { AllowedMentionAttributes, MappedSuggestion } from "@vector-im/matrix-wysiwyg";
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
import { ICompletion } from "../../../../../autocomplete/Autocompleter";
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { richToPlain, plainToRich } from "@matrix-org/matrix-wysiwyg";
import { richToPlain, plainToRich } from "@vector-im/matrix-wysiwyg";
import { IContent, IEventRelation, MatrixEvent, MsgType } from "matrix-js-sdk/src/matrix";
import { ReplacementEvent, RoomMessageEventContent, RoomMessageTextEventContent } from "matrix-js-sdk/src/types";
-12
View File
@@ -904,16 +904,6 @@
"incompatible_database_disable": "Continue With Encryption Disabled",
"incompatible_database_sign_out_description": "To avoid losing your chat history, you must export your room keys before logging out. You will need to go back to the newer version of %(brand)s to do this",
"incompatible_database_title": "Incompatible Database",
"key_signature_upload_cancelled": "Cancelled signature upload",
"key_signature_upload_completed": "Upload completed",
"key_signature_upload_failed": "Unable to upload",
"key_signature_upload_failed_body": "%(brand)s encountered an error during upload of:",
"key_signature_upload_failed_cross_signing_key_signature": "a new cross-signing key signature",
"key_signature_upload_failed_device_cross_signing_key_signature": "a device cross-signing signature",
"key_signature_upload_failed_key_signature": "a key signature",
"key_signature_upload_failed_master_key_signature": "a new master key signature",
"key_signature_upload_failed_title": "Signature upload failed",
"key_signature_upload_success_title": "Signature upload success",
"messages_not_secure": {
"cause_1": "Your homeserver",
"cause_2": "The homeserver the user you're verifying is connected to",
@@ -929,8 +919,6 @@
"warning": "If you didn't set the new recovery method, an attacker may be trying to access your account. Change your account password and set a new recovery method immediately in Settings."
},
"not_supported": "<not supported>",
"old_version_detected_description": "Data from an older version of %(brand)s has been detected. This will have caused end-to-end cryptography to malfunction in the older version. End-to-end encrypted messages exchanged recently whilst using the older version may not be decryptable in this version. This may also cause messages exchanged with this version to fail. If you experience problems, log out and back in again. To retain message history, export and re-import your keys.",
"old_version_detected_title": "Old cryptography data detected",
"recovery_method_removed": {
"description_1": "This session has detected that your Security Phrase and key for Secure Messages have been removed.",
"description_2": "If you did this accidentally, you can setup Secure Messages on this session which will re-encrypt this session's message history with a new recovery method.",
+7 -2
View File
@@ -36,8 +36,13 @@ export abstract class AsyncStoreWithClient<T extends Object> extends AsyncStore<
})(dispatcher);
}
public async start(): Promise<void> {
await this.readyStore.start();
protected async start(matrixClient: MatrixClient | null): Promise<void> {
await this.readyStore.start(matrixClient);
}
// XXX: This method is intended only for use in tests.
public async useUnitTestClient(cli: MatrixClient): Promise<void> {
await this.readyStore.useUnitTestClient(cli);
}
public get matrixClient(): MatrixClient | null {
+1 -3
View File
@@ -46,9 +46,7 @@ interface IState {
*/
export default class AutoRageshakeStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new AutoRageshakeStore();
instance.start();
return instance;
return new AutoRageshakeStore();
})();
private constructor() {
+1 -3
View File
@@ -30,9 +30,7 @@ interface IState {
export class BreadcrumbsStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new BreadcrumbsStore();
instance.start();
return instance;
return new BreadcrumbsStore();
})();
private waitingRooms: { roomId: string; addedTs: number }[] = [];
-1
View File
@@ -31,7 +31,6 @@ export class CallStore extends AsyncStoreWithClient<{}> {
public static get instance(): CallStore {
if (!this._instance) {
this._instance = new CallStore();
this._instance.start();
}
return this._instance;
}
-1
View File
@@ -24,7 +24,6 @@ interface IState {
export class ModalWidgetStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new ModalWidgetStore();
instance.start();
return instance;
})();
private modalInstance: IHandle<typeof ModalWidgetDialog> | null = null;
-1
View File
@@ -87,7 +87,6 @@ const getLocallyCreatedBeaconEventIds = (): string[] => {
export class OwnBeaconStore extends AsyncStoreWithClient<OwnBeaconStoreState> {
private static readonly internalInstance = (() => {
const instance = new OwnBeaconStore();
instance.start();
return instance;
})();
// users beacons, keyed by event type
-1
View File
@@ -28,7 +28,6 @@ const KEY_AVATAR_URL = "mx_profile_avatar_url";
export class OwnProfileStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new OwnProfileStore();
instance.start();
return instance;
})();
+26 -11
View File
@@ -9,27 +9,40 @@
import { MatrixClient, SyncState } from "matrix-js-sdk/src/matrix";
import { EventEmitter } from "events";
import { MatrixClientPeg } from "../MatrixClientPeg";
import { ActionPayload } from "../dispatcher/payloads";
import { IDestroyable } from "../utils/IDestroyable";
import { Action } from "../dispatcher/actions";
import { MatrixDispatcher } from "../dispatcher/dispatcher";
export abstract class ReadyWatchingStore extends EventEmitter implements IDestroyable {
protected matrixClient: MatrixClient | null = null;
private static instances: ReadyWatchingStore[] = [];
protected _matrixClient: MatrixClient | null = null;
private dispatcherRef: string | null = null;
public static set matrixClient(client: MatrixClient) {
for (const instance of ReadyWatchingStore.instances) {
instance.start(client);
}
}
public constructor(protected readonly dispatcher: MatrixDispatcher) {
super();
this.dispatcherRef = this.dispatcher.register(this.onAction);
}
public async start(): Promise<void> {
this.dispatcherRef = this.dispatcher.register(this.onAction);
public get matrixClient(): MatrixClient | null {
return this._matrixClient;
}
// MatrixClientPeg can be undefined in tests because of circular dependencies with other stores
const matrixClient = MatrixClientPeg?.get();
public async start(matrixClient: MatrixClient | null): Promise<void> {
const oldClient = this._matrixClient;
this._matrixClient = matrixClient;
if (oldClient !== matrixClient) {
await this.onNotReady();
}
if (matrixClient) {
this.matrixClient = matrixClient;
await this.onReady();
}
}
@@ -38,8 +51,10 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro
return this.matrixClient; // for external readonly access
}
public useUnitTestClient(cli: MatrixClient): void {
this.matrixClient = cli;
// XXX: This method is intended only for use in tests.
public async useUnitTestClient(cli: MatrixClient): Promise<void> {
this._matrixClient = cli;
await this.onReady();
}
public destroy(): void {
@@ -74,13 +89,13 @@ export abstract class ReadyWatchingStore extends EventEmitter implements IDestro
if (this.matrixClient) {
await this.onNotReady();
}
this.matrixClient = payload.matrixClient;
this._matrixClient = payload.matrixClient;
await this.onReady();
}
} else if (payload.action === "on_client_not_viable" || payload.action === Action.OnLoggedOut) {
if (this.matrixClient) {
await this.onNotReady();
this.matrixClient = null;
this._matrixClient = null;
}
}
};
-1
View File
@@ -30,7 +30,6 @@ export class VoiceRecordingStore extends AsyncStoreWithClient<IState> {
public static get instance(): VoiceRecordingStore {
if (!this.internalInstance) {
this.internalInstance = new VoiceRecordingStore();
this.internalInstance.start();
}
return this.internalInstance;
}
-1
View File
@@ -45,7 +45,6 @@ interface IRoomWidgets {
export default class WidgetStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new WidgetStore();
instance.start();
return instance;
})();
-1
View File
@@ -38,7 +38,6 @@ export class EchoStore extends AsyncStoreWithClient<IState> {
public static get instance(): EchoStore {
if (!this._instance) {
this._instance = new EchoStore();
this._instance.start();
}
return this._instance;
}
@@ -26,7 +26,6 @@ export const UPDATE_STATUS_INDICATOR = Symbol("update-status-indicator");
export class RoomNotificationStateStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new RoomNotificationStateStore();
instance.start();
return instance;
})();
private roomMap = new Map<Room, RoomNotificationState>();
@@ -403,7 +403,6 @@ export default class RightPanelStore extends ReadyWatchingStore {
public static get instance(): RightPanelStore {
if (!this.internalInstance) {
this.internalInstance = new RightPanelStore();
this.internalInstance.start();
}
return this.internalInstance;
}
+1 -5
View File
@@ -124,11 +124,7 @@ const mkMessagePreview = (text: string, event: MatrixEvent): MessagePreview => {
};
export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
private static readonly internalInstance = (() => {
const instance = new MessagePreviewStore();
instance.start();
return instance;
})();
private static readonly internalInstance = (() => new MessagePreviewStore())();
/**
* @internal Public for test only
@@ -28,7 +28,6 @@ export default class RoomListLayoutStore extends AsyncStoreWithClient<IState> {
public static get instance(): RoomListLayoutStore {
if (!this.internalInstance) {
this.internalInstance = new RoomListLayoutStore();
this.internalInstance.start();
}
return RoomListLayoutStore.internalInstance;
}
-2
View File
@@ -643,11 +643,9 @@ export default class RoomListStore {
if (SettingsStore.getValue("feature_sliding_sync")) {
logger.info("using SlidingRoomListStoreClass");
const instance = new SlidingRoomListStoreClass(defaultDispatcher, SdkContextClass.instance);
instance.start();
RoomListStore.internalInstance = instance;
} else {
const instance = new RoomListStoreClass(defaultDispatcher);
instance.start();
RoomListStore.internalInstance = instance;
}
}
+3 -3
View File
@@ -17,6 +17,7 @@ import {
MatrixEvent,
ClientEvent,
ISendEventResponse,
MatrixClient,
} from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
@@ -1397,7 +1398,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
export default class SpaceStore {
private static readonly internalInstance = (() => {
const instance = new SpaceStoreClass();
instance.start();
return instance;
})();
@@ -1408,9 +1408,9 @@ export default class SpaceStore {
/**
* @internal for test only
*/
public static testInstance(): SpaceStoreClass {
public static testInstance(client: MatrixClient): SpaceStoreClass {
const store = new SpaceStoreClass();
store.start();
store.useUnitTestClient(client);
return store;
}
}
-1
View File
@@ -60,7 +60,6 @@ export class WidgetLayoutStore extends ReadyWatchingStore {
public static get instance(): WidgetLayoutStore {
if (!this.internalInstance) {
this.internalInstance = new WidgetLayoutStore();
this.internalInstance.start();
}
return this.internalInstance;
}
@@ -27,7 +27,6 @@ export enum WidgetMessagingStoreEvent {
export class WidgetMessagingStore extends AsyncStoreWithClient<{}> {
private static readonly internalInstance = (() => {
const instance = new WidgetMessagingStore();
instance.start();
return instance;
})();
+3 -1
View File
@@ -38,7 +38,9 @@ export function presentableTextForFile(
shortened = false,
): string {
let text = fallbackText;
if (content.body?.length) {
if (content.filename?.length) {
text = content.filename;
} else if (content.body?.length) {
// The content body should be the name of the file including a
// file extension.
text = content.body;
@@ -8,7 +8,10 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { render, RenderResult } from "@testing-library/react";
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { MatrixClient, MatrixEvent, EventType, Room, MsgType } from "matrix-js-sdk/src/matrix";
import fetchMock from "fetch-mock-jest";
import fs from "fs";
import path from "path";
import SettingsStore from "../../../../src/settings/SettingsStore";
import { VoiceBroadcastInfoEventType, VoiceBroadcastInfoState } from "../../../../src/voice-broadcast";
@@ -25,6 +28,26 @@ jest.mock("../../../../src/voice-broadcast/components/VoiceBroadcastBody", () =>
VoiceBroadcastBody: () => <div data-testid="voice-broadcast-body" />,
}));
jest.mock("../../../../src/components/views/messages/MImageBody", () => ({
__esModule: true,
default: () => <div data-testid="image-body" />,
}));
jest.mock("../../../../src/components/views/messages/MImageReplyBody", () => ({
__esModule: true,
default: () => <div data-testid="image-reply-body" />,
}));
jest.mock("../../../../src/components/views/messages/MStickerBody", () => ({
__esModule: true,
default: () => <div data-testid="sticker-body" />,
}));
jest.mock("../../../../src/components/views/messages/TextualBody.tsx", () => ({
__esModule: true,
default: () => <div data-testid="textual-body" />,
}));
describe("MessageEvent", () => {
let room: Room;
let client: MatrixClient;
@@ -68,4 +91,42 @@ describe("MessageEvent", () => {
result.getByTestId("voice-broadcast-body");
});
});
describe("when an image with a caption is sent", () => {
let result: RenderResult;
beforeEach(() => {
event = mkEvent({
event: true,
type: EventType.RoomMessage,
user: client.getUserId()!,
room: room.roomId,
content: {
body: "caption for a test image",
format: "org.matrix.custom.html",
formatted_body: "<strong>caption for a test image</strong>",
msgtype: MsgType.Image,
filename: "image.webp",
info: {
w: 40,
h: 50,
},
url: "mxc://server/image",
},
});
result = renderMessageEvent();
});
it("should render a TextualBody and an ImageBody", () => {
fetchMock.getOnce(
"https://server/_matrix/media/v3/download/server/image",
{
body: fs.readFileSync(path.resolve(__dirname, "..", "..", "..", "images", "animated-logo.webp")),
},
{ sendAsJson: false },
);
result.getByTestId("image-body");
result.getByTestId("textual-body");
});
});
});
@@ -9,7 +9,7 @@ Please see LICENSE files in the repository root for full details.
import React from "react";
import { cleanup, render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ActionState, ActionTypes, AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { ActionState, ActionTypes, AllActionStates, FormattingFunctions } from "@vector-im/matrix-wysiwyg";
import { FormattingButtons } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/FormattingButtons";
import * as LinkModal from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal";
@@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
import { FormattingFunctions } from "@matrix-org/matrix-wysiwyg";
import { FormattingFunctions } from "@vector-im/matrix-wysiwyg";
import { render, screen, waitFor } from "@testing-library/react";
import React from "react";
import userEvent from "@testing-library/user-event";
+1 -1
View File
@@ -47,7 +47,7 @@ describe("AutoRageshakeStore", () => {
// @ts-ignore bypass private ctor for tests
autoRageshakeStore = new AutoRageshakeStore();
autoRageshakeStore.start();
autoRageshakeStore.useUnitTestClient(client);
utdEvent = mkEvent({
event: true,
+3 -3
View File
@@ -40,7 +40,7 @@ describe("OwnProfileStore", () => {
displayname: "Display Name",
avatar_url: "mxc://example.com/abc123",
});
await ownProfileStore.start();
await ownProfileStore.useUnitTestClient(client);
expect(onUpdate).toHaveBeenCalled();
expect(ownProfileStore.displayName).toBe("Display Name");
@@ -54,7 +54,7 @@ describe("OwnProfileStore", () => {
errcode: "M_NOT_FOUND",
}),
);
await ownProfileStore.start();
await ownProfileStore.useUnitTestClient(client);
expect(onUpdate).toHaveBeenCalled();
expect(ownProfileStore.displayName).toBe(client.getSafeUserId());
@@ -69,7 +69,7 @@ describe("OwnProfileStore", () => {
}),
);
try {
await ownProfileStore.start();
await ownProfileStore.useUnitTestClient(client);
} catch (ignore) {}
expect(onUpdate).not.toHaveBeenCalled();
+2 -2
View File
@@ -1428,7 +1428,7 @@ describe("SpaceStore", () => {
it("passes that value in calls to getVisibleRooms during getSpaceFilteredRoomIds", () => {
// Given a store
const store = SpaceStore.testInstance();
const store = SpaceStore.testInstance(client);
// When we ask for filtered room ids
store.getSpaceFilteredRoomIds(MetaSpace.Home);
@@ -1478,7 +1478,7 @@ describe("SpaceStore", () => {
it("passes that value in calls to getVisibleRooms during getSpaceFilteredRoomIds", () => {
// Given a store
const store = SpaceStore.testInstance();
const store = SpaceStore.testInstance(client);
// When we ask for filtered room ids
store.getSpaceFilteredRoomIds(MetaSpace.Home);
+1 -1
View File
@@ -31,7 +31,7 @@ describe("VoiceRecordingStore", () => {
const mkStore = (): VoiceRecordingStore => {
const store = new VoiceRecordingStore();
store.start();
store.useUnitTestClient(stubClient);
return store;
};
+4 -4
View File
@@ -167,7 +167,7 @@ describe("WidgetLayoutStore", () => {
it("should recalculate all rooms when the client is ready", async () => {
mocked(client.getVisibleRooms).mockReturnValue([mockRoom]);
await store.start();
await store.start(client);
expect(roomUpdateListener).toHaveBeenCalled();
expect(store.getContainerWidgets(mockRoom, Container.Top)).toEqual([]);
@@ -243,7 +243,7 @@ describe("WidgetLayoutStore", () => {
});
it("should copy the layout to the room", async () => {
await store.start();
await store.start(client);
store.recalculateRoom(mockRoom);
store.moveToContainer(mockRoom, mockApps[0], Container.Top);
store.copyLayoutToRoom(mockRoom);
@@ -297,7 +297,7 @@ describe("WidgetLayoutStore", () => {
mocked(client.getVisibleRooms).mockReturnValue([]);
// @ts-ignore bypass private ctor for tests
const store = new WidgetLayoutStore();
await store.start();
await store.start(client);
expect(client.getVisibleRooms).toHaveBeenCalledWith(false);
});
});
@@ -314,7 +314,7 @@ describe("WidgetLayoutStore", () => {
mocked(client.getVisibleRooms).mockReturnValue([]);
// @ts-ignore bypass private ctor for tests
const store = new WidgetLayoutStore();
await store.start();
await store.start(client);
expect(client.getVisibleRooms).toHaveBeenCalledWith(true);
});
});
@@ -80,7 +80,7 @@ describe("MessagePreviewStore", () => {
mocked(client.getRoom).mockReturnValue(room);
store = MessagePreviewStore.testInstance();
await store.start();
await store.useUnitTestClient(client);
await setupAsyncStoreWithClient(store, client);
});
+10 -5
View File
@@ -29,6 +29,9 @@ import DMRoomMap from "../../../src/utils/DMRoomMap";
import { flushPromises, stubClient, upsertRoomStateEvents, mkRoom } from "../../test-utils";
import { DEFAULT_PUSH_RULES, makePushRule } from "../../test-utils/pushRules";
// Mock out the SpaceWatcher as it messes with the prefilterConditions
jest.mock("../../../src/stores/room-list/SpaceWatcher.ts");
describe("RoomListStore", () => {
const client = stubClient();
const newRoomId = "!roomid:example.com";
@@ -91,6 +94,10 @@ describe("RoomListStore", () => {
await (RoomListStore.instance as RoomListStoreClass).makeReady(client);
});
beforeEach(() => {
DMRoomMap.makeShared(client);
});
it.each(OrderedDefaultTagIDs)("defaults to importance ordering for %s=", (tagId) => {
expect(RoomListStore.instance.getTagSorting(tagId)).toBe(SortAlgorithm.Recent);
});
@@ -102,11 +109,11 @@ describe("RoomListStore", () => {
function createStore(): { store: RoomListStoreClass; handleRoomUpdate: jest.Mock<any, any> } {
const fakeDispatcher = { register: jest.fn() } as unknown as MatrixDispatcher;
const store = new RoomListStoreClass(fakeDispatcher);
// @ts-ignore accessing private member to set client
store.readyStore.matrixClient = client;
const handleRoomUpdate = jest.fn();
// @ts-ignore accessing private member to mock it
store.algorithm.handleRoomUpdate = handleRoomUpdate;
// @ts-ignore accessing private member to set client
store.readyStore.useUnitTestClient(client);
return { store, handleRoomUpdate };
}
@@ -157,7 +164,6 @@ describe("RoomListStore", () => {
room1.updateMyMembership(KnownMembership.Join);
room2.updateMyMembership(KnownMembership.Join);
room3.updateMyMembership(KnownMembership.Join);
DMRoomMap.makeShared(client);
const { store } = createStore();
client.getVisibleRooms = jest.fn().mockReturnValue([room1, room2, room3]);
@@ -269,7 +275,6 @@ describe("RoomListStore", () => {
it("Passes the feature flag on to the client when asking for visible rooms", () => {
// Given a store that we can ask for a room list
DMRoomMap.makeShared(client);
const { store } = createStore();
client.getVisibleRooms = jest.fn().mockReturnValue([]);
@@ -285,7 +290,7 @@ describe("RoomListStore", () => {
describe("room updates", () => {
const makeStore = async () => {
const store = new RoomListStoreClass(defaultDispatcher);
await store.start();
await store.useUnitTestClient(client);
return store;
};
@@ -65,7 +65,7 @@ describe("SlidingRoomListStore", () => {
describe("spaces", () => {
it("alters 'filters.spaces' on the DefaultTagID.Untagged list when the selected space changes", async () => {
await store.start(); // call onReady
await store.useUnitTestClient(context.client!); // call onReady
const spaceRoomId = "!foo:bar";
const p = untilEmission(store, LISTS_LOADING_EVENT, (listName, isLoading) => {
@@ -92,7 +92,7 @@ describe("SlidingRoomListStore", () => {
},
);
activeSpace = MetaSpace.Home;
await store.start(); // call onReady
await store.useUnitTestClient(context.client!); // call onReady
expect(context._SlidingSyncManager!.ensureListRegistered).toHaveBeenCalledWith(DefaultTagID.Untagged, {
filters: expect.objectContaining({
@@ -108,7 +108,7 @@ describe("SlidingRoomListStore", () => {
const p = untilEmission(store, LISTS_LOADING_EVENT, (listName, isLoading) => {
return listName === DefaultTagID.Untagged && !isLoading;
});
await store.start(); // call onReady
await store.useUnitTestClient(context.client!); // call onReady
await p;
expect(context._SlidingSyncManager!.ensureListRegistered).toHaveBeenCalledWith(
DefaultTagID.Untagged,
@@ -121,7 +121,7 @@ describe("SlidingRoomListStore", () => {
});
it("includes subspaces in 'filters.spaces' when the selected space has subspaces", async () => {
await store.start(); // call onReady
await store.useUnitTestClient(context.client!); // call onReady
const spaceRoomId = "!foo:bar";
const subSpace1 = "!ss1:bar";
const subSpace2 = "!ss2:bar";
@@ -168,7 +168,7 @@ describe("SlidingRoomListStore", () => {
});
it("getTagsForRoom gets the tags for the room", async () => {
await store.start();
await store.useUnitTestClient(context.client!);
const roomA = "!a:localhost";
const roomB = "!b:localhost";
const keyToListData: Record<string, { joinedCount: number; roomIndexToRoomId: Record<number, string> }> = {
@@ -200,7 +200,7 @@ describe("SlidingRoomListStore", () => {
});
it("emits LISTS_UPDATE_EVENT when slidingSync lists update", async () => {
await store.start();
await store.useUnitTestClient(context.client!);
const roomA = "!a:localhost";
const roomB = "!b:localhost";
const roomC = "!c:localhost";
@@ -236,7 +236,7 @@ describe("SlidingRoomListStore", () => {
});
it("sets the sticky room on the basis of the viewed room in RoomViewStore", async () => {
await store.start();
await store.useUnitTestClient(context.client!);
// seed the store with 3 rooms
const roomIdA = "!a:localhost";
const roomIdB = "!b:localhost";
@@ -301,7 +301,7 @@ describe("SlidingRoomListStore", () => {
});
it("gracefully handles unknown room IDs", async () => {
await store.start();
await store.useUnitTestClient(context.client!);
const roomIdA = "!a:localhost";
const roomIdB = "!b:localhost"; // does not exist
const roomIdC = "!c:localhost";
+7 -7
View File
@@ -1911,13 +1911,6 @@
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-wasm/-/matrix-sdk-crypto-wasm-7.0.0.tgz#8d6abdb9ded8656cc9e2a7909913a34bf3fc9b3a"
integrity sha512-MOencXiW/gI5MuTtCNsuojjwT5DXCrjMqv9xOslJC9h2tPdLFFFMGr58dY5Lis4DRd9MRWcgrGowUIHOqieWTA==
"@matrix-org/matrix-wysiwyg@2.37.9":
version "2.37.9"
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-2.37.9.tgz#4d5667df3c74e11fd01c4b5be920caff72bf2f48"
integrity sha512-Jn2ug6ySX5es5/SV5BVgSBhVPS7GXggwZ/GGWmnJvhnp/IArit4kgUAsNRhQeKebuVvNphwQykCGwyBOn2PLBA==
dependencies:
eslint-plugin-unicorn "^54.0.0"
"@matrix-org/olm@3.2.15":
version "3.2.15"
resolved "https://registry.yarnpkg.com/@matrix-org/olm/-/olm-3.2.15.tgz#55f3c1b70a21bbee3f9195cecd6846b1083451ec"
@@ -3101,6 +3094,13 @@
ts-xor "^1.3.0"
vaul "^0.7.0"
"@vector-im/matrix-wysiwyg@2.37.13":
version "2.37.13"
resolved "https://registry.yarnpkg.com/@vector-im/matrix-wysiwyg/-/matrix-wysiwyg-2.37.13.tgz#7b64e7652a196e811c0470dcbff8d36e2229cd46"
integrity sha512-3ilnJBJSzeTfAQXNJJ29EAqa14exrkca3acTPssdoh3WhTKwXyQ0xU8sS50d6gqlAP/Nahw1y2k+PzajXo1SsQ==
dependencies:
eslint-plugin-unicorn "^54.0.0"
"@zxcvbn-ts/core@^3.0.4":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@zxcvbn-ts/core/-/core-3.0.4.tgz#c5bde72235eb6c273cec78b672bb47c0d7045cad"