feat(models): Added the necessary contextual help and tabs for the Sonarr UI
This commit is contained in:
@@ -31,3 +31,58 @@ pub static HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [
|
|||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
(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),
|
||||||
|
];
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ mod tests {
|
|||||||
|
|
||||||
use crate::app::{
|
use crate::app::{
|
||||||
key_binding::DEFAULT_KEYBINDINGS,
|
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]
|
#[test]
|
||||||
@@ -98,4 +103,155 @@ mod tests {
|
|||||||
assert_str_eq!(*description, "cancel filter");
|
assert_str_eq!(*description, "cancel filter");
|
||||||
assert_eq!(history_context_clues_iter.next(), None);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,25 @@
|
|||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::models::{
|
use crate::{
|
||||||
servarr_data::modals::EditIndexerModal,
|
app::{
|
||||||
servarr_models::{Indexer, RootFolder},
|
context_clues::build_context_clue_string,
|
||||||
sonarr_models::{Episode, Series, SeriesMonitor, SeriesType, SonarrHistoryItem, SonarrRelease},
|
sonarr::sonarr_context_clues::{
|
||||||
stateful_list::StatefulList,
|
EPISODE_DETAILS_CONTEXT_CLUES, MANUAL_EPISODE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
|
||||||
stateful_table::StatefulTable,
|
MANUAL_EPISODE_SEARCH_CONTEXT_CLUES, MANUAL_SEASON_SEARCH_CONTEXT_CLUES,
|
||||||
HorizontallyScrollableText, ScrollableText,
|
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)]
|
#[cfg(test)]
|
||||||
#[path = "modals_tests.rs"]
|
#[path = "modals_tests.rs"]
|
||||||
@@ -246,22 +256,86 @@ impl From<&SonarrData<'_>> for EditSeriesModal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct EpisodeDetailsModal {
|
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 episode_details: ScrollableText,
|
||||||
pub file_details: String,
|
pub file_details: String,
|
||||||
pub audio_details: String,
|
pub audio_details: String,
|
||||||
pub video_details: String,
|
pub video_details: String,
|
||||||
pub episode_history: StatefulTable<SonarrHistoryItem>,
|
pub episode_history: StatefulTable<SonarrHistoryItem>,
|
||||||
pub episode_releases: StatefulTable<SonarrRelease>,
|
pub episode_releases: StatefulTable<SonarrRelease>,
|
||||||
|
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 struct SeasonDetailsModal {
|
||||||
pub episodes: StatefulTable<Episode>,
|
pub episodes: StatefulTable<Episode>,
|
||||||
pub episode_details_modal: Option<EpisodeDetailsModal>,
|
pub episode_details_modal: Option<EpisodeDetailsModal>,
|
||||||
pub season_releases: StatefulTable<SonarrRelease>,
|
pub season_releases: StatefulTable<SonarrRelease>,
|
||||||
|
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,
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,16 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
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_models::{Indexer, IndexerField};
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
servarr_data::sonarr::{modals::AddSeriesModal, sonarr_data::SonarrData},
|
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.monitored, Some(true));
|
||||||
assert_eq!(edit_series_modal.use_season_folders, 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
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ use crate::{
|
|||||||
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
|
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
|
||||||
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_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::{
|
models::{
|
||||||
servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem},
|
servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem},
|
||||||
@@ -30,6 +32,10 @@ use super::modals::{AddSeriesModal, EditSeriesModal, SeasonDetailsModal};
|
|||||||
#[path = "sonarr_data_tests.rs"]
|
#[path = "sonarr_data_tests.rs"]
|
||||||
mod sonarr_data_tests;
|
mod sonarr_data_tests;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "sonarr_test_utils.rs"]
|
||||||
|
pub mod sonarr_test_utils;
|
||||||
|
|
||||||
pub struct SonarrData<'a> {
|
pub struct SonarrData<'a> {
|
||||||
pub add_list_exclusion: bool,
|
pub add_list_exclusion: bool,
|
||||||
pub add_searched_series: Option<StatefulTable<AddSeriesSearchResult>>,
|
pub add_searched_series: Option<StatefulTable<AddSeriesSearchResult>>,
|
||||||
@@ -49,6 +55,7 @@ pub struct SonarrData<'a> {
|
|||||||
pub indexer_test_error: Option<String>,
|
pub indexer_test_error: Option<String>,
|
||||||
pub language_profiles_map: BiMap<i64, String>,
|
pub language_profiles_map: BiMap<i64, String>,
|
||||||
pub logs: StatefulList<HorizontallyScrollableText>,
|
pub logs: StatefulList<HorizontallyScrollableText>,
|
||||||
|
pub log_details: StatefulList<HorizontallyScrollableText>,
|
||||||
pub main_tabs: TabState,
|
pub main_tabs: TabState,
|
||||||
pub prompt_confirm: bool,
|
pub prompt_confirm: bool,
|
||||||
pub prompt_confirm_action: Option<SonarrEvent>,
|
pub prompt_confirm_action: Option<SonarrEvent>,
|
||||||
@@ -60,6 +67,7 @@ pub struct SonarrData<'a> {
|
|||||||
pub selected_block: BlockSelectionState<'a, ActiveSonarrBlock>,
|
pub selected_block: BlockSelectionState<'a, ActiveSonarrBlock>,
|
||||||
pub series: StatefulTable<Series>,
|
pub series: StatefulTable<Series>,
|
||||||
pub series_history: Option<StatefulTable<SonarrHistoryItem>>,
|
pub series_history: Option<StatefulTable<SonarrHistoryItem>>,
|
||||||
|
pub series_info_tabs: TabState,
|
||||||
pub start_time: DateTime<Utc>,
|
pub start_time: DateTime<Utc>,
|
||||||
pub tags_map: BiMap<i64, String>,
|
pub tags_map: BiMap<i64, String>,
|
||||||
pub tasks: StatefulTable<SonarrTask>,
|
pub tasks: StatefulTable<SonarrTask>,
|
||||||
@@ -95,6 +103,7 @@ impl<'a> Default for SonarrData<'a> {
|
|||||||
indexer_test_all_results: None,
|
indexer_test_all_results: None,
|
||||||
language_profiles_map: BiMap::new(),
|
language_profiles_map: BiMap::new(),
|
||||||
logs: StatefulList::default(),
|
logs: StatefulList::default(),
|
||||||
|
log_details: StatefulList::default(),
|
||||||
prompt_confirm: false,
|
prompt_confirm: false,
|
||||||
prompt_confirm_action: None,
|
prompt_confirm_action: None,
|
||||||
quality_profile_map: BiMap::new(),
|
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)),
|
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)),
|
||||||
|
},
|
||||||
|
]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ mod tests {
|
|||||||
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
|
build_context_clue_string, BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
|
||||||
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_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::{
|
models::{
|
||||||
servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, SonarrData},
|
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.indexer_test_all_results.is_none());
|
||||||
assert!(sonarr_data.language_profiles_map.is_empty());
|
assert!(sonarr_data.language_profiles_map.is_empty());
|
||||||
assert!(sonarr_data.logs.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);
|
||||||
assert!(sonarr_data.prompt_confirm_action.is_none());
|
assert!(sonarr_data.prompt_confirm_action.is_none());
|
||||||
assert!(sonarr_data.quality_profile_map.is_empty());
|
assert!(sonarr_data.quality_profile_map.is_empty());
|
||||||
@@ -170,6 +173,30 @@ mod tests {
|
|||||||
sonarr_data.main_tabs.tabs[6].contextual_help,
|
sonarr_data.main_tabs.tabs[6].contextual_help,
|
||||||
Some(build_context_clue_string(&SYSTEM_CONTEXT_CLUES))
|
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))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user