diff --git a/src/app/sonarr/sonarr_context_clues.rs b/src/app/sonarr/sonarr_context_clues.rs index ecd89ea..2a7ceab 100644 --- a/src/app/sonarr/sonarr_context_clues.rs +++ b/src/app/sonarr/sonarr_context_clues.rs @@ -31,3 +31,58 @@ pub static HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [ ), (DEFAULT_KEYBINDINGS.esc, "cancel filter"), ]; + +pub static SERIES_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc), + (DEFAULT_KEYBINDINGS.submit, "details"), + (DEFAULT_KEYBINDINGS.search, "auto search"), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; + +pub static SEASON_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.submit, "details"), + (DEFAULT_KEYBINDINGS.search, "auto search"), + (DEFAULT_KEYBINDINGS.delete, "delete episode"), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; + +pub static MANUAL_SEASON_SEARCH_CONTEXT_CLUES: [ContextClue; 5] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.search, "auto search"), + (DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc), + (DEFAULT_KEYBINDINGS.submit, "details"), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; + +pub static MANUAL_EPISODE_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.search, "auto search"), + (DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; + +pub static MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 1] = + [(DEFAULT_KEYBINDINGS.submit, "details")]; + +pub static EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.search, "auto search"), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; diff --git a/src/app/sonarr/sonarr_context_clues_tests.rs b/src/app/sonarr/sonarr_context_clues_tests.rs index 30de8b0..6f93de0 100644 --- a/src/app/sonarr/sonarr_context_clues_tests.rs +++ b/src/app/sonarr/sonarr_context_clues_tests.rs @@ -4,7 +4,12 @@ mod tests { use crate::app::{ key_binding::DEFAULT_KEYBINDINGS, - sonarr::sonarr_context_clues::{HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES}, + sonarr::sonarr_context_clues::{ + EPISODE_DETAILS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, + MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, MANUAL_EPISODE_SEARCH_CONTEXT_CLUES, + MANUAL_SEASON_SEARCH_CONTEXT_CLUES, SEASON_DETAILS_CONTEXT_CLUES, SERIES_CONTEXT_CLUES, + SERIES_DETAILS_CONTEXT_CLUES, + }, }; #[test] @@ -98,4 +103,155 @@ mod tests { assert_str_eq!(*description, "cancel filter"); assert_eq!(history_context_clues_iter.next(), None); } + + #[test] + fn test_series_details_context_clues() { + let mut series_details_context_clues_iter = SERIES_DETAILS_CONTEXT_CLUES.iter(); + + let (key_binding, description) = series_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc); + + let (key_binding, description) = series_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.update.desc); + + let (key_binding, description) = series_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit); + assert_str_eq!(*description, "details"); + + let (key_binding, description) = series_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search); + assert_str_eq!(*description, "auto search"); + + let (key_binding, description) = series_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); + assert_eq!(series_details_context_clues_iter.next(), None); + } + + #[test] + fn test_season_details_context_clues() { + let mut season_details_context_clues_iter = SEASON_DETAILS_CONTEXT_CLUES.iter(); + + let (key_binding, description) = season_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc); + + let (key_binding, description) = season_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit); + assert_str_eq!(*description, "details"); + + let (key_binding, description) = season_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search); + assert_str_eq!(*description, "auto search"); + + let (key_binding, description) = season_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete); + assert_str_eq!(*description, "delete episode"); + + let (key_binding, description) = season_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); + assert_eq!(season_details_context_clues_iter.next(), None); + } + + #[test] + fn test_manual_season_search_context_clues() { + let mut manual_season_search_context_clues_iter = MANUAL_SEASON_SEARCH_CONTEXT_CLUES.iter(); + + let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc); + + let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search); + assert_str_eq!(*description, "auto search"); + + let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc); + + let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit); + assert_str_eq!(*description, "details"); + + let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); + assert_eq!(manual_season_search_context_clues_iter.next(), None); + } + + #[test] + fn test_manual_episode_search_context_clues() { + let mut manual_episode_search_context_clues_iter = MANUAL_EPISODE_SEARCH_CONTEXT_CLUES.iter(); + + let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc); + + let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search); + assert_str_eq!(*description, "auto search"); + + let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc); + + let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); + assert_eq!(manual_episode_search_context_clues_iter.next(), None); + } + + #[test] + fn test_manual_episode_search_contextual_context_clues() { + let mut manual_search_contextual_context_clues_iter = + MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES.iter(); + let (key_binding, description) = manual_search_contextual_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit); + assert_str_eq!(*description, "details"); + assert_eq!(manual_search_contextual_context_clues_iter.next(), None); + } + + #[test] + fn test_episode_details_context_clues() { + let mut episode_details_context_clues_iter = EPISODE_DETAILS_CONTEXT_CLUES.iter(); + + let (key_binding, description) = episode_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc); + + let (key_binding, description) = episode_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search); + assert_str_eq!(*description, "auto search"); + + let (key_binding, description) = episode_details_context_clues_iter.next().unwrap(); + + assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc); + assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc); + assert_eq!(episode_details_context_clues_iter.next(), None); + } } diff --git a/src/models/servarr_data/sonarr/modals.rs b/src/models/servarr_data/sonarr/modals.rs index 96538fa..848f199 100644 --- a/src/models/servarr_data/sonarr/modals.rs +++ b/src/models/servarr_data/sonarr/modals.rs @@ -1,15 +1,25 @@ use strum::IntoEnumIterator; -use crate::models::{ - servarr_data::modals::EditIndexerModal, - servarr_models::{Indexer, RootFolder}, - sonarr_models::{Episode, Series, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease}, - stateful_list::StatefulList, - stateful_table::StatefulTable, - HorizontallyScrollableText, ScrollableText, +use crate::{ + app::{ + context_clues::build_context_clue_string, + sonarr::sonarr_context_clues::{ + EPISODE_DETAILS_CONTEXT_CLUES, MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, + MANUAL_EPISODE_SEARCH_CONTEXT_CLUES, MANUAL_SEASON_SEARCH_CONTEXT_CLUES, + SEASON_DETAILS_CONTEXT_CLUES, + }, + }, + models::{ + servarr_data::modals::EditIndexerModal, + servarr_models::{Indexer, RootFolder}, + sonarr_models::{Episode, Series, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease}, + stateful_list::StatefulList, + stateful_table::StatefulTable, + HorizontallyScrollableText, ScrollableText, TabRoute, TabState, + }, }; -use super::sonarr_data::SonarrData; +use super::sonarr_data::{ActiveSonarrBlock, SonarrData}; #[cfg(test)] #[path = "modals_tests.rs"] @@ -246,22 +256,86 @@ impl From<&SonarrData<'_>> for EditSeriesModal { } } -#[derive(Default)] pub struct EpisodeDetailsModal { - // Temporarily allowing this, since the value is only current written and not read. - // This will be read from once I begin the UI work for Sonarr - #[allow(dead_code)] pub episode_details: ScrollableText, pub file_details: String, pub audio_details: String, pub video_details: String, pub episode_history: StatefulTable, pub episode_releases: StatefulTable, + pub episode_details_tabs: TabState, +} + +impl Default for EpisodeDetailsModal { + fn default() -> EpisodeDetailsModal { + EpisodeDetailsModal { + episode_details: ScrollableText::default(), + file_details: String::new(), + audio_details: String::new(), + video_details: String::new(), + episode_history: StatefulTable::default(), + episode_releases: StatefulTable::default(), + episode_details_tabs: TabState::new(vec![ + TabRoute { + title: "Details", + route: ActiveSonarrBlock::EpisodeDetails.into(), + help: build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES), + contextual_help: None, + }, + TabRoute { + title: "History", + route: ActiveSonarrBlock::EpisodeHistory.into(), + help: build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES), + contextual_help: None, + }, + TabRoute { + title: "File", + route: ActiveSonarrBlock::EpisodeFile.into(), + help: build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES), + contextual_help: None, + }, + TabRoute { + title: "Manual Search", + route: ActiveSonarrBlock::ManualEpisodeSearch.into(), + help: build_context_clue_string(&MANUAL_EPISODE_SEARCH_CONTEXT_CLUES), + contextual_help: Some(build_context_clue_string( + &MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, + )), + }, + ]), + } + } } -#[derive(Default)] pub struct SeasonDetailsModal { pub episodes: StatefulTable, pub episode_details_modal: Option, pub season_releases: StatefulTable, + pub season_details_tabs: TabState, +} + +impl Default for SeasonDetailsModal { + fn default() -> SeasonDetailsModal { + SeasonDetailsModal { + episodes: StatefulTable::default(), + episode_details_modal: None, + season_releases: StatefulTable::default(), + season_details_tabs: TabState::new(vec![ + TabRoute { + title: "Episodes", + route: ActiveSonarrBlock::SeasonDetails.into(), + help: String::new(), + contextual_help: Some(build_context_clue_string(&SEASON_DETAILS_CONTEXT_CLUES)), + }, + TabRoute { + title: "Manual Search", + route: ActiveSonarrBlock::ManualSeasonSearch.into(), + help: String::new(), + contextual_help: Some(build_context_clue_string( + &MANUAL_SEASON_SEARCH_CONTEXT_CLUES, + )), + }, + ]), + } + } } diff --git a/src/models/servarr_data/sonarr/modals_tests.rs b/src/models/servarr_data/sonarr/modals_tests.rs index 96af39f..cbaecd8 100644 --- a/src/models/servarr_data/sonarr/modals_tests.rs +++ b/src/models/servarr_data/sonarr/modals_tests.rs @@ -5,7 +5,16 @@ mod tests { use rstest::rstest; use strum::IntoEnumIterator; - use crate::models::servarr_data::sonarr::modals::EditSeriesModal; + use crate::app::context_clues::build_context_clue_string; + use crate::app::sonarr::sonarr_context_clues::{ + EPISODE_DETAILS_CONTEXT_CLUES, MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, + MANUAL_EPISODE_SEARCH_CONTEXT_CLUES, MANUAL_SEASON_SEARCH_CONTEXT_CLUES, + SEASON_DETAILS_CONTEXT_CLUES, + }; + use crate::models::servarr_data::sonarr::modals::{ + EditSeriesModal, EpisodeDetailsModal, SeasonDetailsModal, + }; + use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_models::{Indexer, IndexerField}; use crate::models::{ servarr_data::sonarr::{modals::AddSeriesModal, sonarr_data::SonarrData}, @@ -221,4 +230,130 @@ mod tests { assert_eq!(edit_series_modal.monitored, Some(true)); assert_eq!(edit_series_modal.use_season_folders, Some(true)); } + + #[test] + fn test_episode_details_modal_default() { + let episode_details_modal = EpisodeDetailsModal::default(); + + assert!(episode_details_modal.episode_details.is_empty()); + assert!(episode_details_modal.file_details.is_empty()); + assert!(episode_details_modal.audio_details.is_empty()); + assert!(episode_details_modal.video_details.is_empty()); + assert!(episode_details_modal.episode_history.is_empty()); + assert!(episode_details_modal.episode_releases.is_empty()); + + assert_eq!(episode_details_modal.episode_details_tabs.tabs.len(), 4); + + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[0].title, + "Details" + ); + assert_eq!( + episode_details_modal.episode_details_tabs.tabs[0].route, + ActiveSonarrBlock::EpisodeDetails.into() + ); + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[0].help, + build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES) + ); + assert!(episode_details_modal.episode_details_tabs.tabs[0] + .contextual_help + .is_none()); + + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[1].title, + "History" + ); + assert_eq!( + episode_details_modal.episode_details_tabs.tabs[1].route, + ActiveSonarrBlock::EpisodeHistory.into() + ); + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[1].help, + build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES) + ); + assert!(episode_details_modal.episode_details_tabs.tabs[1] + .contextual_help + .is_none()); + + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[2].title, + "File" + ); + assert_eq!( + episode_details_modal.episode_details_tabs.tabs[2].route, + ActiveSonarrBlock::EpisodeFile.into() + ); + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[2].help, + build_context_clue_string(&EPISODE_DETAILS_CONTEXT_CLUES) + ); + assert!(episode_details_modal.episode_details_tabs.tabs[2] + .contextual_help + .is_none()); + + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[3].title, + "Manual Search" + ); + assert_eq!( + episode_details_modal.episode_details_tabs.tabs[3].route, + ActiveSonarrBlock::ManualEpisodeSearch.into() + ); + assert_str_eq!( + episode_details_modal.episode_details_tabs.tabs[3].help, + build_context_clue_string(&MANUAL_EPISODE_SEARCH_CONTEXT_CLUES) + ); + assert_eq!( + episode_details_modal.episode_details_tabs.tabs[3].contextual_help, + Some(build_context_clue_string( + &MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES + )) + ); + } + + #[test] + fn test_season_details_modal_default() { + let season_details_modal = SeasonDetailsModal::default(); + + assert!(season_details_modal.episodes.is_empty()); + assert!(season_details_modal.episode_details_modal.is_none()); + assert!(season_details_modal.season_releases.is_empty()); + + assert_eq!(season_details_modal.season_details_tabs.tabs.len(), 2); + + assert_str_eq!( + season_details_modal.season_details_tabs.tabs[0].title, + "Episodes" + ); + assert_eq!( + season_details_modal.season_details_tabs.tabs[0].route, + ActiveSonarrBlock::SeasonDetails.into() + ); + assert!(season_details_modal.season_details_tabs.tabs[0] + .help + .is_empty()); + assert_eq!( + season_details_modal.season_details_tabs.tabs[0].contextual_help, + Some(build_context_clue_string(&SEASON_DETAILS_CONTEXT_CLUES)) + ); + + assert_str_eq!( + season_details_modal.season_details_tabs.tabs[1].title, + "Manual Search" + ); + assert_eq!( + season_details_modal.season_details_tabs.tabs[1].route, + ActiveSonarrBlock::ManualSeasonSearch.into() + ); + assert!(season_details_modal.season_details_tabs.tabs[1] + .help + .is_empty()); + assert_eq!( + season_details_modal.season_details_tabs.tabs[1].contextual_help, + Some(build_context_clue_string( + &MANUAL_SEASON_SEARCH_CONTEXT_CLUES + )) + ); + } } diff --git a/src/models/servarr_data/sonarr/sonarr_data.rs b/src/models/servarr_data/sonarr/sonarr_data.rs index 1cf7664..168a84c 100644 --- a/src/models/servarr_data/sonarr/sonarr_data.rs +++ b/src/models/servarr_data/sonarr/sonarr_data.rs @@ -8,7 +8,9 @@ use crate::{ 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}, + sonarr::sonarr_context_clues::{ + HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES, SERIES_DETAILS_CONTEXT_CLUES, + }, }, models::{ servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem}, @@ -30,6 +32,10 @@ use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal}; #[path = "sonarr_data_tests.rs"] mod sonarr_data_tests; +#[cfg(test)] +#[path = "sonarr_test_utils.rs"] +pub mod sonarr_test_utils; + pub struct SonarrData<'a> { pub add_list_exclusion: bool, pub add_searched_series: Option>, @@ -49,6 +55,7 @@ pub struct SonarrData<'a> { pub indexer_test_error: Option, pub language_profiles_map: BiMap, pub logs: StatefulList, + pub log_details: StatefulList, pub main_tabs: TabState, pub prompt_confirm: bool, pub prompt_confirm_action: Option, @@ -60,6 +67,7 @@ pub struct SonarrData<'a> { pub selected_block: BlockSelectionState<'a, ActiveSonarrBlock>, pub series: StatefulTable, pub series_history: Option>, + pub series_info_tabs: TabState, pub start_time: DateTime, pub tags_map: BiMap, pub tasks: StatefulTable, @@ -95,6 +103,7 @@ impl<'a> Default for SonarrData<'a> { indexer_test_all_results: None, language_profiles_map: BiMap::new(), logs: StatefulList::default(), + log_details: StatefulList::default(), prompt_confirm: false, prompt_confirm_action: None, quality_profile_map: BiMap::new(), @@ -154,6 +163,20 @@ impl<'a> Default for SonarrData<'a> { contextual_help: Some(build_context_clue_string(&SYSTEM_CONTEXT_CLUES)), }, ]), + series_info_tabs: TabState::new(vec![ + TabRoute { + title: "Seasons", + route: ActiveSonarrBlock::SeriesDetails.into(), + help: String::new(), + contextual_help: Some(build_context_clue_string(&SERIES_DETAILS_CONTEXT_CLUES)), + }, + TabRoute { + title: "History", + route: ActiveSonarrBlock::SeriesHistory.into(), + help: String::new(), + contextual_help: Some(build_context_clue_string(&HISTORY_CONTEXT_CLUES)), + }, + ]), } } } diff --git a/src/models/servarr_data/sonarr/sonarr_data_tests.rs b/src/models/servarr_data/sonarr/sonarr_data_tests.rs index 2d76b91..02e590a 100644 --- a/src/models/servarr_data/sonarr/sonarr_data_tests.rs +++ b/src/models/servarr_data/sonarr/sonarr_data_tests.rs @@ -10,7 +10,9 @@ mod tests { 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}, + sonarr::sonarr_context_clues::{ + HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES, SERIES_DETAILS_CONTEXT_CLUES, + }, }, models::{ servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData}, @@ -76,6 +78,7 @@ 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.log_details.is_empty()); assert!(!sonarr_data.prompt_confirm); assert!(sonarr_data.prompt_confirm_action.is_none()); assert!(sonarr_data.quality_profile_map.is_empty()); @@ -170,6 +173,30 @@ mod tests { sonarr_data.main_tabs.tabs[6].contextual_help, Some(build_context_clue_string(&SYSTEM_CONTEXT_CLUES)) ); + + assert_eq!(sonarr_data.series_info_tabs.tabs.len(), 2); + + assert_str_eq!(sonarr_data.series_info_tabs.tabs[0].title, "Seasons"); + assert_eq!( + sonarr_data.series_info_tabs.tabs[0].route, + ActiveSonarrBlock::SeriesDetails.into() + ); + assert!(sonarr_data.series_info_tabs.tabs[0].help.is_empty()); + assert_eq!( + sonarr_data.series_info_tabs.tabs[0].contextual_help, + Some(build_context_clue_string(&SERIES_DETAILS_CONTEXT_CLUES)) + ); + + assert_str_eq!(sonarr_data.series_info_tabs.tabs[1].title, "History"); + assert_eq!( + sonarr_data.series_info_tabs.tabs[1].route, + ActiveSonarrBlock::SeriesHistory.into() + ); + assert!(sonarr_data.series_info_tabs.tabs[1].help.is_empty()); + assert_eq!( + sonarr_data.series_info_tabs.tabs[1].contextual_help, + Some(build_context_clue_string(&HISTORY_CONTEXT_CLUES)) + ); } } diff --git a/src/models/servarr_data/sonarr/sonarr_test_utils.rs b/src/models/servarr_data/sonarr/sonarr_test_utils.rs new file mode 100644 index 0000000..4919c67 --- /dev/null +++ b/src/models/servarr_data/sonarr/sonarr_test_utils.rs @@ -0,0 +1,58 @@ +#[cfg(test)] +pub mod utils { + use crate::models::{ + servarr_data::sonarr::{ + modals::{EpisodeDetailsModal, SeasonDetailsModal}, + sonarr_data::SonarrData, + }, + sonarr_models::{AddSeriesSearchResult, Episode, Season, SonarrHistoryItem, SonarrRelease}, + stateful_table::StatefulTable, + HorizontallyScrollableText, ScrollableText, + }; + + pub fn create_test_sonarr_data<'a>() -> SonarrData<'a> { + let mut episode_details_modal = EpisodeDetailsModal { + episode_details: ScrollableText::with_string("test episode details".to_owned()), + ..EpisodeDetailsModal::default() + }; + episode_details_modal + .episode_history + .set_items(vec![SonarrHistoryItem::default()]); + episode_details_modal + .episode_releases + .set_items(vec![SonarrRelease::default()]); + let mut season_details_modal = SeasonDetailsModal::default(); + season_details_modal + .episodes + .set_items(vec![Episode::default()]); + season_details_modal + .season_releases + .set_items(vec![SonarrRelease::default()]); + season_details_modal.episode_details_modal = Some(episode_details_modal); + + let mut seasons = StatefulTable::default(); + seasons.set_items(vec![Season::default()]); + + let mut sonarr_data = SonarrData { + delete_series_files: true, + add_list_exclusion: true, + add_series_search: Some("test search".into()), + edit_root_folder: Some("test path".into()), + seasons, + season_details_modal: Some(season_details_modal), + add_searched_series: Some(StatefulTable::default()), + ..SonarrData::default() + }; + sonarr_data.series_info_tabs.index = 1; + sonarr_data + .add_searched_series + .as_mut() + .unwrap() + .set_items(vec![AddSeriesSearchResult::default()]); + sonarr_data + .log_details + .set_items(vec![HorizontallyScrollableText::default()]); + + sonarr_data + } +}