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