From 7e4eb4f72bdc3f3ea9a128ac0c699600df410834 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 20 Feb 2026 10:15:42 +0100 Subject: [PATCH] agent_ui: Fix panic in load/copy thread to/from clipboard (#49694) Fixes ZED-4VW Release Notes: - N/A *or* Added/Fixed/Improved ... --- crates/agent_ui/src/agent_panel.rs | 88 ++++++++++-------------------- 1 file changed, 29 insertions(+), 59 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 61e0c65cc7ec96c9706da7eccfdec20fc491617c..f53682744fba5124f8751da8b0607cb01d482a3e 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -1348,19 +1348,7 @@ impl AgentPanel { fn copy_thread_to_clipboard(&mut self, window: &mut Window, cx: &mut Context) { let Some(thread) = self.active_native_agent_thread(cx) else { - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - struct NoThreadToast; - workspace.show_toast( - workspace::Toast::new( - workspace::notifications::NotificationId::unique::(), - "No active native thread to copy", - ) - .autohide(), - cx, - ); - }); - } + Self::show_deferred_toast(&self.workspace, "No active native thread to copy", cx); return; }; @@ -1395,38 +1383,37 @@ impl AgentPanel { .detach_and_log_err(cx); } - fn load_thread_from_clipboard(&mut self, window: &mut Window, cx: &mut Context) { - let Some(clipboard) = cx.read_from_clipboard() else { - if let Some(workspace) = self.workspace.upgrade() { + fn show_deferred_toast( + workspace: &WeakEntity, + message: &'static str, + cx: &mut App, + ) { + let workspace = workspace.clone(); + cx.defer(move |cx| { + if let Some(workspace) = workspace.upgrade() { workspace.update(cx, |workspace, cx| { - struct NoClipboardToast; + struct ClipboardToast; workspace.show_toast( workspace::Toast::new( - workspace::notifications::NotificationId::unique::(), - "No clipboard content available", + workspace::notifications::NotificationId::unique::(), + message, ) .autohide(), cx, ); }); } + }); + } + + fn load_thread_from_clipboard(&mut self, window: &mut Window, cx: &mut Context) { + let Some(clipboard) = cx.read_from_clipboard() else { + Self::show_deferred_toast(&self.workspace, "No clipboard content available", cx); return; }; let Some(encoded) = clipboard.text() else { - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - struct InvalidClipboardToast; - workspace.show_toast( - workspace::Toast::new( - workspace::notifications::NotificationId::unique::(), - "Clipboard does not contain text", - ) - .autohide(), - cx, - ); - }); - } + Self::show_deferred_toast(&self.workspace, "Clipboard does not contain text", cx); return; }; @@ -1434,19 +1421,11 @@ impl AgentPanel { { Ok(data) => data, Err(_) => { - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - struct DecodeErrorToast; - workspace.show_toast( - workspace::Toast::new( - workspace::notifications::NotificationId::unique::(), - "Failed to decode clipboard content (expected base64)", - ) - .autohide(), - cx, - ); - }); - } + Self::show_deferred_toast( + &self.workspace, + "Failed to decode clipboard content (expected base64)", + cx, + ); return; } }; @@ -1454,20 +1433,11 @@ impl AgentPanel { let shared_thread = match SharedThread::from_bytes(&thread_data) { Ok(thread) => thread, Err(_) => { - if let Some(workspace) = self.workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - struct ParseErrorToast; - workspace.show_toast( - workspace::Toast::new( - workspace::notifications::NotificationId::unique::( - ), - "Failed to parse thread data from clipboard", - ) - .autohide(), - cx, - ); - }); - } + Self::show_deferred_toast( + &self.workspace, + "Failed to parse thread data from clipboard", + cx, + ); return; } };