diff --git a/crates/agent/src/assistant_configuration.rs b/crates/agent/src/assistant_configuration.rs index 7616b1f8b0..18dc4b5e21 100644 --- a/crates/agent/src/assistant_configuration.rs +++ b/crates/agent/src/assistant_configuration.rs @@ -9,11 +9,14 @@ use assistant_tool::{ToolSource, ToolWorkingSet}; use collections::HashMap; use context_server::manager::ContextServerManager; use fs::Fs; -use gpui::{Action, AnyView, App, Entity, EventEmitter, FocusHandle, Focusable, Subscription}; +use gpui::{ + Action, AnyView, App, Entity, EventEmitter, FocusHandle, Focusable, ScrollHandle, Subscription, +}; use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry}; use settings::{Settings, update_settings_file}; use ui::{ - Disclosure, Divider, DividerColor, ElevationIndex, Indicator, Switch, Tooltip, prelude::*, + Disclosure, Divider, DividerColor, ElevationIndex, Indicator, Scrollbar, ScrollbarState, + Switch, Tooltip, prelude::*, }; use util::ResultExt as _; use zed_actions::ExtensionCategoryFilter; @@ -31,6 +34,8 @@ pub struct AssistantConfiguration { expanded_context_server_tools: HashMap, bool>, tools: Entity, _registry_subscription: Subscription, + scroll_handle: ScrollHandle, + scrollbar_state: ScrollbarState, } impl AssistantConfiguration { @@ -60,6 +65,9 @@ impl AssistantConfiguration { }, ); + let scroll_handle = ScrollHandle::new(); + let scrollbar_state = ScrollbarState::new(scroll_handle.clone()); + let mut this = Self { fs, focus_handle, @@ -68,6 +76,8 @@ impl AssistantConfiguration { expanded_context_server_tools: HashMap::default(), tools, _registry_subscription: registry_subscription, + scroll_handle, + scrollbar_state, }; this.build_provider_configuration_views(window, cx); this @@ -109,7 +119,7 @@ pub enum AssistantConfigurationEvent { impl EventEmitter for AssistantConfiguration {} impl AssistantConfiguration { - fn render_provider_configuration( + fn render_provider_configuration_block( &mut self, provider: &Arc, cx: &mut Context, @@ -164,7 +174,7 @@ impl AssistantConfiguration { .p(DynamicSpacing::Base08.rems(cx)) .bg(cx.theme().colors().editor_background) .border_1() - .border_color(cx.theme().colors().border_variant) + .border_color(cx.theme().colors().border) .rounded_sm() .map(|parent| match configuration_view { Some(configuration_view) => parent.child(configuration_view), @@ -175,6 +185,33 @@ impl AssistantConfiguration { ) } + fn render_provider_configuration_section( + &mut self, + cx: &mut Context, + ) -> impl IntoElement { + let providers = LanguageModelRegistry::read_global(cx).providers(); + + v_flex() + .p(DynamicSpacing::Base16.rems(cx)) + .pr(DynamicSpacing::Base20.rems(cx)) + .gap_4() + .flex_1() + .child( + v_flex() + .gap_0p5() + .child(Headline::new("LLM Providers").size(HeadlineSize::Small)) + .child( + Label::new("Add at least one provider to use AI-powered features.") + .color(Color::Muted), + ), + ) + .children( + providers + .into_iter() + .map(|provider| self.render_provider_configuration_block(&provider, cx)), + ) + } + fn render_command_permission(&mut self, cx: &mut Context) -> impl IntoElement { let always_allow_tool_actions = AssistantSettings::get_global(cx).always_allow_tool_actions; @@ -182,6 +219,7 @@ impl AssistantConfiguration { v_flex() .p(DynamicSpacing::Base16.rems(cx)) + .pr(DynamicSpacing::Base20.rems(cx)) .gap_2() .flex_1() .child(Headline::new("General Settings").size(HeadlineSize::Small)) @@ -233,6 +271,7 @@ impl AssistantConfiguration { v_flex() .p(DynamicSpacing::Base16.rems(cx)) + .pr(DynamicSpacing::Base20.rems(cx)) .gap_2() .flex_1() .child( @@ -426,39 +465,51 @@ impl AssistantConfiguration { impl Render for AssistantConfiguration { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - let providers = LanguageModelRegistry::read_global(cx).providers(); - v_flex() .id("assistant-configuration") .key_context("AgentConfiguration") .track_focus(&self.focus_handle(cx)) - .bg(cx.theme().colors().panel_background) + .relative() .size_full() - .overflow_y_scroll() - .child(self.render_command_permission(cx)) - .child(Divider::horizontal().color(DividerColor::Border)) - .child(self.render_context_servers_section(cx)) - .child(Divider::horizontal().color(DividerColor::Border)) + .pb_8() + .bg(cx.theme().colors().panel_background) .child( v_flex() - .p(DynamicSpacing::Base16.rems(cx)) - .mt_1() - .gap_6() - .flex_1() - .child( - v_flex() - .gap_0p5() - .child(Headline::new("LLM Providers").size(HeadlineSize::Small)) - .child( - Label::new("Add at least one provider to use AI-powered features.") - .color(Color::Muted), - ), - ) - .children( - providers - .into_iter() - .map(|provider| self.render_provider_configuration(&provider, cx)), - ), + .id("assistant-configuration-content") + .track_scroll(&self.scroll_handle) + .size_full() + .overflow_y_scroll() + .child(self.render_command_permission(cx)) + .child(Divider::horizontal().color(DividerColor::Border)) + .child(self.render_context_servers_section(cx)) + .child(Divider::horizontal().color(DividerColor::Border)) + .child(self.render_provider_configuration_section(cx)), + ) + .child( + div() + .id("assistant-configuration-scrollbar") + .occlude() + .absolute() + .right(px(3.)) + .top_0() + .bottom_0() + .pb_6() + .w(px(12.)) + .cursor_default() + .on_mouse_move(cx.listener(|_, _, _window, cx| { + cx.notify(); + cx.stop_propagation() + })) + .on_hover(|_, _window, cx| { + cx.stop_propagation(); + }) + .on_any_mouse_down(|_, _window, cx| { + cx.stop_propagation(); + }) + .on_scroll_wheel(cx.listener(|_, _, _window, cx| { + cx.notify(); + })) + .children(Scrollbar::vertical(self.scrollbar_state.clone())), ) } }