nsg_cli/commands/
status.rs1use anyhow::Result;
2use clap::Args;
3use colored::Colorize;
4use crate::client::NsgClient;
5use crate::config::Credentials;
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!(" [{}] {}", msg.stage.cyan(), msg.timestamp.as_deref().unwrap_or(""));
63 if !msg.text.is_empty() {
64 let text = if msg.text.len() > 200 {
65 format!("{}...", &msg.text[..200])
66 } else {
67 msg.text.clone()
68 };
69 println!(" {}", text);
70 }
71 }
72 }
73
74 println!();
75 println!("{}", "=".repeat(80));
76 println!();
77
78 print_next_action(&status.job_stage, &self.job);
79
80 Ok(())
81 }
82}
83
84fn get_stage_icon(stage: &str) -> &'static str {
85 match stage {
86 "COMPLETED" => "✓",
87 "RUNNING" | "RUN" => "⟳",
88 "QUEUE" | "SUBMITTED" => "⏳",
89 "FAILED" => "✗",
90 _ => "?",
91 }
92}
93
94fn format_timestamp(ts: &str) -> String {
95 use chrono::{DateTime, Utc};
96 if let Ok(dt) = ts.parse::<DateTime<Utc>>() {
97 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
98 } else {
99 ts.to_string()
100 }
101}
102
103fn print_next_action(stage: &str, job_id: &str) {
104 match stage {
105 "COMPLETED" => {
106 println!("{} Job completed! You can now download results.", "✓".green().bold());
107 println!();
108 println!("To download all results:");
109 println!(" {}", format!("nsg download {}", job_id).cyan());
110 }
111 "FAILED" => {
112 println!("{} Job failed. Check messages above for error details.", "✗".red().bold());
113 }
114 "QUEUE" | "SUBMITTED" => {
115 println!("{} Job is queued. Check again later.", "⏳".yellow());
116 println!();
117 println!("To check status again:");
118 println!(" {}", format!("nsg status {}", job_id).cyan());
119 }
120 "RUN" | "RUNNING" => {
121 println!("{} Job is running. Check back later for completion.", "⟳".yellow());
122 println!();
123 println!("To check status again:");
124 println!(" {}", format!("nsg status {}", job_id).cyan());
125 }
126 _ => {
127 println!("{} Unknown job stage: {}", "?".yellow(), stage);
128 }
129 }
130 println!();
131}