mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-10 00:13:29 +00:00
git_ui: Show tags in Git panel history (#60534)
# Objective - Make Git Panel History show commit tags so release/version markers are visible without opening the full Git graph or commit details. ## Solution - Store commit history entries with both the commit SHA and tag names from existing git graph data. - Render tag names as muted chips next to the commit subject. - Limit visible tags to 3 per commit and show `+N` for additional tags. ## Testing - Ran `cargo check -p git_ui`. - Manually verified on Linux with `script/zed-local --stateful .`. - Confirmed tags appear in Git Panel History. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon] (https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase Git Panel History now shows commit tags inline as muted chips next to the commit subject. --- Release Notes: - Added tag labels to the Git Panel commit history. --------- Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
This commit is contained in:
parent
fc827a218e
commit
d564495dde
1 changed files with 98 additions and 26 deletions
|
|
@ -27,8 +27,9 @@ use git::Oid;
|
|||
use git::commit::ParsedCommitMessage;
|
||||
use git::repository::{
|
||||
Branch, CommitData, CommitDetails, CommitOptions, CommitSummary, DiffType, FetchOptions,
|
||||
GitCommitTemplate, GitCommitter, LogOrder, LogSource, PushOptions, Remote, RemoteCommandOutput,
|
||||
ResetMode, Upstream, UpstreamTracking, UpstreamTrackingStatus, get_git_committer,
|
||||
GitCommitTemplate, GitCommitter, InitialGraphCommitData, LogOrder, LogSource, PushOptions,
|
||||
Remote, RemoteCommandOutput, ResetMode, Upstream, UpstreamTracking, UpstreamTrackingStatus,
|
||||
get_git_committer,
|
||||
};
|
||||
use git::stash::GitStash;
|
||||
use git::status::{DiffStat, StageStatus};
|
||||
|
|
@ -80,7 +81,7 @@ use strum::{IntoEnumIterator, VariantNames};
|
|||
use theme_settings::ThemeSettings;
|
||||
use time::OffsetDateTime;
|
||||
use ui::{
|
||||
ButtonLike, Checkbox, ContextMenu, ContextMenuEntry, Divider, ElevationIndex,
|
||||
ButtonLike, Checkbox, Chip, ContextMenu, ContextMenuEntry, Divider, ElevationIndex,
|
||||
IndentGuideColors, KeyBinding, PopoverMenu, PopoverMenuHandle, ProjectEmptyState, ScrollAxes,
|
||||
Scrollbars, SplitButton, Tab, TintColor, Tooltip, WithScrollbar, prelude::*,
|
||||
};
|
||||
|
|
@ -98,6 +99,7 @@ const GIT_PANEL_KEY: &str = "GitPanel";
|
|||
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
|
||||
// TODO: We should revise this part. It seems the indentation width is not aligned with the one in project panel
|
||||
const TREE_INDENT: f32 = 16.0;
|
||||
const MAX_HISTORY_TAG_CHIPS: usize = 3;
|
||||
// Horizontal offset that aligns the tree indent guides with the row icon column.
|
||||
const INDENT_GUIDE_LEFT_OFFSET: gpui::Pixels = gpui::px(19.);
|
||||
|
||||
|
|
@ -804,7 +806,7 @@ pub struct GitPanel {
|
|||
stash_entries: GitStash,
|
||||
active_tab: GitPanelTab,
|
||||
commit_history_scroll_handle: UniformListScrollHandle,
|
||||
commit_history_shas: Option<Vec<Oid>>,
|
||||
commit_history_entries: Option<Rc<[CommitHistoryEntry]>>,
|
||||
focused_history_entry: Option<usize>,
|
||||
history_keyboard_nav: bool,
|
||||
_commit_message_buffer_subscription: Option<Subscription>,
|
||||
|
|
@ -822,6 +824,25 @@ struct BulkStaging {
|
|||
anchor: RepoPath,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CommitHistoryEntry {
|
||||
sha: Oid,
|
||||
tag_names: Vec<SharedString>,
|
||||
}
|
||||
|
||||
impl From<&Arc<InitialGraphCommitData>> for CommitHistoryEntry {
|
||||
fn from(commit: &Arc<InitialGraphCommitData>) -> Self {
|
||||
Self {
|
||||
sha: commit.sha,
|
||||
tag_names: commit
|
||||
.tag_names()
|
||||
.into_iter()
|
||||
.map(|tag_name| SharedString::from(tag_name.to_string()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_PANEL_EDITOR_LINES: usize = 6;
|
||||
|
||||
pub(crate) fn commit_message_editor(
|
||||
|
|
@ -1087,7 +1108,7 @@ impl GitPanel {
|
|||
stash_entries: Default::default(),
|
||||
active_tab: GitPanelTab::Changes,
|
||||
commit_history_scroll_handle: UniformListScrollHandle::new(),
|
||||
commit_history_shas: None,
|
||||
commit_history_entries: None,
|
||||
focused_history_entry: None,
|
||||
history_keyboard_nav: false,
|
||||
_commit_message_buffer_subscription: None,
|
||||
|
|
@ -5678,10 +5699,10 @@ impl GitPanel {
|
|||
v_flex().flex_1().size_full().overflow_hidden().map(|this| {
|
||||
let has_repo = self.active_repository.is_some();
|
||||
let has_commits = self
|
||||
.commit_history_shas
|
||||
.commit_history_entries
|
||||
.as_ref()
|
||||
.map_or(false, |shas| !shas.is_empty());
|
||||
let is_loading = self.commit_history_shas.is_none() && has_repo;
|
||||
.map_or(false, |entries| !entries.is_empty());
|
||||
let is_loading = self.commit_history_entries.is_none() && has_repo;
|
||||
if is_loading {
|
||||
this.child(
|
||||
h_flex()
|
||||
|
|
@ -5711,7 +5732,10 @@ impl GitPanel {
|
|||
}
|
||||
|
||||
fn select_next_history_entry(&mut self, cx: &mut Context<Self>) {
|
||||
let count = self.commit_history_shas.as_ref().map_or(0, Vec::len);
|
||||
let count = self
|
||||
.commit_history_entries
|
||||
.as_ref()
|
||||
.map_or(0, |entries| entries.len());
|
||||
if count == 0 {
|
||||
return;
|
||||
}
|
||||
|
|
@ -5727,7 +5751,10 @@ impl GitPanel {
|
|||
}
|
||||
|
||||
fn select_previous_history_entry(&mut self, cx: &mut Context<Self>) {
|
||||
let count = self.commit_history_shas.as_ref().map_or(0, Vec::len);
|
||||
let count = self
|
||||
.commit_history_entries
|
||||
.as_ref()
|
||||
.map_or(0, |entries| entries.len());
|
||||
if count == 0 {
|
||||
return;
|
||||
}
|
||||
|
|
@ -5746,14 +5773,18 @@ impl GitPanel {
|
|||
let Some(index) = self.focused_history_entry else {
|
||||
return;
|
||||
};
|
||||
let Some(sha) = self.commit_history_shas.as_ref().and_then(|s| s.get(index)) else {
|
||||
let Some(entry) = self
|
||||
.commit_history_entries
|
||||
.as_ref()
|
||||
.and_then(|entries| entries.get(index))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(active_repository) = self.active_repository.as_ref() else {
|
||||
return;
|
||||
};
|
||||
CommitView::open(
|
||||
sha.to_string(),
|
||||
entry.sha.to_string(),
|
||||
active_repository.downgrade(),
|
||||
self.workspace.clone(),
|
||||
None,
|
||||
|
|
@ -5794,7 +5825,7 @@ impl GitPanel {
|
|||
}
|
||||
GitPanelTab::Changes => {
|
||||
self.focus_handle.focus(window, cx);
|
||||
self.commit_history_shas.take();
|
||||
self.commit_history_entries.take();
|
||||
self.focused_history_entry = None;
|
||||
self._repo_subscriptions.clear();
|
||||
}
|
||||
|
|
@ -5833,7 +5864,7 @@ impl GitPanel {
|
|||
|this, _repo, event, cx| {
|
||||
if let RepositoryEvent::GraphEvent(_, _) = event {
|
||||
if this.active_tab == GitPanelTab::History {
|
||||
this.fetch_commit_history_shas(cx);
|
||||
this.fetch_commit_history_entries(cx);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -5844,10 +5875,10 @@ impl GitPanel {
|
|||
}));
|
||||
}
|
||||
|
||||
self.fetch_commit_history_shas(cx);
|
||||
self.fetch_commit_history_entries(cx);
|
||||
}
|
||||
|
||||
fn fetch_commit_history_shas(&mut self, cx: &mut Context<Self>) {
|
||||
fn fetch_commit_history_entries(&mut self, cx: &mut Context<Self>) {
|
||||
let Some(active_repository) = self.active_repository.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
|
@ -5860,9 +5891,13 @@ impl GitPanel {
|
|||
let log_source = LogSource::Branch(branch_name.into());
|
||||
let log_order = LogOrder::DateOrder;
|
||||
|
||||
self.commit_history_shas = Some(active_repository.update(cx, |repository, cx| {
|
||||
self.commit_history_entries = Some(active_repository.update(cx, |repository, cx| {
|
||||
let response = repository.graph_data(log_source, log_order, 0..usize::MAX, cx);
|
||||
response.commits.iter().map(|commit| commit.sha).collect()
|
||||
response
|
||||
.commits
|
||||
.iter()
|
||||
.map(CommitHistoryEntry::from)
|
||||
.collect()
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -5883,11 +5918,11 @@ impl GitPanel {
|
|||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> Option<impl IntoElement> {
|
||||
let shas = self.commit_history_shas.clone()?;
|
||||
let entries = self.commit_history_entries.clone()?;
|
||||
let active_repository = self.active_repository.as_ref()?;
|
||||
let workspace = self.workspace.clone();
|
||||
let repo_weak = active_repository.downgrade();
|
||||
let item_count = shas.len();
|
||||
let item_count = entries.len();
|
||||
let commit_history_scroll_handle = self.commit_history_scroll_handle.clone();
|
||||
let remote = self.git_remote(cx);
|
||||
|
||||
|
|
@ -5921,10 +5956,11 @@ impl GitPanel {
|
|||
|
||||
let visible_data: Vec<Option<Arc<CommitData>>> = repo_weak
|
||||
.update(cx, |repository, cx| {
|
||||
shas[range.clone()]
|
||||
entries[range.clone()]
|
||||
.iter()
|
||||
.map(|sha| {
|
||||
match repository.fetch_commit_data(*sha, false, cx) {
|
||||
.map(|entry| {
|
||||
match repository.fetch_commit_data(entry.sha, false, cx)
|
||||
{
|
||||
CommitDataState::Loaded(data) => Some(data.clone()),
|
||||
CommitDataState::Loading(_) => None,
|
||||
}
|
||||
|
|
@ -5933,16 +5969,17 @@ impl GitPanel {
|
|||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
shas[range.clone()]
|
||||
entries[range.clone()]
|
||||
.iter()
|
||||
.zip(visible_data)
|
||||
.enumerate()
|
||||
.map(|(ix, (sha, data))| {
|
||||
.map(|(ix, (entry, data))| {
|
||||
let index = range.start + ix;
|
||||
let sha_string = sha.to_string();
|
||||
let sha_string = entry.sha.to_string();
|
||||
let sha_shared: SharedString = sha_string.clone().into();
|
||||
let short_sha: SharedString =
|
||||
sha_string[..7.min(sha_string.len())].to_string().into();
|
||||
let tag_names = entry.tag_names.clone();
|
||||
|
||||
let (subject, author_name, author_email, timestamp): (
|
||||
SharedString,
|
||||
|
|
@ -6017,7 +6054,42 @@ impl GitPanel {
|
|||
h_flex()
|
||||
.gap_1()
|
||||
.w_full()
|
||||
.min_w_0()
|
||||
.child(Label::new(subject).truncate())
|
||||
.children((!tag_names.is_empty()).then(|| {
|
||||
let hidden_tag_count = tag_names
|
||||
.len()
|
||||
.saturating_sub(MAX_HISTORY_TAG_CHIPS);
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.min_w_0()
|
||||
.children(
|
||||
tag_names
|
||||
.iter()
|
||||
.take(MAX_HISTORY_TAG_CHIPS)
|
||||
.cloned()
|
||||
.map(|tag_name| {
|
||||
Chip::new(tag_name.clone())
|
||||
.truncate()
|
||||
.tooltip(Tooltip::text(
|
||||
tag_name,
|
||||
))
|
||||
}),
|
||||
)
|
||||
.when(hidden_tag_count > 0, |this| {
|
||||
let hidden_tag_names = tag_names
|
||||
[MAX_HISTORY_TAG_CHIPS..]
|
||||
.join(", ");
|
||||
this.child(
|
||||
Chip::new(format!(
|
||||
"+{hidden_tag_count}"
|
||||
))
|
||||
.tooltip(Tooltip::text(
|
||||
hidden_tag_names,
|
||||
)),
|
||||
)
|
||||
})
|
||||
}))
|
||||
.when(is_unpushed, |this| {
|
||||
this.child(
|
||||
Icon::new(IconName::ArrowUp)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue