1use crate::common::{translate_column, ColumnId};
2use crate::ui::table::Column as TableColumn;
3use ratatui::prelude::*;
4use rusticity_core::vpc::Vpc;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Column {
8 VpcId,
9 State,
10 EncryptionControlId,
11 EncryptionControlMode,
12 BlockPublicAccess,
13 Ipv4Cidrs,
14 Ipv6Cidrs,
15 DhcpOptions,
16 MainRouteTable,
17 MainNetworkAcl,
18 Tenancy,
19 DefaultVpc,
20 Owner,
21}
22
23impl Column {
24 pub const ALL: [Self; 13] = [
27 Self::VpcId,
28 Self::State,
29 Self::EncryptionControlId,
30 Self::EncryptionControlMode,
31 Self::BlockPublicAccess,
32 Self::Ipv4Cidrs,
33 Self::Ipv6Cidrs,
34 Self::DhcpOptions,
35 Self::MainRouteTable,
36 Self::MainNetworkAcl,
37 Self::Tenancy,
38 Self::DefaultVpc,
39 Self::Owner,
40 ];
41
42 fn definition(self) -> (ColumnId, &'static str, usize) {
43 match self {
44 Self::VpcId => ("column.vpc.vpc.id", "VPC ID", 23),
45 Self::State => ("column.vpc.vpc.state", "State", 16),
46 Self::EncryptionControlId => (
47 "column.vpc.vpc.encryption_control_id",
48 "Encryption control ID",
49 25,
50 ),
51 Self::EncryptionControlMode => (
52 "column.vpc.vpc.encryption_control_mode",
53 "Encryption control mode",
54 25,
55 ),
56 Self::BlockPublicAccess => (
57 "column.vpc.vpc.block_public_access",
58 "Block Public Access",
59 23,
60 ),
61 Self::Ipv4Cidrs => ("column.vpc.vpc.ipv4", "IPv4 CIDR", 22),
62 Self::Ipv6Cidrs => ("column.vpc.vpc.ipv6", "IPv6 CIDR", 45),
63 Self::DhcpOptions => ("column.vpc.vpc.dhcp_options", "DHCP option set", 24),
64 Self::MainRouteTable => ("column.vpc.vpc.main_route_table", "Main route table", 24),
65 Self::MainNetworkAcl => ("column.vpc.vpc.main_network_acl", "Main network ACL", 24),
66 Self::Tenancy => ("column.vpc.vpc.tenancy", "Tenancy", 12),
67 Self::DefaultVpc => ("column.vpc.vpc.default", "Default VPC", 12),
68 Self::Owner => ("column.vpc.vpc.owner", "Owner ID", 14),
69 }
70 }
71 pub fn id(self) -> ColumnId {
72 self.definition().0
73 }
74 pub fn default_name(self) -> &'static str {
75 self.definition().1
76 }
77 pub fn name(self) -> String {
78 translate_column(self.id(), self.default_name())
79 }
80 pub fn ids() -> Vec<ColumnId> {
81 Self::ALL.into_iter().map(Self::id).collect()
82 }
83 pub fn default_visible_ids() -> Vec<ColumnId> {
84 [
85 Self::VpcId,
86 Self::State,
87 Self::Ipv4Cidrs,
88 Self::Ipv6Cidrs,
89 Self::Tenancy,
90 Self::DefaultVpc,
91 Self::Owner,
92 ]
93 .into_iter()
94 .map(Self::id)
95 .collect()
96 }
97 pub fn from_id(id: &str) -> Option<Self> {
98 Self::ALL.into_iter().find(|c| c.id() == id)
99 }
100 pub fn render(self, vpc: &Vpc) -> (String, Style) {
101 let (value, color) = match self {
102 Self::State => match vpc.state.to_ascii_lowercase().as_str() {
103 "available" => ("✅ Available".into(), Color::Green),
104 "pending" => ("⏳ Pending".into(), Color::Yellow),
105 _ => (vpc.state.clone(), Color::White),
106 },
107 Self::DefaultVpc => match vpc.is_default {
108 Some(true) => ("Yes".into(), Color::Green),
109 Some(false) => ("No".into(), Color::White),
110 None => (String::new(), Color::White),
111 },
112 Self::VpcId => (vpc.vpc_id.clone(), Color::White),
113 Self::EncryptionControlId => (vpc.encryption_control_id.clone(), Color::White),
114 Self::EncryptionControlMode => (vpc.encryption_control_mode.clone(), Color::White),
115 Self::BlockPublicAccess => {
116 match vpc.block_public_access.to_ascii_lowercase().as_str() {
117 "off" => ("❌ Off".into(), Color::White),
118 "block-ingress" => ("✅ Block ingress".into(), Color::Green),
119 "block-bidirectional" => ("✅ Block bidirectional".into(), Color::Green),
120 _ => (vpc.block_public_access.clone(), Color::White),
121 }
122 }
123 Self::Ipv4Cidrs => (vpc.ipv4_cidrs.clone(), Color::White),
124 Self::Ipv6Cidrs => (vpc.ipv6_cidrs.clone(), Color::White),
125 Self::DhcpOptions => (vpc.dhcp_options_id.clone(), Color::White),
126 Self::MainRouteTable => (vpc.main_route_table.clone(), Color::White),
127 Self::MainNetworkAcl => (vpc.main_network_acl.clone(), Color::White),
128 Self::Tenancy => (vpc.tenancy.clone(), Color::White),
129 Self::Owner => (vpc.owner_id.clone(), Color::White),
130 };
131 if value.is_empty() {
132 ("-".into(), Style::default().fg(Color::White))
133 } else if value == "Unavailable" {
134 (value, Style::default().fg(Color::Yellow))
135 } else {
136 (value, Style::default().fg(color))
137 }
138 }
139 pub fn into_table_column(self) -> Box<dyn TableColumn<Vpc>> {
140 Box::new(VpcColumn {
141 column: self,
142 label: self.name(),
143 })
144 }
145}
146
147struct VpcColumn {
148 column: Column,
149 label: String,
150}
151impl TableColumn<Vpc> for VpcColumn {
152 fn name(&self) -> &str {
153 &self.label
154 }
155 fn width(&self) -> u16 {
156 self.label
157 .chars()
158 .count()
159 .max(self.column.definition().2)
160 .min(u16::MAX as usize) as u16
161 }
162 fn fit_content(&self) -> bool {
163 true
164 }
165
166 fn render(&self, item: &Vpc) -> (String, Style) {
167 self.column.render(item)
168 }
169}