feat: sort and filter pull requests by review state
This commit is contained in:
+76
-1
@@ -109,6 +109,40 @@ pub enum PullRequestReviewState {
|
||||
Requested,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
|
||||
pub(crate) enum PullRequestReviewScope {
|
||||
#[default]
|
||||
All,
|
||||
Requested,
|
||||
Approved,
|
||||
}
|
||||
|
||||
impl PullRequestReviewScope {
|
||||
pub(crate) fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::All => "All",
|
||||
Self::Requested => "Requested",
|
||||
Self::Approved => "Approved",
|
||||
}
|
||||
}
|
||||
|
||||
fn next(self) -> Self {
|
||||
match self {
|
||||
Self::All => Self::Requested,
|
||||
Self::Requested => Self::Approved,
|
||||
Self::Approved => Self::All,
|
||||
}
|
||||
}
|
||||
|
||||
fn matches(self, state: PullRequestReviewState) -> bool {
|
||||
match self {
|
||||
Self::All => true,
|
||||
Self::Requested => state == PullRequestReviewState::Requested,
|
||||
Self::Approved => state == PullRequestReviewState::Approved,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PullRequestPage {
|
||||
pub kind: RepoKind,
|
||||
@@ -582,6 +616,8 @@ pub struct DiffState {
|
||||
pull_request_categories: [PullRequestCategory; 2],
|
||||
pull_request_order: BTreeMap<u64, (String, usize, PullRequestReviewState)>,
|
||||
pub(crate) pull_request_retries: [u64; 2],
|
||||
pub(crate) pull_request_filter: PullRequestReviewScope,
|
||||
pub(crate) pull_request_priority: PullRequestReviewScope,
|
||||
pub phase: Phase,
|
||||
pub word_wrap: bool,
|
||||
pub view_mode: ViewMode,
|
||||
@@ -646,6 +682,8 @@ impl DiffState {
|
||||
pull_request_categories: Default::default(),
|
||||
pull_request_order: BTreeMap::new(),
|
||||
pull_request_retries: [0; 2],
|
||||
pull_request_filter: PullRequestReviewScope::All,
|
||||
pull_request_priority: PullRequestReviewScope::All,
|
||||
phase: Phase::Before,
|
||||
word_wrap: false,
|
||||
view_mode: ViewMode::Split,
|
||||
@@ -1324,6 +1362,10 @@ impl DiffState {
|
||||
entry.category,
|
||||
Category::Open | Category::Closed | Category::Drafts
|
||||
)))
|
||||
|| (self.pull_request_remote.is_some()
|
||||
&& !self
|
||||
.pull_request_filter
|
||||
.matches(self.pull_request_review_state(entry)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -1359,7 +1401,24 @@ impl DiffState {
|
||||
self.search_matches.push((score, index));
|
||||
}
|
||||
}
|
||||
self.search_matches.sort_unstable();
|
||||
let priority = |index: usize| {
|
||||
if self.pull_request_priority == PullRequestReviewScope::All {
|
||||
return false;
|
||||
}
|
||||
let RevisionTarget::PullRequest { number, .. } = catalog.entries[index].target
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
!self
|
||||
.pull_request_priority
|
||||
.matches(self.pull_request_order[&number].2)
|
||||
};
|
||||
if self.pull_request_priority != PullRequestReviewScope::All {
|
||||
self.visible
|
||||
.sort_unstable_by_key(|&index| (priority(index), index));
|
||||
}
|
||||
self.search_matches
|
||||
.sort_unstable_by_key(|&(score, index)| (priority(index), score, index));
|
||||
self.visible
|
||||
.extend(self.search_matches.iter().map(|(_, index)| *index));
|
||||
}
|
||||
@@ -1447,6 +1506,22 @@ impl DiffState {
|
||||
self.choose()
|
||||
}
|
||||
Input::Ctrl('r') if self.pull_request_remote.is_some() => self.retry_pull_requests(),
|
||||
Input::Ctrl('f' | 's') if self.pull_request_remote.is_some() => {
|
||||
let selected = self
|
||||
.entries()
|
||||
.nth(self.selected)
|
||||
.map(|entry| entry.target.clone());
|
||||
let scope = if input == Input::Ctrl('f') {
|
||||
&mut self.pull_request_filter
|
||||
} else {
|
||||
&mut self.pull_request_priority
|
||||
};
|
||||
*scope = scope.next();
|
||||
self.refilter();
|
||||
if let Some(target) = selected {
|
||||
self.select_target(&target);
|
||||
}
|
||||
}
|
||||
input if BackspaceKind::from_input(&input).is_some() => {
|
||||
if BackspaceKind::from_input(&input)
|
||||
.expect("guard checked backspace input")
|
||||
|
||||
@@ -108,6 +108,7 @@ Local reviews: :diff.comment anchors exact Visual text, Visual Line rows, or the
|
||||
Pull requests: :pull_requests [REMOTE]; GitHub/GitLab/Gitea Open/Closed/Drafts/All tabs, type to search
|
||||
Enter opens the immutable PR head against its merge base; API auth uses provider tokens or gh/glab
|
||||
🙏 marks a personal review request; 👍 marks your active approval (API account)
|
||||
Ctrl+f filters All/Requested/Approved; Ctrl+s sorts Newest/Requested first/Approved first
|
||||
Symbols: config.pull_request_review_requested_symbol / config.pull_request_approved_symbol
|
||||
Resolve jj conflicts: :resolve opens the current working-copy conflicts in a dedicated workspace
|
||||
Editable marker-free Draft vs readonly Alternative; :resolve.history shows inputs/base
|
||||
|
||||
+17
-6
@@ -3397,6 +3397,7 @@ fn draw_diff(
|
||||
.and_then(|catalog| catalog.notice.as_deref())
|
||||
}
|
||||
});
|
||||
let stacked_review_controls = pull_requests && content.width < 68 && content.height >= 8;
|
||||
let [
|
||||
stage_area,
|
||||
tabs_area,
|
||||
@@ -3406,7 +3407,11 @@ fn draw_diff(
|
||||
results,
|
||||
help,
|
||||
] = Layout::vertical([
|
||||
Constraint::Length(u16::from(content.height >= 5)),
|
||||
Constraint::Length(if stacked_review_controls {
|
||||
2
|
||||
} else {
|
||||
u16::from(content.height >= 5)
|
||||
}),
|
||||
Constraint::Length(u16::from(content.height >= 4)),
|
||||
Constraint::Length(1),
|
||||
Constraint::Length(u16::from(notice.is_some() && content.height >= 3)),
|
||||
@@ -3420,11 +3425,15 @@ fn draw_diff(
|
||||
.as_ref()
|
||||
.map_or("not selected", |revision| revision.label.as_str());
|
||||
let stage_text = if pull_requests {
|
||||
if diff.pull_request_partial() {
|
||||
"Partial search · Select a loaded pull request".into()
|
||||
} else {
|
||||
"Select a pull request to compare its branch changes".into()
|
||||
}
|
||||
let sort = match diff.pull_request_priority {
|
||||
crate::diff::PullRequestReviewScope::All => "Newest".into(),
|
||||
scope => format!("{} first", scope.label()),
|
||||
};
|
||||
format!(
|
||||
"Review: {} · Ctrl+f{}Sort: {sort} · Ctrl+s",
|
||||
diff.pull_request_filter.label(),
|
||||
if stacked_review_controls { "\n" } else { " " },
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{} · Ctrl+b toggle · Before: {}",
|
||||
@@ -3522,6 +3531,8 @@ fn draw_diff(
|
||||
diff.category,
|
||||
&diff.query,
|
||||
diff.comparison_mode as u8,
|
||||
diff.pull_request_filter,
|
||||
diff.pull_request_priority,
|
||||
diff.catalog
|
||||
.as_ref()
|
||||
.map(|catalog| (catalog.entries.as_ptr(), catalog.entries.len())),
|
||||
|
||||
Reference in New Issue
Block a user