assistant2: Show accept terms UI in thread empty state (#23630)

<img
src="https://github.com/user-attachments/assets/cea93cfb-8a40-48c4-9d90-f1751c79603b"
width=400>



Release Notes:

- N/A

---------

Co-authored-by: Danilo <danilo@zed.dev>
This commit is contained in:
Agus Zubiaga 2025-01-24 19:34:46 -03:00 committed by GitHub
parent ec5d02d5c2
commit ba16b4eb65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 155 additions and 144 deletions

View file

@ -12,14 +12,14 @@ use futures::{
TryStreamExt as _,
};
use gpui::{
AnyElement, AnyView, AppContext, AsyncAppContext, EventEmitter, FontWeight, Global, Model,
ModelContext, ReadGlobal, Subscription, Task,
AnyElement, AnyView, AppContext, AsyncAppContext, EventEmitter, Global, Model, ModelContext,
ReadGlobal, Subscription, Task,
};
use http_client::{AsyncBody, HttpClient, Method, Response, StatusCode};
use language_model::{
CloudModel, LanguageModel, LanguageModelCacheConfiguration, LanguageModelId, LanguageModelName,
LanguageModelProviderId, LanguageModelProviderName, LanguageModelProviderState,
LanguageModelRequest, RateLimiter, ZED_CLOUD_PROVIDER_ID,
LanguageModelProviderTosView, LanguageModelRequest, RateLimiter, ZED_CLOUD_PROVIDER_ID,
};
use language_model::{
LanguageModelAvailability, LanguageModelCompletionEvent, LanguageModelProvider,
@ -378,60 +378,12 @@ impl LanguageModelProvider for CloudLanguageModelProvider {
!self.state.read(cx).has_accepted_terms_of_service(cx)
}
fn render_accept_terms(&self, cx: &mut WindowContext) -> Option<AnyElement> {
let state = self.state.read(cx);
let terms = [(
"terms_of_service",
"Terms of Service",
"https://zed.dev/terms-of-service",
)]
.map(|(id, label, url)| {
Button::new(id, label)
.style(ButtonStyle::Subtle)
.icon(IconName::ExternalLink)
.icon_size(IconSize::XSmall)
.icon_color(Color::Muted)
.on_click(move |_, cx| cx.open_url(url))
});
if state.has_accepted_terms_of_service(cx) {
None
} else {
let disabled = state.accept_terms.is_some();
Some(
v_flex()
.gap_2()
.child(
v_flex()
.child(Label::new("Terms and Conditions").weight(FontWeight::MEDIUM))
.child(
Label::new(
"Please read and accept our terms and conditions to continue.",
)
.size(LabelSize::Small),
),
)
.child(v_flex().gap_1().children(terms))
.child(
h_flex().justify_end().child(
Button::new("accept_terms", "I've read it and accept it")
.disabled(disabled)
.on_click({
let state = self.state.downgrade();
move |_, cx| {
state
.update(cx, |state, cx| {
state.accept_terms_of_service(cx)
})
.ok();
}
}),
),
)
.into_any(),
)
}
fn render_accept_terms(
&self,
view: LanguageModelProviderTosView,
cx: &mut WindowContext,
) -> Option<AnyElement> {
render_accept_terms(self.state.clone(), view, cx)
}
fn reset_credentials(&self, _cx: &mut AppContext) -> Task<Result<()>> {
@ -439,6 +391,68 @@ impl LanguageModelProvider for CloudLanguageModelProvider {
}
}
fn render_accept_terms(
state: Model<State>,
view_kind: LanguageModelProviderTosView,
cx: &mut WindowContext,
) -> Option<AnyElement> {
if state.read(cx).has_accepted_terms_of_service(cx) {
return None;
}
let accept_terms_disabled = state.read(cx).accept_terms.is_some();
let terms_button = Button::new("terms_of_service", "Terms of Service")
.style(ButtonStyle::Subtle)
.icon(IconName::ArrowUpRight)
.icon_color(Color::Muted)
.icon_size(IconSize::XSmall)
.on_click(move |_, cx| cx.open_url("https://zed.dev/terms-of-service"));
let text = "To start using Zed AI, please read and accept the";
let form = v_flex()
.w_full()
.gap_2()
.when(
view_kind == LanguageModelProviderTosView::ThreadEmptyState,
|form| form.items_center(),
)
.child(
h_flex()
.flex_wrap()
.when(
view_kind == LanguageModelProviderTosView::ThreadEmptyState,
|form| form.justify_center(),
)
.child(Label::new(text))
.child(terms_button),
)
.child({
let button_container = h_flex().w_full().child(
Button::new("accept_terms", "I accept the Terms of Service")
.style(ButtonStyle::Tinted(TintColor::Accent))
.disabled(accept_terms_disabled)
.on_click({
let state = state.downgrade();
move |_, cx| {
state
.update(cx, |state, cx| state.accept_terms_of_service(cx))
.ok();
}
}),
);
match view_kind {
LanguageModelProviderTosView::ThreadEmptyState => button_container.justify_center(),
LanguageModelProviderTosView::PromptEditorPopup => button_container.justify_end(),
LanguageModelProviderTosView::Configuration => button_container.justify_start(),
}
});
Some(form.into_any())
}
pub struct CloudLanguageModel {
id: LanguageModelId,
model: CloudModel,
@ -852,44 +866,6 @@ impl ConfigurationView {
});
cx.notify();
}
fn render_accept_terms(&mut self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
if self.state.read(cx).has_accepted_terms_of_service(cx) {
return None;
}
let accept_terms_disabled = self.state.read(cx).accept_terms.is_some();
let terms_button = Button::new("terms_of_service", "Terms of Service")
.style(ButtonStyle::Subtle)
.icon(IconName::ArrowUpRight)
.icon_color(Color::Muted)
.icon_size(IconSize::XSmall)
.on_click(move |_, cx| cx.open_url("https://zed.dev/terms-of-service"));
let text = "To start using Zed AI, please read and accept the";
let form = v_flex()
.gap_1()
.child(h_flex().child(Label::new(text)).child(terms_button))
.child(
h_flex().child(
Button::new("accept_terms", "I've read and accept the Terms of Service")
.style(ButtonStyle::Tinted(TintColor::Accent))
.disabled(accept_terms_disabled)
.on_click({
let state = self.state.downgrade();
move |_, cx| {
state
.update(cx, |state, cx| state.accept_terms_of_service(cx))
.ok();
}
}),
),
);
Some(form.into_any())
}
}
impl Render for ConfigurationView {
@ -939,8 +915,12 @@ impl Render for ConfigurationView {
if is_connected {
v_flex()
.gap_3()
.max_w_4_5()
.children(self.render_accept_terms(cx))
.w_full()
.children(render_accept_terms(
self.state.clone(),
LanguageModelProviderTosView::Configuration,
cx,
))
.when(has_accepted_terms, |this| {
this.child(subscription_text)
.children(manage_subscription_button)