Skip to main content

ic_query/cloud_engine/provider/
text.rs

1//! Module: cloud_engine::provider::text
2//!
3//! Responsibility: render CloudEngine provider reports as compact human-facing text.
4//! Does not own: JSON serialization, source validation, live calls, or process output.
5//! Boundary: separates Dashboard provenance from provider and location tables.
6
7use crate::text_value::REPORT_TABLE_OPTIONS;
8use ic_host_text::{
9    escape::terminal_text,
10    table::{Alignment, render},
11};
12
13use super::{
14    CloudEngineProviderInfoReport, CloudEngineProviderListReport, CloudEngineProviderLocation,
15};
16use crate::{
17    ic::dashboard_provenance_lines,
18    text_value::{optional_text, yes_no},
19};
20
21/// Render the complete CloudEngine-bearing provider list.
22#[must_use]
23pub fn cloud_engine_provider_list_report_text(report: &CloudEngineProviderListReport) -> String {
24    let mut lines = dashboard_provenance_lines(&report.provenance);
25    lines.extend([
26        format!(
27            "source_node_provider_count: {}",
28            report.source_node_provider_count
29        ),
30        format!(
31            "cloud_engine_provider_count: {}",
32            report.cloud_engine_provider_count
33        ),
34    ]);
35    if !report.providers.is_empty() {
36        let rows = report
37            .providers
38            .iter()
39            .map(|provider| {
40                [
41                    provider.principal_id.clone(),
42                    terminal_text(&provider.display_name),
43                    provider.total_cloud_engines.to_string(),
44                    provider.total_cloud_engine_nodes.to_string(),
45                    provider.total_cloud_engine_unassigned_nodes.to_string(),
46                    provider.cloud_engine_location_count.to_string(),
47                ]
48            })
49            .collect::<Vec<_>>();
50        lines.push(String::new());
51        lines.push("CloudEngine providers".to_string());
52        lines.push(render(
53            &[
54                "Provider",
55                "Name",
56                "Engines",
57                "CE nodes",
58                "CE unassigned",
59                "CE locations",
60            ],
61            &rows,
62            &[
63                Alignment::Left,
64                Alignment::Left,
65                Alignment::Right,
66                Alignment::Right,
67                Alignment::Right,
68                Alignment::Right,
69            ],
70            REPORT_TABLE_OPTIONS,
71        ));
72    }
73    lines.join("\n")
74}
75
76/// Render one exact Dashboard provider record and its CloudEngine location evidence.
77#[must_use]
78pub fn cloud_engine_provider_info_report_text(report: &CloudEngineProviderInfoReport) -> String {
79    let provider = &report.provider;
80    let mut lines = dashboard_provenance_lines(&report.provenance);
81    lines.extend([
82        format!(
83            "cloud_engine_evidence_present: {}",
84            yes_no(report.cloud_engine_evidence_present)
85        ),
86        format!("node_provider_id: {}", provider.principal_id),
87        format!("display_name: {}", terminal_text(&provider.display_name)),
88        format!("website: {}", optional_text(provider.website.as_ref())),
89        format!("logo_url: {}", optional_text(provider.logo_url.as_ref())),
90        format!("total_cloud_engines: {}", provider.total_cloud_engines),
91        format!(
92            "total_cloud_engine_nodes: {}",
93            provider.total_cloud_engine_nodes
94        ),
95        format!(
96            "total_cloud_engine_unassigned_nodes: {}",
97            provider.total_cloud_engine_unassigned_nodes
98        ),
99        format!(
100            "cloud_engine_location_count: {}",
101            provider.cloud_engine_location_count
102        ),
103        format!("total_nodes: {}", provider.total_nodes),
104        format!(
105            "total_unassigned_nodes: {}",
106            provider.total_unassigned_nodes
107        ),
108        format!(
109            "total_rewardable_nodes: {}",
110            provider.total_rewardable_nodes
111        ),
112        format!("total_node_allowance: {}", provider.total_node_allowance),
113        format!("total_subnets: {}", provider.total_subnets),
114        format!("location_count: {}", provider.location_count),
115    ]);
116    if !provider.cloud_engine_locations.is_empty() {
117        lines.push(String::new());
118        lines.push("CloudEngine locations".to_string());
119        lines.push(location_table(&provider.cloud_engine_locations));
120    }
121    lines.join("\n")
122}
123
124fn location_table(locations: &[CloudEngineProviderLocation]) -> String {
125    let rows = locations
126        .iter()
127        .map(|location| {
128            [
129                location.dc_key.clone(),
130                terminal_text(&location.display_name),
131                terminal_text(location.owner.trim()),
132                terminal_text(&location.region),
133                location.latitude.to_string(),
134                location.longitude.to_string(),
135            ]
136        })
137        .collect::<Vec<_>>();
138    render(
139        &["DC", "Location", "Owner", "Region", "Latitude", "Longitude"],
140        &rows,
141        &[
142            Alignment::Left,
143            Alignment::Left,
144            Alignment::Left,
145            Alignment::Left,
146            Alignment::Right,
147            Alignment::Right,
148        ],
149        REPORT_TABLE_OPTIONS,
150    )
151}