Added network support for updating all indexer settings, editing specific indexer settings, deleting an indexer; Also added keybindings for all of the above that change the current route. Added full support for deleting an indexer; still need to add an indexer_handler to handle the add, edit, and settings functionalities
This commit is contained in:
@@ -16,6 +16,7 @@ generate_keybindings! {
|
|||||||
right,
|
right,
|
||||||
backspace,
|
backspace,
|
||||||
search,
|
search,
|
||||||
|
settings,
|
||||||
filter,
|
filter,
|
||||||
sort,
|
sort,
|
||||||
edit,
|
edit,
|
||||||
@@ -66,6 +67,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
|||||||
key: Key::Char('s'),
|
key: Key::Char('s'),
|
||||||
desc: "Search",
|
desc: "Search",
|
||||||
},
|
},
|
||||||
|
settings: KeyBinding {
|
||||||
|
key: Key::Char('s'),
|
||||||
|
desc: "Settings",
|
||||||
|
},
|
||||||
filter: KeyBinding {
|
filter: KeyBinding {
|
||||||
key: Key::Char('f'),
|
key: Key::Char('f'),
|
||||||
desc: "Filter",
|
desc: "Filter",
|
||||||
|
|||||||
+22
-4
@@ -5,8 +5,8 @@ use strum::IntoEnumIterator;
|
|||||||
use crate::app::{App, Route};
|
use crate::app::{App, Route};
|
||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
AddMovieSearchResult, Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord, Indexer,
|
AddMovieSearchResult, Collection, CollectionMovie, Credit, DiskSpace, DownloadRecord, Indexer,
|
||||||
MinimumAvailability, Monitor, Movie, MovieHistoryItem, QueueEvent, Release, ReleaseField,
|
IndexerSettings, MinimumAvailability, Monitor, Movie, MovieHistoryItem, QueueEvent, Release,
|
||||||
RootFolder, Task,
|
ReleaseField, RootFolder, Task,
|
||||||
};
|
};
|
||||||
use crate::models::{
|
use crate::models::{
|
||||||
BlockSelectionState, HorizontallyScrollableText, ScrollableText, StatefulList, StatefulTable,
|
BlockSelectionState, HorizontallyScrollableText, ScrollableText, StatefulList, StatefulTable,
|
||||||
@@ -37,6 +37,7 @@ pub struct RadarrData<'a> {
|
|||||||
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
|
pub selected_block: BlockSelectionState<'a, ActiveRadarrBlock>,
|
||||||
pub downloads: StatefulTable<DownloadRecord>,
|
pub downloads: StatefulTable<DownloadRecord>,
|
||||||
pub indexers: StatefulTable<Indexer>,
|
pub indexers: StatefulTable<Indexer>,
|
||||||
|
pub indexer_settings: Option<IndexerSettings>,
|
||||||
pub quality_profile_map: BiMap<u64, String>,
|
pub quality_profile_map: BiMap<u64, String>,
|
||||||
pub tags_map: BiMap<u64, String>,
|
pub tags_map: BiMap<u64, String>,
|
||||||
pub movie_details: ScrollableText,
|
pub movie_details: ScrollableText,
|
||||||
@@ -263,6 +264,7 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
filtered_movies: StatefulTable::default(),
|
filtered_movies: StatefulTable::default(),
|
||||||
downloads: StatefulTable::default(),
|
downloads: StatefulTable::default(),
|
||||||
indexers: StatefulTable::default(),
|
indexers: StatefulTable::default(),
|
||||||
|
indexer_settings: None,
|
||||||
quality_profile_map: BiMap::default(),
|
quality_profile_map: BiMap::default(),
|
||||||
tags_map: BiMap::default(),
|
tags_map: BiMap::default(),
|
||||||
file_details: String::default(),
|
file_details: String::default(),
|
||||||
@@ -324,7 +326,7 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
title: "Indexers",
|
title: "Indexers",
|
||||||
route: ActiveRadarrBlock::Indexers.into(),
|
route: ActiveRadarrBlock::Indexers.into(),
|
||||||
help: "",
|
help: "",
|
||||||
contextual_help: Some("<r> refresh"),
|
contextual_help: Some("<enter> edit | <s> settings | <del> delete | <r> refresh"),
|
||||||
},
|
},
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "System",
|
title: "System",
|
||||||
@@ -377,6 +379,7 @@ impl<'a> Default for RadarrData<'a> {
|
|||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
|
||||||
pub enum ActiveRadarrBlock {
|
pub enum ActiveRadarrBlock {
|
||||||
|
AddIndexer,
|
||||||
AddMovieAlreadyInLibrary,
|
AddMovieAlreadyInLibrary,
|
||||||
AddMovieSearchInput,
|
AddMovieSearchInput,
|
||||||
AddMovieSearchResults,
|
AddMovieSearchResults,
|
||||||
@@ -394,11 +397,12 @@ pub enum ActiveRadarrBlock {
|
|||||||
CollectionDetails,
|
CollectionDetails,
|
||||||
Cast,
|
Cast,
|
||||||
Crew,
|
Crew,
|
||||||
|
DeleteDownloadPrompt,
|
||||||
|
DeleteIndexerPrompt,
|
||||||
DeleteMoviePrompt,
|
DeleteMoviePrompt,
|
||||||
DeleteMovieConfirmPrompt,
|
DeleteMovieConfirmPrompt,
|
||||||
DeleteMovieToggleDeleteFile,
|
DeleteMovieToggleDeleteFile,
|
||||||
DeleteMovieToggleAddListExclusion,
|
DeleteMovieToggleAddListExclusion,
|
||||||
DeleteDownloadPrompt,
|
|
||||||
DeleteRootFolderPrompt,
|
DeleteRootFolderPrompt,
|
||||||
Downloads,
|
Downloads,
|
||||||
EditCollectionPrompt,
|
EditCollectionPrompt,
|
||||||
@@ -408,6 +412,7 @@ pub enum ActiveRadarrBlock {
|
|||||||
EditCollectionSelectQualityProfile,
|
EditCollectionSelectQualityProfile,
|
||||||
EditCollectionToggleSearchOnAdd,
|
EditCollectionToggleSearchOnAdd,
|
||||||
EditCollectionToggleMonitored,
|
EditCollectionToggleMonitored,
|
||||||
|
EditIndexer,
|
||||||
EditMoviePrompt,
|
EditMoviePrompt,
|
||||||
EditMovieConfirmPrompt,
|
EditMovieConfirmPrompt,
|
||||||
EditMoviePathInput,
|
EditMoviePathInput,
|
||||||
@@ -419,6 +424,7 @@ pub enum ActiveRadarrBlock {
|
|||||||
FilterCollections,
|
FilterCollections,
|
||||||
FilterMovies,
|
FilterMovies,
|
||||||
Indexers,
|
Indexers,
|
||||||
|
IndexerSettings,
|
||||||
ManualSearch,
|
ManualSearch,
|
||||||
ManualSearchSortPrompt,
|
ManualSearchSortPrompt,
|
||||||
ManualSearchConfirmPrompt,
|
ManualSearchConfirmPrompt,
|
||||||
@@ -531,6 +537,13 @@ pub static DELETE_MOVIE_SELECTION_BLOCKS: [ActiveRadarrBlock; 3] = [
|
|||||||
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
|
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion,
|
||||||
ActiveRadarrBlock::DeleteMovieConfirmPrompt,
|
ActiveRadarrBlock::DeleteMovieConfirmPrompt,
|
||||||
];
|
];
|
||||||
|
pub static INDEXER_BLOCKS: [ActiveRadarrBlock; 5] = [
|
||||||
|
ActiveRadarrBlock::Indexers,
|
||||||
|
ActiveRadarrBlock::IndexerSettings,
|
||||||
|
ActiveRadarrBlock::AddIndexer,
|
||||||
|
ActiveRadarrBlock::EditIndexer,
|
||||||
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
|
];
|
||||||
pub static SYSTEM_DETAILS_BLOCKS: [ActiveRadarrBlock; 5] = [
|
pub static SYSTEM_DETAILS_BLOCKS: [ActiveRadarrBlock; 5] = [
|
||||||
ActiveRadarrBlock::SystemLogs,
|
ActiveRadarrBlock::SystemLogs,
|
||||||
ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
@@ -587,6 +600,11 @@ impl<'a> App<'a> {
|
|||||||
.dispatch_network_event(RadarrEvent::GetIndexers.into())
|
.dispatch_network_event(RadarrEvent::GetIndexers.into())
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::IndexerSettings => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetIndexerSettings.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
ActiveRadarrBlock::System => {
|
ActiveRadarrBlock::System => {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetTasks.into())
|
.dispatch_network_event(RadarrEvent::GetTasks.into())
|
||||||
|
|||||||
+19
-1
@@ -274,6 +274,7 @@ mod tests {
|
|||||||
assert!(radarr_data.filtered_movies.items.is_empty());
|
assert!(radarr_data.filtered_movies.items.is_empty());
|
||||||
assert!(radarr_data.downloads.items.is_empty());
|
assert!(radarr_data.downloads.items.is_empty());
|
||||||
assert!(radarr_data.indexers.items.is_empty());
|
assert!(radarr_data.indexers.items.is_empty());
|
||||||
|
assert!(radarr_data.indexer_settings.is_none());
|
||||||
assert!(radarr_data.quality_profile_map.is_empty());
|
assert!(radarr_data.quality_profile_map.is_empty());
|
||||||
assert!(radarr_data.tags_map.is_empty());
|
assert!(radarr_data.tags_map.is_empty());
|
||||||
assert!(radarr_data.file_details.is_empty());
|
assert!(radarr_data.file_details.is_empty());
|
||||||
@@ -357,7 +358,7 @@ mod tests {
|
|||||||
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
assert!(radarr_data.main_tabs.tabs[4].help.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
radarr_data.main_tabs.tabs[4].contextual_help,
|
radarr_data.main_tabs.tabs[4].contextual_help,
|
||||||
Some("<r> refresh")
|
Some("<enter> edit | <s> settings | <del> delete | <r> refresh")
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "System");
|
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "System");
|
||||||
@@ -713,6 +714,23 @@ mod tests {
|
|||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_indexer_settings_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_radarr_block(&ActiveRadarrBlock::IndexerSettings)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetIndexerSettings.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_system_block() {
|
async fn test_dispatch_by_system_block() {
|
||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|||||||
@@ -251,6 +251,9 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
ActiveRadarrBlock::RootFolders => self
|
ActiveRadarrBlock::RootFolders => self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into()),
|
.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into()),
|
||||||
|
ActiveRadarrBlock::Indexers => self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into()),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,6 +281,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt
|
ActiveRadarrBlock::DeleteDownloadPrompt
|
||||||
|
| ActiveRadarrBlock::DeleteIndexerPrompt
|
||||||
| ActiveRadarrBlock::DeleteRootFolderPrompt
|
| ActiveRadarrBlock::DeleteRootFolderPrompt
|
||||||
| ActiveRadarrBlock::UpdateAllMoviesPrompt
|
| ActiveRadarrBlock::UpdateAllMoviesPrompt
|
||||||
| ActiveRadarrBlock::UpdateAllCollectionsPrompt
|
| ActiveRadarrBlock::UpdateAllCollectionsPrompt
|
||||||
@@ -404,6 +408,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::DeleteIndexerPrompt => {
|
||||||
|
if self.app.data.radarr_data.prompt_confirm {
|
||||||
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteIndexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
||||||
if self.app.data.radarr_data.prompt_confirm {
|
if self.app.data.radarr_data.prompt_confirm {
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
||||||
@@ -431,6 +442,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
self.app.should_ignore_quit_key = false;
|
self.app.should_ignore_quit_key = false;
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::Indexers => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveRadarrBlock::EditIndexer.into());
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,6 +470,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
self.app.should_ignore_quit_key = false;
|
self.app.should_ignore_quit_key = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt
|
ActiveRadarrBlock::DeleteDownloadPrompt
|
||||||
|
| ActiveRadarrBlock::DeleteIndexerPrompt
|
||||||
| ActiveRadarrBlock::DeleteRootFolderPrompt
|
| ActiveRadarrBlock::DeleteRootFolderPrompt
|
||||||
| ActiveRadarrBlock::UpdateAllMoviesPrompt
|
| ActiveRadarrBlock::UpdateAllMoviesPrompt
|
||||||
| ActiveRadarrBlock::UpdateAllCollectionsPrompt
|
| ActiveRadarrBlock::UpdateAllCollectionsPrompt
|
||||||
@@ -527,9 +544,19 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::Indexers => match self.key {
|
ActiveRadarrBlock::Indexers => match self.key {
|
||||||
|
_ if *key == DEFAULT_KEYBINDINGS.add.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveRadarrBlock::AddIndexer.into());
|
||||||
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
|
_ if *key == DEFAULT_KEYBINDINGS.settings.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveRadarrBlock::IndexerSettings.into());
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::Collections => match self.key {
|
ActiveRadarrBlock::Collections => match self.key {
|
||||||
|
|||||||
@@ -135,4 +135,21 @@ mod utils {
|
|||||||
assert_eq!(app.data.radarr_data.edit_search_on_add, Some(true));
|
assert_eq!(app.data.radarr_data.edit_search_on_add, Some(true));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_delete_prompt {
|
||||||
|
($block:expr, $expected_block:expr) => {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
RadarrHandler::with(&DELETE_KEY, &mut app, &$block, &None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), &$expected_block.into());
|
||||||
|
};
|
||||||
|
|
||||||
|
($app:expr, $block:expr, $expected_block:expr) => {
|
||||||
|
RadarrHandler::with(&DELETE_KEY, &mut $app, &$block, &None).handle();
|
||||||
|
|
||||||
|
assert_eq!($app.get_current_route(), &$expected_block.into());
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,6 +209,8 @@ mod tests {
|
|||||||
mod test_handle_delete {
|
mod test_handle_delete {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use crate::assert_delete_prompt;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
||||||
@@ -217,11 +219,10 @@ mod tests {
|
|||||||
fn test_movies_delete() {
|
fn test_movies_delete() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
RadarrHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Movies, &None).handle();
|
assert_delete_prompt!(
|
||||||
|
app,
|
||||||
assert_eq!(
|
ActiveRadarrBlock::Movies,
|
||||||
app.get_current_route(),
|
ActiveRadarrBlock::DeleteMoviePrompt
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt.into()
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
@@ -229,34 +230,18 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[rstest]
|
||||||
fn test_downloads_delete() {
|
#[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::DeleteDownloadPrompt)]
|
||||||
let mut app = App::default();
|
#[case(
|
||||||
|
ActiveRadarrBlock::RootFolders,
|
||||||
RadarrHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
ActiveRadarrBlock::DeleteRootFolderPrompt
|
||||||
|
)]
|
||||||
assert_eq!(
|
#[case(ActiveRadarrBlock::Indexers, ActiveRadarrBlock::DeleteIndexerPrompt)]
|
||||||
app.get_current_route(),
|
fn test_delete_prompt(
|
||||||
&ActiveRadarrBlock::DeleteDownloadPrompt.into()
|
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||||
);
|
#[case] expected_radarr_block: ActiveRadarrBlock,
|
||||||
}
|
) {
|
||||||
|
assert_delete_prompt!(active_radarr_block, expected_radarr_block);
|
||||||
#[test]
|
|
||||||
fn test_root_folder_delete() {
|
|
||||||
let mut app = App::default();
|
|
||||||
|
|
||||||
RadarrHandler::with(
|
|
||||||
&DELETE_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::RootFolders,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,6 +317,7 @@ mod tests {
|
|||||||
fn test_left_right_prompt_toggle(
|
fn test_left_right_prompt_toggle(
|
||||||
#[values(
|
#[values(
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt,
|
ActiveRadarrBlock::DeleteDownloadPrompt,
|
||||||
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt,
|
ActiveRadarrBlock::UpdateAllMoviesPrompt,
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||||
@@ -387,6 +373,18 @@ mod tests {
|
|||||||
|
|
||||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_submit_aka_edit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
RadarrHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
&ActiveRadarrBlock::EditIndexer.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::MovieDetails)]
|
#[case(ActiveRadarrBlock::Movies, ActiveRadarrBlock::MovieDetails)]
|
||||||
#[case(ActiveRadarrBlock::Collections, ActiveRadarrBlock::CollectionDetails)]
|
#[case(ActiveRadarrBlock::Collections, ActiveRadarrBlock::CollectionDetails)]
|
||||||
@@ -629,6 +627,11 @@ mod tests {
|
|||||||
ActiveRadarrBlock::DeleteDownloadPrompt,
|
ActiveRadarrBlock::DeleteDownloadPrompt,
|
||||||
RadarrEvent::DeleteDownload
|
RadarrEvent::DeleteDownload
|
||||||
)]
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveRadarrBlock::Indexers,
|
||||||
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
|
RadarrEvent::DeleteIndexer
|
||||||
|
)]
|
||||||
#[case(
|
#[case(
|
||||||
ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
@@ -751,6 +754,7 @@ mod tests {
|
|||||||
ActiveRadarrBlock::DeleteRootFolderPrompt
|
ActiveRadarrBlock::DeleteRootFolderPrompt
|
||||||
)]
|
)]
|
||||||
#[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::DeleteDownloadPrompt)]
|
#[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::DeleteDownloadPrompt)]
|
||||||
|
#[case(ActiveRadarrBlock::Indexers, ActiveRadarrBlock::DeleteIndexerPrompt)]
|
||||||
#[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::UpdateDownloadsPrompt)]
|
#[case(ActiveRadarrBlock::Downloads, ActiveRadarrBlock::UpdateDownloadsPrompt)]
|
||||||
#[case(
|
#[case(
|
||||||
ActiveRadarrBlock::Collections,
|
ActiveRadarrBlock::Collections,
|
||||||
@@ -899,6 +903,24 @@ mod tests {
|
|||||||
assert!(app.should_ignore_quit_key);
|
assert!(app.should_ignore_quit_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_add() {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
RadarrHandler::with(
|
||||||
|
&DEFAULT_KEYBINDINGS.add.key,
|
||||||
|
&mut app,
|
||||||
|
&ActiveRadarrBlock::Indexers,
|
||||||
|
&None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
&ActiveRadarrBlock::AddIndexer.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_root_folder_add() {
|
fn test_root_folder_add() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
@@ -1054,6 +1076,24 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_settings_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
RadarrHandler::with(
|
||||||
|
&DEFAULT_KEYBINDINGS.settings.key,
|
||||||
|
&mut app,
|
||||||
|
&ActiveRadarrBlock::Indexers,
|
||||||
|
&None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
&ActiveRadarrBlock::IndexerSettings.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_root_folder_prompt_backspace_key() {
|
fn test_add_root_folder_prompt_backspace_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|||||||
@@ -182,7 +182,6 @@ pub struct IndexerField {
|
|||||||
pub value: Option<Value>,
|
pub value: Option<Value>,
|
||||||
#[serde(rename(deserialize = "type"))]
|
#[serde(rename(deserialize = "type"))]
|
||||||
pub field_type: Option<String>,
|
pub field_type: Option<String>,
|
||||||
pub advanced: bool,
|
|
||||||
pub select_options: Option<Vec<IndexerSelectOption>>,
|
pub select_options: Option<Vec<IndexerSelectOption>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +196,27 @@ pub struct IndexerSelectOption {
|
|||||||
pub order: Number,
|
pub order: Number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Derivative, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct IndexerSettings {
|
||||||
|
pub allow_hardcoded_subs: bool,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub availability_delay: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub id: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub maximum_size: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub minimum_age: Number,
|
||||||
|
pub prefer_indexer_flags: bool,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub retention: Number,
|
||||||
|
#[derivative(Default(value = "Number::from(0)"))]
|
||||||
|
pub rss_sync_interval: Number,
|
||||||
|
pub whitelisted_hardcoded_subs: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
#[derive(Deserialize, Default, Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
|
||||||
pub struct Language {
|
pub struct Language {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use crate::app::RadarrConfig;
|
|||||||
use crate::models::radarr_models::{
|
use crate::models::radarr_models::{
|
||||||
AddMovieBody, AddMovieSearchResult, AddOptions, AddRootFolderBody, Collection, CollectionMovie,
|
AddMovieBody, AddMovieSearchResult, AddOptions, AddRootFolderBody, Collection, CollectionMovie,
|
||||||
CommandBody, Credit, CreditType, DiskSpace, DownloadRecord, DownloadsResponse, Indexer,
|
CommandBody, Credit, CreditType, DiskSpace, DownloadRecord, DownloadsResponse, Indexer,
|
||||||
LogResponse, Movie, MovieCommandBody, MovieHistoryItem, QualityProfile, QueueEvent, Release,
|
IndexerSettings, LogResponse, Movie, MovieCommandBody, MovieHistoryItem, QualityProfile,
|
||||||
ReleaseDownloadBody, RootFolder, SystemStatus, Tag, Task, Update,
|
QueueEvent, Release, ReleaseDownloadBody, RootFolder, SystemStatus, Tag, Task, Update,
|
||||||
};
|
};
|
||||||
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
|
use crate::models::{HorizontallyScrollableText, Route, Scrollable, ScrollableText};
|
||||||
use crate::network::{Network, NetworkEvent, RequestMethod, RequestProps};
|
use crate::network::{Network, NetworkEvent, RequestMethod, RequestProps};
|
||||||
@@ -27,6 +27,7 @@ pub enum RadarrEvent {
|
|||||||
AddMovie,
|
AddMovie,
|
||||||
AddRootFolder,
|
AddRootFolder,
|
||||||
DeleteDownload,
|
DeleteDownload,
|
||||||
|
DeleteIndexer,
|
||||||
DeleteMovie,
|
DeleteMovie,
|
||||||
DeleteRootFolder,
|
DeleteRootFolder,
|
||||||
DownloadRelease,
|
DownloadRelease,
|
||||||
@@ -35,6 +36,7 @@ pub enum RadarrEvent {
|
|||||||
GetCollections,
|
GetCollections,
|
||||||
GetDownloads,
|
GetDownloads,
|
||||||
GetIndexers,
|
GetIndexers,
|
||||||
|
GetIndexerSettings,
|
||||||
GetLogs,
|
GetLogs,
|
||||||
GetMovieCredits,
|
GetMovieCredits,
|
||||||
GetMovieDetails,
|
GetMovieDetails,
|
||||||
@@ -57,6 +59,7 @@ pub enum RadarrEvent {
|
|||||||
UpdateAndScan,
|
UpdateAndScan,
|
||||||
UpdateCollections,
|
UpdateCollections,
|
||||||
UpdateDownloads,
|
UpdateDownloads,
|
||||||
|
UpdateIndexerSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RadarrEvent {
|
impl RadarrEvent {
|
||||||
@@ -64,7 +67,8 @@ impl RadarrEvent {
|
|||||||
match self {
|
match self {
|
||||||
RadarrEvent::GetCollections | RadarrEvent::EditCollection => "/collection",
|
RadarrEvent::GetCollections | RadarrEvent::EditCollection => "/collection",
|
||||||
RadarrEvent::GetDownloads | RadarrEvent::DeleteDownload => "/queue",
|
RadarrEvent::GetDownloads | RadarrEvent::DeleteDownload => "/queue",
|
||||||
RadarrEvent::GetIndexers => "/indexer",
|
RadarrEvent::GetIndexers | RadarrEvent::DeleteIndexer => "/indexer",
|
||||||
|
RadarrEvent::GetIndexerSettings | RadarrEvent::UpdateIndexerSettings => "/config/indexer",
|
||||||
RadarrEvent::GetLogs => "/log",
|
RadarrEvent::GetLogs => "/log",
|
||||||
RadarrEvent::AddMovie
|
RadarrEvent::AddMovie
|
||||||
| RadarrEvent::EditMovie
|
| RadarrEvent::EditMovie
|
||||||
@@ -107,8 +111,9 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
match radarr_event {
|
match radarr_event {
|
||||||
RadarrEvent::AddMovie => self.add_movie().await,
|
RadarrEvent::AddMovie => self.add_movie().await,
|
||||||
RadarrEvent::AddRootFolder => self.add_root_folder().await,
|
RadarrEvent::AddRootFolder => self.add_root_folder().await,
|
||||||
RadarrEvent::DeleteMovie => self.delete_movie().await,
|
|
||||||
RadarrEvent::DeleteDownload => self.delete_download().await,
|
RadarrEvent::DeleteDownload => self.delete_download().await,
|
||||||
|
RadarrEvent::DeleteIndexer => self.delete_indexer().await,
|
||||||
|
RadarrEvent::DeleteMovie => self.delete_movie().await,
|
||||||
RadarrEvent::DeleteRootFolder => self.delete_root_folder().await,
|
RadarrEvent::DeleteRootFolder => self.delete_root_folder().await,
|
||||||
RadarrEvent::DownloadRelease => self.download_release().await,
|
RadarrEvent::DownloadRelease => self.download_release().await,
|
||||||
RadarrEvent::EditCollection => self.edit_collection().await,
|
RadarrEvent::EditCollection => self.edit_collection().await,
|
||||||
@@ -116,6 +121,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
RadarrEvent::GetCollections => self.get_collections().await,
|
RadarrEvent::GetCollections => self.get_collections().await,
|
||||||
RadarrEvent::GetDownloads => self.get_downloads().await,
|
RadarrEvent::GetDownloads => self.get_downloads().await,
|
||||||
RadarrEvent::GetIndexers => self.get_indexers().await,
|
RadarrEvent::GetIndexers => self.get_indexers().await,
|
||||||
|
RadarrEvent::GetIndexerSettings => self.get_indexer_settings().await,
|
||||||
RadarrEvent::GetLogs => self.get_logs().await,
|
RadarrEvent::GetLogs => self.get_logs().await,
|
||||||
RadarrEvent::GetMovieCredits => self.get_credits().await,
|
RadarrEvent::GetMovieCredits => self.get_credits().await,
|
||||||
RadarrEvent::GetMovieDetails => self.get_movie_details().await,
|
RadarrEvent::GetMovieDetails => self.get_movie_details().await,
|
||||||
@@ -138,6 +144,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
RadarrEvent::UpdateAndScan => self.update_and_scan().await,
|
RadarrEvent::UpdateAndScan => self.update_and_scan().await,
|
||||||
RadarrEvent::UpdateCollections => self.update_collections().await,
|
RadarrEvent::UpdateCollections => self.update_collections().await,
|
||||||
RadarrEvent::UpdateDownloads => self.update_downloads().await,
|
RadarrEvent::UpdateDownloads => self.update_downloads().await,
|
||||||
|
RadarrEvent::UpdateIndexerSettings => self.update_indexer_settings().await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,6 +300,37 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn delete_indexer(&self) {
|
||||||
|
let indexer_id = self
|
||||||
|
.app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexers
|
||||||
|
.current_selection()
|
||||||
|
.id
|
||||||
|
.as_u64()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Deleting Radarr indexer for indexer with id: {}",
|
||||||
|
indexer_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.radarr_request_props_from(
|
||||||
|
format!("{}/{}", RadarrEvent::DeleteIndexer.resource(), indexer_id).as_str(),
|
||||||
|
RequestMethod::Delete,
|
||||||
|
None::<()>,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), ()>(request_props, |_, _| ())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
async fn delete_movie(&self) {
|
async fn delete_movie(&self) {
|
||||||
let movie_id = self.extract_movie_id().await;
|
let movie_id = self.extract_movie_id().await;
|
||||||
let delete_files = self.app.lock().await.data.radarr_data.delete_movie_files;
|
let delete_files = self.app.lock().await.data.radarr_data.delete_movie_files;
|
||||||
@@ -644,6 +682,24 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_indexer_settings(&self) {
|
||||||
|
info!("Fetching Radarr indexer settings");
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.radarr_request_props_from(
|
||||||
|
RadarrEvent::GetIndexerSettings.resource(),
|
||||||
|
RequestMethod::Get,
|
||||||
|
None::<()>,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<(), IndexerSettings>(request_props, |indexer_settings, mut app| {
|
||||||
|
app.data.radarr_data.indexer_settings = Some(indexer_settings);
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_healthcheck(&self) {
|
async fn get_healthcheck(&self) {
|
||||||
info!("Performing Radarr health check");
|
info!("Performing Radarr health check");
|
||||||
|
|
||||||
@@ -1302,6 +1358,37 @@ impl<'a, 'b> Network<'a, 'b> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn update_indexer_settings(&self) {
|
||||||
|
info!("Updating Radarr indexer settings");
|
||||||
|
|
||||||
|
let body = self
|
||||||
|
.app
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
debug!("Indexer settings body: {:?}", body);
|
||||||
|
|
||||||
|
let request_props = self
|
||||||
|
.radarr_request_props_from(
|
||||||
|
RadarrEvent::UpdateIndexerSettings.resource(),
|
||||||
|
RequestMethod::Put,
|
||||||
|
Some(body),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self
|
||||||
|
.handle_request::<IndexerSettings, Value>(request_props, |_, _| {})
|
||||||
|
.await;
|
||||||
|
|
||||||
|
self.app.lock().await.data.radarr_data.indexer_settings = None;
|
||||||
|
}
|
||||||
|
|
||||||
async fn radarr_request_props_from<T: Serialize + Debug>(
|
async fn radarr_request_props_from<T: Serialize + Debug>(
|
||||||
&self,
|
&self,
|
||||||
resource: &str,
|
resource: &str,
|
||||||
|
|||||||
@@ -531,6 +531,44 @@ mod test {
|
|||||||
async_server.assert_async().await;
|
async_server.assert_async().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_update_indexer_settings_event() {
|
||||||
|
let indexer_settings_json = json!({
|
||||||
|
"minimumAge": 0,
|
||||||
|
"maximumSize": 0,
|
||||||
|
"retention": 0,
|
||||||
|
"rssSyncInterval": 60,
|
||||||
|
"preferIndexerFlags": false,
|
||||||
|
"availabilityDelay": 0,
|
||||||
|
"allowHardcodedSubs": true,
|
||||||
|
"whitelistedHardcodedSubs": "",
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
|
RequestMethod::Put,
|
||||||
|
Some(indexer_settings_json),
|
||||||
|
None,
|
||||||
|
RadarrEvent::UpdateIndexerSettings.resource(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
app_arc.lock().await.data.radarr_data.indexer_settings = Some(indexer_settings());
|
||||||
|
let network = Network::new(reqwest::Client::new(), &app_arc);
|
||||||
|
|
||||||
|
network
|
||||||
|
.handle_radarr_event(RadarrEvent::UpdateIndexerSettings)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
async_server.assert_async().await;
|
||||||
|
assert!(app_arc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_update_collections_event() {
|
async fn test_handle_update_collections_event() {
|
||||||
let (async_server, app_arc, _server) = mock_radarr_api(
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
@@ -873,13 +911,11 @@ mod test {
|
|||||||
"label": "Value Is String",
|
"label": "Value Is String",
|
||||||
"value": "hello",
|
"value": "hello",
|
||||||
"type": "textbox",
|
"type": "textbox",
|
||||||
"advanced": false
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"order": 1,
|
"order": 1,
|
||||||
"name": "emptyValueWithSelectOptions",
|
"name": "emptyValueWithSelectOptions",
|
||||||
"label": "Empty Value With Select Options",
|
"label": "Empty Value With Select Options",
|
||||||
"advanced": true,
|
|
||||||
"type": "select",
|
"type": "select",
|
||||||
"selectOptions": [
|
"selectOptions": [
|
||||||
{
|
{
|
||||||
@@ -895,7 +931,6 @@ mod test {
|
|||||||
"label": "Value is an array",
|
"label": "Value is an array",
|
||||||
"value": [1, 2],
|
"value": [1, 2],
|
||||||
"type": "select",
|
"type": "select",
|
||||||
"advanced": false,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"implementationName": "Torznab",
|
"implementationName": "Torznab",
|
||||||
@@ -922,6 +957,39 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_get_indexer_settings_event() {
|
||||||
|
let indexer_settings_response_json = json!({
|
||||||
|
"minimumAge": 0,
|
||||||
|
"maximumSize": 0,
|
||||||
|
"retention": 0,
|
||||||
|
"rssSyncInterval": 60,
|
||||||
|
"preferIndexerFlags": false,
|
||||||
|
"availabilityDelay": 0,
|
||||||
|
"allowHardcodedSubs": true,
|
||||||
|
"whitelistedHardcodedSubs": "",
|
||||||
|
"id": 1
|
||||||
|
});
|
||||||
|
let (async_server, app_arc, _server) = mock_radarr_api(
|
||||||
|
RequestMethod::Get,
|
||||||
|
None,
|
||||||
|
Some(indexer_settings_response_json),
|
||||||
|
RadarrEvent::GetIndexerSettings.resource(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
let network = Network::new(reqwest::Client::new(), &app_arc);
|
||||||
|
|
||||||
|
network
|
||||||
|
.handle_radarr_event(RadarrEvent::GetIndexerSettings)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
async_server.assert_async().await;
|
||||||
|
assert_eq!(
|
||||||
|
app_arc.lock().await.data.radarr_data.indexer_settings,
|
||||||
|
Some(indexer_settings())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_get_queued_events_event() {
|
async fn test_handle_get_queued_events_event() {
|
||||||
let queued_events_json = json!([{
|
let queued_events_json = json!([{
|
||||||
@@ -1362,6 +1430,27 @@ mod test {
|
|||||||
async_server.assert_async().await;
|
async_server.assert_async().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_delete_indexer_event() {
|
||||||
|
let resource = format!("{}/1", RadarrEvent::DeleteIndexer.resource());
|
||||||
|
let (async_server, app_arc, _server) =
|
||||||
|
mock_radarr_api(RequestMethod::Delete, None, None, &resource).await;
|
||||||
|
app_arc
|
||||||
|
.lock()
|
||||||
|
.await
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![indexer()]);
|
||||||
|
let network = Network::new(reqwest::Client::new(), &app_arc);
|
||||||
|
|
||||||
|
network
|
||||||
|
.handle_radarr_event(RadarrEvent::DeleteIndexer)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
async_server.assert_async().await;
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_delete_root_folder_event() {
|
async fn test_handle_delete_root_folder_event() {
|
||||||
let resource = format!("{}/1", RadarrEvent::DeleteRootFolder.resource());
|
let resource = format!("{}/1", RadarrEvent::DeleteRootFolder.resource());
|
||||||
@@ -2216,7 +2305,6 @@ mod test {
|
|||||||
name: Some("valueIsString".to_owned()),
|
name: Some("valueIsString".to_owned()),
|
||||||
label: Some("Value Is String".to_owned()),
|
label: Some("Value Is String".to_owned()),
|
||||||
value: Some(json!("hello")),
|
value: Some(json!("hello")),
|
||||||
advanced: false,
|
|
||||||
field_type: Some("textbox".to_owned()),
|
field_type: Some("textbox".to_owned()),
|
||||||
select_options: None,
|
select_options: None,
|
||||||
},
|
},
|
||||||
@@ -2225,7 +2313,6 @@ mod test {
|
|||||||
name: Some("emptyValueWithSelectOptions".to_owned()),
|
name: Some("emptyValueWithSelectOptions".to_owned()),
|
||||||
label: Some("Empty Value With Select Options".to_owned()),
|
label: Some("Empty Value With Select Options".to_owned()),
|
||||||
value: None,
|
value: None,
|
||||||
advanced: true,
|
|
||||||
field_type: Some("select".to_owned()),
|
field_type: Some("select".to_owned()),
|
||||||
select_options: Some(vec![IndexerSelectOption {
|
select_options: Some(vec![IndexerSelectOption {
|
||||||
value: Number::from(-2),
|
value: Number::from(-2),
|
||||||
@@ -2238,11 +2325,19 @@ mod test {
|
|||||||
name: Some("valueIsAnArray".to_owned()),
|
name: Some("valueIsAnArray".to_owned()),
|
||||||
label: Some("Value is an array".to_owned()),
|
label: Some("Value is an array".to_owned()),
|
||||||
value: Some(json!([1, 2])),
|
value: Some(json!([1, 2])),
|
||||||
advanced: false,
|
|
||||||
field_type: Some("select".to_owned()),
|
field_type: Some("select".to_owned()),
|
||||||
select_options: None,
|
select_options: None,
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn indexer_settings() -> IndexerSettings {
|
||||||
|
IndexerSettings {
|
||||||
|
rss_sync_interval: Number::from(60),
|
||||||
|
allow_hardcoded_subs: true,
|
||||||
|
id: Number::from(1),
|
||||||
|
..IndexerSettings::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,17 +9,24 @@ use crate::app::App;
|
|||||||
use crate::models::radarr_models::Indexer;
|
use crate::models::radarr_models::Indexer;
|
||||||
use crate::models::Route;
|
use crate::models::Route;
|
||||||
use crate::ui::utils::{layout_block_top_border, style_failure, style_primary, style_success};
|
use crate::ui::utils::{layout_block_top_border, style_failure, style_primary, style_success};
|
||||||
use crate::ui::{draw_table, DrawUi, TableProps};
|
use crate::ui::{draw_prompt_box, draw_prompt_popup_over, draw_table, DrawUi, TableProps};
|
||||||
|
|
||||||
pub(super) struct IndexersUi {}
|
pub(super) struct IndexersUi {}
|
||||||
|
|
||||||
impl DrawUi for IndexersUi {
|
impl DrawUi for IndexersUi {
|
||||||
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
fn draw<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, content_rect: Rect) {
|
||||||
if matches!(
|
if let Route::Radarr(active_radarr_block, _) = *app.get_current_route() {
|
||||||
*app.get_current_route(),
|
match active_radarr_block {
|
||||||
Route::Radarr(ActiveRadarrBlock::Indexers, _)
|
ActiveRadarrBlock::Indexers => draw_indexers(f, app, content_rect),
|
||||||
) {
|
ActiveRadarrBlock::DeleteIndexerPrompt => draw_prompt_popup_over(
|
||||||
draw_indexers(f, app, content_rect);
|
f,
|
||||||
|
app,
|
||||||
|
content_rect,
|
||||||
|
draw_indexers,
|
||||||
|
draw_delete_indexer_prompt,
|
||||||
|
),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,3 +101,28 @@ fn draw_indexers<B: Backend>(f: &mut Frame<'_, B>, app: &mut App<'_>, area: Rect
|
|||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_delete_indexer_prompt<B: Backend>(
|
||||||
|
f: &mut Frame<'_, B>,
|
||||||
|
app: &mut App<'_>,
|
||||||
|
prompt_area: Rect,
|
||||||
|
) {
|
||||||
|
draw_prompt_box(
|
||||||
|
f,
|
||||||
|
prompt_area,
|
||||||
|
"Delete Indexer",
|
||||||
|
format!(
|
||||||
|
"Do you really want to delete this indexer: {}?",
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexers
|
||||||
|
.current_selection()
|
||||||
|
.name
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default()
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
app.data.radarr_data.prompt_confirm,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use tui::Frame;
|
|||||||
|
|
||||||
use crate::app::radarr::{
|
use crate::app::radarr::{
|
||||||
ActiveRadarrBlock, RadarrData, ADD_MOVIE_BLOCKS, COLLECTION_DETAILS_BLOCKS, DELETE_MOVIE_BLOCKS,
|
ActiveRadarrBlock, RadarrData, ADD_MOVIE_BLOCKS, COLLECTION_DETAILS_BLOCKS, DELETE_MOVIE_BLOCKS,
|
||||||
EDIT_COLLECTION_BLOCKS, EDIT_MOVIE_BLOCKS, FILTER_BLOCKS, MOVIE_DETAILS_BLOCKS, SEARCH_BLOCKS,
|
EDIT_COLLECTION_BLOCKS, EDIT_MOVIE_BLOCKS, FILTER_BLOCKS, INDEXER_BLOCKS, MOVIE_DETAILS_BLOCKS,
|
||||||
SYSTEM_DETAILS_BLOCKS,
|
SEARCH_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::logos::RADARR_LOGO;
|
use crate::logos::RADARR_LOGO;
|
||||||
@@ -74,7 +74,9 @@ impl DrawUi for RadarrUi {
|
|||||||
ActiveRadarrBlock::Downloads
|
ActiveRadarrBlock::Downloads
|
||||||
| ActiveRadarrBlock::DeleteDownloadPrompt
|
| ActiveRadarrBlock::DeleteDownloadPrompt
|
||||||
| ActiveRadarrBlock::UpdateDownloadsPrompt => DownloadsUi::draw(f, app, content_rect),
|
| ActiveRadarrBlock::UpdateDownloadsPrompt => DownloadsUi::draw(f, app, content_rect),
|
||||||
ActiveRadarrBlock::Indexers => IndexersUi::draw(f, app, content_rect),
|
_ if INDEXER_BLOCKS.contains(&active_radarr_block) => {
|
||||||
|
IndexersUi::draw(f, app, content_rect)
|
||||||
|
}
|
||||||
ActiveRadarrBlock::RootFolders
|
ActiveRadarrBlock::RootFolders
|
||||||
| ActiveRadarrBlock::AddRootFolderPrompt
|
| ActiveRadarrBlock::AddRootFolderPrompt
|
||||||
| ActiveRadarrBlock::DeleteRootFolderPrompt => RootFoldersUi::draw(f, app, content_rect),
|
| ActiveRadarrBlock::DeleteRootFolderPrompt => RootFoldersUi::draw(f, app, content_rect),
|
||||||
|
|||||||
Reference in New Issue
Block a user