use std::cmp::Reverse;
use std::collections::HashSet;
use std::path::Path;
use super::App;
use super::types::CiRunDisplayMode;
use crate::ci;
use crate::ci::CiRun;
use crate::project::AbsolutePath;
use crate::project::ProjectCiData;
use crate::project::ProjectCiInfo;
use crate::project::ProjectPrData;
use crate::scan;
use crate::scan::CachedRepoData;
use crate::scan::CiFetchResult;
use crate::tui::panes::CiFetchKind;
impl App {
pub(super) fn insert_ci_runs(&mut self, path: &Path, runs: Vec<CiRun>, github_total: u32) {
let exhausted = self
.project_list
.primary_url_for(path)
.and_then(ci::parse_owner_repo)
.is_some_and(|owner_repo| scan::is_exhausted(owner_repo.owner(), owner_repo.repo()));
if let Some(entry) = self.project_list.entry_containing_mut(path) {
let repo = entry.git_repo.get_or_insert_with(Default::default);
repo.ci_data = ProjectCiData::Loaded(ProjectCiInfo {
runs,
github_total,
exhausted,
});
} else {
self.ci.fetch_tracker.complete(path);
}
}
pub(super) fn handle_ci_fetch_complete(
&mut self,
path: &str,
result: CiFetchResult,
kind: CiFetchKind,
) -> bool {
let abs = AbsolutePath::from(Path::new(path));
let prev_info = self.project_list.ci_info_for(abs.as_path());
let prev_count = prev_info.map_or(0, |info| info.runs.len());
let prev_exhausted = prev_info.is_some_and(|info| info.exhausted);
let prev_github_total = prev_info.map_or(0, |info| info.github_total);
let github_total = match (&result, kind) {
(CiFetchResult::Loaded { github_total, .. }, CiFetchKind::Sync) => *github_total,
_ => prev_github_total,
};
let new_runs = result.into_runs();
let existing = prev_info.map_or_else(Vec::new, |info| info.runs.clone());
let mut seen = HashSet::new();
let mut merged = Vec::new();
for run in new_runs {
if seen.insert(run.run_id) {
merged.push(run);
}
}
for run in existing {
if seen.insert(run.run_id) {
merged.push(run);
}
}
merged.sort_by_key(|run| Reverse(run.run_id));
let found_new = merged.len() > prev_count;
let chain_older =
matches!(kind, CiFetchKind::Sync) && !found_new && merged.last().is_some();
let exhausted = match kind {
CiFetchKind::Sync => {
if found_new {
if let Some(url) = self.project_list.primary_url_for(&abs)
&& let Some(owner_repo) = ci::parse_owner_repo(url)
{
scan::clear_exhausted(owner_repo.owner(), owner_repo.repo());
}
false
} else {
if !chain_older {
self.overlays.set_status_flash(
"no new runs found".to_string(),
std::time::Instant::now(),
);
}
prev_exhausted
}
},
CiFetchKind::FetchOlder => {
if found_new {
if let Some(url) = self.project_list.primary_url_for(&abs)
&& let Some(owner_repo) = ci::parse_owner_repo(url)
{
scan::clear_exhausted(owner_repo.owner(), owner_repo.repo());
}
false
} else {
if let Some(url) = self.project_list.primary_url_for(&abs)
&& let Some(owner_repo) = ci::parse_owner_repo(url)
{
scan::mark_exhausted(owner_repo.owner(), owner_repo.repo());
}
self.overlays.set_status_flash(
"no older runs found".to_string(),
std::time::Instant::now(),
);
true
}
},
};
self.ci.viewport.set_pos(merged.len());
if let Some(repo) = self.project_list.owner_repo_for_path_inner(&abs) {
let cached = scan::load_cached_repo_data(&self.net.github.fetch_cache, &repo);
let meta = cached.as_ref().and_then(|cached| cached.meta.clone());
let pr_data = cached.map_or(ProjectPrData::Unfetched, |cached| cached.pr_data);
scan::store_cached_repo_data(
&self.net.github.fetch_cache,
&repo,
CachedRepoData {
runs: merged.clone(),
meta,
github_total,
pr_data,
},
);
}
self.ci.fetch_tracker.complete(abs.as_path());
if let Some(entry) = self.project_list.entry_containing_mut(abs.as_path()) {
let repo = entry.git_repo.get_or_insert_with(Default::default);
repo.ci_data = ProjectCiData::Loaded(ProjectCiInfo {
runs: merged,
github_total,
exhausted,
});
}
self.scan.bump_generation();
chain_older
}
pub(super) fn ci_display_mode_for(&self, path: &Path) -> CiRunDisplayMode {
self.ci.display_mode_for(path)
}
pub(super) fn set_ci_display_mode_for_inner(&mut self, path: &Path, mode: CiRunDisplayMode) {
let owner = self.project_list.ci_branch_owner_path(path);
if !self
.project_list
.ci_toggle_available_for_inner(owner.as_path())
{
self.ci.remove_display_mode(owner.as_path());
return;
}
if self.ci_display_mode_for(owner.as_path()) == mode {
return;
}
self.ci.viewport.home();
self.ci.set_display_mode(owner, mode);
self.scan.bump_generation();
}
}