feat: Support for updating all Lidarr artists in both the CLI and TUI

This commit is contained in:
2026-01-06 12:47:10 -07:00
parent 96308afeee
commit 9b4eda6a9d
21 changed files with 701 additions and 100 deletions
@@ -55,7 +55,7 @@ impl<'a> Default for LidarrData<'a> {
quality_profile_map: BiMap::new(),
root_folders: StatefulTable::default(),
selected_block: BlockSelectionState::default(),
start_time: Utc::now(),
start_time: DateTime::default(),
tags_map: BiMap::new(),
version: String::new(),
main_tabs: TabState::new(vec![TabRoute {
@@ -112,19 +112,21 @@ pub enum ActiveLidarrBlock {
DeleteArtistConfirmPrompt,
DeleteArtistToggleDeleteFile,
DeleteArtistToggleAddListExclusion,
SearchArtists,
SearchArtistsError,
FilterArtists,
FilterArtistsError,
SearchArtists,
SearchArtistsError,
UpdateAllArtistsPrompt,
}
pub static LIBRARY_BLOCKS: [ActiveLidarrBlock; 6] = [
pub static LIBRARY_BLOCKS: [ActiveLidarrBlock; 7] = [
ActiveLidarrBlock::Artists,
ActiveLidarrBlock::ArtistsSortPrompt,
ActiveLidarrBlock::SearchArtists,
ActiveLidarrBlock::SearchArtistsError,
ActiveLidarrBlock::FilterArtists,
ActiveLidarrBlock::FilterArtistsError,
ActiveLidarrBlock::SearchArtists,
ActiveLidarrBlock::SearchArtistsError,
ActiveLidarrBlock::UpdateAllArtistsPrompt,
];
pub static DELETE_ARTIST_BLOCKS: [ActiveLidarrBlock; 4] = [
@@ -1,11 +1,15 @@
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use crate::models::{
Route,
servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LidarrData},
use crate::app::lidarr::lidarr_context_clues::ARTISTS_CONTEXT_CLUES;
use crate::models::servarr_data::lidarr::lidarr_data::{
DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS,
};
use crate::models::{
BlockSelectionState, Route,
servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LIBRARY_BLOCKS, LidarrData},
};
use chrono::{DateTime, Utc};
use pretty_assertions::{assert_eq, assert_str_eq};
#[test]
fn test_from_active_lidarr_block_to_route() {
@@ -36,4 +40,77 @@ mod tests {
assert!(!lidarr_data.delete_artist_files);
assert!(!lidarr_data.add_import_list_exclusion);
}
#[test]
fn test_lidarr_data_default() {
let lidarr_data = LidarrData::default();
assert!(!lidarr_data.add_import_list_exclusion);
assert_is_empty!(lidarr_data.artists);
assert!(!lidarr_data.delete_artist_files);
assert_is_empty!(lidarr_data.disk_space_vec);
assert_is_empty!(lidarr_data.downloads);
assert_is_empty!(lidarr_data.metadata_profile_map);
assert!(!lidarr_data.prompt_confirm);
assert_none!(lidarr_data.prompt_confirm_action);
assert_is_empty!(lidarr_data.quality_profile_map);
assert_is_empty!(lidarr_data.root_folders);
assert_eq!(lidarr_data.selected_block, BlockSelectionState::default());
assert_eq!(lidarr_data.start_time, <DateTime<Utc>>::default());
assert_is_empty!(lidarr_data.tags_map);
assert_is_empty!(lidarr_data.version);
assert_eq!(lidarr_data.main_tabs.tabs.len(), 1);
assert_str_eq!(lidarr_data.main_tabs.tabs[0].title, "Library");
assert_eq!(
lidarr_data.main_tabs.tabs[0].route,
ActiveLidarrBlock::Artists.into()
);
assert_some_eq_x!(
&lidarr_data.main_tabs.tabs[0].contextual_help,
&ARTISTS_CONTEXT_CLUES
);
assert_none!(lidarr_data.main_tabs.tabs[0].config);
}
#[test]
fn test_library_blocks_contains_expected_blocks() {
assert_eq!(LIBRARY_BLOCKS.len(), 7);
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::Artists));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::ArtistsSortPrompt));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::SearchArtists));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::SearchArtistsError));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::FilterArtists));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::FilterArtistsError));
assert!(LIBRARY_BLOCKS.contains(&ActiveLidarrBlock::UpdateAllArtistsPrompt));
}
#[test]
fn test_delete_artist_blocks_contents() {
assert_eq!(DELETE_ARTIST_BLOCKS.len(), 4);
assert!(DELETE_ARTIST_BLOCKS.contains(&ActiveLidarrBlock::DeleteArtistPrompt));
assert!(DELETE_ARTIST_BLOCKS.contains(&ActiveLidarrBlock::DeleteArtistConfirmPrompt));
assert!(DELETE_ARTIST_BLOCKS.contains(&ActiveLidarrBlock::DeleteArtistToggleDeleteFile));
assert!(DELETE_ARTIST_BLOCKS.contains(&ActiveLidarrBlock::DeleteArtistToggleAddListExclusion));
}
#[test]
fn test_delete_artist_selection_blocks_ordering() {
let mut delete_artist_block_iter = DELETE_ARTIST_SELECTION_BLOCKS.iter();
assert_eq!(
delete_artist_block_iter.next().unwrap(),
&[ActiveLidarrBlock::DeleteArtistToggleDeleteFile]
);
assert_eq!(
delete_artist_block_iter.next().unwrap(),
&[ActiveLidarrBlock::DeleteArtistToggleAddListExclusion]
);
assert_eq!(
delete_artist_block_iter.next().unwrap(),
&[ActiveLidarrBlock::DeleteArtistConfirmPrompt]
);
assert_none!(delete_artist_block_iter.next());
}
}
+3
View File
@@ -23,6 +23,7 @@ use crate::{
mod modals_tests;
#[derive(Default)]
#[cfg_attr(test, derive(Debug))]
pub struct AddSeriesModal {
pub root_folder_list: StatefulList<RootFolder>,
pub monitor_list: StatefulList<SeriesMonitor>,
@@ -130,6 +131,7 @@ impl From<&SonarrData<'_>> for EditIndexerModal {
}
#[derive(Default)]
#[cfg_attr(test, derive(Debug))]
pub struct EditSeriesModal {
pub series_type_list: StatefulList<SeriesType>,
pub quality_profile_list: StatefulList<String>,
@@ -260,6 +262,7 @@ impl Default for EpisodeDetailsModal {
}
}
#[cfg_attr(test, derive(Debug))]
pub struct SeasonDetailsModal {
pub episodes: StatefulTable<Episode>,
pub episode_files: StatefulTable<EpisodeFile>,
@@ -82,39 +82,39 @@ mod tests {
let sonarr_data = SonarrData::default();
assert!(!sonarr_data.add_list_exclusion);
assert!(sonarr_data.add_searched_series.is_none());
assert!(sonarr_data.add_series_search.is_none());
assert!(sonarr_data.add_series_modal.is_none());
assert!(sonarr_data.blocklist.is_empty());
assert_none!(sonarr_data.add_searched_series);
assert_none!(sonarr_data.add_series_search);
assert_none!(sonarr_data.add_series_modal);
assert_is_empty!(sonarr_data.blocklist);
assert!(!sonarr_data.delete_series_files);
assert!(sonarr_data.downloads.is_empty());
assert!(sonarr_data.disk_space_vec.is_empty());
assert!(sonarr_data.edit_indexer_modal.is_none());
assert!(sonarr_data.edit_root_folder.is_none());
assert!(sonarr_data.edit_series_modal.is_none());
assert!(sonarr_data.history.is_empty());
assert!(sonarr_data.indexers.is_empty());
assert!(sonarr_data.indexer_settings.is_none());
assert!(sonarr_data.indexer_test_errors.is_none());
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_is_empty!(sonarr_data.downloads);
assert_is_empty!(sonarr_data.disk_space_vec);
assert_none!(sonarr_data.edit_indexer_modal);
assert_none!(sonarr_data.edit_root_folder);
assert_none!(sonarr_data.edit_series_modal);
assert_is_empty!(sonarr_data.history);
assert_is_empty!(sonarr_data.indexers);
assert_none!(sonarr_data.indexer_settings);
assert_none!(sonarr_data.indexer_test_errors);
assert_none!(sonarr_data.indexer_test_all_results);
assert_is_empty!(sonarr_data.language_profiles_map);
assert_is_empty!(sonarr_data.logs);
assert_is_empty!(sonarr_data.log_details);
assert!(!sonarr_data.prompt_confirm);
assert!(sonarr_data.prompt_confirm_action.is_none());
assert!(sonarr_data.quality_profile_map.is_empty());
assert!(sonarr_data.queued_events.is_empty());
assert!(sonarr_data.root_folders.is_empty());
assert!(sonarr_data.seasons.is_empty());
assert!(sonarr_data.season_details_modal.is_none());
assert_none!(sonarr_data.prompt_confirm_action);
assert_is_empty!(sonarr_data.quality_profile_map);
assert_is_empty!(sonarr_data.queued_events);
assert_is_empty!(sonarr_data.root_folders);
assert_is_empty!(sonarr_data.seasons);
assert_none!(sonarr_data.season_details_modal);
assert_eq!(sonarr_data.selected_block, BlockSelectionState::default());
assert!(sonarr_data.series.is_empty());
assert!(sonarr_data.series_history.is_none());
assert_is_empty!(sonarr_data.series);
assert_none!(sonarr_data.series_history);
assert_eq!(sonarr_data.start_time, <DateTime<Utc>>::default());
assert!(sonarr_data.tags_map.is_empty());
assert!(sonarr_data.tasks.is_empty());
assert!(sonarr_data.updates.is_empty());
assert!(sonarr_data.version.is_empty());
assert_is_empty!(sonarr_data.tags_map);
assert_is_empty!(sonarr_data.tasks);
assert_is_empty!(sonarr_data.updates);
assert_is_empty!(sonarr_data.version);
assert_eq!(sonarr_data.main_tabs.tabs.len(), 7);
@@ -123,84 +123,77 @@ mod tests {
sonarr_data.main_tabs.tabs[0].route,
ActiveSonarrBlock::Series.into()
);
assert!(sonarr_data.main_tabs.tabs[0].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[0].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[0].contextual_help,
&SERIES_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[0].config, None);
assert_none!(sonarr_data.main_tabs.tabs[0].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[1].title, "Downloads");
assert_eq!(
sonarr_data.main_tabs.tabs[1].route,
ActiveSonarrBlock::Downloads.into()
);
assert!(sonarr_data.main_tabs.tabs[1].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[1].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[1].contextual_help,
&DOWNLOADS_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[1].config, None);
assert_none!(sonarr_data.main_tabs.tabs[1].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[2].title, "Blocklist");
assert_eq!(
sonarr_data.main_tabs.tabs[2].route,
ActiveSonarrBlock::Blocklist.into()
);
assert!(sonarr_data.main_tabs.tabs[2].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[2].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[2].contextual_help,
&BLOCKLIST_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[2].config, None);
assert_none!(sonarr_data.main_tabs.tabs[2].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[3].title, "History");
assert_eq!(
sonarr_data.main_tabs.tabs[3].route,
ActiveSonarrBlock::History.into()
);
assert!(sonarr_data.main_tabs.tabs[3].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[3].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[3].contextual_help,
&HISTORY_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[3].config, None);
assert_none!(sonarr_data.main_tabs.tabs[3].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[4].title, "Root Folders");
assert_eq!(
sonarr_data.main_tabs.tabs[4].route,
ActiveSonarrBlock::RootFolders.into()
);
assert!(sonarr_data.main_tabs.tabs[4].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[4].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[4].contextual_help,
&ROOT_FOLDERS_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[4].config, None);
assert_none!(sonarr_data.main_tabs.tabs[4].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[5].title, "Indexers");
assert_eq!(
sonarr_data.main_tabs.tabs[5].route,
ActiveSonarrBlock::Indexers.into()
);
assert!(sonarr_data.main_tabs.tabs[5].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[5].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[5].contextual_help,
&INDEXERS_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[5].config, None);
assert_none!(sonarr_data.main_tabs.tabs[5].config);
assert_str_eq!(sonarr_data.main_tabs.tabs[6].title, "System");
assert_eq!(
sonarr_data.main_tabs.tabs[6].route,
ActiveSonarrBlock::System.into()
);
assert!(sonarr_data.main_tabs.tabs[6].contextual_help.is_some());
assert_eq!(
sonarr_data.main_tabs.tabs[6].contextual_help.unwrap(),
assert_some_eq_x!(
&sonarr_data.main_tabs.tabs[6].contextual_help,
&SYSTEM_CONTEXT_CLUES
);
assert_eq!(sonarr_data.main_tabs.tabs[6].config, None);
assert_none!(sonarr_data.main_tabs.tabs[6].config);
assert_eq!(sonarr_data.series_info_tabs.tabs.len(), 2);
@@ -209,36 +202,22 @@ mod tests {
sonarr_data.series_info_tabs.tabs[0].route,
ActiveSonarrBlock::SeriesDetails.into()
);
assert!(
sonarr_data.series_info_tabs.tabs[0]
.contextual_help
.is_some()
);
assert_eq!(
sonarr_data.series_info_tabs.tabs[0]
.contextual_help
.unwrap(),
assert_some_eq_x!(
&sonarr_data.series_info_tabs.tabs[0].contextual_help,
&SERIES_DETAILS_CONTEXT_CLUES
);
assert_eq!(sonarr_data.series_info_tabs.tabs[0].config, None);
assert_none!(sonarr_data.series_info_tabs.tabs[0].config);
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]
.contextual_help
.is_some()
);
assert_eq!(
sonarr_data.series_info_tabs.tabs[1]
.contextual_help
.unwrap(),
assert_some_eq_x!(
&sonarr_data.series_info_tabs.tabs[1].contextual_help,
&SERIES_HISTORY_CONTEXT_CLUES
);
assert_eq!(sonarr_data.series_info_tabs.tabs[1].config, None);
assert_none!(sonarr_data.series_info_tabs.tabs[1].config);
}
}