use std::process::ExitCode;
use chrono::Utc;
use clap::{Args, ValueEnum};
use comfy_table::{Cell, Color, Table};
use crate::config::ResolvedContext;
use crate::output::OutputFormat;
use super::client;
use super::models::{compute_timeout_color, format_countdown, ApprovalResponse, TimeoutColor};
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ApprovalStatusFilter {
Pending,
Approved,
Rejected,
}
impl ApprovalStatusFilter {
pub fn as_query_value(self) -> &'static str {
match self {
Self::Pending => "pending",
Self::Approved => "approved",
Self::Rejected => "rejected",
}
}
}
#[derive(Debug, Args)]
pub struct ListArgs {
#[arg(long, value_enum)]
pub output: Option<OutputFormat>,
#[arg(long, value_enum)]
pub status: Option<ApprovalStatusFilter>,
#[arg(long)]
pub agent: Option<String>,
}
pub fn render_approvals_table(items: &[ApprovalResponse], now_epoch: i64) {
let mut table = Table::new();
table.set_header(vec!["ID", "AGENT", "ACTION", "CONDITION", "SUBMITTED_AT", "TIMEOUT_IN"]);
for item in items {
let submitted_epoch = chrono::DateTime::parse_from_rfc3339(&item.created_at)
.map(|dt| dt.timestamp())
.unwrap_or(0);
let timeout_secs: i64 = 300;
let remaining = (submitted_epoch + timeout_secs) - now_epoch;
let color = match compute_timeout_color(remaining) {
TimeoutColor::Red => Color::Red,
TimeoutColor::Yellow => Color::Yellow,
TimeoutColor::Green => Color::Green,
};
table.add_row(vec![
Cell::new(&item.id),
Cell::new(&item.agent_id),
Cell::new(&item.action),
Cell::new(&item.reason),
Cell::new(&item.created_at),
Cell::new(format_countdown(remaining)).fg(color),
]);
}
println!("{table}");
}
pub fn run_list(args: ListArgs, ctx: &ResolvedContext, global_output: OutputFormat) -> ExitCode {
let rt = tokio::runtime::Runtime::new().expect("failed to create tokio runtime");
let status = args.status.map(|s| s.as_query_value());
let result = rt.block_on(client::list_approvals(ctx, status, args.agent.as_deref()));
match result {
Ok(paginated) => {
let format = args.output.unwrap_or(global_output);
match format {
OutputFormat::Json => {
println!("{}", serde_json::to_string_pretty(&paginated.items).unwrap_or_default());
}
OutputFormat::Yaml => {
println!("{}", serde_yaml::to_string(&paginated.items).unwrap_or_default());
}
OutputFormat::Table => {
let now = Utc::now().timestamp();
render_approvals_table(&paginated.items, now);
println!("\n{} pending approval(s)", paginated.total);
}
}
ExitCode::SUCCESS
}
Err(e) => {
eprintln!("error: {e}");
ExitCode::FAILURE
}
}
}