From 27ed0f42733471df0920cd0eb277309efa690c22 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 9 May 2024 18:29:08 -0400 Subject: [PATCH] assistant2: Render saved conversations inline instead of in a modal (#11630) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR reworks how saved conversations are rendered in the new assistant panel. Instead of rendering them in a modal we now display them in the panel itself: Screenshot 2024-05-09 at 6 18 40 PM Release Notes: - N/A --- crates/assistant2/src/assistant2.rs | 76 +++++++++++++------ ...ation_picker.rs => saved_conversations.rs} | 74 ++++++++---------- 2 files changed, 83 insertions(+), 67 deletions(-) rename crates/assistant2/src/{saved_conversation_picker.rs => saved_conversations.rs} (70%) diff --git a/crates/assistant2/src/assistant2.rs b/crates/assistant2/src/assistant2.rs index f54dd3b7d102da11f38152b01af64734d9402696..41b426e0846941b64e4b041ac1d740c1188ed608 100644 --- a/crates/assistant2/src/assistant2.rs +++ b/crates/assistant2/src/assistant2.rs @@ -2,10 +2,11 @@ mod assistant_settings; mod attachments; mod completion_provider; mod saved_conversation; -mod saved_conversation_picker; +mod saved_conversations; mod tools; pub mod ui; +use crate::saved_conversation::SavedConversationMetadata; use crate::ui::UserOrAssistant; use ::ui::{div, prelude::*, Color, Tooltip, ViewContext}; use anyhow::{Context, Result}; @@ -29,7 +30,7 @@ use language::{language_settings::SoftWrap, LanguageRegistry}; use open_ai::{FunctionContent, ToolCall, ToolCallContent}; use rich_text::RichText; use saved_conversation::{SavedAssistantMessagePart, SavedChatMessage, SavedConversation}; -use saved_conversation_picker::SavedConversationPicker; +use saved_conversations::SavedConversations; use semantic_index::{CloudEmbeddingProvider, ProjectIndex, ProjectIndexDebugView, SemanticIndex}; use serde::{Deserialize, Serialize}; use settings::Settings; @@ -61,15 +62,7 @@ pub enum SubmitMode { Codebase, } -gpui::actions!( - assistant2, - [ - Cancel, - ToggleFocus, - DebugProjectIndex, - ToggleSavedConversations - ] -); +gpui::actions!(assistant2, [Cancel, ToggleFocus, DebugProjectIndex,]); gpui::impl_actions!(assistant2, [Submit]); pub fn init(client: Arc, cx: &mut AppContext) { @@ -109,8 +102,6 @@ pub fn init(client: Arc, cx: &mut AppContext) { }, ) .detach(); - cx.observe_new_views(SavedConversationPicker::register) - .detach(); } pub fn enabled(cx: &AppContext) -> bool { @@ -262,6 +253,8 @@ pub struct AssistantChat { fs: Arc, language_registry: Arc, composer_editor: View, + saved_conversations: View, + saved_conversations_open: bool, project_index_button: View, active_file_button: Option>, user_store: Model, @@ -317,6 +310,24 @@ impl AssistantChat { _ => None, }; + let saved_conversations = cx.new_view(|cx| SavedConversations::new(cx)); + cx.spawn({ + let fs = fs.clone(); + let saved_conversations = saved_conversations.downgrade(); + |_assistant_chat, mut cx| async move { + let saved_conversation_metadata = SavedConversationMetadata::list(fs).await?; + + cx.update(|cx| { + saved_conversations.update(cx, |this, cx| { + this.init(saved_conversation_metadata, cx); + }) + })??; + + anyhow::Ok(()) + } + }) + .detach_and_log_err(cx); + Self { model, messages: Vec::new(), @@ -326,6 +337,8 @@ impl AssistantChat { editor.set_placeholder_text("Send a message…", cx); editor }), + saved_conversations, + saved_conversations_open: false, list_state, user_store, fs, @@ -357,6 +370,10 @@ impl AssistantChat { }) } + fn toggle_saved_conversations(&mut self) { + self.saved_conversations_open = !self.saved_conversations_open; + } + fn cancel(&mut self, _: &Cancel, cx: &mut ViewContext) { // If we're currently editing a message, cancel the edit. if let Some(editing_message) = self.editing_message.take() { @@ -1017,18 +1034,18 @@ impl Render for AssistantChat { .h(header_height) .p(Spacing::Small.rems(cx)) .child( - IconButton::new("open-saved-conversations", IconName::ChevronLeft) - .on_click(|_event, cx| { - cx.dispatch_action(Box::new(ToggleSavedConversations)) - }) - .tooltip(move |cx| { - Tooltip::with_meta( - "Switch Conversations", - Some(&ToggleSavedConversations), - "UI will change, temporary.", - cx, - ) - }), + IconButton::new( + "toggle-saved-conversations", + if self.saved_conversations_open { + IconName::ChevronRight + } else { + IconName::ChevronLeft + }, + ) + .on_click(cx.listener(|this, _event, _cx| { + this.toggle_saved_conversations(); + })) + .tooltip(move |cx| Tooltip::text("Switch Conversations", cx)), ) .child( h_flex() @@ -1052,6 +1069,15 @@ impl Render for AssistantChat { ), ), ) + .when(self.saved_conversations_open, |element| { + element.child( + h_flex() + .absolute() + .top(header_height) + .w_full() + .child(self.saved_conversations.clone()), + ) + }) .child(Composer::new( self.composer_editor.clone(), self.project_index_button.clone(), diff --git a/crates/assistant2/src/saved_conversation_picker.rs b/crates/assistant2/src/saved_conversations.rs similarity index 70% rename from crates/assistant2/src/saved_conversation_picker.rs rename to crates/assistant2/src/saved_conversations.rs index 17962cb1f35aa379de58e6c9cbb7e305f823b130..4ddb90d7e4a839a6f87a62c38806ea5483ef63d2 100644 --- a/crates/assistant2/src/saved_conversation_picker.rs +++ b/crates/assistant2/src/saved_conversations.rs @@ -5,65 +5,56 @@ use gpui::{AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, V use picker::{Picker, PickerDelegate}; use ui::{prelude::*, HighlightedLabel, ListItem, ListItemSpacing}; use util::ResultExt; -use workspace::{ModalView, Workspace}; use crate::saved_conversation::SavedConversationMetadata; -use crate::ToggleSavedConversations; -pub struct SavedConversationPicker { - picker: View>, +pub struct SavedConversations { + focus_handle: FocusHandle, + picker: Option>>, } -impl EventEmitter for SavedConversationPicker {} +impl EventEmitter for SavedConversations {} -impl ModalView for SavedConversationPicker {} - -impl FocusableView for SavedConversationPicker { +impl FocusableView for SavedConversations { fn focus_handle(&self, cx: &AppContext) -> FocusHandle { - self.picker.focus_handle(cx) + if let Some(picker) = self.picker.as_ref() { + picker.focus_handle(cx) + } else { + self.focus_handle.clone() + } } } -impl SavedConversationPicker { - pub fn register(workspace: &mut Workspace, _cx: &mut ViewContext) { - workspace.register_action(|workspace, _: &ToggleSavedConversations, cx| { - let fs = workspace.project().read(cx).fs().clone(); - - cx.spawn(|workspace, mut cx| async move { - let saved_conversations = SavedConversationMetadata::list(fs).await?; - - cx.update(|cx| { - workspace.update(cx, |workspace, cx| { - workspace.toggle_modal(cx, move |cx| { - let delegate = SavedConversationPickerDelegate::new( - cx.view().downgrade(), - saved_conversations, - ); - Self::new(delegate, cx) - }); - }) - })??; - - anyhow::Ok(()) - }) - .detach_and_log_err(cx); - }); +impl SavedConversations { + pub fn new(cx: &mut ViewContext) -> Self { + Self { + focus_handle: cx.focus_handle(), + picker: None, + } } - pub fn new(delegate: SavedConversationPickerDelegate, cx: &mut ViewContext) -> Self { - let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx)); - Self { picker } + pub fn init( + &mut self, + saved_conversations: Vec, + cx: &mut ViewContext, + ) { + let delegate = + SavedConversationPickerDelegate::new(cx.view().downgrade(), saved_conversations); + self.picker = Some(cx.new_view(|cx| Picker::uniform_list(delegate, cx).modal(false))); } } -impl Render for SavedConversationPicker { - fn render(&mut self, _cx: &mut ViewContext) -> impl IntoElement { - v_flex().w(rems(34.)).child(self.picker.clone()) +impl Render for SavedConversations { + fn render(&mut self, cx: &mut ViewContext) -> impl IntoElement { + v_flex() + .w_full() + .bg(cx.theme().colors().panel_background) + .children(self.picker.clone()) } } pub struct SavedConversationPickerDelegate { - view: WeakView, + view: WeakView, saved_conversations: Vec, selected_index: usize, matches: Vec, @@ -71,7 +62,7 @@ pub struct SavedConversationPickerDelegate { impl SavedConversationPickerDelegate { pub fn new( - weak_view: WeakView, + weak_view: WeakView, saved_conversations: Vec, ) -> Self { let matches = saved_conversations @@ -194,7 +185,6 @@ impl PickerDelegate for SavedConversationPickerDelegate { Some( ListItem::new(ix) - .inset(true) .spacing(ListItemSpacing::Sparse) .selected(selected) .child(HighlightedLabel::new(