diff --git a/docs/src/configurations/config-file-format.md b/docs/src/configurations/config-file-format.md index f52a1a5..2352d0d 100644 --- a/docs/src/configurations/config-file-format.md +++ b/docs/src/configurations/config-file-format.md @@ -9,9 +9,13 @@ max_concurrent_requests = 5 default_region = "us-east-1" +[ui.bucket_list] +default_sort = "default" + [ui.object_list] date_format = "%Y-%m-%d %H:%M:%S" date_width = 19 +default_sort = "default" [ui.object_detail] date_format = "%Y-%m-%d %H:%M:%S" @@ -58,6 +62,17 @@ The default region to use if the region cannot be obtained from the command line - type: `string` - default: `us-east-1` +### `ui.bucket_list.default_sort` + +The default sort order of the bucket list. + +- type: `string` +- default: `default` +- possible values: + - `default` + - `name_asc` + - `name_desc` + ### `ui.object_list.date_format` The date format of a last modified in the object list. @@ -74,6 +89,21 @@ It is recommended to set this when setting `date_format`. - type: `u16` - default: `19` +### `ui.object_list.default_sort` + +The default sort order of the object list. + +- type: `string` +- default: `default` +- possible values: + - `default` + - `name_asc` + - `name_desc` + - `date_asc` + - `date_desc` + - `size_asc` + - `size_desc` + ### `ui.object_detail.date_format` The date format of a last modified in the object detail. diff --git a/src/config.rs b/src/config.rs index 0e9454b..5156161 100644 --- a/src/config.rs +++ b/src/config.rs @@ -37,6 +37,8 @@ pub struct Config { #[optional(derives = [Deserialize])] #[derive(Debug, Clone, SmartDefault)] pub struct UiConfig { + #[nested] + pub bucket_list: UiBucketListConfig, #[nested] pub object_list: UiObjectListConfig, #[nested] @@ -45,6 +47,21 @@ pub struct UiConfig { pub help: UiHelpConfig, } +#[optional(derives = [Deserialize])] +#[derive(Debug, Clone, SmartDefault)] +pub struct UiBucketListConfig { + #[default(BucketListDefaultSort::Default)] + pub default_sort: BucketListDefaultSort, +} + +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum BucketListDefaultSort { + Default, + NameAsc, + NameDesc, +} + #[optional(derives = [Deserialize])] #[derive(Debug, Clone, SmartDefault)] pub struct UiObjectListConfig { @@ -52,6 +69,20 @@ pub struct UiObjectListConfig { pub date_format: String, #[default = 19] // // "2021-01-01 12:34:56".len() pub date_width: usize, + #[default(ObjectListDefaultSort::Default)] + pub default_sort: ObjectListDefaultSort, +} + +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ObjectListDefaultSort { + Default, + NameAsc, + NameDesc, + DateAsc, + DateDesc, + SizeAsc, + SizeDesc, } #[optional(derives = [Deserialize])] diff --git a/src/pages/bucket_list.rs b/src/pages/bucket_list.rs index 364f74f..d45ab22 100644 --- a/src/pages/bucket_list.rs +++ b/src/pages/bucket_list.rs @@ -60,16 +60,20 @@ impl BucketListPage { pub fn new(bucket_items: Vec, ctx: Rc, tx: Sender) -> Self { let items_len = bucket_items.len(); let view_indices = (0..items_len).collect(); - Self { + let mut page = Self { bucket_items, view_indices, view_state: ViewState::Default, list_state: ScrollListState::new(items_len), filter_input_state: InputDialogState::default(), - sort_dialog_state: BucketListSortDialogState::default(), + sort_dialog_state: BucketListSortDialogState::new( + ctx.config.ui.bucket_list.default_sort, + ), ctx, tx, - } + }; + page.sort_view_indices(); // initial sort + page } pub fn handle_key(&mut self, user_events: Vec, key_event: KeyEvent) { diff --git a/src/pages/object_list.rs b/src/pages/object_list.rs index 798ad9d..bd61831 100644 --- a/src/pages/object_list.rs +++ b/src/pages/object_list.rs @@ -69,17 +69,21 @@ impl ObjectListPage { ) -> Self { let items_len = object_items.len(); let view_indices = (0..items_len).collect(); - Self { + let mut page = Self { object_items, object_key, view_indices, view_state: ViewState::Default, list_state: ScrollListState::new(items_len), filter_input_state: InputDialogState::default(), - sort_dialog_state: ObjectListSortDialogState::default(), + sort_dialog_state: ObjectListSortDialogState::new( + ctx.config.ui.object_list.default_sort, + ), ctx, tx, - } + }; + page.sort_view_indices(); // initial sort + page } pub fn handle_key(&mut self, user_events: Vec, key_event: KeyEvent) { diff --git a/src/widget/sort_list_dialog.rs b/src/widget/sort_list_dialog.rs index bfa3eeb..6f7f4a1 100644 --- a/src/widget/sort_list_dialog.rs +++ b/src/widget/sort_list_dialog.rs @@ -8,17 +8,25 @@ use ratatui::{ widgets::{block::Title, Block, BorderType, List, ListItem, Padding, Widget, WidgetRef}, }; -use crate::{color::ColorTheme, widget::Dialog}; +use crate::{color::ColorTheme, config, widget::Dialog}; -#[derive(Default)] #[zero_indexed_enum] pub enum BucketListSortType { - #[default] Default, NameAsc, NameDesc, } +impl From for BucketListSortType { + fn from(sort: config::BucketListDefaultSort) -> Self { + match sort { + config::BucketListDefaultSort::Default => BucketListSortType::Default, + config::BucketListDefaultSort::NameAsc => BucketListSortType::NameAsc, + config::BucketListDefaultSort::NameDesc => BucketListSortType::NameDesc, + } + } +} + impl BucketListSortType { pub fn str(&self) -> &'static str { match self { @@ -29,12 +37,20 @@ impl BucketListSortType { } } -#[derive(Debug, Default, Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct BucketListSortDialogState { + default: BucketListSortType, selected: BucketListSortType, } impl BucketListSortDialogState { + pub fn new(default_sort: config::BucketListDefaultSort) -> Self { + Self { + default: default_sort.into(), + selected: default_sort.into(), + } + } + pub fn select_next(&mut self) { self.selected = self.selected.next(); } @@ -44,7 +60,7 @@ impl BucketListSortDialogState { } pub fn reset(&mut self) { - self.selected = BucketListSortType::Default; + self.selected = self.default; } pub fn selected(&self) -> BucketListSortType { @@ -84,10 +100,8 @@ impl Widget for BucketListSortDialog { } } -#[derive(Default)] #[zero_indexed_enum] pub enum ObjectListSortType { - #[default] Default, NameAsc, NameDesc, @@ -97,6 +111,20 @@ pub enum ObjectListSortType { SizeDesc, } +impl From for ObjectListSortType { + fn from(sort: config::ObjectListDefaultSort) -> Self { + match sort { + config::ObjectListDefaultSort::Default => ObjectListSortType::Default, + config::ObjectListDefaultSort::NameAsc => ObjectListSortType::NameAsc, + config::ObjectListDefaultSort::NameDesc => ObjectListSortType::NameDesc, + config::ObjectListDefaultSort::DateAsc => ObjectListSortType::LastModifiedAsc, + config::ObjectListDefaultSort::DateDesc => ObjectListSortType::LastModifiedDesc, + config::ObjectListDefaultSort::SizeAsc => ObjectListSortType::SizeAsc, + config::ObjectListDefaultSort::SizeDesc => ObjectListSortType::SizeDesc, + } + } +} + impl ObjectListSortType { pub fn str(&self) -> &'static str { match self { @@ -111,12 +139,20 @@ impl ObjectListSortType { } } -#[derive(Debug, Default, Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct ObjectListSortDialogState { + default: ObjectListSortType, selected: ObjectListSortType, } impl ObjectListSortDialogState { + pub fn new(default_sort: config::ObjectListDefaultSort) -> Self { + Self { + default: default_sort.into(), + selected: default_sort.into(), + } + } + pub fn select_next(&mut self) { self.selected = self.selected.next(); } @@ -126,7 +162,7 @@ impl ObjectListSortDialogState { } pub fn reset(&mut self) { - self.selected = ObjectListSortType::Default; + self.selected = self.default; } pub fn selected(&self) -> ObjectListSortType {