feat: stream newest pull requests by category

This commit is contained in:
Valdemar Lorenzen
2026-10-14 14:08:21 +02:00
parent 5243de66fe
commit 0000089f42
8 changed files with 1465 additions and 377 deletions
+91 -38
View File
@@ -2608,21 +2608,30 @@ fn draw_diff(
format!(" Diff · Choose {stage} · {} ", diff.comparison_mode.label())
};
let content = diff_panel(frame, panel, &title, "", "", true);
let notice = diff.error.as_deref().or_else(|| {
if diff.loading {
Some(if diff.after.is_some() {
"Loading comparison…"
} else if pull_requests {
"Loading pull requests…"
let pull_request_notice = (pull_requests && diff.phase == Phase::Before)
.then(|| diff.pull_request_notice())
.flatten();
let notice = diff
.error
.as_deref()
.or(pull_request_notice.as_deref())
.or_else(|| {
if diff.loading {
Some(
if diff.after.is_some() || (pull_requests && diff.phase == Phase::After) {
"Loading comparison…"
} else if pull_requests {
"Loading pull requests…"
} else {
"Loading repository…"
},
)
} else {
"Loading repository…"
})
} else {
diff.catalog
.as_ref()
.and_then(|catalog| catalog.notice.as_deref())
}
});
diff.catalog
.as_ref()
.and_then(|catalog| catalog.notice.as_deref())
}
});
let [
stage_area,
tabs_area,
@@ -2646,7 +2655,11 @@ fn draw_diff(
.as_ref()
.map_or("not selected", |revision| revision.label.as_str());
let stage_text = if pull_requests {
"Select a pull request to compare its branch changes".into()
if diff.pull_request_partial() {
"Partial search · Select a loaded pull request".into()
} else {
"Select a pull request to compare its branch changes".into()
}
} else {
format!(
"{} · Ctrl+b toggle · Before: {}",
@@ -2676,7 +2689,15 @@ fn draw_diff(
.collect();
frame.render_widget(Paragraph::new(Line::from(tabs)), tabs_area);
}
let query = format!("> {}", display_text(&diff.query));
let query = format!(
"> {}{}",
if pull_requests && diff.pull_request_partial() {
"[partial] "
} else {
""
},
display_text(&diff.query)
);
let width = usize::from(query_area.width);
let query_width = display_column(&query, usize::MAX);
let offset = query_width.saturating_sub(width.saturating_sub(1));
@@ -2790,7 +2811,14 @@ fn draw_diff(
));
}
}
if lines.is_empty() && !diff.loading && diff.error.is_none() {
if lines.is_empty()
&& !(if pull_requests {
diff.pull_request_partial()
} else {
diff.loading
})
&& diff.error.is_none()
{
let empty = if pull_requests {
"No matching pull requests"
} else {
@@ -2805,9 +2833,14 @@ fn draw_diff(
} else {
"select"
};
let retry = if pull_requests {
" · Ctrl+r retry category"
} else {
""
};
frame.render_widget(
Paragraph::new(format!(
"{navigation_hint} · Tab categories · type search · Enter {accept} · Esc close · Ctrl+p actions"
"{navigation_hint} · Tab categories · type search · Enter {accept}{retry} · Esc close · Ctrl+p actions"
))
.style(Style::default().fg(Color::DarkGray)),
help,
@@ -6739,7 +6772,7 @@ mod tests {
#[test]
fn pull_request_picker_renders_all_rows_without_a_pinned_offset() {
use crate::diff::{Catalog, Category, RepoKind, Revision, RevisionTarget};
use crate::diff::{Category, PullRequestPage, RepoKind, Revision, RevisionTarget};
for (width, height) in [(100, 16), (44, 12)] {
let mut diff = DiffState::pull_requests("origin".into());
diff.take_request();
@@ -6747,7 +6780,8 @@ mod tests {
Terminal::new(ratatui::backend::TestBackend::new(width, height)).unwrap();
let mut panels = WheelPanels::default();
render_diff(&mut terminal, &diff, &mut panels);
assert!(screen_text(&terminal).contains("Loading pull requests"));
assert!(screen_text(&terminal).contains("loading"));
assert!(screen_text(&terminal).contains("[partial]"));
diff.apply_result(1, Err("offline".into()));
render_diff(&mut terminal, &diff, &mut panels);
assert!(screen_text(&terminal).contains("offline"));
@@ -6756,24 +6790,30 @@ mod tests {
diff.take_request();
diff.apply_result(
2,
Ok(crate::diff::Outcome::Catalog(Catalog {
kind: RepoKind::Git,
entries: (0..20)
.map(|index| Revision {
target: RevisionTarget::PullRequest {
remote: "origin".into(),
base_ref: "refs/heads/main".into(),
base_sha: "base".into(),
head_ref: format!("refs/pull/{index}/head"),
head_sha: format!("head-{index}"),
},
label: format!("#{index:02} Pull request"),
description: "open · main ← topic".into(),
category: Category::Open,
})
.collect(),
notice: None,
})),
Ok(crate::diff::Outcome::PullRequestPage {
closed: false,
result: Ok(PullRequestPage {
kind: RepoKind::Git,
remote: "origin".into(),
entries: (0..20)
.map(|index| {
(
Revision {
target: RevisionTarget::PullRequest {
remote: "origin".into(),
number: index,
},
label: format!("#{index:02} Pull request"),
description: "open · main ← topic".into(),
category: Category::Open,
},
format!("2026-01-{:02}T00:00:00Z", 20 - index),
)
})
.collect(),
has_more: true,
}),
}),
);
render_diff(&mut terminal, &diff, &mut panels);
let text = screen_text(&terminal);
@@ -6781,6 +6821,7 @@ mod tests {
assert!(text.contains("Open") && text.contains("Closed") && text.contains("All"));
assert!(text.contains("> #00 Pull request"));
assert!(!text.contains("pinned"));
assert!(text.contains("[partial]"));
diff.handle(Input::End);
render_diff(&mut terminal, &diff, &mut panels);
let text = screen_text(&terminal);
@@ -6790,6 +6831,18 @@ mod tests {
render_diff(&mut terminal, &diff, &mut panels);
assert!(screen_text(&terminal).contains("> #00 Pull request"));
diff.handle(Input::Char('\t'));
diff.apply_result(
2,
Ok(crate::diff::Outcome::PullRequestPage {
closed: true,
result: Ok(PullRequestPage {
kind: RepoKind::Git,
remote: "origin".into(),
entries: vec![],
has_more: false,
}),
}),
);
render_diff(&mut terminal, &diff, &mut panels);
assert!(screen_text(&terminal).contains("No matching pull requests"));
}