git_ui: More git panel refinement (#24065)
- Removes flakey keybindings from buttons - Moves git panel entries to use a standard ListItem - Show a repo selector in the panel when more than one repo is present - Remove temporary repo selector from title bar Release Notes: - N/A
This commit is contained in:
parent
52a3013d73
commit
66e2028313
5 changed files with 210 additions and 315 deletions
|
@ -1,5 +1,8 @@
|
|||
use crate::git_panel_settings::StatusStyle;
|
||||
use crate::{git_panel_settings::GitPanelSettings, git_status_icon};
|
||||
use crate::repository_selector::RepositorySelectorPopoverMenu;
|
||||
use crate::{
|
||||
git_panel_settings::GitPanelSettings, git_status_icon, repository_selector::RepositorySelector,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use db::kvp::KEY_VALUE_STORE;
|
||||
use editor::actions::MoveToEnd;
|
||||
|
@ -19,7 +22,8 @@ use settings::Settings as _;
|
|||
use std::{collections::HashSet, ops::Range, path::PathBuf, sync::Arc, time::Duration, usize};
|
||||
use theme::ThemeSettings;
|
||||
use ui::{
|
||||
prelude::*, Checkbox, Divider, DividerColor, ElevationIndex, Scrollbar, ScrollbarState, Tooltip,
|
||||
prelude::*, ButtonLike, Checkbox, Divider, DividerColor, ElevationIndex, ListItem,
|
||||
ListItemSpacing, Scrollbar, ScrollbarState, Tooltip,
|
||||
};
|
||||
use util::{ResultExt, TryFutureExt};
|
||||
use workspace::notifications::{DetachAndPromptErr, NotificationId};
|
||||
|
@ -91,6 +95,7 @@ pub struct GitPanel {
|
|||
selected_entry: Option<usize>,
|
||||
show_scrollbar: bool,
|
||||
update_visible_entries_task: Task<()>,
|
||||
repository_selector: Entity<RepositorySelector>,
|
||||
commit_editor: Entity<Editor>,
|
||||
visible_entries: Vec<GitListEntry>,
|
||||
all_staged: Option<bool>,
|
||||
|
@ -185,6 +190,9 @@ impl GitPanel {
|
|||
.detach();
|
||||
}
|
||||
|
||||
let repository_selector =
|
||||
cx.new(|cx| RepositorySelector::new(project.clone(), window, cx));
|
||||
|
||||
let mut git_panel = Self {
|
||||
focus_handle: cx.focus_handle(),
|
||||
pending_serialization: Task::ready(None),
|
||||
|
@ -194,6 +202,7 @@ impl GitPanel {
|
|||
width: Some(px(360.)),
|
||||
scrollbar_state: ScrollbarState::new(scroll_handle.clone())
|
||||
.parent_model(&cx.entity()),
|
||||
repository_selector,
|
||||
selected_entry: None,
|
||||
show_scrollbar: false,
|
||||
hide_scrollbar_task: None,
|
||||
|
@ -828,11 +837,16 @@ impl GitPanel {
|
|||
|
||||
pub fn render_panel_header(
|
||||
&self,
|
||||
window: &mut Window,
|
||||
has_write_access: bool,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> impl IntoElement {
|
||||
let focus_handle = self.focus_handle(cx).clone();
|
||||
let all_repositories = self
|
||||
.project
|
||||
.read(cx)
|
||||
.git_state()
|
||||
.map(|state| state.read(cx).all_repositories())
|
||||
.unwrap_or_default();
|
||||
let entry_count = self
|
||||
.active_repository
|
||||
.as_ref()
|
||||
|
@ -844,123 +858,102 @@ impl GitPanel {
|
|||
n => format!("{} changes", n),
|
||||
};
|
||||
|
||||
// for our use case treat None as false
|
||||
let all_staged = self.all_staged.unwrap_or(false);
|
||||
|
||||
h_flex()
|
||||
.h(px(32.))
|
||||
.items_center()
|
||||
.px_2()
|
||||
.bg(ElevationIndex::Surface.bg(cx))
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
.child(h_flex().gap_2().child(if all_repositories.len() <= 1 {
|
||||
div()
|
||||
.id("changes-label")
|
||||
.text_buffer(cx)
|
||||
.text_ui_sm(cx)
|
||||
.child(
|
||||
Checkbox::new(
|
||||
"all-changes",
|
||||
if entry_count == 0 {
|
||||
ToggleState::Selected
|
||||
} else {
|
||||
self.all_staged
|
||||
.map_or(ToggleState::Indeterminate, ToggleState::from)
|
||||
},
|
||||
)
|
||||
.fill()
|
||||
.elevation(ElevationIndex::Surface)
|
||||
.tooltip(if all_staged {
|
||||
Tooltip::text("Unstage all changes")
|
||||
} else {
|
||||
Tooltip::text("Stage all changes")
|
||||
})
|
||||
.disabled(!has_write_access || entry_count == 0)
|
||||
.on_click(cx.listener(
|
||||
move |git_panel, _, window, cx| match all_staged {
|
||||
true => git_panel.unstage_all(&UnstageAll, window, cx),
|
||||
false => git_panel.stage_all(&StageAll, window, cx),
|
||||
},
|
||||
)),
|
||||
Label::new(changes_string)
|
||||
.single_line()
|
||||
.size(LabelSize::Small),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.id("changes-checkbox-label")
|
||||
.text_buffer(cx)
|
||||
.text_ui_sm(cx)
|
||||
.child(changes_string)
|
||||
.on_click(cx.listener(
|
||||
move |git_panel, _, window, cx| match all_staged {
|
||||
true => git_panel.unstage_all(&UnstageAll, window, cx),
|
||||
false => git_panel.stage_all(&StageAll, window, cx),
|
||||
},
|
||||
)),
|
||||
),
|
||||
)
|
||||
.into_any_element()
|
||||
} else {
|
||||
self.render_repository_selector(cx).into_any_element()
|
||||
}))
|
||||
.child(div().flex_grow())
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_2()
|
||||
// TODO: Re-add once revert all is added
|
||||
// .child(
|
||||
// IconButton::new("discard-changes", IconName::Undo)
|
||||
// .tooltip({
|
||||
// let focus_handle = focus_handle.clone();
|
||||
// move |cx| {
|
||||
// Tooltip::for_action_in(
|
||||
// "Discard all changes",
|
||||
// &RevertAll,
|
||||
// &focus_handle,
|
||||
// cx,
|
||||
// )
|
||||
// }
|
||||
// })
|
||||
// .icon_size(IconSize::Small)
|
||||
// .disabled(true),
|
||||
// )
|
||||
.child(if self.all_staged.unwrap_or(false) {
|
||||
self.panel_button("unstage-all", "Unstage All")
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Unstage all changes",
|
||||
&UnstageAll,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.key_binding(ui::KeyBinding::for_action_in(
|
||||
.child(h_flex().gap_2().child(if self.all_staged.unwrap_or(false) {
|
||||
self.panel_button("unstage-all", "Unstage All")
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Unstage all changes",
|
||||
&UnstageAll,
|
||||
&focus_handle,
|
||||
window,
|
||||
))
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.unstage_all(&UnstageAll, window, cx)
|
||||
}))
|
||||
} else {
|
||||
self.panel_button("stage-all", "Stage All")
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Stage all changes",
|
||||
&StageAll,
|
||||
&focus_handle,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.key_binding(ui::KeyBinding::for_action_in(
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.unstage_all(&UnstageAll, window, cx)
|
||||
}))
|
||||
} else {
|
||||
self.panel_button("stage-all", "Stage All")
|
||||
.tooltip({
|
||||
let focus_handle = focus_handle.clone();
|
||||
move |window, cx| {
|
||||
Tooltip::for_action_in(
|
||||
"Stage all changes",
|
||||
&StageAll,
|
||||
&focus_handle,
|
||||
window,
|
||||
))
|
||||
.on_click(cx.listener(move |this, _, window, cx| {
|
||||
this.stage_all(&StageAll, window, cx)
|
||||
}))
|
||||
}),
|
||||
)
|
||||
cx,
|
||||
)
|
||||
}
|
||||
})
|
||||
.on_click(
|
||||
cx.listener(move |this, _, window, cx| {
|
||||
this.stage_all(&StageAll, window, cx)
|
||||
}),
|
||||
)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn render_repository_selector(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let active_repository = self.project.read(cx).active_repository(cx);
|
||||
let repository_display_name = active_repository
|
||||
.as_ref()
|
||||
.map(|repo| repo.display_name(self.project.read(cx), cx))
|
||||
.unwrap_or_default();
|
||||
|
||||
let entry_count = self.visible_entries.len();
|
||||
|
||||
RepositorySelectorPopoverMenu::new(
|
||||
self.repository_selector.clone(),
|
||||
ButtonLike::new("active-repository")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.child(
|
||||
h_flex().w_full().gap_0p5().child(
|
||||
div()
|
||||
.overflow_x_hidden()
|
||||
.flex_grow()
|
||||
.whitespace_nowrap()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
Label::new(repository_display_name).size(LabelSize::Small),
|
||||
)
|
||||
.when(entry_count > 0, |flex| {
|
||||
flex.child(
|
||||
Label::new(format!("({})", entry_count))
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
})
|
||||
.into_any_element(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn render_commit_editor(
|
||||
|
@ -1041,12 +1034,10 @@ impl GitPanel {
|
|||
.absolute()
|
||||
.bottom_2p5()
|
||||
.right_3()
|
||||
.gap_1p5()
|
||||
.child(div().gap_1().flex_grow())
|
||||
.child(if self.current_modifiers.alt {
|
||||
commit_all_button
|
||||
} else {
|
||||
commit_staged_button
|
||||
}),
|
||||
.child(commit_all_button)
|
||||
.child(commit_staged_button),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -1124,7 +1115,7 @@ impl GitPanel {
|
|||
fn render_entries(&self, has_write_access: bool, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let entry_count = self.visible_entries.len();
|
||||
|
||||
h_flex()
|
||||
v_flex()
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.child(
|
||||
|
@ -1140,12 +1131,15 @@ impl GitPanel {
|
|||
.size_full()
|
||||
.with_sizing_behavior(ListSizingBehavior::Infer)
|
||||
.with_horizontal_sizing_behavior(ListHorizontalSizingBehavior::Unconstrained)
|
||||
// .with_width_from_item(self.max_width_item_index)
|
||||
.track_scroll(self.scroll_handle.clone()),
|
||||
)
|
||||
.children(self.render_scrollbar(cx))
|
||||
}
|
||||
|
||||
fn entry_label(&self, label: impl Into<SharedString>, color: Color) -> Label {
|
||||
Label::new(label.into()).color(color).single_line()
|
||||
}
|
||||
|
||||
fn render_entry(
|
||||
&self,
|
||||
ix: usize,
|
||||
|
@ -1157,149 +1151,117 @@ impl GitPanel {
|
|||
let selected = self.selected_entry == Some(ix);
|
||||
let status_style = GitPanelSettings::get_global(cx).status_style;
|
||||
let status = entry_details.status;
|
||||
let has_conflict = status.is_conflicted();
|
||||
let is_modified = status.is_modified();
|
||||
let is_deleted = status.is_deleted();
|
||||
|
||||
let mut label_color = cx.theme().colors().text;
|
||||
if status_style == StatusStyle::LabelColor {
|
||||
label_color = if status.is_conflicted() {
|
||||
cx.theme().colors().version_control_conflict
|
||||
} else if status.is_modified() {
|
||||
cx.theme().colors().version_control_modified
|
||||
} else if status.is_deleted() {
|
||||
// Don't use `version_control_deleted` here or all the
|
||||
// deleted entries will be likely a red color.
|
||||
cx.theme().colors().text_disabled
|
||||
let label_color = if status_style == StatusStyle::LabelColor {
|
||||
if has_conflict {
|
||||
Color::Conflict
|
||||
} else if is_modified {
|
||||
Color::Modified
|
||||
} else if is_deleted {
|
||||
// We don't want a bunch of red labels in the list
|
||||
Color::Disabled
|
||||
} else {
|
||||
cx.theme().colors().version_control_added
|
||||
Color::Created
|
||||
}
|
||||
}
|
||||
|
||||
let path_color = status
|
||||
.is_deleted()
|
||||
.then_some(cx.theme().colors().text_disabled)
|
||||
.unwrap_or(cx.theme().colors().text_muted);
|
||||
|
||||
let entry_id = ElementId::Name(format!("entry_{}", entry_details.display_name).into());
|
||||
let checkbox_id =
|
||||
ElementId::Name(format!("checkbox_{}", entry_details.display_name).into());
|
||||
let is_tree_view = false;
|
||||
let handle = cx.entity().downgrade();
|
||||
|
||||
let end_slot = h_flex()
|
||||
.invisible()
|
||||
.when(selected, |this| this.visible())
|
||||
.when(!selected, |this| {
|
||||
this.group_hover("git-panel-entry", |this| this.visible())
|
||||
})
|
||||
.gap_1()
|
||||
.items_center()
|
||||
.child(
|
||||
IconButton::new("more", IconName::EllipsisVertical)
|
||||
.icon_color(Color::Placeholder)
|
||||
.icon_size(IconSize::Small),
|
||||
);
|
||||
|
||||
let mut entry = h_flex()
|
||||
.id(entry_id)
|
||||
.group("git-panel-entry")
|
||||
.h(px(28.))
|
||||
.w_full()
|
||||
.pr(px(4.))
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.font_buffer(cx)
|
||||
.text_ui_sm(cx)
|
||||
.when(!selected, |this| {
|
||||
this.hover(|this| this.bg(cx.theme().colors().ghost_element_hover))
|
||||
});
|
||||
|
||||
if is_tree_view {
|
||||
entry = entry.pl(px(8. + 12. * entry_details.depth as f32))
|
||||
} else {
|
||||
entry = entry.pl(px(8.))
|
||||
}
|
||||
Color::Default
|
||||
};
|
||||
|
||||
if selected {
|
||||
entry = entry.bg(cx.theme().status().info_background);
|
||||
}
|
||||
let path_color = if status.is_deleted() {
|
||||
Color::Disabled
|
||||
} else {
|
||||
Color::Muted
|
||||
};
|
||||
|
||||
entry = entry
|
||||
.child(
|
||||
Checkbox::new(
|
||||
checkbox_id,
|
||||
entry_details
|
||||
.is_staged
|
||||
.map_or(ToggleState::Indeterminate, ToggleState::from),
|
||||
)
|
||||
.disabled(!has_write_access)
|
||||
.fill()
|
||||
.elevation(ElevationIndex::Surface)
|
||||
.on_click({
|
||||
let handle = handle.clone();
|
||||
let id: ElementId = ElementId::Name(format!("entry_{}", entry_details.display_name).into());
|
||||
|
||||
let checkbox = Checkbox::new(
|
||||
id,
|
||||
entry_details
|
||||
.is_staged
|
||||
.map_or(ToggleState::Indeterminate, ToggleState::from),
|
||||
)
|
||||
.disabled(!has_write_access)
|
||||
.fill()
|
||||
.elevation(ElevationIndex::Surface)
|
||||
.on_click({
|
||||
let handle = cx.entity().downgrade();
|
||||
let repo_path = repo_path.clone();
|
||||
move |toggle, _window, cx| {
|
||||
let Some(this) = handle.upgrade() else {
|
||||
return;
|
||||
};
|
||||
this.update(cx, |this, cx| {
|
||||
this.visible_entries[ix].is_staged = match *toggle {
|
||||
ToggleState::Selected => Some(true),
|
||||
ToggleState::Unselected => Some(false),
|
||||
ToggleState::Indeterminate => None,
|
||||
};
|
||||
let repo_path = repo_path.clone();
|
||||
move |toggle, _window, cx| {
|
||||
let Some(active_repository) = this.active_repository.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let result = match toggle {
|
||||
ToggleState::Selected | ToggleState::Indeterminate => active_repository
|
||||
.stage_entries(vec![repo_path], this.err_sender.clone()),
|
||||
ToggleState::Unselected => active_repository
|
||||
.unstage_entries(vec![repo_path], this.err_sender.clone()),
|
||||
};
|
||||
if let Err(e) = result {
|
||||
this.show_err_toast("toggle staged error", e, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let start_slot = h_flex()
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.child(checkbox)
|
||||
.child(git_status_icon(status, cx));
|
||||
|
||||
let id = ElementId::Name(format!("entry_{}", entry_details.display_name).into());
|
||||
|
||||
div().w_full().px_0p5().child(
|
||||
ListItem::new(id)
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.start_slot(start_slot)
|
||||
.toggle_state(selected)
|
||||
.disabled(!has_write_access)
|
||||
.on_click({
|
||||
let handle = cx.entity().downgrade();
|
||||
move |_, window, cx| {
|
||||
let Some(this) = handle.upgrade() else {
|
||||
return;
|
||||
};
|
||||
this.update(cx, |this, cx| {
|
||||
this.visible_entries[ix].is_staged = match *toggle {
|
||||
ToggleState::Selected => Some(true),
|
||||
ToggleState::Unselected => Some(false),
|
||||
ToggleState::Indeterminate => None,
|
||||
};
|
||||
let repo_path = repo_path.clone();
|
||||
let Some(active_repository) = this.active_repository.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let result = match toggle {
|
||||
ToggleState::Selected | ToggleState::Indeterminate => {
|
||||
active_repository
|
||||
.stage_entries(vec![repo_path], this.err_sender.clone())
|
||||
}
|
||||
ToggleState::Unselected => active_repository
|
||||
.unstage_entries(vec![repo_path], this.err_sender.clone()),
|
||||
};
|
||||
if let Err(e) = result {
|
||||
this.show_err_toast("toggle staged error", e, cx);
|
||||
}
|
||||
this.selected_entry = Some(ix);
|
||||
window.dispatch_action(Box::new(OpenSelected), cx);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
}),
|
||||
)
|
||||
.when(status_style == StatusStyle::Icon, |this| {
|
||||
this.child(git_status_icon(status, cx))
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.text_color(label_color)
|
||||
.when(status.is_deleted(), |this| this.line_through())
|
||||
.when_some(repo_path.parent(), |this, parent| {
|
||||
let parent_str = parent.to_string_lossy();
|
||||
if !parent_str.is_empty() {
|
||||
this.child(
|
||||
div()
|
||||
.text_color(path_color)
|
||||
.child(format!("{}/", parent_str)),
|
||||
)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
})
|
||||
.child(div().child(entry_details.display_name.clone())),
|
||||
)
|
||||
.child(div().flex_1())
|
||||
.child(end_slot)
|
||||
.on_click(move |_, window, cx| {
|
||||
// TODO: add `select_entry` method then do after that
|
||||
window.dispatch_action(Box::new(OpenSelected), cx);
|
||||
|
||||
handle
|
||||
.update(cx, |git_panel, _| {
|
||||
git_panel.selected_entry = Some(ix);
|
||||
})
|
||||
.ok();
|
||||
});
|
||||
|
||||
entry
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.when_some(repo_path.parent(), |this, parent| {
|
||||
let parent_str = parent.to_string_lossy();
|
||||
if !parent_str.is_empty() {
|
||||
this.child(
|
||||
self.entry_label(format!("{}/", parent_str), path_color)
|
||||
.when(status.is_deleted(), |this| this.strikethrough(true)),
|
||||
)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
})
|
||||
.child(
|
||||
self.entry_label(entry_details.display_name.clone(), label_color)
|
||||
.when(status.is_deleted(), |this| this.strikethrough(true)),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1426,10 +1388,9 @@ impl Render for GitPanel {
|
|||
}))
|
||||
.size_full()
|
||||
.overflow_hidden()
|
||||
.font_buffer(cx)
|
||||
.py_1()
|
||||
.bg(ElevationIndex::Surface.bg(cx))
|
||||
.child(self.render_panel_header(window, has_write_access, cx))
|
||||
.child(self.render_panel_header(window, cx))
|
||||
.child(self.render_divider(cx))
|
||||
.child(if has_entries {
|
||||
self.render_entries(has_write_access, cx).into_any_element()
|
||||
|
|
|
@ -34,7 +34,8 @@ impl RepositorySelector {
|
|||
};
|
||||
|
||||
let picker = cx.new(|cx| {
|
||||
Picker::uniform_list(delegate, window, cx).max_height(Some(rems(20.).into()))
|
||||
Picker::nonsearchable_uniform_list(delegate, window, cx)
|
||||
.max_height(Some(rems(20.).into()))
|
||||
});
|
||||
|
||||
let _subscriptions = if let Some(git_state) = git_state {
|
||||
|
@ -236,18 +237,4 @@ impl PickerDelegate for RepositorySelectorDelegate {
|
|||
.child(Label::new(display_name)),
|
||||
)
|
||||
}
|
||||
|
||||
fn render_footer(
|
||||
&self,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Picker<Self>>,
|
||||
) -> Option<gpui::AnyElement> {
|
||||
// TODO: Implement footer rendering if needed
|
||||
Some(
|
||||
div()
|
||||
.text_ui_sm(cx)
|
||||
.child("Temporary location for repo selector")
|
||||
.into_any_element(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ util.workspace = true
|
|||
telemetry.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
git_ui.workspace = true
|
||||
zed_predict_onboarding.workspace = true
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
|
|
|
@ -15,9 +15,7 @@ use crate::platforms::{platform_linux, platform_mac, platform_windows};
|
|||
use auto_update::AutoUpdateStatus;
|
||||
use call::ActiveCall;
|
||||
use client::{Client, UserStore};
|
||||
use feature_flags::{FeatureFlagAppExt, GitUiFeatureFlag, ZedPro};
|
||||
use git_ui::repository_selector::RepositorySelector;
|
||||
use git_ui::repository_selector::RepositorySelectorPopoverMenu;
|
||||
use feature_flags::{FeatureFlagAppExt, ZedPro};
|
||||
use gpui::{
|
||||
actions, div, px, Action, AnyElement, App, Context, Decorations, Element, Entity,
|
||||
InteractiveElement, Interactivity, IntoElement, MouseButton, ParentElement, Render, Stateful,
|
||||
|
@ -27,7 +25,6 @@ use project::Project;
|
|||
use rpc::proto;
|
||||
use settings::Settings as _;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use theme::ActiveTheme;
|
||||
use ui::{
|
||||
|
@ -105,7 +102,6 @@ pub struct TitleBar {
|
|||
platform_style: PlatformStyle,
|
||||
content: Stateful<Div>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
repository_selector: Entity<RepositorySelector>,
|
||||
project: Entity<Project>,
|
||||
user_store: Entity<UserStore>,
|
||||
client: Arc<Client>,
|
||||
|
@ -113,7 +109,6 @@ pub struct TitleBar {
|
|||
should_move: bool,
|
||||
application_menu: Option<Entity<ApplicationMenu>>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
git_ui_enabled: Arc<AtomicBool>,
|
||||
zed_predict_banner: Entity<ZedPredictBanner>,
|
||||
}
|
||||
|
||||
|
@ -191,7 +186,6 @@ impl Render for TitleBar {
|
|||
title_bar
|
||||
.children(self.render_project_host(cx))
|
||||
.child(self.render_project_name(cx))
|
||||
.children(self.render_current_repository(cx))
|
||||
.children(self.render_project_branch(cx))
|
||||
})
|
||||
})
|
||||
|
@ -302,14 +296,6 @@ impl TitleBar {
|
|||
subscriptions.push(cx.observe_window_activation(window, Self::window_activation_changed));
|
||||
subscriptions.push(cx.observe(&user_store, |_, _, cx| cx.notify()));
|
||||
|
||||
let is_git_ui_enabled = Arc::new(AtomicBool::new(false));
|
||||
subscriptions.push(cx.observe_flag::<GitUiFeatureFlag, _>({
|
||||
let is_git_ui_enabled = is_git_ui_enabled.clone();
|
||||
move |enabled, _cx| {
|
||||
is_git_ui_enabled.store(enabled, Ordering::SeqCst);
|
||||
}
|
||||
}));
|
||||
|
||||
let zed_predict_banner = cx.new(|cx| {
|
||||
ZedPredictBanner::new(
|
||||
workspace.weak_handle(),
|
||||
|
@ -325,14 +311,12 @@ impl TitleBar {
|
|||
content: div().id(id.into()),
|
||||
children: SmallVec::new(),
|
||||
application_menu,
|
||||
repository_selector: cx.new(|cx| RepositorySelector::new(project.clone(), window, cx)),
|
||||
workspace: workspace.weak_handle(),
|
||||
should_move: false,
|
||||
project,
|
||||
user_store,
|
||||
client,
|
||||
_subscriptions: subscriptions,
|
||||
git_ui_enabled: is_git_ui_enabled,
|
||||
zed_predict_banner,
|
||||
}
|
||||
}
|
||||
|
@ -515,41 +499,6 @@ impl TitleBar {
|
|||
}))
|
||||
}
|
||||
|
||||
// NOTE: Not sure we want to keep this in the titlebar, but for while we are working on Git it is helpful in the short term
|
||||
pub fn render_current_repository(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> {
|
||||
if !self.git_ui_enabled.load(Ordering::SeqCst) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let active_repository = self.project.read(cx).active_repository(cx)?;
|
||||
let display_name = active_repository.display_name(self.project.read(cx), cx);
|
||||
|
||||
// TODO: what to render if no active repository?
|
||||
Some(RepositorySelectorPopoverMenu::new(
|
||||
self.repository_selector.clone(),
|
||||
ButtonLike::new("active-repository")
|
||||
.style(ButtonStyle::Subtle)
|
||||
.child(
|
||||
h_flex().w_full().gap_0p5().child(
|
||||
div()
|
||||
.overflow_x_hidden()
|
||||
.flex_grow()
|
||||
.whitespace_nowrap()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
Label::new(display_name)
|
||||
.size(LabelSize::Small)
|
||||
.color(Color::Muted),
|
||||
)
|
||||
.into_any_element(),
|
||||
),
|
||||
),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn render_project_branch(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> {
|
||||
let entry = {
|
||||
let mut names_and_branches =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue