agent_panel_onboarding_content.rs

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