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
 43impl Render for ApiKeysWithProviders {
 44    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
 45        let configured_providers_list =
 46            self.configured_providers
 47                .iter()
 48                .cloned()
 49                .map(|(icon, name)| {
 50                    h_flex()
 51                        .gap_1p5()
 52                        .child(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
 53                        .child(Label::new(name))
 54                });
 55        div()
 56            .mx_2p5()
 57            .p_1()
 58            .pb_0()
 59            .gap_2()
 60            .rounded_t_lg()
 61            .border_t_1()
 62            .border_x_1()
 63            .border_color(cx.theme().colors().border.opacity(0.5))
 64            .bg(cx.theme().colors().background.alpha(0.5))
 65            .shadow(vec![gpui::BoxShadow {
 66                color: gpui::black().opacity(0.15),
 67                offset: point(px(1.), px(-1.)),
 68                blur_radius: px(3.),
 69                spread_radius: px(0.),
 70            }])
 71            .child(
 72                h_flex()
 73                    .px_2p5()
 74                    .py_1p5()
 75                    .gap_2()
 76                    .flex_wrap()
 77                    .rounded_t(px(5.))
 78                    .overflow_hidden()
 79                    .border_t_1()
 80                    .border_x_1()
 81                    .border_color(cx.theme().colors().border)
 82                    .bg(cx.theme().colors().panel_background)
 83                    .child(
 84                        h_flex()
 85                            .min_w_0()
 86                            .gap_2()
 87                            .child(
 88                                Icon::new(IconName::Info)
 89                                    .size(IconSize::XSmall)
 90                                    .color(Color::Muted)
 91                            )
 92                            .child(
 93                                div()
 94                                    .w_full()
 95                                    .child(
 96                                        Label::new("Start now using API keys from your environment for the following providers:")
 97                                            .color(Color::Muted)
 98                                    )
 99                            )
100                    )
101                    .children(configured_providers_list)
102            )
103    }
104}
105
106#[derive(IntoElement)]
107pub struct ApiKeysWithoutProviders;
108
109impl ApiKeysWithoutProviders {
110    pub fn new() -> Self {
111        Self
112    }
113}
114
115impl RenderOnce for ApiKeysWithoutProviders {
116    fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
117        v_flex()
118            .mt_2()
119            .gap_1()
120            .child(
121                h_flex()
122                    .gap_2()
123                    .child(
124                        Label::new("API Keys")
125                            .size(LabelSize::Small)
126                            .color(Color::Muted)
127                            .buffer_font(cx),
128                    )
129                    .child(Divider::horizontal()),
130            )
131            .child(List::new().child(BulletItem::new(
132                "Add your own keys to use AI without signing in.",
133            )))
134            .child(
135                Button::new("configure-providers", "Configure Providers")
136                    .full_width()
137                    .style(ButtonStyle::Outlined)
138                    .on_click(move |_, window, cx| {
139                        window.dispatch_action(zed_actions::agent::OpenSettings.boxed_clone(), cx);
140                    }),
141            )
142    }
143}