diff --git a/knip.ts b/knip.ts index 6872a3d532..e71f71d0fb 100644 --- a/knip.ts +++ b/knip.ts @@ -40,6 +40,8 @@ export default { "util", // Used by workflows "ts-prune", + // Required due to bug in bloom-filters https://github.com/Callidon/bloom-filters/issues/75 + "@types/seedrandom", ], ignoreBinaries: [ // Used in scripts & workflows diff --git a/package.json b/package.json index f31cfa73c4..e9f34cf4de 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "@zxcvbn-ts/language-common": "^3.0.4", "@zxcvbn-ts/language-en": "^3.0.2", "await-lock": "^2.1.0", - "bloom-filters": "^3.0.1", + "bloom-filters": "^3.0.2", "blurhash": "^2.0.3", "browserslist": "^4.23.2", "classnames": "^2.2.6", @@ -203,6 +203,7 @@ "@types/react-dom": "18.3.1", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "2.13.0", + "@types/seedrandom": "3.0.8", "@types/semver": "^7.5.8", "@types/tar-js": "^0.3.5", "@types/ua-parser-js": "^0.7.36", diff --git a/src/Modal.tsx b/src/Modal.tsx index a2919bdc5f..076c0987e7 100644 --- a/src/Modal.tsx +++ b/src/Modal.tsx @@ -14,7 +14,7 @@ import { IDeferred, defer } from "matrix-js-sdk/src/utils"; import { TypedEventEmitter } from "matrix-js-sdk/src/matrix"; import { Glass, TooltipProvider } from "@vector-im/compound-web"; -import dis, { defaultDispatcher } from "./dispatcher/dispatcher"; +import defaultDispatcher from "./dispatcher/dispatcher"; import AsyncWrapper from "./AsyncWrapper"; import { Defaultize } from "./@types/common"; import { ActionPayload } from "./dispatcher/payloads"; @@ -396,7 +396,7 @@ export class ModalManager extends TypedEventEmitter); @@ -407,7 +407,7 @@ export class ModalManager extends TypedEventEmitter { private onWidgetLayoutChange = (): void => { if (!this.state.room) return; - dis.dispatch({ + defaultDispatcher.dispatch({ action: "appsDrawer", show: true, }); @@ -598,7 +598,7 @@ export class RoomView extends React.Component { // Handle the use case of a link to a thread message // ie: #/room/roomId/eventId (eventId of a thread message) if (thread?.rootEvent && !initialEvent?.isThreadRoot) { - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.ShowThread, rootEvent: thread.rootEvent, initialEvent, @@ -704,7 +704,7 @@ export class RoomView extends React.Component { const activeCall = CallStore.instance.getActiveCall(this.state.roomId); if (activeCall === null) { // We disconnected from the call, so stop viewing it - dis.dispatch( + defaultDispatcher.dispatch( { action: Action.ViewRoom, room_id: this.state.roomId, @@ -850,7 +850,7 @@ export class RoomView extends React.Component { public componentDidMount(): void { this.unmounted = false; - this.dispatcherRef = dis.register(this.onAction); + this.dispatcherRef = defaultDispatcher.register(this.onAction); if (this.context.client) { this.context.client.on(ClientEvent.Room, this.onRoom); this.context.client.on(RoomEvent.Timeline, this.onRoomTimeline); @@ -967,7 +967,7 @@ export class RoomView extends React.Component { // stop tracking room changes to format permalinks this.stopAllPermalinkCreators(); - dis.unregister(this.dispatcherRef); + defaultDispatcher.unregister(this.dispatcherRef); if (this.context.client) { this.context.client.removeListener(ClientEvent.Room, this.onRoom); this.context.client.removeListener(RoomEvent.Timeline, this.onRoomTimeline); @@ -1045,7 +1045,7 @@ export class RoomView extends React.Component { handled = true; break; case KeyBindingAction.UploadFile: { - dis.dispatch( + defaultDispatcher.dispatch( { action: "upload_file", context: TimelineRenderingType.Room, @@ -1145,7 +1145,7 @@ export class RoomView extends React.Component { if (payload.event && payload.event.getRoomId() !== this.state.roomId) { // If the event is in a different room (e.g. because the event to be edited is being displayed // in the results of an all-rooms search), we need to view that room first. - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: payload.event.getRoomId(), metricsTrigger: undefined, @@ -1188,7 +1188,7 @@ export class RoomView extends React.Component { } // re-dispatch to the correct composer - dis.dispatch({ + defaultDispatcher.dispatch({ ...(payload as ComposerInsertPayload), timelineRenderingType, composerType: this.state.editState ? ComposerType.Edit : ComposerType.Send, @@ -1197,7 +1197,7 @@ export class RoomView extends React.Component { } case Action.FocusAComposer: { - dis.dispatch({ + defaultDispatcher.dispatch({ ...(payload as FocusComposerPayload), // re-dispatch to the correct composer (the send message will still be on screen even when editing a message) action: this.state.editState ? Action.FocusEditMessageComposer : Action.FocusSendMessageComposer, @@ -1303,7 +1303,7 @@ export class RoomView extends React.Component { if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) { // For initial threads launch, chat effects are disabled see #19731 if (!ev.isRelation(THREAD_RELATION_TYPE.name)) { - dis.dispatch({ action: `effects.${effect.command}`, event: ev }); + defaultDispatcher.dispatch({ action: `effects.${effect.command}`, event: ev }); } } }); @@ -1363,7 +1363,7 @@ export class RoomView extends React.Component { liveTimeline: room.getLiveTimeline(), }); - dis.dispatch({ action: Action.RoomLoaded }); + defaultDispatcher.dispatch({ action: Action.RoomLoaded }); }; private onRoomTimelineReset = (room?: Room): void => { @@ -1561,7 +1561,7 @@ export class RoomView extends React.Component { private onInviteClick = (): void => { // open the room inviter - dis.dispatch({ + defaultDispatcher.dispatch({ action: "view_invite", roomId: this.getRoomId(), }); @@ -1572,7 +1572,7 @@ export class RoomView extends React.Component { if (this.context.client?.isGuest()) { // Join this room once the user has registered and logged in // (If we failed to peek, we may not have a valid room object.) - dis.dispatch>({ + defaultDispatcher.dispatch>({ action: Action.DoAfterSyncPrepared, deferred_action: { action: Action.ViewRoom, @@ -1580,13 +1580,13 @@ export class RoomView extends React.Component { metricsTrigger: undefined, }, }); - dis.dispatch({ action: "require_registration" }); + defaultDispatcher.dispatch({ action: "require_registration" }); } else { Promise.resolve().then(() => { const signUrl = this.props.threepidInvite?.signUrl; const roomId = this.getRoomId(); if (isNotUndefined(roomId)) { - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.JoinRoom, roomId, opts: { inviteSignUrl: signUrl }, @@ -1622,7 +1622,7 @@ export class RoomView extends React.Component { this.state.initialEventId === eventId ) { debuglog("Removing scroll_into_view flag from initial event"); - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: this.getRoomId(), event_id: this.state.initialEventId, @@ -1638,7 +1638,7 @@ export class RoomView extends React.Component { const roomId = this.getRoomId(); if (!this.context.client || !roomId) return; if (this.context.client.isGuest()) { - dis.dispatch({ action: "require_registration" }); + defaultDispatcher.dispatch({ action: "require_registration" }); return; } @@ -1688,7 +1688,7 @@ export class RoomView extends React.Component { }; private onForgetClick = (): void => { - dis.dispatch({ + defaultDispatcher.dispatch({ action: "forget_room", room_id: this.getRoomId(), }); @@ -1702,7 +1702,7 @@ export class RoomView extends React.Component { }); this.context.client?.leave(roomId).then( () => { - dis.dispatch({ action: Action.ViewHomePage }); + defaultDispatcher.dispatch({ action: Action.ViewHomePage }); this.setState({ rejecting: false, }); @@ -1736,7 +1736,7 @@ export class RoomView extends React.Component { await this.context.client!.setIgnoredUsers(ignoredUsers); await this.context.client!.leave(this.state.roomId!); - dis.dispatch({ action: Action.ViewHomePage }); + defaultDispatcher.dispatch({ action: Action.ViewHomePage }); this.setState({ rejecting: false, }); @@ -1760,7 +1760,7 @@ export class RoomView extends React.Component { // using /leave rather than /join. In the short term though, we // just ignore them. // https://github.com/vector-im/vector-web/issues/1134 - dis.fire(Action.ViewRoomDirectory); + defaultDispatcher.fire(Action.ViewRoomDirectory); }; private onSearchChange = debounce((e: ChangeEvent): void => { @@ -1786,7 +1786,7 @@ export class RoomView extends React.Component { // If we were viewing a highlighted event, firing view_room without // an event will take care of both clearing the URL fragment and // jumping to the bottom - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: this.getRoomId(), metricsTrigger: undefined, // room doesn't change @@ -1794,7 +1794,7 @@ export class RoomView extends React.Component { } else { // Otherwise we have to jump manually this.messagePanel?.jumpToLiveTimeline(); - dis.fire(Action.FocusSendMessageComposer); + defaultDispatcher.fire(Action.FocusSendMessageComposer); } }; @@ -1918,7 +1918,7 @@ export class RoomView extends React.Component { public onHiddenHighlightsClick = (): void => { const oldRoom = this.getOldRoom(); if (!oldRoom) return; - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: oldRoom.roomId, metricsTrigger: "Predecessor", @@ -2001,7 +2001,7 @@ export class RoomView extends React.Component { const roomId = this.getRoomId(); if (isNotUndefined(roomId)) { - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.SubmitAskToJoin, roomId, opts: { reason }, @@ -2018,7 +2018,7 @@ export class RoomView extends React.Component { const roomId = this.getRoomId(); if (isNotUndefined(roomId)) { - dis.dispatch({ + defaultDispatcher.dispatch({ action: Action.CancelAskToJoin, roomId, }); diff --git a/src/components/views/beacon/RoomCallBanner.tsx b/src/components/views/beacon/RoomCallBanner.tsx index 1615f6b010..b5626da95b 100644 --- a/src/components/views/beacon/RoomCallBanner.tsx +++ b/src/components/views/beacon/RoomCallBanner.tsx @@ -12,7 +12,7 @@ import { logger } from "matrix-js-sdk/src/logger"; import { _t } from "../../../languageHandler"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; -import dispatcher, { defaultDispatcher } from "../../../dispatcher/dispatcher"; +import defaultDispatcher from "../../../dispatcher/dispatcher"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { Action } from "../../../dispatcher/actions"; import { ConnectionState, ElementCall } from "../../../models/Call"; @@ -53,7 +53,7 @@ const RoomCallBannerInner: React.FC = ({ roomId, call }) => return; } - dispatcher.dispatch({ + defaultDispatcher.dispatch({ action: Action.ViewRoom, room_id: roomId, metricsTrigger: undefined, diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index ddf637dee2..7c7b833ec2 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -37,7 +37,7 @@ import { Icon as ExpandMessageIcon } from "../../../../res/img/element-icons/exp import { Icon as CollapseMessageIcon } from "../../../../res/img/element-icons/collapse-message.svg"; import type { Relations } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; -import dis, { defaultDispatcher } from "../../../dispatcher/dispatcher"; +import defaultDispatcher from "../../../dispatcher/dispatcher"; import ContextMenu, { aboveLeftOf, ContextMenuTooltipButton, useContextMenu } from "../../structures/ContextMenu"; import { isContentActionable, canEditContent, editEvent, canCancel } from "../../../utils/EventUtils"; import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContext"; @@ -323,7 +323,7 @@ export default class MessageActionBar extends React.PureComponent { beforeEach(() => { jest.spyOn(SettingsStore, "getValue").mockImplementation((setting) => setting === "feature_ask_to_join"); jest.spyOn(room, "getJoinRule").mockReturnValue(JoinRule.Knock); - jest.spyOn(dis, "dispatch"); + jest.spyOn(defaultDispatcher, "dispatch"); }); it("allows to request to join", async () => { @@ -536,9 +536,9 @@ describe("RoomView", () => { await mountRoomView(); fireEvent.click(screen.getByRole("button", { name: "Request access" })); - await untilDispatch(Action.SubmitAskToJoin, dis); + await untilDispatch(Action.SubmitAskToJoin, defaultDispatcher); - expect(dis.dispatch).toHaveBeenCalledWith({ + expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: "submit_ask_to_join", roomId: room.roomId, opts: { reason: undefined }, @@ -552,9 +552,12 @@ describe("RoomView", () => { await mountRoomView(); fireEvent.click(screen.getByRole("button", { name: "Cancel request" })); - await untilDispatch(Action.CancelAskToJoin, dis); + await untilDispatch(Action.CancelAskToJoin, defaultDispatcher); - expect(dis.dispatch).toHaveBeenCalledWith({ action: "cancel_ask_to_join", roomId: room.roomId }); + expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ + action: "cancel_ask_to_join", + roomId: room.roomId, + }); }); }); @@ -669,7 +672,7 @@ describe("RoomView", () => { await waitFor(() => { expect(container.querySelector(".mx_RoomView_searchResultsPanel")).toBeVisible(); }); - const prom = untilDispatch(Action.ViewRoom, dis); + const prom = untilDispatch(Action.ViewRoom, defaultDispatcher); await userEvent.hover(getByText("search term")); await userEvent.click(await findByLabelText("Edit")); @@ -678,8 +681,8 @@ describe("RoomView", () => { }); it("fires Action.RoomLoaded", async () => { - jest.spyOn(dis, "dispatch"); + jest.spyOn(defaultDispatcher, "dispatch"); await mountRoomView(); - expect(dis.dispatch).toHaveBeenCalledWith({ action: Action.RoomLoaded }); + expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({ action: Action.RoomLoaded }); }); }); diff --git a/test/unit-tests/components/views/elements/AppTile-test.tsx b/test/unit-tests/components/views/elements/AppTile-test.tsx index 129a409cf6..95ce95d3f4 100644 --- a/test/unit-tests/components/views/elements/AppTile-test.tsx +++ b/test/unit-tests/components/views/elements/AppTile-test.tsx @@ -12,7 +12,6 @@ import { ClientWidgetApi, IWidget, MatrixWidgetType } from "matrix-widget-api"; import { Optional } from "matrix-events-sdk"; import { act, render, RenderResult } from "jest-matrix-react"; import userEvent from "@testing-library/user-event"; -import { SpiedFunction } from "jest-mock"; import { ApprovalOpts, WidgetInfo, @@ -344,7 +343,7 @@ describe("AppTile", () => { describe("for a pinned widget", () => { let renderResult: RenderResult; - let moveToContainerSpy: SpiedFunction; + let moveToContainerSpy: jest.SpyInstance; beforeEach(() => { renderResult = render( diff --git a/yarn.lock b/yarn.lock index ce2ca7d56a..1201530ad6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3080,6 +3080,11 @@ dependencies: htmlparser2 "^8.0.0" +"@types/seedrandom@3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-3.0.8.tgz#61cc8ed88f93a3c31289c295e6df8ca40be42bdf" + integrity sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ== + "@types/semver@^7.5.8": version "7.5.8" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" @@ -4035,7 +4040,7 @@ blob-polyfill@^9.0.0: resolved "https://registry.yarnpkg.com/blob-polyfill/-/blob-polyfill-9.0.20240710.tgz#2ef075a207311ea327704f04dc4a98cbefe4143b" integrity sha512-DPUO/EjNANCgSVg0geTy1vmUpu5hhp9tV2F7xUSTUd1jwe4XpwupGB+lt5PhVUqpqAk+zK1etqp6Pl/HVf71Ug== -bloom-filters@^3.0.1: +bloom-filters@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/bloom-filters/-/bloom-filters-3.0.2.tgz#9c386fca1913da554ededf7a7163bbb93a82d1dd" integrity sha512-QPKiokjBy16SrBh8T/FAWo74VuNwACnJ9t+q15a+9w5CDaOqHTPPBrDUy70U7YE4+DmENRodtlEdeeq1pB4DZQ==