agent_api_keys_onboarding.rs

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