From 70a742eadcf8968f80378ec4e424d7cc45860cef Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Mon, 16 Mar 2026 12:30:32 -0300 Subject: [PATCH] git_ui: Don't display the merge conflict notification if an agent is running (#51498) This PR is motivated by internal feedback in which the notification that we show inviting to resolve merging conflicts with an agent also pops up if the agent itself ran `git merge`. In this case, the notification is unnecessary noise. So, what I'm doing here is simply _not_ showing it if there's a running agent. I want to note that this change is accepting a trade-off here, in which there could be cases that even if an agent is running, the notification can still be useful. There could be other ways to identify whether the agent is running `git merge`, but they all felt a bit too complex for the moment. And given this is reasonably an edge case, I'm favoring a simple approach for now. Release Notes: - N/A --------- Co-authored-by: Lukas Wirth --- .../src/connection_view/thread_view.rs | 26 +++++++++++++++++-- crates/git_ui/src/conflict_view.rs | 17 +++++------- crates/workspace/src/notifications.rs | 8 ++++++ crates/workspace/src/workspace.rs | 6 +++++ 4 files changed, 44 insertions(+), 13 deletions(-) diff --git a/crates/agent_ui/src/connection_view/thread_view.rs b/crates/agent_ui/src/connection_view/thread_view.rs index c5e44a582cefba92161760711ebd5ba6bf0d1936..29ba06f470d78d60772b63ce54802647ef303444 100644 --- a/crates/agent_ui/src/connection_view/thread_view.rs +++ b/crates/agent_ui/src/connection_view/thread_view.rs @@ -739,10 +739,13 @@ impl ThreadView { } } })); + if self.parent_id.is_none() { + self.suppress_merge_conflict_notification(cx); + } generation } - pub fn stop_turn(&mut self, generation: usize) { + pub fn stop_turn(&mut self, generation: usize, cx: &mut Context) { if self.turn_fields.turn_generation != generation { return; } @@ -753,6 +756,25 @@ impl ThreadView { .map(|started| started.elapsed()); self.turn_fields.last_turn_tokens = self.turn_fields.turn_tokens.take(); self.turn_fields._turn_timer_task = None; + if self.parent_id.is_none() { + self.unsuppress_merge_conflict_notification(cx); + } + } + + fn suppress_merge_conflict_notification(&self, cx: &mut Context) { + self.workspace + .update(cx, |workspace, cx| { + workspace.suppress_notification(&workspace::merge_conflict_notification_id(), cx); + }) + .ok(); + } + + fn unsuppress_merge_conflict_notification(&self, cx: &mut Context) { + self.workspace + .update(cx, |workspace, _cx| { + workspace.unsuppress(workspace::merge_conflict_notification_id()); + }) + .ok(); } pub fn update_turn_tokens(&mut self, cx: &App) { @@ -962,7 +984,7 @@ impl ThreadView { let mut cx = cx.clone(); move || { this.update(&mut cx, |this, cx| { - this.stop_turn(generation); + this.stop_turn(generation, cx); cx.notify(); }) .ok(); diff --git a/crates/git_ui/src/conflict_view.rs b/crates/git_ui/src/conflict_view.rs index d3bb5213a5c5c94171d48d324c7ce05e6399399f..96faa8879b38f59133bf3679788a3c24d1201f54 100644 --- a/crates/git_ui/src/conflict_view.rs +++ b/crates/git_ui/src/conflict_view.rs @@ -18,10 +18,7 @@ use settings::Settings; use std::{cell::RefCell, ops::Range, rc::Rc, sync::Arc}; use ui::{ActiveTheme, Divider, Element as _, Styled, Window, prelude::*}; use util::{ResultExt as _, debug_panic, maybe}; -use workspace::{ - Workspace, - notifications::{NotificationId, simple_message_notification::MessageNotification}, -}; +use workspace::{Workspace, notifications::simple_message_notification::MessageNotification}; use zed_actions::agent::{ ConflictContent, ResolveConflictedFilesWithAgent, ResolveConflictsWithAgent, }; @@ -500,12 +497,6 @@ fn render_conflict_buttons( .into_any() } -struct MergeConflictNotification; - -fn merge_conflict_notification_id() -> NotificationId { - NotificationId::unique::() -} - fn collect_conflicted_file_paths(workspace: &Workspace, cx: &App) -> Vec { let project = workspace.project().read(cx); let git_store = project.git_store().read(cx); @@ -547,8 +538,12 @@ pub(crate) fn register_conflict_notification( return; } + if workspace.is_notification_suppressed(workspace::merge_conflict_notification_id()) { + return; + } + let paths = collect_conflicted_file_paths(workspace, cx); - let notification_id = merge_conflict_notification_id(); + let notification_id = workspace::merge_conflict_notification_id(); let current_paths_set: HashSet = paths.iter().cloned().collect(); if paths.is_empty() { diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 29bb9d7b063ff6e4b9f472d708f354fb50f7a2e8..85b1fe4e707acbc7107df14d23caa3bda24519e5 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -234,6 +234,14 @@ impl Workspace { self.suppressed_notifications.insert(id.clone()); } + pub fn is_notification_suppressed(&self, notification_id: NotificationId) -> bool { + self.suppressed_notifications.contains(¬ification_id) + } + + pub fn unsuppress(&mut self, notification_id: NotificationId) { + self.suppressed_notifications.remove(¬ification_id); + } + pub fn show_initial_notifications(&mut self, cx: &mut Context) { // Allow absence of the global so that tests don't need to initialize it. let app_notifications = GLOBAL_APP_NOTIFICATIONS diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 7696af97996a83db0aab05dc11d03f6ac0a77513..dc3d076bd6addc911dfdbf0cc736d876acc78484 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -7268,6 +7268,12 @@ impl GlobalAnyActiveCall { cx.global() } } + +pub fn merge_conflict_notification_id() -> NotificationId { + struct MergeConflictNotification; + NotificationId::unique::() +} + /// Workspace-local view of a remote participant's location. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ParticipantLocation {