From aeb00a8d607b188852554088825be2fcc1ddd4e9 Mon Sep 17 00:00:00 2001 From: Ren Amamiya Date: Mon, 30 Mar 2026 14:55:44 +0700 Subject: [PATCH] add copy function --- crates/chat/src/message.rs | 4 +- crates/coop/src/panels/backup.rs | 5 -- crates/coop/src/panels/trash.rs | 81 ++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 26 deletions(-) diff --git a/crates/chat/src/message.rs b/crates/chat/src/message.rs index 77f08b7..cf4b293 100644 --- a/crates/chat/src/message.rs +++ b/crates/chat/src/message.rs @@ -28,7 +28,7 @@ impl NewMessage { /// Trash message. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct FailedMessage { - pub raw_event: String, + pub raw_event: SharedString, pub reason: SharedString, } @@ -38,7 +38,7 @@ impl FailedMessage { T: Into, { Self { - raw_event: event.as_json(), + raw_event: SharedString::from(event.as_json()), reason: reason.into(), } } diff --git a/crates/coop/src/panels/backup.rs b/crates/coop/src/panels/backup.rs index 12c29c2..ba0310a 100644 --- a/crates/coop/src/panels/backup.rs +++ b/crates/coop/src/panels/backup.rs @@ -84,11 +84,6 @@ impl BackupPanel { fn copy_secret(&mut self, cx: &mut Context) { let value = self.nsec_input.read(cx).value(); let item = ClipboardItem::new_string(value.to_string()); - - #[cfg(target_os = "linux")] - cx.write_to_primary(item); - - #[cfg(not(target_os = "linux"))] cx.write_to_clipboard(item); // Set the copied status to true diff --git a/crates/coop/src/panels/trash.rs b/crates/coop/src/panels/trash.rs index e4c7696..2a2220c 100644 --- a/crates/coop/src/panels/trash.rs +++ b/crates/coop/src/panels/trash.rs @@ -1,13 +1,14 @@ use chat::ChatRegistry; use gpui::{ - AnyElement, App, AppContext, Context, Entity, EventEmitter, FocusHandle, Focusable, - InteractiveElement, IntoElement, ListAlignment, ListState, ParentElement, Render, SharedString, - Styled, Window, div, list, px, + AnyElement, App, AppContext, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, + Focusable, InteractiveElement, IntoElement, ListAlignment, ListState, ParentElement, Render, + SharedString, Styled, Window, div, list, px, relative, }; use theme::ActiveTheme; +use ui::button::{Button, ButtonVariants}; use ui::dock::{Panel, PanelEvent}; use ui::scroll::Scrollbar; -use ui::v_flex; +use ui::{Icon, IconName, Sizable, h_flex, v_flex}; pub fn init(window: &mut Window, cx: &mut App) -> Entity { cx.new(|cx| TrashPanel::new(window, cx)) @@ -34,6 +35,16 @@ impl TrashPanel { } } + fn copy(&self, ix: usize, cx: &App) { + let chat = ChatRegistry::global(cx); + let trashes = chat.read(cx).trashes(); + + if let Some(message) = trashes.read(cx).iter().nth(ix) { + let item = ClipboardItem::new_string(message.raw_event.to_string()); + cx.write_to_clipboard(item); + } + } + fn render_list_item( &mut self, ix: usize, @@ -47,21 +58,48 @@ impl TrashPanel { v_flex() .id(ix) .p_2() - .rounded(cx.theme().radius) - .bg(cx.theme().elevated_surface_background) - .text_sm() + .w_full() .child( - div() - .text_color(cx.theme().text_danger) - .child(message.reason.clone()), - ) - .child( - div() - .line_clamp(1) - .text_ellipsis() - .text_xs() - .overflow_hidden() - .child(message.raw_event.clone()), + v_flex() + .p_2() + .w_full() + .gap_1() + .rounded(cx.theme().radius_lg) + .bg(cx.theme().surface_background) + .text_sm() + .child( + div() + .text_color(cx.theme().text_danger) + .child(message.reason.clone()), + ) + .child( + h_flex() + .h_10() + .w_full() + .px_2() + .justify_between() + .bg(cx.theme().elevated_surface_background) + .border_1() + .border_color(cx.theme().border) + .rounded(cx.theme().radius) + .child( + div() + .truncate() + .text_ellipsis() + .text_xs() + .line_height(relative(1.)) + .child(message.raw_event.clone()), + ) + .child( + Button::new(format!("copy-{ix}")) + .icon(IconName::Copy) + .ghost() + .small() + .on_click(cx.listener(move |this, _ev, _window, cx| { + this.copy(ix, cx); + })), + ), + ), ) .into_any_element() } else { @@ -76,7 +114,12 @@ impl Panel for TrashPanel { } fn title(&self, _cx: &App) -> AnyElement { - self.name.clone().into_any_element() + h_flex() + .gap_1() + .text_sm() + .child(Icon::new(IconName::Warning).small()) + .child("Errors") + .into_any_element() } }