Sprint B.9+B.10: Dependabot alerts + CI status in table, cache and CLI
- Provider::org_dependabot_counts: one org-level request per distinct owner (cursor pagination via Link header — page= returns 400 on this endpoint); 403/404 → None (unknown) vs Some(0) = checked, none open - Provider::latest_ci_status: latest Actions run on the repo's branch → success/failure/running; CiStatus enum with stable string form - cache RepoMeta: ci_status + dependabot_open replace unused ci_ok; RepoSummary carries both, applied at startup/scan/refresh (TUI + CLI) - Repos table: CI column (✓/✗/●) + ALERT column (count, red when >0, '—' = unknown); CLI: list --alerts filter, scan_repos now cache-enriched - verified against live API: 49 repos, 44 with alert counts, CI statuses match reality; table rendering checked via pyte
This commit is contained in:
1 parent
1e74de5e2e
commit
d99660420f
14 files changed
+262
-56
No files matched your search
+20
-1
@@ -20,7 +20,7 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) {
|
||||
let cur_di = state.cur_di().unwrap_or(usize::MAX);
|
||||
|
||||
let header = Row::new(vec![
|
||||
" ", "NAME", "BRANCH", "PROJECT", "VISIB", "AGE", "STATUS", "RELEASE", "LICENSE", "STARS",
|
||||
" ", "NAME", "BRANCH", "PROJECT", "VISIB", "AGE", "STATUS", "RELEASE", "LICENSE", "CI", "ALERT", "STARS",
|
||||
]).style(Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD));
|
||||
|
||||
let rows: Vec<Row> = state.display.iter().enumerate()
|
||||
@@ -51,6 +51,21 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) {
|
||||
Color::Yellow
|
||||
};
|
||||
let lic_str = if r.has_license { "✓" } else { "—" };
|
||||
let (ci_str, ci_col) = match r.ci_status.as_deref() {
|
||||
Some("success") => ("✓", Color::Green),
|
||||
Some("failure") => ("✗", Color::Red),
|
||||
Some("running") => ("●", Color::Yellow),
|
||||
_ => ("—", Color::DarkGray),
|
||||
};
|
||||
let dep_str = match r.dependabot_open {
|
||||
Some(0) => "0".to_string(),
|
||||
Some(n) => format!("{}", n),
|
||||
None => "—".into(),
|
||||
};
|
||||
let dep_col = match r.dependabot_open {
|
||||
Some(0) | None => Color::DarkGray,
|
||||
Some(_) => Color::Red,
|
||||
};
|
||||
let stars_str = r.stars.map(|s| format!("{}", s)).unwrap_or_else(|| "—".into());
|
||||
let stars_col = if r.stars.is_some() { Color::Yellow } else { Color::DarkGray };
|
||||
let is_pinned = state.pins.contains(&r.path);
|
||||
@@ -71,6 +86,8 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) {
|
||||
Cell::from(status_str).style(if r.is_dirty || r.behind > 0 { Style::default().fg(Color::Yellow) } else if is_stale { Style::default().fg(Color::Magenta).add_modifier(Modifier::DIM) } else { Style::default().fg(Color::DarkGray) }),
|
||||
Cell::from(rel.chars().take(7).collect::<String>()).style(Style::default().fg(Color::Cyan)),
|
||||
Cell::from(lic_str).style(Style::default().fg(if r.has_license { Color::Green } else { Color::DarkGray })),
|
||||
Cell::from(ci_str).style(Style::default().fg(ci_col)),
|
||||
Cell::from(dep_str).style(Style::default().fg(dep_col)),
|
||||
Cell::from(stars_str).style(Style::default().fg(stars_col)),
|
||||
]).style(row_sty))
|
||||
})
|
||||
@@ -86,6 +103,8 @@ pub fn render_repos_table(f: &mut Frame, state: &HubState, area: Rect) {
|
||||
Constraint::Length(9),
|
||||
Constraint::Length(10),
|
||||
Constraint::Length(9),
|
||||
Constraint::Length(4),
|
||||
Constraint::Length(6),
|
||||
Constraint::Length(8),
|
||||
];
|
||||
f.render_widget(Table::new(rows, widths).header(header), area);
|
||||
|
||||
Reference in new issue
Block a user