Show the local echo in previews (#12451)

* show the local echo in previews

* a bit more coverage
This commit is contained in:
David Langley 2024-04-24 10:22:07 +01:00 committed by GitHub
parent 158e1110b1
commit 644bf78e2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 114 additions and 4 deletions

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import { Room, RelationType, MatrixEvent, Thread, M_POLL_START } from "matrix-js-sdk/src/matrix"; import { Room, RelationType, MatrixEvent, Thread, M_POLL_START, RoomEvent } from "matrix-js-sdk/src/matrix";
import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
import { ActionPayload } from "../../dispatcher/payloads"; import { ActionPayload } from "../../dispatcher/payloads";
@ -186,7 +186,7 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
} }
private async generatePreview(room: Room, tagId?: TagID): Promise<void> { private async generatePreview(room: Room, tagId?: TagID): Promise<void> {
const events = [...room.getLiveTimeline().getEvents()]; const events = [...room.getLiveTimeline().getEvents(), ...room.getPendingEvents()];
// add last reply from each thread // add last reply from each thread
room.getThreads().forEach((thread: Thread): void => { room.getThreads().forEach((thread: Thread): void => {
@ -279,4 +279,19 @@ export class MessagePreviewStore extends AsyncStoreWithClient<IState> {
await this.generatePreview(room, TAG_ANY); await this.generatePreview(room, TAG_ANY);
} }
} }
protected async onReady(): Promise<void> {
if (!this.matrixClient) return;
this.matrixClient.on(RoomEvent.LocalEchoUpdated, this.onLocalEchoUpdated);
}
protected async onNotReady(): Promise<void> {
if (!this.matrixClient) return;
this.matrixClient.off(RoomEvent.LocalEchoUpdated, this.onLocalEchoUpdated);
}
protected onLocalEchoUpdated = async (ev: MatrixEvent, room: Room): Promise<void> => {
if (!this.previews.has(room.roomId)) return;
await this.generatePreview(room, TAG_ANY);
};
} }

View file

@ -15,7 +15,16 @@ limitations under the License.
*/ */
import { Mocked, mocked } from "jest-mock"; import { Mocked, mocked } from "jest-mock";
import { EventTimeline, EventType, MatrixClient, MatrixEvent, RelationType, Room } from "matrix-js-sdk/src/matrix"; import {
EventStatus,
EventTimeline,
EventType,
MatrixClient,
MatrixEvent,
PendingEventOrdering,
RelationType,
Room,
} from "matrix-js-sdk/src/matrix";
import { MessagePreviewStore } from "../../../src/stores/room-list/MessagePreviewStore"; import { MessagePreviewStore } from "../../../src/stores/room-list/MessagePreviewStore";
import { mkEvent, mkMessage, mkReaction, setupAsyncStoreWithClient, stubClient } from "../../test-utils"; import { mkEvent, mkMessage, mkReaction, setupAsyncStoreWithClient, stubClient } from "../../test-utils";
@ -25,6 +34,7 @@ import { mkThread } from "../../test-utils/threads";
describe("MessagePreviewStore", () => { describe("MessagePreviewStore", () => {
let client: Mocked<MatrixClient>; let client: Mocked<MatrixClient>;
let room: Room; let room: Room;
let nonRenderedRoom: Room;
let store: MessagePreviewStore; let store: MessagePreviewStore;
async function addEvent( async function addEvent(
@ -46,9 +56,35 @@ describe("MessagePreviewStore", () => {
} }
} }
async function addPendingEvent(
store: MessagePreviewStore,
room: Room,
event: MatrixEvent,
fireAction = true,
): Promise<void> {
room.addPendingEvent(event, "txid");
if (fireAction) {
// @ts-ignore private access
await store.onLocalEchoUpdated(event, room);
}
}
async function updatePendingEvent(event: MatrixEvent, eventStatus: EventStatus, fireAction = true): Promise<void> {
room.updatePendingEvent(event, eventStatus);
if (fireAction) {
// @ts-ignore private access
await store.onLocalEchoUpdated(event, room);
}
}
beforeEach(async () => { beforeEach(async () => {
client = mocked(stubClient()); client = mocked(stubClient());
room = new Room("!roomId:server", client, client.getSafeUserId()); room = new Room("!roomId:server", client, client.getSafeUserId(), {
pendingEventOrdering: PendingEventOrdering.Detached,
});
nonRenderedRoom = new Room("!roomId2:server", client, client.getSafeUserId(), {
pendingEventOrdering: PendingEventOrdering.Detached,
});
mocked(client.getRoom).mockReturnValue(room); mocked(client.getRoom).mockReturnValue(room);
store = MessagePreviewStore.testInstance(); store = MessagePreviewStore.testInstance();
@ -286,4 +322,63 @@ describe("MessagePreviewStore", () => {
expect(preview?.isThreadReply).toBe(false); expect(preview?.isThreadReply).toBe(false);
expect(preview?.text).toContain("You reacted 🙃 to root event message"); expect(preview?.text).toContain("You reacted 🙃 to root event message");
}); });
it("should handle local echos correctly", async () => {
const firstMessage = mkMessage({
user: "@sender:server",
event: true,
room: room.roomId,
msg: "First message",
});
await addEvent(store, room, firstMessage);
expect((await store.getPreviewForRoom(room, DefaultTagID.Untagged))?.text).toMatchInlineSnapshot(
`"@sender:server: First message"`,
);
const secondMessage = mkMessage({
user: "@sender:server",
event: true,
room: room.roomId,
msg: "Second message",
});
secondMessage.status = EventStatus.NOT_SENT;
await addPendingEvent(store, room, secondMessage);
expect((await store.getPreviewForRoom(room, DefaultTagID.Untagged))?.text).toMatchInlineSnapshot(
`"@sender:server: Second message"`,
);
await updatePendingEvent(secondMessage, EventStatus.CANCELLED);
expect((await store.getPreviewForRoom(room, DefaultTagID.Untagged))?.text).toMatchInlineSnapshot(
`"@sender:server: First message"`,
);
});
it("should not generate previews for rooms not rendered", async () => {
const firstMessage = mkMessage({
user: "@sender:server",
event: true,
room: nonRenderedRoom.roomId,
msg: "First message",
});
await addEvent(store, room, firstMessage);
const secondMessage = mkMessage({
user: "@sender:server",
event: true,
room: nonRenderedRoom.roomId,
msg: "Second message",
});
secondMessage.status = EventStatus.NOT_SENT;
await addPendingEvent(store, room, secondMessage);
// @ts-ignore private access
expect(store.previews.has(nonRenderedRoom.roomId)).toBeFalsy();
});
}); });