1use std::sync::Arc;
2
3use client::{Client, CloudUserStore, UserStore};
4use cloud_llm_client::Plan;
5use gpui::{Entity, IntoElement, ParentElement};
6use language_model::{LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID};
7use ui::prelude::*;
8
9use crate::{AgentPanelOnboardingCard, ApiKeysWithoutProviders, ZedAiOnboarding};
10
11pub struct AgentPanelOnboarding {
12 user_store: Entity<UserStore>,
13 cloud_user_store: Entity<CloudUserStore>,
14 client: Arc<Client>,
15 configured_providers: Vec<(IconName, SharedString)>,
16 continue_with_zed_ai: Arc<dyn Fn(&mut Window, &mut App)>,
17}
18
19impl AgentPanelOnboarding {
20 pub fn new(
21 user_store: Entity<UserStore>,
22 cloud_user_store: Entity<CloudUserStore>,
23 client: Arc<Client>,
24 continue_with_zed_ai: impl Fn(&mut Window, &mut App) + 'static,
25 cx: &mut Context<Self>,
26 ) -> Self {
27 cx.subscribe(
28 &LanguageModelRegistry::global(cx),
29 |this: &mut Self, _registry, event: &language_model::Event, cx| match event {
30 language_model::Event::ProviderStateChanged
31 | language_model::Event::AddedProvider(_)
32 | language_model::Event::RemovedProvider(_) => {
33 this.configured_providers = Self::compute_available_providers(cx)
34 }
35 _ => {}
36 },
37 )
38 .detach();
39
40 Self {
41 user_store,
42 cloud_user_store,
43 client,
44 configured_providers: Self::compute_available_providers(cx),
45 continue_with_zed_ai: Arc::new(continue_with_zed_ai),
46 }
47 }
48
49 fn compute_available_providers(cx: &App) -> Vec<(IconName, SharedString)> {
50 LanguageModelRegistry::read_global(cx)
51 .providers()
52 .iter()
53 .filter(|provider| {
54 provider.is_authenticated(cx) && provider.id() != ZED_CLOUD_PROVIDER_ID
55 })
56 .map(|provider| (provider.icon(), provider.name().0.clone()))
57 .collect()
58 }
59}
60
61impl Render for AgentPanelOnboarding {
62 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
63 let enrolled_in_trial = self.cloud_user_store.read(cx).plan() == Some(Plan::ZedProTrial);
64 let is_pro_user = self.cloud_user_store.read(cx).plan() == Some(Plan::ZedPro);
65
66 AgentPanelOnboardingCard::new()
67 .child(
68 ZedAiOnboarding::new(
69 self.client.clone(),
70 &self.user_store,
71 self.continue_with_zed_ai.clone(),
72 cx,
73 )
74 .with_dismiss({
75 let callback = self.continue_with_zed_ai.clone();
76 move |window, cx| callback(window, cx)
77 }),
78 )
79 .map(|this| {
80 if enrolled_in_trial || is_pro_user || self.configured_providers.len() >= 1 {
81 this
82 } else {
83 this.child(ApiKeysWithoutProviders::new())
84 }
85 })
86 }
87}