use std::collections::HashMap;
use comfy_table::{ContentArrangement, Table};
use manta_shared::common::{DATETIME_FORMAT, parse_ims_timestamp};
use manta_shared::types::dto::Image;
pub fn print(image_detail_vec: &[Image], safety: &HashMap<String, bool>) {
let mut table = Table::new();
table.set_content_arrangement(ContentArrangement::Dynamic);
table.set_header(vec![
"Image ID",
"Name",
"Creation time",
"Configuration",
"Base",
"Groups",
"Tags",
"Safe to delete",
]);
for image_details in image_detail_vec {
let unknown = String::from("unknown");
let creation_date = image_details.created.as_ref().unwrap_or(&unknown);
let creation_date = parse_ims_timestamp(creation_date).map_or_else(
|| creation_date.clone(),
|v| v.format(DATETIME_FORMAT).to_string(),
);
let configuration_name =
image_details.configuration.as_ref().unwrap_or(&unknown);
let base = image_details.base.as_ref().unwrap_or(&unknown);
let groups = image_details
.groups
.as_ref()
.map(|group_vec| group_vec.join(", "))
.unwrap_or(unknown.clone());
let safety_cell = image_details
.id
.as_deref()
.and_then(|id| safety.get(id))
.map(|safe| if *safe { "yes" } else { "no" })
.unwrap_or("?");
table.add_row(vec![
image_details.id.as_deref().unwrap_or(&unknown),
&image_details.name,
&creation_date,
configuration_name,
base,
&groups,
&image_details
.metadata
.clone()
.unwrap_or_default()
.iter()
.map(|(key, value)| format!("{key}:{value}"))
.collect::<Vec<_>>()
.join("\n"),
safety_cell,
]);
}
println!("{table}");
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn from_json(value: serde_json::Value) -> Image {
serde_json::from_value(value).unwrap()
}
#[test]
fn print_empty_list_does_not_panic() {
print(&[], &HashMap::new());
}
#[test]
fn print_image_with_iso8601_naive_date() {
let img = from_json(json!({
"id": "abcd-1234",
"name": "compute-image-v1",
"created": "2026-06-04T12:30:00",
}));
print(&[img], &HashMap::new());
}
#[test]
fn print_image_with_zoned_date() {
let img = from_json(json!({
"id": "abcd-1234",
"name": "compute-image-v1",
"created": "2026-06-04T12:30:00+00:00",
}));
let mut safety = HashMap::new();
safety.insert("abcd-1234".to_string(), true);
print(&[img], &safety);
}
#[test]
fn print_image_with_unparseable_date_falls_back_to_raw() {
let img = from_json(json!({
"id": "abcd-1234",
"name": "image-bad-date",
"created": "not-a-real-date",
}));
print(&[img], &HashMap::new());
}
#[test]
fn print_image_with_missing_date_uses_unknown_placeholder() {
let img = from_json(json!({
"id": "abcd-1234",
"name": "image-no-date",
}));
let mut safety = HashMap::new();
safety.insert("abcd-1234".to_string(), false);
print(&[img], &safety);
}
#[test]
fn print_image_with_metadata_renders_key_value_pairs() {
let img = from_json(json!({
"id": "abcd-1234",
"name": "compute-image-v1",
"created": "2026-06-04T12:30:00",
"metadata": { "version": "1.0.0", "owner": "ops" },
}));
print(&[img], &HashMap::new());
}
}