mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-21 03:18:47 +03:00
assistant2: Render saved conversations inline instead of in a modal (#11630)
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: <img width="402" alt="Screenshot 2024-05-09 at 6 18 40 PM" src="https://github.com/zed-industries/zed/assets/1486634/82decc04-cb31-4d83-a942-7e8426e02679"> Release Notes: - N/A
This commit is contained in:
parent
a3e75540af
commit
27ed0f4273
@ -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<Client>, cx: &mut AppContext) {
|
||||
@ -109,8 +102,6 @@ pub fn init(client: Arc<Client>, 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<dyn Fs>,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
composer_editor: View<Editor>,
|
||||
saved_conversations: View<SavedConversations>,
|
||||
saved_conversations_open: bool,
|
||||
project_index_button: View<ProjectIndexButton>,
|
||||
active_file_button: Option<View<ActiveFileButton>>,
|
||||
user_store: Model<UserStore>,
|
||||
@ -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<Self>) {
|
||||
// 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(),
|
||||
|
@ -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<Picker<SavedConversationPickerDelegate>>,
|
||||
pub struct SavedConversations {
|
||||
focus_handle: FocusHandle,
|
||||
picker: Option<View<Picker<SavedConversationPickerDelegate>>>,
|
||||
}
|
||||
|
||||
impl EventEmitter<DismissEvent> for SavedConversationPicker {}
|
||||
impl EventEmitter<DismissEvent> 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>) {
|
||||
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 {
|
||||
Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
picker: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(delegate: SavedConversationPickerDelegate, cx: &mut ViewContext<Self>) -> Self {
|
||||
let picker = cx.new_view(|cx| Picker::uniform_list(delegate, cx));
|
||||
Self { picker }
|
||||
pub fn init(
|
||||
&mut self,
|
||||
saved_conversations: Vec<SavedConversationMetadata>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
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<Self>) -> impl IntoElement {
|
||||
v_flex().w(rems(34.)).child(self.picker.clone())
|
||||
impl Render for SavedConversations {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.w_full()
|
||||
.bg(cx.theme().colors().panel_background)
|
||||
.children(self.picker.clone())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SavedConversationPickerDelegate {
|
||||
view: WeakView<SavedConversationPicker>,
|
||||
view: WeakView<SavedConversations>,
|
||||
saved_conversations: Vec<SavedConversationMetadata>,
|
||||
selected_index: usize,
|
||||
matches: Vec<StringMatch>,
|
||||
@ -71,7 +62,7 @@ pub struct SavedConversationPickerDelegate {
|
||||
|
||||
impl SavedConversationPickerDelegate {
|
||||
pub fn new(
|
||||
weak_view: WeakView<SavedConversationPicker>,
|
||||
weak_view: WeakView<SavedConversations>,
|
||||
saved_conversations: Vec<SavedConversationMetadata>,
|
||||
) -> 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(
|
Loading…
Reference in New Issue
Block a user