assistant2: Tweak the settings UI (#23845)

This PR does some somewhat light UI adjustment to the Assistant 2
settings view. The Prompt Library section should feature the default
prompts in the future, so that's why it's been separated that way.

<img width="800" alt="Screenshot 2025-01-29 at 2 59 59 PM"
src="https://github.com/user-attachments/assets/7b033bde-51ab-44d5-9e53-3f72b8ff5f51"
/>

Release Notes:

- N/A
This commit is contained in:
Danilo Leal 2025-01-29 16:20:09 -03:00 committed by GitHub
parent a03b7624f1
commit f8dddf0a5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 82 additions and 50 deletions

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use collections::HashMap; use collections::HashMap;
use gpui::{AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription}; use gpui::{AnyView, App, EventEmitter, FocusHandle, Focusable, Subscription};
use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry}; use language_model::{LanguageModelProvider, LanguageModelProviderId, LanguageModelRegistry};
use ui::{prelude::*, ElevationIndex}; use ui::{prelude::*, Divider, DividerColor, ElevationIndex};
use zed_actions::assistant::DeployPromptLibrary; use zed_actions::assistant::DeployPromptLibrary;
pub struct AssistantConfiguration { pub struct AssistantConfiguration {
@ -91,22 +91,32 @@ impl AssistantConfiguration {
.cloned(); .cloned();
v_flex() v_flex()
.gap_2() .gap_1p5()
.child( .child(
h_flex() h_flex()
.justify_between() .justify_between()
.child(Headline::new(provider_name.clone()).size(HeadlineSize::Small)) .child(
h_flex()
.gap_2()
.child(
Icon::new(provider.icon())
.size(IconSize::Small)
.color(Color::Muted),
)
.child(Label::new(provider_name.clone())),
)
.when(provider.is_authenticated(cx), |parent| { .when(provider.is_authenticated(cx), |parent| {
parent.child( parent.child(
h_flex().justify_end().child(
Button::new( Button::new(
SharedString::from(format!("new-thread-{provider_id}")), SharedString::from(format!("new-thread-{provider_id}")),
"Open New Thread", "Start New Thread",
) )
.icon_position(IconPosition::Start) .icon_position(IconPosition::Start)
.icon(IconName::Plus) .icon(IconName::Plus)
.icon_size(IconSize::Small)
.style(ButtonStyle::Filled) .style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface) .layer(ElevationIndex::ModalSurface)
.label_size(LabelSize::Small)
.on_click(cx.listener({ .on_click(cx.listener({
let provider = provider.clone(); let provider = provider.clone();
move |_this, _event, _window, cx| { move |_this, _event, _window, cx| {
@ -115,14 +125,13 @@ impl AssistantConfiguration {
)) ))
} }
})), })),
),
) )
}), }),
) )
.child( .child(
div() div()
.p(DynamicSpacing::Base08.rems(cx)) .p(DynamicSpacing::Base08.rems(cx))
.bg(cx.theme().colors().surface_background) .bg(cx.theme().colors().editor_background)
.border_1() .border_1()
.border_color(cx.theme().colors().border_variant) .border_color(cx.theme().colors().border_variant)
.rounded_md() .rounded_md()
@ -143,26 +152,43 @@ impl Render for AssistantConfiguration {
v_flex() v_flex()
.id("assistant-configuration") .id("assistant-configuration")
.track_focus(&self.focus_handle(cx)) .track_focus(&self.focus_handle(cx))
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().panel_background)
.size_full() .size_full()
.overflow_y_scroll() .overflow_y_scroll()
.child( .child(
h_flex().p(DynamicSpacing::Base16.rems(cx)).child( v_flex()
.p(DynamicSpacing::Base16.rems(cx))
.gap_1()
.child(Headline::new("Prompt Library").size(HeadlineSize::Small))
.child(
Button::new("open-prompt-library", "Open Prompt Library") Button::new("open-prompt-library", "Open Prompt Library")
.style(ButtonStyle::Filled) .style(ButtonStyle::Filled)
.layer(ElevationIndex::ModalSurface)
.full_width() .full_width()
.icon(IconName::Book) .icon(IconName::Book)
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.icon_position(IconPosition::Start) .icon_position(IconPosition::Start)
.on_click(|_event, _window, cx| cx.dispatch_action(&DeployPromptLibrary)), .on_click(|_event, _window, cx| {
cx.dispatch_action(&DeployPromptLibrary)
}),
), ),
) )
.child(Divider::horizontal().color(DividerColor::Border))
.child( .child(
v_flex() v_flex()
.p(DynamicSpacing::Base16.rems(cx)) .p(DynamicSpacing::Base16.rems(cx))
.mt_1() .mt_1()
.gap_6() .gap_6()
.flex_1() .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( .children(
providers providers
.into_iter() .into_iter()

View file

@ -613,7 +613,7 @@ impl AssistantPanel {
}) })
.unwrap_or_else(|| SharedString::from("Loading Summary…")), .unwrap_or_else(|| SharedString::from("Loading Summary…")),
ActiveView::History | ActiveView::PromptEditorHistory => "History".into(), ActiveView::History | ActiveView::PromptEditorHistory => "History".into(),
ActiveView::Configuration => "Configuration".into(), ActiveView::Configuration => "Assistant Settings".into(),
}; };
let sub_title = match self.active_view { let sub_title = match self.active_view {
@ -700,7 +700,7 @@ impl AssistantPanel {
IconButton::new("configure-assistant", IconName::Settings) IconButton::new("configure-assistant", IconName::Settings)
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.tooltip(Tooltip::text("Configure Assistant")) .tooltip(Tooltip::text("Assistant Settings"))
.on_click(move |_event, window, cx| { .on_click(move |_event, window, cx| {
window.dispatch_action(OpenConfiguration.boxed_clone(), cx); window.dispatch_action(OpenConfiguration.boxed_clone(), cx);
}), }),

View file

@ -689,7 +689,7 @@ impl Render for ConfigurationView {
.child(h_flex().child(Label::new(INSTRUCTIONS[1])).child( .child(h_flex().child(Label::new(INSTRUCTIONS[1])).child(
Button::new("anthropic_console", ANTHROPIC_CONSOLE_URL) Button::new("anthropic_console", ANTHROPIC_CONSOLE_URL)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| cx.open_url(ANTHROPIC_CONSOLE_URL)) .on_click(move |_, _, cx| cx.open_url(ANTHROPIC_CONSOLE_URL))
@ -703,6 +703,8 @@ impl Render for ConfigurationView {
.px_2() .px_2()
.py_1() .py_1()
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md() .rounded_md()
.child(self.render_api_key_editor(cx)), .child(self.render_api_key_editor(cx)),
) )

View file

@ -506,7 +506,7 @@ impl Render for ConfigurationView {
h_flex().child(Label::new(INSTRUCTIONS[1])).child( h_flex().child(Label::new(INSTRUCTIONS[1])).child(
Button::new("deepseek_console", DEEPSEEK_CONSOLE_URL) Button::new("deepseek_console", DEEPSEEK_CONSOLE_URL)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _window, cx| cx.open_url(DEEPSEEK_CONSOLE_URL)), .on_click(move |_, _window, cx| cx.open_url(DEEPSEEK_CONSOLE_URL)),
@ -520,12 +520,14 @@ impl Render for ConfigurationView {
.px_2() .px_2()
.py_1() .py_1()
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md() .rounded_md()
.child(self.render_api_key_editor(cx)), .child(self.render_api_key_editor(cx)),
) )
.child( .child(
Label::new(format!( Label::new(format!(
"Or set {} environment variable", "Or set the {} environment variable.",
DEEPSEEK_API_KEY_VAR DEEPSEEK_API_KEY_VAR
)) ))
.size(LabelSize::Small), .size(LabelSize::Small),

View file

@ -452,7 +452,7 @@ impl Render for ConfigurationView {
.child(h_flex().child(Label::new(INSTRUCTIONS[1])).child( .child(h_flex().child(Label::new(INSTRUCTIONS[1])).child(
Button::new("google_console", GOOGLE_CONSOLE_URL) Button::new("google_console", GOOGLE_CONSOLE_URL)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| cx.open_url(GOOGLE_CONSOLE_URL)) .on_click(move |_, _, cx| cx.open_url(GOOGLE_CONSOLE_URL))
@ -466,6 +466,8 @@ impl Render for ConfigurationView {
.px_2() .px_2()
.py_1() .py_1()
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md() .rounded_md()
.child(self.render_api_key_editor(cx)), .child(self.render_api_key_editor(cx)),
) )

View file

@ -413,8 +413,7 @@ impl Render for ConfigurationView {
let lmstudio_reqs = let lmstudio_reqs =
"To use LM Studio as a provider for Zed assistant, it needs to be running with at least one model downloaded."; "To use LM Studio as a provider for Zed assistant, it needs to be running with at least one model downloaded.";
let mut inline_code_bg = cx.theme().colors().editor_background; let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05);
inline_code_bg.fade_out(0.5);
if self.loading_models_task.is_some() { if self.loading_models_task.is_some() {
div().child(Label::new("Loading models...")).into_any() div().child(Label::new("Loading models...")).into_any()
@ -432,7 +431,7 @@ impl Render for ConfigurationView {
.child( .child(
h_flex() h_flex()
.gap_0p5() .gap_0p5()
.child(Label::new("To get your first model, try running ")) .child(Label::new("To get your first model, try running"))
.child( .child(
div() div()
.bg(inline_code_bg) .bg(inline_code_bg)
@ -457,7 +456,7 @@ impl Render for ConfigurationView {
this.child( this.child(
Button::new("lmstudio-site", "LM Studio") Button::new("lmstudio-site", "LM Studio")
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _window, cx| { .on_click(move |_, _window, cx| {
@ -472,7 +471,7 @@ impl Render for ConfigurationView {
"Download LM Studio", "Download LM Studio",
) )
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _window, cx| { .on_click(move |_, _window, cx| {
@ -485,7 +484,7 @@ impl Render for ConfigurationView {
.child( .child(
Button::new("view-models", "Model Catalog") Button::new("view-models", "Model Catalog")
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _window, cx| { .on_click(move |_, _window, cx| {

View file

@ -452,8 +452,7 @@ impl Render for ConfigurationView {
let ollama_reqs = let ollama_reqs =
"Ollama must be running with at least one model installed to use it in the assistant."; "Ollama must be running with at least one model installed to use it in the assistant.";
let mut inline_code_bg = cx.theme().colors().editor_background; let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05);
inline_code_bg.fade_out(0.5);
if self.loading_models_task.is_some() { if self.loading_models_task.is_some() {
div().child(Label::new("Loading models...")).into_any() div().child(Label::new("Loading models...")).into_any()
@ -496,7 +495,7 @@ impl Render for ConfigurationView {
this.child( this.child(
Button::new("ollama-site", "Ollama") Button::new("ollama-site", "Ollama")
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| cx.open_url(OLLAMA_SITE)) .on_click(move |_, _, cx| cx.open_url(OLLAMA_SITE))
@ -509,7 +508,7 @@ impl Render for ConfigurationView {
"Download Ollama", "Download Ollama",
) )
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| { .on_click(move |_, _, cx| {
@ -522,7 +521,7 @@ impl Render for ConfigurationView {
.child( .child(
Button::new("view-models", "All Models") Button::new("view-models", "All Models")
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| cx.open_url(OLLAMA_LIBRARY_URL)), .on_click(move |_, _, cx| cx.open_url(OLLAMA_LIBRARY_URL)),

View file

@ -502,7 +502,7 @@ impl Render for ConfigurationView {
.child(h_flex().child(Label::new(INSTRUCTIONS[1])).child( .child(h_flex().child(Label::new(INSTRUCTIONS[1])).child(
Button::new("openai_console", OPENAI_CONSOLE_URL) Button::new("openai_console", OPENAI_CONSOLE_URL)
.style(ButtonStyle::Subtle) .style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink) .icon(IconName::ArrowUpRight)
.icon_size(IconSize::XSmall) .icon_size(IconSize::XSmall)
.icon_color(Color::Muted) .icon_color(Color::Muted)
.on_click(move |_, _, cx| cx.open_url(OPENAI_CONSOLE_URL)) .on_click(move |_, _, cx| cx.open_url(OPENAI_CONSOLE_URL))
@ -518,6 +518,8 @@ impl Render for ConfigurationView {
.px_2() .px_2()
.py_1() .py_1()
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().editor_background)
.border_1()
.border_color(cx.theme().colors().border_variant)
.rounded_md() .rounded_md()
.child(self.render_api_key_editor(cx)), .child(self.render_api_key_editor(cx)),
) )