1use owo_colors::OwoColorize;
2
3use crate::api::{ApiError, JiraClient};
4use crate::output::{OutputConfig, use_color};
5
6pub async fn list(client: &JiraClient, out: &OutputConfig) -> Result<(), ApiError> {
7 let projects = client.list_projects().await?;
8
9 if out.json {
10 out.print_data(
11 &serde_json::to_string_pretty(&serde_json::json!({
12 "total": projects.len(),
13 "projects": projects.iter().map(|p| serde_json::json!({
14 "key": p.key,
15 "name": p.name,
16 "id": p.id,
17 "type": p.project_type,
18 })).collect::<Vec<_>>(),
19 }))
20 .expect("failed to serialize JSON"),
21 );
22 } else {
23 if projects.is_empty() {
24 out.print_message("No projects found.");
25 return Ok(());
26 }
27
28 let color = use_color();
29 let key_w = projects
30 .iter()
31 .map(|p| p.key.len())
32 .max()
33 .unwrap_or(3)
34 .max(3)
35 + 2;
36 let name_w = projects
37 .iter()
38 .map(|p| p.name.len())
39 .max()
40 .unwrap_or(4)
41 .max(4)
42 + 2;
43
44 let header = format!("{:<key_w$} {:<name_w$} {}", "Key", "Name", "Type");
45 if color {
46 println!("{}", header.bold());
47 } else {
48 println!("{header}");
49 }
50
51 for p in &projects {
52 let ptype = p.project_type.as_deref().unwrap_or("-");
53 if color {
54 println!(
55 "{} {:<name_w$} {}",
56 format!("{:<key_w$}", p.key).yellow(),
57 p.name,
58 ptype,
59 );
60 } else {
61 println!("{:<key_w$} {:<name_w$} {}", p.key, p.name, ptype);
62 }
63 }
64 out.print_message(&format!("{} projects", projects.len()));
65 }
66 Ok(())
67}
68
69pub async fn components(
70 client: &JiraClient,
71 out: &OutputConfig,
72 project_key: &str,
73) -> Result<(), ApiError> {
74 let comps = client.list_components(project_key).await?;
75
76 if out.json {
77 out.print_data(
78 &serde_json::to_string_pretty(&serde_json::json!({
79 "project": project_key,
80 "total": comps.len(),
81 "components": comps.iter().map(|c| serde_json::json!({
82 "id": c.id,
83 "name": c.name,
84 "description": c.description,
85 })).collect::<Vec<_>>(),
86 }))
87 .expect("failed to serialize JSON"),
88 );
89 } else {
90 if comps.is_empty() {
91 out.print_message(&format!("No components found for project {project_key}."));
92 return Ok(());
93 }
94
95 let color = use_color();
96 let name_w = comps.iter().map(|c| c.name.len()).max().unwrap_or(4).max(4) + 2;
97 let id_w = comps.iter().map(|c| c.id.len()).max().unwrap_or(2).max(2) + 2;
98
99 let header = format!("{:<name_w$} {:<id_w$} {}", "Name", "ID", "Description");
100 if color {
101 println!("{}", header.bold());
102 } else {
103 println!("{header}");
104 }
105
106 for c in &comps {
107 let desc = c.description.as_deref().unwrap_or("-");
108 if color {
109 println!(
110 "{} {:<id_w$} {}",
111 format!("{:<name_w$}", c.name).yellow(),
112 c.id,
113 desc,
114 );
115 } else {
116 println!("{:<name_w$} {:<id_w$} {}", c.name, c.id, desc);
117 }
118 }
119 out.print_message(&format!("{} components", comps.len()));
120 }
121 Ok(())
122}
123
124pub async fn versions(
125 client: &JiraClient,
126 out: &OutputConfig,
127 project_key: &str,
128) -> Result<(), ApiError> {
129 let vers = client.list_versions(project_key).await?;
130
131 if out.json {
132 out.print_data(
133 &serde_json::to_string_pretty(&serde_json::json!({
134 "project": project_key,
135 "total": vers.len(),
136 "versions": vers.iter().map(|v| serde_json::json!({
137 "id": v.id,
138 "name": v.name,
139 "description": v.description,
140 "released": v.released,
141 "archived": v.archived,
142 "releaseDate": v.release_date,
143 })).collect::<Vec<_>>(),
144 }))
145 .expect("failed to serialize JSON"),
146 );
147 } else {
148 if vers.is_empty() {
149 out.print_message(&format!("No versions found for project {project_key}."));
150 return Ok(());
151 }
152
153 let color = use_color();
154 let name_w = vers.iter().map(|v| v.name.len()).max().unwrap_or(4).max(4) + 2;
155 let id_w = vers.iter().map(|v| v.id.len()).max().unwrap_or(2).max(2) + 2;
156
157 let header = format!(
158 "{:<name_w$} {:<id_w$} {:<10} {}",
159 "Name", "ID", "Released", "Release Date"
160 );
161 if color {
162 println!("{}", header.bold());
163 } else {
164 println!("{header}");
165 }
166
167 for v in &vers {
168 let released = match v.released {
169 Some(true) => "yes",
170 Some(false) => "no",
171 None => "-",
172 };
173 let release_date = v.release_date.as_deref().unwrap_or("-");
174 if color {
175 println!(
176 "{} {:<id_w$} {:<10} {}",
177 format!("{:<name_w$}", v.name).yellow(),
178 v.id,
179 released,
180 release_date,
181 );
182 } else {
183 println!(
184 "{:<name_w$} {:<id_w$} {:<10} {}",
185 v.name, v.id, released, release_date
186 );
187 }
188 }
189 out.print_message(&format!("{} versions", vers.len()));
190 }
191 Ok(())
192}
193
194pub async fn show(client: &JiraClient, out: &OutputConfig, key: &str) -> Result<(), ApiError> {
195 let project = client.get_project(key).await?;
196
197 if out.json {
198 out.print_data(
199 &serde_json::to_string_pretty(&serde_json::json!({
200 "key": project.key,
201 "name": project.name,
202 "id": project.id,
203 "type": project.project_type,
204 }))
205 .expect("failed to serialize JSON"),
206 );
207 } else {
208 let color = use_color();
209 let key_str = if color {
210 project.key.yellow().bold().to_string()
211 } else {
212 project.key.clone()
213 };
214 println!("{key_str} {}", project.name);
215 println!(" ID: {}", project.id);
216 if let Some(ref t) = project.project_type {
217 println!(" Type: {t}");
218 }
219 }
220 Ok(())
221}