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).into_owned(),
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!(
88            "display_name: {}",
89            terminal_text(&provider.display_name).into_owned()
90        ),
91        format!("website: {}", optional_text(provider.website.as_ref())),
92        format!("logo_url: {}", optional_text(provider.logo_url.as_ref())),
93        format!("total_cloud_engines: {}", provider.total_cloud_engines),
94        format!(
95            "total_cloud_engine_nodes: {}",
96            provider.total_cloud_engine_nodes
97        ),
98        format!(
99            "total_cloud_engine_unassigned_nodes: {}",
100            provider.total_cloud_engine_unassigned_nodes
101        ),
102        format!(
103            "cloud_engine_location_count: {}",
104            provider.cloud_engine_location_count
105        ),
106        format!("total_nodes: {}", provider.total_nodes),
107        format!(
108            "total_unassigned_nodes: {}",
109            provider.total_unassigned_nodes
110        ),
111        format!(
112            "total_rewardable_nodes: {}",
113            provider.total_rewardable_nodes
114        ),
115        format!("total_node_allowance: {}", provider.total_node_allowance),
116        format!("total_subnets: {}", provider.total_subnets),
117        format!("location_count: {}", provider.location_count),
118    ]);
119    if !provider.cloud_engine_locations.is_empty() {
120        lines.push(String::new());
121        lines.push("CloudEngine locations".to_string());
122        lines.push(location_table(&provider.cloud_engine_locations));
123    }
124    lines.join("\n")
125}
126
127fn location_table(locations: &[CloudEngineProviderLocation]) -> String {
128    let rows = locations
129        .iter()
130        .map(|location| {
131            [
132                location.dc_key.clone(),
133                terminal_text(&location.display_name).into_owned(),
134                terminal_text(location.owner.trim()).into_owned(),
135                terminal_text(&location.region).into_owned(),
136                location.latitude.to_string(),
137                location.longitude.to_string(),
138            ]
139        })
140        .collect::<Vec<_>>();
141    render(
142        &["DC", "Location", "Owner", "Region", "Latitude", "Longitude"],
143        &rows,
144        &[
145            Alignment::Left,
146            Alignment::Left,
147            Alignment::Left,
148            Alignment::Left,
149            Alignment::Right,
150            Alignment::Right,
151        ],
152        REPORT_TABLE_OPTIONS,
153    )
154}