feat: sort and filter pull requests by review state

This commit is contained in:
Valdemar Lorenzen
2026-10-21 12:41:17 +02:00
parent 5c08aa0a67
commit 37b47ebc8a
7 changed files with 206 additions and 7 deletions
+76 -1
View File
@@ -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")