Skip to content

Commit 59cd518

Browse files
langleydt3chguygithub-merge-queue[bot]github-merge-queuerenovate[bot]
authored
Add reactions to html export (#28210)
* Absorb the matrix-react-sdk repository (#28192) Co-authored-by: github-merge-queue <[email protected]> Co-authored-by: github-merge-queue <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Florian Duros <[email protected]> Co-authored-by: Kim Brose <[email protected]> Co-authored-by: Florian Duros <[email protected]> Co-authored-by: R Midhun Suresh <[email protected]> Co-authored-by: dbkr <[email protected]> Co-authored-by: ElementRobot <[email protected]> Co-authored-by: dbkr <[email protected]> Co-authored-by: David Baker <[email protected]> Co-authored-by: Michael Telatynski <[email protected]> Co-authored-by: Richard van der Hoff <[email protected]> Co-authored-by: David Langley <[email protected]> Co-authored-by: Michael Weimann <[email protected]> Co-authored-by: Timshel <[email protected]> Co-authored-by: Sahil Silare <[email protected]> Co-authored-by: Will Hunt <[email protected]> Co-authored-by: Hubert Chathi <[email protected]> Co-authored-by: Andrew Ferrazzutti <[email protected]> Co-authored-by: Robin <[email protected]> Co-authored-by: Tulir Asokan <[email protected]> * Update dependency @sentry/browser to v8.33.0 [SECURITY] (#28194) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update babel monorepo (#28196) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency @types/react to v17.0.83 (#28138) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency @matrix-org/spec to v1.12.0 (#28200) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency @formatjs/intl-segmenter to v11.5.9 (#28197) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Remove references to `MatrixClient.crypto` (#28204) * Remove `VerificationExplorer` * Remove `remakeolm` slash command * Remove call to `crypto.cancelAndResendAllOutgoingKeyRequests` * Remove crypto mock in `LoginWithQR-test.tsx` * Remove `StopGadWidgetDriver.sendToDevice` * Remove remaining mock * Update dependency typescript to v5.6.3 (#28198) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency eslint-plugin-unicorn to v56 (#28202) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update dependency stylelint to v16.10.0 (#28201) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * Update browserslist (#28199) * Update browserslist * Update tests Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Michael Telatynski <[email protected]> * Add reactions to html export and add test * Add reaction to snapshot test * Update snapshot output * Remove logging * Add reaction to html export screenshot test. * lint * Update reference screenshot. --------- Signed-off-by: Michael Telatynski <[email protected]> Co-authored-by: Michael Telatynski <[email protected]> Co-authored-by: github-merge-queue <[email protected]> Co-authored-by: github-merge-queue <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Florian Duros <[email protected]> Co-authored-by: Kim Brose <[email protected]> Co-authored-by: Florian Duros <[email protected]> Co-authored-by: R Midhun Suresh <[email protected]> Co-authored-by: dbkr <[email protected]> Co-authored-by: ElementRobot <[email protected]> Co-authored-by: dbkr <[email protected]> Co-authored-by: Richard van der Hoff <[email protected]> Co-authored-by: Michael Weimann <[email protected]> Co-authored-by: Timshel <[email protected]> Co-authored-by: Sahil Silare <[email protected]> Co-authored-by: Will Hunt <[email protected]> Co-authored-by: Hubert Chathi <[email protected]> Co-authored-by: Andrew Ferrazzutti <[email protected]> Co-authored-by: Robin <[email protected]> Co-authored-by: Tulir Asokan <[email protected]>
1 parent 06d1239 commit 59cd518

File tree

8 files changed

+97
-14
lines changed

8 files changed

+97
-14
lines changed

playwright/e2e/chat-export/html-export.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,10 @@ test.describe("HTML Export", () => {
9696

9797
// Send a bunch of messages to populate the room
9898
for (let i = 1; i < 10; i++) {
99-
await app.client.sendMessage(room.roomId, { body: `Testing ${i}`, msgtype: "m.text" });
99+
const respone = await app.client.sendMessage(room.roomId, { body: `Testing ${i}`, msgtype: "m.text" });
100+
if (i == 1) {
101+
await app.client.reactToMessage(room.roomId, null, respone.event_id, "🙃");
102+
}
100103
}
101104

102105
// Wait for all the messages to be displayed

playwright/e2e/read-receipts/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,14 +222,7 @@ export class MessageBuilder {
222222
threadId: !ev.isThreadRoot ? ev.threadRootId : undefined,
223223
}));
224224
const roomId = await room.evaluate((room) => room.roomId);
225-
226-
await bot.sendEvent(roomId, threadId ?? null, "m.reaction", {
227-
"m.relates_to": {
228-
rel_type: "m.annotation",
229-
event_id: id,
230-
key: reaction,
231-
},
232-
});
225+
await bot.reactToMessage(roomId, threadId, id, reaction);
233226
}
234227
})(this);
235228
}

playwright/pages/client.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,29 @@ export class Client {
143143
);
144144
}
145145

146+
/**
147+
* Send a reaction to to a message
148+
* @param roomId ID of the room to send the reaction into
149+
* @param threadId ID of the thread to send into or null for main timeline
150+
* @param eventId Event ID of the message you are reacting to
151+
* @param reaction The reaction text to send
152+
* @returns
153+
*/
154+
public async reactToMessage(
155+
roomId: string,
156+
threadId: string | null,
157+
eventId: string,
158+
reaction: string,
159+
): Promise<ISendEventResponse> {
160+
return this.sendEvent(roomId, threadId ?? null, "m.reaction", {
161+
"m.relates_to": {
162+
rel_type: "m.annotation",
163+
event_id: eventId,
164+
key: reaction,
165+
},
166+
});
167+
}
168+
146169
/**
147170
* Create a room with given options.
148171
* @param options the options to apply when creating the room
Loading

src/utils/exportUtils/Exporter.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
66
Please see LICENSE files in the repository root for full details.
77
*/
88

9-
import { Direction, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
10-
import { MediaEventContent } from "matrix-js-sdk/src/types";
9+
import { Direction, MatrixEvent, Relations, Room } from "matrix-js-sdk/src/matrix";
10+
import { EventType, MediaEventContent, RelationType } from "matrix-js-sdk/src/types";
1111
import { saveAs } from "file-saver";
1212
import { logger } from "matrix-js-sdk/src/logger";
1313
import sanitizeFilename from "sanitize-filename";
@@ -284,5 +284,13 @@ export default abstract class Exporter {
284284
return mxEv.getType() === attachmentTypes[0] || attachmentTypes.includes(mxEv.getContent().msgtype!);
285285
}
286286

287+
protected getRelationsForEvent = (
288+
eventId: string,
289+
relationType: RelationType | string,
290+
eventType: EventType | string,
291+
): Relations | undefined => {
292+
return this.room.getUnfilteredTimelineSet().relations.getChildEventsForEvent(eventId, relationType, eventType);
293+
};
294+
287295
public abstract export(): Promise<void>;
288296
}

src/utils/exportUtils/HtmlExport.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,10 @@ export default class HTMLExporter extends Exporter {
288288
permalinkCreator={this.permalinkCreator}
289289
lastSuccessful={false}
290290
isSelectedEvent={false}
291-
showReactions={false}
291+
showReactions={true}
292292
layout={Layout.Group}
293293
showReadReceipts={false}
294+
getRelationsForEvent={this.getRelationsForEvent}
294295
/>
295296
</TooltipProvider>
296297
</MatrixClientContext.Provider>

test/unit-tests/utils/exportUtils/HTMLExport-test.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,24 @@ Please see LICENSE files in the repository root for full details.
77
*/
88

99
import {
10+
EventTimeline,
11+
EventTimelineSet,
1012
EventType,
1113
IRoomEvent,
1214
MatrixClient,
1315
MatrixEvent,
1416
MsgType,
17+
Relations,
18+
RelationType,
1519
Room,
1620
RoomMember,
1721
RoomState,
1822
} from "matrix-js-sdk/src/matrix";
1923
import fetchMock from "fetch-mock-jest";
2024
import escapeHtml from "escape-html";
25+
import { RelationsContainer } from "matrix-js-sdk/src/models/relations-container";
2126

22-
import { filterConsole, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
27+
import { filterConsole, mkReaction, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
2328
import { ExportType, IExportOptions } from "../../../../src/utils/exportUtils/exportUtils";
2429
import SdkConfig from "../../../../src/SdkConfig";
2530
import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport";
@@ -123,6 +128,35 @@ describe("HTMLExport", () => {
123128
fetchMock.get(media.srcHttp!, body);
124129
}
125130

131+
function mockReactionForMessage(message: IRoomEvent): MatrixEvent {
132+
const firstMessage = new MatrixEvent(message);
133+
const reaction = mkReaction(firstMessage);
134+
135+
const relationsContainer = {
136+
getRelations: jest.fn(),
137+
getChildEventsForEvent: jest.fn(),
138+
} as unknown as RelationsContainer;
139+
const relations = new Relations(RelationType.Annotation, EventType.Reaction, client);
140+
relations.addEvent(reaction);
141+
relationsContainer.getChildEventsForEvent = jest
142+
.fn()
143+
.mockImplementation(
144+
(eventId: string, relationType: RelationType | string, eventType: EventType | string) => {
145+
if (eventId === firstMessage.getId()) {
146+
return relations;
147+
}
148+
},
149+
);
150+
151+
const timelineSet = {
152+
relations: relationsContainer,
153+
getLiveTimeline: () => timeline,
154+
} as unknown as EventTimelineSet;
155+
const timeline = new EventTimeline(timelineSet);
156+
room.getUnfilteredTimelineSet = jest.fn().mockReturnValue(timelineSet);
157+
return reaction;
158+
}
159+
126160
it("should throw when created with invalid config for LastNMessages", async () => {
127161
expect(
128162
() =>
@@ -167,6 +201,7 @@ describe("HTMLExport", () => {
167201
body: `Message #${i}`,
168202
},
169203
}));
204+
mockReactionForMessage(events[0]);
170205
mockMessages(...events);
171206

172207
const exporter = new HTMLExporter(
@@ -587,4 +622,24 @@ describe("HTMLExport", () => {
587622
expect(await file.text()).toContain("testing testing");
588623
expect(client.createMessagesRequest).not.toHaveBeenCalled();
589624
});
625+
626+
it("should include reactions", async () => {
627+
const reaction = mockReactionForMessage(EVENT_MESSAGE);
628+
mockMessages(EVENT_MESSAGE);
629+
const exporter = new HTMLExporter(
630+
room,
631+
ExportType.LastNMessages,
632+
{
633+
attachmentsIncluded: false,
634+
maxSize: 1_024 * 1_024,
635+
numberOfMessages: 40,
636+
},
637+
() => {},
638+
);
639+
640+
await exporter.export();
641+
642+
const file = getMessageFile(exporter);
643+
expect(await file.text()).toContain(reaction.getContent()["m.relates_to"]?.key);
644+
});
590645
});

test/unit-tests/utils/exportUtils/__snapshots__/HTMLExport-test.ts.snap

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)