quinjet 0.0.58

A fast, live, keyboard-first Git source-control interface for the terminal
#[cfg_attr(not(test), expect(clippy::wildcard_imports, reason = "shared"))]
use super::*;

pub(super) fn draw_tip_gate(
    frame: &mut Frame<'_>,
    area: Rect,
    app: &App,
    stack: &crate::git::github::PullRequestStack,
    theme: &Theme,
) -> StackInspectorHitArea {
    let state = pull_request_stack::stack_gate_state(app);
    let color = state.color(theme);
    let tip = stack.tip();
    let checks = &app.stack_inspector.tip_checks.checks;
    let count = |status| checks.iter().filter(|check| check.status == status).count();
    let passed = count(PullRequestCheckStatus::Passed);
    let failed = count(PullRequestCheckStatus::Failed);
    let running = count(PullRequestCheckStatus::Pending);
    let skipped = count(PullRequestCheckStatus::Skipped);
    let unknown = count(PullRequestCheckStatus::Unknown);
    let cancelled = count(PullRequestCheckStatus::Cancelled);
    let number = tip.map_or(0, |member| member.number);
    let title = tip.map_or("Stack tip", |member| member.title.as_str());
    let head = tip.map_or_else(String::new, |member| short_oid(&member.head_oid));
    let updated = tip.map_or_else(String::new, |member| {
        format_relative_timestamp(&member.updated_at)
    });
    let stack_error = app.pull_request_stack_error.as_deref();
    let detail = match (stack_error, tip) {
        (Some(error), _) => format!("Stack metadata refresh failed: {error}"),
        (None, None) => format!(
            "{} of {} members loaded · final tip checks unavailable",
            stack.members.len(),
            stack.size
        ),
        (None, Some(_)) => app.stack_inspector.tip_checks_error.as_deref().map_or_else(
            || {
                format!(
                    "{passed} passed · {failed} failed · {running} running · {cancelled} stale · {skipped} skipped · {unknown} unknown"
                )
            },
            ToOwned::to_owned,
        ),
    };
    let heading = stack_gate_heading(app, tip, number);
    let identity = if tip.is_none() {
        "GitHub did not return every stack member".to_owned()
    } else {
        format!("#{number} {title}")
    };
    let state_width = state.label().width().saturating_add(4);
    let identity = truncate_end(
        &identity,
        usize::from(area.width).saturating_sub(state_width),
    );
    let revision = if tip.is_none() {
        String::new()
    } else {
        format!(" · head {head} · updated {updated}")
    };
    let lines = vec![
        Line::from(vec![
            Span::styled("▌ ", Style::default().fg(color)),
            Span::styled(
                state.label(),
                Style::default().fg(color).add_modifier(Modifier::BOLD),
            ),
            Span::styled(
                format!("  {identity}"),
                Style::default().fg(theme.text).add_modifier(Modifier::BOLD),
            ),
        ]),
        Line::from(vec![
            Span::styled("▌ ", Style::default().fg(color)),
            Span::styled(detail, Style::default().fg(theme.text)),
            Span::styled(revision, Style::default().fg(theme.muted)),
        ]),
        Line::from(vec![
            Span::styled("▌ ", Style::default().fg(color)),
            Span::styled(
                if tip.is_none() {
                    "[t Final checks unavailable]"
                } else if stack_error.is_some() {
                    "[t Inspect last-known checks]"
                } else {
                    "[t Inspect final checks]"
                },
                Style::default()
                    .fg(theme.accent)
                    .add_modifier(Modifier::BOLD),
            ),
            Span::styled(
                if tip.is_none() {
                    " · refresh stack metadata"
                } else if stack_error.is_some() {
                    " · metadata stale"
                } else if app.stack_inspector.tip_checks_loading {
                    " · refreshing final checks"
                } else if app.stack_inspector.tip_checks.from_cache {
                    " · cached"
                } else {
                    " · cumulative tip CI"
                },
                Style::default().fg(theme.muted),
            ),
        ]),
    ];
    frame.render_widget(section_separator_block(&heading, theme), area);
    frame.render_widget(
        Paragraph::new(Text::from(lines)).style(Style::default().bg(theme.panel_alt)),
        Rect::new(
            area.x,
            area.y.saturating_add(1),
            area.width,
            area.height.saturating_sub(1),
        ),
    );
    StackInspectorHitArea {
        area,
        target: StackInspectorHit::TipChecks,
    }
}

fn stack_gate_heading(
    app: &App,
    tip: Option<&crate::git::github::PullRequestStackMember>,
    number: u64,
) -> String {
    if tip.is_none() && app.pull_request_stack_error.is_some() {
        "STACK GATE / TIP UNAVAILABLE / STALE PARTIAL STACK".to_owned()
    } else if tip.is_none() {
        "STACK GATE / TIP UNAVAILABLE / PARTIAL STACK".to_owned()
    } else if app.pull_request_stack_error.is_some() {
        "STACK GATE / TIP UNVERIFIED / STALE METADATA".to_owned()
    } else if app.stack_inspector.tip_checks_loading && app.stack_inspector.tip_checks_loaded {
        format!("FINAL STACK GATE / TIP #{number} / REFRESHING CHECKS")
    } else {
        format!("FINAL STACK GATE / TIP #{number} / FULL CHANGE SET")
    }
}