Skip to main content

rusticity_term/ui/
vpc.rs

1use crate::app::App;
2use crate::common::{render_pagination_text, ColumnId, InputFocus, SortDirection};
3use crate::keymap::Mode;
4use crate::table::{TableState, TableWindow};
5use crate::ui::filter::{render_simple_filter, SimpleFilterConfig};
6use crate::ui::table::{expanded_from_columns, render_table, TableConfig};
7use crate::ui::{format_title, titled_block};
8use crate::vpc::columns::Column;
9use ratatui::{prelude::*, widgets::Paragraph};
10use rusticity_core::vpc::Vpc;
11
12pub struct State {
13    pub vpcs: TableState<Vpc>,
14    pub input_focus: InputFocus,
15    pub column_ids: Vec<ColumnId>,
16    pub visible_column_ids: Vec<ColumnId>,
17}
18impl Default for State {
19    fn default() -> Self {
20        Self {
21            vpcs: TableState::new(),
22            input_focus: InputFocus::Filter,
23            column_ids: Column::ids(),
24            visible_column_ids: Column::default_visible_ids(),
25        }
26    }
27}
28
29pub fn filtered_vpcs(app: &App) -> Vec<&Vpc> {
30    let query = app.vpc_state.vpcs.filter.to_lowercase();
31    let mut vpcs = app.vpc_state.vpcs.filtered(|vpc| {
32        [
33            &vpc.name,
34            &vpc.vpc_id,
35            &vpc.state,
36            &vpc.ipv4_cidrs,
37            &vpc.ipv6_cidrs,
38            &vpc.owner_id,
39            &vpc.region,
40            &vpc.arn,
41            &vpc.dhcp_options_id,
42            &vpc.tenancy,
43            &vpc.encryption_control_id,
44            &vpc.encryption_control_mode,
45            &vpc.block_public_access,
46            &vpc.main_route_table,
47            &vpc.main_network_acl,
48        ]
49        .iter()
50        .any(|value| value.to_lowercase().contains(&query))
51    });
52    vpcs.sort_by(|a, b| a.vpc_id.cmp(&b.vpc_id));
53    vpcs
54}
55
56pub fn render_vpcs(frame: &mut Frame, app: &App, area: Rect) {
57    let chunks = Layout::vertical([Constraint::Length(3), Constraint::Min(0)]).split(area);
58    let state = &app.vpc_state;
59    let view = state
60        .vpcs
61        .prepare_view(filtered_vpcs(app), TableWindow::SelectedPage);
62    let pagination = render_pagination_text(view.current_page, view.total_pages);
63    render_simple_filter(
64        frame,
65        chunks[0],
66        SimpleFilterConfig {
67            filter_text: &state.vpcs.filter,
68            placeholder: "Search by name, VPC ID, CIDR, or owner",
69            pagination: &pagination,
70            mode: app.mode,
71            is_input_focused: state.input_focus == InputFocus::Filter,
72            is_pagination_focused: state.input_focus == InputFocus::Pagination,
73        },
74    );
75    if state.vpcs.loading && state.vpcs.items.is_empty() {
76        frame.render_widget(
77            Paragraph::new("Loading VPCs...")
78                .block(titled_block("VPCs"))
79                .alignment(Alignment::Center),
80            chunks[1],
81        );
82        return;
83    }
84    let columns: Vec<_> = state
85        .visible_column_ids
86        .iter()
87        .filter_map(|id| Column::from_id(id))
88        .map(Column::into_table_column)
89        .collect();
90    let expanded_columns: Vec<_> = Column::ALL
91        .into_iter()
92        .map(Column::into_table_column)
93        .collect();
94    render_table(
95        frame,
96        TableConfig {
97            items: view.items,
98            selected_index: view.selected_index,
99            expanded_index: view.expanded_index,
100            columns: &columns,
101            sort_column: &Column::VpcId.name(),
102            sort_direction: SortDirection::Asc,
103            title: format_title(&format!("VPCs ({})", view.total_items)),
104            area: chunks[1],
105            get_expanded_content: Some(Box::new(|vpc| {
106                expanded_from_columns(&expanded_columns, vpc)
107            })),
108            is_active: app.mode == Mode::Normal,
109        },
110    );
111}