From 368dea7e68e5e3398a7433ccfcc6434d3b477161 Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Fri, 3 Mar 2023 09:15:10 +0100 Subject: [PATCH 1/3] Fix casing --- src/components/views/right_panel/UserInfo.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 41cd87e1079..c0546a2703e 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -121,13 +121,13 @@ export const getE2EStatus = (cli: MatrixClient, userId: string, devices: IDevice return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified; }; -async function openDMForUser(matrixClient: MatrixClient, user: RoomMember): Promise { - const startDMUser = new DirectoryMember({ +async function openDmForUser(matrixClient: MatrixClient, user: RoomMember): Promise { + const startDmUser = new DirectoryMember({ user_id: user.userId, display_name: user.rawDisplayName, avatar_url: user.getMxcAvatarUrl(), }); - startDmOnFirstMessage(matrixClient, [startDMUser]); + startDmOnFirstMessage(matrixClient, [startDmUser]); } type SetUpdating = (updating: boolean) => void; @@ -320,7 +320,7 @@ const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => { onClick={async () => { if (busy) return; setBusy(true); - await openDMForUser(cli, member); + await openDmForUser(cli, member); setBusy(false); }} className="mx_UserInfo_field" From bc93548cbd347dc83be7be16cd8591b7314f707c Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Fri, 3 Mar 2023 10:21:10 +0100 Subject: [PATCH 2/3] Fix start DM via right panel --- src/components/views/right_panel/UserInfo.tsx | 26 +++++++++++------ .../views/right_panel/UserInfo-test.tsx | 28 +++++++++++++++++-- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index c0546a2703e..88f5c7c0063 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -121,11 +121,15 @@ export const getE2EStatus = (cli: MatrixClient, userId: string, devices: IDevice return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified; }; -async function openDmForUser(matrixClient: MatrixClient, user: RoomMember): Promise { +/** + * Converts the member to a DirectoryMember and starts a DM with them. + */ +async function openDmForUser(matrixClient: MatrixClient, user: Member): Promise { + const avatarUrl = user instanceof User ? user.avatarUrl : user.getMxcAvatarUrl(); const startDmUser = new DirectoryMember({ user_id: user.userId, display_name: user.rawDisplayName, - avatar_url: user.getMxcAvatarUrl(), + avatar_url: avatarUrl, }); startDmOnFirstMessage(matrixClient, [startDmUser]); } @@ -310,7 +314,7 @@ function DevicesSection({ ); } -const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => { +const MessageButton = ({ member }: { member: Member }): JSX.Element => { const cli = useContext(MatrixClientContext); const [busy, setBusy] = useState(false); @@ -332,7 +336,7 @@ const MessageButton = ({ member }: { member: RoomMember }): JSX.Element => { }; export const UserOptionsSection: React.FC<{ - member: RoomMember; + member: Member; isIgnored: boolean; canInvite: boolean; isSpace?: boolean; @@ -360,8 +364,9 @@ export const UserOptionsSection: React.FC<{ }, [cli, member]); const ignore = useCallback(async () => { + const name = (member instanceof User ? member.displayName : member.name) || member.userId; const { finished } = Modal.createDialog(QuestionDialog, { - title: _t("Ignore %(user)s", { user: member.name }), + title: _t("Ignore %(user)s", { user: name }), description: (
{_t( @@ -394,7 +399,7 @@ export const UserOptionsSection: React.FC<{ ); - if (member.roomId && !isSpace) { + if (member instanceof RoomMember && member.roomId && !isSpace) { const onReadReceiptButton = function (): void { const room = cli.getRoom(member.roomId); dis.dispatch({ @@ -415,7 +420,7 @@ export const UserOptionsSection: React.FC<{ }); }; - const room = cli.getRoom(member.roomId); + const room = member instanceof RoomMember ? cli.getRoom(member.roomId) : undefined; if (room?.getEventReadUpTo(member.userId)) { readReceiptButton = ( @@ -431,7 +436,12 @@ export const UserOptionsSection: React.FC<{ ); } - if (canInvite && (member?.membership ?? "leave") === "leave" && shouldShowComponent(UIComponent.InviteUsers)) { + if ( + member instanceof RoomMember && + canInvite && + (member?.membership ?? "leave") === "leave" && + shouldShowComponent(UIComponent.InviteUsers) + ) { const roomId = member && member.roomId ? member.roomId : SdkContextClass.instance.roomViewStore.getRoomId(); const onInviteUserButton = async (ev: ButtonEvent): Promise => { try { diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 1f95c729501..4dfd6fef2b6 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -43,6 +43,12 @@ import MultiInviter from "../../../../src/utils/MultiInviter"; import * as mockVerification from "../../../../src/verification"; import Modal from "../../../../src/Modal"; import { E2EStatus } from "../../../../src/utils/ShieldUtils"; +import { DirectoryMember, startDmOnFirstMessage } from "../../../../src/utils/direct-messages"; + +jest.mock("../../../../src/utils/direct-messages", () => ({ + ...jest.requireActual("../../../../src/utils/direct-messages"), + startDmOnFirstMessage: jest.fn(), +})); jest.mock("../../../../src/dispatcher/dispatcher"); @@ -121,7 +127,7 @@ const mockClient = mocked({ setPowerLevel: jest.fn(), } as unknown as MatrixClient); -const defaultUserId = "@test:test"; +const defaultUserId = "@user:example.com"; const defaultUser = new User(defaultUserId); beforeEach(() => { @@ -554,7 +560,7 @@ describe("", () => { inviteSpy.mockRejectedValue({ this: "could be anything" }); // render the component and click the button - renderComponent({ canInvite: true, member: { ...member, roomId: null } }); + renderComponent({ canInvite: true, member: new RoomMember(null, defaultUserId) }); const inviteButton = screen.getByRole("button", { name: /invite/i }); expect(inviteButton).toBeInTheDocument(); await userEvent.click(inviteButton); @@ -612,6 +618,24 @@ describe("", () => { await userEvent.click(screen.getByRole("button", { name: "Unignore" })); expect(mockClient.setIgnoredUsers).toHaveBeenCalledWith([]); }); + + it.each([ + ["for a RoomMember", member, member.getMxcAvatarUrl()], + ["for a User", defaultUser, defaultUser.avatarUrl], + ])( + "clicking »message« %s should start a DM", + async (test: string, member: RoomMember | User, expectedAvatarUrl: string) => { + renderComponent({ member }); + await userEvent.click(screen.getByText("Message")); + expect(startDmOnFirstMessage).toHaveBeenCalledWith(mockClient, [ + new DirectoryMember({ + user_id: member.userId, + display_name: member.rawDisplayName, + avatar_url: expectedAvatarUrl, + }), + ]); + }, + ); }); describe("", () => { From 35ac4c78a58b29313c2e72ca092a7f6c1a6ef8df Mon Sep 17 00:00:00 2001 From: Michael Weimann Date: Fri, 3 Mar 2023 11:43:39 +0100 Subject: [PATCH 3/3] Fix type errors in tests --- .../views/right_panel/UserInfo-test.tsx | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/test/components/views/right_panel/UserInfo-test.tsx b/test/components/views/right_panel/UserInfo-test.tsx index 4dfd6fef2b6..fe943a88aae 100644 --- a/test/components/views/right_panel/UserInfo-test.tsx +++ b/test/components/views/right_panel/UserInfo-test.tsx @@ -556,23 +556,6 @@ describe("", () => { }); }); - it("calling .invite with a null roomId still calls .invite and shows default error message", async () => { - inviteSpy.mockRejectedValue({ this: "could be anything" }); - - // render the component and click the button - renderComponent({ canInvite: true, member: new RoomMember(null, defaultUserId) }); - const inviteButton = screen.getByRole("button", { name: /invite/i }); - expect(inviteButton).toBeInTheDocument(); - await userEvent.click(inviteButton); - - expect(inviteSpy).toHaveBeenCalledTimes(1); - - // check that the default test error message is displayed - await waitFor(() => { - expect(screen.getByText(/operation failed/i)).toBeInTheDocument(); - }); - }); - it("shows a modal before ignoring the user", async () => { const originalCreateDialog = Modal.createDialog; const modalSpy = (Modal.createDialog = jest.fn().mockReturnValue({ @@ -624,7 +607,7 @@ describe("", () => { ["for a User", defaultUser, defaultUser.avatarUrl], ])( "clicking »message« %s should start a DM", - async (test: string, member: RoomMember | User, expectedAvatarUrl: string) => { + async (test: string, member: RoomMember | User, expectedAvatarUrl: string | undefined) => { renderComponent({ member }); await userEvent.click(screen.getByText("Message")); expect(startDmOnFirstMessage).toHaveBeenCalledWith(mockClient, [