codeberg_cli/actions/issue/
list.rs1use forgejo_api::structs::{Issue, IssueListIssuesQuery, IssueListIssuesQueryState};
2use miette::IntoDiagnostic;
3
4use crate::actions::GlobalArgs;
5use crate::render::json::JsonToStdout;
6use crate::render::option::{option_debug_display, option_display};
7use crate::render::spinner::spin_until_ready;
8use crate::types::api::state_type::ViewStateType;
9use crate::types::context::BergContext;
10use crate::types::git::OwnerRepo;
11use crate::types::output::OutputMode;
12
13use clap::Parser;
14
15#[derive(Parser, Debug)]
17pub struct ListIssueArgs {
18 #[arg(short, long, value_enum, default_value_t = ViewStateType::Open)]
20 pub state: ViewStateType,
21}
22
23impl ListIssueArgs {
24 pub async fn run(self, global_args: GlobalArgs) -> miette::Result<()> {
25 let ctx = BergContext::new(self, global_args).await?;
26 let OwnerRepo { repo, owner } = ctx.owner_repo()?;
27 let state = match ctx.args.state {
28 ViewStateType::Closed => IssueListIssuesQueryState::Closed,
29 ViewStateType::Open => IssueListIssuesQueryState::Open,
30 ViewStateType::All => IssueListIssuesQueryState::All,
31 };
32 let (_, mut issues_list) = spin_until_ready(
33 ctx.client
34 .issue_list_issues(
35 owner.as_str(),
36 repo.as_str(),
37 IssueListIssuesQuery {
38 state: Some(state),
39 ..Default::default()
40 },
41 )
42 .send(),
43 )
44 .await
45 .into_diagnostic()?;
46
47 issues_list.retain(|issue| issue.pull_request.is_none());
48
49 match ctx.global_args.output_mode {
50 OutputMode::Pretty => {
51 present_issues_list(&ctx, issues_list);
52 }
53 OutputMode::Json => issues_list.print_json()?,
54 }
55
56 Ok(())
57 }
58}
59
60fn present_issues_list(ctx: &BergContext<ListIssueArgs>, issues: Vec<Issue>) {
61 let issues_empty = issues.is_empty();
62
63 let table = ctx
64 .make_table()
65 .set_header(vec!["Number", "Status", "Name", "Labels"])
66 .add_rows(issues.into_iter().map(|issue| {
67 let Issue {
68 title,
69 number,
70 labels,
71 state,
72 ..
73 } = issue;
74 let labels = labels.map(|labels| {
75 labels
76 .into_iter()
77 .map(|label| option_display(&label.name))
78 .collect::<Vec<_>>()
79 .join(",")
80 });
81 vec![
82 option_display(&number),
83 option_debug_display(&state),
84 option_display(&title),
85 option_display(&labels),
86 ]
87 }));
88
89 let header = format!(
90 "Issues{}",
91 if issues_empty {
92 " (empty)"
93 } else {
94 Default::default()
95 }
96 );
97
98 let underscore = "=".repeat(header.len());
99 let out = [header, underscore, table.show()].join("\n");
100
101 println!("{out}");
102}