From db1d2defa5d44bec35b92b522fe663b6a5bc912a Mon Sep 17 00:00:00 2001 From: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> Date: Mon, 17 Mar 2025 14:08:32 -0400 Subject: [PATCH] Sync git button states between project diff & git panel (#26938) Closes #ISSUE Release Notes: - Git action buttons are now synced between the project diff and git panel Co-authored-by: Conrad Irwin Co-authored-by: Piotr Osiewicz --- crates/git_ui/src/git_panel.rs | 94 +++++++++++++------------------ crates/git_ui/src/git_ui.rs | 7 +-- crates/git_ui/src/project_diff.rs | 81 ++++++++++++-------------- 3 files changed, 74 insertions(+), 108 deletions(-) diff --git a/crates/git_ui/src/git_panel.rs b/crates/git_ui/src/git_panel.rs index 659b00287d..9ba6528f3b 100644 --- a/crates/git_ui/src/git_panel.rs +++ b/crates/git_ui/src/git_panel.rs @@ -2006,7 +2006,7 @@ impl GitPanel { } fn can_push_and_pull(&self, cx: &App) -> bool { - crate::can_push_and_pull(&self.project, cx) + !self.project.read(cx).is_via_collab() } fn get_current_remote( @@ -2822,6 +2822,36 @@ impl GitPanel { ) } + pub(crate) fn render_remote_button(&self, cx: &mut Context) -> Option { + let branch = self + .active_repository + .as_ref()? + .read(cx) + .current_branch() + .cloned(); + if !self.can_push_and_pull(cx) { + return None; + } + let spinner = self.render_spinner(); + Some( + h_flex() + .gap_1() + .flex_shrink_0() + .children(spinner) + .when_some(branch, |this, branch| { + let focus_handle = Some(self.focus_handle(cx)); + + this.children(render_remote_button( + "remote-button", + &branch, + focus_handle, + true, + )) + }) + .into_any_element(), + ) + } + pub fn render_footer( &self, window: &mut Window, @@ -2861,12 +2891,7 @@ impl GitPanel { }); let footer = v_flex() - .child(PanelRepoFooter::new( - "footer-button", - display_name, - branch, - Some(git_panel), - )) + .child(PanelRepoFooter::new(display_name, branch, Some(git_panel))) .child( panel_editor_container(window, cx) .id("commit-editor-container") @@ -3959,7 +3984,6 @@ impl Render for GitPanelMessageTooltip { #[derive(IntoElement, IntoComponent)] #[component(scope = "Version Control")] pub struct PanelRepoFooter { - id: SharedString, active_repository: SharedString, branch: Option, // Getting a GitPanel in previews will be difficult. @@ -3970,26 +3994,19 @@ pub struct PanelRepoFooter { impl PanelRepoFooter { pub fn new( - id: impl Into, active_repository: SharedString, branch: Option, git_panel: Option>, ) -> Self { Self { - id: id.into(), active_repository, branch, git_panel, } } - pub fn new_preview( - id: impl Into, - active_repository: SharedString, - branch: Option, - ) -> Self { + pub fn new_preview(active_repository: SharedString, branch: Option) -> Self { Self { - id: id.into(), active_repository, branch, git_panel: None, @@ -4105,11 +4122,6 @@ impl RenderOnce for PanelRepoFooter { y: px(-2.0), }); - let spinner = self - .git_panel - .as_ref() - .and_then(|git_panel| git_panel.read(cx).render_spinner()); - h_flex() .w_full() .px_2() @@ -4144,28 +4156,11 @@ impl RenderOnce for PanelRepoFooter { }) .child(branch_selector), ) - .child( - h_flex() - .gap_1() - .flex_shrink_0() - .children(spinner) - .when_some(branch, |this, branch| { - let mut focus_handle = None; - if let Some(git_panel) = self.git_panel.as_ref() { - if !git_panel.read(cx).can_push_and_pull(cx) { - return this; - } - focus_handle = Some(git_panel.focus_handle(cx)); - } - - this.children(render_remote_button( - self.id.clone(), - &branch, - focus_handle, - true, - )) - }), - ) + .children(if let Some(git_panel) = self.git_panel { + git_panel.update(cx, |git_panel, cx| git_panel.render_remote_button(cx)) + } else { + None + }) } } @@ -4256,7 +4251,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "no-branch", active_repository(1).clone(), None, )) @@ -4269,7 +4263,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "unknown-upstream", active_repository(2).clone(), Some(branch(unknown_upstream)), )) @@ -4282,7 +4275,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "no-remote-upstream", active_repository(3).clone(), Some(branch(no_remote_upstream)), )) @@ -4295,7 +4287,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "not-ahead-or-behind", active_repository(4).clone(), Some(branch(not_ahead_or_behind_upstream)), )) @@ -4308,7 +4299,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "behind-remote", active_repository(5).clone(), Some(branch(behind_upstream)), )) @@ -4321,7 +4311,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "ahead-of-remote", active_repository(6).clone(), Some(branch(ahead_of_upstream)), )) @@ -4334,7 +4323,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "ahead-and-behind", active_repository(7).clone(), Some(branch(ahead_and_behind_upstream)), )) @@ -4354,7 +4342,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "short-branch", SharedString::from("zed"), Some(custom("main", behind_upstream)), )) @@ -4367,7 +4354,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "long-branch", SharedString::from("zed"), Some(custom( "redesign-and-update-git-ui-list-entry-style", @@ -4383,7 +4369,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "long-repo", SharedString::from("zed-industries-community-examples"), Some(custom("gpui", ahead_of_upstream)), )) @@ -4396,7 +4381,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "long-repo-and-branch", SharedString::from("zed-industries-community-examples"), Some(custom( "redesign-and-update-git-ui-list-entry-style", @@ -4412,7 +4396,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "uppercase-repo", SharedString::from("LICENSES"), Some(custom("main", ahead_of_upstream)), )) @@ -4425,7 +4408,6 @@ impl ComponentPreview for PanelRepoFooter { .w(example_width) .overflow_hidden() .child(PanelRepoFooter::new_preview( - "uppercase-branch", SharedString::from("zed"), Some(custom("update-README", behind_upstream)), )) diff --git a/crates/git_ui/src/git_ui.rs b/crates/git_ui/src/git_ui.rs index 27499edeea..40dd1ed93d 100644 --- a/crates/git_ui/src/git_ui.rs +++ b/crates/git_ui/src/git_ui.rs @@ -7,9 +7,8 @@ use git::{ status::{FileStatus, StatusCode, UnmergedStatus, UnmergedStatusCode}, }; use git_panel_settings::GitPanelSettings; -use gpui::{actions, App, Entity, FocusHandle}; +use gpui::{actions, App, FocusHandle}; use onboarding::{clear_dismissed, GitOnboardingModal}; -use project::Project; use project_diff::ProjectDiff; use ui::prelude::*; use workspace::Workspace; @@ -120,10 +119,6 @@ pub fn git_status_icon(status: FileStatus) -> impl IntoElement { GitStatusIcon::new(status) } -fn can_push_and_pull(project: &Entity, cx: &App) -> bool { - !project.read(cx).is_via_collab() -} - fn render_remote_button( id: impl Into, branch: &Branch, diff --git a/crates/git_ui/src/project_diff.rs b/crates/git_ui/src/project_diff.rs index 40168aeffa..9ff961bce9 100644 --- a/crates/git_ui/src/project_diff.rs +++ b/crates/git_ui/src/project_diff.rs @@ -673,8 +673,6 @@ impl Render for ProjectDiff { fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { let is_empty = self.multibuffer.read(cx).is_empty(); - let can_push_and_pull = crate::can_push_and_pull(&self.project, cx); - div() .track_focus(&self.focus_handle) .key_context(if is_empty { "EmptyPane" } else { "GitDiff" }) @@ -684,6 +682,16 @@ impl Render for ProjectDiff { .justify_center() .size_full() .when(is_empty, |el| { + let remote_button = if let Some(panel) = self + .workspace + .upgrade() + .and_then(|workspace| workspace.read(cx).panel::(cx)) + { + panel.update(cx, |panel, cx| panel.render_remote_button(cx)) + } else { + None + }; + let keybinding_focus_handle = self.focus_handle(cx).clone(); el.child( v_flex() .gap_1() @@ -692,52 +700,33 @@ impl Render for ProjectDiff { .justify_around() .child(Label::new("No uncommitted changes")), ) - .when(can_push_and_pull, |this_div| { - let keybinding_focus_handle = self.focus_handle(cx); - - this_div.when_some(self.current_branch.as_ref(), |this_div, branch| { - let remote_button = crate::render_remote_button( - "project-diff-remote-button", - branch, - Some(keybinding_focus_handle.clone()), - false, - ); - - match remote_button { - Some(button) => { - this_div.child(h_flex().justify_around().child(button)) - } - None => this_div.child( - h_flex() - .justify_around() - .child(Label::new("Remote up to date")), - ), - } - }) + .map(|el| match remote_button { + Some(button) => el.child(h_flex().justify_around().child(button)), + None => el.child( + h_flex() + .justify_around() + .child(Label::new("Remote up to date")), + ), }) - .map(|this| { - let keybinding_focus_handle = self.focus_handle(cx).clone(); - - this.child( - h_flex().justify_around().mt_1().child( - Button::new("project-diff-close-button", "Close") - // .style(ButtonStyle::Transparent) - .key_binding(KeyBinding::for_action_in( - &CloseActiveItem::default(), - &keybinding_focus_handle, - window, + .child( + h_flex().justify_around().mt_1().child( + Button::new("project-diff-close-button", "Close") + // .style(ButtonStyle::Transparent) + .key_binding(KeyBinding::for_action_in( + &CloseActiveItem::default(), + &keybinding_focus_handle, + window, + cx, + )) + .on_click(move |_, window, cx| { + window.focus(&keybinding_focus_handle); + window.dispatch_action( + Box::new(CloseActiveItem::default()), cx, - )) - .on_click(move |_, window, cx| { - window.focus(&keybinding_focus_handle); - window.dispatch_action( - Box::new(CloseActiveItem::default()), - cx, - ); - }), - ), - ) - }), + ); + }), + ), + ), ) }) .when(!is_empty, |el| el.child(self.editor.clone()))