Load filtered home activity streams

This commit is contained in:
Georg Bauer
2026-07-31 17:33:45 +02:00
parent 822cf1f769
commit dba6359d30
11 changed files with 258 additions and 118 deletions

View File

@@ -5,6 +5,48 @@ use crate::{
};
use gitea_openapi::apis;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum ActivityFilter {
#[default]
All,
Issues,
PullRequests,
}
impl ActivityFilter {
fn matches(self, activity: &models::Activity) -> bool {
use models::activity::OpType;
match self {
Self::All => true,
Self::Issues => matches!(
activity.op_type,
Some(
OpType::CreateIssue
| OpType::CloseIssue
| OpType::ReopenIssue
| OpType::CommentIssue
)
),
Self::PullRequests => matches!(
activity.op_type,
Some(
OpType::CreatePullRequest
| OpType::MergePullRequest
| OpType::AutoMergePullRequest
| OpType::ClosePullRequest
| OpType::ReopenPullRequest
| OpType::CommentPull
| OpType::ApprovePullRequest
| OpType::RejectPullRequest
| OpType::PullReviewDismissed
| OpType::PullRequestReadyForReview
)
),
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum Target {
Repository {
@@ -29,7 +71,7 @@ pub enum Target {
}
impl Client {
pub async fn home(&self, page: i32) -> Result<HomeData> {
pub async fn home(&self, page: i32, filter: ActivityFilter) -> Result<HomeData> {
if page < 1 {
return Err(Error::InvalidInput("page must be positive".into()));
}
@@ -39,27 +81,51 @@ impl Client {
.await?
.login
.ok_or_else(|| Error::Generated("The server account has no username.".into()))?;
let activities = apis::user_api::user_list_activity_feeds(
&configuration,
&login,
Some(true),
None,
Some(page),
Some(DEFAULT_PAGE_SIZE),
);
let activities = activity_page(&configuration, &login, page);
let (activities, heatmap) = tokio::join!(
activities,
apis::user_api::user_get_heatmap_data(&configuration, &login),
);
let activities = activities.map_err(Error::generated)?;
Ok(HomeData {
has_more: activities.len() == DEFAULT_PAGE_SIZE as usize,
activities,
heatmap: heatmap.map_err(Error::generated)?,
})
let mut activities = activities?;
let heatmap = heatmap.map_err(Error::generated)?;
let mut page = page;
loop {
let has_more = activities.len() == DEFAULT_PAGE_SIZE as usize;
let filtered: Vec<_> = activities
.into_iter()
.filter(|activity| filter.matches(activity))
.collect();
if filter == ActivityFilter::All || !filtered.is_empty() || !has_more {
return Ok(HomeData {
activities: filtered,
heatmap,
next_page: has_more.then_some(page + 1),
});
}
page += 1;
activities = activity_page(&configuration, &login, page).await?;
}
}
}
async fn activity_page(
configuration: &apis::configuration::Configuration,
login: &str,
page: i32,
) -> Result<Vec<models::Activity>> {
apis::user_api::user_list_activity_feeds(
configuration,
login,
Some(true),
None,
Some(page),
Some(DEFAULT_PAGE_SIZE),
)
.await
.map_err(Error::generated)
}
pub fn target(activity: &models::Activity) -> Option<Target> {
use models::activity::OpType;
@@ -205,4 +271,29 @@ mod tests {
})
);
}
#[test]
fn filters_issue_and_pull_request_activity() {
let activities = [
activity(OpType::CreateIssue, ""),
activity(OpType::CreatePullRequest, ""),
activity(OpType::PullRequestReadyForReview, ""),
activity(OpType::CreateRepo, ""),
];
assert_eq!(
activities
.iter()
.filter(|activity| ActivityFilter::Issues.matches(activity))
.count(),
1
);
assert_eq!(
activities
.iter()
.filter(|activity| ActivityFilter::PullRequests.matches(activity))
.count(),
2
);
}
}

View File

@@ -164,7 +164,7 @@ pub struct HistoryCommit {
pub struct HomeData {
pub activities: Vec<models::Activity>,
pub heatmap: Vec<models::UserHeatmapData>,
pub has_more: bool,
pub next_page: Option<i32>,
}
pub type PullRefs = HashMap<String, Vec<String>>;

View File

@@ -19,6 +19,7 @@ mod milestones;
mod pulls;
mod repositories;
pub use activity::ActivityFilter;
pub use domain::{
CreateIssue, DEFAULT_PAGE_SIZE, EditIssue, HistoryCommit, HomeData, IssueDetails, IssueDraft,
IssueEditorData, IssueQuery, MilestoneDetails, MilestoneDraft, Page, PullDetails, RepositoryId,