assistant panel: Add button to open new context to configuration page (#15628)

This adds a button to the `Configuration` page for providers so it's
easy to start a new context _with the given provider_ selected.

![screenshot-2024-08-01-17 53
07@2x](https://github.com/user-attachments/assets/f25ecbe0-0b96-4a32-ac98-a5113b08ec2a)

Obviously not the most beautiful form this button can have, but works!

cc @iamnbutler 

Release Notes:

- N/A

Co-authored-by: Bennet <bennet@zed.dev>
This commit is contained in:
Thorsten Ball 2024-08-01 19:33:00 +02:00 committed by GitHub
parent 70b2da78f8
commit 5afa799f37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -46,7 +46,7 @@ use multi_buffer::MultiBufferRow;
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use project::{Project, ProjectLspAdapterDelegate}; use project::{Project, ProjectLspAdapterDelegate};
use search::{buffer_search::DivRegistrar, BufferSearchBar}; use search::{buffer_search::DivRegistrar, BufferSearchBar};
use settings::Settings; use settings::{update_settings_file, Settings};
use std::{ use std::{
borrow::Cow, borrow::Cow,
cmp::{self, Ordering}, cmp::{self, Ordering},
@ -139,6 +139,7 @@ pub struct AssistantPanel {
model_selector_menu_handle: PopoverMenuHandle<ContextMenu>, model_selector_menu_handle: PopoverMenuHandle<ContextMenu>,
model_summary_editor: View<Editor>, model_summary_editor: View<Editor>,
authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>, authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>,
configuration_subscription: Option<Subscription>,
} }
#[derive(Clone)] #[derive(Clone)]
@ -423,6 +424,7 @@ impl AssistantPanel {
model_selector_menu_handle, model_selector_menu_handle,
model_summary_editor, model_summary_editor,
authenticate_provider_task: None, authenticate_provider_task: None,
configuration_subscription: None,
}; };
if LanguageModelRegistry::read_global(cx) if LanguageModelRegistry::read_global(cx)
@ -478,6 +480,17 @@ impl AssistantPanel {
true true
} }
pane::Event::RemoveItem { idx } => {
if self
.pane
.read(cx)
.item_for_index(*idx)
.map_or(false, |item| item.downcast::<ConfigurationView>().is_some())
{
self.configuration_subscription = None;
}
false
}
pane::Event::RemovedItem { .. } => { pane::Event::RemovedItem { .. } => {
cx.emit(AssistantPanelEvent::ContextEdited); cx.emit(AssistantPanelEvent::ContextEdited);
true true
@ -546,12 +559,7 @@ impl AssistantPanel {
log::error!("no context found with ID: {}", context_id.to_proto()); log::error!("no context found with ID: {}", context_id.to_proto());
return; return;
}; };
let Some(workspace) = self.workspace.upgrade() else { let lsp_adapter_delegate = make_lsp_adapter_delegate(&self.project, cx).log_err();
return;
};
let lsp_adapter_delegate = workspace.update(cx, |workspace, cx| {
make_lsp_adapter_delegate(workspace.project(), cx).log_err()
});
let assistant_panel = cx.view().downgrade(); let assistant_panel = cx.view().downgrade();
let editor = cx.new_view(|cx| { let editor = cx.new_view(|cx| {
@ -943,6 +951,27 @@ impl AssistantPanel {
} }
view view
}); });
self.configuration_subscription = Some(cx.subscribe(
&configuration,
|this, _, event: &ConfigurationViewEvent, cx| match event {
ConfigurationViewEvent::NewProviderContextEditor(provider) => {
if LanguageModelRegistry::read_global(cx)
.active_provider()
.map_or(true, |p| p.id() != provider.id())
{
if let Some(model) = provider.provided_models(cx).first().cloned() {
update_settings_file::<AssistantSettings>(
this.fs.clone(),
cx,
move |settings, _| settings.set_model(model),
);
}
}
this.new_context(cx);
}
},
));
self.pane.update(cx, |pane, cx| { self.pane.update(cx, |pane, cx| {
pane.add_item(Box::new(configuration), true, true, None, cx); pane.add_item(Box::new(configuration), true, true, None, cx);
}); });
@ -1024,12 +1053,7 @@ impl AssistantPanel {
let project = self.project.clone(); let project = self.project.clone();
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
let lsp_adapter_delegate = workspace let lsp_adapter_delegate = make_lsp_adapter_delegate(&project, cx).log_err();
.update(cx, |workspace, cx| {
make_lsp_adapter_delegate(workspace.project(), cx).log_err()
})
.log_err()
.flatten();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let context = context.await?; let context = context.await?;
@ -1076,13 +1100,7 @@ impl AssistantPanel {
.update(cx, |store, cx| store.open_remote_context(id, cx)); .update(cx, |store, cx| store.open_remote_context(id, cx));
let fs = self.fs.clone(); let fs = self.fs.clone();
let workspace = self.workspace.clone(); let workspace = self.workspace.clone();
let lsp_adapter_delegate = make_lsp_adapter_delegate(&self.project, cx).log_err();
let lsp_adapter_delegate = workspace
.update(cx, |workspace, cx| {
make_lsp_adapter_delegate(workspace.project(), cx).log_err()
})
.log_err()
.flatten();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
let context = context.await?; let context = context.await?;
@ -3100,6 +3118,9 @@ impl ConfigurationView {
return None; return None;
}; };
let provider = active_tab.provider.clone();
let provider_name = provider.name().0.clone();
let show_spinner = active_tab.is_loading_credentials(); let show_spinner = active_tab.is_loading_credentials();
let content = if show_spinner { let content = if show_spinner {
@ -3123,6 +3144,9 @@ impl ConfigurationView {
}; };
Some( Some(
v_flex()
.gap_4()
.child(
div() div()
.p(Spacing::Large.rems(cx)) .p(Spacing::Large.rems(cx))
.bg(cx.theme().colors().title_bar_background) .bg(cx.theme().colors().title_bar_background)
@ -3131,6 +3155,31 @@ impl ConfigurationView {
.rounded_md() .rounded_md()
.child(content), .child(content),
) )
.when(
!show_spinner && provider.is_authenticated(cx),
move |this| {
this.child(
h_flex().justify_end().child(
Button::new(
"new-context",
format!("Open new context using {}", provider_name),
)
.icon_position(IconPosition::Start)
.icon(IconName::Plus)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface)
.on_click(cx.listener(
move |_, _, cx| {
cx.emit(ConfigurationViewEvent::NewProviderContextEditor(
provider.clone(),
))
},
)),
),
)
},
),
)
} }
fn render_tab( fn render_tab(
@ -3218,7 +3267,11 @@ impl Render for ConfigurationView {
} }
} }
impl EventEmitter<()> for ConfigurationView {} pub enum ConfigurationViewEvent {
NewProviderContextEditor(Arc<dyn LanguageModelProvider>),
}
impl EventEmitter<ConfigurationViewEvent> for ConfigurationView {}
impl FocusableView for ConfigurationView { impl FocusableView for ConfigurationView {
fn focus_handle(&self, _: &AppContext) -> FocusHandle { fn focus_handle(&self, _: &AppContext) -> FocusHandle {
@ -3230,7 +3283,7 @@ impl FocusableView for ConfigurationView {
} }
impl Item for ConfigurationView { impl Item for ConfigurationView {
type Event = (); type Event = ConfigurationViewEvent;
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> { fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
Some("Configuration".into()) Some("Configuration".into())