Skip to main content

rusticity_term/efs/
actions.rs

1use crate::app::{App, Service};
2use crate::common::InputFocus;
3use crate::preferences::bindings;
4use crate::ui::efs::{
5    filtered_access_points, filtered_efs_file_systems, DetailTab, FILTER_CONTROLS,
6};
7
8// ── Navigation ────────────────────────────────────────────────────────────────
9
10pub fn next_item(app: &mut App) {
11    if app.efs_state.current_file_system.is_some() {
12        match app.efs_state.detail_tab {
13            DetailTab::Tags => {
14                let tag_count = current_fs_tag_count(app);
15                if tag_count > 0 {
16                    app.efs_state.tags_table.next_item(tag_count);
17                }
18            }
19            DetailTab::AccessPoints => {
20                let n = filtered_access_points(app).len();
21                if n > 0 {
22                    app.efs_state.access_points.next_item(n);
23                }
24            }
25            DetailTab::Network => {
26                let n = app.efs_state.mount_targets.items.len();
27                if n > 0 {
28                    app.efs_state.mount_targets.next_item(n);
29                }
30            }
31            _ => {}
32        }
33    } else {
34        let filtered = filtered_efs_file_systems(app);
35        if !filtered.is_empty() {
36            app.efs_state.file_systems.next_item(filtered.len());
37        }
38    }
39}
40
41fn current_fs_tag_count(app: &App) -> usize {
42    app.efs_state
43        .current_file_system
44        .as_deref()
45        .and_then(|id| {
46            app.efs_state
47                .file_systems
48                .items
49                .iter()
50                .find(|f| f.file_system_id == id)
51        })
52        .map(|fs| fs.tags.len())
53        .unwrap_or(0)
54}
55
56pub fn prev_item(app: &mut App) {
57    if app.efs_state.current_file_system.is_some() {
58        match app.efs_state.detail_tab {
59            DetailTab::Tags => app.efs_state.tags_table.prev_item(),
60            DetailTab::AccessPoints => app.efs_state.access_points.prev_item(),
61            DetailTab::Network => app.efs_state.mount_targets.prev_item(),
62            _ => {}
63        }
64    } else {
65        app.efs_state.file_systems.prev_item();
66    }
67}
68
69pub fn page_down_filter_input(app: &mut App) {
70    if app.efs_state.current_file_system.is_some()
71        && app.efs_state.detail_tab == DetailTab::AccessPoints
72    {
73        let n = filtered_access_points(app).len();
74        app.efs_state.access_points.page_down(n);
75        return;
76    }
77    if app.efs_state.input_focus == InputFocus::Filter {
78        let filtered = filtered_efs_file_systems(app);
79        app.efs_state.file_systems.page_down(filtered.len());
80    } else {
81        let page_size = app.efs_state.file_systems.page_size.value();
82        let filtered_count = filtered_efs_file_systems(app).len();
83        app.efs_state.input_focus.handle_page_down(
84            &mut app.efs_state.file_systems.selected,
85            &mut app.efs_state.file_systems.scroll_offset,
86            page_size,
87            filtered_count,
88        );
89    }
90}
91
92pub fn page_down_normal(app: &mut App) {
93    if app.efs_state.current_file_system.is_some() {
94        match app.efs_state.detail_tab {
95            DetailTab::AccessPoints => {
96                let n = filtered_access_points(app).len();
97                app.efs_state.access_points.page_down(n);
98            }
99            DetailTab::Network => {
100                let n = app.efs_state.mount_targets.items.len();
101                app.efs_state.mount_targets.page_down(n);
102            }
103            _ => {}
104        }
105        return;
106    }
107    let filtered = filtered_efs_file_systems(app);
108    app.efs_state.file_systems.page_down(filtered.len());
109}
110
111pub fn page_up_filter_input(app: &mut App) {
112    if app.efs_state.current_file_system.is_some()
113        && app.efs_state.detail_tab == DetailTab::AccessPoints
114    {
115        app.efs_state.access_points.page_up();
116        return;
117    }
118    if app.efs_state.input_focus == InputFocus::Filter {
119        app.efs_state.file_systems.page_up();
120    } else {
121        let page_size = app.efs_state.file_systems.page_size.value();
122        app.efs_state.input_focus.handle_page_up(
123            &mut app.efs_state.file_systems.selected,
124            &mut app.efs_state.file_systems.scroll_offset,
125            page_size,
126        );
127    }
128}
129
130pub fn page_up_normal(app: &mut App) {
131    if app.efs_state.current_file_system.is_some() {
132        match app.efs_state.detail_tab {
133            DetailTab::AccessPoints => app.efs_state.access_points.page_up(),
134            DetailTab::Network => app.efs_state.mount_targets.page_up(),
135            _ => {}
136        }
137        return;
138    }
139    app.efs_state.file_systems.page_up();
140}
141
142pub fn expand_row(app: &mut App) {
143    if app.efs_state.current_file_system.is_some() {
144        match app.efs_state.detail_tab {
145            DetailTab::Tags => app.efs_state.tags_table.toggle_expand(),
146            DetailTab::AccessPoints => app.efs_state.access_points.toggle_expand(),
147            DetailTab::Network => app.efs_state.mount_targets.toggle_expand(),
148            _ => {}
149        }
150    } else {
151        app.efs_state.file_systems.toggle_expand();
152    }
153}
154
155pub fn prev_pane(app: &mut App) {
156    collapse_row(app);
157}
158
159pub fn collapse_row(app: &mut App) {
160    if app.efs_state.current_file_system.is_some() {
161        match app.efs_state.detail_tab {
162            DetailTab::Tags => app.efs_state.tags_table.collapse(),
163            DetailTab::AccessPoints => app.efs_state.access_points.collapse(),
164            DetailTab::Network => app.efs_state.mount_targets.collapse(),
165            _ => {}
166        }
167    } else {
168        app.efs_state.file_systems.collapse();
169    }
170}
171
172pub fn go_to_page(app: &mut App, page: usize) {
173    if app.efs_state.current_file_system.is_some()
174        && app.efs_state.detail_tab == DetailTab::AccessPoints
175    {
176        let n = filtered_access_points(app).len();
177        app.efs_state.access_points.goto_page(page, n);
178        return;
179    }
180    let filtered_count = filtered_efs_file_systems(app).len();
181    app.efs_state.file_systems.goto_page(page, filtered_count);
182}
183
184// ── Filter ────────────────────────────────────────────────────────────────────
185
186pub fn get_active_filter_mut(app: &mut App) -> Option<&mut String> {
187    if app.efs_state.current_file_system.is_some()
188        && app.efs_state.detail_tab == DetailTab::AccessPoints
189    {
190        return Some(&mut app.efs_state.access_points.filter);
191    }
192    Some(&mut app.efs_state.file_systems.filter)
193}
194
195pub fn apply_filter_reset(app: &mut App) {
196    if app.efs_state.current_file_system.is_some()
197        && app.efs_state.detail_tab == DetailTab::AccessPoints
198    {
199        app.efs_state.access_points.reset();
200        return;
201    }
202    app.efs_state.file_systems.reset();
203}
204
205pub fn start_filter(app: &mut App) {
206    app.efs_state.input_focus = InputFocus::Filter;
207}
208
209pub fn next_filter_focus(app: &mut App) {
210    app.efs_state.input_focus = app.efs_state.input_focus.next(&FILTER_CONTROLS);
211}
212
213pub fn prev_filter_focus(app: &mut App) {
214    app.efs_state.input_focus = app.efs_state.input_focus.prev(&FILTER_CONTROLS);
215}
216
217pub fn is_pagination_focused(app: &App) -> bool {
218    app.efs_state.input_focus == InputFocus::Pagination
219}
220
221// ── Yank / console URL / breadcrumb ──────────────────────────────────────────
222
223pub fn yank(app: &App) {
224    if let Some(fs_id) = &app.efs_state.current_file_system {
225        // On the File system policy tab, copy the policy JSON.
226        if app.efs_state.detail_tab == crate::ui::efs::DetailTab::FileSystemPolicy
227            && !app.efs_state.policy_document.is_empty()
228        {
229            app.clipboard.request_text(&app.efs_state.policy_document);
230            return;
231        }
232        // Otherwise in detail view — copy the ARN
233        if let Some(fs) = app
234            .efs_state
235            .file_systems
236            .items
237            .iter()
238            .find(|f| &f.file_system_id == fs_id)
239        {
240            app.clipboard.request_text(&fs.file_system_arn);
241        }
242    } else {
243        // In list view — copy the file system ID
244        let filtered = filtered_efs_file_systems(app);
245        if let Some(fs) = app.efs_state.file_systems.get_selected(&filtered) {
246            app.clipboard.request_text(&fs.file_system_id);
247        }
248    }
249}
250
251// ── Select / go back ──────────────────────────────────────────────────────────
252
253pub fn select_item(app: &mut App) {
254    if app.efs_state.current_file_system.is_none() {
255        let filtered = filtered_efs_file_systems(app);
256        if let Some(fs) = app.efs_state.file_systems.get_selected(&filtered) {
257            app.efs_state.current_file_system = Some(fs.file_system_id.clone());
258            app.efs_state.detail_tab = crate::ui::efs::DetailTab::MeteredSize;
259        }
260    }
261}
262
263pub fn go_back(app: &mut App) {
264    app.efs_state.current_file_system = None;
265    app.efs_state.detail_tab = crate::ui::efs::DetailTab::MeteredSize;
266}
267
268pub fn next_detail_tab(app: &mut App) {
269    use crate::common::CyclicEnum;
270    app.efs_state.detail_tab = app.efs_state.detail_tab.next();
271    trigger_tab_load(app);
272}
273
274pub fn prev_detail_tab(app: &mut App) {
275    use crate::common::CyclicEnum;
276    app.efs_state.detail_tab = app.efs_state.detail_tab.prev();
277    trigger_tab_load(app);
278}
279
280/// When switching to the Monitoring tab, mark metrics as loading so the event
281/// loop fetches fresh CloudWatch data and reset the chart scroll. When switching
282/// to the File system policy tab, mark the policy as loading.
283fn trigger_tab_load(app: &mut App) {
284    use crate::ui::monitoring::MonitoringState;
285    match app.efs_state.detail_tab {
286        crate::ui::efs::DetailTab::Monitoring => {
287            app.efs_state.set_metrics_loading(true);
288            app.efs_state.set_monitoring_scroll(0);
289            app.efs_state.clear_metrics();
290        }
291        crate::ui::efs::DetailTab::FileSystemPolicy => {
292            app.efs_state.policy_loading = true;
293            app.efs_state.policy_scroll = 0;
294        }
295        crate::ui::efs::DetailTab::AccessPoints => {
296            app.efs_state.ap_loading = true;
297            app.efs_state.access_points.reset();
298        }
299        crate::ui::efs::DetailTab::Network => {
300            app.efs_state.mt_loading = true;
301            app.efs_state.mount_targets.reset();
302        }
303        crate::ui::efs::DetailTab::Replication => {
304            app.efs_state.replication_loading = true;
305        }
306        _ => {}
307    }
308}
309
310/// Number of charts in the EFS Monitoring tab; the last scrollable index is
311/// `EFS_MONITORING_CHARTS - 1`.
312const EFS_MONITORING_CHARTS: usize = 6;
313
314/// Scroll the active detail tab down (Ctrl+D / ScrollDown).
315pub fn scroll_down_detail(app: &mut App) {
316    use crate::ui::monitoring::MonitoringState;
317    match app.efs_state.detail_tab {
318        crate::ui::efs::DetailTab::Monitoring => {
319            let max = EFS_MONITORING_CHARTS.saturating_sub(1);
320            app.efs_state
321                .set_monitoring_scroll((app.efs_state.monitoring_scroll() + 1).min(max));
322        }
323        crate::ui::efs::DetailTab::FileSystemPolicy => {
324            let max = app
325                .efs_state
326                .policy_document
327                .lines()
328                .count()
329                .saturating_sub(1);
330            app.efs_state.policy_scroll = (app.efs_state.policy_scroll + 1).min(max);
331        }
332        _ => {}
333    }
334}
335
336/// Scroll the active detail tab up (Ctrl+U / ScrollUp).
337pub fn scroll_up_detail(app: &mut App) {
338    use crate::ui::monitoring::MonitoringState;
339    match app.efs_state.detail_tab {
340        crate::ui::efs::DetailTab::Monitoring => {
341            app.efs_state
342                .set_monitoring_scroll(app.efs_state.monitoring_scroll().saturating_sub(1));
343        }
344        crate::ui::efs::DetailTab::FileSystemPolicy => {
345            app.efs_state.policy_scroll = app.efs_state.policy_scroll.saturating_sub(1);
346        }
347        _ => {}
348    }
349}
350
351pub fn breadcrumb(app: &App) -> Vec<String> {
352    let mut parts = vec!["EFS".to_string()];
353    if let Some(fs_id) = &app.efs_state.current_file_system {
354        parts.push(fs_id.clone());
355    } else {
356        parts.push("File Systems".to_string());
357    }
358    parts
359}
360
361pub fn console_url(app: &App) -> String {
362    use crate::efs;
363    // In detail view, link to the current file system's active tab.
364    if let Some(fs_id) = &app.efs_state.current_file_system {
365        return efs::console_url_file_system_with_tab(
366            &app.config.region,
367            fs_id,
368            app.efs_state.detail_tab,
369        );
370    }
371    let filtered = filtered_efs_file_systems(app);
372    if let Some(fs) = app.efs_state.file_systems.get_selected(&filtered) {
373        efs::console_url_file_system(&app.config.region, &fs.file_system_id)
374    } else {
375        efs::console_url_file_systems(&app.config.region)
376    }
377}
378
379// ── Column preferences ────────────────────────────────────────────────────────
380
381pub fn toggle_column(app: &mut App) {
382    bindings::activate_for(app, Service::EfsFileSystems);
383}
384
385pub fn next_preferences(app: &mut App) {
386    bindings::move_section_for(app, Service::EfsFileSystems, true);
387}
388
389pub fn prev_preferences(app: &mut App) {
390    bindings::move_section_for(app, Service::EfsFileSystems, false);
391}
392
393pub fn column_selector_max(app: &App) -> usize {
394    bindings::model_for(app, Service::EfsFileSystems).max_index()
395}
396
397pub fn column_count(app: &App) -> usize {
398    bindings::model_for(app, Service::EfsFileSystems).column_count()
399}