Add overflow menu to the git panel (#25618)

Nate Butler created

Before: 

![CleanShot 2025-02-25 at 20 11
48@2x](https://github.com/user-attachments/assets/2400270e-64fe-4711-a2aa-31588e73367a)

After:

![CleanShot 2025-02-25 at 20 13
18@2x](https://github.com/user-attachments/assets/70c88d2f-5e16-4f2d-9cc5-666b2f9b8de0)

Release Notes:

- N/A

Change summary

crates/git_ui/src/git_panel.rs | 33 +++++++++++++++++++++++----------
1 file changed, 23 insertions(+), 10 deletions(-)

Detailed changes

crates/git_ui/src/git_panel.rs 🔗

@@ -34,7 +34,7 @@ use strum::{IntoEnumIterator, VariantNames};
 use time::OffsetDateTime;
 use ui::{
     prelude::*, ButtonLike, Checkbox, ContextMenu, Divider, DividerColor, ElevationIndex, ListItem,
-    ListItemSpacing, Scrollbar, ScrollbarState, Tooltip,
+    ListItemSpacing, PopoverMenu, Scrollbar, ScrollbarState, Tooltip,
 };
 use util::{maybe, post_inc, ResultExt, TryFutureExt};
 use workspace::{
@@ -1840,7 +1840,8 @@ impl GitPanel {
                                             cx.dispatch_action(&Diff);
                                         })
                                     }),
-                            ),
+                            )
+                            .child(self.render_overflow_menu()),
                     ),
             )
         } else {
@@ -1862,6 +1863,13 @@ impl GitPanel {
         })
     }
 
+    pub fn render_overflow_menu(&self) -> impl IntoElement {
+        PopoverMenu::new("overflow-menu")
+            .trigger(IconButton::new("overflow-menu-trigger", IconName::Ellipsis))
+            .menu(move |window, cx| Some(Self::panel_context_menu(window, cx)))
+            .anchor(Corner::TopRight)
+    }
+
     pub fn render_sync_button(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> {
         let active_repository = self.project.read(cx).active_repository(cx);
         active_repository.as_ref().map(|_| {
@@ -2383,21 +2391,26 @@ impl GitPanel {
         self.set_context_menu(context_menu, position, window, cx);
     }
 
-    fn deploy_panel_context_menu(
-        &mut self,
-        position: Point<Pixels>,
-        window: &mut Window,
-        cx: &mut Context<Self>,
-    ) {
-        let context_menu = ContextMenu::build(window, cx, |context_menu, _, _| {
+    fn panel_context_menu(window: &mut Window, cx: &mut App) -> Entity<ContextMenu> {
+        ContextMenu::build(window, cx, |context_menu, _, _| {
             context_menu
                 .action("Stage All", StageAll.boxed_clone())
                 .action("Unstage All", UnstageAll.boxed_clone())
+                .separator()
                 .action("Open Diff", project_diff::Diff.boxed_clone())
                 .separator()
                 .action("Discard Tracked Changes", RestoreTrackedFiles.boxed_clone())
                 .action("Trash Untracked Files", TrashUntrackedFiles.boxed_clone())
-        });
+        })
+    }
+
+    fn deploy_panel_context_menu(
+        &mut self,
+        position: Point<Pixels>,
+        window: &mut Window,
+        cx: &mut Context<Self>,
+    ) {
+        let context_menu = Self::panel_context_menu(window, cx);
         self.set_context_menu(context_menu, position, window, cx);
     }