Skip to main content

rusticity_term/ec2/
actions.rs

1use crate::app::App;
2use crate::common::{CyclicEnum, InputFocus, PageSize};
3use crate::ui::ec2::{
4    filtered_ec2_instances, filtered_tags, DetailTab as Ec2DetailTab, FILTER_CONTROLS,
5    STATE_FILTER as EC2_STATE_FILTER,
6};
7use crate::ui::monitoring::MonitoringState;
8
9// ── Filter ────────────────────────────────────────────────────────────────────
10
11pub fn apply_filter_reset(app: &mut App) {
12    app.ec2_state.table.reset();
13}
14
15pub fn get_active_filter_mut(app: &mut App) -> Option<&mut String> {
16    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
17        Some(&mut app.ec2_state.tags.filter)
18    } else {
19        Some(&mut app.ec2_state.table.filter)
20    }
21}
22
23pub fn is_pagination_focused(app: &App) -> bool {
24    app.ec2_state.input_focus == InputFocus::Pagination
25}
26
27pub fn next_filter_focus(app: &mut App) {
28    app.ec2_state.input_focus = app.ec2_state.input_focus.next(&FILTER_CONTROLS);
29}
30
31pub fn prev_filter_focus(app: &mut App) {
32    app.ec2_state.input_focus = app.ec2_state.input_focus.prev(&FILTER_CONTROLS);
33}
34
35pub fn filter_char_push(app: &mut App, c: char) {
36    if app.ec2_state.input_focus == InputFocus::Filter {
37        app.ec2_state.tags.filter.push(c);
38        app.ec2_state.tags.selected = 0;
39    }
40}
41
42pub fn filter_char_pop(app: &mut App) {
43    if app.ec2_state.input_focus == InputFocus::Filter {
44        app.ec2_state.tags.filter.pop();
45        app.ec2_state.tags.selected = 0;
46    }
47}
48
49pub fn toggle_state_filter_next(app: &mut App) {
50    if app.ec2_state.input_focus == EC2_STATE_FILTER {
51        app.ec2_state.state_filter = app.ec2_state.state_filter.next();
52        app.ec2_state.table.reset();
53    }
54}
55
56pub fn toggle_state_filter_prev(app: &mut App) {
57    if app.ec2_state.input_focus == EC2_STATE_FILTER {
58        app.ec2_state.state_filter = app.ec2_state.state_filter.prev();
59        app.ec2_state.table.reset();
60    }
61}
62
63pub fn toggle_filter_checkbox(app: &mut App) {
64    if app.ec2_state.input_focus == EC2_STATE_FILTER {
65        app.ec2_state.state_filter = app.ec2_state.state_filter.next();
66        app.ec2_state.table.reset();
67    }
68}
69
70// ── Navigation ────────────────────────────────────────────────────────────────
71
72pub fn next_item(app: &mut App) {
73    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
74        let filtered = filtered_tags(app);
75        if !filtered.is_empty() {
76            app.ec2_state.tags.next_item(filtered.len());
77        }
78    } else {
79        let filtered = filtered_ec2_instances(app);
80        if !filtered.is_empty() {
81            app.ec2_state.table.next_item(filtered.len());
82        }
83    }
84}
85
86pub fn prev_item(app: &mut App) {
87    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
88        app.ec2_state.tags.prev_item();
89    } else {
90        app.ec2_state.table.prev_item();
91    }
92}
93
94pub fn page_down_normal(app: &mut App) {
95    let filtered = filtered_ec2_instances(app);
96    if !filtered.is_empty() {
97        app.ec2_state.table.page_down(filtered.len());
98    }
99}
100
101pub fn page_up_normal(app: &mut App) {
102    if app.ec2_state.current_instance.is_some()
103        && app.ec2_state.detail_tab == Ec2DetailTab::Monitoring
104        && !app.ec2_state.is_metrics_loading()
105    {
106        app.ec2_state
107            .set_monitoring_scroll(app.ec2_state.monitoring_scroll().saturating_sub(1));
108    } else {
109        app.ec2_state.table.page_up();
110    }
111}
112
113pub fn scroll_up(app: &mut App) {
114    if app.ec2_state.current_instance.is_some()
115        && app.ec2_state.detail_tab == Ec2DetailTab::Monitoring
116        && !app.ec2_state.is_metrics_loading()
117    {
118        app.ec2_state
119            .set_monitoring_scroll(app.ec2_state.monitoring_scroll().saturating_sub(1));
120    }
121}
122
123pub fn scroll_down(app: &mut App) {
124    if app.ec2_state.current_instance.is_some()
125        && app.ec2_state.detail_tab == Ec2DetailTab::Monitoring
126        && !app.ec2_state.is_metrics_loading()
127    {
128        app.ec2_state
129            .set_monitoring_scroll((app.ec2_state.monitoring_scroll() + 1).min(5));
130    }
131}
132
133pub fn expand_row(app: &mut App) {
134    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
135        app.ec2_state.tags.toggle_expand();
136    } else if !app.ec2_state.table.is_expanded() {
137        app.ec2_state.table.toggle_expand();
138    }
139}
140
141pub fn prev_pane(app: &mut App) {
142    app.ec2_state.table.collapse();
143}
144
145pub fn collapse_row(app: &mut App) {
146    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
147        app.ec2_state.tags.collapse();
148    } else {
149        app.ec2_state.table.collapse();
150    }
151}
152
153// ── Actions ───────────────────────────────────────────────────────────────────
154
155pub fn select_item(app: &mut App) {
156    if app.ec2_state.current_instance.is_none() {
157        let filtered = filtered_ec2_instances(app);
158        if let Some(instance) = app.ec2_state.table.get_selected(&filtered) {
159            app.ec2_state.current_instance = Some(instance.instance_id.clone());
160            app.view_mode = crate::app::ViewMode::Detail;
161            app.update_current_tab_breadcrumb();
162        }
163    }
164}
165
166pub fn go_back(app: &mut App) {
167    app.ec2_state.current_instance = None;
168    app.view_mode = crate::app::ViewMode::List;
169    app.update_current_tab_breadcrumb();
170}
171
172pub fn next_detail_tab(app: &mut App) {
173    app.ec2_state.detail_tab = app.ec2_state.detail_tab.next();
174    if app.ec2_state.detail_tab == Ec2DetailTab::Tags {
175        app.ec2_state.tags.loading = true;
176    } else if app.ec2_state.detail_tab == Ec2DetailTab::Monitoring {
177        app.ec2_state.set_metrics_loading(true);
178        app.ec2_state.set_monitoring_scroll(0);
179        app.ec2_state.clear_metrics();
180    }
181}
182
183pub fn prev_detail_tab(app: &mut App) {
184    app.ec2_state.detail_tab = app.ec2_state.detail_tab.prev();
185    if app.ec2_state.detail_tab == Ec2DetailTab::Tags {
186        app.ec2_state.tags.loading = true;
187    } else if app.ec2_state.detail_tab == Ec2DetailTab::Monitoring {
188        app.ec2_state.set_metrics_loading(true);
189        app.ec2_state.set_monitoring_scroll(0);
190        app.ec2_state.clear_metrics();
191    }
192}
193
194pub fn block_column_selector(app: &App) -> bool {
195    app.ec2_state.table.expanded_item.is_some() && app.ec2_state.detail_tab != Ec2DetailTab::Tags
196}
197
198// ── Column preferences ────────────────────────────────────────────────────────
199
200pub fn toggle_column(app: &mut App) {
201    let idx = app.column_selector_index;
202    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
203        if idx > 0 && idx <= app.ec2_state.tag_column_ids.len() {
204            if let Some(col) = app.ec2_state.tag_column_ids.get(idx - 1) {
205                if let Some(pos) = app
206                    .ec2_state
207                    .tag_visible_column_ids
208                    .iter()
209                    .position(|c| c == col)
210                {
211                    if app.ec2_state.tag_visible_column_ids.len() > 1 {
212                        app.ec2_state.tag_visible_column_ids.remove(pos);
213                    }
214                } else {
215                    app.ec2_state.tag_visible_column_ids.push(col.clone());
216                }
217            }
218        } else if idx == app.ec2_state.tag_column_ids.len() + 3 {
219            app.ec2_state.tags.page_size = PageSize::Ten;
220        } else if idx == app.ec2_state.tag_column_ids.len() + 4 {
221            app.ec2_state.tags.page_size = PageSize::TwentyFive;
222        } else if idx == app.ec2_state.tag_column_ids.len() + 5 {
223            app.ec2_state.tags.page_size = PageSize::Fifty;
224        } else if idx == app.ec2_state.tag_column_ids.len() + 6 {
225            app.ec2_state.tags.page_size = PageSize::OneHundred;
226        }
227    } else {
228        if idx > 0 && idx <= app.ec2_column_ids.len() {
229            if let Some(col) = app.ec2_column_ids.get(idx - 1) {
230                if let Some(pos) = app.ec2_visible_column_ids.iter().position(|c| c == col) {
231                    if app.ec2_visible_column_ids.len() > 1 {
232                        app.ec2_visible_column_ids.remove(pos);
233                    }
234                } else {
235                    app.ec2_visible_column_ids.push(*col);
236                }
237            }
238        } else if idx == app.ec2_column_ids.len() + 3 {
239            app.ec2_state.table.page_size = PageSize::Ten;
240        } else if idx == app.ec2_column_ids.len() + 4 {
241            app.ec2_state.table.page_size = PageSize::TwentyFive;
242        } else if idx == app.ec2_column_ids.len() + 5 {
243            app.ec2_state.table.page_size = PageSize::Fifty;
244        } else if idx == app.ec2_column_ids.len() + 6 {
245            app.ec2_state.table.page_size = PageSize::OneHundred;
246        }
247    }
248}
249
250pub fn next_preferences(app: &mut App) {
251    let page_size_idx = app.ec2_column_ids.len() + 2;
252    if app.column_selector_index < page_size_idx {
253        app.column_selector_index = page_size_idx;
254    } else {
255        app.column_selector_index = 0;
256    }
257}
258
259pub fn column_selector_max(app: &App) -> usize {
260    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
261        app.ec2_state.tag_column_ids.len() + 6
262    } else {
263        app.ec2_column_ids.len() + 6
264    }
265}
266
267pub fn column_count(app: &App) -> usize {
268    if app.ec2_state.current_instance.is_some() && app.ec2_state.detail_tab == Ec2DetailTab::Tags {
269        app.ec2_state.tag_column_ids.len()
270    } else {
271        app.ec2_column_ids.len()
272    }
273}
274
275// ── Breadcrumb / console URL ──────────────────────────────────────────────────
276
277pub fn breadcrumb(app: &App) -> Vec<String> {
278    let mut parts = vec!["EC2".to_string()];
279    if let Some(id) = &app.ec2_state.current_instance {
280        parts.push(id.clone());
281    } else {
282        parts.push("Instances".to_string());
283    }
284    parts
285}
286
287pub fn console_url(app: &App) -> String {
288    if let Some(instance_id) = &app.ec2_state.current_instance {
289        format!(
290            "https://{}.console.aws.amazon.com/ec2/home?region={}#InstanceDetails:instanceId={}",
291            app.config.region, app.config.region, instance_id
292        )
293    } else {
294        format!(
295            "https://{}.console.aws.amazon.com/ec2/home?region={}#Instances:",
296            app.config.region, app.config.region
297        )
298    }
299}