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 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}