agent: Fix deleting threads in history via keyboard (#28113)

Using `shift-backspace` now because we need `backspace` for search

Release Notes:
- agent: Fix deleting threads in history via keyboard
This commit is contained in:
Agus Zubiaga 2025-04-04 17:45:44 -03:00 committed by GitHub
parent 6162d9942d
commit f3adf41c25
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 63 additions and 50 deletions

View file

@ -339,9 +339,9 @@
} }
}, },
{ {
"context": "ThreadHistory", "context": "ThreadHistory > Editor",
"bindings": { "bindings": {
"backspace": "agent::RemoveSelectedThread" "shift-backspace": "agent::RemoveSelectedThread"
} }
}, },
{ {

View file

@ -653,20 +653,26 @@ impl AssistantPanel {
self.thread.read(cx).thread().clone() self.thread.read(cx).thread().clone()
} }
pub(crate) fn delete_thread(&mut self, thread_id: &ThreadId, cx: &mut Context<Self>) { pub(crate) fn delete_thread(
&mut self,
thread_id: &ThreadId,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
self.thread_store self.thread_store
.update(cx, |this, cx| this.delete_thread(thread_id, cx)) .update(cx, |this, cx| this.delete_thread(thread_id, cx))
.detach_and_log_err(cx);
} }
pub(crate) fn active_context_editor(&self) -> Option<Entity<ContextEditor>> { pub(crate) fn active_context_editor(&self) -> Option<Entity<ContextEditor>> {
self.context_editor.clone() self.context_editor.clone()
} }
pub(crate) fn delete_context(&mut self, path: PathBuf, cx: &mut Context<Self>) { pub(crate) fn delete_context(
&mut self,
path: PathBuf,
cx: &mut Context<Self>,
) -> Task<Result<()>> {
self.context_store self.context_store
.update(cx, |this, cx| this.delete_local_context(path, cx)) .update(cx, |this, cx| this.delete_local_context(path, cx))
.detach_and_log_err(cx);
} }
} }

View file

@ -17,6 +17,7 @@ use crate::{AssistantPanel, RemoveSelectedThread};
pub struct ThreadHistory { pub struct ThreadHistory {
assistant_panel: WeakEntity<AssistantPanel>, assistant_panel: WeakEntity<AssistantPanel>,
history_store: Entity<HistoryStore>,
scroll_handle: UniformListScrollHandle, scroll_handle: UniformListScrollHandle,
selected_index: usize, selected_index: usize,
search_query: SharedString, search_query: SharedString,
@ -40,33 +41,26 @@ impl ThreadHistory {
editor editor
}); });
let search_editor_subscription = cx.subscribe_in( let search_editor_subscription =
&search_editor, cx.subscribe(&search_editor, |this, search_editor, event, cx| {
window,
|this, search_editor, event, window, cx| {
if let EditorEvent::BufferEdited = event { if let EditorEvent::BufferEdited = event {
let query = search_editor.read(cx).text(cx); let query = search_editor.read(cx).text(cx);
this.search_query = query.into(); this.search_query = query.into();
this.update_search(window, cx); this.update_search(cx);
} }
}, });
);
let entries: Arc<Vec<_>> = history_store let entries: Arc<Vec<_>> = history_store
.update(cx, |store, cx| store.entries(cx)) .update(cx, |store, cx| store.entries(cx))
.into(); .into();
let history_store_subscription = let history_store_subscription = cx.observe(&history_store, |this, _, cx| {
cx.observe_in(&history_store, window, |this, history_store, window, cx| { this.update_all_entries(cx);
this.all_entries = history_store });
.update(cx, |store, cx| store.entries(cx))
.into();
this.matches.clear();
this.update_search(window, cx);
});
Self { Self {
assistant_panel, assistant_panel,
history_store,
scroll_handle: UniformListScrollHandle::default(), scroll_handle: UniformListScrollHandle::default(),
selected_index: 0, selected_index: 0,
search_query: SharedString::new_static(""), search_query: SharedString::new_static(""),
@ -78,7 +72,16 @@ impl ThreadHistory {
} }
} }
fn update_search(&mut self, _window: &mut Window, cx: &mut Context<Self>) { fn update_all_entries(&mut self, cx: &mut Context<Self>) {
self.all_entries = self
.history_store
.update(cx, |store, cx| store.entries(cx))
.into();
self.matches.clear();
self.update_search(cx);
}
fn update_search(&mut self, cx: &mut Context<Self>) {
self._search_task.take(); self._search_task.take();
if self.has_search_query() { if self.has_search_query() {
@ -222,17 +225,15 @@ impl ThreadHistory {
let task_result = match entry { let task_result = match entry {
HistoryEntry::Thread(thread) => self HistoryEntry::Thread(thread) => self
.assistant_panel .assistant_panel
.update(cx, move |this, cx| this.open_thread(&thread.id, window, cx)) .update(cx, move |this, cx| this.open_thread(&thread.id, window, cx)),
.ok(), HistoryEntry::Context(context) => {
HistoryEntry::Context(context) => self self.assistant_panel.update(cx, move |this, cx| {
.assistant_panel
.update(cx, move |this, cx| {
this.open_saved_prompt_editor(context.path.clone(), window, cx) this.open_saved_prompt_editor(context.path.clone(), window, cx)
}) })
.ok(), }
}; };
if let Some(task) = task_result { if let Some(task) = task_result.log_err() {
task.detach_and_log_err(cx); task.detach_and_log_err(cx);
}; };
@ -243,28 +244,26 @@ impl ThreadHistory {
fn remove_selected_thread( fn remove_selected_thread(
&mut self, &mut self,
_: &RemoveSelectedThread, _: &RemoveSelectedThread,
window: &mut Window, _window: &mut Window,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) { ) {
if let Some(entry) = self.get_match(self.selected_index) { if let Some(entry) = self.get_match(self.selected_index) {
match entry { let task_result = match entry {
HistoryEntry::Thread(thread) => { HistoryEntry::Thread(thread) => self
self.assistant_panel .assistant_panel
.update(cx, |this, cx| { .update(cx, |this, cx| this.delete_thread(&thread.id, cx)),
this.delete_thread(&thread.id, cx); HistoryEntry::Context(context) => self
}) .assistant_panel
.ok(); .update(cx, |this, cx| this.delete_context(context.path.clone(), cx)),
} };
HistoryEntry::Context(context) => {
self.assistant_panel
.update(cx, |this, cx| {
this.delete_context(context.path.clone(), cx);
})
.ok();
}
}
self.update_search(window, cx); if let Some(task) = task_result.log_err() {
cx.spawn(async move |this, cx| {
task.await?;
this.update(cx, |this, cx| this.update_all_entries(cx))
})
.detach_and_log_err(cx);
};
cx.notify(); cx.notify();
} }
@ -456,14 +455,21 @@ impl RenderOnce for PastThread {
IconButton::new("delete", IconName::TrashAlt) IconButton::new("delete", IconName::TrashAlt)
.shape(IconButtonShape::Square) .shape(IconButtonShape::Square)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.tooltip(Tooltip::text("Delete Thread")) .tooltip(move |window, cx| {
Tooltip::for_action(
"Delete Thread",
&RemoveSelectedThread,
window,
cx,
)
})
.on_click({ .on_click({
let assistant_panel = self.assistant_panel.clone(); let assistant_panel = self.assistant_panel.clone();
let id = self.thread.id.clone(); let id = self.thread.id.clone();
move |_event, _window, cx| { move |_event, _window, cx| {
assistant_panel assistant_panel
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.delete_thread(&id, cx); this.delete_thread(&id, cx).detach_and_log_err(cx);
}) })
.ok(); .ok();
} }
@ -563,7 +569,8 @@ impl RenderOnce for PastContext {
move |_event, _window, cx| { move |_event, _window, cx| {
assistant_panel assistant_panel
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.delete_context(path.clone(), cx); this.delete_context(path.clone(), cx)
.detach_and_log_err(cx);
}) })
.ok(); .ok();
} }