nsg_cli/commands/
status.rs1use crate::client::NsgClient;
2use crate::config::Credentials;
3use anyhow::Result;
4use clap::Args;
5use colored::Colorize;
6
7#[derive(Debug, Args)]
8pub struct StatusCommand {
9 #[arg(help = "Job URL or Job ID")]
10 job: String,
11}
12
13impl StatusCommand {
14 pub fn execute(self) -> Result<()> {
15 let credentials = Credentials::load()?;
16 let client = NsgClient::new(credentials)?;
17
18 println!("{}", "NSG Job Status".bold().cyan());
19 println!("{}", "=".repeat(80).cyan());
20 println!();
21 println!("{} Checking job status...", "→".cyan());
22 println!(" Job: {}", self.job.bold());
23 println!();
24
25 let status = client.get_job_status(&self.job)?;
26
27 println!("{} Job found", "✓".green().bold());
28 println!();
29 println!("{}", "Job Status Information".bold());
30 println!("{}", "=".repeat(80));
31 println!();
32 println!("Job ID: {}", status.job_id.cyan());
33
34 let stage_icon = get_stage_icon(&status.job_stage);
35 println!("Stage: {} {}", stage_icon, status.job_stage.bold());
36
37 if status.failed {
38 println!("Failed: {} YES", "✗".red().bold());
39 }
40
41 if let Some(date) = &status.date_submitted {
42 println!("Submitted: {}", format_timestamp(date));
43 }
44
45 if status.results_uri.is_some() {
46 println!("Results: {} Available", "✓".green());
47 } else {
48 println!("Results: {} Not yet available", "⏳".yellow());
49 }
50
51 if !status.messages.is_empty() {
52 println!();
53 println!("{}", "Recent Messages:".bold());
54 let recent = if status.messages.len() > 5 {
55 &status.messages[status.messages.len() - 5..]
56 } else {
57 &status.messages[..]
58 };
59
60 for msg in recent {
61 println!();
62 println!(
63 " [{}] {}",
64 msg.stage.cyan(),
65 msg.timestamp.as_deref().unwrap_or("")
66 );
67 if !msg.text.is_empty() {
68 let text = if msg.text.len() > 200 {
69 format!("{}...", &msg.text[..200])
70 } else {
71 msg.text.clone()
72 };
73 println!(" {}", text);
74 }
75 }
76 }
77
78 println!();
79 println!("{}", "=".repeat(80));
80 println!();
81
82 print_next_action(&status.job_stage, &self.job);
83
84 Ok(())
85 }
86}
87
88fn get_stage_icon(stage: &str) -> &'static str {
89 match stage {
90 "COMPLETED" => "✓",
91 "RUNNING" | "RUN" => "⟳",
92 "QUEUE" | "SUBMITTED" => "⏳",
93 "FAILED" => "✗",
94 _ => "?",
95 }
96}
97
98fn format_timestamp(ts: &str) -> String {
99 use chrono::{DateTime, Utc};
100 if let Ok(dt) = ts.parse::<DateTime<Utc>>() {
101 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
102 } else {
103 ts.to_string()
104 }
105}
106
107fn print_next_action(stage: &str, job_id: &str) {
108 match stage {
109 "COMPLETED" => {
110 println!(
111 "{} Job completed! You can now download results.",
112 "✓".green().bold()
113 );
114 println!();
115 println!("To download all results:");
116 println!(" {}", format!("nsg download {}", job_id).cyan());
117 }
118 "FAILED" => {
119 println!(
120 "{} Job failed. Check messages above for error details.",
121 "✗".red().bold()
122 );
123 }
124 "QUEUE" | "SUBMITTED" => {
125 println!("{} Job is queued. Check again later.", "⏳".yellow());
126 println!();
127 println!("To check status again:");
128 println!(" {}", format!("nsg status {}", job_id).cyan());
129 }
130 "RUN" | "RUNNING" => {
131 println!(
132 "{} Job is running. Check back later for completion.",
133 "⟳".yellow()
134 );
135 println!();
136 println!("To check status again:");
137 println!(" {}", format!("nsg status {}", job_id).cyan());
138 }
139 _ => {
140 println!("{} Unknown job stage: {}", "?".yellow(), stage);
141 }
142 }
143 println!();
144}