edit predictions: Restore red dot in status buttons when pending ToS (#24408)

In one of the recent changes to the edit predictions status bar menu, we
lost the red dot that is displayed when the user has Zed as the provider
but hasn't accepted terms of service. Note: All the checks were still in
place, just the visual indicator was missing.

![CleanShot 2025-02-06 at 20 22
21@2x](https://github.com/user-attachments/assets/da8f25dd-5ed2-4bf9-8453-10b80f00bf63)


Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
This commit is contained in:
Agus Zubiaga 2025-02-07 15:42:27 -03:00 committed by GitHub
parent a7a14e59bf
commit fd7fa87939
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 93 additions and 53 deletions

View file

@ -5549,7 +5549,7 @@ impl Editor {
})) }))
.child( .child(
h_flex() h_flex()
.w_full() .flex_1()
.gap_2() .gap_2()
.child(Icon::new(IconName::ZedPredict)) .child(Icon::new(IconName::ZedPredict))
.child(Label::new("Accept Terms of Service")) .child(Label::new("Accept Terms of Service"))

View file

@ -24,8 +24,8 @@ use std::{
}; };
use supermaven::{AccountStatus, Supermaven}; use supermaven::{AccountStatus, Supermaven};
use ui::{ use ui::{
prelude::*, Clickable, ContextMenu, ContextMenuEntry, IconButton, IconButtonShape, PopoverMenu, prelude::*, Clickable, ContextMenu, ContextMenuEntry, IconButton, IconButtonShape, Indicator,
PopoverMenuHandle, Tooltip, PopoverMenu, PopoverMenuHandle, Tooltip,
}; };
use workspace::{ use workspace::{
create_and_open_local_file, item::ItemHandle, notifications::NotificationId, StatusItemView, create_and_open_local_file, item::ItemHandle, notifications::NotificationId, StatusItemView,
@ -240,24 +240,20 @@ impl Render for InlineCompletionButton {
let current_user_terms_accepted = let current_user_terms_accepted =
self.user_store.read(cx).current_user_has_accepted_terms(); self.user_store.read(cx).current_user_has_accepted_terms();
let icon_button = || { if !current_user_terms_accepted.unwrap_or(false) {
let base = IconButton::new("zed-predict-pending-button", zeta_icon) let signed_in = current_user_terms_accepted.is_some();
.shape(IconButtonShape::Square); let tooltip_meta = if signed_in {
"Read Terms of Service"
} else {
"Sign in to use"
};
match ( return div().child(
current_user_terms_accepted, IconButton::new("zed-predict-pending-button", zeta_icon)
self.popover_menu_handle.is_deployed(), .shape(IconButtonShape::Square)
enabled, .indicator(Indicator::dot().color(Color::Error))
) { .indicator_border_color(Some(cx.theme().colors().status_bar_background))
(Some(false) | None, _, _) => { .tooltip(move |window, cx| {
let signed_in = current_user_terms_accepted.is_some();
let tooltip_meta = if signed_in {
"Read Terms of Service"
} else {
"Sign in to use"
};
base.tooltip(move |window, cx| {
Tooltip::with_meta( Tooltip::with_meta(
"Edit Predictions", "Edit Predictions",
None, None,
@ -266,34 +262,38 @@ impl Render for InlineCompletionButton {
cx, cx,
) )
}) })
.on_click(cx.listener( .on_click(cx.listener(move |_, _, window, cx| {
move |_, _, window, cx| { telemetry::event!(
telemetry::event!( "Pending ToS Clicked",
"Pending ToS Clicked", source = "Edit Prediction Status Button"
source = "Edit Prediction Status Button" );
); window.dispatch_action(
window.dispatch_action( zed_actions::OpenZedPredictOnboarding.boxed_clone(),
zed_actions::OpenZedPredictOnboarding.boxed_clone(), cx,
cx, );
); })),
}, );
)) }
let icon_button = IconButton::new("zed-predict-pending-button", zeta_icon)
.shape(IconButtonShape::Square)
.when(!self.popover_menu_handle.is_deployed(), |element| {
if enabled {
element.tooltip(|window, cx| {
Tooltip::for_action("Edit Prediction", &ToggleMenu, window, cx)
})
} else {
element.tooltip(|window, cx| {
Tooltip::with_meta(
"Edit Prediction",
Some(&ToggleMenu),
"Disabled For This File",
window,
cx,
)
})
} }
(Some(true), true, _) => base, });
(Some(true), false, true) => base.tooltip(|window, cx| {
Tooltip::for_action("Edit Prediction", &ToggleMenu, window, cx)
}),
(Some(true), false, false) => base.tooltip(|window, cx| {
Tooltip::with_meta(
"Edit Prediction",
Some(&ToggleMenu),
"Disabled For This File",
window,
cx,
)
}),
}
};
let this = cx.entity().clone(); let this = cx.entity().clone();
@ -311,7 +311,7 @@ impl Render for InlineCompletionButton {
if is_refreshing { if is_refreshing {
popover_menu = popover_menu.trigger( popover_menu = popover_menu.trigger(
icon_button().with_animation( icon_button.with_animation(
"pulsating-label", "pulsating-label",
Animation::new(Duration::from_secs(2)) Animation::new(Duration::from_secs(2))
.repeat() .repeat()
@ -320,7 +320,7 @@ impl Render for InlineCompletionButton {
), ),
); );
} else { } else {
popover_menu = popover_menu.trigger(icon_button()); popover_menu = popover_menu.trigger(icon_button);
} }
div().child(popover_menu.into_any_element()) div().child(popover_menu.into_any_element())

View file

@ -1,5 +1,6 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use crate::{prelude::*, Icon, IconName, IconSize}; use crate::{prelude::*, Icon, IconName, IconSize, IconWithIndicator, Indicator};
use gpui::Hsla;
/// An icon that appears within a button. /// An icon that appears within a button.
/// ///
@ -15,6 +16,8 @@ pub(super) struct ButtonIcon {
selected_icon: Option<IconName>, selected_icon: Option<IconName>,
selected_icon_color: Option<Color>, selected_icon_color: Option<Color>,
selected_style: Option<ButtonStyle>, selected_style: Option<ButtonStyle>,
indicator: Option<Indicator>,
indicator_border_color: Option<Hsla>,
} }
impl ButtonIcon { impl ButtonIcon {
@ -28,6 +31,8 @@ impl ButtonIcon {
selected_icon: None, selected_icon: None,
selected_icon_color: None, selected_icon_color: None,
selected_style: None, selected_style: None,
indicator: None,
indicator_border_color: None,
} }
} }
@ -56,6 +61,16 @@ impl ButtonIcon {
self.selected_icon_color = color.into(); self.selected_icon_color = color.into();
self self
} }
pub fn indicator(mut self, indicator: Indicator) -> Self {
self.indicator = Some(indicator);
self
}
pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
self.indicator_border_color = color;
self
}
} }
impl Disableable for ButtonIcon { impl Disableable for ButtonIcon {
@ -96,6 +111,13 @@ impl RenderOnce for ButtonIcon {
self.color self.color
}; };
Icon::new(icon).size(self.size).color(icon_color) let icon = Icon::new(icon).size(self.size).color(icon_color);
match self.indicator {
Some(indicator) => IconWithIndicator::new(icon, Some(indicator))
.indicator_border_color(self.indicator_border_color)
.into_any_element(),
None => icon.into_any_element(),
}
} }
} }

View file

@ -1,8 +1,8 @@
#![allow(missing_docs)] #![allow(missing_docs)]
use gpui::{AnyView, DefiniteLength}; use gpui::{AnyView, DefiniteLength, Hsla};
use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle}; use super::button_like::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle};
use crate::{prelude::*, ElevationIndex, SelectableButton}; use crate::{prelude::*, ElevationIndex, Indicator, SelectableButton};
use crate::{IconName, IconSize}; use crate::{IconName, IconSize};
use super::button_icon::ButtonIcon; use super::button_icon::ButtonIcon;
@ -22,6 +22,8 @@ pub struct IconButton {
icon_size: IconSize, icon_size: IconSize,
icon_color: Color, icon_color: Color,
selected_icon: Option<IconName>, selected_icon: Option<IconName>,
indicator: Option<Indicator>,
indicator_border_color: Option<Hsla>,
alpha: Option<f32>, alpha: Option<f32>,
} }
@ -34,6 +36,8 @@ impl IconButton {
icon_size: IconSize::default(), icon_size: IconSize::default(),
icon_color: Color::Default, icon_color: Color::Default,
selected_icon: None, selected_icon: None,
indicator: None,
indicator_border_color: None,
alpha: None, alpha: None,
}; };
this.base.base = this.base.base.debug_selector(|| format!("ICON-{:?}", icon)); this.base.base = this.base.base.debug_selector(|| format!("ICON-{:?}", icon));
@ -64,6 +68,16 @@ impl IconButton {
self.selected_icon = icon.into(); self.selected_icon = icon.into();
self self
} }
pub fn indicator(mut self, indicator: Indicator) -> Self {
self.indicator = Some(indicator);
self
}
pub fn indicator_border_color(mut self, color: Option<Hsla>) -> Self {
self.indicator_border_color = color;
self
}
} }
impl Disableable for IconButton { impl Disableable for IconButton {
@ -168,6 +182,10 @@ impl RenderOnce for IconButton {
.toggle_state(is_selected) .toggle_state(is_selected)
.selected_icon(self.selected_icon) .selected_icon(self.selected_icon)
.when_some(selected_style, |this, style| this.selected_style(style)) .when_some(selected_style, |this, style| this.selected_style(style))
.when_some(self.indicator, |this, indicator| {
this.indicator(indicator)
.indicator_border_color(self.indicator_border_color)
})
.size(self.icon_size) .size(self.icon_size)
.color(Color::Custom(color)), .color(Color::Custom(color)),
) )