rusticity_term/ecr/
image.rs

1use crate::common::translate_column;
2use crate::common::{format_iso_timestamp, ColumnId, UTC_TIMESTAMP_WIDTH};
3use crate::ui::table::Column as TableColumn;
4use ratatui::prelude::*;
5use std::collections::HashMap;
6
7pub fn init(i18n: &mut HashMap<String, String>) {
8    for col in [
9        Column::Tag,
10        Column::ArtifactType,
11        Column::PushedAt,
12        Column::SizeMb,
13        Column::Uri,
14        Column::Digest,
15        Column::LastPullTime,
16    ] {
17        i18n.entry(col.id().to_string())
18            .or_insert_with(|| col.default_name().to_string());
19    }
20}
21
22#[derive(Debug, Clone)]
23pub struct Image {
24    pub tag: String,
25    pub artifact_type: String,
26    pub pushed_at: String,
27    pub size_bytes: i64,
28    pub uri: String,
29    pub digest: String,
30    pub last_pull_time: String,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq)]
34pub enum Column {
35    Tag,
36    ArtifactType,
37    PushedAt,
38    SizeMb,
39    Uri,
40    Digest,
41    LastPullTime,
42}
43
44impl Column {
45    pub fn id(&self) -> &'static str {
46        match self {
47            Column::Tag => "column.ecr.image.tag",
48            Column::ArtifactType => "column.ecr.image.artifact_type",
49            Column::PushedAt => "column.ecr.image.pushed_at",
50            Column::SizeMb => "column.ecr.image.size_mb",
51            Column::Uri => "column.ecr.image.uri",
52            Column::Digest => "column.ecr.image.digest",
53            Column::LastPullTime => "column.ecr.image.last_pull_time",
54        }
55    }
56
57    pub fn default_name(&self) -> &'static str {
58        match self {
59            Column::Tag => "Image tag",
60            Column::ArtifactType => "Artifact type",
61            Column::PushedAt => "Pushed at",
62            Column::SizeMb => "Size (MB)",
63            Column::Uri => "Image URI",
64            Column::Digest => "Digest",
65            Column::LastPullTime => "Last recorded pull time",
66        }
67    }
68
69    pub fn all() -> [Column; 7] {
70        [
71            Column::Tag,
72            Column::ArtifactType,
73            Column::PushedAt,
74            Column::SizeMb,
75            Column::Uri,
76            Column::Digest,
77            Column::LastPullTime,
78        ]
79    }
80
81    pub fn ids() -> Vec<ColumnId> {
82        Self::all().iter().map(|c| c.id()).collect()
83    }
84
85    pub fn from_id(id: &str) -> Option<Self> {
86        match id {
87            "column.ecr.image.tag" => Some(Column::Tag),
88            "column.ecr.image.artifact_type" => Some(Column::ArtifactType),
89            "column.ecr.image.pushed_at" => Some(Column::PushedAt),
90            "column.ecr.image.size_mb" => Some(Column::SizeMb),
91            "column.ecr.image.uri" => Some(Column::Uri),
92            "column.ecr.image.digest" => Some(Column::Digest),
93            "column.ecr.image.last_pull_time" => Some(Column::LastPullTime),
94            _ => None,
95        }
96    }
97
98    pub fn name(&self) -> String {
99        translate_column(self.id(), self.default_name())
100    }
101}
102
103impl TableColumn<Image> for Column {
104    fn name(&self) -> &str {
105        Box::leak(translate_column(self.id(), self.default_name()).into_boxed_str())
106    }
107
108    fn width(&self) -> u16 {
109        let translated = translate_column(self.id(), self.default_name());
110        translated.len().max(match self {
111            Column::Tag => 20,
112            Column::ArtifactType => 20,
113            Column::PushedAt => UTC_TIMESTAMP_WIDTH as usize,
114            Column::SizeMb => 12,
115            Column::Uri => 50,
116            Column::Digest => 20,
117            Column::LastPullTime => UTC_TIMESTAMP_WIDTH as usize,
118        }) as u16
119    }
120
121    fn render(&self, item: &Image) -> (String, Style) {
122        let text = match self {
123            Column::Tag => item.tag.clone(),
124            Column::ArtifactType => item.artifact_type.clone(),
125            Column::PushedAt => format_iso_timestamp(&item.pushed_at),
126            Column::SizeMb => crate::common::format_bytes(item.size_bytes),
127            Column::Uri => item.uri.clone(),
128            Column::Digest => item.digest.clone(),
129            Column::LastPullTime => format_iso_timestamp(&item.last_pull_time),
130        };
131        (text, Style::default())
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_column_ids_have_correct_prefix() {
141        for col in Column::all() {
142            assert!(
143                col.id().starts_with("column.ecr.image."),
144                "Column ID '{}' should start with 'column.ecr.image.'",
145                col.id()
146            );
147        }
148    }
149}