From ed772e6baf21ed3edf743854efb11d32e1b367dd Mon Sep 17 00:00:00 2001 From: Chris Kelly Date: Mon, 12 May 2025 01:07:30 -0700 Subject: [PATCH] agent: Allow to collapse provider sections in the settings view (#30437) This is my first time contributing, so happy to make changes as needed. ## Problem I found the LLM Provider settings to be pretty difficult to scan as I was looking to enter my API credentials for a provider. Because all of the provider configuration is exposed by default, providers that come at the end of the list are pushed fairly far down and require scrolling. As this list increases the problem only get worse. ## Solution This is strictly a UI change. * I put each provider configuration in a Disclosure that is closed by default. This made scanning for my provider easy, and exposing the configuration takes a single click. No scrolling is required to see all providers on my 956px high laptop screen. * I also added the success checkmark to authenticated providers to make it even easier to find them to update a key or sign out. * The `Start New Thread` had a class applied that was overriding the default hover behavior of other buttons, so I removed it. ## Before ![CleanShot 2025-05-09 at 14 06 04@2x](https://github.com/user-attachments/assets/48d1e7ea-0dc8-4adc-845c-5227ec965130) ## After ![CleanShot 2025-05-09 at 14 33 23](https://github.com/user-attachments/assets/67e842a7-3251-46e5-ab18-7c4e600b84d8) Release Notes: - Improved Agent Panel settings view scannability by making each provider block collapsible by default. --------- Co-authored-by: Danilo Leal --- crates/agent/src/agent_configuration.rs | 85 +++++++++++++++++-------- 1 file changed, 60 insertions(+), 25 deletions(-) diff --git a/crates/agent/src/agent_configuration.rs b/crates/agent/src/agent_configuration.rs index 253066b5518e55f402e977b08bff27ac9fb3cd8e..8b338a50e80efbe12b71a0aba2f8d82c1cbe3bba 100644 --- a/crates/agent/src/agent_configuration.rs +++ b/crates/agent/src/agent_configuration.rs @@ -36,6 +36,7 @@ pub struct AgentConfiguration { configuration_views_by_provider: HashMap, context_server_store: Entity, expanded_context_server_tools: HashMap, + expanded_provider_configurations: HashMap, tools: Entity, _registry_subscription: Subscription, scroll_handle: ScrollHandle, @@ -78,6 +79,7 @@ impl AgentConfiguration { configuration_views_by_provider: HashMap::default(), context_server_store, expanded_context_server_tools: HashMap::default(), + expanded_provider_configurations: HashMap::default(), tools, _registry_subscription: registry_subscription, scroll_handle, @@ -96,6 +98,7 @@ impl AgentConfiguration { fn remove_provider_configuration_view(&mut self, provider_id: &LanguageModelProviderId) { self.configuration_views_by_provider.remove(provider_id); + self.expanded_provider_configurations.remove(provider_id); } fn add_provider_configuration_view( @@ -135,9 +138,14 @@ impl AgentConfiguration { .get(&provider.id()) .cloned(); + let is_expanded = self + .expanded_provider_configurations + .get(&provider.id()) + .copied() + .unwrap_or(true); + v_flex() .pt_3() - .pb_1() .gap_1p5() .border_t_1() .border_color(cx.theme().colors().border.opacity(0.6)) @@ -152,32 +160,59 @@ impl AgentConfiguration { .size(IconSize::Small) .color(Color::Muted), ) - .child(Label::new(provider_name.clone()).size(LabelSize::Large)), + .child(Label::new(provider_name.clone()).size(LabelSize::Large)) + .when(provider.is_authenticated(cx) && !is_expanded, |parent| { + parent.child(Icon::new(IconName::Check).color(Color::Success)) + }), ) - .when(provider.is_authenticated(cx), |parent| { - parent.child( - Button::new( - SharedString::from(format!("new-thread-{provider_id}")), - "Start New Thread", - ) - .icon_position(IconPosition::Start) - .icon(IconName::Plus) - .icon_size(IconSize::Small) - .style(ButtonStyle::Filled) - .layer(ElevationIndex::ModalSurface) - .label_size(LabelSize::Small) - .on_click(cx.listener({ - let provider = provider.clone(); - move |_this, _event, _window, cx| { - cx.emit(AssistantConfigurationEvent::NewThread( - provider.clone(), - )) - } - })), - ) - }), + .child( + h_flex() + .gap_1() + .when(provider.is_authenticated(cx), |parent| { + parent.child( + Button::new( + SharedString::from(format!("new-thread-{provider_id}")), + "Start New Thread", + ) + .icon_position(IconPosition::Start) + .icon(IconName::Plus) + .icon_size(IconSize::Small) + .layer(ElevationIndex::ModalSurface) + .label_size(LabelSize::Small) + .on_click(cx.listener({ + let provider = provider.clone(); + move |_this, _event, _window, cx| { + cx.emit(AssistantConfigurationEvent::NewThread( + provider.clone(), + )) + } + })), + ) + }) + .child( + Disclosure::new( + SharedString::from(format!( + "provider-disclosure-{provider_id}" + )), + is_expanded, + ) + .opened_icon(IconName::ChevronUp) + .closed_icon(IconName::ChevronDown) + .on_click(cx.listener({ + let provider_id = provider.id().clone(); + move |this, _event, _window, _cx| { + let is_open = this + .expanded_provider_configurations + .entry(provider_id.clone()) + .or_insert(true); + + *is_open = !*is_open; + } + })), + ), + ), ) - .map(|parent| match configuration_view { + .when(is_expanded, |parent| match configuration_view { Some(configuration_view) => parent.child(configuration_view), None => parent.child(div().child(Label::new(format!( "No configuration view for {provider_name}",