Make repo and branch popovers extend up from their trigger buttons (#26950)

Previously, when clicking on the branch, the popover would obscure the
button you just clicked, which was awkward.

Release Notes:

- Improved the placement of the repo and branch picker popovers in the
git panel.
- Added a 'SelectRepo' action that opens the repository selector in a
modal.
This commit is contained in:
Max Brunsfeld 2025-03-17 15:05:17 -07:00 committed by GitHub
parent a05066cd83
commit 2b2b9c1624
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 59 additions and 49 deletions

View file

@ -7,7 +7,7 @@ use gpui::{
InteractiveElement, IntoElement, Modifiers, ModifiersChangedEvent, ParentElement, Render,
SharedString, Styled, Subscription, Task, Window,
};
use picker::{Picker, PickerDelegate};
use picker::{Picker, PickerDelegate, PickerEditorPosition};
use project::git::Repository;
use std::sync::Arc;
use time::OffsetDateTime;
@ -17,13 +17,10 @@ use util::ResultExt;
use workspace::notifications::DetachAndPromptErr;
use workspace::{ModalView, Workspace};
pub fn init(cx: &mut App) {
cx.observe_new(|workspace: &mut Workspace, _, _| {
workspace.register_action(open);
workspace.register_action(switch);
workspace.register_action(checkout_branch);
})
.detach();
pub fn register(workspace: &mut Workspace) {
workspace.register_action(open);
workspace.register_action(switch);
workspace.register_action(checkout_branch);
}
pub fn checkout_branch(
@ -225,6 +222,13 @@ impl PickerDelegate for BranchListDelegate {
"Select branch...".into()
}
fn editor_position(&self) -> PickerEditorPosition {
match self.style {
BranchListStyle::Modal => PickerEditorPosition::Start,
BranchListStyle::Popover => PickerEditorPosition::End,
}
}
fn match_count(&self) -> usize {
self.matches.len()
}

View file

@ -54,16 +54,6 @@ impl ModalContainerProperties {
}
}
pub fn init(cx: &mut App) {
cx.observe_new(|workspace: &mut Workspace, window, cx| {
let Some(window) = window else {
return;
};
CommitModal::register(workspace, window, cx)
})
.detach();
}
pub struct CommitModal {
git_panel: Entity<GitPanel>,
commit_editor: Entity<Editor>,
@ -108,7 +98,7 @@ struct RestoreDock {
}
impl CommitModal {
pub fn register(workspace: &mut Workspace, _: &mut Window, _cx: &mut Context<Workspace>) {
pub fn register(workspace: &mut Workspace) {
workspace.register_action(|workspace, _: &Commit, window, cx| {
CommitModal::toggle(workspace, window, cx);
});

View file

@ -127,18 +127,13 @@ const GIT_PANEL_KEY: &str = "GitPanel";
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
pub fn init(cx: &mut App) {
cx.observe_new(
|workspace: &mut Workspace, _window, _: &mut Context<Workspace>| {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<GitPanel>(window, cx);
});
workspace.register_action(|workspace, _: &ExpandCommitEditor, window, cx| {
CommitModal::toggle(workspace, window, cx)
});
},
)
.detach();
pub fn register(workspace: &mut Workspace) {
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
workspace.toggle_panel_focus::<GitPanel>(window, cx);
});
workspace.register_action(|workspace, _: &ExpandCommitEditor, window, cx| {
CommitModal::toggle(workspace, window, cx)
});
}
#[derive(Debug, Clone)]
@ -3829,7 +3824,7 @@ impl Render for GitPanel {
deferred(
anchored()
.position(*position)
.anchor(gpui::Corner::TopLeft)
.anchor(Corner::TopLeft)
.child(menu.clone()),
)
.with_priority(1)
@ -4087,14 +4082,14 @@ impl RenderOnce for PanelRepoFooter {
let project = project.clone();
move |window, cx| {
let project = project.clone()?;
Some(cx.new(|cx| RepositorySelector::new(project, window, cx)))
Some(cx.new(|cx| RepositorySelector::new(project, rems(16.), window, cx)))
}
})
.trigger_with_tooltip(
repo_selector_trigger.disabled(single_repo).truncate(true),
Tooltip::text("Switch active repository"),
)
.attach(gpui::Corner::BottomLeft)
.anchor(Corner::BottomLeft)
.into_any_element();
let branch_selector_button = Button::new("branch-selector", truncated_branch_name)
@ -4116,7 +4111,7 @@ impl RenderOnce for PanelRepoFooter {
branch_selector_button,
Tooltip::for_action_title("Switch Branch", &zed_actions::git::Branch),
)
.anchor(Corner::TopLeft)
.anchor(Corner::BottomLeft)
.offset(gpui::Point {
x: px(0.0),
y: px(-2.0),

View file

@ -2,6 +2,7 @@ use std::any::Any;
use ::settings::Settings;
use command_palette_hooks::CommandPaletteFilter;
use commit_modal::CommitModal;
use git::{
repository::{Branch, Upstream, UpstreamTracking, UpstreamTrackingStatus},
status::{FileStatus, StatusCode, UnmergedStatus, UnmergedStatusCode},
@ -28,12 +29,14 @@ actions!(git, [ResetOnboarding]);
pub fn init(cx: &mut App) {
GitPanelSettings::register(cx);
branch_picker::init(cx);
cx.observe_new(ProjectDiff::register).detach();
commit_modal::init(cx);
git_panel::init(cx);
cx.observe_new(|workspace: &mut Workspace, _, cx| {
ProjectDiff::register(workspace, cx);
CommitModal::register(workspace);
git_panel::register(workspace);
repository_selector::register(workspace);
branch_picker::register(workspace);
let project = workspace.project().read(cx);
if project.is_read_only(cx) {
return;

View file

@ -66,16 +66,11 @@ const TRACKED_NAMESPACE: &'static str = "1";
const NEW_NAMESPACE: &'static str = "2";
impl ProjectDiff {
pub(crate) fn register(
workspace: &mut Workspace,
_window: Option<&mut Window>,
cx: &mut Context<Workspace>,
) {
pub(crate) fn register(workspace: &mut Workspace, cx: &mut Context<Workspace>) {
workspace.register_action(Self::deploy);
workspace.register_action(|workspace, _: &Add, window, cx| {
Self::deploy(workspace, &Diff, window, cx);
});
workspace::register_serializable_item::<ProjectDiff>(cx);
}

View file

@ -9,14 +9,33 @@ use project::{
};
use std::sync::Arc;
use ui::{prelude::*, ListItem, ListItemSpacing};
use workspace::{ModalView, Workspace};
pub fn register(workspace: &mut Workspace) {
workspace.register_action(open);
}
pub fn open(
workspace: &mut Workspace,
_: &zed_actions::git::SelectRepo,
window: &mut Window,
cx: &mut Context<Workspace>,
) {
let project = workspace.project().clone();
workspace.toggle_modal(window, cx, |window, cx| {
RepositorySelector::new(project, rems(34.), window, cx)
})
}
pub struct RepositorySelector {
width: Rems,
picker: Entity<Picker<RepositorySelectorDelegate>>,
}
impl RepositorySelector {
pub fn new(
project_handle: Entity<Project>,
width: Rems,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
@ -48,7 +67,7 @@ impl RepositorySelector {
.max_height(Some(rems(20.).into()))
});
RepositorySelector { picker }
RepositorySelector { picker, width }
}
}
@ -91,10 +110,12 @@ impl Focusable for RepositorySelector {
impl Render for RepositorySelector {
fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
self.picker.clone()
div().w(self.width).child(self.picker.clone())
}
}
impl ModalView for RepositorySelector {}
pub struct RepositorySelectorDelegate {
project: WeakEntity<Project>,
repository_selector: WeakEntity<RepositorySelector>,

View file

@ -2039,7 +2039,9 @@ impl Repository {
let mut path = PathBuf::new();
path = path.join(worktree_name);
path = path.join(project_path.path);
if project_path.path.components().count() > 0 {
path = path.join(project_path.path);
}
Some(path.to_string_lossy().to_string())
})
.unwrap_or_else(|| self.repository_entry.work_directory.display_name())

View file

@ -116,7 +116,7 @@ pub mod workspace {
pub mod git {
use gpui::{action_with_deprecated_aliases, actions};
actions!(git, [CheckoutBranch, Switch]);
actions!(git, [CheckoutBranch, Switch, SelectRepo]);
action_with_deprecated_aliases!(git, Branch, ["branches::OpenRecent"]);
}