Skip to main content

rusticity_term/s3/
actions.rs

1use crate::app::App;
2use crate::common::{CyclicEnum, InputFocus, PageSize};
3use crate::ui::s3::{calculate_filtered_bucket_rows, BucketType as S3BucketType};
4
5const FILTER_CONTROLS: [InputFocus; 2] = [InputFocus::Filter, InputFocus::Pagination];
6
7// ── Filter ────────────────────────────────────────────────────────────────────
8
9pub fn apply_filter_reset(app: &mut App) {
10    if app.s3_state.current_bucket.is_some() {
11        app.s3_state.selected_object = 0;
12    } else {
13        app.s3_state.buckets.reset();
14        app.s3_state.selected_row = 0;
15        app.s3_state.bucket_scroll_offset = 0;
16    }
17}
18
19pub fn reset_on_service_select(app: &mut App) {
20    app.s3_state.selected_row = 0;
21    app.s3_state.selected_object = 0;
22}
23
24pub fn start_filter(app: &mut App) {
25    app.s3_state.input_focus = InputFocus::Filter;
26}
27
28pub fn next_filter_focus(app: &mut App) {
29    app.s3_state.input_focus = app.s3_state.input_focus.next(&FILTER_CONTROLS);
30}
31
32pub fn prev_filter_focus(app: &mut App) {
33    app.s3_state.input_focus = app.s3_state.input_focus.prev(&FILTER_CONTROLS);
34}
35
36pub fn is_pagination_focused(app: &App) -> bool {
37    app.s3_state.input_focus == InputFocus::Pagination
38}
39
40// ── Navigation — pagination ───────────────────────────────────────────────────
41
42pub fn page_down_filter_input(app: &mut App) {
43    if app.s3_state.input_focus == InputFocus::Pagination {
44        let page_size = app.s3_state.buckets.page_size.value();
45        let total_rows = calculate_filtered_bucket_rows(app);
46        let last_page = if total_rows > page_size {
47            ((total_rows - 1) / page_size) * page_size
48        } else {
49            0
50        };
51        app.s3_state.selected_row = (app.s3_state.selected_row + page_size).min(last_page);
52        app.s3_state.bucket_scroll_offset = app.s3_state.selected_row;
53    }
54}
55
56pub fn page_up_filter_input(app: &mut App) {
57    if app.s3_state.input_focus == InputFocus::Pagination {
58        let page_size = app.s3_state.buckets.page_size.value();
59        app.s3_state.selected_row = app.s3_state.selected_row.saturating_sub(page_size);
60        app.s3_state.bucket_scroll_offset = app.s3_state.selected_row;
61    }
62}
63
64// ── Actions ───────────────────────────────────────────────────────────────────
65
66pub fn go_back(app: &mut App) {
67    if !app.s3_state.prefix_stack.is_empty() {
68        app.s3_state.prefix_stack.pop();
69        app.s3_state.buckets.loading = true;
70    } else {
71        app.s3_state.current_bucket = None;
72        app.s3_state.objects.clear();
73    }
74}
75
76pub fn next_detail_tab(app: &mut App) {
77    if app.s3_state.current_bucket.is_some() {
78        app.s3_state.object_tab = app.s3_state.object_tab.next();
79    } else {
80        app.s3_state.bucket_type = match app.s3_state.bucket_type {
81            S3BucketType::GeneralPurpose => S3BucketType::Directory,
82            S3BucketType::Directory => S3BucketType::GeneralPurpose,
83        };
84        app.s3_state.buckets.reset();
85    }
86}
87
88pub fn prev_detail_tab(app: &mut App) {
89    if app.s3_state.current_bucket.is_some() {
90        app.s3_state.object_tab = app.s3_state.object_tab.prev();
91    }
92}
93
94// ── Column preferences ────────────────────────────────────────────────────────
95
96pub fn toggle_column(app: &mut App) {
97    let idx = app.column_selector_index;
98    if idx > 0 && idx <= app.s3_bucket_column_ids.len() {
99        if let Some(col) = app.s3_bucket_column_ids.get(idx - 1) {
100            App::toggle_column_visibility(
101                &mut app.s3_bucket_visible_column_ids,
102                &app.s3_bucket_column_ids,
103                *col,
104            );
105        }
106    } else if idx == app.s3_bucket_column_ids.len() + 3 {
107        app.s3_state.buckets.page_size = PageSize::Ten;
108    } else if idx == app.s3_bucket_column_ids.len() + 4 {
109        app.s3_state.buckets.page_size = PageSize::TwentyFive;
110    } else if idx == app.s3_bucket_column_ids.len() + 5 {
111        app.s3_state.buckets.page_size = PageSize::Fifty;
112    } else if idx == app.s3_bucket_column_ids.len() + 6 {
113        app.s3_state.buckets.page_size = PageSize::OneHundred;
114    }
115}
116
117pub fn next_preferences(app: &mut App) {
118    let page_size_idx = app.s3_bucket_column_ids.len() + 2;
119    if app.column_selector_index < page_size_idx {
120        app.column_selector_index = page_size_idx;
121    } else {
122        app.column_selector_index = 0;
123    }
124}
125
126pub fn prev_preferences(app: &mut App) {
127    let page_size_idx = app.s3_bucket_column_ids.len() + 2;
128    if app.column_selector_index >= page_size_idx {
129        app.column_selector_index = 0;
130    } else {
131        app.column_selector_index = page_size_idx;
132    }
133}
134
135pub fn column_selector_max(app: &App) -> usize {
136    app.s3_bucket_column_ids.len() + 6
137}
138
139pub fn column_count(app: &App) -> usize {
140    app.s3_bucket_column_ids.len()
141}
142
143// ── Breadcrumb / console URL ──────────────────────────────────────────────────
144
145pub fn breadcrumb(app: &App) -> Vec<String> {
146    let mut parts = vec!["S3".to_string()];
147    if let Some(bucket) = &app.s3_state.current_bucket {
148        parts.push(bucket.clone());
149        if let Some(prefix) = app.s3_state.prefix_stack.last() {
150            parts.push(prefix.trim_end_matches('/').to_string());
151        }
152    } else {
153        parts.push("Buckets".to_string());
154    }
155    parts
156}
157
158pub fn console_url(app: &App) -> String {
159    use crate::s3;
160    if let Some(bucket_name) = &app.s3_state.current_bucket {
161        let prefix = app.s3_state.prefix_stack.join("");
162        s3::console_url_bucket(&app.config.region, bucket_name, &prefix)
163    } else {
164        s3::console_url_buckets(&app.config.region)
165    }
166}