rusticity_term/ecr/
image.rs1use 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 const ID_TAG: &'static str = "column.ecr.image.tag";
46 const ID_ARTIFACT_TYPE: &'static str = "column.ecr.image.artifact_type";
47 const ID_PUSHED_AT: &'static str = "column.ecr.image.pushed_at";
48 const ID_SIZE_MB: &'static str = "column.ecr.image.size_mb";
49 const ID_URI: &'static str = "column.ecr.image.uri";
50 const ID_DIGEST: &'static str = "column.ecr.image.digest";
51 const ID_LAST_PULL_TIME: &'static str = "column.ecr.image.last_pull_time";
52
53 pub const fn id(&self) -> &'static str {
54 match self {
55 Column::Tag => Self::ID_TAG,
56 Column::ArtifactType => Self::ID_ARTIFACT_TYPE,
57 Column::PushedAt => Self::ID_PUSHED_AT,
58 Column::SizeMb => Self::ID_SIZE_MB,
59 Column::Uri => Self::ID_URI,
60 Column::Digest => Self::ID_DIGEST,
61 Column::LastPullTime => Self::ID_LAST_PULL_TIME,
62 }
63 }
64
65 pub const fn default_name(&self) -> &'static str {
66 match self {
67 Column::Tag => "Image tag",
68 Column::ArtifactType => "Artifact type",
69 Column::PushedAt => "Pushed at",
70 Column::SizeMb => "Size (MB)",
71 Column::Uri => "Image URI",
72 Column::Digest => "Digest",
73 Column::LastPullTime => "Last recorded pull time",
74 }
75 }
76
77 pub const fn all() -> [Column; 7] {
78 [
79 Column::Tag,
80 Column::ArtifactType,
81 Column::PushedAt,
82 Column::SizeMb,
83 Column::Uri,
84 Column::Digest,
85 Column::LastPullTime,
86 ]
87 }
88
89 pub fn ids() -> Vec<ColumnId> {
90 Self::all().iter().map(|c| c.id()).collect()
91 }
92
93 pub fn from_id(id: &str) -> Option<Self> {
94 match id {
95 Self::ID_TAG => Some(Column::Tag),
96 Self::ID_ARTIFACT_TYPE => Some(Column::ArtifactType),
97 Self::ID_PUSHED_AT => Some(Column::PushedAt),
98 Self::ID_SIZE_MB => Some(Column::SizeMb),
99 Self::ID_URI => Some(Column::Uri),
100 Self::ID_DIGEST => Some(Column::Digest),
101 Self::ID_LAST_PULL_TIME => Some(Column::LastPullTime),
102 _ => None,
103 }
104 }
105
106 pub fn name(&self) -> String {
107 translate_column(self.id(), self.default_name())
108 }
109}
110
111impl TableColumn<Image> for Column {
112 fn name(&self) -> &str {
113 Box::leak(translate_column(self.id(), self.default_name()).into_boxed_str())
114 }
115
116 fn width(&self) -> u16 {
117 let translated = translate_column(self.id(), self.default_name());
118 translated.len().max(match self {
119 Column::Tag => 20,
120 Column::ArtifactType => 20,
121 Column::PushedAt => UTC_TIMESTAMP_WIDTH as usize,
122 Column::SizeMb => 12,
123 Column::Uri => 50,
124 Column::Digest => 20,
125 Column::LastPullTime => UTC_TIMESTAMP_WIDTH as usize,
126 }) as u16
127 }
128
129 fn render(&self, item: &Image) -> (String, Style) {
130 let text = match self {
131 Column::Tag => item.tag.clone(),
132 Column::ArtifactType => item.artifact_type.clone(),
133 Column::PushedAt => format_iso_timestamp(&item.pushed_at),
134 Column::SizeMb => crate::common::format_bytes(item.size_bytes),
135 Column::Uri => item.uri.clone(),
136 Column::Digest => item.digest.clone(),
137 Column::LastPullTime => format_iso_timestamp(&item.last_pull_time),
138 };
139 (text, Style::default())
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_column_ids_have_correct_prefix() {
149 for col in Column::all() {
150 assert!(
151 col.id().starts_with("column.ecr.image."),
152 "Column ID '{}' should start with 'column.ecr.image.'",
153 col.id()
154 );
155 }
156 }
157}