feat: Pagination support for jumping 20 items at a time in all table views [#45]
This commit is contained in:
@@ -40,7 +40,7 @@ mod tests {
|
|||||||
title: "Sonarr Test".to_owned(),
|
title: "Sonarr Test".to_owned(),
|
||||||
route: ActiveSonarrBlock::default().into(),
|
route: ActiveSonarrBlock::default().into(),
|
||||||
help: format!(
|
help: format!(
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
"<↑↓> scroll | <C-u/d> page up/down | ←→ change tab | {} ",
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
||||||
),
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
@@ -50,7 +50,7 @@ mod tests {
|
|||||||
title: "Radarr 1".to_owned(),
|
title: "Radarr 1".to_owned(),
|
||||||
route: ActiveRadarrBlock::default().into(),
|
route: ActiveRadarrBlock::default().into(),
|
||||||
help: format!(
|
help: format!(
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
"<↑↓> scroll | <C-u/d> page up/down | ←→ change tab | {} ",
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
||||||
),
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
@@ -60,7 +60,7 @@ mod tests {
|
|||||||
title: "Radarr Test".to_owned(),
|
title: "Radarr Test".to_owned(),
|
||||||
route: ActiveRadarrBlock::default().into(),
|
route: ActiveRadarrBlock::default().into(),
|
||||||
help: format!(
|
help: format!(
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
"<↑↓> scroll | <C-u/d> page up/down | ←→ change tab | {} ",
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
||||||
),
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
@@ -70,7 +70,7 @@ mod tests {
|
|||||||
title: "Sonarr 1".to_owned(),
|
title: "Sonarr 1".to_owned(),
|
||||||
route: ActiveSonarrBlock::default().into(),
|
route: ActiveSonarrBlock::default().into(),
|
||||||
help: format!(
|
help: format!(
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
"<↑↓> scroll | <C-u/d> page up/down | ←→ change tab | {} ",
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
||||||
),
|
),
|
||||||
contextual_help: None,
|
contextual_help: None,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ generate_keybindings! {
|
|||||||
down,
|
down,
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
|
pg_down,
|
||||||
|
pg_up,
|
||||||
backspace,
|
backspace,
|
||||||
next_servarr,
|
next_servarr,
|
||||||
previous_servarr,
|
previous_servarr,
|
||||||
@@ -74,6 +76,16 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
|||||||
alt: Some(Key::Char('l')),
|
alt: Some(Key::Char('l')),
|
||||||
desc: "right",
|
desc: "right",
|
||||||
},
|
},
|
||||||
|
pg_down: KeyBinding {
|
||||||
|
key: Key::PgDown,
|
||||||
|
alt: Some(Key::Ctrl('d')),
|
||||||
|
desc: "page down",
|
||||||
|
},
|
||||||
|
pg_up: KeyBinding {
|
||||||
|
key: Key::PgUp,
|
||||||
|
alt: Some(Key::Ctrl('u')),
|
||||||
|
desc: "page up",
|
||||||
|
},
|
||||||
backspace: KeyBinding {
|
backspace: KeyBinding {
|
||||||
key: Key::Backspace,
|
key: Key::Backspace,
|
||||||
alt: Some(Key::Ctrl('h')),
|
alt: Some(Key::Ctrl('h')),
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ mod test {
|
|||||||
#[case(DEFAULT_KEYBINDINGS.down, Key::Down, Some(Key::Char('j')), "down")]
|
#[case(DEFAULT_KEYBINDINGS.down, Key::Down, Some(Key::Char('j')), "down")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, Some(Key::Char('h')), "left")]
|
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, Some(Key::Char('h')), "left")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, Some(Key::Char('l')), "right")]
|
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, Some(Key::Char('l')), "right")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.pg_down, Key::PgDown, Some(Key::Ctrl('d')), "page down")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.pg_up, Key::PgUp, Some(Key::Ctrl('u')), "page up")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, Some(Key::Ctrl('h')), "backspace")]
|
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, Some(Key::Ctrl('h')), "backspace")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, None, "next servarr")]
|
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, None, "next servarr")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, None, "previous servarr")]
|
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, None, "previous servarr")]
|
||||||
|
|||||||
+1
-1
@@ -52,7 +52,7 @@ impl App<'_> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let mut server_tabs = Vec::new();
|
let mut server_tabs = Vec::new();
|
||||||
let help = format!(
|
let help = format!(
|
||||||
"<↑↓> scroll | ←→ change tab | {} ",
|
"<↑↓> scroll | <C-u/d> page up/down | ←→ change tab | {} ",
|
||||||
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
build_context_clue_string(&SERVARR_CONTEXT_CLUES)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ pub enum Key {
|
|||||||
Down,
|
Down,
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
|
PgDown,
|
||||||
|
PgUp,
|
||||||
Enter,
|
Enter,
|
||||||
Esc,
|
Esc,
|
||||||
Backspace,
|
Backspace,
|
||||||
@@ -35,6 +37,8 @@ impl Display for Key {
|
|||||||
Key::Down => write!(f, "<↓>"),
|
Key::Down => write!(f, "<↓>"),
|
||||||
Key::Left => write!(f, "<←>"),
|
Key::Left => write!(f, "<←>"),
|
||||||
Key::Right => write!(f, "<→>"),
|
Key::Right => write!(f, "<→>"),
|
||||||
|
Key::PgDown => write!(f, "<C-d>"),
|
||||||
|
Key::PgUp => write!(f, "<C-u>"),
|
||||||
Key::Enter => write!(f, "<enter>"),
|
Key::Enter => write!(f, "<enter>"),
|
||||||
Key::Esc => write!(f, "<esc>"),
|
Key::Esc => write!(f, "<esc>"),
|
||||||
Key::Backspace => write!(f, "<backspace>"),
|
Key::Backspace => write!(f, "<backspace>"),
|
||||||
@@ -66,6 +70,14 @@ impl From<KeyEvent> for Key {
|
|||||||
code: KeyCode::Right,
|
code: KeyCode::Right,
|
||||||
..
|
..
|
||||||
} => Key::Right,
|
} => Key::Right,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::PageDown,
|
||||||
|
..
|
||||||
|
} => Key::PgDown,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::PageUp,
|
||||||
|
..
|
||||||
|
} => Key::PgUp,
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Backspace,
|
code: KeyCode::Backspace,
|
||||||
..
|
..
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ mod tests {
|
|||||||
#[case(Key::Down, "↓")]
|
#[case(Key::Down, "↓")]
|
||||||
#[case(Key::Left, "←")]
|
#[case(Key::Left, "←")]
|
||||||
#[case(Key::Right, "→")]
|
#[case(Key::Right, "→")]
|
||||||
|
#[case(Key::PgDown, "C-d")]
|
||||||
|
#[case(Key::PgUp, "C-u")]
|
||||||
#[case(Key::Enter, "enter")]
|
#[case(Key::Enter, "enter")]
|
||||||
#[case(Key::Esc, "esc")]
|
#[case(Key::Esc, "esc")]
|
||||||
#[case(Key::Backspace, "backspace")]
|
#[case(Key::Backspace, "backspace")]
|
||||||
@@ -45,6 +47,16 @@ mod tests {
|
|||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Right)), Key::Right);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Right)), Key::Right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_page_down() {
|
||||||
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::PageDown)), Key::PgDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_page_up() {
|
||||||
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::PageUp)), Key::PgUp);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from_backspace() {
|
fn test_key_from_backspace() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ macro_rules! handle_table_events {
|
|||||||
match $self.key {
|
match $self.key {
|
||||||
_ if $crate::matches_key!(up, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_up>](config),
|
_ if $crate::matches_key!(up, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_up>](config),
|
||||||
_ if $crate::matches_key!(down, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_down>](config),
|
_ if $crate::matches_key!(down, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_scroll_down>](config),
|
||||||
|
_ if $crate::matches_key!(pg_up, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_page_up>](config),
|
||||||
|
_ if $crate::matches_key!(pg_down, $self.key, $self.ignore_special_keys()) => $self.[<handle_ $name _table_page_down>](config),
|
||||||
_ if $crate::matches_key!(home, $self.key) => $self.[<handle_ $name _table_home>](config),
|
_ if $crate::matches_key!(home, $self.key) => $self.[<handle_ $name _table_home>](config),
|
||||||
_ if $crate::matches_key!(end, $self.key) => $self.[<handle_ $name _table_end>](config),
|
_ if $crate::matches_key!(end, $self.key) => $self.[<handle_ $name _table_end>](config),
|
||||||
_ if $crate::matches_key!(left, $self.key, $self.ignore_special_keys())
|
_ if $crate::matches_key!(left, $self.key, $self.ignore_special_keys())
|
||||||
@@ -116,6 +118,30 @@ macro_rules! handle_table_events {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn [<handle_ $name _table_page_down>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool {
|
||||||
|
use $crate::models::Paginated;
|
||||||
|
|
||||||
|
match $self.app.get_current_route() {
|
||||||
|
_ if config.table_block == $self.app.get_current_route() => {
|
||||||
|
$table.page_down();
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn [<handle_ $name _table_page_up>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool {
|
||||||
|
use $crate::models::Paginated;
|
||||||
|
|
||||||
|
match $self.app.get_current_route() {
|
||||||
|
_ if config.table_block == $self.app.get_current_route() => {
|
||||||
|
$table.page_up();
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn [<handle_ $name _table_home>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool {
|
fn [<handle_ $name _table_home>](&mut $self, config: $crate::handlers::table_handler::TableHandlingConfig<$row>) -> bool {
|
||||||
use $crate::models::Scrollable;
|
use $crate::models::Scrollable;
|
||||||
|
|
||||||
|
|||||||
@@ -429,6 +429,48 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod test_handle_pagination_scroll {
|
||||||
|
use super::*;
|
||||||
|
use crate::handlers::table_handler::table_handler_tests::tests::TableHandlerUnit;
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
|
use pretty_assertions::assert_str_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_table_pagination_scroll(
|
||||||
|
#[values(DEFAULT_KEYBINDINGS.pg_up.key, DEFAULT_KEYBINDINGS.pg_down.key)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::test_default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
|
let mut curr = 0;
|
||||||
|
let movies_vec = iter::repeat_with(|| {
|
||||||
|
let tmp = curr;
|
||||||
|
curr += 1;
|
||||||
|
Movie {
|
||||||
|
title: format!("Test {tmp}").into(),
|
||||||
|
..Movie::default()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.take(100)
|
||||||
|
.collect();
|
||||||
|
app.data.radarr_data.movies.set_items(movies_vec);
|
||||||
|
TableHandlerUnit::new(key, &mut app, ActiveRadarrBlock::Movies, None).handle();
|
||||||
|
|
||||||
|
if key == Key::PgUp {
|
||||||
|
assert_str_eq!(
|
||||||
|
app.data.radarr_data.movies.current_selection().title.text,
|
||||||
|
"Test 79"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_str_eq!(
|
||||||
|
app.data.radarr_data.movies.current_selection().title.text,
|
||||||
|
"Test 20"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mod test_handle_left_right_action {
|
mod test_handle_left_right_action {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use std::sync::atomic::Ordering::SeqCst;
|
use std::sync::atomic::Ordering::SeqCst;
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ pub trait Scrollable {
|
|||||||
fn scroll_to_bottom(&mut self);
|
fn scroll_to_bottom(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Paginated {
|
||||||
|
fn page_down(&mut self);
|
||||||
|
fn page_up(&mut self);
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ScrollableText {
|
pub struct ScrollableText {
|
||||||
pub items: Vec<String>,
|
pub items: Vec<String>,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::models::stateful_list::StatefulList;
|
use crate::models::stateful_list::StatefulList;
|
||||||
use crate::models::{strip_non_search_characters, HorizontallyScrollableText, Scrollable};
|
use crate::models::{
|
||||||
|
strip_non_search_characters, HorizontallyScrollableText, Paginated, Scrollable,
|
||||||
|
};
|
||||||
use ratatui::widgets::TableState;
|
use ratatui::widgets::TableState;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@@ -151,6 +153,79 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Paginated for StatefulTable<T>
|
||||||
|
where
|
||||||
|
T: Clone + PartialEq + Eq + Debug,
|
||||||
|
{
|
||||||
|
fn page_down(&mut self) {
|
||||||
|
if let Some(filtered_items) = self.filtered_items.as_ref() {
|
||||||
|
if filtered_items.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.filtered_state.as_ref().unwrap().selected() {
|
||||||
|
Some(i) => {
|
||||||
|
self
|
||||||
|
.filtered_state
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.select(Some(i.saturating_add(20) % (filtered_items.len() - 1)));
|
||||||
|
}
|
||||||
|
None => self.filtered_state.as_mut().unwrap().select_first(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.items.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.state.selected() {
|
||||||
|
Some(i) => {
|
||||||
|
self
|
||||||
|
.state
|
||||||
|
.select(Some(i.saturating_add(20) % (self.items.len() - 1)));
|
||||||
|
}
|
||||||
|
None => self.state.select_first(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn page_up(&mut self) {
|
||||||
|
if let Some(filtered_items) = self.filtered_items.as_ref() {
|
||||||
|
if filtered_items.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.filtered_state.as_ref().unwrap().selected() {
|
||||||
|
Some(i) => {
|
||||||
|
let len = filtered_items.len() - 1;
|
||||||
|
self
|
||||||
|
.filtered_state
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.select(Some((i + len - (20 % len)) % len));
|
||||||
|
}
|
||||||
|
None => self.filtered_state.as_mut().unwrap().select_last(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.items.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.state.selected() {
|
||||||
|
Some(i) => {
|
||||||
|
let len = self.items.len() - 1;
|
||||||
|
self.state.select(Some((i + len - (20 % len)) % len));
|
||||||
|
}
|
||||||
|
None => self.state.select_last(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> StatefulTable<T>
|
impl<T> StatefulTable<T>
|
||||||
where
|
where
|
||||||
T: Clone + PartialEq + Eq + Debug + Default,
|
T: Clone + PartialEq + Eq + Debug + Default,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::stateful_table::{SortOption, StatefulTable};
|
use crate::models::stateful_table::{SortOption, StatefulTable};
|
||||||
use crate::models::Scrollable;
|
use crate::models::{Paginated, Scrollable};
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
use ratatui::widgets::TableState;
|
use ratatui::widgets::TableState;
|
||||||
|
use std::iter;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stateful_table_scrolling_on_empty_table_performs_no_op() {
|
fn test_stateful_table_scrolling_on_empty_table_performs_no_op() {
|
||||||
@@ -190,6 +191,174 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stateful_table_pagination_on_empty_table_performs_no_op() {
|
||||||
|
let mut stateful_table: StatefulTable<String> = StatefulTable::default();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), None);
|
||||||
|
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), None);
|
||||||
|
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stateful_table_filtered_pagination_on_empty_table_performs_no_op() {
|
||||||
|
let mut filtered_stateful_table: StatefulTable<String> = StatefulTable {
|
||||||
|
filtered_items: Some(Vec::new()),
|
||||||
|
filtered_state: Some(TableState::default()),
|
||||||
|
..StatefulTable::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
filtered_stateful_table
|
||||||
|
.filtered_state
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.selected(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
filtered_stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
filtered_stateful_table
|
||||||
|
.filtered_state
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.selected(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
filtered_stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
filtered_stateful_table
|
||||||
|
.filtered_state
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.selected(),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stateful_table_pagination() {
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
let mut curr = 0;
|
||||||
|
stateful_table.set_filtered_items(
|
||||||
|
iter::repeat_with(|| {
|
||||||
|
let tmp = curr;
|
||||||
|
curr += 1;
|
||||||
|
tmp
|
||||||
|
})
|
||||||
|
.take(100)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(20)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(stateful_table.filtered_items.as_ref().unwrap().len() - 21)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(0)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.scroll_down();
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(stateful_table.filtered_items.as_ref().unwrap().len() - 20)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.scroll_down();
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.filtered_state.as_ref().unwrap().selected(),
|
||||||
|
Some(2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stateful_table_filtered_items_pagination() {
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
let mut curr = 0;
|
||||||
|
stateful_table.set_items(
|
||||||
|
iter::repeat_with(|| {
|
||||||
|
let tmp = curr;
|
||||||
|
curr += 1;
|
||||||
|
tmp
|
||||||
|
})
|
||||||
|
.take(100)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), Some(0));
|
||||||
|
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), Some(20));
|
||||||
|
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), Some(0));
|
||||||
|
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.state.selected(),
|
||||||
|
Some(stateful_table.items.len() - 21)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), Some(0));
|
||||||
|
|
||||||
|
stateful_table.scroll_down();
|
||||||
|
stateful_table.page_up();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
stateful_table.state.selected(),
|
||||||
|
Some(stateful_table.items.len() - 20)
|
||||||
|
);
|
||||||
|
|
||||||
|
stateful_table.scroll_down();
|
||||||
|
stateful_table.page_down();
|
||||||
|
|
||||||
|
assert_eq!(stateful_table.state.selected(), Some(2));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stateful_table_set_items() {
|
fn test_stateful_table_set_items() {
|
||||||
let items_vec = vec!["Test 1", "Test 2", "Test 3"];
|
let items_vec = vec!["Test 1", "Test 2", "Test 3"];
|
||||||
|
|||||||
Reference in New Issue
Block a user