Merge pull request #6720 from matrix-org/gsouquet/replies-fix-18717
This commit is contained in:
commit
9be9e75c13
6 changed files with 45 additions and 19 deletions
|
@ -136,6 +136,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
<MessageComposer
|
<MessageComposer
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
replyInThread={true}
|
||||||
replyToEvent={this.state?.thread?.replyToEvent}
|
replyToEvent={this.state?.thread?.replyToEvent}
|
||||||
showReplyPreview={false}
|
showReplyPreview={false}
|
||||||
permalinkCreator={this.props.permalinkCreator}
|
permalinkCreator={this.props.permalinkCreator}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||||
|
import { UNSTABLE_ELEMENT_REPLY_IN_THREAD } from "matrix-js-sdk/src/@types/event";
|
||||||
import { makeUserPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
import { makeUserPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import { Layout } from "../../../settings/Layout";
|
import { Layout } from "../../../settings/Layout";
|
||||||
|
@ -206,15 +207,28 @@ export default class ReplyThread extends React.Component<IProps, IState> {
|
||||||
return { body, html };
|
return { body, html };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static makeReplyMixIn(ev: MatrixEvent) {
|
public static makeReplyMixIn(ev: MatrixEvent, replyInThread: boolean) {
|
||||||
if (!ev) return {};
|
if (!ev) return {};
|
||||||
return {
|
|
||||||
|
const replyMixin = {
|
||||||
'm.relates_to': {
|
'm.relates_to': {
|
||||||
'm.in_reply_to': {
|
'm.in_reply_to': {
|
||||||
'event_id': ev.getId(),
|
'event_id': ev.getId(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
* Rendering hint for threads, only attached if true to make
|
||||||
|
* sure that Element does not start sending that property for all events
|
||||||
|
*/
|
||||||
|
if (replyInThread) {
|
||||||
|
const inReplyTo = replyMixin['m.relates_to']['m.in_reply_to'];
|
||||||
|
inReplyTo[UNSTABLE_ELEMENT_REPLY_IN_THREAD.name] = replyInThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
return replyMixin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static makeThread(
|
public static makeThread(
|
||||||
|
|
|
@ -43,11 +43,6 @@ import QuestionDialog from "../dialogs/QuestionDialog";
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
|
||||||
function eventIsReply(mxEvent: MatrixEvent): boolean {
|
|
||||||
const relatesTo = mxEvent.getContent()["m.relates_to"];
|
|
||||||
return !!(relatesTo && relatesTo["m.in_reply_to"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
function getHtmlReplyFallback(mxEvent: MatrixEvent): string {
|
||||||
const html = mxEvent.getContent().formatted_body;
|
const html = mxEvent.getContent().formatted_body;
|
||||||
if (!html) {
|
if (!html) {
|
||||||
|
@ -72,7 +67,7 @@ function createEditContent(model: EditorModel, editedEvent: MatrixEvent): IConte
|
||||||
if (isEmote) {
|
if (isEmote) {
|
||||||
model = stripEmoteCommand(model);
|
model = stripEmoteCommand(model);
|
||||||
}
|
}
|
||||||
const isReply = eventIsReply(editedEvent);
|
const isReply = !!editedEvent.replyEventId;
|
||||||
let plainPrefix = "";
|
let plainPrefix = "";
|
||||||
let htmlPrefix = "";
|
let htmlPrefix = "";
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,7 @@ interface IProps {
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
permalinkCreator: RoomPermalinkCreator;
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
replyToEvent?: MatrixEvent;
|
replyToEvent?: MatrixEvent;
|
||||||
|
replyInThread?: boolean;
|
||||||
showReplyPreview?: boolean;
|
showReplyPreview?: boolean;
|
||||||
e2eStatus?: E2EStatus;
|
e2eStatus?: E2EStatus;
|
||||||
compact?: boolean;
|
compact?: boolean;
|
||||||
|
@ -204,6 +205,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
||||||
private voiceRecordingButton: VoiceRecordComposerTile;
|
private voiceRecordingButton: VoiceRecordComposerTile;
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
|
replyInThread: false,
|
||||||
showReplyPreview: true,
|
showReplyPreview: true,
|
||||||
compact: false,
|
compact: false,
|
||||||
};
|
};
|
||||||
|
@ -383,6 +385,7 @@ export default class MessageComposer extends React.Component<IProps, IState> {
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
placeholder={this.renderPlaceholderText()}
|
placeholder={this.renderPlaceholderText()}
|
||||||
permalinkCreator={this.props.permalinkCreator}
|
permalinkCreator={this.props.permalinkCreator}
|
||||||
|
replyInThread={this.props.replyInThread}
|
||||||
replyToEvent={this.props.replyToEvent}
|
replyToEvent={this.props.replyToEvent}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
disabled={this.state.haveRecording}
|
disabled={this.state.haveRecording}
|
||||||
|
|
|
@ -57,15 +57,16 @@ import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
|
|
||||||
function addReplyToMessageContent(
|
function addReplyToMessageContent(
|
||||||
content: IContent,
|
content: IContent,
|
||||||
repliedToEvent: MatrixEvent,
|
replyToEvent: MatrixEvent,
|
||||||
|
replyInThread: boolean,
|
||||||
permalinkCreator: RoomPermalinkCreator,
|
permalinkCreator: RoomPermalinkCreator,
|
||||||
): void {
|
): void {
|
||||||
const replyContent = ReplyThread.makeReplyMixIn(repliedToEvent);
|
const replyContent = ReplyThread.makeReplyMixIn(replyToEvent, replyInThread);
|
||||||
Object.assign(content, replyContent);
|
Object.assign(content, replyContent);
|
||||||
|
|
||||||
// Part of Replies fallback support - prepend the text we're sending
|
// Part of Replies fallback support - prepend the text we're sending
|
||||||
// with the text we're replying to
|
// with the text we're replying to
|
||||||
const nestedReply = ReplyThread.getNestedReplyText(repliedToEvent, permalinkCreator);
|
const nestedReply = ReplyThread.getNestedReplyText(replyToEvent, permalinkCreator);
|
||||||
if (nestedReply) {
|
if (nestedReply) {
|
||||||
if (content.formatted_body) {
|
if (content.formatted_body) {
|
||||||
content.formatted_body = nestedReply.html + content.formatted_body;
|
content.formatted_body = nestedReply.html + content.formatted_body;
|
||||||
|
@ -77,8 +78,9 @@ function addReplyToMessageContent(
|
||||||
// exported for tests
|
// exported for tests
|
||||||
export function createMessageContent(
|
export function createMessageContent(
|
||||||
model: EditorModel,
|
model: EditorModel,
|
||||||
permalinkCreator: RoomPermalinkCreator,
|
|
||||||
replyToEvent: MatrixEvent,
|
replyToEvent: MatrixEvent,
|
||||||
|
replyInThread: boolean,
|
||||||
|
permalinkCreator: RoomPermalinkCreator,
|
||||||
): IContent {
|
): IContent {
|
||||||
const isEmote = containsEmote(model);
|
const isEmote = containsEmote(model);
|
||||||
if (isEmote) {
|
if (isEmote) {
|
||||||
|
@ -101,7 +103,7 @@ export function createMessageContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (replyToEvent) {
|
if (replyToEvent) {
|
||||||
addReplyToMessageContent(content, replyToEvent, permalinkCreator);
|
addReplyToMessageContent(content, replyToEvent, replyInThread, permalinkCreator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
|
@ -129,6 +131,7 @@ interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
permalinkCreator: RoomPermalinkCreator;
|
permalinkCreator: RoomPermalinkCreator;
|
||||||
|
replyInThread?: boolean;
|
||||||
replyToEvent?: MatrixEvent;
|
replyToEvent?: MatrixEvent;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange?(model: EditorModel): void;
|
onChange?(model: EditorModel): void;
|
||||||
|
@ -357,7 +360,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
||||||
if (cmd.category === CommandCategories.messages) {
|
if (cmd.category === CommandCategories.messages) {
|
||||||
content = await this.runSlashCommand(cmd, args);
|
content = await this.runSlashCommand(cmd, args);
|
||||||
if (replyToEvent) {
|
if (replyToEvent) {
|
||||||
addReplyToMessageContent(content, replyToEvent, this.props.permalinkCreator);
|
addReplyToMessageContent(
|
||||||
|
content,
|
||||||
|
replyToEvent,
|
||||||
|
this.props.replyInThread,
|
||||||
|
this.props.permalinkCreator,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.runSlashCommand(cmd, args);
|
this.runSlashCommand(cmd, args);
|
||||||
|
@ -400,7 +408,12 @@ export default class SendMessageComposer extends React.Component<IProps> {
|
||||||
const startTime = CountlyAnalytics.getTimestamp();
|
const startTime = CountlyAnalytics.getTimestamp();
|
||||||
const { roomId } = this.props.room;
|
const { roomId } = this.props.room;
|
||||||
if (!content) {
|
if (!content) {
|
||||||
content = createMessageContent(this.model, this.props.permalinkCreator, replyToEvent);
|
content = createMessageContent(
|
||||||
|
this.model,
|
||||||
|
replyToEvent,
|
||||||
|
this.props.replyInThread,
|
||||||
|
this.props.permalinkCreator,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// don't bother sending an empty message
|
// don't bother sending an empty message
|
||||||
if (!content.body.trim()) return;
|
if (!content.body.trim()) return;
|
||||||
|
|
|
@ -46,7 +46,7 @@ describe('<SendMessageComposer/>', () => {
|
||||||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||||
model.update("hello world", "insertText", { offset: 11, atNodeEnd: true });
|
model.update("hello world", "insertText", { offset: 11, atNodeEnd: true });
|
||||||
|
|
||||||
const content = createMessageContent(model, permalinkCreator);
|
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||||
|
|
||||||
expect(content).toEqual({
|
expect(content).toEqual({
|
||||||
body: "hello world",
|
body: "hello world",
|
||||||
|
@ -58,7 +58,7 @@ describe('<SendMessageComposer/>', () => {
|
||||||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||||
model.update("hello *world*", "insertText", { offset: 13, atNodeEnd: true });
|
model.update("hello *world*", "insertText", { offset: 13, atNodeEnd: true });
|
||||||
|
|
||||||
const content = createMessageContent(model, permalinkCreator);
|
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||||
|
|
||||||
expect(content).toEqual({
|
expect(content).toEqual({
|
||||||
body: "hello *world*",
|
body: "hello *world*",
|
||||||
|
@ -72,7 +72,7 @@ describe('<SendMessageComposer/>', () => {
|
||||||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||||
model.update("/me blinks __quickly__", "insertText", { offset: 22, atNodeEnd: true });
|
model.update("/me blinks __quickly__", "insertText", { offset: 22, atNodeEnd: true });
|
||||||
|
|
||||||
const content = createMessageContent(model, permalinkCreator);
|
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||||
|
|
||||||
expect(content).toEqual({
|
expect(content).toEqual({
|
||||||
body: "blinks __quickly__",
|
body: "blinks __quickly__",
|
||||||
|
@ -86,7 +86,7 @@ describe('<SendMessageComposer/>', () => {
|
||||||
const model = new EditorModel([], createPartCreator(), createRenderer());
|
const model = new EditorModel([], createPartCreator(), createRenderer());
|
||||||
model.update("//dev/null is my favourite place", "insertText", { offset: 32, atNodeEnd: true });
|
model.update("//dev/null is my favourite place", "insertText", { offset: 32, atNodeEnd: true });
|
||||||
|
|
||||||
const content = createMessageContent(model, permalinkCreator);
|
const content = createMessageContent(model, null, false, permalinkCreator);
|
||||||
|
|
||||||
expect(content).toEqual({
|
expect(content).toEqual({
|
||||||
body: "/dev/null is my favourite place",
|
body: "/dev/null is my favourite place",
|
||||||
|
|
Loading…
Reference in a new issue