1use crate::global::{GlobalCheck, GlobalSource};
2use check_updates_core::UpdateSeverity;
3use colored::Colorize;
4
5pub use check_updates_core::TableRenderer;
7
8pub struct GlobalTableRenderer {
10 show_colors: bool,
11}
12
13impl GlobalTableRenderer {
14 pub fn new(show_colors: bool) -> Self {
15 Self { show_colors }
16 }
17
18 pub fn render(&self, checks: &[GlobalCheck]) {
20 if checks.is_empty() {
21 return;
22 }
23
24 let mut by_source: std::collections::HashMap<&GlobalSource, Vec<&GlobalCheck>> =
26 std::collections::HashMap::new();
27
28 for check in checks {
29 by_source
30 .entry(&check.package.source)
31 .or_default()
32 .push(check);
33 }
34
35 let mut first_group = true;
36
37 if let Some(npm_checks) = by_source.get(&GlobalSource::Npm) {
38 if !first_group {
39 println!();
40 }
41 first_group = false;
42 self.render_group_or_uptodate("npm global:", npm_checks);
43 }
44
45 let _ = first_group;
47 }
48
49 fn render_group_or_uptodate(&self, header: &str, checks: &[&GlobalCheck]) {
50 let updates: Vec<&GlobalCheck> = checks.iter().filter(|c| c.has_update).copied().collect();
51
52 println!("{header}");
53
54 if updates.is_empty() {
55 println!(" All packages up to date.");
56 } else {
57 self.render_group_rows(&updates);
58 }
59 }
60
61 fn render_group_rows(&self, checks: &[&GlobalCheck]) {
62 let max_name = checks.iter().map(|c| c.package.name.len()).max().unwrap_or(0);
63 let max_installed = checks
64 .iter()
65 .map(|c| c.package.installed_version.to_string().len())
66 .max()
67 .unwrap_or(0);
68 let max_latest = checks
69 .iter()
70 .map(|c| c.latest.to_string().len())
71 .max()
72 .unwrap_or(0);
73
74 let mut sorted_checks = checks.to_vec();
75 sorted_checks.sort_by_key(|a| a.package.name.to_lowercase());
76
77 for check in sorted_checks {
78 let severity_str = match check.update_severity() {
79 Some(UpdateSeverity::Major) => {
80 if self.show_colors {
81 "MAJOR".red().to_string()
82 } else {
83 "MAJOR".to_string()
84 }
85 }
86 Some(UpdateSeverity::Minor) => {
87 if self.show_colors {
88 "minor".yellow().to_string()
89 } else {
90 "minor".to_string()
91 }
92 }
93 Some(UpdateSeverity::Patch) => {
94 if self.show_colors {
95 "patch".green().to_string()
96 } else {
97 "patch".to_string()
98 }
99 }
100 None => String::new(),
101 };
102
103 println!(
104 " {:<name_w$} {:>inst_w$} \u{2192} {:<to_w$} {}",
105 check.package.name,
106 check.package.installed_version.to_string(),
107 check.latest.to_string(),
108 severity_str,
109 name_w = max_name,
110 inst_w = max_installed,
111 to_w = max_latest,
112 );
113 }
114 }
115}