Skip to content

Commit

Permalink
Add reactions to html export (#28210)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
21 people authored Oct 18, 2024
1 parent 06d1239 commit 59cd518
Show file tree
Hide file tree
Showing 8 changed files with 97 additions and 14 deletions.
5 changes: 4 additions & 1 deletion playwright/e2e/chat-export/html-export.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ test.describe("HTML Export", () => {

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

// Wait for all the messages to be displayed
Expand Down
9 changes: 1 addition & 8 deletions playwright/e2e/read-receipts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,14 +222,7 @@ export class MessageBuilder {
threadId: !ev.isThreadRoot ? ev.threadRootId : undefined,
}));
const roomId = await room.evaluate((room) => room.roomId);

await bot.sendEvent(roomId, threadId ?? null, "m.reaction", {
"m.relates_to": {
rel_type: "m.annotation",
event_id: id,
key: reaction,
},
});
await bot.reactToMessage(roomId, threadId, id, reaction);
}
})(this);
}
Expand Down
23 changes: 23 additions & 0 deletions playwright/pages/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ export class Client {
);
}

/**
* Send a reaction to to a message
* @param roomId ID of the room to send the reaction into
* @param threadId ID of the thread to send into or null for main timeline
* @param eventId Event ID of the message you are reacting to
* @param reaction The reaction text to send
* @returns
*/
public async reactToMessage(
roomId: string,
threadId: string | null,
eventId: string,
reaction: string,
): Promise<ISendEventResponse> {
return this.sendEvent(roomId, threadId ?? null, "m.reaction", {
"m.relates_to": {
rel_type: "m.annotation",
event_id: eventId,
key: reaction,
},
});
}

/**
* Create a room with given options.
* @param options the options to apply when creating the room
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 10 additions & 2 deletions src/utils/exportUtils/Exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

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

protected getRelationsForEvent = (
eventId: string,
relationType: RelationType | string,
eventType: EventType | string,
): Relations | undefined => {
return this.room.getUnfilteredTimelineSet().relations.getChildEventsForEvent(eventId, relationType, eventType);
};

public abstract export(): Promise<void>;
}
3 changes: 2 additions & 1 deletion src/utils/exportUtils/HtmlExport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,9 +288,10 @@ export default class HTMLExporter extends Exporter {
permalinkCreator={this.permalinkCreator}
lastSuccessful={false}
isSelectedEvent={false}
showReactions={false}
showReactions={true}
layout={Layout.Group}
showReadReceipts={false}
getRelationsForEvent={this.getRelationsForEvent}
/>
</TooltipProvider>
</MatrixClientContext.Provider>
Expand Down
57 changes: 56 additions & 1 deletion test/unit-tests/utils/exportUtils/HTMLExport-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@ Please see LICENSE files in the repository root for full details.
*/

import {
EventTimeline,
EventTimelineSet,
EventType,
IRoomEvent,
MatrixClient,
MatrixEvent,
MsgType,
Relations,
RelationType,
Room,
RoomMember,
RoomState,
} from "matrix-js-sdk/src/matrix";
import fetchMock from "fetch-mock-jest";
import escapeHtml from "escape-html";
import { RelationsContainer } from "matrix-js-sdk/src/models/relations-container";

import { filterConsole, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
import { filterConsole, mkReaction, mkStubRoom, REPEATABLE_DATE, stubClient } from "../../../test-utils";
import { ExportType, IExportOptions } from "../../../../src/utils/exportUtils/exportUtils";
import SdkConfig from "../../../../src/SdkConfig";
import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport";
Expand Down Expand Up @@ -123,6 +128,35 @@ describe("HTMLExport", () => {
fetchMock.get(media.srcHttp!, body);
}

function mockReactionForMessage(message: IRoomEvent): MatrixEvent {
const firstMessage = new MatrixEvent(message);
const reaction = mkReaction(firstMessage);

const relationsContainer = {
getRelations: jest.fn(),
getChildEventsForEvent: jest.fn(),
} as unknown as RelationsContainer;
const relations = new Relations(RelationType.Annotation, EventType.Reaction, client);
relations.addEvent(reaction);
relationsContainer.getChildEventsForEvent = jest
.fn()
.mockImplementation(
(eventId: string, relationType: RelationType | string, eventType: EventType | string) => {
if (eventId === firstMessage.getId()) {
return relations;
}
},
);

const timelineSet = {
relations: relationsContainer,
getLiveTimeline: () => timeline,
} as unknown as EventTimelineSet;
const timeline = new EventTimeline(timelineSet);
room.getUnfilteredTimelineSet = jest.fn().mockReturnValue(timelineSet);
return reaction;
}

it("should throw when created with invalid config for LastNMessages", async () => {
expect(
() =>
Expand Down Expand Up @@ -167,6 +201,7 @@ describe("HTMLExport", () => {
body: `Message #${i}`,
},
}));
mockReactionForMessage(events[0]);
mockMessages(...events);

const exporter = new HTMLExporter(
Expand Down Expand Up @@ -587,4 +622,24 @@ describe("HTMLExport", () => {
expect(await file.text()).toContain("testing testing");
expect(client.createMessagesRequest).not.toHaveBeenCalled();
});

it("should include reactions", async () => {
const reaction = mockReactionForMessage(EVENT_MESSAGE);
mockMessages(EVENT_MESSAGE);
const exporter = new HTMLExporter(
room,
ExportType.LastNMessages,
{
attachmentsIncluded: false,
maxSize: 1_024 * 1_024,
numberOfMessages: 40,
},
() => {},
);

await exporter.export();

const file = getMessageFile(exporter);
expect(await file.text()).toContain(reaction.getContent()["m.relates_to"]?.key);
});
});

Large diffs are not rendered by default.

0 comments on commit 59cd518

Please sign in to comment.