diff --git a/src/utils/EventUtils.ts b/src/utils/EventUtils.ts index b3ba86a914b..2c6d149342a 100644 --- a/src/utils/EventUtils.ts +++ b/src/utils/EventUtils.ts @@ -70,7 +70,9 @@ export function canEditContent(matrixClient: MatrixClient, mxEvent: MatrixEvent) if ( !isCancellable || - mxEvent.status === EventStatus.CANCELLED || + // Editing local echos is not supported(results in send a message that references the local ID). + // We need to ensure the event is not local, and therefore has no send status. + mxEvent.status !== null || mxEvent.isRedacted() || mxEvent.isRelation(RelationType.Replace) || mxEvent.getSender() !== matrixClient.getUserId() diff --git a/src/utils/PinningUtils.ts b/src/utils/PinningUtils.ts index 9575e3b7675..19a1a9a7265 100644 --- a/src/utils/PinningUtils.ts +++ b/src/utils/PinningUtils.ts @@ -81,6 +81,9 @@ export default class PinningUtils { const room = matrixClient.getRoom(mxEvent.getRoomId()); if (!room) return false; + // Should have a non-local event id + if (mxEvent.status !== null) return false; + return PinningUtils.userHasPinOrUnpinPermission(matrixClient, room) && PinningUtils.isPinnable(mxEvent); } @@ -94,6 +97,9 @@ export default class PinningUtils { const room = matrixClient.getRoom(mxEvent.getRoomId()); if (!room) return false; + // Should have a non-local event id + if (mxEvent.status !== null) return false; + return PinningUtils.userHasPinOrUnpinPermission(matrixClient, room) && PinningUtils.isUnpinnable(mxEvent); } @@ -123,6 +129,9 @@ export default class PinningUtils { const eventId = mxEvent.getId(); if (!eventId) return; + // Should have a non-local event id + if (mxEvent.status !== null) return; + // Get the current pinned events of the room const pinnedIds: Array = room diff --git a/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx b/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx index 4c735bdd8ce..4b26b361ad7 100644 --- a/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx +++ b/test/unit-tests/components/views/context_menus/MessageContextMenu-test.tsx @@ -748,7 +748,8 @@ function createMenu( // @ts-ignore illegally set private prop room.currentState.beacons = beacons; - mxEvent.setStatus(EventStatus.SENT); + // The base case is that we have received the remote echo and have an eventId. No sending status. + mxEvent.setStatus(null); client.getUserId = jest.fn().mockReturnValue("@user:example.com"); client.getRoom = jest.fn().mockReturnValue(room); diff --git a/test/unit-tests/components/views/messages/MessageActionBar-test.tsx b/test/unit-tests/components/views/messages/MessageActionBar-test.tsx index 10592635338..f8baf7505ec 100644 --- a/test/unit-tests/components/views/messages/MessageActionBar-test.tsx +++ b/test/unit-tests/components/views/messages/MessageActionBar-test.tsx @@ -125,7 +125,8 @@ describe("", () => { beforeEach(() => { jest.clearAllMocks(); - alicesMessageEvent.setStatus(EventStatus.SENT); + // The base case is that we have received the remote echo and have an eventId. No sending status. + alicesMessageEvent.setStatus(null); jest.spyOn(SettingsStore, "getValue").mockReturnValue(false); jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined); }); @@ -376,6 +377,25 @@ describe("", () => { expect(queryByLabelText("Delete")).toBeTruthy(); }); + it("only shows retry and delete buttons when event could not be sent", () => { + // Enable pin and other features + jest.spyOn(SettingsStore, "getValue").mockReturnValue(true); + + alicesMessageEvent.setStatus(EventStatus.NOT_SENT); + const { queryByLabelText } = getComponent({ mxEvent: alicesMessageEvent }); + + // Should show retry and cancel buttons + expect(queryByLabelText("Retry")).toBeTruthy(); + expect(queryByLabelText("Delete")).toBeTruthy(); + + // Should NOT show edit, pin, react, reply buttons + expect(queryByLabelText("Edit")).toBeFalsy(); + expect(queryByLabelText("Pin")).toBeFalsy(); + expect(queryByLabelText("React")).toBeFalsy(); + expect(queryByLabelText("Reply")).toBeFalsy(); + expect(queryByLabelText("Reply in thread")).toBeFalsy(); + }); + it.todo("unsends event on cancel click"); it.todo("retrys event on retry click"); });