use tabled::Table;
use crate::client::ApiClient;
use crate::config::PartiriConfig;
use crate::error::Result;
use crate::output::{colored_job_status, JobRow};
pub fn run_list(client: &ApiClient, config: &PartiriConfig) -> Result<()> {
let id = config.id_or_err()?;
let jobs = client.list_service_jobs(id)?;
if jobs.is_empty() {
println!("No jobs found for this service.");
return Ok(());
}
let mut jobs = jobs;
jobs.sort_by(|a, b| b.created_at.cmp(&a.created_at));
let rows: Vec<JobRow> = jobs
.into_iter()
.take(5)
.map(|j| JobRow {
job_type: j.job_type,
deploy_ref: j
.deploy_ref
.as_deref()
.map(|r| r.get(..7).unwrap_or(r).to_string())
.unwrap_or_else(|| "—".to_string()),
status: colored_job_status(&j.status),
created_at: j
.created_at
.as_deref()
.map(format_timestamp)
.unwrap_or_else(|| "—".to_string()),
})
.collect();
println!("{}", Table::new(rows));
Ok(())
}
fn format_timestamp(ts: &str) -> String {
if ts.len() >= 16 && ts.as_bytes().get(10) == Some(&b'T') {
format!("{} {}", &ts[..10], &ts[11..16])
} else {
ts.to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn formats_utc_timestamp() {
assert_eq!(format_timestamp("2024-02-25T10:30:00Z"), "2024-02-25 10:30");
}
#[test]
fn formats_timestamp_with_positive_offset() {
assert_eq!(
format_timestamp("2024-02-25T12:30:00+02:00"),
"2024-02-25 12:30"
);
}
#[test]
fn formats_timestamp_with_negative_offset() {
assert_eq!(
format_timestamp("2024-02-25T08:00:00-05:00"),
"2024-02-25 08:00"
);
}
#[test]
fn invalid_string_returns_original() {
assert_eq!(format_timestamp("not-a-timestamp"), "not-a-timestamp");
}
#[test]
fn empty_string_returns_empty() {
assert_eq!(format_timestamp(""), "");
}
#[test]
fn date_only_returns_original() {
assert_eq!(format_timestamp("2024-02-25"), "2024-02-25");
}
#[test]
fn milliseconds_are_dropped_in_output() {
assert_eq!(
format_timestamp("2024-02-25T10:30:45.123Z"),
"2024-02-25 10:30"
);
}
}