refactor(ui): all table search and filter functionality is now available directly through the ManagarrTable widget to make life easier moving forward
This commit is contained in:
+4
-1
@@ -36,7 +36,10 @@ strum = { version = "0.26.3", features = ["derive"] }
|
|||||||
strum_macros = "0.26.4"
|
strum_macros = "0.26.4"
|
||||||
tokio = { version = "1.36.0", features = ["full"] }
|
tokio = { version = "1.36.0", features = ["full"] }
|
||||||
tokio-util = "0.7.8"
|
tokio-util = "0.7.8"
|
||||||
ratatui = { version = "0.29.0", features = ["all-widgets"] }
|
ratatui = { version = "0.29.0", features = [
|
||||||
|
"all-widgets",
|
||||||
|
"unstable-widget-ref",
|
||||||
|
] }
|
||||||
urlencoding = "2.1.2"
|
urlencoding = "2.1.2"
|
||||||
clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
|
clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
|
||||||
clap_complete = "4.5.33"
|
clap_complete = "4.5.33"
|
||||||
|
|||||||
+6
-1
@@ -9,6 +9,7 @@ use ratatui::widgets::Tabs;
|
|||||||
use ratatui::widgets::Wrap;
|
use ratatui::widgets::Wrap;
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
use sonarr_ui::SonarrUi;
|
use sonarr_ui::SonarrUi;
|
||||||
|
use utils::layout_block;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::{HorizontallyScrollableText, Route, TabState};
|
use crate::models::{HorizontallyScrollableText, Route, TabState};
|
||||||
@@ -161,7 +162,11 @@ pub fn draw_popup_over_ui<T: DrawUi>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect {
|
fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -> Rect {
|
||||||
f.render_widget(title_block(title), area);
|
if title.is_empty() {
|
||||||
|
f.render_widget(layout_block(), area);
|
||||||
|
} else {
|
||||||
|
f.render_widget(title_block(title), area);
|
||||||
|
}
|
||||||
|
|
||||||
let [header_area, content_area] = Layout::vertical([Constraint::Length(1), Constraint::Fill(0)])
|
let [header_area, content_area] = Layout::vertical([Constraint::Length(1), Constraint::Fill(0)])
|
||||||
.margin(1)
|
.margin(1)
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ use crate::ui::styles::ManagarrStyle;
|
|||||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||||
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
use crate::ui::widgets::message::Message;
|
|
||||||
use crate::ui::widgets::popup::{Popup, Size};
|
use crate::ui::widgets::popup::{Popup, Size};
|
||||||
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi};
|
use crate::ui::DrawUi;
|
||||||
|
|
||||||
mod collection_details_ui;
|
mod collection_details_ui;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -40,40 +39,12 @@ impl DrawUi for CollectionsUi {
|
|||||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
let route = app.get_current_route();
|
let route = app.get_current_route();
|
||||||
let mut collections_ui_matcher = |active_radarr_block| match active_radarr_block {
|
let mut collections_ui_matcher = |active_radarr_block| match active_radarr_block {
|
||||||
ActiveRadarrBlock::Collections | ActiveRadarrBlock::CollectionsSortPrompt => {
|
ActiveRadarrBlock::Collections
|
||||||
draw_collections(f, app, area)
|
| ActiveRadarrBlock::CollectionsSortPrompt
|
||||||
}
|
| ActiveRadarrBlock::SearchCollection
|
||||||
ActiveRadarrBlock::SearchCollection => draw_popup_over(
|
| ActiveRadarrBlock::SearchCollectionError
|
||||||
f,
|
| ActiveRadarrBlock::FilterCollections
|
||||||
app,
|
| ActiveRadarrBlock::FilterCollectionsError => draw_collections(f, app, area),
|
||||||
area,
|
|
||||||
draw_collections,
|
|
||||||
draw_collection_search_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveRadarrBlock::SearchCollectionError => {
|
|
||||||
let popup = Popup::new(Message::new("Collection not found!")).size(Size::Message);
|
|
||||||
|
|
||||||
draw_collections(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterCollections => draw_popup_over(
|
|
||||||
f,
|
|
||||||
app,
|
|
||||||
area,
|
|
||||||
draw_collections,
|
|
||||||
draw_filter_collections_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveRadarrBlock::FilterCollectionsError => {
|
|
||||||
let popup = Popup::new(Message::new(
|
|
||||||
"No collections found matching the given filter!",
|
|
||||||
))
|
|
||||||
.size(Size::Message);
|
|
||||||
|
|
||||||
draw_collections(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
||||||
let confirmation_prompt = ConfirmationPrompt::new()
|
let confirmation_prompt = ConfirmationPrompt::new()
|
||||||
.title("Update All Collections")
|
.title("Update All Collections")
|
||||||
@@ -156,6 +127,14 @@ pub(super) fn draw_collections(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
|
|||||||
.footer(collections_table_footer)
|
.footer(collections_table_footer)
|
||||||
.block(layout_block_top_border())
|
.block(layout_block_top_border())
|
||||||
.sorting(active_radarr_block == ActiveRadarrBlock::CollectionsSortPrompt)
|
.sorting(active_radarr_block == ActiveRadarrBlock::CollectionsSortPrompt)
|
||||||
|
.searching(active_radarr_block == ActiveRadarrBlock::SearchCollection)
|
||||||
|
.search_produced_empty_results(
|
||||||
|
active_radarr_block == ActiveRadarrBlock::SearchCollectionError,
|
||||||
|
)
|
||||||
|
.filtering(active_radarr_block == ActiveRadarrBlock::FilterCollections)
|
||||||
|
.filter_produced_empty_results(
|
||||||
|
active_radarr_block == ActiveRadarrBlock::FilterCollectionsError,
|
||||||
|
)
|
||||||
.headers([
|
.headers([
|
||||||
"Collection",
|
"Collection",
|
||||||
"Number of Movies",
|
"Number of Movies",
|
||||||
@@ -173,24 +152,15 @@ pub(super) fn draw_collections(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect)
|
|||||||
Constraint::Percentage(15),
|
Constraint::Percentage(15),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if [
|
||||||
|
ActiveRadarrBlock::SearchCollection,
|
||||||
|
ActiveRadarrBlock::FilterCollections,
|
||||||
|
]
|
||||||
|
.contains(&active_radarr_block)
|
||||||
|
{
|
||||||
|
collections_table.show_cursor(f, area);
|
||||||
|
}
|
||||||
|
|
||||||
f.render_widget(collections_table, area);
|
f.render_widget(collections_table, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_collection_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Search",
|
|
||||||
app.data.radarr_data.collections.search.as_ref().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_filter_collections_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Filter",
|
|
||||||
app.data.radarr_data.collections.filter.as_ref().unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,9 +14,8 @@ use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
|
|||||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||||
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
use crate::ui::widgets::message::Message;
|
|
||||||
use crate::ui::widgets::popup::{Popup, Size};
|
use crate::ui::widgets::popup::{Popup, Size};
|
||||||
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi};
|
use crate::ui::DrawUi;
|
||||||
use crate::utils::{convert_runtime, convert_to_gb};
|
use crate::utils::{convert_runtime, convert_to_gb};
|
||||||
|
|
||||||
mod add_movie_ui;
|
mod add_movie_ui;
|
||||||
@@ -47,36 +46,12 @@ impl DrawUi for LibraryUi {
|
|||||||
let route = app.get_current_route();
|
let route = app.get_current_route();
|
||||||
let mut library_ui_matchers = |active_radarr_block: ActiveRadarrBlock| match active_radarr_block
|
let mut library_ui_matchers = |active_radarr_block: ActiveRadarrBlock| match active_radarr_block
|
||||||
{
|
{
|
||||||
ActiveRadarrBlock::Movies | ActiveRadarrBlock::MoviesSortPrompt => draw_library(f, app, area),
|
ActiveRadarrBlock::Movies
|
||||||
ActiveRadarrBlock::SearchMovie => draw_popup_over(
|
| ActiveRadarrBlock::MoviesSortPrompt
|
||||||
f,
|
| ActiveRadarrBlock::SearchMovie
|
||||||
app,
|
| ActiveRadarrBlock::SearchMovieError
|
||||||
area,
|
| ActiveRadarrBlock::FilterMovies
|
||||||
draw_library,
|
| ActiveRadarrBlock::FilterMoviesError => draw_library(f, app, area),
|
||||||
draw_movie_search_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveRadarrBlock::SearchMovieError => {
|
|
||||||
let popup = Popup::new(Message::new("Movie not found!")).size(Size::Message);
|
|
||||||
|
|
||||||
draw_library(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterMovies => draw_popup_over(
|
|
||||||
f,
|
|
||||||
app,
|
|
||||||
area,
|
|
||||||
draw_library,
|
|
||||||
draw_filter_movies_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveRadarrBlock::FilterMoviesError => {
|
|
||||||
let popup = Popup::new(Message::new("No movies found matching the given filter!"))
|
|
||||||
.size(Size::Message);
|
|
||||||
|
|
||||||
draw_library(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
||||||
let confirmation_prompt = ConfirmationPrompt::new()
|
let confirmation_prompt = ConfirmationPrompt::new()
|
||||||
.title("Update All Movies")
|
.title("Update All Movies")
|
||||||
@@ -174,6 +149,10 @@ pub(super) fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
.loading(app.is_loading)
|
.loading(app.is_loading)
|
||||||
.footer(help_footer)
|
.footer(help_footer)
|
||||||
.sorting(active_radarr_block == ActiveRadarrBlock::MoviesSortPrompt)
|
.sorting(active_radarr_block == ActiveRadarrBlock::MoviesSortPrompt)
|
||||||
|
.searching(active_radarr_block == ActiveRadarrBlock::SearchMovie)
|
||||||
|
.search_produced_empty_results(active_radarr_block == ActiveRadarrBlock::SearchMovieError)
|
||||||
|
.filtering(active_radarr_block == ActiveRadarrBlock::FilterMovies)
|
||||||
|
.filter_produced_empty_results(active_radarr_block == ActiveRadarrBlock::FilterMoviesError)
|
||||||
.headers([
|
.headers([
|
||||||
"Title",
|
"Title",
|
||||||
"Year",
|
"Year",
|
||||||
@@ -199,24 +178,15 @@ pub(super) fn draw_library(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
Constraint::Percentage(12),
|
Constraint::Percentage(12),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if [
|
||||||
|
ActiveRadarrBlock::SearchMovie,
|
||||||
|
ActiveRadarrBlock::FilterMovies,
|
||||||
|
]
|
||||||
|
.contains(&active_radarr_block)
|
||||||
|
{
|
||||||
|
library_table.show_cursor(f, area);
|
||||||
|
}
|
||||||
|
|
||||||
f.render_widget(library_table, area);
|
f.render_widget(library_table, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_movie_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Search",
|
|
||||||
app.data.radarr_data.movies.search.as_ref().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_filter_movies_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Filter",
|
|
||||||
app.data.radarr_data.movies.filter.as_ref().unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
+39
-226
@@ -1,19 +1,27 @@
|
|||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS};
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS};
|
||||||
use crate::models::sonarr_models::{SonarrHistoryData, SonarrHistoryEventType, SonarrHistoryItem};
|
use crate::models::sonarr_models::{SonarrHistoryEventType, SonarrHistoryItem};
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
use crate::ui::styles::ManagarrStyle;
|
use crate::ui::styles::ManagarrStyle;
|
||||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
use crate::ui::widgets::message::Message;
|
use crate::ui::widgets::message::Message;
|
||||||
use crate::ui::widgets::popup::{Popup, Size};
|
use crate::ui::widgets::popup::{Popup, Size};
|
||||||
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi};
|
use crate::ui::DrawUi;
|
||||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||||
use ratatui::style::{Style, Stylize};
|
use ratatui::style::Style;
|
||||||
use ratatui::text::{Line, Text};
|
use ratatui::text::Text;
|
||||||
use ratatui::widgets::{Cell, Row};
|
use ratatui::widgets::{Cell, Row};
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
|
|
||||||
|
use super::sonarr_ui_utils::{
|
||||||
|
create_download_failed_history_event_details,
|
||||||
|
create_download_folder_imported_history_event_details,
|
||||||
|
create_episode_file_deleted_history_event_details,
|
||||||
|
create_episode_file_renamed_history_event_details, create_grabbed_history_event_details,
|
||||||
|
create_no_data_history_event_details,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "history_ui_tests.rs"]
|
#[path = "history_ui_tests.rs"]
|
||||||
mod history_ui_tests;
|
mod history_ui_tests;
|
||||||
@@ -32,40 +40,12 @@ impl DrawUi for HistoryUi {
|
|||||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||||
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
if let Route::Sonarr(active_sonarr_block, _) = app.get_current_route() {
|
||||||
match active_sonarr_block {
|
match active_sonarr_block {
|
||||||
ActiveSonarrBlock::History | ActiveSonarrBlock::HistorySortPrompt => {
|
ActiveSonarrBlock::History
|
||||||
draw_history_table(f, app, area)
|
| ActiveSonarrBlock::HistorySortPrompt
|
||||||
}
|
| ActiveSonarrBlock::SearchHistory
|
||||||
ActiveSonarrBlock::SearchHistory => draw_popup_over(
|
| ActiveSonarrBlock::SearchHistoryError
|
||||||
f,
|
| ActiveSonarrBlock::FilterHistory
|
||||||
app,
|
| ActiveSonarrBlock::FilterHistoryError => draw_history_table(f, app, area),
|
||||||
area,
|
|
||||||
draw_history_table,
|
|
||||||
draw_history_search_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveSonarrBlock::SearchHistoryError => {
|
|
||||||
let popup = Popup::new(Message::new("History item not found!")).size(Size::Message);
|
|
||||||
|
|
||||||
draw_history_table(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveSonarrBlock::FilterHistory => draw_popup_over(
|
|
||||||
f,
|
|
||||||
app,
|
|
||||||
area,
|
|
||||||
draw_history_table,
|
|
||||||
draw_filter_history_box,
|
|
||||||
Size::InputBox,
|
|
||||||
),
|
|
||||||
ActiveSonarrBlock::FilterHistoryError => {
|
|
||||||
let popup = Popup::new(Message::new(
|
|
||||||
"No history items found matching the given filter!",
|
|
||||||
))
|
|
||||||
.size(Size::Message);
|
|
||||||
|
|
||||||
draw_history_table(f, app, area);
|
|
||||||
f.render_widget(popup, f.area());
|
|
||||||
}
|
|
||||||
ActiveSonarrBlock::HistoryItemDetails => {
|
ActiveSonarrBlock::HistoryItemDetails => {
|
||||||
draw_history_table(f, app, area);
|
draw_history_table(f, app, area);
|
||||||
draw_history_item_details_popup(f, app);
|
draw_history_item_details_popup(f, app);
|
||||||
@@ -120,6 +100,10 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
.loading(app.is_loading)
|
.loading(app.is_loading)
|
||||||
.footer(history_table_footer)
|
.footer(history_table_footer)
|
||||||
.sorting(active_sonarr_block == ActiveSonarrBlock::HistorySortPrompt)
|
.sorting(active_sonarr_block == ActiveSonarrBlock::HistorySortPrompt)
|
||||||
|
.searching(active_sonarr_block == ActiveSonarrBlock::SearchHistory)
|
||||||
|
.search_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::SearchHistoryError)
|
||||||
|
.filtering(active_sonarr_block == ActiveSonarrBlock::FilterHistory)
|
||||||
|
.filter_produced_empty_results(active_sonarr_block == ActiveSonarrBlock::FilterHistoryError)
|
||||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||||
.constraints([
|
.constraints([
|
||||||
Constraint::Percentage(40),
|
Constraint::Percentage(40),
|
||||||
@@ -129,6 +113,15 @@ fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|||||||
Constraint::Percentage(20),
|
Constraint::Percentage(20),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if [
|
||||||
|
ActiveSonarrBlock::SearchHistory,
|
||||||
|
ActiveSonarrBlock::FilterHistory,
|
||||||
|
]
|
||||||
|
.contains(&active_sonarr_block)
|
||||||
|
{
|
||||||
|
history_table.show_cursor(f, area);
|
||||||
|
}
|
||||||
|
|
||||||
f.render_widget(history_table, area);
|
f.render_widget(history_table, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,18 +134,20 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let line_vec = match current_selection.event_type {
|
let line_vec = match current_selection.event_type {
|
||||||
SonarrHistoryEventType::Unknown => create_unknown_event_vec(current_selection),
|
SonarrHistoryEventType::Grabbed => create_grabbed_history_event_details(current_selection),
|
||||||
SonarrHistoryEventType::DownloadFolderImported => {
|
SonarrHistoryEventType::DownloadFolderImported => {
|
||||||
create_download_folder_imported_event_vec(current_selection)
|
create_download_folder_imported_history_event_details(current_selection)
|
||||||
|
}
|
||||||
|
SonarrHistoryEventType::DownloadFailed => {
|
||||||
|
create_download_failed_history_event_details(current_selection)
|
||||||
}
|
}
|
||||||
SonarrHistoryEventType::DownloadFailed => create_download_failed_event_vec(current_selection),
|
|
||||||
SonarrHistoryEventType::EpisodeFileDeleted => {
|
SonarrHistoryEventType::EpisodeFileDeleted => {
|
||||||
create_episode_file_deleted_event_vec(current_selection)
|
create_episode_file_deleted_history_event_details(current_selection)
|
||||||
}
|
}
|
||||||
SonarrHistoryEventType::EpisodeFileRenamed => {
|
SonarrHistoryEventType::EpisodeFileRenamed => {
|
||||||
create_episode_file_renamed_event_vec(current_selection)
|
create_episode_file_renamed_history_event_details(current_selection)
|
||||||
}
|
}
|
||||||
_ => create_no_data_event_vec(current_selection),
|
_ => create_no_data_history_event_details(current_selection),
|
||||||
};
|
};
|
||||||
let text = Text::from(line_vec);
|
let text = Text::from(line_vec);
|
||||||
|
|
||||||
@@ -163,185 +158,3 @@ fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
|||||||
|
|
||||||
f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area());
|
f.render_widget(Popup::new(message).size(Size::NarrowMessage), f.area());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_unknown_event_vec(history_item: SonarrHistoryItem) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem {
|
|
||||||
source_title, data, ..
|
|
||||||
} = history_item;
|
|
||||||
let SonarrHistoryData {
|
|
||||||
indexer,
|
|
||||||
release_group,
|
|
||||||
series_match_type,
|
|
||||||
nzb_info_url,
|
|
||||||
download_client_name,
|
|
||||||
age,
|
|
||||||
published_date,
|
|
||||||
..
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Indexer: ".bold().secondary(),
|
|
||||||
indexer.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Release Group: ".bold().secondary(),
|
|
||||||
release_group.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Series Match Type: ".bold().secondary(),
|
|
||||||
series_match_type.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"NZB Info URL: ".bold().secondary(),
|
|
||||||
nzb_info_url.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Download Client Name: ".bold().secondary(),
|
|
||||||
download_client_name.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Age: ".bold().secondary(),
|
|
||||||
format!("{} days", age.unwrap_or("0".to_owned())).secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Published Date: ".bold().secondary(),
|
|
||||||
published_date.unwrap_or_default().to_string().secondary(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_download_folder_imported_event_vec(
|
|
||||||
history_item: SonarrHistoryItem,
|
|
||||||
) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem {
|
|
||||||
source_title, data, ..
|
|
||||||
} = history_item;
|
|
||||||
let SonarrHistoryData {
|
|
||||||
dropped_path,
|
|
||||||
imported_path,
|
|
||||||
..
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Dropped Path: ".bold().secondary(),
|
|
||||||
dropped_path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Imported Path: ".bold().secondary(),
|
|
||||||
imported_path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_download_failed_event_vec(history_item: SonarrHistoryItem) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem {
|
|
||||||
source_title, data, ..
|
|
||||||
} = history_item;
|
|
||||||
let SonarrHistoryData { message, .. } = data;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Message: ".bold().secondary(),
|
|
||||||
message.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_episode_file_deleted_event_vec(history_item: SonarrHistoryItem) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem {
|
|
||||||
source_title, data, ..
|
|
||||||
} = history_item;
|
|
||||||
let SonarrHistoryData { reason, .. } = data;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Reason: ".bold().secondary(),
|
|
||||||
reason.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_episode_file_renamed_event_vec(history_item: SonarrHistoryItem) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem {
|
|
||||||
source_title, data, ..
|
|
||||||
} = history_item;
|
|
||||||
let SonarrHistoryData {
|
|
||||||
source_path,
|
|
||||||
source_relative_path,
|
|
||||||
path,
|
|
||||||
relative_path,
|
|
||||||
..
|
|
||||||
} = data;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Path: ".bold().secondary(),
|
|
||||||
source_path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Relative Path: ".bold().secondary(),
|
|
||||||
source_relative_path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Destination Path: ".bold().secondary(),
|
|
||||||
path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![
|
|
||||||
"Destination Relative Path: ".bold().secondary(),
|
|
||||||
relative_path.unwrap_or_default().secondary(),
|
|
||||||
]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_no_data_event_vec(history_item: SonarrHistoryItem) -> Vec<Line<'static>> {
|
|
||||||
let SonarrHistoryItem { source_title, .. } = history_item;
|
|
||||||
|
|
||||||
vec![
|
|
||||||
Line::from(vec![
|
|
||||||
"Source Title: ".bold().secondary(),
|
|
||||||
source_title.text.secondary(),
|
|
||||||
]),
|
|
||||||
Line::from(vec![String::new().secondary()]),
|
|
||||||
Line::from(vec!["No additional data available".bold().secondary()]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_history_search_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Search",
|
|
||||||
app.data.sonarr_data.history.search.as_ref().unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw_filter_history_box(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
|
||||||
draw_input_box_popup(
|
|
||||||
f,
|
|
||||||
area,
|
|
||||||
"Filter",
|
|
||||||
app.data.sonarr_data.history.filter.as_ref().unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::servarr_data::sonarr::sonarr_data::{
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
ActiveSonarrBlock, ADD_SERIES_BLOCKS, DELETE_SERIES_BLOCKS, EDIT_SERIES_BLOCKS,
|
ActiveSonarrBlock, ADD_SERIES_BLOCKS, DELETE_SERIES_BLOCKS, EDIT_SERIES_BLOCKS,
|
||||||
|
SERIES_DETAILS_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_data::sonarr::sonarr_data::LIBRARY_BLOCKS, sonarr_models::SeriesStatus,
|
servarr_data::sonarr::sonarr_data::LIBRARY_BLOCKS, sonarr_models::SeriesStatus,
|
||||||
@@ -26,12 +27,13 @@ mod tests {
|
|||||||
library_ui_blocks.extend(ADD_SERIES_BLOCKS);
|
library_ui_blocks.extend(ADD_SERIES_BLOCKS);
|
||||||
library_ui_blocks.extend(DELETE_SERIES_BLOCKS);
|
library_ui_blocks.extend(DELETE_SERIES_BLOCKS);
|
||||||
library_ui_blocks.extend(EDIT_SERIES_BLOCKS);
|
library_ui_blocks.extend(EDIT_SERIES_BLOCKS);
|
||||||
|
library_ui_blocks.extend(SERIES_DETAILS_BLOCKS);
|
||||||
|
|
||||||
ActiveSonarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
if library_ui_blocks.contains(&active_radarr_block) {
|
if library_ui_blocks.contains(&active_sonarr_block) {
|
||||||
assert!(LibraryUi::accepts(active_radarr_block.into()));
|
assert!(LibraryUi::accepts(active_sonarr_block.into()));
|
||||||
} else {
|
} else {
|
||||||
assert!(!LibraryUi::accepts(active_radarr_block.into()));
|
assert!(!LibraryUi::accepts(active_sonarr_block.into()));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use ratatui::buffer::Buffer;
|
|||||||
use ratatui::layout::{Constraint, Layout, Position, Rect};
|
use ratatui::layout::{Constraint, Layout, Position, Rect};
|
||||||
use ratatui::prelude::Text;
|
use ratatui::prelude::Text;
|
||||||
use ratatui::style::{Style, Styled, Stylize};
|
use ratatui::style::{Style, Styled, Stylize};
|
||||||
use ratatui::widgets::{Block, Paragraph, Widget};
|
use ratatui::widgets::{Block, Paragraph, Widget, WidgetRef};
|
||||||
use ratatui::Frame;
|
use ratatui::Frame;
|
||||||
|
|
||||||
use crate::ui::styles::ManagarrStyle;
|
use crate::ui::styles::ManagarrStyle;
|
||||||
@@ -12,6 +12,8 @@ use crate::ui::utils::{borderless_block, layout_block};
|
|||||||
#[path = "input_box_tests.rs"]
|
#[path = "input_box_tests.rs"]
|
||||||
mod input_box_tests;
|
mod input_box_tests;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
#[cfg_attr(test, derive(Debug, PartialEq))]
|
||||||
pub struct InputBox<'a> {
|
pub struct InputBox<'a> {
|
||||||
content: &'a str,
|
content: &'a str,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
@@ -96,7 +98,7 @@ impl<'a> InputBox<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_input_box(self, area: Rect, buf: &mut Buffer) {
|
fn render_input_box(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let style =
|
let style =
|
||||||
if matches!(self.is_highlighted, Some(true)) && matches!(self.is_selected, Some(false)) {
|
if matches!(self.is_highlighted, Some(true)) && matches!(self.is_selected, Some(false)) {
|
||||||
Style::new().system_function().bold()
|
Style::new().system_function().bold()
|
||||||
@@ -106,7 +108,7 @@ impl<'a> InputBox<'a> {
|
|||||||
|
|
||||||
let input_box_paragraph = Paragraph::new(Text::from(self.content))
|
let input_box_paragraph = Paragraph::new(Text::from(self.content))
|
||||||
.style(style)
|
.style(style)
|
||||||
.block(self.block);
|
.block(self.block.clone());
|
||||||
|
|
||||||
if let Some(label) = self.label {
|
if let Some(label) = self.label {
|
||||||
let [label_area, text_box_area] =
|
let [label_area, text_box_area] =
|
||||||
@@ -133,6 +135,12 @@ impl<'a> Widget for InputBox<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> WidgetRef for InputBox<'a> {
|
||||||
|
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
||||||
|
self.render_input_box(area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Styled for InputBox<'a> {
|
impl<'a> Styled for InputBox<'a> {
|
||||||
type Item = InputBox<'a>;
|
type Item = InputBox<'a>;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
use crate::ui::styles::ManagarrStyle;
|
||||||
|
use crate::ui::utils::{background_block, borderless_block, centered_rect};
|
||||||
|
use ratatui::buffer::Buffer;
|
||||||
|
use ratatui::layout::{Constraint, Layout, Rect};
|
||||||
|
use ratatui::widgets::{Block, Clear, Paragraph, Widget, WidgetRef};
|
||||||
|
|
||||||
|
use super::input_box::InputBox;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "input_box_popup_tests.rs"]
|
||||||
|
mod input_box_popup_tests;
|
||||||
|
|
||||||
|
pub struct InputBoxPopup<'a> {
|
||||||
|
input_box: InputBox<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> InputBoxPopup<'a> {
|
||||||
|
pub fn new(content: &'a str) -> Self {
|
||||||
|
Self {
|
||||||
|
input_box: InputBox::new(content),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block(mut self, block: Block<'a>) -> InputBoxPopup<'a> {
|
||||||
|
self.input_box = self.input_box.block(block);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(mut self, offset: usize) -> InputBoxPopup<'a> {
|
||||||
|
self.input_box = self.input_box.offset(offset);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_popup(&self, area: Rect, buf: &mut Buffer) {
|
||||||
|
let popup_area = Rect {
|
||||||
|
height: 6,
|
||||||
|
..centered_rect(30, 20, area)
|
||||||
|
};
|
||||||
|
Clear.render(popup_area, buf);
|
||||||
|
background_block().render(popup_area, buf);
|
||||||
|
|
||||||
|
let [text_box_area, help_area] =
|
||||||
|
Layout::vertical([Constraint::Length(3), Constraint::Length(1)])
|
||||||
|
.margin(1)
|
||||||
|
.areas(popup_area);
|
||||||
|
self.input_box.render_ref(text_box_area, buf);
|
||||||
|
|
||||||
|
let help = Paragraph::new("<esc> cancel")
|
||||||
|
.help()
|
||||||
|
.centered()
|
||||||
|
.block(borderless_block());
|
||||||
|
help.render(help_area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> WidgetRef for InputBoxPopup<'a> {
|
||||||
|
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
||||||
|
self.render_popup(area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::ui::utils::layout_block;
|
||||||
|
use crate::ui::widgets::input_box::InputBox;
|
||||||
|
use crate::ui::widgets::input_box_popup::InputBoxPopup;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_box_popup_new() {
|
||||||
|
let expected_input_box = InputBox::new("test");
|
||||||
|
|
||||||
|
let input_box_popup = InputBoxPopup::new("test");
|
||||||
|
|
||||||
|
assert_eq!(input_box_popup.input_box, expected_input_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_box_popup_block() {
|
||||||
|
let expected_input_box = InputBox::new("test").block(layout_block().title("title"));
|
||||||
|
|
||||||
|
let input_box_popup = InputBoxPopup::new("test").block(layout_block().title("title"));
|
||||||
|
|
||||||
|
assert_eq!(input_box_popup.input_box, expected_input_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_input_box_popup_offset() {
|
||||||
|
let expected_input_box = InputBox::new("test").offset(5);
|
||||||
|
|
||||||
|
let input_box_popup = InputBoxPopup::new("test").offset(5);
|
||||||
|
|
||||||
|
assert_eq!(input_box_popup.input_box, expected_input_box);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,21 @@
|
|||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::ui::styles::ManagarrStyle;
|
use crate::ui::styles::ManagarrStyle;
|
||||||
use crate::ui::utils::layout_block_top_border;
|
use crate::ui::utils::{centered_rect, layout_block_top_border, title_block_centered};
|
||||||
use crate::ui::widgets::loading_block::LoadingBlock;
|
use crate::ui::widgets::loading_block::LoadingBlock;
|
||||||
use crate::ui::widgets::popup::Popup;
|
use crate::ui::widgets::popup::Popup;
|
||||||
use crate::ui::widgets::selectable_list::SelectableList;
|
use crate::ui::widgets::selectable_list::SelectableList;
|
||||||
use crate::ui::HIGHLIGHT_SYMBOL;
|
use crate::ui::HIGHLIGHT_SYMBOL;
|
||||||
use ratatui::buffer::Buffer;
|
use ratatui::buffer::Buffer;
|
||||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
use ratatui::layout::{Alignment, Constraint, Layout, Position, Rect};
|
||||||
use ratatui::prelude::{Style, Stylize, Text};
|
use ratatui::prelude::{Style, Stylize, Text};
|
||||||
use ratatui::widgets::{Block, ListItem, Paragraph, Row, StatefulWidget, Table, Widget};
|
use ratatui::widgets::{Block, ListItem, Paragraph, Row, StatefulWidget, Table, Widget, WidgetRef};
|
||||||
|
use ratatui::Frame;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
|
use super::input_box_popup::InputBoxPopup;
|
||||||
|
use super::message::Message;
|
||||||
|
use super::popup::Size;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "managarr_table_tests.rs"]
|
#[path = "managarr_table_tests.rs"]
|
||||||
@@ -31,6 +37,14 @@ where
|
|||||||
is_loading: bool,
|
is_loading: bool,
|
||||||
highlight_rows: bool,
|
highlight_rows: bool,
|
||||||
is_sorting: bool,
|
is_sorting: bool,
|
||||||
|
is_searching: bool,
|
||||||
|
search_produced_empty_results: bool,
|
||||||
|
is_filtering: bool,
|
||||||
|
filter_produced_empty_results: bool,
|
||||||
|
search_box_content_length: usize,
|
||||||
|
search_box_offset: usize,
|
||||||
|
filter_box_content_length: usize,
|
||||||
|
filter_box_offset: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, F> ManagarrTable<'a, T, F>
|
impl<'a, T, F> ManagarrTable<'a, T, F>
|
||||||
@@ -39,8 +53,8 @@ where
|
|||||||
T: Clone + PartialEq + Eq + Debug,
|
T: Clone + PartialEq + Eq + Debug,
|
||||||
{
|
{
|
||||||
pub fn new(content: Option<&'a mut StatefulTable<T>>, row_mapper: F) -> Self {
|
pub fn new(content: Option<&'a mut StatefulTable<T>>, row_mapper: F) -> Self {
|
||||||
Self {
|
let mut managarr_table = Self {
|
||||||
content,
|
content: None,
|
||||||
table_headers: Vec::new(),
|
table_headers: Vec::new(),
|
||||||
constraints: Vec::new(),
|
constraints: Vec::new(),
|
||||||
row_mapper,
|
row_mapper,
|
||||||
@@ -51,7 +65,28 @@ where
|
|||||||
is_loading: false,
|
is_loading: false,
|
||||||
highlight_rows: true,
|
highlight_rows: true,
|
||||||
is_sorting: false,
|
is_sorting: false,
|
||||||
|
is_searching: false,
|
||||||
|
search_produced_empty_results: false,
|
||||||
|
is_filtering: false,
|
||||||
|
filter_produced_empty_results: false,
|
||||||
|
search_box_content_length: 0,
|
||||||
|
search_box_offset: 0,
|
||||||
|
filter_box_content_length: 0,
|
||||||
|
filter_box_offset: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(content) = content.as_ref() {
|
||||||
|
if let Some(search) = content.search.as_ref() {
|
||||||
|
managarr_table.search_box_content_length = search.text.len();
|
||||||
|
managarr_table.search_box_offset = search.offset.load(Ordering::SeqCst);
|
||||||
|
} else if let Some(filter) = content.filter.as_ref() {
|
||||||
|
managarr_table.filter_box_content_length = filter.text.len();
|
||||||
|
managarr_table.filter_box_offset = filter.offset.load(Ordering::SeqCst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
managarr_table.content = content;
|
||||||
|
managarr_table
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn headers<I>(mut self, headers: I) -> Self
|
pub fn headers<I>(mut self, headers: I) -> Self
|
||||||
@@ -107,6 +142,26 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn searching(mut self, is_searching: bool) -> Self {
|
||||||
|
self.is_searching = is_searching;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search_produced_empty_results(mut self, no_search_results: bool) -> Self {
|
||||||
|
self.search_produced_empty_results = no_search_results;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filtering(mut self, is_filtering: bool) -> Self {
|
||||||
|
self.is_filtering = is_filtering;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_produced_empty_results(mut self, no_filter_results: bool) -> Self {
|
||||||
|
self.filter_produced_empty_results = no_filter_results;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
fn render_table(self, area: Rect, buf: &mut Buffer) {
|
fn render_table(self, area: Rect, buf: &mut Buffer) {
|
||||||
let table_headers = self.parse_headers();
|
let table_headers = self.parse_headers();
|
||||||
let table_area = if let Some(ref footer) = self.footer {
|
let table_area = if let Some(ref footer) = self.footer {
|
||||||
@@ -160,6 +215,34 @@ where
|
|||||||
.dimensions(20, 50)
|
.dimensions(20, 50)
|
||||||
.render(table_area, buf);
|
.render(table_area, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.is_searching {
|
||||||
|
let box_content = &content.search.as_ref().unwrap();
|
||||||
|
InputBoxPopup::new(&box_content.text)
|
||||||
|
.offset(box_content.offset.load(Ordering::SeqCst))
|
||||||
|
.block(title_block_centered("Search"))
|
||||||
|
.render_ref(table_area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_filtering {
|
||||||
|
let box_content = &content.filter.as_ref().unwrap();
|
||||||
|
InputBoxPopup::new(&box_content.text)
|
||||||
|
.offset(box_content.offset.load(Ordering::SeqCst))
|
||||||
|
.block(title_block_centered("Filter"))
|
||||||
|
.render_ref(table_area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.search_produced_empty_results {
|
||||||
|
Popup::new(Message::new("No items found matching search"))
|
||||||
|
.size(Size::Message)
|
||||||
|
.render(table_area, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.filter_produced_empty_results {
|
||||||
|
Popup::new(Message::new("The given filter produced empty results"))
|
||||||
|
.size(Size::Message)
|
||||||
|
.render(table_area, buf);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
loading_block.render(table_area, buf);
|
loading_block.render(table_area, buf);
|
||||||
}
|
}
|
||||||
@@ -189,6 +272,36 @@ where
|
|||||||
.map(Text::from)
|
.map(Text::from)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn show_cursor(&self, f: &mut Frame<'_>, area: Rect) {
|
||||||
|
let mut draw_cursor = |length: usize, offset: usize| {
|
||||||
|
let table_area = if self.footer.is_some() {
|
||||||
|
let [content_area, _] = Layout::vertical([Constraint::Fill(0), Constraint::Length(2)])
|
||||||
|
.margin(self.margin)
|
||||||
|
.areas(area);
|
||||||
|
content_area
|
||||||
|
} else {
|
||||||
|
area
|
||||||
|
};
|
||||||
|
let popup_area = Rect {
|
||||||
|
height: 7,
|
||||||
|
..centered_rect(30, 20, table_area)
|
||||||
|
};
|
||||||
|
let [text_box_area, _] = Layout::vertical([Constraint::Length(3), Constraint::Length(1)])
|
||||||
|
.margin(1)
|
||||||
|
.areas(popup_area);
|
||||||
|
f.set_cursor_position(Position {
|
||||||
|
x: text_box_area.x + (length - offset) as u16 + 1,
|
||||||
|
y: text_box_area.y + 1,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if self.is_searching {
|
||||||
|
draw_cursor(self.search_box_content_length, self.search_box_offset);
|
||||||
|
} else if self.is_filtering {
|
||||||
|
draw_cursor(self.filter_box_content_length, self.filter_box_offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, F> Widget for ManagarrTable<'a, T, F>
|
impl<'a, T, F> Widget for ManagarrTable<'a, T, F>
|
||||||
|
|||||||
@@ -2,13 +2,14 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::models::stateful_list::StatefulList;
|
use crate::models::stateful_list::StatefulList;
|
||||||
use crate::models::stateful_table::{SortOption, StatefulTable};
|
use crate::models::stateful_table::{SortOption, StatefulTable};
|
||||||
use crate::models::Scrollable;
|
use crate::models::{HorizontallyScrollableText, Scrollable};
|
||||||
use crate::ui::utils::layout_block;
|
use crate::ui::utils::layout_block;
|
||||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use ratatui::layout::{Alignment, Constraint};
|
use ratatui::layout::{Alignment, Constraint};
|
||||||
use ratatui::text::Text;
|
use ratatui::text::Text;
|
||||||
use ratatui::widgets::{Block, Cell, Row};
|
use ratatui::widgets::{Block, Cell, Row};
|
||||||
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_managarr_table_new() {
|
fn test_managarr_table_new() {
|
||||||
@@ -31,6 +32,86 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_new_search_box_populated() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
let horizontally_scrollable_test = HorizontallyScrollableText {
|
||||||
|
text: "test".to_owned(),
|
||||||
|
offset: AtomicUsize::new(3),
|
||||||
|
};
|
||||||
|
stateful_table.search = Some(horizontally_scrollable_test);
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]));
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 4);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 3);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_new_filter_box_populated() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
let horizontally_scrollable_test = HorizontallyScrollableText {
|
||||||
|
text: "test".to_owned(),
|
||||||
|
offset: AtomicUsize::new(3),
|
||||||
|
};
|
||||||
|
stateful_table.filter = Some(horizontally_scrollable_test);
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]));
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 4);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -56,6 +137,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -81,6 +170,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -106,6 +203,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -130,6 +235,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -154,6 +267,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -177,6 +298,14 @@ mod tests {
|
|||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -201,6 +330,14 @@ mod tests {
|
|||||||
assert_eq!(managarr_table.margin, 0);
|
assert_eq!(managarr_table.margin, 0);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -225,6 +362,14 @@ mod tests {
|
|||||||
assert_eq!(managarr_table.margin, 0);
|
assert_eq!(managarr_table.margin, 0);
|
||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(!managarr_table.is_sorting);
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -249,6 +394,142 @@ mod tests {
|
|||||||
assert_eq!(managarr_table.margin, 0);
|
assert_eq!(managarr_table.margin, 0);
|
||||||
assert!(!managarr_table.is_loading);
|
assert!(!managarr_table.is_loading);
|
||||||
assert!(managarr_table.highlight_rows);
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_is_searching() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]))
|
||||||
|
.searching(true);
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert!(managarr_table.is_searching);
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_search_produced_empty_results() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]))
|
||||||
|
.search_produced_empty_results(true);
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert!(managarr_table.search_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_is_filtering() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]))
|
||||||
|
.filtering(true);
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert!(managarr_table.is_filtering);
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_managarr_table_filter_produced_empty_results() {
|
||||||
|
let items = vec!["item1", "item2", "item3"];
|
||||||
|
let mut stateful_table = StatefulTable::default();
|
||||||
|
stateful_table.set_items(items.clone());
|
||||||
|
|
||||||
|
let managarr_table =
|
||||||
|
ManagarrTable::new(Some(&mut stateful_table), |&s| Row::new(vec![Cell::new(s)]))
|
||||||
|
.filter_produced_empty_results(true);
|
||||||
|
|
||||||
|
let row_mapper = managarr_table.row_mapper;
|
||||||
|
assert!(managarr_table.filter_produced_empty_results);
|
||||||
|
assert_eq!(managarr_table.content.unwrap().items, items);
|
||||||
|
assert_eq!(row_mapper(&"item1"), Row::new(vec![Cell::new("item1")]));
|
||||||
|
assert_eq!(managarr_table.table_headers, Vec::<String>::new());
|
||||||
|
assert_eq!(managarr_table.constraints, Vec::new());
|
||||||
|
assert_eq!(managarr_table.footer, None);
|
||||||
|
assert_eq!(managarr_table.footer_alignment, Alignment::Left);
|
||||||
|
assert_eq!(managarr_table.block, Block::new());
|
||||||
|
assert_eq!(managarr_table.margin, 0);
|
||||||
|
assert!(!managarr_table.is_loading);
|
||||||
|
assert!(managarr_table.highlight_rows);
|
||||||
|
assert!(!managarr_table.is_sorting);
|
||||||
|
assert!(!managarr_table.is_searching);
|
||||||
|
assert!(!managarr_table.search_produced_empty_results);
|
||||||
|
assert!(!managarr_table.is_filtering);
|
||||||
|
assert_eq!(managarr_table.search_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.search_box_offset, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_content_length, 0);
|
||||||
|
assert_eq!(managarr_table.filter_box_offset, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -7,3 +7,4 @@ pub(super) mod managarr_table;
|
|||||||
pub(super) mod message;
|
pub(super) mod message;
|
||||||
pub(super) mod popup;
|
pub(super) mod popup;
|
||||||
pub(super) mod selectable_list;
|
pub(super) mod selectable_list;
|
||||||
|
mod input_box_popup;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ pub enum Size {
|
|||||||
Small,
|
Small,
|
||||||
Medium,
|
Medium,
|
||||||
Large,
|
Large,
|
||||||
|
XXLarge,
|
||||||
Long,
|
Long,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ impl Size {
|
|||||||
Size::Small => (40, 40),
|
Size::Small => (40, 40),
|
||||||
Size::Medium => (60, 60),
|
Size::Medium => (60, 60),
|
||||||
Size::Large => (75, 75),
|
Size::Large => (75, 75),
|
||||||
|
Size::XXLarge => (90, 90),
|
||||||
Size::Long => (65, 75),
|
Size::Long => (65, 75),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,6 +120,6 @@ impl<'a, T: Widget> Popup<'a, T> {
|
|||||||
|
|
||||||
impl<'a, T: Widget> Widget for Popup<'a, T> {
|
impl<'a, T: Widget> Widget for Popup<'a, T> {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
self.render_popup(area, buf);
|
self.render_popup(area, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ mod tests {
|
|||||||
assert_eq!(Size::Small.to_percent(), (40, 40));
|
assert_eq!(Size::Small.to_percent(), (40, 40));
|
||||||
assert_eq!(Size::Medium.to_percent(), (60, 60));
|
assert_eq!(Size::Medium.to_percent(), (60, 60));
|
||||||
assert_eq!(Size::Large.to_percent(), (75, 75));
|
assert_eq!(Size::Large.to_percent(), (75, 75));
|
||||||
|
assert_eq!(Size::XXLarge.to_percent(), (90, 90));
|
||||||
assert_eq!(Size::Long.to_percent(), (65, 75));
|
assert_eq!(Size::Long.to_percent(), (65, 75));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user