1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use cod_cli::milestone::view::ViewMilestonesArgs;
use cod_client::CodebergClient;
use cod_render::spinner::spin_until_ready;
use cod_render::ui::fuzzy_select_with_key;
use cod_types::api::milestone::Milestone;
use cod_types::api::state_type::StateType;

use crate::text_manipulation::select_prompt_for;

pub async fn view_milestone(
    args: ViewMilestonesArgs,
    client: &CodebergClient,
) -> anyhow::Result<()> {
    let milestones_list =
        spin_until_ready(client.get_repo_milestones(Some(args.state), None)).await?;

    let selected_milestone =
        fuzzy_select_with_key(milestones_list, select_prompt_for("milestone"))?
            .ok_or_else(|| anyhow::anyhow!("No milestone chosen. Aborting."))?;

    present_milestone_overview(selected_milestone, client, args.state).await?;

    Ok(())
}

async fn present_milestone_overview(
    milestone: Milestone,
    client: &CodebergClient,
    state: StateType,
) -> anyhow::Result<()> {
    use cod_render::prelude::*;
    use std::iter::once;

    let issues_list = spin_until_ready(client.get_repo_issues(Some(state), None)).await?;

    let mut milestone_issues = issues_list
        .iter()
        .filter(|&issue| {
            issue
                .milestone
                .as_ref()
                .map_or(false, |issue_milestone| issue_milestone.id == milestone.id)
        })
        .map(|issue| {
            format!(
                "#{}{}",
                issue.number,
                if issue.state.is_done() {
                    "✓ "
                } else {
                    "○ "
                }
            )
        })
        .collect::<Vec<_>>();

    milestone_issues.sort();

    let rows = once([
        TableCell::new_with_alignment("Name", 1, Alignment::Center),
        TableCell::new_with_alignment(milestone.title, 1, Alignment::Left),
    ])
    .chain(once([
        TableCell::new_with_alignment("Status", 1, Alignment::Center),
        TableCell::new_with_alignment(milestone.state, 1, Alignment::Left),
    ]))
    .chain(milestone.description.iter().map(|description| {
        [
            TableCell::new_with_alignment("Description", 1, Alignment::Center),
            TableCell::new_with_alignment(description, 1, Alignment::Left),
        ]
    }))
    .chain(once([
        TableCell::new_with_alignment("Related issues", 1, Alignment::Center),
        TableCell::new_with_alignment(milestone_issues.join(", "), 1, Alignment::Left),
    ]))
    .chain(once([
        TableCell::new_with_alignment("Progress", 1, Alignment::Center),
        TableCell::new_with_alignment(
            format!(
                "Progress: {} / {} done",
                milestone.closed_issues,
                milestone.open_issues + milestone.closed_issues
            ),
            1,
            Alignment::Left,
        ),
    ]))
    .chain(milestone.due_on.iter().map(|due_on| {
        [
            TableCell::new_with_alignment("Due on", 1, Alignment::Center),
            TableCell::new_with_alignment(due_on, 1, Alignment::Left),
        ]
    }))
    .map(Row::new);

    let table = CodTableBuilder::new().add_rows(rows).build();

    println!("{}", table.render());

    Ok(())
}