Skip to main content

rusticity_term/efs/
access_point.rs

1use crate::common::{translate_column, ColumnId};
2use crate::ui::table::Column as TableColumn;
3use ratatui::prelude::*;
4use rusticity_core::efs::EfsAccessPoint as AccessPoint;
5use std::collections::HashMap;
6
7pub fn init(i18n: &mut HashMap<String, String>) {
8    for col in Column::all() {
9        i18n.entry(col.id().to_string())
10            .or_insert_with(|| col.default_name().to_string());
11    }
12}
13
14#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum Column {
16    Name,
17    AccessPointId,
18    Path,
19    PosixUser,
20    CreationInfo,
21    State,
22}
23
24impl Column {
25    const ID_NAME: &'static str = "column.efs.ap.name";
26    const ID_ACCESS_POINT_ID: &'static str = "column.efs.ap.access_point_id";
27    const ID_PATH: &'static str = "column.efs.ap.path";
28    const ID_POSIX_USER: &'static str = "column.efs.ap.posix_user";
29    const ID_CREATION_INFO: &'static str = "column.efs.ap.creation_info";
30    const ID_STATE: &'static str = "column.efs.ap.state";
31
32    pub const fn id(&self) -> &'static str {
33        match self {
34            Column::Name => Self::ID_NAME,
35            Column::AccessPointId => Self::ID_ACCESS_POINT_ID,
36            Column::Path => Self::ID_PATH,
37            Column::PosixUser => Self::ID_POSIX_USER,
38            Column::CreationInfo => Self::ID_CREATION_INFO,
39            Column::State => Self::ID_STATE,
40        }
41    }
42
43    pub const fn default_name(&self) -> &'static str {
44        match self {
45            Column::Name => "Name",
46            Column::AccessPointId => "Access point ID",
47            Column::Path => "Path",
48            Column::PosixUser => "POSIX user",
49            Column::CreationInfo => "Creation info",
50            Column::State => "State",
51        }
52    }
53
54    pub const fn all() -> [Column; 6] {
55        [
56            Column::Name,
57            Column::AccessPointId,
58            Column::Path,
59            Column::PosixUser,
60            Column::CreationInfo,
61            Column::State,
62        ]
63    }
64
65    pub fn ids() -> Vec<ColumnId> {
66        Self::all().iter().map(|c| c.id()).collect()
67    }
68
69    /// All columns are visible by default.
70    pub fn default_visible_ids() -> Vec<ColumnId> {
71        Self::ids()
72    }
73
74    pub fn from_id(id: &str) -> Option<Self> {
75        match id {
76            Self::ID_NAME => Some(Column::Name),
77            Self::ID_ACCESS_POINT_ID => Some(Column::AccessPointId),
78            Self::ID_PATH => Some(Column::Path),
79            Self::ID_POSIX_USER => Some(Column::PosixUser),
80            Self::ID_CREATION_INFO => Some(Column::CreationInfo),
81            Self::ID_STATE => Some(Column::State),
82            _ => None,
83        }
84    }
85
86    pub fn name(&self) -> String {
87        translate_column(self.id(), self.default_name())
88    }
89}
90
91impl TableColumn<AccessPoint> for Column {
92    fn name(&self) -> &str {
93        Box::leak(translate_column(self.id(), self.default_name()).into_boxed_str())
94    }
95
96    fn width(&self) -> u16 {
97        let translated = translate_column(self.id(), self.default_name());
98        translated.len().max(match self {
99            Column::Name => 24,
100            Column::AccessPointId => 22,
101            Column::Path => 24,
102            Column::PosixUser => 14,
103            Column::CreationInfo => 22,
104            Column::State => 14,
105        }) as u16
106    }
107
108    fn render(&self, item: &AccessPoint) -> (String, Style) {
109        match self {
110            Column::Name => (item.name.clone(), Style::default()),
111            Column::AccessPointId => (item.access_point_id.clone(), Style::default()),
112            Column::Path => (item.path.clone(), Style::default()),
113            Column::PosixUser => (item.posix_user.clone(), Style::default()),
114            Column::CreationInfo => (item.creation_info.clone(), Style::default()),
115            Column::State => {
116                let (text, color) = format_state(&item.life_cycle_state);
117                (text.to_string(), Style::default().fg(color))
118            }
119        }
120    }
121}
122
123fn format_state(state: &str) -> (&'static str, Color) {
124    match state {
125        "available" | "Available" | "AVAILABLE" => ("✅ Available", Color::Green),
126        "creating" | "Creating" | "CREATING" => ("⏳ Creating", Color::Yellow),
127        "deleting" | "Deleting" | "DELETING" => ("🗑 Deleting", Color::Red),
128        "deleted" | "Deleted" | "DELETED" => ("🗑 Deleted", Color::Red),
129        "updating" | "Updating" | "UPDATING" => ("🔄 Updating", Color::Yellow),
130        "error" | "Error" | "ERROR" => ("⚠ Error", Color::Red),
131        _ => ("Unknown", Color::White),
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn test_ap_column_ids_have_prefix() {
141        for col in Column::all() {
142            assert!(col.id().starts_with("column.efs.ap."));
143        }
144    }
145
146    #[test]
147    fn test_ap_from_id_roundtrip() {
148        for col in Column::all() {
149            assert_eq!(Column::from_id(col.id()), Some(col));
150        }
151    }
152
153    #[test]
154    fn test_ap_all_six_columns_visible_by_default() {
155        assert_eq!(Column::all().len(), 6);
156        assert_eq!(Column::default_visible_ids().len(), 6);
157    }
158}