From bd18e087549e58611e3c5cccb34bb0027671ee2d Mon Sep 17 00:00:00 2001
From: Adam Dalloul <47503782+Adam-Dalloul@users.noreply.github.com>
Date: Sat, 15 Aug 2026 17:59:01 -0700
Subject: [PATCH 1/3] feat(chat): two-way composer draft sync across desktop
and mobile
---
src-tauri/src/commands/conversations.rs | 76 ++++++-
.../entities/conversation_composer_draft.rs | 19 ++
src-tauri/src/db/entities/mod.rs | 1 +
...0815_000002_conversation_composer_draft.rs | 64 ++++++
src-tauri/src/db/migration/mod.rs | 2 +
.../conversation_composer_draft_service.rs | 206 ++++++++++++++++++
src-tauri/src/db/service/mod.rs | 1 +
src-tauri/src/lib.rs | 2 +
src-tauri/src/web/event_bridge.rs | 45 ++++
src-tauri/src/web/handlers/conversations.rs | 43 ++++
src-tauri/src/web/router.rs | 8 +
src/components/chat/message-input.tsx | 38 +++-
src/hooks/use-composer-draft-sync.ts | 155 +++++++++++++
src/lib/api.ts | 20 ++
src/lib/composer-draft-sync.test.ts | 67 ++++++
src/lib/composer-draft-sync.ts | 47 ++++
src/lib/types.ts | 26 +++
17 files changed, 815 insertions(+), 5 deletions(-)
create mode 100644 src-tauri/src/db/entities/conversation_composer_draft.rs
create mode 100644 src-tauri/src/db/migration/m20260815_000002_conversation_composer_draft.rs
create mode 100644 src-tauri/src/db/service/conversation_composer_draft_service.rs
create mode 100644 src/hooks/use-composer-draft-sync.ts
create mode 100644 src/lib/composer-draft-sync.test.ts
create mode 100644 src/lib/composer-draft-sync.ts
diff --git a/src-tauri/src/commands/conversations.rs b/src-tauri/src/commands/conversations.rs
index 23ba28b1c..7db410a87 100644
--- a/src-tauri/src/commands/conversations.rs
+++ b/src-tauri/src/commands/conversations.rs
@@ -3,7 +3,10 @@ use std::collections::{HashMap, HashSet};
use crate::app_error::AppCommandError;
use crate::db::entities::conversation;
use crate::db::entities::folder::FolderKind;
-use crate::db::service::{conversation_service, folder_service, import_service, tab_service};
+use crate::db::service::{
+ conversation_composer_draft_service, conversation_service, folder_service, import_service,
+ tab_service,
+};
#[cfg(feature = "tauri-runtime")]
use crate::db::AppDatabase;
use crate::models::*;
@@ -26,9 +29,10 @@ use crate::parsers::{
ParseError,
};
use crate::web::event_bridge::{
- emit_event, ConversationChange, ConversationsBulkChanged, EventEmitter, ImportScanProgress,
- TabsChanged, CONVERSATIONS_BULK_CHANGED_EVENT, CONVERSATION_CHANGED_EVENT,
- IMPORT_SCAN_PROGRESS_EVENT, TABS_CHANGED_EVENT,
+ emit_event, ComposerDraftChanged, ConversationChange, ConversationsBulkChanged, EventEmitter,
+ ImportScanProgress, TabsChanged, COMPOSER_DRAFT_CHANGED_EVENT,
+ CONVERSATIONS_BULK_CHANGED_EVENT, CONVERSATION_CHANGED_EVENT, IMPORT_SCAN_PROGRESS_EVENT,
+ TABS_CHANGED_EVENT,
};
pub async fn list_all_conversations_core(
@@ -2000,6 +2004,70 @@ pub async fn update_conversation_pinned(
Ok(())
}
+/// Fetch the unsent composer text for a persisted conversation. `None` when
+/// no client has saved a draft yet. The body is only returned here — the
+/// WS notify never carries it.
+pub async fn get_composer_draft_core(
+ conn: &sea_orm::DatabaseConnection,
+ conversation_id: i32,
+) -> Result