1use std::collections::HashMap;
2
3use serde_json::json;
4use term_table::{
5 row::Row,
6 table_cell::{Alignment, TableCell},
7 Table,
8};
9use wash_lib::{cli::CommandOutput, plugin::subcommand::Metadata};
10use wasmcloud_control_interface::{Host, HostInventory, Link};
11
12use crate::util::format_optional;
13
14pub fn get_hosts_output(hosts: Vec<Host>) -> CommandOutput {
15 let mut map = HashMap::new();
16 map.insert("hosts".to_string(), json!(hosts));
17 CommandOutput::new(hosts_table(hosts), map)
18}
19
20pub fn get_host_inventories_output(invs: Vec<HostInventory>) -> CommandOutput {
21 let mut map = HashMap::new();
22 map.insert("inventories".to_string(), json!(invs));
23 CommandOutput::new(host_inventories_table(invs), map)
24}
25
26pub fn get_claims_output(claims: Vec<HashMap<String, String>>) -> CommandOutput {
27 let mut map = HashMap::new();
28 map.insert("claims".to_string(), json!(claims));
29 CommandOutput::new(claims_table(claims), map)
30}
31
32pub fn links_table(mut list: Vec<Link>) -> String {
33 list.sort_by(|a, b| a.source_id().cmp(b.source_id()));
35
36 let mut table = Table::new();
37 crate::util::configure_table_style(&mut table, 4);
38
39 table.add_row(Row::new(vec![
40 TableCell::new_with_alignment("Source ID", 1, Alignment::Left),
41 TableCell::new_with_alignment("Target", 1, Alignment::Left),
42 TableCell::new_with_alignment("Interface(s)", 1, Alignment::Left),
43 TableCell::new_with_alignment("Name", 1, Alignment::Left),
44 ]));
45
46 list.iter().for_each(|l| {
47 table.add_row(Row::new(vec![
48 TableCell::new_with_alignment(l.source_id().to_string(), 1, Alignment::Left),
49 TableCell::new_with_alignment(l.target().to_string(), 1, Alignment::Left),
50 TableCell::new_with_alignment(
51 format!(
52 "{}:{}/{}",
53 l.wit_namespace(),
54 l.wit_package(),
55 l.interfaces().join(",")
56 ),
57 1,
58 Alignment::Left,
59 ),
60 TableCell::new_with_alignment(l.name().to_string(), 1, Alignment::Left),
61 ]))
62 });
63
64 table.render()
65}
66
67pub fn hosts_table(mut hosts: Vec<Host>) -> String {
69 hosts.sort_by_key(|a| std::cmp::Reverse(a.uptime_seconds()));
72
73 let mut table = Table::new();
74 crate::util::configure_table_style(&mut table, 4);
75
76 table.add_row(Row::new(vec![
77 TableCell::new_with_alignment("Host ID", 2, Alignment::Left),
78 TableCell::new_with_alignment("Friendly name", 1, Alignment::Left),
79 TableCell::new_with_alignment("Uptime (seconds)", 1, Alignment::Left),
80 ]));
81
82 hosts.iter().for_each(|h| {
83 table.add_row(Row::new(vec![
84 TableCell::new_with_alignment(h.id().to_string(), 2, Alignment::Left),
85 TableCell::new_with_alignment(h.friendly_name().to_string(), 1, Alignment::Left),
86 TableCell::new_with_alignment(format!("{}", h.uptime_seconds()), 1, Alignment::Left),
87 ]))
88 });
89
90 table.render()
91}
92
93pub fn host_inventories_table(mut invs: Vec<HostInventory>) -> String {
95 let mut table = Table::new();
96 crate::util::configure_table_style(&mut table, 3);
97
98 invs.sort_by(|a, b| a.host_id().cmp(b.host_id()));
100
101 invs.into_iter().for_each(|inv| {
102 table.add_row(Row::new(vec![
103 TableCell::new_with_alignment("Host ID", 2, Alignment::Left),
104 TableCell::new_with_alignment("Friendly name", 1, Alignment::Left),
105 ]));
106 table.add_row(Row::new(vec![
107 TableCell::new_with_alignment(inv.host_id().to_string(), 2, Alignment::Left),
108 TableCell::new_with_alignment(inv.friendly_name().to_string(), 1, Alignment::Left),
109 ]));
110
111 let mut sorted_labels: Vec<_> = inv.labels().iter().collect();
113 sorted_labels.sort_by(|a, b| a.0.cmp(b.0));
114
115 if !sorted_labels.is_empty() {
116 table.add_row(Row::new(vec![TableCell::new_with_alignment(
117 "",
118 3,
119 Alignment::Left,
120 )]));
121 table.add_row(Row::new(vec![TableCell::new_with_alignment(
122 "Host labels",
123 1,
124 Alignment::Left,
125 )]));
126 sorted_labels.into_iter().for_each(|(k, v)| {
127 table.add_row(Row::new(vec![
128 TableCell::new_with_alignment(k, 1, Alignment::Left),
129 TableCell::new_with_alignment(v, 1, Alignment::Left),
130 ]))
131 });
132 } else {
133 table.add_row(Row::new(vec![TableCell::new_with_alignment(
134 "No labels present",
135 4,
136 Alignment::Center,
137 )]));
138 }
139
140 table.add_row(Row::new(vec![TableCell::new_with_alignment(
141 "",
142 4,
143 Alignment::Center,
144 )]));
145
146 let mut components = inv.components().clone();
148 components.sort_by(|a, b| a.name().cmp(&b.name()));
149
150 if !components.is_empty() {
151 table.add_row(Row::new(vec![
152 TableCell::new_with_alignment("Component ID", 1, Alignment::Left),
153 TableCell::new_with_alignment("Name", 1, Alignment::Left),
154 TableCell::new_with_alignment("Max count", 1, Alignment::Left),
155 ]));
156 components.iter().for_each(|a| {
157 let a = a.clone();
158 table.add_row(Row::new(vec![
159 TableCell::new_with_alignment(a.id(), 1, Alignment::Left),
160 TableCell::new_with_alignment(
161 format_optional(a.name().map(String::from)),
162 1,
163 Alignment::Left,
164 ),
165 TableCell::new_with_alignment(a.max_instances(), 1, Alignment::Left),
166 ]))
167 });
168 } else {
169 table.add_row(Row::new(vec![TableCell::new_with_alignment(
170 "No components found",
171 4,
172 Alignment::Left,
173 )]));
174 }
175
176 table.add_row(Row::new(vec![TableCell::new_with_alignment(
177 "",
178 4,
179 Alignment::Left,
180 )]));
181
182 let mut providers = inv.providers().clone();
184 providers.sort_by(|a, b| a.name().cmp(&b.name()));
185
186 if !providers.is_empty() {
187 table.add_row(Row::new(vec![
188 TableCell::new_with_alignment("Provider ID", 1, Alignment::Left),
189 TableCell::new_with_alignment("Name", 1, Alignment::Left),
190 ]));
191 inv.providers().iter().for_each(|p| {
192 let p = p.clone();
193 table.add_row(Row::new(vec![
194 TableCell::new_with_alignment(p.id(), 1, Alignment::Left),
195 TableCell::new_with_alignment(
196 format_optional(p.name().map(String::from)),
197 1,
198 Alignment::Left,
199 ),
200 ]))
201 });
202 } else {
203 table.add_row(Row::new(vec![TableCell::new_with_alignment(
204 "No providers found",
205 4,
206 Alignment::Left,
207 )]));
208 }
209 table.add_row(Row::new(vec![TableCell::new_with_alignment(
210 "",
211 4,
212 Alignment::Left,
213 )]));
214 });
215
216 table.render()
217}
218
219pub fn claims_table(list: Vec<HashMap<String, String>>) -> String {
221 let mut table = Table::new();
222 crate::util::configure_table_style(&mut table, 2);
223
224 table.add_row(Row::new(vec![TableCell::new_with_alignment(
225 "Claims",
226 2,
227 Alignment::Center,
228 )]));
229
230 list.iter().for_each(|c| {
231 table.add_row(Row::new(vec![
232 TableCell::new_with_alignment("Issuer", 1, Alignment::Left),
233 TableCell::new_with_alignment(
234 c.get("issuer")
235 .or_else(|| c.get("iss"))
236 .unwrap_or(&"".to_string()),
237 1,
238 Alignment::Left,
239 ),
240 ]));
241 table.add_row(Row::new(vec![
242 TableCell::new_with_alignment("Subject", 1, Alignment::Left),
243 TableCell::new_with_alignment(
244 c.get("subject")
245 .or_else(|| c.get("sub"))
246 .unwrap_or(&"".to_string()),
247 1,
248 Alignment::Left,
249 ),
250 ]));
251 table.add_row(Row::new(vec![
252 TableCell::new_with_alignment("Capabilities", 1, Alignment::Left),
253 TableCell::new_with_alignment(
254 c.get("capabilities")
255 .or_else(|| c.get("caps"))
256 .unwrap_or(&"".to_string()),
257 1,
258 Alignment::Left,
259 ),
260 ]));
261 table.add_row(Row::new(vec![
262 TableCell::new_with_alignment("Version", 1, Alignment::Left),
263 TableCell::new_with_alignment(
264 c.get("version").unwrap_or(&"".to_string()),
265 1,
266 Alignment::Left,
267 ),
268 ]));
269 table.add_row(Row::new(vec![
270 TableCell::new_with_alignment("Revision", 1, Alignment::Left),
271 TableCell::new_with_alignment(
272 c.get("revision")
273 .or_else(|| c.get("rev"))
274 .unwrap_or(&"".to_string()),
275 1,
276 Alignment::Left,
277 ),
278 ]));
279 table.add_row(Row::new(vec![TableCell::new_with_alignment(
280 String::new(),
281 2,
282 Alignment::Center,
283 )]));
284 });
285
286 table.render()
287}
288
289pub fn plugins_table(list: Vec<&Metadata>) -> String {
291 let mut table = Table::new();
292 crate::util::configure_table_style(&mut table, 4);
293
294 table.add_row(Row::new(vec![
295 TableCell::new_with_alignment("Name", 1, Alignment::Left),
296 TableCell::new_with_alignment("ID", 1, Alignment::Left),
297 TableCell::new_with_alignment("Version", 1, Alignment::Left),
298 TableCell::new_with_alignment("Author", 1, Alignment::Left),
299 ]));
300 list.into_iter().for_each(|metadata| {
301 table.add_row(Row::new(vec![
302 TableCell::new_with_alignment(&metadata.name, 1, Alignment::Left),
303 TableCell::new_with_alignment(&metadata.id, 1, Alignment::Left),
304 TableCell::new_with_alignment(&metadata.version, 1, Alignment::Left),
305 TableCell::new_with_alignment(&metadata.author, 1, Alignment::Left),
306 ]));
307 if !metadata.description.is_empty() {
308 table.add_row(Row::new(vec![TableCell::new_with_alignment(
309 format!(" └ {}", metadata.description),
310 4,
311 Alignment::Left,
312 )]));
313 }
314 });
315
316 table.render()
317}