From d560931c4ec27d6a55523b95bba1eb33fa2b945f Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Tue, 20 Dec 2022 15:02:01 +0100 Subject: [PATCH 1/9] Prevent unnecessary m.direct updates Signed-off-by: Michael Weimann --- src/Rooms.ts | 21 ++++++- test/Rooms-test.ts | 151 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 test/Rooms-test.ts diff --git a/src/Rooms.ts b/src/Rooms.ts index b3c1a553284..6ab8c60d680 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -57,18 +57,33 @@ export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise /** * Marks or unmarks the given room as being as a DM room. * @param {string} roomId The ID of the room to modify - * @param {string} userId The user ID of the desired DM + * @param {string | null} userId The user ID of the desired DM room target user or null to un-mark this room as a DM room * @returns {object} A promise */ -export async function setDMRoom(roomId: string, userId: string): Promise { +export async function setDMRoom(roomId: string, userId: string | null): Promise { if (MatrixClientPeg.get().isGuest()) return; const mDirectEvent = MatrixClientPeg.get().getAccountData(EventType.Direct); + const currentContent = mDirectEvent?.getContent() || {}; + + // already marked as DM + if (userId && currentContent[userId]?.includes?.(roomId)) return; + + if (userId === null) { + const roomInDMs = Object.values(currentContent).find((roomIds: any) => { + if (!Array.isArray(roomIds)) return false; + return roomIds.includes(roomId); + }); + + // skip remove unknown room + if (!roomInDMs) return; + } + let dmRoomMap = {}; - if (mDirectEvent !== undefined) dmRoomMap = { ...mDirectEvent.getContent() }; // copy as we will mutate + if (mDirectEvent !== undefined) dmRoomMap = { ...currentContent }; // copy as we will mutate // remove it from the lists of any others users // (it can only be a DM room for one person) diff --git a/test/Rooms-test.ts b/test/Rooms-test.ts new file mode 100644 index 00000000000..e37bab71322 --- /dev/null +++ b/test/Rooms-test.ts @@ -0,0 +1,151 @@ +/* +Copyright 2022 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 { mocked } from "jest-mock"; +import { EventType, MatrixClient, MatrixEvent } from "matrix-js-sdk/src/matrix"; + +import { setDMRoom } from "../src/Rooms"; +import { mkEvent, stubClient } from "./test-utils"; + +describe("setDMRoom", () => { + const userId1 = "@user1:example.com"; + const userId2 = "@user2:example.com"; + const userId3 = "@user3:example.com"; + const roomId1 = "!room1:example.com"; + const roomId2 = "!room2:example.com"; + const roomId3 = "!room3:example.com"; + const roomId4 = "!room4:example.com"; + let client: MatrixClient; + + beforeEach(() => { + client = mocked(stubClient()); + client.getAccountData = jest.fn().mockImplementation((eventType: string): MatrixEvent | undefined => { + if (eventType === EventType.Direct) { + return mkEvent({ + event: true, + content: { + [userId1]: [roomId1, roomId2], + [userId2]: [roomId3], + }, + type: EventType.Direct, + user: client.getSafeUserId(), + }); + } + + return undefined; + }); + }); + + describe("when logged in as a guest and marking a room as DM", () => { + beforeEach(() => { + mocked(client.isGuest).mockReturnValue(true); + setDMRoom(roomId1, userId1); + }); + + it("should not update the account data", () => { + expect(client.setAccountData).not.toHaveBeenCalled(); + }); + }); + + describe("when adding a new room to an existing DM relation", () => { + beforeEach(() => { + setDMRoom(roomId4, userId1); + }); + + it("should update the account data accordingly", () => { + expect(client.setAccountData).toHaveBeenCalledWith(EventType.Direct, { + [userId1]: [roomId1, roomId2, roomId4], + [userId2]: [roomId3], + }); + }); + }); + + describe("when adding a new DM room", () => { + beforeEach(() => { + setDMRoom(roomId4, userId3); + }); + + it("should update the account data accordingly", () => { + expect(client.setAccountData).toHaveBeenCalledWith(EventType.Direct, { + [userId1]: [roomId1, roomId2], + [userId2]: [roomId3], + [userId3]: [roomId4], + }); + }); + }); + + describe("when trying to add a DM, that already exists", () => { + beforeEach(() => { + setDMRoom(roomId1, userId1); + }); + + it("should not update the account data", () => { + expect(client.setAccountData).not.toHaveBeenCalled(); + }); + }); + + describe("when removing an existing DM", () => { + beforeEach(() => { + setDMRoom(roomId1, null); + }); + + it("should update the account data accordingly", () => { + expect(client.setAccountData).toHaveBeenCalledWith(EventType.Direct, { + [userId1]: [roomId2], + [userId2]: [roomId3], + }); + }); + }); + + describe("when removing an unknown room", () => { + beforeEach(() => { + setDMRoom(roomId4, null); + }); + + it("should not update the account data", () => { + expect(client.setAccountData).not.toHaveBeenCalled(); + }); + }); + + describe("when the direct event is undefined", () => { + beforeEach(() => { + mocked(client.getAccountData).mockReturnValue(undefined); + setDMRoom(roomId1, userId1); + }); + + it("should update the account data accordingly", () => { + expect(client.setAccountData).toHaveBeenCalledWith(EventType.Direct, { + [userId1]: [roomId1], + }); + }); + }); + + describe("when the current content is undefined", () => { + beforeEach(() => { + // @ts-ignore + mocked(client.getAccountData).mockReturnValue({ + getContent: jest.fn(), + }); + setDMRoom(roomId1, userId1); + }); + + it("should update the account data accordingly", () => { + expect(client.setAccountData).toHaveBeenCalledWith(EventType.Direct, { + [userId1]: [roomId1], + }); + }); + }); +}); From 035b515170dffbc2cd47c49433aa60e351c50c5a Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Tue, 20 Dec 2022 16:03:39 +0100 Subject: [PATCH 2/9] Replace object with Map --- src/Rooms.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Rooms.ts b/src/Rooms.ts index 6ab8c60d680..d7f9cc3c9e3 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -81,14 +81,14 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< if (!roomInDMs) return; } - let dmRoomMap = {}; + let dmRoomMap: Map = new Map(); - if (mDirectEvent !== undefined) dmRoomMap = { ...currentContent }; // copy as we will mutate + if (mDirectEvent !== undefined) dmRoomMap = new Map(Object.entries(currentContent)); // copy as we will mutate // remove it from the lists of any others users // (it can only be a DM room for one person) - for (const thisUserId of Object.keys(dmRoomMap)) { - const roomList = dmRoomMap[thisUserId]; + for (const thisUserId of dmRoomMap.keys()) { + const roomList = dmRoomMap.get(thisUserId) || []; if (thisUserId != userId) { const indexOfRoom = roomList.indexOf(roomId); @@ -100,14 +100,14 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< // now add it, if it's not already there if (userId) { - const roomList = dmRoomMap[userId] || []; + const roomList = dmRoomMap.get(userId) || []; if (roomList.indexOf(roomId) == -1) { roomList.push(roomId); } - dmRoomMap[userId] = roomList; + dmRoomMap.set(userId, roomList); } - await MatrixClientPeg.get().setAccountData(EventType.Direct, dmRoomMap); + await MatrixClientPeg.get().setAccountData(EventType.Direct, Object.fromEntries(dmRoomMap)); } /** From 392f0e420c2939f9644fef626b00aa6379e01f9b Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 09:12:49 +0100 Subject: [PATCH 3/9] Clean up comment; simplify code --- src/Rooms.ts | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Rooms.ts b/src/Rooms.ts index d7f9cc3c9e3..a0f32af9719 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -57,9 +57,8 @@ export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise /** * Marks or unmarks the given room as being as a DM room. * @param {string} roomId The ID of the room to modify - * @param {string | null} userId The user ID of the desired DM - room target user or null to un-mark - this room as a DM room + * @param {string | null} userId The user ID of the desired DM room target user or + * null to un-mark this room as a DM room * @returns {object} A promise */ export async function setDMRoom(roomId: string, userId: string | null): Promise { @@ -71,19 +70,8 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< // already marked as DM if (userId && currentContent[userId]?.includes?.(roomId)) return; - if (userId === null) { - const roomInDMs = Object.values(currentContent).find((roomIds: any) => { - if (!Array.isArray(roomIds)) return false; - return roomIds.includes(roomId); - }); - - // skip remove unknown room - if (!roomInDMs) return; - } - - let dmRoomMap: Map = new Map(); - - if (mDirectEvent !== undefined) dmRoomMap = new Map(Object.entries(currentContent)); // copy as we will mutate + const dmRoomMap = new Map(Object.entries(currentContent)); + let removed = false; // remove it from the lists of any others users // (it can only be a DM room for one person) @@ -94,10 +82,14 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< const indexOfRoom = roomList.indexOf(roomId); if (indexOfRoom > -1) { roomList.splice(indexOfRoom, 1); + removed = true; } } } + // already not marked as DM + if (userId === null && !removed) return; + // now add it, if it's not already there if (userId) { const roomList = dmRoomMap.get(userId) || []; From 20d9eb3924c5ebc63f03cb61b172035725e3474d Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Wed, 21 Dec 2022 12:22:17 +0100 Subject: [PATCH 4/9] Fix rte flaky test (#9811) --- .../rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx index c0849145bf4..b442640ce63 100644 --- a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx @@ -64,12 +64,15 @@ describe("EditWysiwygComposer", () => { ); }; + beforeAll(() => { + // Load the dynamic import + customRender(false).unmount(); + }); + it("Should not render the component when not ready", async () => { // When const { rerender } = customRender(false); - await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"), { - timeout: 2000, - }); + await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true")); rerender( From be1e5753677bdf84b3657994dc5ad20d250038bd Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 14:06:26 +0100 Subject: [PATCH 5/9] Snap in PiP widget when content changed (#9797) --- .../views/voip/PictureInPictureDragger.tsx | 4 ++ .../voip/PictureInPictureDragger-test.tsx | 69 +++++++++++++++++++ .../PictureInPictureDragger-test.tsx.snap | 39 +++++++++++ 3 files changed, 112 insertions(+) create mode 100644 test/components/views/voip/PictureInPictureDragger-test.tsx create mode 100644 test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap diff --git a/src/components/views/voip/PictureInPictureDragger.tsx b/src/components/views/voip/PictureInPictureDragger.tsx index aa47a4c7f9c..58a7a564937 100644 --- a/src/components/views/voip/PictureInPictureDragger.tsx +++ b/src/components/views/voip/PictureInPictureDragger.tsx @@ -85,6 +85,10 @@ export default class PictureInPictureDragger extends React.Component { UIStore.instance.off(UI_EVENTS.Resize, this.onResize); } + public componentDidUpdate(prevProps: Readonly): void { + if (prevProps.children !== this.props.children) this.snap(true); + } + private animationCallback = () => { if ( !this.moving && diff --git a/test/components/views/voip/PictureInPictureDragger-test.tsx b/test/components/views/voip/PictureInPictureDragger-test.tsx new file mode 100644 index 00000000000..138f0257eb4 --- /dev/null +++ b/test/components/views/voip/PictureInPictureDragger-test.tsx @@ -0,0 +1,69 @@ +/* +Copyright 2022 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 { render, RenderResult } from "@testing-library/react"; + +import PictureInPictureDragger, { + CreatePipChildren, +} from "../../../../src/components/views/voip/PictureInPictureDragger"; + +describe("PictureInPictureDragger", () => { + let renderResult: RenderResult; + + const mkContent1: CreatePipChildren = () => { + return
content 1
; + }; + + const mkContent2: CreatePipChildren = () => { + return ( +
+ content 2
+ content 2.2 +
+ ); + }; + + describe("when rendering the dragger with PiP content 1", () => { + beforeEach(() => { + renderResult = render({mkContent1}); + }); + + it("should render the PiP content", () => { + expect(renderResult.container).toMatchSnapshot("pip-content-1"); + }); + + describe("and rerendering PiP content 1", () => { + beforeEach(() => { + renderResult.rerender({mkContent1}); + }); + + it("should not change the PiP content", () => { + expect(renderResult.container).toMatchSnapshot("pip-content-1"); + }); + }); + + describe("and rendering PiP content 2", () => { + beforeEach(() => { + renderResult.rerender({mkContent2}); + }); + + it("should update the PiP content", () => { + expect(renderResult.container).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap b/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap new file mode 100644 index 00000000000..7996519485c --- /dev/null +++ b/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 and rendering PiP content 2 should update the PiP content 1`] = ` +
+ +
+`; + +exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 and rerendering PiP content 1 should not change the PiP content: pip-content-1 1`] = ` +
+ +
+`; + +exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 should render the PiP content: pip-content-1 1`] = ` +
+ +
+`; From 16fb043e08f5d771d4706bc0aa778fd8564c2fa8 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 16:04:02 +0100 Subject: [PATCH 6/9] Check modified at the end of setDMRoom --- src/Rooms.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Rooms.ts b/src/Rooms.ts index a0f32af9719..2c18a372d78 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -67,11 +67,8 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< const mDirectEvent = MatrixClientPeg.get().getAccountData(EventType.Direct); const currentContent = mDirectEvent?.getContent() || {}; - // already marked as DM - if (userId && currentContent[userId]?.includes?.(roomId)) return; - const dmRoomMap = new Map(Object.entries(currentContent)); - let removed = false; + let modified = false; // remove it from the lists of any others users // (it can only be a DM room for one person) @@ -82,23 +79,24 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< const indexOfRoom = roomList.indexOf(roomId); if (indexOfRoom > -1) { roomList.splice(indexOfRoom, 1); - removed = true; + modified = true; } } } - // already not marked as DM - if (userId === null && !removed) return; - // now add it, if it's not already there if (userId) { const roomList = dmRoomMap.get(userId) || []; if (roomList.indexOf(roomId) == -1) { roomList.push(roomId); + modified = true; } dmRoomMap.set(userId, roomList); } + // prevent unnecessary changes + if (!modified) return; + await MatrixClientPeg.get().setAccountData(EventType.Direct, Object.fromEntries(dmRoomMap)); } From 3b4f64cd1600b8c1b0f8c45ebd22a44b5101f6af Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 16:11:20 +0100 Subject: [PATCH 7/9] Revert "Snap in PiP widget when content changed (#9797)" This reverts commit be1e5753677bdf84b3657994dc5ad20d250038bd. --- .../views/voip/PictureInPictureDragger.tsx | 4 -- .../voip/PictureInPictureDragger-test.tsx | 69 ------------------- .../PictureInPictureDragger-test.tsx.snap | 39 ----------- 3 files changed, 112 deletions(-) delete mode 100644 test/components/views/voip/PictureInPictureDragger-test.tsx delete mode 100644 test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap diff --git a/src/components/views/voip/PictureInPictureDragger.tsx b/src/components/views/voip/PictureInPictureDragger.tsx index 58a7a564937..aa47a4c7f9c 100644 --- a/src/components/views/voip/PictureInPictureDragger.tsx +++ b/src/components/views/voip/PictureInPictureDragger.tsx @@ -85,10 +85,6 @@ export default class PictureInPictureDragger extends React.Component { UIStore.instance.off(UI_EVENTS.Resize, this.onResize); } - public componentDidUpdate(prevProps: Readonly): void { - if (prevProps.children !== this.props.children) this.snap(true); - } - private animationCallback = () => { if ( !this.moving && diff --git a/test/components/views/voip/PictureInPictureDragger-test.tsx b/test/components/views/voip/PictureInPictureDragger-test.tsx deleted file mode 100644 index 138f0257eb4..00000000000 --- a/test/components/views/voip/PictureInPictureDragger-test.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2022 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 { render, RenderResult } from "@testing-library/react"; - -import PictureInPictureDragger, { - CreatePipChildren, -} from "../../../../src/components/views/voip/PictureInPictureDragger"; - -describe("PictureInPictureDragger", () => { - let renderResult: RenderResult; - - const mkContent1: CreatePipChildren = () => { - return
content 1
; - }; - - const mkContent2: CreatePipChildren = () => { - return ( -
- content 2
- content 2.2 -
- ); - }; - - describe("when rendering the dragger with PiP content 1", () => { - beforeEach(() => { - renderResult = render({mkContent1}); - }); - - it("should render the PiP content", () => { - expect(renderResult.container).toMatchSnapshot("pip-content-1"); - }); - - describe("and rerendering PiP content 1", () => { - beforeEach(() => { - renderResult.rerender({mkContent1}); - }); - - it("should not change the PiP content", () => { - expect(renderResult.container).toMatchSnapshot("pip-content-1"); - }); - }); - - describe("and rendering PiP content 2", () => { - beforeEach(() => { - renderResult.rerender({mkContent2}); - }); - - it("should update the PiP content", () => { - expect(renderResult.container).toMatchSnapshot(); - }); - }); - }); -}); diff --git a/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap b/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap deleted file mode 100644 index 7996519485c..00000000000 --- a/test/components/views/voip/__snapshots__/PictureInPictureDragger-test.tsx.snap +++ /dev/null @@ -1,39 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 and rendering PiP content 2 should update the PiP content 1`] = ` -
- -
-`; - -exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 and rerendering PiP content 1 should not change the PiP content: pip-content-1 1`] = ` -
- -
-`; - -exports[`PictureInPictureDragger when rendering the dragger with PiP content 1 should render the PiP content: pip-content-1 1`] = ` -
- -
-`; From a8a70f87dd9d720348d05e8b4d0510a491ae4a92 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 16:11:36 +0100 Subject: [PATCH 8/9] Revert "Fix rte flaky test (#9811)" This reverts commit 20d9eb3924c5ebc63f03cb61b172035725e3474d. --- .../rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx index b442640ce63..c0849145bf4 100644 --- a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx @@ -64,15 +64,12 @@ describe("EditWysiwygComposer", () => { ); }; - beforeAll(() => { - // Load the dynamic import - customRender(false).unmount(); - }); - it("Should not render the component when not ready", async () => { // When const { rerender } = customRender(false); - await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true")); + await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"), { + timeout: 2000, + }); rerender( From d5d6b45f2525f3da5096b29541d992711fca28d5 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Wed, 21 Dec 2022 16:56:24 +0100 Subject: [PATCH 9/9] Update src/Rooms.ts Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --- src/Rooms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Rooms.ts b/src/Rooms.ts index 2c18a372d78..8d10f121afc 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -94,7 +94,7 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise< dmRoomMap.set(userId, roomList); } - // prevent unnecessary changes + // prevent unnecessary calls to setAccountData if (!modified) return; await MatrixClientPeg.get().setAccountData(EventType.Direct, Object.fromEntries(dmRoomMap));