diff --git a/desktop/src-tauri/src/commands/messages.rs b/desktop/src-tauri/src/commands/messages.rs index 8396068d0..4664a846e 100644 --- a/desktop/src-tauri/src/commands/messages.rs +++ b/desktop/src-tauri/src/commands/messages.rs @@ -869,40 +869,48 @@ pub async fn remove_reaction( Ok(()) } -#[tauri::command] -pub async fn edit_message( +#[derive(serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct EditMessageInput { channel_id: String, event_id: String, content: String, + #[serde(default)] media_tags: Vec>, - emoji_tags: Option>>, - // Pubkeys of mentions *newly added* by this edit (the composer diffs the - // edited body against the original). Only these get a `p` tag, so a typo-fix - // edit that leaves the mention set unchanged never re-wakes anyone. - mention_pubkeys: Option>, - suppress_link_previews: Option, + #[serde(default)] + emoji_tags: Vec>, + // Pubkeys of mentions *newly added* by this edit. Only these get a `p` + // tag, so a typo-fix edit never re-wakes existing mentions. + #[serde(default)] + mention_pubkeys: Vec, + #[serde(default)] + suppress_link_previews: bool, +} + +#[tauri::command] +pub async fn edit_message( + input: EditMessageInput, state: State<'_, AppState>, ) -> Result<(), String> { - let channel_uuid = uuid::Uuid::parse_str(&channel_id) - .map_err(|_| format!("invalid channel UUID: {channel_id}"))?; - let target_eid = EventId::from_hex(&event_id).map_err(|e| format!("invalid event ID: {e}"))?; - let trimmed = content.trim(); + let channel_uuid = uuid::Uuid::parse_str(&input.channel_id) + .map_err(|_| format!("invalid channel UUID: {}", input.channel_id))?; + let target_eid = + EventId::from_hex(&input.event_id).map_err(|e| format!("invalid event ID: {e}"))?; + let trimmed = input.content.trim(); // Empty text is allowed when the edit still carries imeta attachments // (a media-only edit). Reject only when both are empty. - if trimmed.is_empty() && media_tags.is_empty() { + if trimmed.is_empty() && input.media_tags.is_empty() { return Err("edit must have content or attachments".into()); } - let emoji = emoji_tags.unwrap_or_default(); - let mentions = mention_pubkeys.unwrap_or_default(); - let mention_refs: Vec<&str> = mentions.iter().map(|s| s.as_str()).collect(); + let mention_refs: Vec<&str> = input.mention_pubkeys.iter().map(|s| s.as_str()).collect(); let builder = events::build_message_edit( channel_uuid, target_eid, trimmed, - &media_tags, - &emoji, + &input.media_tags, + &input.emoji_tags, &mention_refs, - suppress_link_previews.unwrap_or(false), + input.suppress_link_previews, )?; submit_event(builder, &state).await?; Ok(()) diff --git a/desktop/src/shared/api/editMessage.ts b/desktop/src/shared/api/editMessage.ts index ec4742322..fc63502e4 100644 --- a/desktop/src/shared/api/editMessage.ts +++ b/desktop/src/shared/api/editMessage.ts @@ -10,12 +10,14 @@ export async function editMessage( suppressLinkPreviews?: boolean, ): Promise { await invokeTauri("edit_message", { - channelId, - eventId, - content, - mediaTags: mediaTags ?? [], - emojiTags: emojiTags ?? [], - mentionPubkeys: mentionPubkeys ?? null, - suppressLinkPreviews: suppressLinkPreviews ?? false, + input: { + channelId, + eventId, + content, + mediaTags: mediaTags ?? [], + emojiTags: emojiTags ?? [], + mentionPubkeys: mentionPubkeys ?? [], + suppressLinkPreviews: suppressLinkPreviews ?? false, + }, }); } diff --git a/desktop/src/testing/e2eBridge.ts b/desktop/src/testing/e2eBridge.ts index 2500ab4c8..d40ac244e 100644 --- a/desktop/src/testing/e2eBridge.ts +++ b/desktop/src/testing/e2eBridge.ts @@ -11387,7 +11387,7 @@ export function maybeInstallE2eTauriMocks() { return null; case "edit_message": return handleEditMessage( - payload as Parameters[0], + (payload as { input: Parameters[0] }).input, activeConfig, ); case "add_reaction":