agent_panel_onboarding_content.rs

 1use std::sync::Arc;
 2
 3use client::{Client, UserStore};
 4use cloud_llm_client::{Plan, PlanV1, PlanV2};
 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    has_configured_providers: bool,
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                | language_model::Event::ProvidersChanged => {
32                    this.has_configured_providers = Self::has_configured_providers(cx)
33                }
34                _ => {}
35            },
36        )
37        .detach();
38
39        Self {
40            user_store,
41            client,
42            has_configured_providers: Self::has_configured_providers(cx),
43            continue_with_zed_ai: Arc::new(continue_with_zed_ai),
44        }
45    }
46
47    fn has_configured_providers(cx: &App) -> bool {
48        LanguageModelRegistry::read_global(cx)
49            .visible_providers()
50            .iter()
51            .any(|provider| provider.is_authenticated(cx) && provider.id() != ZED_CLOUD_PROVIDER_ID)
52    }
53}
54
55impl Render for AgentPanelOnboarding {
56    fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
57        let enrolled_in_trial = self.user_store.read(cx).plan().is_some_and(|plan| {
58            matches!(
59                plan,
60                Plan::V1(PlanV1::ZedProTrial) | Plan::V2(PlanV2::ZedProTrial)
61            )
62        });
63        let is_pro_user = self.user_store.read(cx).plan().is_some_and(|plan| {
64            matches!(plan, Plan::V1(PlanV1::ZedPro) | Plan::V2(PlanV2::ZedPro))
65        });
66
67        AgentPanelOnboardingCard::new()
68            .child(
69                ZedAiOnboarding::new(
70                    self.client.clone(),
71                    &self.user_store,
72                    self.continue_with_zed_ai.clone(),
73                    cx,
74                )
75                .with_dismiss({
76                    let callback = self.continue_with_zed_ai.clone();
77                    move |window, cx| callback(window, cx)
78                }),
79            )
80            .map(|this| {
81                if enrolled_in_trial || is_pro_user || self.has_configured_providers {
82                    this
83                } else {
84                    this.child(ApiKeysWithoutProviders::new())
85                }
86            })
87    }
88}