Fixed sending url preview bundles relying on update delay (#34266)

* Fixed url preview bundle using url previews generated after the composer is cleared when sending message

* lint fix

* added comment

* fixed linting error

* added comments
This commit is contained in:
Sirius
2026-07-15 18:48:05 +00:00
committed by GitHub
parent 6f02054452
commit 8e0ed84eac
2 changed files with 20 additions and 6 deletions
@@ -401,6 +401,10 @@ export class MessageComposer extends React.Component<IProps, IState> {
}; };
private sendMessage = async (): Promise<void> => { private sendMessage = async (): Promise<void> => {
// snapshot need to be captured before the composer is cleared
// otherwise the send message function will think there are no URLs in
// message and will not attach URL bundles
const urlPreviewSnapshot = this.props.urlPreviewVm.getSnapshot();
this.props.urlPreviewVm.updateWithText({ content: "", debounced: false }); this.props.urlPreviewVm.updateWithText({ content: "", debounced: false });
if (this.state.haveRecording && this.voiceRecordingButton.current) { if (this.state.haveRecording && this.voiceRecordingButton.current) {
// There shouldn't be any text message to send when a voice recording is active, so // There shouldn't be any text message to send when a voice recording is active, so
@@ -409,7 +413,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
return; return;
} }
this.messageComposerInput.current?.sendMessage(); this.messageComposerInput.current?.sendMessage({ urlPreviewSnapshot });
if (this.state.isWysiwygLabEnabled) { if (this.state.isWysiwygLabEnabled) {
const { relation, replyToEvent } = this.props; const { relation, replyToEvent } = this.props;
@@ -424,7 +428,7 @@ export class MessageComposer extends React.Component<IProps, IState> {
roomContext: this.context, roomContext: this.context,
relation, relation,
replyToEvent, replyToEvent,
urlPreviewSnapshot: this.props.urlPreviewVm.getSnapshot(), urlPreviewSnapshot,
}); });
} }
}; };
@@ -67,6 +67,7 @@ import { EMOJI_REGEX } from "../../../HtmlUtils";
import { attachMentions, attachRelation, attachUrlPreviews } from "../../../utils/messages"; import { attachMentions, attachRelation, attachUrlPreviews } from "../../../utils/messages";
import { type RoomUploadViewModel, useRoomUploadViewModel } from "../../../viewmodels/room/RoomUploadViewModel"; import { type RoomUploadViewModel, useRoomUploadViewModel } from "../../../viewmodels/room/RoomUploadViewModel";
import { type MessageComposerUrlPreviewViewModel } from "../../../viewmodels/composer/MessageComposerUrlPreviewViewModel"; import { type MessageComposerUrlPreviewViewModel } from "../../../viewmodels/composer/MessageComposerUrlPreviewViewModel";
import { type MessageComposerUrlPreviewSnapshot } from "@element-hq/web-shared-components";
// The prefix used when persisting editor drafts to localstorage. // The prefix used when persisting editor drafts to localstorage.
export const EDITOR_STATE_STORAGE_PREFIX = "mx_cider_state_"; export const EDITOR_STATE_STORAGE_PREFIX = "mx_cider_state_";
@@ -141,6 +142,10 @@ interface ISendMessageComposerProps extends MatrixClientProps {
urlPreviewVm: MessageComposerUrlPreviewViewModel; urlPreviewVm: MessageComposerUrlPreviewViewModel;
} }
interface ISendMessageActionProps {
urlPreviewSnapshot: MessageComposerUrlPreviewSnapshot;
}
export class SendMessageComposer extends React.Component<ISendMessageComposerProps> { export class SendMessageComposer extends React.Component<ISendMessageComposerProps> {
public static contextType = RoomContext; public static contextType = RoomContext;
declare public context: React.ContextType<typeof RoomContext>; declare public context: React.ContextType<typeof RoomContext>;
@@ -197,10 +202,12 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
const replyingToThread = this.props.relation?.key === THREAD_RELATION_TYPE.name; const replyingToThread = this.props.relation?.key === THREAD_RELATION_TYPE.name;
const action = getKeyBindingsManager().getMessageComposerAction(event); const action = getKeyBindingsManager().getMessageComposerAction(event);
switch (action) { switch (action) {
case KeyBindingAction.SendMessage: case KeyBindingAction.SendMessage: {
this.sendMessage(); const urlPreviewSnapshot = this.props.urlPreviewVm.getSnapshot();
this.sendMessage({ urlPreviewSnapshot });
event.preventDefault(); event.preventDefault();
break; break;
}
case KeyBindingAction.SelectPrevSendHistory: case KeyBindingAction.SelectPrevSendHistory:
case KeyBindingAction.SelectNextSendHistory: { case KeyBindingAction.SelectNextSendHistory: {
// Try select composer history // Try select composer history
@@ -330,7 +337,10 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
} }
} }
public async sendMessage(): Promise<void> { /*
* The URL preview VM snapshot before the composer is cleared
*/
public async sendMessage({ urlPreviewSnapshot }: ISendMessageActionProps): Promise<void> {
const model = this.model; const model = this.model;
if (model.isEmpty) { if (model.isEmpty) {
@@ -443,7 +453,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
// clear composer first so the user doesn't actually see the delay of attach URL preview image files // clear composer first so the user doesn't actually see the delay of attach URL preview image files
clearComposerAndPushHistory(); clearComposerAndPushHistory();
attachUrlPreviews(this.props.urlPreviewVm.getSnapshot(), content); attachUrlPreviews(urlPreviewSnapshot, content);
if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) {
decorateStartSendingTime(content); decorateStartSendingTime(content);