syncable_cli/wizard/
target_selection.rs1use crate::platform::api::types::{DeploymentTarget, ProviderDeploymentStatus};
4use crate::wizard::render::{display_step_header, wizard_render_config};
5use colored::Colorize;
6use inquire::{InquireError, Select};
7
8#[derive(Debug, Clone)]
10pub enum TargetSelectionResult {
11 Selected(DeploymentTarget),
13 Back,
15 Cancelled,
17}
18
19pub fn select_target(provider_status: &ProviderDeploymentStatus) -> TargetSelectionResult {
21 display_step_header(
22 2,
23 "Select Target",
24 "Choose how to deploy your service. Cloud Runner is fully managed. Kubernetes gives you more control.",
25 );
26
27 let available_targets = provider_status.available_targets();
28
29 if available_targets.is_empty() {
30 println!(
31 "\n{}",
32 "No deployment targets available for this provider.".red()
33 );
34 return TargetSelectionResult::Cancelled;
35 }
36
37 let mut options: Vec<String> = available_targets
39 .iter()
40 .map(|t| {
41 match t {
42 DeploymentTarget::CloudRunner => {
43 format!(
44 "{} {}",
45 "Cloud Runner".cyan(),
46 "Fully managed, auto-scaling containers".dimmed()
47 )
48 }
49 DeploymentTarget::Kubernetes => {
50 let cluster_count = provider_status.clusters.iter().filter(|c| c.is_healthy).count();
51 format!(
52 "{} {} cluster{} available",
53 "Kubernetes".cyan(),
54 cluster_count,
55 if cluster_count == 1 { "" } else { "s" }
56 )
57 }
58 }
59 })
60 .collect();
61
62 options.push("← Back to provider selection".dimmed().to_string());
64
65 let selection = Select::new("Select deployment target:", options.clone())
66 .with_render_config(wizard_render_config())
67 .with_help_message("↑↓ to move, Enter to select, Esc to cancel")
68 .with_page_size(4)
69 .prompt();
70
71 match selection {
72 Ok(answer) => {
73 if answer.contains("Back") {
74 return TargetSelectionResult::Back;
75 }
76
77 let target = if answer.contains("Cloud Runner") {
78 DeploymentTarget::CloudRunner
79 } else {
80 DeploymentTarget::Kubernetes
81 };
82
83 println!("\n{} Selected: {}", "✓".green(), target.display_name());
84 TargetSelectionResult::Selected(target)
85 }
86 Err(InquireError::OperationCanceled) | Err(InquireError::OperationInterrupted) => {
87 println!("\n{}", "Wizard cancelled.".dimmed());
88 TargetSelectionResult::Cancelled
89 }
90 Err(_) => TargetSelectionResult::Cancelled,
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_target_selection_result_variants() {
100 let _ = TargetSelectionResult::Selected(DeploymentTarget::CloudRunner);
101 let _ = TargetSelectionResult::Selected(DeploymentTarget::Kubernetes);
102 let _ = TargetSelectionResult::Back;
103 let _ = TargetSelectionResult::Cancelled;
104 }
105}