feat: Implemented TUI handler support for the Album Details popup in Lidarr

This commit is contained in:
2026-01-16 17:16:44 -07:00
parent bc6ecc39f4
commit caf4ad1e64
17 changed files with 2136 additions and 79 deletions
+1 -5
View File
@@ -92,15 +92,11 @@ pub static MANUAL_ARTIST_SEARCH_CONTEXT_CLUES: [ContextClue; 7] = [
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
]; ];
pub static ALBUM_DETAILS_CONTEXT_CLUES: [ContextClue; 7] = [ pub static ALBUM_DETAILS_CONTEXT_CLUES: [ContextClue; 6] = [
( (
DEFAULT_KEYBINDINGS.refresh, DEFAULT_KEYBINDINGS.refresh,
DEFAULT_KEYBINDINGS.refresh.desc, DEFAULT_KEYBINDINGS.refresh.desc,
), ),
(
DEFAULT_KEYBINDINGS.toggle_monitoring,
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
),
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc), (DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
( (
DEFAULT_KEYBINDINGS.auto_search, DEFAULT_KEYBINDINGS.auto_search,
@@ -249,13 +249,6 @@ mod tests {
DEFAULT_KEYBINDINGS.refresh.desc DEFAULT_KEYBINDINGS.refresh.desc
) )
); );
assert_some_eq_x!(
album_details_context_clues_iter.next(),
&(
DEFAULT_KEYBINDINGS.toggle_monitoring,
DEFAULT_KEYBINDINGS.toggle_monitoring.desc
)
);
assert_some_eq_x!( assert_some_eq_x!(
album_details_context_clues_iter.next(), album_details_context_clues_iter.next(),
&(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc) &(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc)
+112
View File
@@ -9,6 +9,7 @@ mod tests {
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::artist; use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::artist;
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::models::servarr_data::lidarr::modals::AlbumDetailsModal;
#[tokio::test] #[tokio::test]
async fn test_dispatch_by_lidarr_block_artists() { async fn test_dispatch_by_lidarr_block_artists() {
@@ -156,6 +157,117 @@ mod tests {
assert_eq!(app.tick_count, 0); assert_eq!(app.tick_count, 0);
} }
#[tokio::test]
async fn test_dispatch_by_album_history_block() {
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
let mut app = App::test_default();
app.data.lidarr_data.prompt_confirm = true;
app.network_tx = Some(tx);
app.data.lidarr_data.artists.set_items(vec![Artist {
id: 1,
..Artist::default()
}]);
app.data.lidarr_data.albums.set_items(vec![Album {
id: 1,
..Album::default()
}]);
app
.dispatch_by_lidarr_block(&ActiveLidarrBlock::AlbumHistory)
.await;
assert!(app.is_loading);
assert_eq!(
rx.recv().await.unwrap(),
LidarrEvent::GetAlbumHistory(1, 1).into()
);
assert!(!app.data.lidarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0);
}
#[tokio::test]
async fn test_dispatch_by_album_history_block_no_op_when_albums_table_is_empty() {
let (tx, _) = mpsc::channel::<NetworkEvent>(500);
let mut app = App::test_default();
app.data.lidarr_data.prompt_confirm = true;
app.network_tx = Some(tx);
app.data.lidarr_data.artists.set_items(vec![Artist {
id: 1,
..Artist::default()
}]);
app
.dispatch_by_lidarr_block(&ActiveLidarrBlock::AlbumHistory)
.await;
assert!(!app.is_loading);
assert!(!app.data.lidarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0);
}
#[tokio::test]
async fn test_dispatch_by_manual_album_search_block() {
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
let mut app = App::test_default();
app.data.lidarr_data.prompt_confirm = true;
app.network_tx = Some(tx);
app.data.lidarr_data.artists.set_items(vec![Artist {
id: 1,
..Artist::default()
}]);
app.data.lidarr_data.albums.set_items(vec![Album {
id: 1,
..Album::default()
}]);
app.data.lidarr_data.album_details_modal = Some(AlbumDetailsModal::default());
app
.dispatch_by_lidarr_block(&ActiveLidarrBlock::ManualAlbumSearch)
.await;
assert!(app.is_loading);
assert_eq!(
rx.recv().await.unwrap(),
LidarrEvent::GetAlbumReleases(1, 1).into()
);
assert!(!app.data.lidarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0);
}
#[tokio::test]
async fn test_dispatch_by_manual_album_search_block_is_loading() {
let mut app = App {
is_loading: true,
..App::test_default()
};
app
.dispatch_by_lidarr_block(&ActiveLidarrBlock::ManualAlbumSearch)
.await;
assert!(app.is_loading);
assert!(!app.data.lidarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0);
}
#[tokio::test]
async fn test_dispatch_by_manual_album_search_block_album_releases_non_empty() {
let mut app = App::test_default();
let mut album_details_modal = AlbumDetailsModal::default();
album_details_modal
.album_releases
.set_items(vec![LidarrRelease::default()]);
app.data.lidarr_data.album_details_modal = Some(album_details_modal);
app
.dispatch_by_lidarr_block(&ActiveLidarrBlock::ManualAlbumSearch)
.await;
assert!(!app.is_loading);
assert!(!app.data.lidarr_data.prompt_confirm);
assert_eq!(app.tick_count, 0);
}
#[tokio::test] #[tokio::test]
async fn test_dispatch_by_downloads_block() { async fn test_dispatch_by_downloads_block() {
let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500); let (tx, mut rx) = mpsc::channel::<NetworkEvent>(500);
+23 -1
View File
@@ -2,7 +2,6 @@ use crate::{
models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock, models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock,
network::lidarr_network::LidarrEvent, network::lidarr_network::LidarrEvent,
}; };
use super::App; use super::App;
pub mod lidarr_context_clues; pub mod lidarr_context_clues;
@@ -67,6 +66,29 @@ impl App<'_> {
.dispatch_network_event(LidarrEvent::GetDownloads(500).into()) .dispatch_network_event(LidarrEvent::GetDownloads(500).into())
.await; .await;
} }
ActiveLidarrBlock::AlbumHistory => {
if !self.data.lidarr_data.albums.is_empty() {
self
.dispatch_network_event(
LidarrEvent::GetAlbumHistory(self.extract_artist_id().await, self.extract_album_id().await)
.into(),
)
.await;
}
}
ActiveLidarrBlock::ManualAlbumSearch => {
match self.data.lidarr_data.album_details_modal.as_ref() {
Some(album_details_modal) if album_details_modal.album_releases.is_empty() => {
self
.dispatch_network_event(
LidarrEvent::GetAlbumReleases(self.extract_artist_id().await, self.extract_album_id().await)
.into(),
)
.await;
}
_ => (),
}
}
ActiveLidarrBlock::AddArtistSearchResults => { ActiveLidarrBlock::AddArtistSearchResults => {
self self
.dispatch_network_event( .dispatch_network_event(
@@ -0,0 +1,476 @@
use crate::app::App;
use crate::event::Key;
use crate::handlers::lidarr_handlers::history::history_sorting_options;
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
use crate::handlers::{KeyEventHandler, handle_prompt_toggle};
use crate::matches_key;
use crate::models::Route;
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, ALBUM_DETAILS_BLOCKS};
use crate::models::lidarr_models::{
Track, LidarrHistoryItem, LidarrRelease, LidarrReleaseDownloadBody,
};
use crate::models::stateful_table::SortOption;
use crate::network::lidarr_network::LidarrEvent;
use serde_json::Number;
#[cfg(test)]
#[path = "album_details_handler_tests.rs"]
mod album_details_handler_tests;
pub(in crate::handlers::lidarr_handlers) struct AlbumDetailsHandler<'a, 'b> {
key: Key,
app: &'a mut App<'b>,
active_lidarr_block: ActiveLidarrBlock,
_context: Option<ActiveLidarrBlock>,
}
impl AlbumDetailsHandler<'_, '_> {
fn extract_track_file_id(&self) -> i64 {
self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.expect("Album details have not been loaded")
.tracks
.current_selection()
.track_file_id
}
fn extract_album_id(&self) -> i64 {
self
.app
.data
.lidarr_data
.albums
.current_selection()
.id
}
}
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for AlbumDetailsHandler<'a, 'b> {
fn handle(&mut self) {
let tracks_table_handling_config =
TableHandlingConfig::new(ActiveLidarrBlock::AlbumDetails.into())
.searching_block(ActiveLidarrBlock::SearchTracks.into())
.search_error_block(ActiveLidarrBlock::SearchTracksError.into())
.search_field_fn(|track: &Track| &track.title);
let album_history_table_handling_config =
TableHandlingConfig::new(ActiveLidarrBlock::AlbumHistory.into())
.sorting_block(ActiveLidarrBlock::AlbumHistorySortPrompt.into())
.sort_options(history_sorting_options())
.searching_block(ActiveLidarrBlock::SearchAlbumHistory.into())
.search_error_block(ActiveLidarrBlock::SearchAlbumHistoryError.into())
.search_field_fn(|history_item: &LidarrHistoryItem| &history_item.source_title.text)
.filtering_block(ActiveLidarrBlock::FilterAlbumHistory.into())
.filter_error_block(ActiveLidarrBlock::FilterAlbumHistoryError.into())
.filter_field_fn(|history_item: &LidarrHistoryItem| &history_item.source_title.text);
let album_releases_table_handling_config =
TableHandlingConfig::new(ActiveLidarrBlock::ManualAlbumSearch.into())
.sorting_block(ActiveLidarrBlock::ManualAlbumSearchSortPrompt.into())
.sort_options(releases_sorting_options());
if !handle_table(
self,
|app| {
&mut app
.data
.lidarr_data
.album_details_modal
.as_mut()
.expect("Album details modal is undefined")
.tracks
},
tracks_table_handling_config,
) && !handle_table(
self,
|app| {
&mut app
.data
.lidarr_data
.album_details_modal
.as_mut()
.expect("Album details modal is undefined")
.album_history
},
album_history_table_handling_config,
) && !handle_table(
self,
|app| {
&mut app
.data
.lidarr_data
.album_details_modal
.as_mut()
.expect("Album details modal is undefined")
.album_releases
},
album_releases_table_handling_config,
) {
self.handle_key_event();
}
}
fn accepts(active_block: ActiveLidarrBlock) -> bool {
ALBUM_DETAILS_BLOCKS.contains(&active_block)
}
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new(
key: Key,
app: &'a mut App<'b>,
active_block: ActiveLidarrBlock,
context: Option<ActiveLidarrBlock>,
) -> AlbumDetailsHandler<'a, 'b> {
AlbumDetailsHandler {
key,
app,
active_lidarr_block: active_block,
_context: context,
}
}
fn get_key(&self) -> Key {
self.key
}
fn is_ready(&self) -> bool {
if self.app.is_loading {
return false;
}
let Some(album_details_modal) = &self.app.data.lidarr_data.album_details_modal else {
return false;
};
match self.active_lidarr_block {
ActiveLidarrBlock::AlbumDetails => !album_details_modal.tracks.is_empty(),
ActiveLidarrBlock::AlbumHistory => !album_details_modal.album_history.is_empty(),
ActiveLidarrBlock::ManualAlbumSearch => !album_details_modal.album_releases.is_empty(),
_ => true,
}
}
fn handle_scroll_up(&mut self) {}
fn handle_scroll_down(&mut self) {}
fn handle_home(&mut self) {}
fn handle_end(&mut self) {}
fn handle_delete(&mut self) {
if self.active_lidarr_block == ActiveLidarrBlock::AlbumDetails {
self
.app
.push_navigation_stack(ActiveLidarrBlock::DeleteTrackFilePrompt.into());
}
}
fn handle_left_right_action(&mut self) {
match self.active_lidarr_block {
ActiveLidarrBlock::AlbumDetails
| ActiveLidarrBlock::AlbumHistory
| ActiveLidarrBlock::ManualAlbumSearch => match self.key {
_ if matches_key!(left, self.key) => {
self
.app
.data
.lidarr_data
.album_details_modal
.as_mut()
.unwrap()
.album_details_tabs
.previous();
self.app.pop_and_push_navigation_stack(
self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.unwrap()
.album_details_tabs
.get_active_route(),
);
}
_ if matches_key!(right, self.key) => {
self
.app
.data
.lidarr_data
.album_details_modal
.as_mut()
.unwrap()
.album_details_tabs
.next();
self.app.pop_and_push_navigation_stack(
self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.unwrap()
.album_details_tabs
.get_active_route(),
);
}
_ => (),
},
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt
| ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt
| ActiveLidarrBlock::DeleteTrackFilePrompt => {
handle_prompt_toggle(self.app, self.key);
}
_ => (),
}
}
fn handle_submit(&mut self) {
match self.active_lidarr_block {
// ActiveLidarrBlock::AlbumDetails
// if self.app.data.lidarr_data.album_details_modal.is_some()
// && !self
// .app
// .data
// .lidarr_data
// .album_details_modal
// .as_ref()
// .unwrap()
// .tracks
// .is_empty() =>
// {
// self
// .app
// .push_navigation_stack(ActiveLidarrBlock::TrackDetails.into())
// }
ActiveLidarrBlock::AlbumHistory => self
.app
.push_navigation_stack(ActiveLidarrBlock::AlbumHistoryDetails.into()),
ActiveLidarrBlock::DeleteTrackFilePrompt => {
if self.app.data.lidarr_data.prompt_confirm {
self.app.data.lidarr_data.prompt_confirm_action = Some(LidarrEvent::DeleteTrackFile(
self.extract_track_file_id(),
));
}
self.app.pop_navigation_stack();
}
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt => {
if self.app.data.lidarr_data.prompt_confirm {
self.app.data.lidarr_data.prompt_confirm_action = Some(
LidarrEvent::TriggerAutomaticAlbumSearch(self.extract_album_id()),
);
}
self.app.pop_navigation_stack();
}
ActiveLidarrBlock::ManualAlbumSearch => {
self
.app
.push_navigation_stack(ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt.into());
}
ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt => {
if self.app.data.lidarr_data.prompt_confirm {
let LidarrRelease {
guid, indexer_id, ..
} = self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.unwrap()
.album_releases
.current_selection();
let params = LidarrReleaseDownloadBody {
guid: guid.clone(),
indexer_id: *indexer_id,
};
self.app.data.lidarr_data.prompt_confirm_action =
Some(LidarrEvent::DownloadRelease(params));
}
self.app.pop_navigation_stack();
}
_ => (),
}
}
fn handle_esc(&mut self) {
match self.active_lidarr_block {
ActiveLidarrBlock::AlbumDetails | ActiveLidarrBlock::ManualAlbumSearch => {
self.app.pop_navigation_stack();
self.app.data.lidarr_data.album_details_modal = None;
}
ActiveLidarrBlock::AlbumHistoryDetails => {
self.app.pop_navigation_stack();
}
ActiveLidarrBlock::AlbumHistory => {
if self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.unwrap()
.album_history
.filtered_items
.is_some()
{
self
.app
.data
.lidarr_data
.album_details_modal
.as_mut()
.unwrap()
.album_history
.filtered_items = None;
} else {
self.app.pop_navigation_stack();
self.app.data.lidarr_data.album_details_modal = None;
}
}
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt
| ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt
| ActiveLidarrBlock::DeleteTrackFilePrompt => {
self.app.pop_navigation_stack();
self.app.data.lidarr_data.prompt_confirm = false;
}
_ => (),
}
}
fn handle_char_key_event(&mut self) {
let key = self.key;
match self.active_lidarr_block {
ActiveLidarrBlock::AlbumDetails
| ActiveLidarrBlock::AlbumHistory
| ActiveLidarrBlock::ManualAlbumSearch => match self.key {
_ if matches_key!(refresh, self.key) => {
self
.app
.pop_and_push_navigation_stack(self.active_lidarr_block.into());
}
_ if matches_key!(auto_search, self.key) => {
self
.app
.push_navigation_stack(ActiveLidarrBlock::AutomaticallySearchAlbumPrompt.into());
}
_ => (),
},
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt if matches_key!(confirm, key) => {
self.app.data.lidarr_data.prompt_confirm = true;
self.app.data.lidarr_data.prompt_confirm_action = Some(
LidarrEvent::TriggerAutomaticAlbumSearch(self.extract_album_id()),
);
self.app.pop_navigation_stack();
}
ActiveLidarrBlock::DeleteTrackFilePrompt if matches_key!(confirm, key) => {
self.app.data.lidarr_data.prompt_confirm = true;
self.app.data.lidarr_data.prompt_confirm_action = Some(LidarrEvent::DeleteTrackFile(
self.extract_track_file_id(),
));
self.app.pop_navigation_stack();
}
ActiveLidarrBlock::ManualAlbumSearchConfirmPrompt if matches_key!(confirm, key) => {
self.app.data.lidarr_data.prompt_confirm = true;
let LidarrRelease {
guid, indexer_id, ..
} = self
.app
.data
.lidarr_data
.album_details_modal
.as_ref()
.unwrap()
.album_releases
.current_selection();
let params = LidarrReleaseDownloadBody {
guid: guid.clone(),
indexer_id: *indexer_id,
};
self.app.data.lidarr_data.prompt_confirm_action =
Some(LidarrEvent::DownloadRelease(params));
self.app.pop_navigation_stack();
}
_ => (),
}
}
fn app_mut(&mut self) -> &mut App<'b> {
self.app
}
fn current_route(&self) -> Route {
self.app.get_current_route()
}
}
pub(in crate::handlers::lidarr_handlers::library) fn releases_sorting_options()
-> Vec<SortOption<LidarrRelease>> {
vec![
SortOption {
name: "Source",
cmp_fn: Some(|a, b| a.protocol.cmp(&b.protocol)),
},
SortOption {
name: "Age",
cmp_fn: Some(|a, b| a.age.cmp(&b.age)),
},
SortOption {
name: "Rejected",
cmp_fn: Some(|a, b| a.rejected.cmp(&b.rejected)),
},
SortOption {
name: "Title",
cmp_fn: Some(|a, b| {
a.title
.text
.to_lowercase()
.cmp(&b.title.text.to_lowercase())
}),
},
SortOption {
name: "Indexer",
cmp_fn: Some(|a, b| a.indexer.to_lowercase().cmp(&b.indexer.to_lowercase())),
},
SortOption {
name: "Size",
cmp_fn: Some(|a, b| a.size.cmp(&b.size)),
},
SortOption {
name: "Peers",
cmp_fn: Some(|a, b| {
let default_number = Number::from(i64::MAX);
let seeder_a = a
.seeders
.as_ref()
.unwrap_or(&default_number)
.as_u64()
.unwrap();
let seeder_b = b
.seeders
.as_ref()
.unwrap_or(&default_number)
.as_u64()
.unwrap();
seeder_a.cmp(&seeder_b)
}),
},
SortOption {
name: "Quality",
cmp_fn: Some(|a, b| a.quality.cmp(&b.quality)),
},
]
}
File diff suppressed because it is too large Load Diff
@@ -16,6 +16,7 @@ use crate::models::stateful_table::SortOption;
use crate::models::{BlockSelectionState, Route}; use crate::models::{BlockSelectionState, Route};
use crate::network::lidarr_network::LidarrEvent; use crate::network::lidarr_network::LidarrEvent;
use serde_json::Number; use serde_json::Number;
use crate::handlers::lidarr_handlers::library::album_details_handler::AlbumDetailsHandler;
#[cfg(test)] #[cfg(test)]
#[path = "artist_details_handler_tests.rs"] #[path = "artist_details_handler_tests.rs"]
@@ -80,13 +81,17 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
DeleteAlbumHandler::new(self.key, self.app, self.active_lidarr_block, self.context) DeleteAlbumHandler::new(self.key, self.app, self.active_lidarr_block, self.context)
.handle(); .handle();
} }
_ if AlbumDetailsHandler::accepts(self.active_lidarr_block) => {
AlbumDetailsHandler::new(self.key, self.app, self.active_lidarr_block, self.context)
.handle();
}
_ => self.handle_key_event(), _ => self.handle_key_event(),
}; };
} }
} }
fn accepts(active_block: ActiveLidarrBlock) -> bool { fn accepts(active_block: ActiveLidarrBlock) -> bool {
DeleteAlbumHandler::accepts(active_block) || ARTIST_DETAILS_BLOCKS.contains(&active_block) DeleteAlbumHandler::accepts(active_block) || AlbumDetailsHandler::accepts(active_block) || ARTIST_DETAILS_BLOCKS.contains(&active_block)
} }
fn ignore_special_keys(&self) -> bool { fn ignore_special_keys(&self) -> bool {
@@ -183,6 +188,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
fn handle_submit(&mut self) { fn handle_submit(&mut self) {
match self.active_lidarr_block { match self.active_lidarr_block {
ActiveLidarrBlock::ArtistDetails if !self.app.data.lidarr_data.albums.is_empty() => {
self
.app
.push_navigation_stack(ActiveLidarrBlock::AlbumDetails.into());
}
ActiveLidarrBlock::ArtistHistory if !self.app.data.lidarr_data.artist_history.is_empty() => { ActiveLidarrBlock::ArtistHistory if !self.app.data.lidarr_data.artist_history.is_empty() => {
self self
.app .app
@@ -14,12 +14,11 @@ mod tests {
}; };
use crate::models::HorizontallyScrollableText; use crate::models::HorizontallyScrollableText;
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease}; use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
use crate::models::servarr_data::lidarr::lidarr_data::{ use crate::models::servarr_data::lidarr::lidarr_data::{ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, ALBUM_DETAILS_BLOCKS};
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
};
use crate::models::servarr_models::{Quality, QualityWrapper}; use crate::models::servarr_models::{Quality, QualityWrapper};
use crate::test_handler_delegation;
mod test_handle_delete { mod test_handle_delete {
use super::*; use super::*;
use crate::assert_delete_prompt; use crate::assert_delete_prompt;
use crate::event::Key; use crate::event::Key;
@@ -813,6 +812,7 @@ mod tests {
fn test_artist_details_handler_accepts() { fn test_artist_details_handler_accepts() {
let mut artist_details_blocks = ARTIST_DETAILS_BLOCKS.clone().to_vec(); let mut artist_details_blocks = ARTIST_DETAILS_BLOCKS.clone().to_vec();
artist_details_blocks.extend(DELETE_ALBUM_BLOCKS); artist_details_blocks.extend(DELETE_ALBUM_BLOCKS);
artist_details_blocks.extend(ALBUM_DETAILS_BLOCKS);
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| { ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
if artist_details_blocks.contains(&active_lidarr_block) { if artist_details_blocks.contains(&active_lidarr_block) {
@@ -1000,6 +1000,33 @@ mod tests {
); );
} }
#[rstest]
fn test_delegates_album_details_blocks_to_album_details_handler(
#[values(
ActiveLidarrBlock::AlbumDetails,
ActiveLidarrBlock::AlbumHistory,
ActiveLidarrBlock::SearchTracks,
ActiveLidarrBlock::SearchTracksError,
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt,
ActiveLidarrBlock::SearchAlbumHistory,
ActiveLidarrBlock::SearchAlbumHistoryError,
ActiveLidarrBlock::FilterAlbumHistory,
ActiveLidarrBlock::FilterAlbumHistoryError,
ActiveLidarrBlock::AlbumHistorySortPrompt,
ActiveLidarrBlock::AlbumHistoryDetails,
ActiveLidarrBlock::ManualAlbumSearch,
ActiveLidarrBlock::ManualAlbumSearchSortPrompt,
ActiveLidarrBlock::DeleteTrackFilePrompt
)]
active_sonarr_block: ActiveLidarrBlock,
) {
test_handler_delegation!(
ArtistDetailsHandler,
ActiveLidarrBlock::Artists,
active_sonarr_block
);
}
#[test] #[test]
fn test_releases_sorting_options_source() { fn test_releases_sorting_options_source() {
let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering = let expected_cmp_fn: fn(&LidarrRelease, &LidarrRelease) -> Ordering =
@@ -12,15 +12,10 @@ mod tests {
use crate::handlers::KeyEventHandler; use crate::handlers::KeyEventHandler;
use crate::handlers::lidarr_handlers::library::{LibraryHandler, artists_sorting_options}; use crate::handlers::lidarr_handlers::library::{LibraryHandler, artists_sorting_options};
use crate::models::lidarr_models::{Album, Artist, ArtistStatistics, ArtistStatus}; use crate::models::lidarr_models::{Album, Artist, ArtistStatistics, ArtistStatus};
use crate::models::servarr_data::lidarr::lidarr_data::{ use crate::models::servarr_data::lidarr::lidarr_data::{ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, LIBRARY_BLOCKS, ALBUM_DETAILS_BLOCKS};
ADD_ARTIST_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, LIBRARY_BLOCKS,
};
use crate::models::servarr_data::lidarr::modals::EditArtistModal; use crate::models::servarr_data::lidarr::modals::EditArtistModal;
use crate::network::lidarr_network::LidarrEvent; use crate::network::lidarr_network::LidarrEvent;
use crate::{ use crate::{assert_modal_absent, assert_modal_present, assert_navigation_popped, assert_navigation_pushed, test_handler_delegation};
assert_modal_absent, assert_modal_present, assert_navigation_popped, assert_navigation_pushed,
};
#[test] #[test]
fn test_library_handler_accepts() { fn test_library_handler_accepts() {
@@ -31,6 +26,7 @@ mod tests {
library_handler_blocks.extend(DELETE_ALBUM_BLOCKS); library_handler_blocks.extend(DELETE_ALBUM_BLOCKS);
library_handler_blocks.extend(EDIT_ARTIST_BLOCKS); library_handler_blocks.extend(EDIT_ARTIST_BLOCKS);
library_handler_blocks.extend(ADD_ARTIST_BLOCKS); library_handler_blocks.extend(ADD_ARTIST_BLOCKS);
library_handler_blocks.extend(ALBUM_DETAILS_BLOCKS);
ActiveLidarrBlock::iter().for_each(|lidarr_block| { ActiveLidarrBlock::iter().for_each(|lidarr_block| {
if library_handler_blocks.contains(&lidarr_block) { if library_handler_blocks.contains(&lidarr_block) {
@@ -640,6 +636,33 @@ mod tests {
assert_eq!(app.get_current_route(), ActiveLidarrBlock::Artists.into()); assert_eq!(app.get_current_route(), ActiveLidarrBlock::Artists.into());
} }
#[rstest]
fn test_delegates_album_details_blocks_to_album_details_handler(
#[values(
ActiveLidarrBlock::AlbumDetails,
ActiveLidarrBlock::AlbumHistory,
ActiveLidarrBlock::SearchTracks,
ActiveLidarrBlock::SearchTracksError,
ActiveLidarrBlock::AutomaticallySearchAlbumPrompt,
ActiveLidarrBlock::SearchAlbumHistory,
ActiveLidarrBlock::SearchAlbumHistoryError,
ActiveLidarrBlock::FilterAlbumHistory,
ActiveLidarrBlock::FilterAlbumHistoryError,
ActiveLidarrBlock::AlbumHistorySortPrompt,
ActiveLidarrBlock::AlbumHistoryDetails,
ActiveLidarrBlock::ManualAlbumSearch,
ActiveLidarrBlock::ManualAlbumSearchSortPrompt,
ActiveLidarrBlock::DeleteTrackFilePrompt
)]
active_sonarr_block: ActiveLidarrBlock,
) {
test_handler_delegation!(
LibraryHandler,
ActiveLidarrBlock::Artists,
active_sonarr_block
);
}
#[test] #[test]
fn test_edit_key() { fn test_edit_key() {
let mut app = App::test_default(); let mut app = App::test_default();
+16 -15
View File
@@ -1,22 +1,22 @@
use crate::{ use crate::{
app::App, app::App,
event::Key, event::Key,
handlers::{KeyEventHandler, handle_clear_errors, handle_prompt_toggle}, handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler},
matches_key, matches_key,
models::{ models::{
BlockSelectionState, HorizontallyScrollableText, lidarr_models::Artist, servarr_data::lidarr::lidarr_data::{
lidarr_models::Artist, ActiveLidarrBlock, DELETE_ARTIST_SELECTION_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS,
servarr_data::lidarr::lidarr_data::{ LIBRARY_BLOCKS,
ActiveLidarrBlock, DELETE_ARTIST_SELECTION_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, },
LIBRARY_BLOCKS, stateful_table::SortOption,
}, BlockSelectionState,
stateful_table::SortOption, HorizontallyScrollableText,
}, },
network::lidarr_network::LidarrEvent, network::lidarr_network::LidarrEvent,
}; };
use super::handle_change_tab_left_right_keys; use super::handle_change_tab_left_right_keys;
use crate::handlers::table_handler::{TableHandlingConfig, handle_table}; use crate::handlers::table_handler::{handle_table, TableHandlingConfig};
mod add_artist_handler; mod add_artist_handler;
mod artist_details_handler; mod artist_details_handler;
@@ -33,6 +33,7 @@ pub(in crate::handlers::lidarr_handlers) use edit_artist_handler::EditArtistHand
#[cfg(test)] #[cfg(test)]
#[path = "library_handler_tests.rs"] #[path = "library_handler_tests.rs"]
mod library_handler_tests; mod library_handler_tests;
mod album_details_handler;
pub(super) struct LibraryHandler<'a, 'b> { pub(super) struct LibraryHandler<'a, 'b> {
key: Key, key: Key,
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
│ ││ ││ ⠀⠀⠀⠉⠻⠿⢿⡆⡾⠿⠟⠉⠀⠀⠀ │
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
╭ Artists ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Library │ Downloads │ History │ Root Folders │ Indexers │ System │
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ Name ▼ Type Status Quality Profile Metadata Profile Albums Tracks Size Monitored Tags │
│=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Lidarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: │=> a add │ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: │ m toggle monitoring │ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free │ o sort │ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ │ del delete │ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
│ │ s search │ ││ ⠀⠀⠀⠉⠻⠿⢿⡆⡾⠿⠟⠉⠀⠀⠀ │
╰───────────────────────────────────│ f filter │─────────────────╯╰──────────────────╯
╭ Artists ────────────────────────│ ctrl-r refresh │─────────────────────────────────────╮
│ Library │ Downloads │ History │ Ro│ u update all │ │
│───────────────────────────────────│ enter details │─────────────────────────────────────│
│ Name ▼ Typ│ esc cancel filter │e Monitored Tags │
│=> Alex Per│ ↑ k scroll up │0 GB 🏷 alex │
│ │ ↓ j scroll down │ │
│ │ ← h previous tab │ │
│ │ → l next tab │ │
│ │ pgUp ctrl-u page up │ │
│ │ pgDown ctrl-d page down │ │
│ │ tab next servarr │ │
│ │ shift-tab previous servarr │ │
│ │ q quit │ │
│ │ ? show/hide keybindings │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Error | <esc> to close ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Some error │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Lidarr Version: 1.2.3.4 ││Test download title ││ ⠀⠀⠀⣠⣴⣶⡿⠻⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⢠⣾⠟⠋⠀⠀⢀⣀⠀⠙⠻⣷⡄⠀ │
│Storage: ││ ││ ⢠⣿⠋⠀⣴⠃⠀⢸⣿⣿⣦⡀⠙⣿⡄ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣾⡟⠀⢸⠃⠀⠀⠀⠈⠉⠉⠁⠀⢹⣷ │
│Root Folders: ││ ││ ⢿⣧⠀⠈⠀⠀⠀⠀⠀⠀⢀⡟⠀⣸⡿ │
│/nfs: 204800.00 GB free ││ ││ ⠘⣿⣄⠀⠻⣿⣿⡇⠀⢀⠞⠀⣠⣿⠃ │
│ ││ ││ ⠀⠘⢿⣦⣄⠀⠉⠁⠀⠀⣠⣴⡿⠃⠀ │
│ ││ ││ ⠀⠀⠀⠉⠻⠿⢿⡆⡾⠿⠟⠉⠀⠀⠀ │
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
╭ Artists ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Library │ Downloads │ History │ Root Folders │ Indexers │ System │
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ Name ▼ Type Status Quality Profile Metadata Profile Albums Tracks Size Monitored Tags │
│=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
│ ││ ││ ⠀⠀⠀⠘⠻⠿⣿⣿⣿⣿⠿⠟⠋⠀⠀⠀ │
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
╭ Series ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Library │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ Title ▼ Year Network Status Rating Type Quality Profile Language Size Monitored Tags │
│=> Test 2022 HBO Continuin TV-MA Standard Bluray-1080p English 59.51 GB 🏷 │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Sonarr Version: 1.2.3.4 ╭ Keybindings ──────────────────────────────────────────────────────────────────────────╮ ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 │ Key Alt Key Description │━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: │=> a add │ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━│ e edit │ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: │ m toggle monitoring │ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free │ o sort │ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ │ del delete │ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
│ │ s search │ ││ ⠀⠀⠀⠘⠻⠿⣿⣿⣿⣿⠿⠟⠋⠀⠀⠀ │
╰───────────────────────────────────│ f filter │─────────────────╯╰──────────────────╯
╭ Series ─────────────────────────│ ctrl-r refresh │─────────────────────────────────────╮
│ Library │ Downloads │ Blocklist │ │ u update all │ │
│───────────────────────────────────│ enter details │─────────────────────────────────────│
│ Title ▼ │ esc cancel filter │ Monitored Tags │
│=> Test │ ↑ k scroll up │ GB 🏷 │
│ │ ↓ j scroll down │ │
│ │ ← h previous tab │ │
│ │ → l next tab │ │
│ │ pgUp ctrl-u page up │ │
│ │ pgDown ctrl-d page down │ │
│ │ tab next servarr │ │
│ │ shift-tab previous servarr │ │
│ │ q quit │ │
│ │ ? show/hide keybindings │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ │ │ │
│ ╰─────────────────────────────────────────────────────────────────────────────────────────╯ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,54 @@
---
source: src/ui/ui_tests.rs
expression: output
---
╭ Managarr - A Servarr management TUI ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Radarr │ Sonarr │ Lidarr <?> to open help│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Error | <esc> to close ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Some error │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭ Stats ──────────────────────────────────────────────────────────────╮╭ Downloads ─────────────────────────────────────────────────────────╮╭──────────────────╮
│Sonarr Version: 1.2.3.4 ││Test Download Title ││ ⠀⠀⠀⣠⣴⣶⣿⣿⣿⣿⣶⣦⣄⠀⠀⠀ │
│Uptime: 0d 00:00:44 ││50% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ⠀⣠⡀⠈⠻⣿⣿⣿⣿⣿⣿⠟⠁⢀⣀⠀ │
│Storage: ││ ││ ⢰⣿⣿⣦⠐⠄⠉⠉⠉⠉⠠⠂⣰⣿⣿⡆ │
│Disk 1: 100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━││ ││ ⣿⣿⣿⣿⡆⠀⣴⣿⣿⣦⠀⢰⣿⣿⣿⣿ │
│Root Folders: ││ ││ ⣿⣿⣿⣿⡇⠀⠻⣿⣿⠟⠀⠸⣿⣿⣿⣿ │
│/nfs: 204800.00 GB free ││ ││ ⠸⣿⣿⠟⠠⠂⠀⢀⡀⠀⠐⠄⠻⣿⣿⠇ │
│ ││ ││ ⠀⠙⠁⢀⣴⣾⣿⣿⣿⣿⣷⣦⡀⠈⠋⠀ │
│ ││ ││ ⠀⠀⠀⠘⠻⠿⣿⣿⣿⣿⠿⠟⠋⠀⠀⠀ │
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
╭ Series ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Library │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
│ Title ▼ Year Network Status Rating Type Quality Profile Language Size Monitored Tags │
│=> Test 2022 HBO Continuin TV-MA Standard Bluray-1080p English 59.51 GB 🏷 │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
+78 -39
View File
@@ -2,7 +2,9 @@
mod snapshot_tests { mod snapshot_tests {
use crate::app::App; use crate::app::App;
use crate::handlers::populate_keymapping_table; use crate::handlers::populate_keymapping_table;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::lidarr::lidarr_data::ActiveLidarrBlock;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::ui; use crate::ui;
use crate::ui::ui_test_utils::test_utils::{TerminalSize, render_to_string_with_app}; use crate::ui::ui_test_utils::test_utils::{TerminalSize, render_to_string_with_app};
@@ -44,42 +46,79 @@ mod snapshot_tests {
insta::assert_snapshot!(output); insta::assert_snapshot!(output);
} }
// TODO after adding fully populated Sonarr data #[test]
// #[test] fn test_sonarr_ui_renders_library_tab() {
// fn test_sonarr_ui_renders_library_tab() { let mut app = App::test_default_fully_populated();
// let mut app = App::test_default_fully_populated(); app.push_navigation_stack(ActiveSonarrBlock::default().into());
// app.push_navigation_stack(ActiveSonarrBlock::default().into());
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { ui(f, app);
// ui(f, app); });
// });
// insta::assert_snapshot!(output);
// insta::assert_snapshot!(output); }
// }
// #[test]
// #[test] fn test_sonarr_ui_renders_library_tab_with_error() {
// fn test_sonarr_ui_renders_library_tab_with_error() { let mut app = App::test_default_fully_populated();
// let mut app = App::test_default_fully_populated(); app.push_navigation_stack(ActiveSonarrBlock::default().into());
// app.push_navigation_stack(ActiveSonarrBlock::default().into()); app.error = "Some error".into();
// app.error = "Some error".into();
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { ui(f, app);
// ui(f, app); });
// });
// insta::assert_snapshot!(output);
// insta::assert_snapshot!(output); }
// }
// #[test]
// #[test] fn test_sonarr_ui_renders_library_tab_error_popup() {
// fn test_sonarr_ui_renders_library_tab_error_popup() { let mut app = App::test_default_fully_populated();
// let mut app = App::test_default_fully_populated(); populate_keymapping_table(&mut app);
// populate_keymapping_table(&mut app); app.push_navigation_stack(ActiveSonarrBlock::default().into());
// app.push_navigation_stack(ActiveSonarrBlock::default().into());
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
// let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { ui(f, app);
// ui(f, app); });
// });
// insta::assert_snapshot!(output);
// insta::assert_snapshot!(output); }
// }
#[test]
fn test_lidarr_ui_renders_library_tab() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::default().into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ui(f, app);
});
insta::assert_snapshot!(output);
}
#[test]
fn test_lidarr_ui_renders_library_tab_with_error() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::default().into());
app.error = "Some error".into();
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ui(f, app);
});
insta::assert_snapshot!(output);
}
#[test]
fn test_lidarr_ui_renders_library_tab_error_popup() {
let mut app = App::test_default_fully_populated();
populate_keymapping_table(&mut app);
app.push_navigation_stack(ActiveLidarrBlock::default().into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ui(f, app);
});
insta::assert_snapshot!(output);
}
} }