Skip to main content

rusticity_term/lambda/
functions.rs

1use crate::app::App;
2use crate::common::{CyclicEnum, InputFocus, PageSize};
3use crate::keymap::Mode;
4use crate::ui::lambda::{filtered_lambda_functions, DetailTab as LambdaDetailTab, FILTER_CONTROLS};
5use crate::ui::monitoring::MonitoringState;
6
7// ── Navigation ────────────────────────────────────────────────────────────────
8
9pub fn next_item(app: &mut App) {
10    if app.lambda_state.current_function.is_some()
11        && app.lambda_state.detail_tab == LambdaDetailTab::Code
12    {
13        if let Some(func_name) = &app.lambda_state.current_function.clone() {
14            if let Some(func) = app
15                .lambda_state
16                .table
17                .items
18                .iter()
19                .find(|f| f.name == *func_name)
20            {
21                let max = func.layers.len().saturating_sub(1);
22                if !func.layers.is_empty() {
23                    app.lambda_state.layer_selected =
24                        (app.lambda_state.layer_selected + 1).min(max);
25                }
26            }
27        }
28    } else if app.lambda_state.current_function.is_some()
29        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
30    {
31        let filtered: Vec<_> = app
32            .lambda_state
33            .version_table
34            .items
35            .iter()
36            .filter(|v| {
37                app.lambda_state.version_table.filter.is_empty()
38                    || v.version
39                        .to_lowercase()
40                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
41                    || v.aliases
42                        .to_lowercase()
43                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
44                    || v.description
45                        .to_lowercase()
46                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
47            })
48            .collect();
49        if !filtered.is_empty() {
50            app.lambda_state.version_table.selected =
51                (app.lambda_state.version_table.selected + 1).min(filtered.len() - 1);
52            app.lambda_state.version_table.snap_to_page();
53        }
54    } else if app.lambda_state.current_function.is_some()
55        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
56            || (app.lambda_state.current_version.is_some()
57                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
58    {
59        let version_filter = app.lambda_state.current_version.clone();
60        let filtered: Vec<_> = app
61            .lambda_state
62            .alias_table
63            .items
64            .iter()
65            .filter(|a| {
66                (version_filter.is_none() || a.versions.contains(version_filter.as_ref().unwrap()))
67                    && (app.lambda_state.alias_table.filter.is_empty()
68                        || a.name
69                            .to_lowercase()
70                            .contains(&app.lambda_state.alias_table.filter.to_lowercase())
71                        || a.versions
72                            .to_lowercase()
73                            .contains(&app.lambda_state.alias_table.filter.to_lowercase())
74                        || a.description
75                            .to_lowercase()
76                            .contains(&app.lambda_state.alias_table.filter.to_lowercase()))
77            })
78            .collect();
79        if !filtered.is_empty() {
80            app.lambda_state.alias_table.selected =
81                (app.lambda_state.alias_table.selected + 1).min(filtered.len() - 1);
82            app.lambda_state.alias_table.snap_to_page();
83        }
84    } else if app.lambda_state.current_function.is_none() {
85        let filtered = filtered_lambda_functions(app);
86        if !filtered.is_empty() {
87            app.lambda_state.table.next_item(filtered.len());
88            app.lambda_state.table.snap_to_page();
89        }
90    }
91}
92
93pub fn prev_item(app: &mut App) {
94    if app.lambda_state.current_function.is_some()
95        && app.lambda_state.detail_tab == LambdaDetailTab::Code
96    {
97        app.lambda_state.layer_selected = app.lambda_state.layer_selected.saturating_sub(1);
98    } else if app.lambda_state.current_function.is_some()
99        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
100    {
101        app.lambda_state.version_table.prev_item();
102    } else if app.lambda_state.current_function.is_some()
103        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
104            || (app.lambda_state.current_version.is_some()
105                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
106    {
107        app.lambda_state.alias_table.prev_item();
108    } else if app.lambda_state.current_function.is_none() {
109        app.lambda_state.table.prev_item();
110    }
111}
112
113pub fn page_down_filter_input(app: &mut App) {
114    if app.lambda_state.current_function.is_some()
115        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
116        && app.lambda_state.version_input_focus == InputFocus::Pagination
117    {
118        let page_size = app.lambda_state.version_table.page_size.value();
119        let filtered_count: usize = app
120            .lambda_state
121            .version_table
122            .items
123            .iter()
124            .filter(|v| {
125                app.lambda_state.version_table.filter.is_empty()
126                    || v.version
127                        .to_lowercase()
128                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
129                    || v.aliases
130                        .to_lowercase()
131                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
132                    || v.description
133                        .to_lowercase()
134                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
135            })
136            .count();
137        let target = app.lambda_state.version_table.selected + page_size;
138        app.lambda_state.version_table.selected = target.min(filtered_count.saturating_sub(1));
139    } else if app.lambda_state.current_function.is_some()
140        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
141            || (app.lambda_state.current_version.is_some()
142                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
143        && app.lambda_state.alias_input_focus == InputFocus::Pagination
144    {
145        let page_size = app.lambda_state.alias_table.page_size.value();
146        let version_filter = app.lambda_state.current_version.clone();
147        let filtered_count = app
148            .lambda_state
149            .alias_table
150            .items
151            .iter()
152            .filter(|a| {
153                (version_filter.is_none() || a.versions.contains(version_filter.as_ref().unwrap()))
154                    && (app.lambda_state.alias_table.filter.is_empty()
155                        || a.name
156                            .to_lowercase()
157                            .contains(&app.lambda_state.alias_table.filter.to_lowercase())
158                        || a.versions
159                            .to_lowercase()
160                            .contains(&app.lambda_state.alias_table.filter.to_lowercase())
161                        || a.description
162                            .to_lowercase()
163                            .contains(&app.lambda_state.alias_table.filter.to_lowercase()))
164            })
165            .count();
166        let target = app.lambda_state.alias_table.selected + page_size;
167        app.lambda_state.alias_table.selected = target.min(filtered_count.saturating_sub(1));
168    } else if app.lambda_state.current_function.is_none() {
169        let page_size = app.lambda_state.table.page_size.value();
170        let filtered_count = filtered_lambda_functions(app).len();
171        app.lambda_state.input_focus.handle_page_down(
172            &mut app.lambda_state.table.selected,
173            &mut app.lambda_state.table.scroll_offset,
174            page_size,
175            filtered_count,
176        );
177    }
178}
179
180pub fn page_down_normal(app: &mut App) {
181    let len = filtered_lambda_functions(app).len();
182    app.lambda_state.table.page_down(len);
183}
184
185pub fn page_up_filter_input(app: &mut App) {
186    if app.lambda_state.current_function.is_some()
187        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
188        && app.lambda_state.version_input_focus == InputFocus::Pagination
189    {
190        let page_size = app.lambda_state.version_table.page_size.value();
191        app.lambda_state.version_table.selected = app
192            .lambda_state
193            .version_table
194            .selected
195            .saturating_sub(page_size);
196    } else if app.lambda_state.current_function.is_some()
197        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
198            || (app.lambda_state.current_version.is_some()
199                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
200        && app.lambda_state.alias_input_focus == InputFocus::Pagination
201    {
202        let page_size = app.lambda_state.alias_table.page_size.value();
203        app.lambda_state.alias_table.selected = app
204            .lambda_state
205            .alias_table
206            .selected
207            .saturating_sub(page_size);
208    } else if app.lambda_state.current_function.is_none() {
209        let page_size = app.lambda_state.table.page_size.value();
210        app.lambda_state.input_focus.handle_page_up(
211            &mut app.lambda_state.table.selected,
212            &mut app.lambda_state.table.scroll_offset,
213            page_size,
214        );
215    }
216}
217
218pub fn page_up_normal(app: &mut App) {
219    app.lambda_state.table.page_up();
220}
221
222pub fn scroll_up(app: &mut App) {
223    if app.lambda_state.current_function.is_some()
224        && app.lambda_state.detail_tab == LambdaDetailTab::Monitor
225        && !app.lambda_state.is_metrics_loading()
226    {
227        app.lambda_state
228            .set_monitoring_scroll(app.lambda_state.monitoring_scroll().saturating_sub(1));
229    }
230}
231
232pub fn scroll_down(app: &mut App) {
233    if app.lambda_state.current_function.is_some()
234        && app.lambda_state.detail_tab == LambdaDetailTab::Monitor
235        && !app.lambda_state.is_metrics_loading()
236    {
237        app.lambda_state
238            .set_monitoring_scroll((app.lambda_state.monitoring_scroll() + 1).min(9));
239    }
240}
241
242pub fn expand_row(app: &mut App) {
243    if app.lambda_state.current_function.is_some()
244        && app.lambda_state.detail_tab == LambdaDetailTab::Code
245    {
246        if app.lambda_state.layer_expanded != Some(app.lambda_state.layer_selected) {
247            app.lambda_state.layer_expanded = Some(app.lambda_state.layer_selected);
248        } else {
249            app.lambda_state.layer_expanded = None;
250        }
251    } else if app.lambda_state.current_function.is_some()
252        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
253    {
254        app.lambda_state.version_table.toggle_expand();
255    } else if app.lambda_state.current_function.is_some()
256        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
257            || (app.lambda_state.current_version.is_some()
258                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
259    {
260        app.lambda_state.alias_table.toggle_expand();
261    } else if app.lambda_state.current_function.is_none() {
262        app.lambda_state.table.expand();
263    }
264}
265
266pub fn collapse_row(app: &mut App) {
267    app.lambda_state.table.collapse();
268}
269
270pub fn prev_pane(app: &mut App) {
271    if app.lambda_state.current_function.is_some()
272        && app.lambda_state.detail_tab == LambdaDetailTab::Code
273    {
274        app.lambda_state.layer_expanded = None;
275    } else if app.lambda_state.current_function.is_some()
276        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
277    {
278        app.lambda_state.version_table.collapse();
279    } else if app.lambda_state.current_function.is_some()
280        && (app.lambda_state.detail_tab == LambdaDetailTab::Aliases
281            || (app.lambda_state.current_version.is_some()
282                && app.lambda_state.detail_tab == LambdaDetailTab::Configuration))
283    {
284        app.lambda_state.alias_table.collapse();
285    } else if app.lambda_state.current_function.is_none() {
286        app.lambda_state.table.collapse();
287    }
288}
289
290pub fn go_to_page(app: &mut App, page: usize) {
291    if app.lambda_state.current_function.is_some()
292        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
293    {
294        let filtered_count = app
295            .lambda_state
296            .version_table
297            .filtered(|v| {
298                app.lambda_state.version_table.filter.is_empty()
299                    || v.version
300                        .to_lowercase()
301                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
302                    || v.aliases
303                        .to_lowercase()
304                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
305                    || v.description
306                        .to_lowercase()
307                        .contains(&app.lambda_state.version_table.filter.to_lowercase())
308            })
309            .len();
310        app.lambda_state
311            .version_table
312            .goto_page(page, filtered_count);
313    } else {
314        let filtered_count = filtered_lambda_functions(app).len();
315        app.lambda_state.table.goto_page(page, filtered_count);
316    }
317}
318
319// ── Filter ────────────────────────────────────────────────────────────────────
320
321pub fn apply_filter_reset(app: &mut App) {
322    if app.lambda_state.current_version.is_some() || app.lambda_state.current_function.is_some() {
323        app.lambda_state.version_table.reset();
324        app.lambda_state.alias_table.reset();
325    } else {
326        app.lambda_state.table.reset();
327    }
328}
329
330pub fn start_filter(app: &mut App) {
331    if app.lambda_state.current_version.is_some()
332        && app.lambda_state.detail_tab == LambdaDetailTab::Configuration
333    {
334        app.lambda_state.alias_input_focus = InputFocus::Filter;
335    } else if app.lambda_state.current_function.is_some()
336        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
337    {
338        app.lambda_state.version_input_focus = InputFocus::Filter;
339    } else if app.lambda_state.current_function.is_none() {
340        app.lambda_state.input_focus = InputFocus::Filter;
341    }
342}
343
344pub fn is_pagination_focused(app: &App) -> bool {
345    if app.lambda_state.current_function.is_some()
346        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
347    {
348        app.lambda_state.version_input_focus == InputFocus::Pagination
349    } else if app.lambda_state.current_function.is_none() {
350        app.lambda_state.input_focus == InputFocus::Pagination
351    } else {
352        false
353    }
354}
355
356pub fn next_filter_focus(app: &mut App) {
357    if app.lambda_state.current_version.is_some()
358        && app.lambda_state.detail_tab == LambdaDetailTab::Configuration
359    {
360        app.lambda_state.alias_input_focus =
361            app.lambda_state.alias_input_focus.next(&FILTER_CONTROLS);
362    } else if app.lambda_state.current_function.is_some()
363        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
364    {
365        app.lambda_state.version_input_focus =
366            app.lambda_state.version_input_focus.next(&FILTER_CONTROLS);
367    } else if app.lambda_state.current_function.is_some()
368        && app.lambda_state.detail_tab == LambdaDetailTab::Aliases
369    {
370        app.lambda_state.alias_input_focus =
371            app.lambda_state.alias_input_focus.next(&FILTER_CONTROLS);
372    } else if app.lambda_state.current_function.is_none() {
373        app.lambda_state.input_focus = app.lambda_state.input_focus.next(&FILTER_CONTROLS);
374    }
375}
376
377pub fn prev_filter_focus(app: &mut App) {
378    if app.lambda_state.current_version.is_some()
379        && app.lambda_state.detail_tab == LambdaDetailTab::Configuration
380    {
381        app.lambda_state.alias_input_focus =
382            app.lambda_state.alias_input_focus.prev(&FILTER_CONTROLS);
383    } else if app.lambda_state.current_function.is_some()
384        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
385    {
386        app.lambda_state.version_input_focus =
387            app.lambda_state.version_input_focus.prev(&FILTER_CONTROLS);
388    } else if app.lambda_state.current_function.is_some()
389        && app.lambda_state.detail_tab == LambdaDetailTab::Aliases
390    {
391        app.lambda_state.alias_input_focus =
392            app.lambda_state.alias_input_focus.prev(&FILTER_CONTROLS);
393    } else if app.lambda_state.current_function.is_none() {
394        app.lambda_state.input_focus = app.lambda_state.input_focus.prev(&FILTER_CONTROLS);
395    }
396}
397
398pub fn filter_char_allowed(app: &App) -> bool {
399    if app.lambda_state.current_version.is_some()
400        && app.lambda_state.detail_tab == LambdaDetailTab::Configuration
401    {
402        app.lambda_state.alias_input_focus == InputFocus::Filter
403    } else if app.lambda_state.current_function.is_some()
404        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
405    {
406        app.lambda_state.version_input_focus == InputFocus::Filter
407    } else if app.lambda_state.current_function.is_some()
408        && app.lambda_state.detail_tab == LambdaDetailTab::Aliases
409    {
410        app.lambda_state.alias_input_focus == InputFocus::Filter
411    } else {
412        false
413    }
414}
415
416// ── Actions ───────────────────────────────────────────────────────────────────
417
418pub fn select_item(app: &mut App) {
419    if app.lambda_state.current_function.is_some()
420        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
421    {
422        if app.mode == Mode::Normal {
423            let page_size = app.lambda_state.version_table.page_size.value();
424            let filtered: Vec<_> = app
425                .lambda_state
426                .version_table
427                .items
428                .iter()
429                .filter(|v| {
430                    app.lambda_state.version_table.filter.is_empty()
431                        || v.version
432                            .to_lowercase()
433                            .contains(&app.lambda_state.version_table.filter.to_lowercase())
434                        || v.aliases
435                            .to_lowercase()
436                            .contains(&app.lambda_state.version_table.filter.to_lowercase())
437                })
438                .collect();
439            let current_page = app.lambda_state.version_table.selected / page_size;
440            let start_idx = current_page * page_size;
441            let end_idx = (start_idx + page_size).min(filtered.len());
442            let paginated: Vec<_> = filtered[start_idx..end_idx].to_vec();
443            let page_index = app.lambda_state.version_table.selected % page_size;
444            if let Some(version) = paginated.get(page_index) {
445                app.lambda_state.current_version = Some(version.version.clone());
446                app.lambda_state.detail_tab = LambdaDetailTab::Code;
447            }
448        } else {
449            if app.lambda_state.version_table.expanded_item
450                == Some(app.lambda_state.version_table.selected)
451            {
452                app.lambda_state.version_table.collapse();
453            } else {
454                app.lambda_state.version_table.expanded_item =
455                    Some(app.lambda_state.version_table.selected);
456            }
457        }
458    } else if app.lambda_state.current_function.is_some()
459        && app.lambda_state.detail_tab == LambdaDetailTab::Aliases
460    {
461        let filtered: Vec<_> = app
462            .lambda_state
463            .alias_table
464            .items
465            .iter()
466            .filter(|a| {
467                app.lambda_state.alias_table.filter.is_empty()
468                    || a.name
469                        .to_lowercase()
470                        .contains(&app.lambda_state.alias_table.filter.to_lowercase())
471                    || a.versions
472                        .to_lowercase()
473                        .contains(&app.lambda_state.alias_table.filter.to_lowercase())
474            })
475            .collect();
476        if let Some(alias) = app.lambda_state.alias_table.get_selected(&filtered) {
477            app.lambda_state.current_alias = Some(alias.name.clone());
478        }
479    } else if app.lambda_state.current_function.is_none() {
480        let filtered = filtered_lambda_functions(app);
481        if let Some(func) = app.lambda_state.table.get_selected(&filtered) {
482            app.lambda_state.current_function = Some(func.name.clone());
483            app.lambda_state.detail_tab = LambdaDetailTab::Code;
484            app.update_current_tab_breadcrumb();
485        }
486    }
487}
488
489pub fn go_back(app: &mut App) {
490    if app.lambda_state.current_version.is_some() {
491        app.lambda_state.current_version = None;
492        app.lambda_state.detail_tab = LambdaDetailTab::Versions;
493    } else if app.lambda_state.current_alias.is_some() {
494        app.lambda_state.current_alias = None;
495        app.lambda_state.detail_tab = LambdaDetailTab::Aliases;
496    } else if app.lambda_state.current_function.is_some() {
497        app.lambda_state.current_function = None;
498        app.update_current_tab_breadcrumb();
499    }
500}
501
502pub fn next_detail_tab(app: &mut App) {
503    if app.lambda_state.current_version.is_some() {
504        app.lambda_state.version_detail_tab = app.lambda_state.version_detail_tab.next();
505        app.lambda_state.detail_tab = app.lambda_state.version_detail_tab.to_detail_tab();
506        if app.lambda_state.detail_tab == LambdaDetailTab::Monitor {
507            app.lambda_state.set_metrics_loading(true);
508            app.lambda_state.set_monitoring_scroll(0);
509            app.lambda_state.clear_metrics();
510        }
511    } else {
512        app.lambda_state.detail_tab = app.lambda_state.detail_tab.next();
513        if app.lambda_state.detail_tab == LambdaDetailTab::Monitor {
514            app.lambda_state.set_metrics_loading(true);
515            app.lambda_state.set_monitoring_scroll(0);
516            app.lambda_state.clear_metrics();
517        }
518    }
519}
520
521pub fn prev_detail_tab(app: &mut App) {
522    if app.lambda_state.current_version.is_some() {
523        app.lambda_state.version_detail_tab = app.lambda_state.version_detail_tab.prev();
524        app.lambda_state.detail_tab = app.lambda_state.version_detail_tab.to_detail_tab();
525        if app.lambda_state.detail_tab == LambdaDetailTab::Monitor {
526            app.lambda_state.set_metrics_loading(true);
527            app.lambda_state.set_monitoring_scroll(0);
528            app.lambda_state.clear_metrics();
529        }
530    } else {
531        app.lambda_state.detail_tab = app.lambda_state.detail_tab.prev();
532        if app.lambda_state.detail_tab == LambdaDetailTab::Monitor {
533            app.lambda_state.set_metrics_loading(true);
534            app.lambda_state.set_monitoring_scroll(0);
535            app.lambda_state.clear_metrics();
536        }
537    }
538}
539
540pub fn refresh(app: &mut App) {
541    app.lambda_state.table.loading = true;
542}
543
544pub fn yank(app: &App) {
545    use crate::app::copy_to_clipboard;
546    let filtered = filtered_lambda_functions(app);
547    if let Some(func) = app.lambda_state.table.get_selected(&filtered) {
548        copy_to_clipboard(&func.arn);
549    }
550}
551
552// ── Column preferences ────────────────────────────────────────────────────────
553
554pub fn toggle_column(app: &mut App) {
555    let idx = app.column_selector_index;
556    if app.lambda_state.current_function.is_some()
557        && app.lambda_state.detail_tab == LambdaDetailTab::Versions
558    {
559        if idx > 0 && idx <= app.lambda_state.version_column_ids.len() {
560            if let Some(col) = app.lambda_state.version_column_ids.get(idx - 1) {
561                if let Some(pos) = app
562                    .lambda_state
563                    .version_visible_column_ids
564                    .iter()
565                    .position(|c| *c == *col)
566                {
567                    if app.lambda_state.version_visible_column_ids.len() > 1 {
568                        app.lambda_state.version_visible_column_ids.remove(pos);
569                    }
570                } else {
571                    app.lambda_state
572                        .version_visible_column_ids
573                        .push(col.clone());
574                }
575            }
576        } else if idx == app.lambda_state.version_column_ids.len() + 3 {
577            app.lambda_state.version_table.page_size = PageSize::Ten;
578        } else if idx == app.lambda_state.version_column_ids.len() + 4 {
579            app.lambda_state.version_table.page_size = PageSize::TwentyFive;
580        } else if idx == app.lambda_state.version_column_ids.len() + 5 {
581            app.lambda_state.version_table.page_size = PageSize::Fifty;
582        } else if idx == app.lambda_state.version_column_ids.len() + 6 {
583            app.lambda_state.version_table.page_size = PageSize::OneHundred;
584        }
585    } else if (app.lambda_state.current_function.is_some()
586        && app.lambda_state.detail_tab == LambdaDetailTab::Aliases)
587        || (app.lambda_state.current_version.is_some()
588            && app.lambda_state.detail_tab == LambdaDetailTab::Configuration)
589    {
590        if idx > 0 && idx <= app.lambda_state.alias_column_ids.len() {
591            if let Some(col) = app.lambda_state.alias_column_ids.get(idx - 1) {
592                if let Some(pos) = app
593                    .lambda_state
594                    .alias_visible_column_ids
595                    .iter()
596                    .position(|c| *c == *col)
597                {
598                    if app.lambda_state.alias_visible_column_ids.len() > 1 {
599                        app.lambda_state.alias_visible_column_ids.remove(pos);
600                    }
601                } else {
602                    app.lambda_state.alias_visible_column_ids.push(col.clone());
603                }
604            }
605        } else if idx == app.lambda_state.alias_column_ids.len() + 3 {
606            app.lambda_state.alias_table.page_size = PageSize::Ten;
607        } else if idx == app.lambda_state.alias_column_ids.len() + 4 {
608            app.lambda_state.alias_table.page_size = PageSize::TwentyFive;
609        } else if idx == app.lambda_state.alias_column_ids.len() + 5 {
610            app.lambda_state.alias_table.page_size = PageSize::Fifty;
611        } else if idx == app.lambda_state.alias_column_ids.len() + 6 {
612            app.lambda_state.alias_table.page_size = PageSize::OneHundred;
613        }
614    } else {
615        if idx > 0 && idx <= app.lambda_state.function_column_ids.len() {
616            if let Some(col) = app.lambda_state.function_column_ids.get(idx - 1) {
617                if let Some(pos) = app
618                    .lambda_state
619                    .function_visible_column_ids
620                    .iter()
621                    .position(|c| c == col)
622                {
623                    if app.lambda_state.function_visible_column_ids.len() > 1 {
624                        app.lambda_state.function_visible_column_ids.remove(pos);
625                    }
626                } else {
627                    app.lambda_state.function_visible_column_ids.push(*col);
628                }
629            }
630        } else if idx == app.lambda_state.function_column_ids.len() + 3 {
631            app.lambda_state.table.page_size = PageSize::Ten;
632        } else if idx == app.lambda_state.function_column_ids.len() + 4 {
633            app.lambda_state.table.page_size = PageSize::TwentyFive;
634        } else if idx == app.lambda_state.function_column_ids.len() + 5 {
635            app.lambda_state.table.page_size = PageSize::Fifty;
636        } else if idx == app.lambda_state.function_column_ids.len() + 6 {
637            app.lambda_state.table.page_size = PageSize::OneHundred;
638        }
639    }
640}
641
642pub fn next_preferences(app: &mut App) {
643    let page_size_idx = app.lambda_state.function_column_ids.len() + 2;
644    if app.column_selector_index < page_size_idx {
645        app.column_selector_index = page_size_idx;
646    } else {
647        app.column_selector_index = 0;
648    }
649}
650
651pub fn prev_preferences(app: &mut App) {
652    let page_size_idx = app.lambda_state.function_column_ids.len() + 2;
653    if app.column_selector_index >= page_size_idx {
654        app.column_selector_index = 0;
655    } else {
656        app.column_selector_index = page_size_idx;
657    }
658}
659
660pub fn column_selector_max(app: &App) -> usize {
661    app.lambda_state.function_column_ids.len() + 6
662}
663
664pub fn column_count(app: &App) -> usize {
665    app.lambda_state.function_column_ids.len()
666}
667
668// ── Breadcrumb / console URL ──────────────────────────────────────────────────
669
670pub fn breadcrumb(app: &App) -> Vec<String> {
671    let mut parts = vec!["Lambda".to_string()];
672    if let Some(func) = &app.lambda_state.current_function {
673        parts.push(func.clone());
674    } else {
675        parts.push("Functions".to_string());
676    }
677    parts
678}
679
680pub fn console_url(app: &App) -> String {
681    use crate::lambda;
682    if let Some(func_name) = &app.lambda_state.current_function {
683        if let Some(version) = &app.lambda_state.current_version {
684            lambda::console_url_function_version(
685                &app.config.region,
686                func_name,
687                version,
688                &app.lambda_state.detail_tab,
689            )
690        } else {
691            lambda::console_url_function_detail(&app.config.region, func_name)
692        }
693    } else {
694        lambda::console_url_functions(&app.config.region)
695    }
696}