agent_api_keys_onboarding.rs

  1use gpui::{Action, IntoElement, ParentElement, RenderOnce, point};
  2use language_model::{LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID};
  3use ui::{Divider, List, prelude::*};
  4
  5use crate::BulletItem;
  6
  7pub struct ApiKeysWithProviders {
  8    configured_providers: Vec<(IconName, SharedString)>,
  9}
 10
 11impl ApiKeysWithProviders {
 12    pub fn new(cx: &mut Context<Self>) -> Self {
 13        cx.subscribe(
 14            &LanguageModelRegistry::global(cx),
 15            |this: &mut Self, _registry, event: &language_model::Event, cx| match event {
 16                language_model::Event::ProviderStateChanged
 17                | language_model::Event::AddedProvider(_)
 18                | language_model::Event::RemovedProvider(_) => {
 19                    this.configured_providers = Self::compute_configured_providers(cx)
 20                }
 21                _ => {}
 22            },
 23        )
 24        .detach();
 25
 26        Self {
 27            configured_providers: Self::compute_configured_providers(cx),
 28        }
 29    }
 30
 31    fn compute_configured_providers(cx: &App) -> Vec<(IconName, SharedString)> {
 32        LanguageModelRegistry::read_global(cx)
 33            .providers()
 34            .iter()
 35            .filter(|provider| {
 36                provider.is_authenticated(cx) && provider.id() != ZED_CLOUD_PROVIDER_ID
 37            })
 38            .map(|provider| (provider.icon(), provider.name().0.clone()))
 39            .collect()
 40    }
 41
 42    pub fn has_providers(&self) -> bool {
 43        !self.configured_providers.is_empty()
 44    }
 45}
 46
 47impl Render for ApiKeysWithProviders {
 48    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 49        let configured_providers_list =
 50            self.configured_providers
 51                .iter()
 52                .cloned()
 53                .map(|(icon, name)| {
 54                    h_flex()
 55                        .gap_1p5()
 56                        .child(Icon::new(icon).size(IconSize::Small).color(Color::Muted))
 57                        .child(Label::new(name))
 58                });
 59
 60        h_flex()
 61            .mx_2p5()
 62            .p_1()
 63            .pb_0()
 64            .gap_2()
 65            .rounded_t_lg()
 66            .border_t_1()
 67            .border_x_1()
 68            .border_color(cx.theme().colors().border.opacity(0.5))
 69            .bg(cx.theme().colors().background.alpha(0.5))
 70            .shadow(vec![gpui::BoxShadow {
 71                color: gpui::black().opacity(0.15),
 72                offset: point(px(1.), px(-1.)),
 73                blur_radius: px(3.),
 74                spread_radius: px(0.),
 75            }])
 76            .child(
 77                h_flex()
 78                    .px_2p5()
 79                    .py_1p5()
 80                    .gap_2()
 81                    .flex_wrap()
 82                    .rounded_t(px(5.))
 83                    .overflow_hidden()
 84                    .border_t_1()
 85                    .border_x_1()
 86                    .border_color(cx.theme().colors().border)
 87                    .bg(cx.theme().colors().panel_background)
 88                    .child(Icon::new(IconName::Info).size(IconSize::XSmall).color(Color::Muted))
 89                    .child(Label::new("Or start now using API keys from your environment for the following providers:").color(Color::Muted))
 90                    .children(configured_providers_list)
 91            )
 92    }
 93}
 94
 95#[derive(IntoElement)]
 96pub struct ApiKeysWithoutProviders;
 97
 98impl ApiKeysWithoutProviders {
 99    pub fn new() -> Self {
100        Self
101    }
102}
103
104impl RenderOnce for ApiKeysWithoutProviders {
105    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
106        v_flex()
107            .mt_2()
108            .gap_1()
109            .child(
110                h_flex()
111                    .gap_2()
112                    .child(
113                        Label::new("API Keys")
114                            .size(LabelSize::Small)
115                            .color(Color::Muted)
116                            .buffer_font(cx),
117                    )
118                    .child(Divider::horizontal()),
119            )
120            .child(List::new().child(BulletItem::new(
121                "You can also use AI in Zed by bringing your own API keys",
122            )))
123            .child(
124                Button::new("configure-providers", "Configure Providers")
125                    .full_width()
126                    .style(ButtonStyle::Outlined)
127                    .on_click(move |_, window, cx| {
128                        window.dispatch_action(
129                            zed_actions::agent::OpenConfiguration.boxed_clone(),
130                            cx,
131                        );
132                    }),
133            )
134    }
135}