feat(app): Dispatch support for all relevant Sonarr blocks

This commit is contained in:
2024-11-27 17:06:20 -07:00
parent 73a4129000
commit f139db07d9
86 changed files with 4075 additions and 3005 deletions
+4 -4
View File
@@ -290,8 +290,8 @@ impl TabState {
&self.tabs[self.index]
}
pub fn get_active_route(&self) -> &Route {
&self.tabs[self.index].route
pub fn get_active_route(&self) -> Route {
self.tabs[self.index].route
}
pub fn get_active_tab_help(&self) -> &str {
@@ -332,8 +332,8 @@ where
BlockSelectionState { blocks, index: 0 }
}
pub fn get_active_block(&self) -> &T {
&self.blocks[self.index]
pub fn get_active_block(&self) -> T {
self.blocks[self.index]
}
pub fn next(&mut self) {
+14 -14
View File
@@ -517,7 +517,7 @@ mod tests {
let active_route = tab_state.get_active_route();
assert_eq!(active_route, &second_tab);
assert_eq!(active_route, second_tab);
}
#[test]
@@ -548,15 +548,15 @@ mod tests {
let tab_routes = create_test_tab_routes();
let mut tab_state = TabState::new(create_test_tab_routes());
assert_eq!(tab_state.get_active_route(), &tab_routes[0].route);
assert_eq!(tab_state.get_active_route(), tab_routes[0].route);
tab_state.next();
assert_eq!(tab_state.get_active_route(), &tab_routes[1].route);
assert_eq!(tab_state.get_active_route(), tab_routes[1].route);
tab_state.next();
assert_eq!(tab_state.get_active_route(), &tab_routes[0].route);
assert_eq!(tab_state.get_active_route(), tab_routes[0].route);
}
#[test]
@@ -564,15 +564,15 @@ mod tests {
let tab_routes = create_test_tab_routes();
let mut tab_state = TabState::new(create_test_tab_routes());
assert_eq!(tab_state.get_active_route(), &tab_routes[0].route);
assert_eq!(tab_state.get_active_route(), tab_routes[0].route);
tab_state.previous();
assert_eq!(tab_state.get_active_route(), &tab_routes[1].route);
assert_eq!(tab_state.get_active_route(), tab_routes[1].route);
tab_state.previous();
assert_eq!(tab_state.get_active_route(), &tab_routes[0].route);
assert_eq!(tab_state.get_active_route(), tab_routes[0].route);
}
#[test]
@@ -592,7 +592,7 @@ mod tests {
let active_block = block_selection_state.get_active_block();
assert_eq!(active_block, &second_block);
assert_eq!(active_block, second_block);
}
#[test]
@@ -603,15 +603,15 @@ mod tests {
];
let mut block_selection_state = BlockSelectionState::new(&blocks);
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
assert_eq!(block_selection_state.get_active_block(), blocks[0]);
block_selection_state.next();
assert_eq!(block_selection_state.get_active_block(), &blocks[1]);
assert_eq!(block_selection_state.get_active_block(), blocks[1]);
block_selection_state.next();
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
assert_eq!(block_selection_state.get_active_block(), blocks[0]);
}
#[test]
@@ -622,15 +622,15 @@ mod tests {
];
let mut block_selection_state = BlockSelectionState::new(&blocks);
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
assert_eq!(block_selection_state.get_active_block(), blocks[0]);
block_selection_state.previous();
assert_eq!(block_selection_state.get_active_block(), &blocks[1]);
assert_eq!(block_selection_state.get_active_block(), blocks[1]);
block_selection_state.previous();
assert_eq!(block_selection_state.get_active_block(), &blocks[0]);
assert_eq!(block_selection_state.get_active_block(), blocks[0]);
}
#[test]
@@ -1,9 +1,10 @@
use crate::app::context_clues::build_context_clue_string;
use crate::app::context_clues::{
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
};
use crate::app::radarr::radarr_context_clues::{
BLOCKLIST_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
SYSTEM_CONTEXT_CLUES,
COLLECTIONS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES,
};
use crate::models::radarr_models::{
AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord,
@@ -4,12 +4,14 @@ mod tests {
use chrono::{DateTime, Utc};
use pretty_assertions::{assert_eq, assert_str_eq};
use crate::app::context_clues::build_context_clue_string;
use crate::app::context_clues::{
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
};
use crate::app::radarr::radarr_context_clues::{
BLOCKLIST_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
SYSTEM_CONTEXT_CLUES,
COLLECTIONS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES,
MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES,
MOVIE_DETAILS_CONTEXT_CLUES,
};
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils;
+6 -6
View File
@@ -26,8 +26,8 @@ pub struct AddSeriesModal {
pub tags: HorizontallyScrollableText,
}
impl From<&SonarrData> for AddSeriesModal {
fn from(sonarr_data: &SonarrData) -> AddSeriesModal {
impl From<&SonarrData<'_>> for AddSeriesModal {
fn from(sonarr_data: &SonarrData<'_>) -> AddSeriesModal {
let mut add_series_modal = AddSeriesModal {
use_season_folder: true,
..AddSeriesModal::default()
@@ -64,8 +64,8 @@ impl From<&SonarrData> for AddSeriesModal {
}
}
impl From<&SonarrData> for EditIndexerModal {
fn from(sonarr_data: &SonarrData) -> EditIndexerModal {
impl From<&SonarrData<'_>> for EditIndexerModal {
fn from(sonarr_data: &SonarrData<'_>) -> EditIndexerModal {
let mut edit_indexer_modal = EditIndexerModal::default();
let Indexer {
name,
@@ -153,8 +153,8 @@ pub struct EditSeriesModal {
pub tags: HorizontallyScrollableText,
}
impl From<&SonarrData> for EditSeriesModal {
fn from(sonarr_data: &SonarrData) -> EditSeriesModal {
impl From<&SonarrData<'_>> for EditSeriesModal {
fn from(sonarr_data: &SonarrData<'_>) -> EditSeriesModal {
let mut edit_series_modal = EditSeriesModal::default();
let Series {
path,
+91 -14
View File
@@ -2,16 +2,26 @@ use bimap::BiMap;
use chrono::{DateTime, Utc};
use strum::EnumIter;
use crate::models::{
servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem},
servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder},
sonarr_models::{
AddSeriesSearchResult, BlocklistItem, DownloadRecord, IndexerSettings, Season, Series,
SonarrHistoryItem, SonarrTask,
use crate::{
app::{
context_clues::{
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
},
sonarr::sonarr_context_clues::{HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES},
},
stateful_list::StatefulList,
stateful_table::StatefulTable,
HorizontallyScrollableText, Route, ScrollableText,
models::{
servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem},
servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder},
sonarr_models::{
AddSeriesSearchResult, BlocklistItem, DownloadRecord, IndexerSettings, Season, Series,
SonarrHistoryItem, SonarrTask,
},
stateful_list::StatefulList,
stateful_table::StatefulTable,
BlockSelectionState, HorizontallyScrollableText, Route, ScrollableText, TabRoute, TabState,
},
network::sonarr_network::SonarrEvent,
};
use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal};
@@ -20,7 +30,7 @@ use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal};
#[path = "sonarr_data_tests.rs"]
mod sonarr_data_tests;
pub struct SonarrData {
pub struct SonarrData<'a> {
pub add_list_exclusion: bool,
pub add_searched_series: Option<StatefulTable<AddSeriesSearchResult>>,
pub add_series_modal: Option<AddSeriesModal>,
@@ -39,11 +49,15 @@ pub struct SonarrData {
pub indexer_test_error: Option<String>,
pub language_profiles_map: BiMap<i64, String>,
pub logs: StatefulList<HorizontallyScrollableText>,
pub main_tabs: TabState,
pub prompt_confirm: bool,
pub prompt_confirm_action: Option<SonarrEvent>,
pub quality_profile_map: BiMap<i64, String>,
pub queued_events: StatefulTable<QueueEvent>,
pub root_folders: StatefulTable<RootFolder>,
pub seasons: StatefulTable<Season>,
pub season_details_modal: Option<SeasonDetailsModal>,
pub selected_block: BlockSelectionState<'a, ActiveSonarrBlock>,
pub series: StatefulTable<Series>,
pub series_history: Option<StatefulTable<SonarrHistoryItem>>,
pub start_time: DateTime<Utc>,
@@ -53,15 +67,15 @@ pub struct SonarrData {
pub version: String,
}
impl SonarrData {
impl<'a> SonarrData<'a> {
pub fn reset_delete_series_preferences(&mut self) {
self.delete_series_files = false;
self.add_list_exclusion = false;
}
}
impl Default for SonarrData {
fn default() -> SonarrData {
impl<'a> Default for SonarrData<'a> {
fn default() -> SonarrData<'a> {
SonarrData {
add_list_exclusion: false,
add_searched_series: None,
@@ -81,11 +95,14 @@ impl Default for SonarrData {
indexer_test_all_results: None,
language_profiles_map: BiMap::new(),
logs: StatefulList::default(),
prompt_confirm: false,
prompt_confirm_action: None,
quality_profile_map: BiMap::new(),
queued_events: StatefulTable::default(),
root_folders: StatefulTable::default(),
seasons: StatefulTable::default(),
season_details_modal: None,
selected_block: BlockSelectionState::default(),
series: StatefulTable::default(),
series_history: None,
start_time: DateTime::default(),
@@ -93,6 +110,50 @@ impl Default for SonarrData {
tasks: StatefulTable::default(),
updates: ScrollableText::default(),
version: String::new(),
main_tabs: TabState::new(vec![
TabRoute {
title: "Library",
route: ActiveSonarrBlock::Series.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&SERIES_CONTEXT_CLUES)),
},
TabRoute {
title: "Downloads",
route: ActiveSonarrBlock::Downloads.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&DOWNLOADS_CONTEXT_CLUES)),
},
TabRoute {
title: "Blocklist",
route: ActiveSonarrBlock::Blocklist.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&BLOCKLIST_CONTEXT_CLUES)),
},
TabRoute {
title: "History",
route: ActiveSonarrBlock::History.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&HISTORY_CONTEXT_CLUES)),
},
TabRoute {
title: "Root Folders",
route: ActiveSonarrBlock::RootFolders.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&ROOT_FOLDERS_CONTEXT_CLUES)),
},
TabRoute {
title: "Indexers",
route: ActiveSonarrBlock::Indexers.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&INDEXERS_CONTEXT_CLUES)),
},
TabRoute {
title: "System",
route: ActiveSonarrBlock::System.into(),
help: String::new(),
contextual_help: Some(build_context_clue_string(&SYSTEM_CONTEXT_CLUES)),
},
]),
}
}
}
@@ -182,7 +243,6 @@ pub enum ActiveSonarrBlock {
SearchSeriesHistory,
SearchSeriesHistoryError,
SeasonDetails,
SeasonHistory,
#[default]
Series,
SeriesDetails,
@@ -199,8 +259,25 @@ pub enum ActiveSonarrBlock {
TestIndexer,
UpdateAllSeriesPrompt,
UpdateAndScanSeriesPrompt,
UpdateDownloadsPrompt,
}
pub static SERIES_BLOCKS: [ActiveSonarrBlock; 7] = [
ActiveSonarrBlock::Series,
ActiveSonarrBlock::SeriesSortPrompt,
ActiveSonarrBlock::SearchSeries,
ActiveSonarrBlock::SearchSeriesError,
ActiveSonarrBlock::FilterSeries,
ActiveSonarrBlock::FilterSeriesError,
ActiveSonarrBlock::UpdateAllSeriesPrompt,
];
pub static DOWNLOADS_BLOCKS: [ActiveSonarrBlock; 3] = [
ActiveSonarrBlock::Downloads,
ActiveSonarrBlock::DeleteDownloadPrompt,
ActiveSonarrBlock::UpdateDownloadsPrompt,
];
impl From<ActiveSonarrBlock> for Route {
fn from(active_sonarr_block: ActiveSonarrBlock) -> Route {
Route::Sonarr(active_sonarr_block, None)
@@ -2,10 +2,20 @@
mod tests {
mod sonarr_data_tests {
use chrono::{DateTime, Utc};
use pretty_assertions::{assert_eq, assert_str_eq};
use crate::models::{
servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData},
Route,
use crate::{
app::{
context_clues::{
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
},
sonarr::sonarr_context_clues::{HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES},
},
models::{
servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData},
BlockSelectionState, Route,
},
};
#[test]
@@ -66,11 +76,14 @@ mod tests {
assert!(sonarr_data.indexer_test_all_results.is_none());
assert!(sonarr_data.language_profiles_map.is_empty());
assert!(sonarr_data.logs.is_empty());
assert!(!sonarr_data.prompt_confirm);
assert!(sonarr_data.prompt_confirm_action.is_none());
assert!(sonarr_data.quality_profile_map.is_empty());
assert!(sonarr_data.queued_events.is_empty());
assert!(sonarr_data.root_folders.is_empty());
assert!(sonarr_data.seasons.is_empty());
assert!(sonarr_data.season_details_modal.is_none());
assert_eq!(sonarr_data.selected_block, BlockSelectionState::default());
assert!(sonarr_data.series.is_empty());
assert!(sonarr_data.series_history.is_none());
assert_eq!(sonarr_data.start_time, <DateTime<Utc>>::default());
@@ -78,6 +91,111 @@ mod tests {
assert!(sonarr_data.tasks.is_empty());
assert!(sonarr_data.updates.is_empty());
assert!(sonarr_data.version.is_empty());
assert_eq!(sonarr_data.main_tabs.tabs.len(), 7);
assert_str_eq!(sonarr_data.main_tabs.tabs[0].title, "Library");
assert_eq!(
sonarr_data.main_tabs.tabs[0].route,
ActiveSonarrBlock::Series.into()
);
assert!(sonarr_data.main_tabs.tabs[0].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[0].contextual_help,
Some(build_context_clue_string(&SERIES_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[1].title, "Downloads");
assert_eq!(
sonarr_data.main_tabs.tabs[1].route,
ActiveSonarrBlock::Downloads.into()
);
assert!(sonarr_data.main_tabs.tabs[1].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[1].contextual_help,
Some(build_context_clue_string(&DOWNLOADS_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[2].title, "Blocklist");
assert_eq!(
sonarr_data.main_tabs.tabs[2].route,
ActiveSonarrBlock::Blocklist.into()
);
assert!(sonarr_data.main_tabs.tabs[2].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[2].contextual_help,
Some(build_context_clue_string(&BLOCKLIST_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[3].title, "History");
assert_eq!(
sonarr_data.main_tabs.tabs[3].route,
ActiveSonarrBlock::History.into()
);
assert!(sonarr_data.main_tabs.tabs[3].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[3].contextual_help,
Some(build_context_clue_string(&HISTORY_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[4].title, "Root Folders");
assert_eq!(
sonarr_data.main_tabs.tabs[4].route,
ActiveSonarrBlock::RootFolders.into()
);
assert!(sonarr_data.main_tabs.tabs[4].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[4].contextual_help,
Some(build_context_clue_string(&ROOT_FOLDERS_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[5].title, "Indexers");
assert_eq!(
sonarr_data.main_tabs.tabs[5].route,
ActiveSonarrBlock::Indexers.into()
);
assert!(sonarr_data.main_tabs.tabs[5].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[5].contextual_help,
Some(build_context_clue_string(&INDEXERS_CONTEXT_CLUES))
);
assert_str_eq!(sonarr_data.main_tabs.tabs[6].title, "System");
assert_eq!(
sonarr_data.main_tabs.tabs[6].route,
ActiveSonarrBlock::System.into()
);
assert!(sonarr_data.main_tabs.tabs[6].help.is_empty());
assert_eq!(
sonarr_data.main_tabs.tabs[6].contextual_help,
Some(build_context_clue_string(&SYSTEM_CONTEXT_CLUES))
);
}
}
mod active_sonarr_block_tests {
use crate::models::servarr_data::sonarr::sonarr_data::{
ActiveSonarrBlock, DOWNLOADS_BLOCKS, SERIES_BLOCKS,
};
#[test]
fn test_series_blocks_contents() {
assert_eq!(SERIES_BLOCKS.len(), 7);
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::Series));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::SeriesSortPrompt));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::SearchSeries));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::SearchSeriesError));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::FilterSeries));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::FilterSeriesError));
assert!(SERIES_BLOCKS.contains(&ActiveSonarrBlock::UpdateAllSeriesPrompt));
}
#[test]
fn test_downloads_blocks_contents() {
assert_eq!(DOWNLOADS_BLOCKS.len(), 3);
assert!(DOWNLOADS_BLOCKS.contains(&ActiveSonarrBlock::Downloads));
assert!(DOWNLOADS_BLOCKS.contains(&ActiveSonarrBlock::DeleteDownloadPrompt));
assert!(DOWNLOADS_BLOCKS.contains(&ActiveSonarrBlock::UpdateDownloadsPrompt));
}
}
}