Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 46e1ac6

Browse files
authored
Merge pull request #9422 from matrix-org/feat/reply-support-wysiwyg-composer
Add reply support to WysiwygComposer
2 parents cf1b592 + 2146c91 commit 46e1ac6

File tree

2 files changed

+111
-16
lines changed

2 files changed

+111
-16
lines changed

src/components/views/rooms/wysiwyg_composer/message.ts

+16-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,23 @@ import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
2222
import { PosthogAnalytics } from "../../../../PosthogAnalytics";
2323
import SettingsStore from "../../../../settings/SettingsStore";
2424
import { decorateStartSendingTime, sendRoundTripMetric } from "../../../../sendTimePerformanceMetrics";
25-
import { attachRelation } from "../SendMessageComposer";
2625
import { RoomPermalinkCreator } from "../../../../utils/permalinks/Permalinks";
2726
import { doMaybeLocalRoomAction } from "../../../../utils/local-room";
2827
import { CHAT_EFFECTS } from "../../../../effects";
2928
import { containsEmoji } from "../../../../effects/utils";
3029
import { IRoomState } from "../../../structures/RoomView";
3130
import dis from '../../../../dispatcher/dispatcher';
31+
import { addReplyToMessageContent } from "../../../../utils/Reply";
32+
33+
// Merges favouring the given relation
34+
function attachRelation(content: IContent, relation?: IEventRelation): void {
35+
if (relation) {
36+
content['m.relates_to'] = {
37+
...(content['m.relates_to'] || {}),
38+
...relation,
39+
};
40+
}
41+
}
3242

3343
interface SendMessageParams {
3444
mxClient: MatrixClient;
@@ -81,13 +91,12 @@ export function createMessageContent(
8191

8292
attachRelation(content, relation);
8393

84-
// TODO reply
85-
/*if (replyToEvent) {
94+
if (replyToEvent) {
8695
addReplyToMessageContent(content, replyToEvent, {
8796
permalinkCreator,
8897
includeLegacyFallback: includeReplyLegacyFallback,
8998
});
90-
}*/
99+
}
91100

92101
return content;
93102
}
@@ -148,16 +157,16 @@ export function sendMessage(
148157
mxClient,
149158
);
150159

151-
// TODO reply
152-
/*if (replyToEvent) {
160+
if (replyToEvent) {
153161
// Clear reply_to_event as we put the message into the queue
154162
// if the send fails, retry will handle resending.
155163
dis.dispatch({
156164
action: 'reply_to_event',
157165
event: null,
158166
context: roomContext.timelineRenderingType,
159167
});
160-
}*/
168+
}
169+
161170
dis.dispatch({ action: "message_sent" });
162171
CHAT_EFFECTS.forEach((effect) => {
163172
if (containsEmoji(content, effect.emojis)) {

test/components/views/rooms/wysiwyg_composer/message-test.ts

+95-9
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ import { createTestClient, mkEvent, mkStubRoom } from "../../../../test-utils";
2222
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
2323
import SettingsStore from "../../../../../src/settings/SettingsStore";
2424
import { SettingLevel } from "../../../../../src/settings/SettingLevel";
25+
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks";
2526

2627
describe('message', () => {
27-
const permalinkCreator = jest.fn() as any;
28+
const permalinkCreator = {
29+
forEvent(eventId: string): string {
30+
return "$$permalink$$";
31+
},
32+
} as RoomPermalinkCreator;
2833
const message = '<i><b>hello</b> world</i>';
2934
const mockEvent = mkEvent({
3035
type: "m.room.message",
@@ -45,10 +50,51 @@ describe('message', () => {
4550

4651
// Then
4752
expect(content).toEqual({
48-
body: message,
49-
format: "org.matrix.custom.html",
50-
formatted_body: message,
51-
msgtype: "m.text",
53+
"body": message,
54+
"format": "org.matrix.custom.html",
55+
"formatted_body": message,
56+
"msgtype": "m.text",
57+
});
58+
});
59+
60+
it('Should add reply to message content', () => {
61+
// When
62+
const content = createMessageContent(message, { permalinkCreator, replyToEvent: mockEvent });
63+
64+
// Then
65+
expect(content).toEqual({
66+
"body": "> <myfakeuser> Replying to this\n\n<i><b>hello</b> world</i>",
67+
"format": "org.matrix.custom.html",
68+
"formatted_body": "<mx-reply><blockquote><a href=\"$$permalink$$\">In reply to</a>" +
69+
" <a href=\"https://matrix.to/#/myfakeuser\">myfakeuser</a>"+
70+
"<br>Replying to this</blockquote></mx-reply><i><b>hello</b> world</i>",
71+
"msgtype": "m.text",
72+
"m.relates_to": {
73+
"m.in_reply_to": {
74+
"event_id": mockEvent.getId(),
75+
},
76+
},
77+
});
78+
});
79+
80+
it("Should add relation to message", () => {
81+
// When
82+
const relation = {
83+
rel_type: "m.thread",
84+
event_id: "myFakeThreadId",
85+
};
86+
const content = createMessageContent(message, { permalinkCreator, relation });
87+
88+
// Then
89+
expect(content).toEqual({
90+
"body": message,
91+
"format": "org.matrix.custom.html",
92+
"formatted_body": message,
93+
"msgtype": "m.text",
94+
"m.relates_to": {
95+
"event_id": "myFakeThreadId",
96+
"rel_type": "m.thread",
97+
},
5298
});
5399
});
54100
});
@@ -102,6 +148,15 @@ describe('message', () => {
102148
const spyDispatcher = jest.spyOn(defaultDispatcher, "dispatch");
103149

104150
it('Should not send empty html message', async () => {
151+
// When
152+
await sendMessage('', { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
153+
154+
// Then
155+
expect(mockClient.sendMessage).toBeCalledTimes(0);
156+
expect(spyDispatcher).toBeCalledTimes(0);
157+
});
158+
159+
it('Should send html message', async () => {
105160
// When
106161
await sendMessage(message, { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
107162

@@ -116,13 +171,44 @@ describe('message', () => {
116171
expect(spyDispatcher).toBeCalledWith({ action: 'message_sent' });
117172
});
118173

119-
it('Should send html message', async () => {
174+
it('Should send reply to html message', async () => {
175+
const mockReplyEvent = mkEvent({
176+
type: "m.room.message",
177+
room: 'myfakeroom',
178+
user: 'myfakeuser2',
179+
content: { "msgtype": "m.text", "body": "My reply" },
180+
event: true,
181+
});
182+
120183
// When
121-
await sendMessage('', { roomContext: defaultRoomContext, mxClient: mockClient, permalinkCreator });
184+
await sendMessage(message, {
185+
roomContext: defaultRoomContext,
186+
mxClient: mockClient,
187+
permalinkCreator,
188+
replyToEvent: mockReplyEvent,
189+
});
122190

123191
// Then
124-
expect(mockClient.sendMessage).toBeCalledTimes(0);
125-
expect(spyDispatcher).toBeCalledTimes(0);
192+
expect(spyDispatcher).toBeCalledWith({
193+
action: 'reply_to_event',
194+
event: null,
195+
context: defaultRoomContext.timelineRenderingType,
196+
});
197+
198+
const expectedContent = {
199+
"body": "> <myfakeuser2> My reply\n\n<i><b>hello</b> world</i>",
200+
"format": "org.matrix.custom.html",
201+
"formatted_body": "<mx-reply><blockquote><a href=\"$$permalink$$\">In reply to</a>" +
202+
" <a href=\"https://matrix.to/#/myfakeuser2\">myfakeuser2</a>" +
203+
"<br>My reply</blockquote></mx-reply><i><b>hello</b> world</i>",
204+
"msgtype": "m.text",
205+
"m.relates_to": {
206+
"m.in_reply_to": {
207+
"event_id": mockReplyEvent.getId(),
208+
},
209+
},
210+
};
211+
expect(mockClient.sendMessage).toBeCalledWith('myfakeroom', null, expectedContent);
126212
});
127213

128214
it('Should scroll to bottom after sending a html message', async () => {

0 commit comments

Comments
 (0)