From 6e19c9b141d169c9fc358d9bc74a632b696d1949 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Wed, 7 May 2025 20:50:52 +0300 Subject: [PATCH] Add a way to clear activity indicator (#30156) Follow-up of https://github.com/zed-industries/zed/pull/30015 * Restyles the dismiss and close buttons a bit: change the dismiss icon and add tooltips with the bindings to both * Allows ESC to clear any status that's in the activity indicator now, if all notifications are cleared: this won't suppress any further status additions though, so statuses may resurface later Release Notes: - Added a way to clear activity indicator --- .../src/activity_indicator.rs | 28 +++++++-- crates/auto_update/src/auto_update.rs | 6 +- crates/collab_ui/src/notification_panel.rs | 13 ++++- crates/workspace/src/notifications.rs | 58 +++++++++++++++---- crates/workspace/src/workspace.rs | 2 + 5 files changed, 88 insertions(+), 19 deletions(-) diff --git a/crates/activity_indicator/src/activity_indicator.rs b/crates/activity_indicator/src/activity_indicator.rs index f1cb1f0952..5ce8f06448 100644 --- a/crates/activity_indicator/src/activity_indicator.rs +++ b/crates/activity_indicator/src/activity_indicator.rs @@ -43,6 +43,7 @@ pub struct ActivityIndicator { context_menu_handle: PopoverMenuHandle, } +#[derive(Debug)] struct ServerStatus { name: SharedString, status: BinaryStatus, @@ -70,6 +71,7 @@ impl ActivityIndicator { ) -> Entity { let project = workspace.project().clone(); let auto_updater = AutoUpdater::get(cx); + let workspace_handle = cx.entity(); let this = cx.new(|cx| { let mut status_events = languages.language_server_binary_statuses(); cx.spawn(async move |this, cx| { @@ -84,6 +86,25 @@ impl ActivityIndicator { }) .detach(); + cx.subscribe_in( + &workspace_handle, + window, + |activity_indicator, _, event, window, cx| match event { + workspace::Event::ClearActivityIndicator { .. } => { + if activity_indicator.statuses.pop().is_some() { + activity_indicator.dismiss_error_message( + &DismissErrorMessage, + window, + cx, + ); + cx.notify(); + } + } + _ => {} + }, + ) + .detach(); + cx.subscribe( &project.read(cx).lsp_store(), |_, _, event, cx| match event { @@ -115,7 +136,7 @@ impl ActivityIndicator { } Self { - statuses: Default::default(), + statuses: Vec::new(), project: project.clone(), auto_updater, context_menu_handle: Default::default(), @@ -185,11 +206,8 @@ impl ActivityIndicator { cx: &mut Context, ) { if let Some(updater) = &self.auto_updater { - updater.update(cx, |updater, cx| { - updater.dismiss_error(cx); - }); + updater.update(cx, |updater, cx| updater.dismiss_error(cx)); } - cx.notify(); } fn pending_language_server_work<'a>( diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 3878bab981..6ff878f10d 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -335,9 +335,13 @@ impl AutoUpdater { self.status.clone() } - pub fn dismiss_error(&mut self, cx: &mut Context) { + pub fn dismiss_error(&mut self, cx: &mut Context) -> bool { + if self.status == AutoUpdateStatus::Idle { + return false; + } self.status = AutoUpdateStatus::Idle; cx.notify(); + true } // If you are packaging Zed and need to override the place it downloads SSH remotes from, diff --git a/crates/collab_ui/src/notification_panel.rs b/crates/collab_ui/src/notification_panel.rs index 883e17fbac..817d15aa0e 100644 --- a/crates/collab_ui/src/notification_panel.rs +++ b/crates/collab_ui/src/notification_panel.rs @@ -22,6 +22,7 @@ use ui::{ Avatar, Button, Icon, IconButton, IconName, Label, Tab, Tooltip, h_flex, prelude::*, v_flex, }; use util::{ResultExt, TryFutureExt}; +use workspace::SuppressNotification; use workspace::notifications::{ Notification as WorkspaceNotification, NotificationId, SuppressEvent, }; @@ -823,11 +824,19 @@ impl Render for NotificationToast { .child(Label::new(self.text.clone())) .child( IconButton::new("close", IconName::Close) + .tooltip(|window, cx| Tooltip::for_action("Close", &menu::Cancel, window, cx)) .on_click(cx.listener(|_, _, _, cx| cx.emit(DismissEvent))), ) .child( - IconButton::new("suppress", IconName::XCircle) - .tooltip(Tooltip::text("Do not show until restart")) + IconButton::new("suppress", IconName::SquareMinus) + .tooltip(|window, cx| { + Tooltip::for_action( + "Do not show until restart", + &SuppressNotification, + window, + cx, + ) + }) .on_click(cx.listener(|_, _, _, cx| cx.emit(SuppressEvent))), ) .on_click(cx.listener(|this, _, window, cx| { diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index eaf3085bc8..603a25044e 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -1,4 +1,4 @@ -use crate::{Toast, Workspace}; +use crate::{SuppressNotification, Toast, Workspace}; use gpui::{ AnyView, App, AppContext as _, AsyncWindowContext, ClipboardItem, Context, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, PromptLevel, Render, ScrollHandle, Task, svg, @@ -290,8 +290,15 @@ impl Render for LanguageServerPrompt { h_flex() .gap_2() .child( - IconButton::new("suppress", IconName::XCircle) - .tooltip(Tooltip::text("Do not show until restart")) + IconButton::new("suppress", IconName::SquareMinus) + .tooltip(|window, cx| { + Tooltip::for_action( + "Do not show until restart", + &SuppressNotification, + window, + cx, + ) + }) .on_click( cx.listener(|_, _, _, cx| cx.emit(SuppressEvent)), ), @@ -308,9 +315,20 @@ impl Render for LanguageServerPrompt { }) .tooltip(Tooltip::text("Copy Description")), ) - .child(IconButton::new("close", IconName::Close).on_click( - cx.listener(|_, _, _, cx| cx.emit(gpui::DismissEvent)), - )), + .child( + IconButton::new("close", IconName::Close) + .tooltip(|window, cx| { + Tooltip::for_action( + "Close", + &menu::Cancel, + window, + cx, + ) + }) + .on_click(cx.listener(|_, _, _, cx| { + cx.emit(gpui::DismissEvent) + })), + ), ), ) .child(Label::new(request.message.to_string()).size(LabelSize::Small)) @@ -443,6 +461,8 @@ pub mod simple_message_notification { }; use ui::{Tooltip, prelude::*}; + use crate::SuppressNotification; + use super::{Notification, SuppressEvent}; pub struct MessageNotification { @@ -640,8 +660,15 @@ pub mod simple_message_notification { .gap_2() .when(self.show_suppress_button, |this| { this.child( - IconButton::new("suppress", IconName::XCircle) - .tooltip(Tooltip::text("Do not show until restart")) + IconButton::new("suppress", IconName::SquareMinus) + .tooltip(|window, cx| { + Tooltip::for_action( + "Do not show until restart", + &SuppressNotification, + window, + cx, + ) + }) .on_click(cx.listener(|_, _, _, cx| { cx.emit(SuppressEvent); })), @@ -649,9 +676,18 @@ pub mod simple_message_notification { }) .when(self.show_close_button, |this| { this.child( - IconButton::new("close", IconName::Close).on_click( - cx.listener(|this, _, _, cx| this.dismiss(cx)), - ), + IconButton::new("close", IconName::Close) + .tooltip(|window, cx| { + Tooltip::for_action( + "Close", + &menu::Cancel, + window, + cx, + ) + }) + .on_click( + cx.listener(|this, _, _, cx| this.dismiss(cx)), + ), ) }), ), diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cf32d8cf50..28348f066d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -869,6 +869,7 @@ pub enum Event { }, ZoomChanged, ModalOpened, + ClearActivityIndicator, } #[derive(Debug)] @@ -5496,6 +5497,7 @@ impl Workspace { return; } + cx.emit(Event::ClearActivityIndicator); cx.propagate(); } }