impl Focusable for Button
This commit is contained in:
parent
6e540a58fa
commit
e56672e542
107 changed files with 524 additions and 417 deletions
|
@ -1017,13 +1017,14 @@ impl Render for ConfigurationView {
|
|||
List::new()
|
||||
.child(
|
||||
InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("Anthropic's settings"),
|
||||
Some("https://console.anthropic.com/settings/keys")
|
||||
)
|
||||
)
|
||||
.child(
|
||||
InstructionListItem::text_only("Paste your API key below and hit enter to start using the assistant")
|
||||
InstructionListItem::text_only(cx, "Paste your API key below and hit enter to start using the assistant")
|
||||
)
|
||||
)
|
||||
.child(
|
||||
|
@ -1066,7 +1067,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key", cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -1232,7 +1232,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key", cx)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_position(IconPosition::Start)
|
||||
|
@ -1257,6 +1257,7 @@ impl Render for ConfigurationView {
|
|||
List::new()
|
||||
.child(
|
||||
InstructionListItem::new(
|
||||
cx,
|
||||
"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"),
|
||||
|
@ -1264,6 +1265,7 @@ impl Render for ConfigurationView {
|
|||
)
|
||||
.child(
|
||||
InstructionListItem::new(
|
||||
cx,
|
||||
"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"),
|
||||
|
@ -1365,19 +1367,23 @@ impl ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create an IAM user in the AWS console with programmatic access",
|
||||
Some("IAM Console"),
|
||||
Some("https://us-east-1.console.aws.amazon.com/iam/home?region=us-east-1#/users"),
|
||||
))
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Attach the necessary Bedrock permissions to this ",
|
||||
Some("user"),
|
||||
Some("https://docs.aws.amazon.com/bedrock/latest/userguide/inference-prereq.html"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Copy the access key ID and secret access key when provided",
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Enter these credentials below",
|
||||
)),
|
||||
)
|
||||
|
|
|
@ -410,12 +410,17 @@ impl LanguageModelProvider for CloudLanguageModelProvider {
|
|||
return None;
|
||||
}
|
||||
Some(
|
||||
render_accept_terms(view, state.accept_terms_of_service_task.is_some(), {
|
||||
let state = self.state.clone();
|
||||
move |_window, cx| {
|
||||
state.update(cx, |state, cx| state.accept_terms_of_service(cx));
|
||||
}
|
||||
})
|
||||
render_accept_terms(
|
||||
view,
|
||||
state.accept_terms_of_service_task.is_some(),
|
||||
{
|
||||
let state = self.state.clone();
|
||||
move |_window, cx| {
|
||||
state.update(cx, |state, cx| state.accept_terms_of_service(cx));
|
||||
}
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
|
@ -429,11 +434,12 @@ fn render_accept_terms(
|
|||
view_kind: LanguageModelProviderTosView,
|
||||
accept_terms_of_service_in_progress: bool,
|
||||
accept_terms_callback: impl Fn(&mut Window, &mut App) + 'static,
|
||||
app: &App,
|
||||
) -> impl IntoElement {
|
||||
let thread_fresh_start = matches!(view_kind, LanguageModelProviderTosView::ThreadFreshStart);
|
||||
let thread_empty_state = matches!(view_kind, LanguageModelProviderTosView::ThreadEmptyState);
|
||||
|
||||
let terms_button = Button::new("terms_of_service", "Terms of Service")
|
||||
let terms_button = Button::new("terms_of_service", "Terms of Service", app)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_color(Color::Muted)
|
||||
|
@ -442,7 +448,7 @@ fn render_accept_terms(
|
|||
.on_click(move |_, _window, cx| cx.open_url("https://zed.dev/terms-of-service"));
|
||||
|
||||
let button_container = h_flex().child(
|
||||
Button::new("accept_terms", "I accept the Terms of Service")
|
||||
Button::new("accept_terms", "I accept the Terms of Service", app)
|
||||
.when(!thread_empty_state, |this| {
|
||||
this.full_width()
|
||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
|
@ -1135,19 +1141,19 @@ impl RenderOnce for ZedAiConfiguration {
|
|||
};
|
||||
|
||||
let manage_subscription_buttons = if is_pro {
|
||||
Button::new("manage_settings", "Manage Subscription")
|
||||
Button::new("manage_settings", "Manage Subscription", _cx)
|
||||
.full_width()
|
||||
.style(ButtonStyle::Tinted(TintColor::Accent))
|
||||
.on_click(|_, _, cx| cx.open_url(&zed_urls::account_url(cx)))
|
||||
.into_any_element()
|
||||
} else if self.plan.is_none() || self.eligible_for_trial {
|
||||
Button::new("start_trial", "Start 14-day Free Pro Trial")
|
||||
Button::new("start_trial", "Start 14-day Free Pro Trial", _cx)
|
||||
.full_width()
|
||||
.style(ui::ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.on_click(|_, _, cx| cx.open_url(&zed_urls::start_trial_url(cx)))
|
||||
.into_any_element()
|
||||
} else {
|
||||
Button::new("upgrade", "Upgrade to Pro")
|
||||
Button::new("upgrade", "Upgrade to Pro", _cx)
|
||||
.full_width()
|
||||
.style(ui::ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.on_click(|_, _, cx| cx.open_url(&zed_urls::upgrade_to_zed_pro_url(cx)))
|
||||
|
@ -1159,7 +1165,7 @@ impl RenderOnce for ZedAiConfiguration {
|
|||
.gap_2()
|
||||
.child(Label::new("Sign in to have access to Zed's complete agentic experience with hosted models."))
|
||||
.child(
|
||||
Button::new("sign_in", "Sign In to use Zed AI")
|
||||
Button::new("sign_in", "Sign In to use Zed AI", _cx)
|
||||
.icon_color(Color::Muted)
|
||||
.icon(IconName::Github)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -1183,12 +1189,13 @@ impl RenderOnce for ZedAiConfiguration {
|
|||
let callback = self.accept_terms_of_service_callback.clone();
|
||||
move |window, cx| (callback)(window, cx)
|
||||
},
|
||||
_cx,
|
||||
))
|
||||
})
|
||||
.map(|this| {
|
||||
if self.has_accepted_terms_of_service && self.account_too_young {
|
||||
this.child(young_account_banner).child(
|
||||
Button::new("upgrade", "Upgrade to Pro")
|
||||
Button::new("upgrade", "Upgrade to Pro", _cx)
|
||||
.style(ui::ButtonStyle::Tinted(ui::TintColor::Accent))
|
||||
.full_width()
|
||||
.on_click(|_, _, cx| {
|
||||
|
|
|
@ -670,7 +670,7 @@ impl Render for ConfigurationView {
|
|||
.child(Label::new("Authorized")),
|
||||
)
|
||||
.child(
|
||||
Button::new("sign_out", "Sign Out")
|
||||
Button::new("sign_out", "Sign Out", cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.on_click(|_, window, cx| {
|
||||
window.dispatch_action(copilot::SignOut.boxed_clone(), cx);
|
||||
|
@ -709,7 +709,7 @@ impl Render for ConfigurationView {
|
|||
const LABEL: &str = "To use Zed's agent 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_2().child(Label::new(LABEL)).child(
|
||||
Button::new("sign_in", "Sign in to use GitHub Copilot")
|
||||
Button::new("sign_in", "Sign in to use GitHub Copilot", cx)
|
||||
.icon_color(Color::Muted)
|
||||
.icon(IconName::Github)
|
||||
.icon_position(IconPosition::Start)
|
||||
|
|
|
@ -679,11 +679,13 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Get your API key from the",
|
||||
Some("DeepSeek console"),
|
||||
Some("https://platform.deepseek.com/api_keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the assistant",
|
||||
)),
|
||||
)
|
||||
|
@ -728,7 +730,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key", cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -884,11 +884,13 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("Google AI's console"),
|
||||
Some("https://aistudio.google.com/app/apikey"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the assistant",
|
||||
)),
|
||||
)
|
||||
|
@ -931,7 +933,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key", cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -668,9 +668,11 @@ impl Render for ConfigurationView {
|
|||
v_flex().gap_1().child(Label::new(lmstudio_intro)).child(
|
||||
List::new()
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"LM Studio needs to be running with at least one model downloaded.",
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"To get your first model, try running `lms get qwen2.5-coder-7b`",
|
||||
)),
|
||||
),
|
||||
|
@ -687,7 +689,7 @@ impl Render for ConfigurationView {
|
|||
.map(|this| {
|
||||
if is_authenticated {
|
||||
this.child(
|
||||
Button::new("lmstudio-site", "LM Studio")
|
||||
Button::new("lmstudio-site", "LM Studio", cx)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -702,6 +704,7 @@ impl Render for ConfigurationView {
|
|||
Button::new(
|
||||
"download_lmstudio_button",
|
||||
"Download LM Studio",
|
||||
cx,
|
||||
)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
|
@ -715,7 +718,7 @@ impl Render for ConfigurationView {
|
|||
}
|
||||
})
|
||||
.child(
|
||||
Button::new("view-models", "Model Catalog")
|
||||
Button::new("view-models", "Model Catalog", cx)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -741,7 +744,7 @@ impl Render for ConfigurationView {
|
|||
)
|
||||
} else {
|
||||
this.child(
|
||||
Button::new("retry_lmstudio_models", "Connect")
|
||||
Button::new("retry_lmstudio_models", "Connect", cx)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon(IconName::PlayFilled)
|
||||
|
|
|
@ -848,14 +848,17 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("Mistral's console"),
|
||||
Some("https://console.mistral.ai/api-keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Ensure your Mistral account has credits",
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the assistant",
|
||||
)),
|
||||
)
|
||||
|
@ -898,7 +901,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key", cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -587,8 +587,9 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
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(cx, "Ollama must be running with at least one model installed to use it in the assistant."))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Once installed, try `ollama run llama3.2`",
|
||||
)),
|
||||
),
|
||||
|
@ -605,7 +606,7 @@ impl Render for ConfigurationView {
|
|||
.map(|this| {
|
||||
if is_authenticated {
|
||||
this.child(
|
||||
Button::new("ollama-site", "Ollama")
|
||||
Button::new("ollama-site", "Ollama", cx)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -618,6 +619,7 @@ impl Render for ConfigurationView {
|
|||
Button::new(
|
||||
"download_ollama_button",
|
||||
"Download Ollama",
|
||||
cx,
|
||||
)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
|
@ -631,7 +633,7 @@ impl Render for ConfigurationView {
|
|||
}
|
||||
})
|
||||
.child(
|
||||
Button::new("view-models", "View All Models")
|
||||
Button::new("view-models", "View All Models", cx)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -655,7 +657,7 @@ impl Render for ConfigurationView {
|
|||
)
|
||||
} else {
|
||||
this.child(
|
||||
Button::new("retry_ollama_models", "Connect")
|
||||
Button::new("retry_ollama_models", "Connect", cx)
|
||||
.icon_position(IconPosition::Start)
|
||||
.icon_size(IconSize::XSmall)
|
||||
.icon(IconName::PlayFilled)
|
||||
|
|
|
@ -812,14 +812,17 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("OpenAI's console"),
|
||||
Some("https://platform.openai.com/api-keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Ensure your OpenAI account has credits",
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the assistant",
|
||||
)),
|
||||
)
|
||||
|
@ -857,7 +860,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-api-key", "Reset API Key")
|
||||
Button::new("reset-api-key", "Reset API Key",cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
|
@ -891,7 +894,7 @@ impl Render for ConfigurationView {
|
|||
.child(Label::new("Zed also supports OpenAI-compatible models.")),
|
||||
)
|
||||
.child(
|
||||
Button::new("docs", "Learn More")
|
||||
Button::new("docs", "Learn More", cx)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.icon_color(Color::Muted)
|
||||
|
|
|
@ -505,7 +505,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-api-key", "Reset API Key")
|
||||
Button::new("reset-api-key", "Reset API Key",cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -859,14 +859,17 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create an API key by visiting",
|
||||
Some("OpenRouter's console"),
|
||||
Some("https://openrouter.ai/keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Ensure your OpenRouter account has credits",
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the assistant",
|
||||
)),
|
||||
)
|
||||
|
@ -909,7 +912,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-key", "Reset Key")
|
||||
Button::new("reset-key", "Reset Key",cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(Some(IconName::Trash))
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -517,11 +517,13 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("Vercel v0's console"),
|
||||
Some("https://v0.dev/chat/settings/keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the agent",
|
||||
)),
|
||||
)
|
||||
|
@ -559,7 +561,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-api-key", "Reset API Key")
|
||||
Button::new("reset-api-key", "Reset API Key",cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -507,11 +507,13 @@ impl Render for ConfigurationView {
|
|||
.child(
|
||||
List::new()
|
||||
.child(InstructionListItem::new(
|
||||
cx,
|
||||
"Create one by visiting",
|
||||
Some("xAI console"),
|
||||
Some("https://console.x.ai/team/default/api-keys"),
|
||||
))
|
||||
.child(InstructionListItem::text_only(
|
||||
cx,
|
||||
"Paste your API key below and hit enter to start using the agent",
|
||||
)),
|
||||
)
|
||||
|
@ -549,7 +551,7 @@ impl Render for ConfigurationView {
|
|||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("reset-api-key", "Reset API Key")
|
||||
Button::new("reset-api-key", "Reset API Key",cx)
|
||||
.label_size(LabelSize::Small)
|
||||
.icon(IconName::Undo)
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
|
@ -2,27 +2,31 @@ use gpui::{AnyElement, IntoElement, ParentElement, SharedString};
|
|||
use ui::{ListItem, prelude::*};
|
||||
|
||||
/// A reusable list item component for adding LLM provider configuration instructions
|
||||
pub struct InstructionListItem {
|
||||
pub struct InstructionListItem<'app> {
|
||||
app: &'app App,
|
||||
label: SharedString,
|
||||
button_label: Option<SharedString>,
|
||||
button_link: Option<String>,
|
||||
}
|
||||
|
||||
impl InstructionListItem {
|
||||
impl<'app> InstructionListItem<'app> {
|
||||
pub fn new(
|
||||
app: &'app App,
|
||||
label: impl Into<SharedString>,
|
||||
button_label: Option<impl Into<SharedString>>,
|
||||
button_link: Option<impl Into<String>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
app,
|
||||
label: label.into(),
|
||||
button_label: button_label.map(|l| l.into()),
|
||||
button_link: button_link.map(|l| l.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_only(label: impl Into<SharedString>) -> Self {
|
||||
pub fn text_only(app: &'app App, label: impl Into<SharedString>) -> Self {
|
||||
Self {
|
||||
app,
|
||||
label: label.into(),
|
||||
button_label: None,
|
||||
button_link: None,
|
||||
|
@ -30,7 +34,7 @@ impl InstructionListItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoElement for InstructionListItem {
|
||||
impl IntoElement for InstructionListItem<'_> {
|
||||
type Element = AnyElement;
|
||||
|
||||
fn into_element(self) -> Self::Element {
|
||||
|
@ -44,7 +48,7 @@ impl IntoElement for InstructionListItem {
|
|||
.flex_wrap()
|
||||
.child(Label::new(self.label))
|
||||
.child(
|
||||
Button::new(unique_id, button_label)
|
||||
Button::new(unique_id, button_label, self.app)
|
||||
.style(ButtonStyle::Subtle)
|
||||
.icon(IconName::ArrowUpRight)
|
||||
.icon_size(IconSize::Small)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue