From e27f6a984f1f8c10af1945e7d84e54980de115c8 Mon Sep 17 00:00:00 2001
From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Date: Fri, 18 Apr 2025 14:24:53 -0300
Subject: [PATCH] agent: Simplify design of the settings view (#29041)
Containing everything in boxes wasn't super necessary here. Want to
still improve the switch color contrast here, but will probably do that
in a separate PR.
Release Notes:
- N/A
---
crates/agent/src/assistant_configuration.rs | 76 +++++++----------
.../language_models/src/provider/anthropic.rs | 12 ++-
.../language_models/src/provider/bedrock.rs | 45 +++++-----
.../src/provider/copilot_chat.rs | 83 +++++++-----------
.../language_models/src/provider/deepseek.rs | 16 +++-
crates/language_models/src/provider/google.rs | 12 ++-
.../language_models/src/provider/lmstudio.rs | 83 ++++++++----------
.../language_models/src/provider/mistral.rs | 12 ++-
crates/language_models/src/provider/ollama.rs | 85 ++++++++-----------
.../language_models/src/provider/open_ai.rs | 12 ++-
crates/markdown/src/markdown.rs | 5 --
11 files changed, 205 insertions(+), 236 deletions(-)
diff --git a/crates/agent/src/assistant_configuration.rs b/crates/agent/src/assistant_configuration.rs
index 18dc4b5e21..33b97a771e 100644
--- a/crates/agent/src/assistant_configuration.rs
+++ b/crates/agent/src/assistant_configuration.rs
@@ -132,7 +132,11 @@ impl AssistantConfiguration {
.cloned();
v_flex()
+ .pt_3()
+ .pb_1()
.gap_1p5()
+ .border_t_1()
+ .border_color(cx.theme().colors().border.opacity(0.6))
.child(
h_flex()
.justify_between()
@@ -144,7 +148,7 @@ impl AssistantConfiguration {
.size(IconSize::Small)
.color(Color::Muted),
)
- .child(Label::new(provider_name.clone())),
+ .child(Label::new(provider_name.clone()).size(LabelSize::Large)),
)
.when(provider.is_authenticated(cx), |parent| {
parent.child(
@@ -169,20 +173,12 @@ impl AssistantConfiguration {
)
}),
)
- .child(
- div()
- .p(DynamicSpacing::Base08.rems(cx))
- .bg(cx.theme().colors().editor_background)
- .border_1()
- .border_color(cx.theme().colors().border)
- .rounded_sm()
- .map(|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}",
- )))),
- }),
- )
+ .map(|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}",
+ )))),
+ })
}
fn render_provider_configuration_section(
@@ -199,7 +195,7 @@ impl AssistantConfiguration {
.child(
v_flex()
.gap_0p5()
- .child(Headline::new("LLM Providers").size(HeadlineSize::Small))
+ .child(Headline::new("LLM Providers"))
.child(
Label::new("Add at least one provider to use AI-powered features.")
.color(Color::Muted),
@@ -215,21 +211,16 @@ impl AssistantConfiguration {
fn render_command_permission(&mut self, cx: &mut Context) -> impl IntoElement {
let always_allow_tool_actions = AssistantSettings::get_global(cx).always_allow_tool_actions;
- const HEADING: &str = "Allow running tools without asking for confirmation";
+ const HEADING: &str = "Allow running editing tools without asking for confirmation";
v_flex()
.p(DynamicSpacing::Base16.rems(cx))
.pr(DynamicSpacing::Base20.rems(cx))
.gap_2()
.flex_1()
- .child(Headline::new("General Settings").size(HeadlineSize::Small))
+ .child(Headline::new("General Settings"))
.child(
h_flex()
- .p_2p5()
- .rounded_sm()
- .bg(cx.theme().colors().editor_background)
- .border_1()
- .border_color(cx.theme().colors().border)
.gap_4()
.justify_between()
.flex_wrap()
@@ -277,10 +268,7 @@ impl AssistantConfiguration {
.child(
v_flex()
.gap_0p5()
- .child(
- Headline::new("Model Context Protocol (MCP) Servers")
- .size(HeadlineSize::Small),
- )
+ .child(Headline::new("Model Context Protocol (MCP) Servers"))
.child(Label::new(SUBHEADING).color(Color::Muted)),
)
.children(context_servers.into_iter().map(|context_server| {
@@ -301,9 +289,9 @@ impl AssistantConfiguration {
v_flex()
.id(SharedString::from(context_server.id()))
.border_1()
- .rounded_sm()
+ .rounded_md()
.border_color(cx.theme().colors().border)
- .bg(cx.theme().colors().editor_background)
+ .bg(cx.theme().colors().background.opacity(0.25))
.child(
h_flex()
.p_1()
@@ -386,34 +374,28 @@ impl AssistantConfiguration {
return parent;
}
- parent.child(v_flex().children(tools.into_iter().enumerate().map(
- |(ix, tool)| {
+ parent.child(v_flex().py_1p5().px_1().gap_1().children(
+ tools.into_iter().enumerate().map(|(ix, tool)| {
h_flex()
- .id("tool-item")
- .pl_2()
- .pr_1()
- .py_1()
+ .id(("tool-item", ix))
+ .px_1()
.gap_2()
.justify_between()
- .when(ix < tool_count - 1, |element| {
- element
- .border_b_1()
- .border_color(cx.theme().colors().border_variant)
- })
+ .hover(|style| style.bg(cx.theme().colors().element_hover))
+ .rounded_sm()
.child(
Label::new(tool.name())
.buffer_font(cx)
.size(LabelSize::Small),
)
.child(
- IconButton::new(("tool-description", ix), IconName::Info)
- .shape(ui::IconButtonShape::Square)
- .icon_size(IconSize::Small)
- .icon_color(Color::Ignored)
- .tooltip(Tooltip::text(tool.description())),
+ Icon::new(IconName::Info)
+ .size(IconSize::Small)
+ .color(Color::Ignored),
)
- },
- )))
+ .tooltip(Tooltip::text(tool.description()))
+ }),
+ ))
})
}))
.child(
diff --git a/crates/language_models/src/provider/anthropic.rs b/crates/language_models/src/provider/anthropic.rs
index ee0f941afa..da796a3f2b 100644
--- a/crates/language_models/src/provider/anthropic.rs
+++ b/crates/language_models/src/provider/anthropic.rs
@@ -934,7 +934,7 @@ impl Render for ConfigurationView {
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border_variant)
+ .border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
@@ -948,8 +948,13 @@ impl Render for ConfigurationView {
.into_any()
} else {
h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -961,7 +966,8 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset key")
+ Button::new("reset-key", "Reset Key")
+ .label_size(LabelSize::Small)
.icon(Some(IconName::Trash))
.icon_size(IconSize::Small)
.icon_position(IconPosition::Start)
diff --git a/crates/language_models/src/provider/bedrock.rs b/crates/language_models/src/provider/bedrock.rs
index aa603534e0..48b7e62757 100644
--- a/crates/language_models/src/provider/bedrock.rs
+++ b/crates/language_models/src/provider/bedrock.rs
@@ -1145,7 +1145,7 @@ impl ConfigurationView {
fn make_input_styles(&self, cx: &Context) -> Div {
let bg_color = cx.theme().colors().editor_background;
- let border_color = cx.theme().colors().border_variant;
+ let border_color = cx.theme().colors().border;
h_flex()
.w_full()
@@ -1173,8 +1173,13 @@ impl Render for ConfigurationView {
if let Some(auth) = self.should_render_editor(cx) {
return h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -1186,16 +1191,16 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset key")
+ Button::new("reset-key", "Reset Key")
.icon(Some(IconName::Trash))
.icon_size(IconSize::Small)
.icon_position(IconPosition::Start)
- .disabled(env_var_set || creds_type)
+ // .disabled(env_var_set || creds_type)
.when(env_var_set, |this| {
this.tooltip(Tooltip::text(format!("To reset your credentials, unset the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR}, and {ZED_BEDROCK_REGION_VAR} environment variables.")))
})
.when(creds_type, |this| {
- this.tooltip(Tooltip::text("You cannot reset credentials as they're being derived, check Zed settings to understand how"))
+ this.tooltip(Tooltip::text("You cannot reset credentials as they're being derived, check Zed settings to understand how."))
})
.on_click(cx.listener(|this, _, window, cx| this.reset_credentials(window, cx))),
)
@@ -1206,19 +1211,19 @@ impl Render for ConfigurationView {
.size_full()
.on_action(cx.listener(ConfigurationView::save_credentials))
.child(Label::new("To use Zed's assistant with Bedrock, you can set a custom authentication strategy through the settings.json, or use static credentials."))
- .child(Label::new("Though to access models on AWS first, you will have to: "))
+ .child(Label::new("But, to access models on AWS, you need to:").mt_1())
.child(
List::new()
.child(
InstructionListItem::new(
- "Grant permissions to the strategy you plan to use according to this documentation: ",
+ "Grant permissions to the strategy you'll use according to the:",
Some("Prerequisites"),
Some("https://docs.aws.amazon.com/bedrock/latest/userguide/inference-prereq.html"),
)
)
.child(
InstructionListItem::new(
- "Select the models you would like access to: ",
+ "Select the models you would like access to:",
Some("Bedrock Model Catalog"),
Some("https://us-east-1.console.aws.amazon.com/bedrock/home?region=us-east-1#/modelaccess"),
)
@@ -1228,7 +1233,15 @@ impl Render for ConfigurationView {
.child(self.render_common_fields(cx))
.child(
Label::new(
- format!("You can also assign the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR} AND {ZED_BEDROCK_REGION_VAR} environment variables and restart Zed.\n Optionally, if your environment uses AWS CLI profiles, you can set {ZED_AWS_PROFILE_VAR}; if it requires a custom endpoint, you can set {ZED_AWS_ENDPOINT_VAR}; and if it requires a Session Token, you can set {ZED_BEDROCK_SESSION_TOKEN_VAR}."),
+ format!("You can also assign the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR} AND {ZED_BEDROCK_REGION_VAR} environment variables and restart Zed."),
+ )
+ .size(LabelSize::Small)
+ .color(Color::Muted)
+ .my_1(),
+ )
+ .child(
+ Label::new(
+ format!("Optionally, if your environment uses AWS CLI profiles, you can set {ZED_AWS_PROFILE_VAR}; if it requires a custom endpoint, you can set {ZED_AWS_ENDPOINT_VAR}; and if it requires a Session Token, you can set {ZED_BEDROCK_SESSION_TOKEN_VAR}."),
)
.size(LabelSize::Small)
.color(Color::Muted),
@@ -1307,7 +1320,6 @@ impl ConfigurationView {
Label::new(
"This method uses your AWS access key ID and secret access key directly.",
)
- .size(LabelSize::Small),
)
.child(
List::new()
@@ -1357,16 +1369,11 @@ impl ConfigurationView {
fn render_common_fields(&self, cx: &mut Context) -> AnyElement {
v_flex()
- .my_2()
- .gap_1p5()
+ .gap_0p5()
+ .child(Label::new("Region").size(LabelSize::Small))
.child(
- v_flex()
- .gap_0p5()
- .child(Label::new("Region").size(LabelSize::Small))
- .child(
- self.make_input_styles(cx)
- .child(self.render_region_editor(cx)),
- ),
+ self.make_input_styles(cx)
+ .child(self.render_region_editor(cx)),
)
.into_any_element()
}
diff --git a/crates/language_models/src/provider/copilot_chat.rs b/crates/language_models/src/provider/copilot_chat.rs
index 3951e69d5d..39c005babc 100644
--- a/crates/language_models/src/provider/copilot_chat.rs
+++ b/crates/language_models/src/provider/copilot_chat.rs
@@ -530,60 +530,51 @@ impl ConfigurationView {
}
impl Render for ConfigurationView {
- fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement {
+ fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement {
if self.state.read(cx).is_authenticated(cx) {
- const LABEL: &str = "Authorized.";
h_flex()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
.child(Icon::new(IconName::Check).color(Color::Success))
- .child(Label::new(LABEL)),
+ .child(Label::new("Authorized")),
)
.child(
Button::new("sign_out", "Sign Out")
- .style(ui::ButtonStyle::Filled)
+ .label_size(LabelSize::Small)
.on_click(|_, window, cx| {
window.dispatch_action(copilot::SignOut.boxed_clone(), cx);
}),
)
} else {
- let loading_icon = svg()
- .size_8()
- .path(IconName::ArrowCircle.path())
- .text_color(window.text_style().color)
- .with_animation(
- "icon_circle_arrow",
- Animation::new(Duration::from_secs(2)).repeat(),
- |svg, delta| svg.with_transformation(Transformation::rotate(percentage(delta))),
- );
+ let loading_icon = Icon::new(IconName::ArrowCircle).with_animation(
+ "arrow-circle",
+ Animation::new(Duration::from_secs(4)).repeat(),
+ |icon, delta| icon.transform(Transformation::rotate(percentage(delta))),
+ );
const ERROR_LABEL: &str = "Copilot Chat requires an active GitHub Copilot subscription. Please ensure Copilot is configured and try again, or use a different Assistant provider.";
match &self.copilot_status {
Some(status) => match status {
- Status::Starting { task: _ } => {
- const LABEL: &str = "Starting Copilot...";
- v_flex()
- .gap_6()
- .justify_center()
- .items_center()
- .child(Label::new(LABEL))
- .child(loading_icon)
- }
+ Status::Starting { task: _ } => h_flex()
+ .gap_2()
+ .child(loading_icon)
+ .child(Label::new("Starting Copilot…")),
Status::SigningIn { prompt: _ }
| Status::SignedOut {
awaiting_signing_in: true,
- } => {
- const LABEL: &str = "Signing in to Copilot...";
- v_flex()
- .gap_6()
- .justify_center()
- .items_center()
- .child(Label::new(LABEL))
- .child(loading_icon)
- }
+ } => h_flex()
+ .gap_2()
+ .child(loading_icon)
+ .child(Label::new("Signing into Copilot…")),
Status::Error(_) => {
const LABEL: &str = "Copilot had issues starting. Please try restarting it. If the issue persists, try reinstalling Copilot.";
v_flex()
@@ -593,28 +584,14 @@ impl Render for ConfigurationView {
}
_ => {
const LABEL: &str = "To use Zed's assistant with GitHub Copilot, you need to be logged in to GitHub. Note that your GitHub account must have an active Copilot Chat subscription.";
- v_flex().gap_6().child(Label::new(LABEL)).child(
- v_flex()
- .gap_2()
- .child(
- Button::new("sign_in", "Sign In")
- .icon_color(Color::Muted)
- .icon(IconName::Github)
- .icon_position(IconPosition::Start)
- .icon_size(IconSize::Medium)
- .style(ui::ButtonStyle::Filled)
- .full_width()
- .on_click(|_, window, cx| {
- copilot::initiate_sign_in(window, cx)
- }),
- )
- .child(
- div().flex().w_full().items_center().child(
- Label::new("Sign in to start using Github Copilot Chat.")
- .color(Color::Muted)
- .size(ui::LabelSize::Small),
- ),
- ),
+ v_flex().gap_2().child(Label::new(LABEL)).child(
+ Button::new("sign_in", "Sign in to use GitHub Copilot")
+ .icon_color(Color::Muted)
+ .icon(IconName::Github)
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::Medium)
+ .full_width()
+ .on_click(|_, window, cx| copilot::initiate_sign_in(window, cx)),
)
}
},
diff --git a/crates/language_models/src/provider/deepseek.rs b/crates/language_models/src/provider/deepseek.rs
index 6c6a8f333c..e4f1cd830a 100644
--- a/crates/language_models/src/provider/deepseek.rs
+++ b/crates/language_models/src/provider/deepseek.rs
@@ -580,7 +580,7 @@ impl Render for ConfigurationView {
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border_variant)
+ .border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
@@ -595,8 +595,13 @@ impl Render for ConfigurationView {
.into_any()
} else {
h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -608,8 +613,11 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset")
- .icon(IconName::Trash)
+ Button::new("reset-key", "Reset Key")
+ .label_size(LabelSize::Small)
+ .icon(Some(IconName::Trash))
+ .icon_size(IconSize::Small)
+ .icon_position(IconPosition::Start)
.disabled(env_var_set)
.on_click(
cx.listener(|this, _, window, cx| this.reset_api_key(window, cx)),
diff --git a/crates/language_models/src/provider/google.rs b/crates/language_models/src/provider/google.rs
index edf187fdbf..bec5a8768d 100644
--- a/crates/language_models/src/provider/google.rs
+++ b/crates/language_models/src/provider/google.rs
@@ -740,7 +740,7 @@ impl Render for ConfigurationView {
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border_variant)
+ .border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
@@ -753,8 +753,13 @@ impl Render for ConfigurationView {
.into_any()
} else {
h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -766,7 +771,8 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset key")
+ Button::new("reset-key", "Reset Key")
+ .label_size(LabelSize::Small)
.icon(Some(IconName::Trash))
.icon_size(IconSize::Small)
.icon_position(IconPosition::Start)
diff --git a/crates/language_models/src/provider/lmstudio.rs b/crates/language_models/src/provider/lmstudio.rs
index d59ed46e05..bd8b6303f8 100644
--- a/crates/language_models/src/provider/lmstudio.rs
+++ b/crates/language_models/src/provider/lmstudio.rs
@@ -16,10 +16,11 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use std::{collections::BTreeMap, sync::Arc};
-use ui::{ButtonLike, Indicator, prelude::*};
+use ui::{ButtonLike, Indicator, List, prelude::*};
use util::ResultExt;
use crate::AllLanguageModelSettings;
+use crate::ui::InstructionListItem;
const LMSTUDIO_DOWNLOAD_URL: &str = "https://lmstudio.ai/download";
const LMSTUDIO_CATALOG_URL: &str = "https://lmstudio.ai/models";
@@ -408,40 +409,26 @@ impl Render for ConfigurationView {
let is_authenticated = self.state.read(cx).is_authenticated();
let lmstudio_intro = "Run local LLMs like Llama, Phi, and Qwen.";
- let lmstudio_reqs = "To use LM Studio as a provider for Zed assistant, it needs to be running with at least one model downloaded.";
-
- let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05);
if self.loading_models_task.is_some() {
div().child(Label::new("Loading models...")).into_any()
} else {
v_flex()
- .size_full()
- .gap_3()
+ .gap_2()
.child(
- v_flex()
- .size_full()
- .gap_2()
- .p_1()
- .child(Label::new(lmstudio_intro))
- .child(Label::new(lmstudio_reqs))
- .child(
- h_flex()
- .gap_0p5()
- .child(Label::new("To get your first model, try running"))
- .child(
- div()
- .bg(inline_code_bg)
- .px_1p5()
- .rounded_sm()
- .child(Label::new("lms get qwen2.5-coder-7b")),
- ),
- ),
+ v_flex().gap_1().child(Label::new(lmstudio_intro)).child(
+ List::new()
+ .child(InstructionListItem::text_only(
+ "LM Studio needs to be running with at least one model downloaded.",
+ ))
+ .child(InstructionListItem::text_only(
+ "To get your first model, try running `lms get qwen2.5-coder-7b`",
+ )),
+ ),
)
.child(
h_flex()
.w_full()
- .pt_2()
.justify_between()
.gap_2()
.child(
@@ -489,29 +476,31 @@ impl Render for ConfigurationView {
}),
),
)
- .child(if is_authenticated {
- // This is only a button to ensure the spacing is correct
- // it should stay disabled
- ButtonLike::new("connected")
- .disabled(true)
- // Since this won't ever be clickable, we can use the arrow cursor
- .cursor_style(gpui::CursorStyle::Arrow)
- .child(
- h_flex()
- .gap_2()
- .child(Indicator::dot().color(Color::Success))
- .child(Label::new("Connected"))
- .into_any_element(),
+ .map(|this| {
+ if is_authenticated {
+ this.child(
+ ButtonLike::new("connected")
+ .disabled(true)
+ .cursor_style(gpui::CursorStyle::Arrow)
+ .child(
+ h_flex()
+ .gap_2()
+ .child(Indicator::dot().color(Color::Success))
+ .child(Label::new("Connected"))
+ .into_any_element(),
+ ),
)
- .into_any_element()
- } else {
- Button::new("retry_lmstudio_models", "Connect")
- .icon_position(IconPosition::Start)
- .icon(IconName::ArrowCircle)
- .on_click(cx.listener(move |this, _, _window, cx| {
- this.retry_connection(cx)
- }))
- .into_any_element()
+ } else {
+ this.child(
+ Button::new("retry_lmstudio_models", "Connect")
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::XSmall)
+ .icon(IconName::Play)
+ .on_click(cx.listener(move |this, _, _window, cx| {
+ this.retry_connection(cx)
+ })),
+ )
+ }
}),
)
.into_any()
diff --git a/crates/language_models/src/provider/mistral.rs b/crates/language_models/src/provider/mistral.rs
index fca0b61698..b9017398e6 100644
--- a/crates/language_models/src/provider/mistral.rs
+++ b/crates/language_models/src/provider/mistral.rs
@@ -554,7 +554,7 @@ impl Render for ConfigurationView {
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border_variant)
+ .border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
@@ -567,8 +567,13 @@ impl Render for ConfigurationView {
.into_any()
} else {
h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -580,7 +585,8 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset key")
+ Button::new("reset-key", "Reset Key")
+ .label_size(LabelSize::Small)
.icon(Some(IconName::Trash))
.icon_size(IconSize::Small)
.icon_position(IconPosition::Start)
diff --git a/crates/language_models/src/provider/ollama.rs b/crates/language_models/src/provider/ollama.rs
index e24c89c239..465dc0d659 100644
--- a/crates/language_models/src/provider/ollama.rs
+++ b/crates/language_models/src/provider/ollama.rs
@@ -16,10 +16,11 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use std::{collections::BTreeMap, sync::Arc};
-use ui::{ButtonLike, Indicator, prelude::*};
+use ui::{ButtonLike, Indicator, List, prelude::*};
use util::ResultExt;
use crate::AllLanguageModelSettings;
+use crate::ui::InstructionListItem;
const OLLAMA_DOWNLOAD_URL: &str = "https://ollama.com/download";
const OLLAMA_LIBRARY_URL: &str = "https://ollama.com/library";
@@ -399,42 +400,26 @@ impl Render for ConfigurationView {
fn render(&mut self, _: &mut Window, cx: &mut Context) -> impl IntoElement {
let is_authenticated = self.state.read(cx).is_authenticated();
- let ollama_intro = "Get up and running with Llama 3.3, Mistral, Gemma 2, and other large language models with Ollama.";
- let ollama_reqs =
- "Ollama must be running with at least one model installed to use it in the assistant.";
-
- let inline_code_bg = cx.theme().colors().editor_foreground.opacity(0.05);
+ let ollama_intro =
+ "Get up & running with Llama 3.3, Mistral, Gemma 2, and other LLMs with Ollama.";
if self.loading_models_task.is_some() {
div().child(Label::new("Loading models...")).into_any()
} else {
v_flex()
- .size_full()
- .gap_3()
+ .gap_2()
.child(
- v_flex()
- .size_full()
- .gap_2()
- .p_1()
- .child(Label::new(ollama_intro))
- .child(Label::new(ollama_reqs))
- .child(
- h_flex()
- .gap_0p5()
- .child(Label::new("Once installed, try "))
- .child(
- div()
- .bg(inline_code_bg)
- .px_1p5()
- .rounded_sm()
- .child(Label::new("ollama run llama3.2")),
- ),
- ),
+ v_flex().gap_1().child(Label::new(ollama_intro)).child(
+ List::new()
+ .child(InstructionListItem::text_only("Ollama must be running with at least one model installed to use it in the assistant."))
+ .child(InstructionListItem::text_only(
+ "Once installed, try `ollama run llama3.2`",
+ )),
+ ),
)
.child(
h_flex()
.w_full()
- .pt_2()
.justify_between()
.gap_2()
.child(
@@ -478,30 +463,32 @@ impl Render for ConfigurationView {
.on_click(move |_, _, cx| cx.open_url(OLLAMA_LIBRARY_URL)),
),
)
- .child(if is_authenticated {
- // This is only a button to ensure the spacing is correct
- // it should stay disabled
- ButtonLike::new("connected")
- .disabled(true)
- // Since this won't ever be clickable, we can use the arrow cursor
- .cursor_style(gpui::CursorStyle::Arrow)
- .child(
- h_flex()
- .gap_2()
- .child(Indicator::dot().color(Color::Success))
- .child(Label::new("Connected"))
- .into_any_element(),
+ .map(|this| {
+ if is_authenticated {
+ this.child(
+ ButtonLike::new("connected")
+ .disabled(true)
+ .cursor_style(gpui::CursorStyle::Arrow)
+ .child(
+ h_flex()
+ .gap_2()
+ .child(Indicator::dot().color(Color::Success))
+ .child(Label::new("Connected"))
+ .into_any_element(),
+ ),
)
- .into_any_element()
- } else {
- Button::new("retry_ollama_models", "Connect")
- .icon_position(IconPosition::Start)
- .icon(IconName::ArrowCircle)
- .on_click(
- cx.listener(move |this, _, _, cx| this.retry_connection(cx)),
+ } else {
+ this.child(
+ Button::new("retry_ollama_models", "Connect")
+ .icon_position(IconPosition::Start)
+ .icon_size(IconSize::XSmall)
+ .icon(IconName::Play)
+ .on_click(cx.listener(move |this, _, _, cx| {
+ this.retry_connection(cx)
+ })),
)
- .into_any_element()
- }),
+ }
+ })
)
.into_any()
}
diff --git a/crates/language_models/src/provider/open_ai.rs b/crates/language_models/src/provider/open_ai.rs
index 774f1f7b2a..6b14744a30 100644
--- a/crates/language_models/src/provider/open_ai.rs
+++ b/crates/language_models/src/provider/open_ai.rs
@@ -693,7 +693,7 @@ impl Render for ConfigurationView {
.py_1()
.bg(cx.theme().colors().editor_background)
.border_1()
- .border_color(cx.theme().colors().border_variant)
+ .border_color(cx.theme().colors().border)
.rounded_sm()
.child(self.render_api_key_editor(cx)),
)
@@ -712,8 +712,13 @@ impl Render for ConfigurationView {
.into_any()
} else {
h_flex()
- .size_full()
+ .mt_1()
+ .p_1()
.justify_between()
+ .rounded_md()
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .bg(cx.theme().colors().background)
.child(
h_flex()
.gap_1()
@@ -725,7 +730,8 @@ impl Render for ConfigurationView {
})),
)
.child(
- Button::new("reset-key", "Reset key")
+ Button::new("reset-key", "Reset Key")
+ .label_size(LabelSize::Small)
.icon(Some(IconName::Trash))
.icon_size(IconSize::Small)
.icon_position(IconPosition::Start)
diff --git a/crates/markdown/src/markdown.rs b/crates/markdown/src/markdown.rs
index 68b3788966..0c1539824e 100644
--- a/crates/markdown/src/markdown.rs
+++ b/crates/markdown/src/markdown.rs
@@ -753,11 +753,6 @@ impl Element for MarkdownElement {
}
});
- // Apply border if required
- // Usage examples:
- // CodeBlockRenderer::Default { copy_button: true, border: true } - Both copy button and border
- // CodeBlockRenderer::Default { copy_button: false, border: true } - Border only
- // CodeBlockRenderer::Default { copy_button: true, border: false } - Copy button only (default)
if let CodeBlockRenderer::Default { border: true, .. } =
&self.code_block_renderer
{