Compare commits

..

15 Commits

Author SHA1 Message Date
Dark-Alex-17 1ff31b1bd9 Updated codecov config to also ignore the ui directory entirely, since it's not very conducive to tests as it is 2024-11-03 16:05:17 -07:00
Dark-Alex-17 ce4cbd8652 Updated codecov config to ignore test files 2024-11-03 16:01:49 -07:00
Dark-Alex-17 346d95f8ec Added Codecov config 2024-11-03 15:57:18 -07:00
Dark-Alex-17 85ea05e3c8 Incremented minor release since removing the --disable-terminal-size-checks flag is a breaking change, but the application is not yet ready for a 1.0 release. 2024-11-03 15:42:59 -07:00
Dark-Alex-17 93d78701ce fix:fixed divide by zero panic when download size is unknown 2024-11-03 15:36:26 -07:00
Dark-Alex-17 8d7cb63c7a Remove the terminal size checks since they've caused so many issues since their introduction 2024-11-03 15:33:08 -07:00
Dark-Alex-17 c8c7d00517 Added environment variables section to the README for added visibility into the feature 2024-11-03 15:06:24 -07:00
Alex Clarke 9402ad3f3b Merge pull request #9 from tangowithfoxtrot/add-env-var-config-options
Add environment variables for --config and terminal size check args
2024-11-03 14:43:50 -07:00
tangowithfoxtrot ea9a9070ce Merge branch 'rc/v0.1.6-address-community-comments' into add-env-var-config-options 2024-11-03 13:40:53 -08:00
Dark-Alex-17 a0fe51c57b Added help that's always visible for modals with new shortcuts for accepting all modals, or closing all modals without the need of seeing the UI 2024-11-03 14:25:33 -07:00
tangowithfoxtrot 9326428141 feat: allow configuration via env vars 2024-11-03 11:20:15 -08:00
Alex Clarke c1da8592b4 Merge pull request #7 from Dark-Alex-17/release-plz-2024-11-03T00-33-10Z
chore: release v0.1.5
2024-11-02 18:37:24 -06:00
github-actions[bot] aa43219c29 chore: release v0.1.5 2024-11-03 00:33:11 +00:00
Dark-Alex-17 f6f477b124 Added HTTPS support for all Servarrs 2024-11-02 18:32:44 -06:00
Alex Clarke 76f22e7434 Merge pull request #5 from Dark-Alex-17/release-plz-2024-11-01T19-06-52Z
chore: release v0.1.4
2024-11-01 13:13:03 -06:00
62 changed files with 1128 additions and 254 deletions
+6
View File
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [0.1.5](https://github.com/Dark-Alex-17/managarr/compare/v0.1.4...v0.1.5) - 2024-11-03
### Other
- Added HTTPS support for all Servarrs
## [0.1.4](https://github.com/Dark-Alex-17/managarr/compare/v0.1.3...v0.1.4) - 2024-11-01 ## [0.1.4](https://github.com/Dark-Alex-17/managarr/compare/v0.1.3...v0.1.4) - 2024-11-01
### Other ### Other
Generated
+1 -1
View File
@@ -1148,7 +1148,7 @@ dependencies = [
[[package]] [[package]]
name = "managarr" name = "managarr"
version = "0.1.4" version = "0.2.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",
+3 -3
View File
@@ -1,9 +1,9 @@
[package] [package]
name = "managarr" name = "managarr"
version = "0.1.4" version = "0.2.0"
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"] authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
description = "A TUI and CLI to manage your Servarrs" description = "A TUI and CLI to manage your Servarrs"
keywords = ["managarr", "tui-rs", "dashboard", "servarr", "tui"] keywords = ["managarr", "ratatui", "dashboard", "servarr", "tui"]
documentation = "https://github.com/Dark-Alex-17/managarr" documentation = "https://github.com/Dark-Alex-17/managarr"
repository = "https://github.com/Dark-Alex-17/managarr" repository = "https://github.com/Dark-Alex-17/managarr"
homepage = "https://github.com/Dark-Alex-17/managarr" homepage = "https://github.com/Dark-Alex-17/managarr"
@@ -38,7 +38,7 @@ tokio = { version = "1.36.0", features = ["full"] }
tokio-util = "0.7.8" tokio-util = "0.7.8"
ratatui = { version = "0.28.0", features = ["all-widgets"] } ratatui = { version = "0.28.0", features = ["all-widgets"] }
urlencoding = "2.1.2" urlencoding = "2.1.2"
clap = { version = "4.5.20", features = ["derive", "cargo"] } clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
clap_complete = "4.5.33" clap_complete = "4.5.33"
itertools = "0.13.0" itertools = "0.13.0"
ctrlc = "3.4.5" ctrlc = "3.4.5"
+16 -3
View File
@@ -113,7 +113,7 @@ To see all available commands, simply run `managarr --help`:
```shell ```shell
$ managarr --help $ managarr --help
managarr 0.1.3 managarr 0.1.5
Alex Clarke <alex.j.tusa@gmail.com> Alex Clarke <alex.j.tusa@gmail.com>
A TUI and CLI to manage your Servarrs A TUI and CLI to manage your Servarrs
@@ -127,7 +127,6 @@ Commands:
Options: Options:
--config <CONFIG> The Managarr configuration file to use --config <CONFIG> The Managarr configuration file to use
--disable-terminal-size-checks Disable the terminal size checks
-h, --help Print help -h, --help Print help
-V, --version Print version -V, --version Print version
``` ```
@@ -159,7 +158,6 @@ Commands:
Options: Options:
--config <CONFIG> The Managarr configuration file to use --config <CONFIG> The Managarr configuration file to use
--disable-terminal-size-checks Disable the terminal size checks
-h, --help Print help -h, --help Print help
``` ```
@@ -206,6 +204,8 @@ radarr:
host: 127.0.0.1 host: 127.0.0.1
port: 7878 port: 7878
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: true
ssl_cert_path: /path/to/radarr.crt
sonarr: sonarr:
host: 127.0.0.1 host: 127.0.0.1
port: 8989 port: 8989
@@ -214,28 +214,41 @@ readarr:
host: 127.0.0.1 host: 127.0.0.1
port: 8787 port: 8787
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
lidarr: lidarr:
host: 127.0.0.1 host: 127.0.0.1
port: 8686 port: 8686
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
whisparr: whisparr:
host: 127.0.0.1 host: 127.0.0.1
port: 6969 port: 6969
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
bazarr: bazarr:
host: 127.0.0.1 host: 127.0.0.1
port: 6767 port: 6767
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
prowlarr: prowlarr:
host: 127.0.0.1 host: 127.0.0.1
port: 9696 port: 9696
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
tautulli: tautulli:
host: 127.0.0.1 host: 127.0.0.1
port: 8181 port: 8181
api_token: someApiToken1234567890 api_token: someApiToken1234567890
use_ssl: false
``` ```
## Environment Variables
Managarr supports using environment variables on startup so you don't have to always specify certain flags:
| Variable | Description | Equivalent Flag |
| --------------------------------------- | -------------------------------- | -------------------------------- |
| `MANAGARR_CONFIG_FILE` | Set the path to the config file | `--config` |
## Track My Progress for the Beta release (With Sonarr Support!) ## Track My Progress for the Beta release (With Sonarr Support!)
Progress for the beta release can be followed on my [Wekan Board](https://wekan.alexjclarke.com/b/dHoGjBb44MHM9HSv4/managarr) Progress for the beta release can be followed on my [Wekan Board](https://wekan.alexjclarke.com/b/dHoGjBb44MHM9HSv4/managarr)
with all items tagged `Beta`. with all items tagged `Beta`.
+6
View File
@@ -0,0 +1,6 @@
coverage:
range: "80..100"
ignore:
- "**/*_tests.rs"
- "src/ui"
+2
View File
@@ -224,5 +224,7 @@ mod tests {
assert_str_eq!(radarr_config.host, "localhost"); assert_str_eq!(radarr_config.host, "localhost");
assert_eq!(radarr_config.port, Some(7878)); assert_eq!(radarr_config.port, Some(7878));
assert!(radarr_config.api_token.is_empty()); assert!(radarr_config.api_token.is_empty());
assert!(!radarr_config.use_ssl);
assert_eq!(radarr_config.ssl_cert_path, None);
} }
} }
+5
View File
@@ -33,6 +33,7 @@ generate_keybindings! {
tab, tab,
delete, delete,
submit, submit,
confirm,
quit, quit,
esc esc
} }
@@ -140,6 +141,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
key: Key::Enter, key: Key::Enter,
desc: "submit", desc: "submit",
}, },
confirm: KeyBinding {
key: Key::Ctrl('s'),
desc: "submit",
},
quit: KeyBinding { quit: KeyBinding {
key: Key::Char('q'), key: Key::Char('q'),
desc: "quit", desc: "quit",
+1
View File
@@ -31,6 +31,7 @@ mod test {
#[case(DEFAULT_KEYBINDINGS.tab, Key::Tab, "tab")] #[case(DEFAULT_KEYBINDINGS.tab, Key::Tab, "tab")]
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")] #[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")]
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")] #[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")]
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), "submit")]
#[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), "quit")] #[case(DEFAULT_KEYBINDINGS.quit, Key::Char('q'), "quit")]
#[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, "close")] #[case(DEFAULT_KEYBINDINGS.esc, Key::Esc, "close")]
fn test_default_key_bindings_and_descriptions( fn test_default_key_bindings_and_descriptions(
+5
View File
@@ -176,6 +176,9 @@ pub struct RadarrConfig {
pub host: String, pub host: String,
pub port: Option<u16>, pub port: Option<u16>,
pub api_token: String, pub api_token: String,
#[serde(default)]
pub use_ssl: bool,
pub ssl_cert_path: Option<String>,
} }
impl Default for RadarrConfig { impl Default for RadarrConfig {
@@ -184,6 +187,8 @@ impl Default for RadarrConfig {
host: "localhost".to_string(), host: "localhost".to_string(),
port: Some(7878), port: Some(7878),
api_token: "".to_string(), api_token: "".to_string(),
use_ssl: false,
ssl_cert_path: None,
} }
} }
} }
+5
View File
@@ -120,6 +120,11 @@ pub static ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
(DEFAULT_KEYBINDINGS.esc, "edit search"), (DEFAULT_KEYBINDINGS.esc, "edit search"),
]; ];
pub static CONFIRMATION_PROMPT_CONTEXT_CLUES: [ContextClue; 2] = [
(DEFAULT_KEYBINDINGS.confirm, "submit"),
(DEFAULT_KEYBINDINGS.esc, "cancel"),
];
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [ pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
(DEFAULT_KEYBINDINGS.submit, "start task"), (DEFAULT_KEYBINDINGS.submit, "start task"),
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
+18 -2
View File
@@ -5,8 +5,8 @@ mod tests {
use crate::app::key_binding::DEFAULT_KEYBINDINGS; use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::radarr::radarr_context_clues::{ use crate::app::radarr::radarr_context_clues::{
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES, ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES,
COLLECTION_DETAILS_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES, COLLECTION_DETAILS_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
SYSTEM_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES,
}; };
@@ -349,6 +349,22 @@ mod tests {
assert_eq!(add_movie_search_results_context_clues_iter.next(), None); assert_eq!(add_movie_search_results_context_clues_iter.next(), None);
} }
#[test]
fn test_confirmation_prompt_context_clues() {
let mut confirmation_prompt_context_clues_iter = CONFIRMATION_PROMPT_CONTEXT_CLUES.iter();
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.confirm);
assert_str_eq!(*description, "submit");
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
assert_str_eq!(*description, "cancel");
assert_eq!(confirmation_prompt_context_clues_iter.next(), None);
}
#[test] #[test]
fn test_system_tasks_context_clues() { fn test_system_tasks_context_clues() {
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter(); let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
@@ -584,6 +584,9 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use crate::network::radarr_network::RadarrEvent;
use super::*; use super::*;
@@ -716,6 +719,43 @@ mod tests {
assert!(app.data.radarr_data.blocklist.sort.is_none()); assert!(app.data.radarr_data.blocklist.sort.is_none());
assert!(!app.data.radarr_data.blocklist.sort_asc); assert!(!app.data.radarr_data.blocklist.sort_asc);
} }
#[rstest]
#[case(
ActiveRadarrBlock::Blocklist,
ActiveRadarrBlock::DeleteBlocklistItemPrompt,
RadarrEvent::DeleteBlocklistItem(None)
)]
#[case(
ActiveRadarrBlock::Blocklist,
ActiveRadarrBlock::BlocklistClearAllItemsPrompt,
RadarrEvent::ClearBlocklist
)]
fn test_blocklist_prompt_confirm(
#[case] base_route: ActiveRadarrBlock,
#[case] prompt_block: ActiveRadarrBlock,
#[case] expected_action: RadarrEvent,
) {
let mut app = App::default();
app.data.radarr_data.blocklist.set_items(blocklist_vec());
app.push_navigation_stack(base_route.into());
app.push_navigation_stack(prompt_block.into());
BlocklistHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&prompt_block,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(expected_action)
);
assert_eq!(app.get_current_route(), &base_route.into());
}
} }
#[test] #[test]
+20 -2
View File
@@ -182,8 +182,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
let key = self.key; let key = self.key;
if self.active_radarr_block == &ActiveRadarrBlock::Blocklist { match self.active_radarr_block {
match self.key { ActiveRadarrBlock::Blocklist => match self.key {
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => { _ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
@@ -204,7 +204,25 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
.push_navigation_stack(ActiveRadarrBlock::BlocklistSortPrompt.into()); .push_navigation_stack(ActiveRadarrBlock::BlocklistSortPrompt.into());
} }
_ => (), _ => (),
},
ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DeleteBlocklistItem(None));
self.app.pop_navigation_stack();
}
} }
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
self.app.pop_navigation_stack();
}
}
_ => (),
} }
} }
} }
@@ -1040,6 +1040,7 @@ mod tests {
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
RadarrData, EDIT_COLLECTION_SELECTION_BLOCKS, RadarrData, EDIT_COLLECTION_SELECTION_BLOCKS,
}; };
use crate::network::radarr_network::RadarrEvent;
use crate::test_edit_collection_key; use crate::test_edit_collection_key;
use super::*; use super::*;
@@ -1509,6 +1510,36 @@ mod tests {
assert!(app.data.radarr_data.collections.sort.is_none()); assert!(app.data.radarr_data.collections.sort.is_none());
assert!(!app.data.radarr_data.collections.sort_asc); assert!(!app.data.radarr_data.collections.sort_asc);
} }
#[test]
fn test_update_all_collections_prompt_confirm_confirm() {
let mut app = App::default();
app
.data
.radarr_data
.collections
.set_items(vec![Collection::default()]);
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
CollectionsHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::UpdateAllCollectionsPrompt,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::UpdateCollections)
);
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::Collections.into()
);
}
} }
#[rstest] #[rstest]
@@ -291,19 +291,34 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
let key = self.key; let key = self.key;
if self.active_radarr_block == &ActiveRadarrBlock::EditCollectionRootFolderPathInput { match self.active_radarr_block {
handle_text_box_keys!( ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
self, handle_text_box_keys!(
key, self,
self key,
.app self
.data .app
.radarr_data .data
.edit_collection_modal .radarr_data
.as_mut() .edit_collection_modal
.unwrap() .as_mut()
.path .unwrap()
) .path
)
}
ActiveRadarrBlock::EditCollectionPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::EditCollectionConfirmPrompt
&& *key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(None));
self.app.should_refresh = true;
self.app.pop_navigation_stack();
}
}
_ => (),
} }
} }
} }
@@ -871,7 +871,15 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use super::*; use super::*;
use crate::models::servarr_data::radarr::modals::EditCollectionModal; use crate::{
models::{
servarr_data::radarr::{
modals::EditCollectionModal, radarr_data::EDIT_COLLECTION_SELECTION_BLOCKS,
},
BlockSelectionState,
},
network::radarr_network::RadarrEvent,
};
#[test] #[test]
fn test_edit_collection_root_folder_path_input_backspace() { fn test_edit_collection_root_folder_path_input_backspace() {
@@ -927,6 +935,39 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_edit_collection_confirm_prompt_prompt_confirmation_confirm() {
let mut app = App::default();
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditCollectionHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::EditCollectionPrompt,
&None,
)
.handle();
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::Collections.into()
);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::EditCollection(None))
);
assert!(app.should_refresh);
}
} }
#[test] #[test]
@@ -385,6 +385,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
.unwrap() .unwrap()
) )
} }
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -349,6 +349,9 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use rstest::rstest;
use crate::network::radarr_network::RadarrEvent;
use super::*; use super::*;
@@ -450,6 +453,47 @@ mod tests {
); );
assert!(!app.should_refresh); assert!(!app.should_refresh);
} }
#[rstest]
#[case(
ActiveRadarrBlock::Downloads,
ActiveRadarrBlock::DeleteDownloadPrompt,
RadarrEvent::DeleteDownload(None)
)]
#[case(
ActiveRadarrBlock::Downloads,
ActiveRadarrBlock::UpdateDownloadsPrompt,
RadarrEvent::UpdateDownloads
)]
fn test_downloads_prompt_confirm_submit(
#[case] base_route: ActiveRadarrBlock,
#[case] prompt_block: ActiveRadarrBlock,
#[case] expected_action: RadarrEvent,
) {
let mut app = App::default();
app
.data
.radarr_data
.downloads
.set_items(vec![DownloadRecord::default()]);
app.push_navigation_stack(base_route.into());
app.push_navigation_stack(prompt_block.into());
DownloadsHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&prompt_block,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(expected_action)
);
assert_eq!(app.get_current_route(), &base_route.into());
}
} }
#[test] #[test]
+19 -2
View File
@@ -119,8 +119,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
let key = self.key; let key = self.key;
if self.active_radarr_block == &ActiveRadarrBlock::Downloads { match self.active_radarr_block {
match self.key { ActiveRadarrBlock::Downloads => match self.key {
_ if *key == DEFAULT_KEYBINDINGS.update.key => { _ if *key == DEFAULT_KEYBINDINGS.update.key => {
self self
.app .app
@@ -130,7 +130,24 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
self.app.should_refresh = true; self.app.should_refresh = true;
} }
_ => (), _ => (),
},
ActiveRadarrBlock::DeleteDownloadPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteDownload(None));
self.app.pop_navigation_stack();
}
} }
ActiveRadarrBlock::UpdateDownloadsPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
self.app.pop_navigation_stack();
}
}
_ => (),
} }
} }
} }
@@ -429,6 +429,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
.tags .tags
); );
} }
ActiveRadarrBlock::EditIndexerPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::EditIndexerConfirmPrompt
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditIndexer(None));
self.app.should_refresh = true;
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -1282,6 +1282,9 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::modals::EditIndexerModal; use crate::models::servarr_data::radarr::modals::EditIndexerModal;
use crate::models::servarr_data::radarr::radarr_data::EDIT_INDEXER_TORRENT_SELECTION_BLOCKS;
use crate::models::BlockSelectionState;
use crate::network::radarr_network::RadarrEvent;
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use super::*; use super::*;
@@ -1560,6 +1563,37 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_edit_indexer_prompt_prompt_confirmation_confirm() {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.push_navigation_stack(ActiveRadarrBlock::EditIndexerPrompt.into());
app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_INDEXER_TORRENT_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_INDEXER_TORRENT_SELECTION_BLOCKS.len() - 1);
app.data.radarr_data.edit_indexer_modal = Some(EditIndexerModal::default());
EditIndexerHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::EditIndexerPrompt,
&None,
)
.handle();
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
assert!(app.data.radarr_data.edit_indexer_modal.is_some());
assert!(app.should_refresh);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::EditIndexer(None))
);
}
} }
#[test] #[test]
@@ -241,19 +241,35 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
} }
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
if self.active_radarr_block == &ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput { match self.active_radarr_block {
handle_text_box_keys!( ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => {
self, handle_text_box_keys!(
self.key, self,
self self.key,
.app self
.data .app
.radarr_data .data
.indexer_settings .radarr_data
.as_mut() .indexer_settings
.unwrap() .as_mut()
.whitelisted_hardcoded_subs .unwrap()
) .whitelisted_hardcoded_subs
)
}
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::IndexerSettingsConfirmPrompt
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::EditAllIndexerSettings(None));
self.app.should_refresh = true;
self.app.pop_navigation_stack();
}
}
_ => (),
} }
} }
} }
@@ -851,7 +851,13 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use crate::models::radarr_models::IndexerSettings; use crate::{
models::{
radarr_models::IndexerSettings,
servarr_data::radarr::radarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS, BlockSelectionState,
},
network::radarr_network::RadarrEvent,
};
use super::*; use super::*;
@@ -909,6 +915,37 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_edit_indexer_settings_prompt_prompt_confirmation_confirm() {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
app.data.radarr_data.selected_block =
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
IndexerSettingsHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
&None,
)
.handle();
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::EditAllIndexerSettings(None))
);
assert!(app.data.radarr_data.indexer_settings.is_some());
assert!(app.should_refresh);
}
} }
#[test] #[test]
@@ -464,7 +464,10 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use crate::models::servarr_data::radarr::radarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS; use crate::{
models::servarr_data::radarr::radarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS,
network::radarr_network::RadarrEvent,
};
use super::*; use super::*;
@@ -696,6 +699,33 @@ mod tests {
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into()); assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
} }
#[test]
fn test_delete_indexer_prompt_confirm() {
let mut app = App::default();
app
.data
.radarr_data
.indexers
.set_items(vec![Indexer::default()]);
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
IndexersHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::DeleteIndexerPrompt,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::DeleteIndexer(None))
);
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
}
} }
#[rstest] #[rstest]
+11 -2
View File
@@ -166,8 +166,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
fn handle_char_key_event(&mut self) { fn handle_char_key_event(&mut self) {
let key = self.key; let key = self.key;
if self.active_radarr_block == &ActiveRadarrBlock::Indexers { match self.active_radarr_block {
match self.key { ActiveRadarrBlock::Indexers => match self.key {
_ if *key == DEFAULT_KEYBINDINGS.add.key => { _ if *key == DEFAULT_KEYBINDINGS.add.key => {
self self
.app .app
@@ -194,7 +194,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS); BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
} }
_ => (), _ => (),
},
ActiveRadarrBlock::DeleteIndexerPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteIndexer(None));
self.app.pop_navigation_stack();
}
} }
_ => (),
} }
} }
} }
@@ -461,6 +461,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
.tags .tags
) )
} }
ActiveRadarrBlock::AddMoviePrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::AddMovieConfirmPrompt
&& *key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::AddMovie(None));
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -1494,7 +1494,13 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use super::*; use super::*;
use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::{
models::{
servarr_data::radarr::{modals::AddMovieModal, radarr_data::ADD_MOVIE_SELECTION_BLOCKS},
BlockSelectionState,
},
network::radarr_network::RadarrEvent,
};
#[test] #[test]
fn test_add_movie_search_input_backspace() { fn test_add_movie_search_input_backspace() {
@@ -1588,6 +1594,35 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_add_movie_confirm_prompt_prompt_confirmation_confirm() {
let mut app = App::default();
app.data.radarr_data.add_movie_modal = Some(AddMovieModal::default());
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
AddMovieHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::AddMoviePrompt,
&None,
)
.handle();
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::AddMovie(None))
);
assert!(app.data.radarr_data.add_movie_modal.is_some());
}
} }
#[test] #[test]
@@ -1,3 +1,4 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App; use crate::app::App;
use crate::event::Key; use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler}; use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
@@ -100,5 +101,17 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
} }
} }
fn handle_char_key_event(&mut self) {} fn handle_char_key_event(&mut self) {
if self.active_radarr_block == &ActiveRadarrBlock::DeleteMoviePrompt
&& self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::DeleteMovieConfirmPrompt
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteMovie(None));
self.app.should_refresh = true;
self.app.pop_navigation_stack();
}
}
} }
@@ -250,6 +250,51 @@ mod tests {
} }
} }
mod test_handle_key_char {
use crate::{
models::{
servarr_data::radarr::radarr_data::DELETE_MOVIE_SELECTION_BLOCKS, BlockSelectionState,
},
network::radarr_network::RadarrEvent,
};
use super::*;
#[test]
fn test_delete_movie_confirm_prompt_prompt_confirm() {
let mut app = App::default();
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
app.data.radarr_data.delete_movie_files = true;
app.data.radarr_data.add_list_exclusion = true;
app.data.radarr_data.selected_block =
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
DeleteMovieHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::DeleteMoviePrompt,
&None,
)
.handle();
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::DeleteMovie(None))
);
assert!(app.should_refresh);
assert!(app.data.radarr_data.prompt_confirm);
assert!(app.data.radarr_data.delete_movie_files);
assert!(app.data.radarr_data.add_list_exclusion);
}
}
#[test] #[test]
fn test_delete_movie_handler_accepts() { fn test_delete_movie_handler_accepts() {
ActiveRadarrBlock::iter().for_each(|active_radarr_block| { ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
@@ -327,6 +327,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
.tags .tags
) )
} }
ActiveRadarrBlock::EditMoviePrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::EditMovieConfirmPrompt
&& *key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditMovie(None));
self.app.should_refresh = true;
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -940,7 +940,16 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use super::*; use super::*;
use crate::models::servarr_data::radarr::modals::EditMovieModal; use crate::{
models::{
servarr_data::radarr::{
modals::EditMovieModal,
radarr_data::{EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS},
},
BlockSelectionState,
},
network::radarr_network::RadarrEvent,
};
#[test] #[test]
fn test_edit_movie_path_input_backspace() { fn test_edit_movie_path_input_backspace() {
@@ -1051,6 +1060,36 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_edit_movie_confirm_prompt_prompt_confirm() {
let mut app = App::default();
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
app
.data
.radarr_data
.selected_block
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
EditMovieHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::EditMoviePrompt,
&None,
)
.handle();
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::EditMovie(None))
);
assert!(app.data.radarr_data.edit_movie_modal.is_some());
assert!(app.should_refresh);
}
} }
#[test] #[test]
@@ -996,6 +996,7 @@ mod tests {
RadarrData, EDIT_MOVIE_SELECTION_BLOCKS, RadarrData, EDIT_MOVIE_SELECTION_BLOCKS,
}; };
use crate::network::radarr_network::RadarrEvent;
use crate::test_edit_movie_key; use crate::test_edit_movie_key;
use super::*; use super::*;
@@ -1452,6 +1453,33 @@ mod tests {
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into()); assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
assert!(app.data.radarr_data.movies.sort.is_none()); assert!(app.data.radarr_data.movies.sort.is_none());
} }
#[test]
fn test_update_all_movies_prompt_confirm() {
let mut app = App::default();
app
.data
.radarr_data
.movies
.set_items(vec![Movie::default()]);
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
app.push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into());
LibraryHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::UpdateAllMoviesPrompt,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::UpdateAllMovies)
);
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
}
} }
#[rstest] #[rstest]
@@ -386,6 +386,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
self.app.data.radarr_data.movies.filter.as_mut().unwrap() self.app.data.radarr_data.movies.filter.as_mut().unwrap()
) )
} }
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -464,6 +464,32 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
} }
_ => (), _ => (),
}, },
ActiveRadarrBlock::AutomaticallySearchMoviePrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::TriggerAutomaticSearch(None));
self.app.pop_navigation_stack();
}
}
ActiveRadarrBlock::UpdateAndScanPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAndScan(None));
self.app.pop_navigation_stack();
}
}
ActiveRadarrBlock::ManualSearchConfirmPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DownloadRelease(None));
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -1468,6 +1468,7 @@ mod tests {
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
RadarrData, EDIT_MOVIE_SELECTION_BLOCKS, RadarrData, EDIT_MOVIE_SELECTION_BLOCKS,
}; };
use crate::network::radarr_network::RadarrEvent;
use crate::test_edit_movie_key; use crate::test_edit_movie_key;
use super::*; use super::*;
@@ -1780,6 +1781,50 @@ mod tests {
assert_eq!(app.get_current_route(), &active_radarr_block.into()); assert_eq!(app.get_current_route(), &active_radarr_block.into());
assert!(app.is_routing); assert!(app.is_routing);
} }
#[rstest]
#[case(
ActiveRadarrBlock::AutomaticallySearchMoviePrompt,
RadarrEvent::TriggerAutomaticSearch(None)
)]
#[case(
ActiveRadarrBlock::UpdateAndScanPrompt,
RadarrEvent::UpdateAndScan(None)
)]
#[case(
ActiveRadarrBlock::ManualSearchConfirmPrompt,
RadarrEvent::DownloadRelease(None)
)]
fn test_movie_info_prompt_confirm(
#[case] prompt_block: ActiveRadarrBlock,
#[case] expected_action: RadarrEvent,
) {
let mut app = App::default();
app.data.radarr_data.movie_details_modal = Some(MovieDetailsModal {
movie_details: ScrollableText::with_string("test".to_owned()),
..MovieDetailsModal::default()
});
app.push_navigation_stack(ActiveRadarrBlock::MovieDetails.into());
app.push_navigation_stack(prompt_block.into());
MovieDetailsHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&prompt_block,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::MovieDetails.into()
);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(expected_action)
);
}
} }
#[test] #[test]
@@ -180,6 +180,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
self.app.data.radarr_data.edit_root_folder.as_mut().unwrap() self.app.data.radarr_data.edit_root_folder.as_mut().unwrap()
) )
} }
ActiveRadarrBlock::DeleteRootFolderPrompt => {
if *key == DEFAULT_KEYBINDINGS.confirm.key {
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action =
Some(RadarrEvent::DeleteRootFolder(None));
self.app.pop_navigation_stack();
}
}
_ => (), _ => (),
} }
} }
@@ -554,6 +554,8 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use crate::network::radarr_network::RadarrEvent;
use super::*; use super::*;
#[test] #[test]
@@ -706,6 +708,36 @@ mod tests {
"h" "h"
); );
} }
#[test]
fn test_delete_root_folder_prompt_confirm() {
let mut app = App::default();
app
.data
.radarr_data
.root_folders
.set_items(vec![RootFolder::default()]);
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
RootFoldersHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::DeleteRootFolderPrompt,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::DeleteRootFolder(None))
);
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::RootFolders.into()
);
}
} }
#[test] #[test]
@@ -168,5 +168,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
{ {
self.app.should_refresh = true; self.app.should_refresh = true;
} }
if self.active_radarr_block == &ActiveRadarrBlock::SystemTaskStartConfirmPrompt
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
{
self.app.data.radarr_data.prompt_confirm = true;
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::StartTask(None));
self.app.pop_navigation_stack();
}
} }
} }
@@ -858,6 +858,8 @@ mod tests {
mod test_handle_key_char { mod test_handle_key_char {
use rstest::rstest; use rstest::rstest;
use crate::network::radarr_network::RadarrEvent;
use super::*; use super::*;
#[rstest] #[rstest]
@@ -912,6 +914,32 @@ mod tests {
assert_eq!(app.get_current_route(), &active_radarr_block.into()); assert_eq!(app.get_current_route(), &active_radarr_block.into());
assert!(!app.should_refresh); assert!(!app.should_refresh);
} }
#[test]
fn test_system_tasks_start_task_prompt_confirm() {
let mut app = App::default();
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
SystemDetailsHandler::with(
&DEFAULT_KEYBINDINGS.confirm.key,
&mut app,
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
&None,
)
.handle();
assert!(app.data.radarr_data.prompt_confirm);
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::StartTask(None))
);
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::SystemTasks.into()
);
}
} }
#[test] #[test]
+67 -32
View File
@@ -1,6 +1,6 @@
#![warn(rust_2018_idioms)] #![warn(rust_2018_idioms)]
use std::fs::File; use std::fs::{self, File};
use std::io::BufReader; use std::io::BufReader;
use std::panic::PanicHookInfo; use std::panic::PanicHookInfo;
use std::path::PathBuf; use std::path::PathBuf;
@@ -18,12 +18,13 @@ use clap_complete::generate;
use colored::Colorize; use colored::Colorize;
use crossterm::execute; use crossterm::execute;
use crossterm::terminal::{ use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, size, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
}; };
use log::error; use log::error;
use network::NetworkTrait; use network::NetworkTrait;
use ratatui::backend::CrosstermBackend; use ratatui::backend::CrosstermBackend;
use ratatui::Terminal; use ratatui::Terminal;
use reqwest::{Certificate, Client};
use tokio::sync::mpsc::Receiver; use tokio::sync::mpsc::Receiver;
use tokio::sync::{mpsc, Mutex}; use tokio::sync::{mpsc, Mutex};
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
@@ -45,9 +46,6 @@ mod network;
mod ui; mod ui;
mod utils; mod utils;
static MIN_TERM_WIDTH: u16 = 205;
static MIN_TERM_HEIGHT: u16 = 40;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
#[command( #[command(
name = crate_name!(), name = crate_name!(),
@@ -70,18 +68,10 @@ struct Cli {
long, long,
global = true, global = true,
value_parser, value_parser,
env = "MANAGARR_CONFIG_FILE",
help = "The Managarr configuration file to use" help = "The Managarr configuration file to use"
)] )]
config: Option<PathBuf>, config: Option<PathBuf>,
#[arg(long, global = true, help = "Disable the terminal size checks")]
disable_terminal_size_checks: bool,
}
fn load_config(path: &str) -> Result<AppConfig> {
let file = File::open(path).map_err(|e| anyhow!(e))?;
let reader = BufReader::new(file);
let config = serde_yaml::from_reader(reader)?;
Ok(config)
} }
#[tokio::main] #[tokio::main]
@@ -98,6 +88,7 @@ async fn main() -> Result<()> {
} else { } else {
confy::load("managarr", "config")? confy::load("managarr", "config")?
}; };
let reqwest_client = build_network_client(&config);
let (sync_network_tx, sync_network_rx) = mpsc::channel(500); let (sync_network_tx, sync_network_rx) = mpsc::channel(500);
let cancellation_token = CancellationToken::new(); let cancellation_token = CancellationToken::new();
let ctrlc_cancellation_token = cancellation_token.clone(); let ctrlc_cancellation_token = cancellation_token.clone();
@@ -119,7 +110,7 @@ async fn main() -> Result<()> {
Some(command) => match command { Some(command) => match command {
Command::Radarr(_) => { Command::Radarr(_) => {
let app_nw = Arc::clone(&app); let app_nw = Arc::clone(&app);
let mut network = Network::new(&app_nw, cancellation_token); let mut network = Network::new(&app_nw, cancellation_token, reqwest_client);
if let Err(e) = cli::handle_command(&app, command, &mut network).await { if let Err(e) = cli::handle_command(&app, command, &mut network).await {
eprintln!("error: {}", e.to_string().red()); eprintln!("error: {}", e.to_string().red());
@@ -133,8 +124,10 @@ async fn main() -> Result<()> {
}, },
None => { None => {
let app_nw = Arc::clone(&app); let app_nw = Arc::clone(&app);
std::thread::spawn(move || start_networking(sync_network_rx, &app_nw, cancellation_token)); std::thread::spawn(move || {
start_ui(&app, !args.disable_terminal_size_checks).await?; start_networking(sync_network_rx, &app_nw, cancellation_token, reqwest_client)
});
start_ui(&app).await?;
} }
} }
@@ -146,8 +139,9 @@ async fn start_networking(
mut network_rx: Receiver<NetworkEvent>, mut network_rx: Receiver<NetworkEvent>,
app: &Arc<Mutex<App<'_>>>, app: &Arc<Mutex<App<'_>>>,
cancellation_token: CancellationToken, cancellation_token: CancellationToken,
client: Client,
) { ) {
let mut network = Network::new(app, cancellation_token); let mut network = Network::new(app, cancellation_token, client);
while let Some(network_event) = network_rx.recv().await { while let Some(network_event) = network_rx.recv().await {
if let Err(e) = network.handle_network_event(network_event).await { if let Err(e) = network.handle_network_event(network_event).await {
@@ -156,20 +150,7 @@ async fn start_networking(
} }
} }
async fn start_ui(app: &Arc<Mutex<App<'_>>>, check_terminal_size: bool) -> Result<()> { async fn start_ui(app: &Arc<Mutex<App<'_>>>) -> Result<()> {
if check_terminal_size {
let (width, height) = size()?;
if width < MIN_TERM_WIDTH || height < MIN_TERM_HEIGHT {
return Err(anyhow!(
"Terminal too small. Minimum size required: {}x{}; current terminal size: {}x{}",
MIN_TERM_WIDTH,
MIN_TERM_HEIGHT,
width,
height
));
}
}
let mut stdout = io::stdout(); let mut stdout = io::stdout();
enable_raw_mode()?; enable_raw_mode()?;
@@ -238,6 +219,60 @@ fn panic_hook(info: &PanicHookInfo<'_>) {
.unwrap(); .unwrap();
} }
fn load_config(path: &str) -> Result<AppConfig> {
let file = File::open(path).map_err(|e| anyhow!(e))?;
let reader = BufReader::new(file);
let config = serde_yaml::from_reader(reader)?;
Ok(config)
}
fn build_network_client(config: &AppConfig) -> Client {
let mut client_builder = Client::builder();
if config.radarr.use_ssl {
let cert = create_cert(config.radarr.ssl_cert_path.clone(), "Radarr");
client_builder = client_builder.add_root_certificate(cert);
}
match client_builder.build() {
Ok(client) => client,
Err(e) => {
error!("Unable to create reqwest client: {}", e);
eprintln!("error: {}", e.to_string().red());
process::exit(1);
}
}
}
fn create_cert(cert_path: Option<String>, servarr_name: &str) -> Certificate {
let err = |error: String| {
error!("{}", error);
eprintln!("error: {}", error.red());
process::exit(1);
};
if cert_path.is_none() {
err(format!(
"A {} cert path is required when 'use_ssl' is 'true'",
servarr_name
));
}
match fs::read(cert_path.unwrap()) {
Ok(cert) => match Certificate::from_pem(&cert) {
Ok(certificate) => certificate,
Err(_) => err(format!(
"Unable to read the specified {} SSL certificate",
servarr_name
)),
},
Err(_) => err(format!(
"Unable to open specified {} SSL certificate",
servarr_name
)),
}
}
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
fn panic_hook(info: &PanicHookInfo<'_>) { fn panic_hook(info: &PanicHookInfo<'_>) {
use human_panic::{handle_dump, print_msg, Metadata}; use human_panic::{handle_dump, print_msg, Metadata};
+4
View File
@@ -291,6 +291,10 @@ pub struct HostConfig {
pub instance_name: Option<HorizontallyScrollableText>, pub instance_name: Option<HorizontallyScrollableText>,
pub application_url: Option<HorizontallyScrollableText>, pub application_url: Option<HorizontallyScrollableText>,
pub enable_ssl: bool, pub enable_ssl: bool,
#[serde(deserialize_with = "super::from_i64")]
pub ssl_port: i64,
pub ssl_cert_path: Option<String>,
pub ssl_cert_password: Option<String>,
} }
#[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)] #[derive(Default, Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
+6 -2
View File
@@ -62,9 +62,13 @@ impl<'a, 'b> NetworkTrait for Network<'a, 'b> {
} }
impl<'a, 'b> Network<'a, 'b> { impl<'a, 'b> Network<'a, 'b> {
pub fn new(app: &'a Arc<Mutex<App<'b>>>, cancellation_token: CancellationToken) -> Self { pub fn new(
app: &'a Arc<Mutex<App<'b>>>,
cancellation_token: CancellationToken,
client: Client,
) -> Self {
Network { Network {
client: Client::new(), client,
app, app,
cancellation_token, cancellation_token,
} }
+13 -10
View File
@@ -6,6 +6,7 @@ mod tests {
use mockito::{Mock, Server, ServerGuard}; use mockito::{Mock, Server, ServerGuard};
use pretty_assertions::assert_str_eq; use pretty_assertions::assert_str_eq;
use reqwest::Client;
use rstest::rstest; use rstest::rstest;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tokio::sync::{mpsc, Mutex}; use tokio::sync::{mpsc, Mutex};
@@ -37,10 +38,12 @@ mod tests {
host, host,
api_token: String::new(), api_token: String::new(),
port, port,
use_ssl: false,
ssl_cert_path: None,
}; };
app.config.radarr = radarr_config; app.config.radarr = radarr_config;
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let _ = network let _ = network
.handle_network_event(RadarrEvent::HealthCheck.into()) .handle_network_event(RadarrEvent::HealthCheck.into())
@@ -64,7 +67,7 @@ mod tests {
.create_async() .create_async()
.await; .await;
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let _ = network let _ = network
.handle_request::<Test, ()>( .handle_request::<Test, ()>(
@@ -90,7 +93,7 @@ mod tests {
#[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod, #[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod,
) { ) {
let (async_server, app_arc, server) = mock_api(request_method, 200, true).await; let (async_server, app_arc, server) = mock_api(request_method, 200, true).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resp = network let resp = network
.handle_request::<(), Test>( .handle_request::<(), Test>(
@@ -122,7 +125,7 @@ mod tests {
#[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod, #[values(RequestMethod::Get, RequestMethod::Post)] request_method: RequestMethod,
) { ) {
let (async_server, app_arc, server) = mock_api(request_method, 400, true).await; let (async_server, app_arc, server) = mock_api(request_method, 400, true).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let mut test_result = String::new(); let mut test_result = String::new();
let resp = network let resp = network
@@ -160,7 +163,7 @@ mod tests {
cancellation_token.clone(), cancellation_token.clone(),
))); )));
app_arc.lock().await.is_loading = true; app_arc.lock().await.is_loading = true;
let mut network = Network::new(&app_arc, cancellation_token); let mut network = Network::new(&app_arc, cancellation_token, Client::new());
network.cancellation_token.cancel(); network.cancellation_token.cancel();
let resp = network let resp = network
@@ -194,7 +197,7 @@ mod tests {
.create_async() .create_async()
.await; .await;
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resp = network let resp = network
.handle_request::<(), Test>( .handle_request::<(), Test>(
@@ -226,7 +229,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_handle_request_failure_to_send_request() { async fn test_handle_request_failure_to_send_request() {
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resp = network let resp = network
.handle_request::<(), Test>( .handle_request::<(), Test>(
@@ -266,7 +269,7 @@ mod tests {
request_method: RequestMethod, request_method: RequestMethod,
) { ) {
let (async_server, app_arc, server) = mock_api(request_method, 404, true).await; let (async_server, app_arc, server) = mock_api(request_method, 404, true).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resp = network let resp = network
.handle_request::<(), Test>( .handle_request::<(), Test>(
@@ -296,7 +299,7 @@ mod tests {
#[tokio::test] #[tokio::test]
async fn test_handle_request_non_success_code_empty_response_body() { async fn test_handle_request_non_success_code_empty_response_body() {
let (async_server, app_arc, server) = mock_api(RequestMethod::Post, 404, false).await; let (async_server, app_arc, server) = mock_api(RequestMethod::Post, 404, false).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let resp = network let resp = network
.handle_request::<(), Test>( .handle_request::<(), Test>(
@@ -354,7 +357,7 @@ mod tests {
async_server = async_server.create_async().await; async_server = async_server.create_async().await;
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
network network
.call_api(RequestProps { .call_api(RequestProps {
+7 -1
View File
@@ -2262,8 +2262,14 @@ impl<'a, 'b> Network<'a, 'b> {
host, host,
port, port,
api_token, api_token,
use_ssl,
..
} = &app.config.radarr; } = &app.config.radarr;
let uri = format!("http://{host}:{}/api/v3{resource}", port.unwrap_or(7878)); let protocol = if *use_ssl { "https" } else { "http" };
let uri = format!(
"{protocol}://{host}:{}/api/v3{resource}",
port.unwrap_or(7878)
);
RequestProps { RequestProps {
uri, uri,
+110 -98
View File
@@ -6,6 +6,7 @@ mod test {
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use mockito::{Matcher, Mock, Server, ServerGuard}; use mockito::{Matcher, Mock, Server, ServerGuard};
use pretty_assertions::{assert_eq, assert_str_eq}; use pretty_assertions::{assert_eq, assert_str_eq};
use reqwest::Client;
use rstest::rstest; use rstest::rstest;
use serde_json::{json, Number, Value}; use serde_json::{json, Number, Value};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@@ -236,7 +237,7 @@ mod test {
RadarrEvent::HealthCheck.resource(), RadarrEvent::HealthCheck.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let _ = network.handle_radarr_event(RadarrEvent::HealthCheck).await; let _ = network.handle_radarr_event(RadarrEvent::HealthCheck).await;
@@ -262,7 +263,7 @@ mod test {
RadarrEvent::GetOverview.resource(), RadarrEvent::GetOverview.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let disk_space_vec = vec![ let disk_space_vec = vec![
DiskSpace { DiskSpace {
free_space: 1111, free_space: 1111,
@@ -301,7 +302,7 @@ mod test {
RadarrEvent::GetStatus.resource(), RadarrEvent::GetStatus.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let date_time = DateTime::from(DateTime::parse_from_rfc3339("2023-02-25T20:16:43Z").unwrap()) let date_time = DateTime::from(DateTime::parse_from_rfc3339("2023-02-25T20:16:43Z").unwrap())
as DateTime<Utc>; as DateTime<Utc>;
@@ -385,7 +386,7 @@ mod test {
.movies .movies
.sorting(vec![title_sort_option]); .sorting(vec![title_sort_option]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Movies(movies) = network if let RadarrSerdeable::Movies(movies) = network
.handle_radarr_event(RadarrEvent::GetMovies) .handle_radarr_event(RadarrEvent::GetMovies)
@@ -440,7 +441,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.sorting(vec![title_sort_option]); .sorting(vec![title_sort_option]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetMovies) .handle_radarr_event(RadarrEvent::GetMovies)
@@ -493,7 +494,7 @@ mod test {
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default()); app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Releases(releases_vec) = network if let RadarrSerdeable::Releases(releases_vec) = network
.handle_radarr_event(RadarrEvent::GetReleases(None)) .handle_radarr_event(RadarrEvent::GetReleases(None))
@@ -551,7 +552,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetReleases(None)) .handle_radarr_event(RadarrEvent::GetReleases(None))
@@ -610,7 +611,7 @@ mod test {
) )
.await; .await;
app_arc.lock().await.data.radarr_data.add_movie_search = Some("test term".into()); app_arc.lock().await.data.radarr_data.add_movie_search = Some("test term".into());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::AddMovieSearchResults(add_movie_search_results) = network if let RadarrSerdeable::AddMovieSearchResults(add_movie_search_results) = network
.handle_radarr_event(RadarrEvent::SearchNewMovie(None)) .handle_radarr_event(RadarrEvent::SearchNewMovie(None))
@@ -676,7 +677,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::AddMovieSearchResults(add_movie_search_results) = network if let RadarrSerdeable::AddMovieSearchResults(add_movie_search_results) = network
.handle_radarr_event(RadarrEvent::SearchNewMovie(Some("test term".into()))) .handle_radarr_event(RadarrEvent::SearchNewMovie(Some("test term".into())))
@@ -711,7 +712,7 @@ mod test {
task_name: TaskName::default(), task_name: TaskName::default(),
..Task::default() ..Task::default()
}]); }]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::StartTask(None)) .handle_radarr_event(RadarrEvent::StartTask(None))
@@ -736,7 +737,7 @@ mod test {
RadarrEvent::StartTask(None).resource(), RadarrEvent::StartTask(None).resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::StartTask(Some(TaskName::default()))) .handle_radarr_event(RadarrEvent::StartTask(Some(TaskName::default())))
@@ -757,7 +758,7 @@ mod test {
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Get, None, Some(json!([])), None, &resource).await; mock_radarr_api(RequestMethod::Get, None, Some(json!([])), None, &resource).await;
app_arc.lock().await.data.radarr_data.add_movie_search = Some("test term".into()); app_arc.lock().await.data.radarr_data.add_movie_search = Some("test term".into());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::SearchNewMovie(None)) .handle_radarr_event(RadarrEvent::SearchNewMovie(None))
@@ -804,10 +805,12 @@ mod test {
host, host,
port, port,
api_token: "test1234".to_owned(), api_token: "test1234".to_owned(),
use_ssl: false,
ssl_cert_path: None,
}; };
app.config.radarr = radarr_config; app.config.radarr = radarr_config;
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::SearchNewMovie(None)) .handle_radarr_event(RadarrEvent::SearchNewMovie(None))
@@ -886,7 +889,7 @@ mod test {
.radarr_data .radarr_data
.indexers .indexers
.set_items(vec![indexer()]); .set_items(vec![indexer()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::TestIndexer(None)) .handle_radarr_event(RadarrEvent::TestIndexer(None))
@@ -954,7 +957,7 @@ mod test {
.radarr_data .radarr_data
.indexers .indexers
.set_items(vec![indexer()]); .set_items(vec![indexer()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::TestIndexer(None)) .handle_radarr_event(RadarrEvent::TestIndexer(None))
@@ -1015,7 +1018,7 @@ mod test {
.with_body("{}") .with_body("{}")
.create_async() .create_async()
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::TestIndexer(Some(1))) .handle_radarr_event(RadarrEvent::TestIndexer(Some(1)))
@@ -1092,7 +1095,7 @@ mod test {
.radarr_data .radarr_data
.indexers .indexers
.set_items(indexers); .set_items(indexers);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::IndexerTestResults(results) = network if let RadarrSerdeable::IndexerTestResults(results) = network
.handle_radarr_event(RadarrEvent::TestAllIndexers) .handle_radarr_event(RadarrEvent::TestAllIndexers)
@@ -1143,7 +1146,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::TriggerAutomaticSearch(None)) .handle_radarr_event(RadarrEvent::TriggerAutomaticSearch(None))
@@ -1166,7 +1169,7 @@ mod test {
RadarrEvent::TriggerAutomaticSearch(None).resource(), RadarrEvent::TriggerAutomaticSearch(None).resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::TriggerAutomaticSearch(Some(1))) .handle_radarr_event(RadarrEvent::TriggerAutomaticSearch(Some(1)))
@@ -1196,7 +1199,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::UpdateAndScan(None)) .handle_radarr_event(RadarrEvent::UpdateAndScan(None))
@@ -1219,7 +1222,7 @@ mod test {
RadarrEvent::UpdateAndScan(None).resource(), RadarrEvent::UpdateAndScan(None).resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::UpdateAndScan(Some(1))) .handle_radarr_event(RadarrEvent::UpdateAndScan(Some(1)))
@@ -1242,7 +1245,7 @@ mod test {
RadarrEvent::UpdateAllMovies.resource(), RadarrEvent::UpdateAllMovies.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::UpdateAllMovies) .handle_radarr_event(RadarrEvent::UpdateAllMovies)
@@ -1264,7 +1267,7 @@ mod test {
RadarrEvent::UpdateDownloads.resource(), RadarrEvent::UpdateDownloads.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::UpdateDownloads) .handle_radarr_event(RadarrEvent::UpdateDownloads)
@@ -1286,7 +1289,7 @@ mod test {
RadarrEvent::UpdateCollections.resource(), RadarrEvent::UpdateCollections.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::UpdateCollections) .handle_radarr_event(RadarrEvent::UpdateCollections)
@@ -1317,7 +1320,7 @@ mod test {
.set_items(vec![movie()]); .set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.quality_profile_map = app_arc.lock().await.data.radarr_data.quality_profile_map =
BiMap::from_iter([(2222, "HD - 1080p".to_owned())]); BiMap::from_iter([(2222, "HD - 1080p".to_owned())]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Movie(movie) = network if let RadarrSerdeable::Movie(movie) = network
.handle_radarr_event(RadarrEvent::GetMovieDetails(None)) .handle_radarr_event(RadarrEvent::GetMovieDetails(None))
@@ -1402,7 +1405,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Movie(movie) = network if let RadarrSerdeable::Movie(movie) = network
.handle_radarr_event(RadarrEvent::GetMovieDetails(Some(1))) .handle_radarr_event(RadarrEvent::GetMovieDetails(Some(1)))
@@ -1456,7 +1459,7 @@ mod test {
.set_items(vec![movie()]); .set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.quality_profile_map = app_arc.lock().await.data.radarr_data.quality_profile_map =
BiMap::from_iter([(2222, "HD - 1080p".to_owned())]); BiMap::from_iter([(2222, "HD - 1080p".to_owned())]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetMovieDetails(None)) .handle_radarr_event(RadarrEvent::GetMovieDetails(None))
@@ -1530,7 +1533,7 @@ mod test {
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default()); app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::MovieHistoryItems(history) = network if let RadarrSerdeable::MovieHistoryItems(history) = network
.handle_radarr_event(RadarrEvent::GetMovieHistory(None)) .handle_radarr_event(RadarrEvent::GetMovieHistory(None))
@@ -1578,7 +1581,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::MovieHistoryItems(history) = network if let RadarrSerdeable::MovieHistoryItems(history) = network
.handle_radarr_event(RadarrEvent::GetMovieHistory(Some(1))) .handle_radarr_event(RadarrEvent::GetMovieHistory(Some(1)))
@@ -1618,7 +1621,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetMovieHistory(None)) .handle_radarr_event(RadarrEvent::GetMovieHistory(None))
@@ -1767,7 +1770,7 @@ mod test {
.blocklist .blocklist
.sorting(vec![blocklist_sort_option]); .sorting(vec![blocklist_sort_option]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::BlocklistResponse(blocklist) = network if let RadarrSerdeable::BlocklistResponse(blocklist) = network
.handle_radarr_event(RadarrEvent::GetBlocklist) .handle_radarr_event(RadarrEvent::GetBlocklist)
@@ -1888,7 +1891,7 @@ mod test {
.radarr_data .radarr_data
.blocklist .blocklist
.sorting(vec![blocklist_sort_option]); .sorting(vec![blocklist_sort_option]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetBlocklist) .handle_radarr_event(RadarrEvent::GetBlocklist)
@@ -2011,7 +2014,7 @@ mod test {
.collections .collections
.sorting(vec![collection_sort_option]); .sorting(vec![collection_sort_option]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Collections(collections) = network if let RadarrSerdeable::Collections(collections) = network
.handle_radarr_event(RadarrEvent::GetCollections) .handle_radarr_event(RadarrEvent::GetCollections)
@@ -2118,7 +2121,7 @@ mod test {
.radarr_data .radarr_data
.collections .collections
.sorting(vec![collection_sort_option]); .sorting(vec![collection_sort_option]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetCollections) .handle_radarr_event(RadarrEvent::GetCollections)
@@ -2162,7 +2165,7 @@ mod test {
RadarrEvent::GetDownloads.resource(), RadarrEvent::GetDownloads.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::DownloadsResponse(downloads) = network if let RadarrSerdeable::DownloadsResponse(downloads) = network
.handle_radarr_event(RadarrEvent::GetDownloads) .handle_radarr_event(RadarrEvent::GetDownloads)
@@ -2186,7 +2189,10 @@ mod test {
"urlBase": "some.test.site/radarr", "urlBase": "some.test.site/radarr",
"instanceName": "Radarr", "instanceName": "Radarr",
"applicationUrl": "https://some.test.site:7878/radarr", "applicationUrl": "https://some.test.site:7878/radarr",
"enableSsl": true "enableSsl": true,
"sslPort": 9898,
"sslCertPath": "/app/radarr.pfx",
"sslCertPassword": "test"
}); });
let response: HostConfig = serde_json::from_value(host_config_response.clone()).unwrap(); let response: HostConfig = serde_json::from_value(host_config_response.clone()).unwrap();
let (async_server, app_arc, _server) = mock_radarr_api( let (async_server, app_arc, _server) = mock_radarr_api(
@@ -2197,7 +2203,7 @@ mod test {
RadarrEvent::GetHostConfig.resource(), RadarrEvent::GetHostConfig.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::HostConfig(host_config) = network if let RadarrSerdeable::HostConfig(host_config) = network
.handle_radarr_event(RadarrEvent::GetHostConfig) .handle_radarr_event(RadarrEvent::GetHostConfig)
@@ -2250,7 +2256,7 @@ mod test {
RadarrEvent::GetIndexers.resource(), RadarrEvent::GetIndexers.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Indexers(indexers) = network if let RadarrSerdeable::Indexers(indexers) = network
.handle_radarr_event(RadarrEvent::GetIndexers) .handle_radarr_event(RadarrEvent::GetIndexers)
@@ -2289,7 +2295,7 @@ mod test {
RadarrEvent::GetAllIndexerSettings.resource(), RadarrEvent::GetAllIndexerSettings.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::IndexerSettings(settings) = network if let RadarrSerdeable::IndexerSettings(settings) = network
.handle_radarr_event(RadarrEvent::GetAllIndexerSettings) .handle_radarr_event(RadarrEvent::GetAllIndexerSettings)
@@ -2327,7 +2333,7 @@ mod test {
) )
.await; .await;
app_arc.lock().await.data.radarr_data.indexer_settings = Some(IndexerSettings::default()); app_arc.lock().await.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetAllIndexerSettings) .handle_radarr_event(RadarrEvent::GetAllIndexerSettings)
@@ -2374,7 +2380,7 @@ mod test {
RadarrEvent::GetQueuedEvents.resource(), RadarrEvent::GetQueuedEvents.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::QueueEvents(events) = network if let RadarrSerdeable::QueueEvents(events) = network
.handle_radarr_event(RadarrEvent::GetQueuedEvents) .handle_radarr_event(RadarrEvent::GetQueuedEvents)
@@ -2435,7 +2441,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::LogResponse(logs) = network if let RadarrSerdeable::LogResponse(logs) = network
.handle_radarr_event(RadarrEvent::GetLogs(None)) .handle_radarr_event(RadarrEvent::GetLogs(None))
@@ -2505,7 +2511,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::LogResponse(logs) = network if let RadarrSerdeable::LogResponse(logs) = network
.handle_radarr_event(RadarrEvent::GetLogs(Some(1000))) .handle_radarr_event(RadarrEvent::GetLogs(Some(1000)))
@@ -2546,7 +2552,7 @@ mod test {
RadarrEvent::GetQualityProfiles.resource(), RadarrEvent::GetQualityProfiles.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::QualityProfiles(quality_profiles) = network if let RadarrSerdeable::QualityProfiles(quality_profiles) = network
.handle_radarr_event(RadarrEvent::GetQualityProfiles) .handle_radarr_event(RadarrEvent::GetQualityProfiles)
@@ -2577,7 +2583,7 @@ mod test {
RadarrEvent::GetTags.resource(), RadarrEvent::GetTags.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Tags(tags) = network if let RadarrSerdeable::Tags(tags) = network
.handle_radarr_event(RadarrEvent::GetTags) .handle_radarr_event(RadarrEvent::GetTags)
@@ -2639,7 +2645,7 @@ mod test {
RadarrEvent::GetTasks.resource(), RadarrEvent::GetTasks.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Tasks(tasks) = network if let RadarrSerdeable::Tasks(tasks) = network
.handle_radarr_event(RadarrEvent::GetTasks) .handle_radarr_event(RadarrEvent::GetTasks)
@@ -2732,7 +2738,7 @@ mod test {
RadarrEvent::GetUpdates.resource(), RadarrEvent::GetUpdates.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Updates(updates) = network if let RadarrSerdeable::Updates(updates) = network
.handle_radarr_event(RadarrEvent::GetUpdates) .handle_radarr_event(RadarrEvent::GetUpdates)
@@ -2762,7 +2768,7 @@ mod test {
.await; .await;
app_arc.lock().await.data.radarr_data.tags_map = app_arc.lock().await.data.radarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]); BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Tag(tag) = network if let RadarrSerdeable::Tag(tag) = network
.handle_radarr_event(RadarrEvent::AddTag("testing".to_owned())) .handle_radarr_event(RadarrEvent::AddTag("testing".to_owned()))
@@ -2787,7 +2793,7 @@ mod test {
let resource = format!("{}/1", RadarrEvent::DeleteTag(1).resource()); let resource = format!("{}/1", RadarrEvent::DeleteTag(1).resource());
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteTag(1)) .handle_radarr_event(RadarrEvent::DeleteTag(1))
@@ -2814,7 +2820,7 @@ mod test {
RadarrEvent::GetRootFolders.resource(), RadarrEvent::GetRootFolders.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::RootFolders(root_folders) = network if let RadarrSerdeable::RootFolders(root_folders) = network
.handle_radarr_event(RadarrEvent::GetRootFolders) .handle_radarr_event(RadarrEvent::GetRootFolders)
@@ -2850,7 +2856,7 @@ mod test {
RadarrEvent::GetSecurityConfig.resource(), RadarrEvent::GetSecurityConfig.resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::SecurityConfig(security_config) = network if let RadarrSerdeable::SecurityConfig(security_config) = network
.handle_radarr_event(RadarrEvent::GetSecurityConfig) .handle_radarr_event(RadarrEvent::GetSecurityConfig)
@@ -2898,7 +2904,7 @@ mod test {
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default()); app_arc.lock().await.data.radarr_data.movie_details_modal = Some(MovieDetailsModal::default());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Credits(credits) = network if let RadarrSerdeable::Credits(credits) = network
.handle_radarr_event(RadarrEvent::GetMovieCredits(None)) .handle_radarr_event(RadarrEvent::GetMovieCredits(None))
@@ -2943,7 +2949,7 @@ mod test {
&resource, &resource,
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Credits(credits) = network if let RadarrSerdeable::Credits(credits) = network
.handle_radarr_event(RadarrEvent::GetMovieCredits(Some(1))) .handle_radarr_event(RadarrEvent::GetMovieCredits(Some(1)))
@@ -2989,7 +2995,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::GetMovieCredits(None)) .handle_radarr_event(RadarrEvent::GetMovieCredits(None))
@@ -3018,7 +3024,7 @@ mod test {
app.data.radarr_data.delete_movie_files = true; app.data.radarr_data.delete_movie_files = true;
app.data.radarr_data.add_list_exclusion = true; app.data.radarr_data.add_list_exclusion = true;
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteMovie(None)) .handle_radarr_event(RadarrEvent::DeleteMovie(None))
@@ -3038,7 +3044,7 @@ mod test {
); );
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let delete_movie_params = DeleteMovieParams { let delete_movie_params = DeleteMovieParams {
id: 1, id: 1,
delete_movie_files: true, delete_movie_files: true,
@@ -3087,7 +3093,7 @@ mod test {
.radarr_data .radarr_data
.blocklist .blocklist
.set_items(blocklist_items); .set_items(blocklist_items);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::ClearBlocklist) .handle_radarr_event(RadarrEvent::ClearBlocklist)
@@ -3109,7 +3115,7 @@ mod test {
.radarr_data .radarr_data
.blocklist .blocklist
.set_items(vec![blocklist_item()]); .set_items(vec![blocklist_item()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteBlocklistItem(None)) .handle_radarr_event(RadarrEvent::DeleteBlocklistItem(None))
@@ -3124,7 +3130,7 @@ mod test {
let resource = format!("{}/1", RadarrEvent::DeleteBlocklistItem(None).resource()); let resource = format!("{}/1", RadarrEvent::DeleteBlocklistItem(None).resource());
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteBlocklistItem(Some(1))) .handle_radarr_event(RadarrEvent::DeleteBlocklistItem(Some(1)))
@@ -3146,7 +3152,7 @@ mod test {
.radarr_data .radarr_data
.downloads .downloads
.set_items(vec![download_record()]); .set_items(vec![download_record()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteDownload(None)) .handle_radarr_event(RadarrEvent::DeleteDownload(None))
@@ -3161,7 +3167,7 @@ mod test {
let resource = format!("{}/1", RadarrEvent::DeleteDownload(None).resource()); let resource = format!("{}/1", RadarrEvent::DeleteDownload(None).resource());
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteDownload(Some(1))) .handle_radarr_event(RadarrEvent::DeleteDownload(Some(1)))
@@ -3183,7 +3189,7 @@ mod test {
.radarr_data .radarr_data
.indexers .indexers
.set_items(vec![indexer()]); .set_items(vec![indexer()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteIndexer(None)) .handle_radarr_event(RadarrEvent::DeleteIndexer(None))
@@ -3198,7 +3204,7 @@ mod test {
let resource = format!("{}/1", RadarrEvent::DeleteIndexer(None).resource()); let resource = format!("{}/1", RadarrEvent::DeleteIndexer(None).resource());
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteIndexer(Some(1))) .handle_radarr_event(RadarrEvent::DeleteIndexer(Some(1)))
@@ -3220,7 +3226,7 @@ mod test {
.radarr_data .radarr_data
.root_folders .root_folders
.set_items(vec![root_folder()]); .set_items(vec![root_folder()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteRootFolder(None)) .handle_radarr_event(RadarrEvent::DeleteRootFolder(None))
@@ -3235,7 +3241,7 @@ mod test {
let resource = format!("{}/1", RadarrEvent::DeleteRootFolder(None).resource()); let resource = format!("{}/1", RadarrEvent::DeleteRootFolder(None).resource());
let (async_server, app_arc, _server) = let (async_server, app_arc, _server) =
mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await; mock_radarr_api(RequestMethod::Delete, None, None, None, &resource).await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DeleteRootFolder(Some(1))) .handle_radarr_event(RadarrEvent::DeleteRootFolder(Some(1)))
@@ -3319,7 +3325,7 @@ mod test {
app.data.radarr_data.add_searched_movies = Some(add_searched_movies); app.data.radarr_data.add_searched_movies = Some(add_searched_movies);
} }
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::AddMovie(None)) .handle_radarr_event(RadarrEvent::AddMovie(None))
@@ -3372,7 +3378,7 @@ mod test {
}, },
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::AddMovie(Some(body))) .handle_radarr_event(RadarrEvent::AddMovie(Some(body)))
@@ -3458,7 +3464,7 @@ mod test {
add_searched_movies.scroll_to_bottom(); add_searched_movies.scroll_to_bottom();
app.data.radarr_data.add_searched_movies = Some(add_searched_movies); app.data.radarr_data.add_searched_movies = Some(add_searched_movies);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::AddMovie(None)) .handle_radarr_event(RadarrEvent::AddMovie(None))
@@ -3502,7 +3508,7 @@ mod test {
.await; .await;
app_arc.lock().await.data.radarr_data.edit_root_folder = Some("/nfs/test".into()); app_arc.lock().await.data.radarr_data.edit_root_folder = Some("/nfs/test".into());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::AddRootFolder(None)) .handle_radarr_event(RadarrEvent::AddRootFolder(None))
@@ -3532,7 +3538,7 @@ mod test {
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::AddRootFolder(Some("/test/test".to_owned()))) .handle_radarr_event(RadarrEvent::AddRootFolder(Some("/test/test".to_owned())))
@@ -3572,7 +3578,7 @@ mod test {
.await; .await;
app_arc.lock().await.data.radarr_data.indexer_settings = Some(indexer_settings()); app_arc.lock().await.data.radarr_data.indexer_settings = Some(indexer_settings());
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditAllIndexerSettings(None)) .handle_radarr_event(RadarrEvent::EditAllIndexerSettings(None))
@@ -3611,7 +3617,7 @@ mod test {
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditAllIndexerSettings( .handle_radarr_event(RadarrEvent::EditAllIndexerSettings(
@@ -3709,7 +3715,7 @@ mod test {
app.data.radarr_data.quality_profile_map = app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]); BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditCollection(None)) .handle_radarr_event(RadarrEvent::EditCollection(None))
@@ -3794,7 +3800,7 @@ mod test {
root_folder_path: Some("/nfs/Test Path".to_owned()), root_folder_path: Some("/nfs/Test Path".to_owned()),
search_on_add: Some(false), search_on_add: Some(false),
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditCollection(Some(edit_collection_params))) .handle_radarr_event(RadarrEvent::EditCollection(Some(edit_collection_params)))
@@ -3873,7 +3879,7 @@ mod test {
collection_id: 123, collection_id: 123,
..EditCollectionParams::default() ..EditCollectionParams::default()
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditCollection(Some(edit_collection_params))) .handle_radarr_event(RadarrEvent::EditCollection(Some(edit_collection_params)))
@@ -3969,7 +3975,7 @@ mod test {
app.data.radarr_data.edit_indexer_modal = Some(edit_indexer_modal); app.data.radarr_data.edit_indexer_modal = Some(edit_indexer_modal);
app.data.radarr_data.indexers.set_items(vec![indexer()]); app.data.radarr_data.indexers.set_items(vec![indexer()]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(None)) .handle_radarr_event(RadarrEvent::EditIndexer(None))
@@ -4070,7 +4076,7 @@ mod test {
); );
app.data.radarr_data.indexers.set_items(vec![indexer]); app.data.radarr_data.indexers.set_items(vec![indexer]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(None)) .handle_radarr_event(RadarrEvent::EditIndexer(None))
@@ -4185,7 +4191,7 @@ mod test {
); );
app.data.radarr_data.indexers.set_items(vec![indexer]); app.data.radarr_data.indexers.set_items(vec![indexer]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(None)) .handle_radarr_event(RadarrEvent::EditIndexer(None))
@@ -4280,7 +4286,7 @@ mod test {
.match_body(Matcher::Json(expected_indexer_edit_body_json)) .match_body(Matcher::Json(expected_indexer_edit_body_json))
.create_async() .create_async()
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params))) .handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params)))
@@ -4340,7 +4346,7 @@ mod test {
.match_body(Matcher::Json(indexer_details_json)) .match_body(Matcher::Json(indexer_details_json))
.create_async() .create_async()
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params))) .handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params)))
@@ -4425,7 +4431,7 @@ mod test {
.match_body(Matcher::Json(expected_edit_indexer_body)) .match_body(Matcher::Json(expected_edit_indexer_body))
.create_async() .create_async()
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params))) .handle_radarr_event(RadarrEvent::EditIndexer(Some(edit_indexer_params)))
@@ -4488,7 +4494,7 @@ mod test {
app.data.radarr_data.quality_profile_map = app.data.radarr_data.quality_profile_map =
BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]); BiMap::from_iter([(1111, "Any".to_owned()), (2222, "HD - 1080p".to_owned())]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditMovie(None)) .handle_radarr_event(RadarrEvent::EditMovie(None))
@@ -4539,7 +4545,7 @@ mod test {
tags: Some(vec![1, 2]), tags: Some(vec![1, 2]),
..EditMovieParams::default() ..EditMovieParams::default()
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params))) .handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params)))
@@ -4576,7 +4582,7 @@ mod test {
movie_id: 1, movie_id: 1,
..EditMovieParams::default() ..EditMovieParams::default()
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params))) .handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params)))
@@ -4617,7 +4623,7 @@ mod test {
clear_tags: true, clear_tags: true,
..EditMovieParams::default() ..EditMovieParams::default()
}; };
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params))) .handle_radarr_event(RadarrEvent::EditMovie(Some(edit_movie_params)))
@@ -4654,7 +4660,7 @@ mod test {
.radarr_data .radarr_data
.movies .movies
.set_items(vec![movie()]); .set_items(vec![movie()]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert!(network assert!(network
.handle_radarr_event(RadarrEvent::DownloadRelease(None)) .handle_radarr_event(RadarrEvent::DownloadRelease(None))
@@ -4678,7 +4684,7 @@ mod test {
RadarrEvent::DownloadRelease(None).resource(), RadarrEvent::DownloadRelease(None).resource(),
) )
.await; .await;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let params = ReleaseDownloadBody { let params = ReleaseDownloadBody {
guid: "1234".to_owned(), guid: "1234".to_owned(),
indexer_id: 2, indexer_id: 2,
@@ -4705,7 +4711,7 @@ mod test {
(3, "hi".to_owned()), (3, "hi".to_owned()),
]); ]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_eq!( assert_eq!(
network.extract_and_add_tag_ids_vec(tags).await, network.extract_and_add_tag_ids_vec(tags).await,
@@ -4733,7 +4739,7 @@ mod test {
app.data.radarr_data.tags_map = app.data.radarr_data.tags_map =
BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]); BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]);
} }
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let tag_ids_vec = network.extract_and_add_tag_ids_vec(tags).await; let tag_ids_vec = network.extract_and_add_tag_ids_vec(tags).await;
@@ -4762,7 +4768,7 @@ mod test {
id: 1, id: 1,
..Movie::default() ..Movie::default()
}]); }]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_eq!(network.extract_movie_id().await, 1); assert_eq!(network.extract_movie_id().await, 1);
} }
@@ -4776,7 +4782,7 @@ mod test {
..Movie::default() ..Movie::default()
}]); }]);
app_arc.lock().await.data.radarr_data.movies = filtered_movies; app_arc.lock().await.data.radarr_data.movies = filtered_movies;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_eq!(network.extract_movie_id().await, 1); assert_eq!(network.extract_movie_id().await, 1);
} }
@@ -4794,7 +4800,7 @@ mod test {
id: 1, id: 1,
..Collection::default() ..Collection::default()
}]); }]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_eq!(network.extract_collection_id().await, 1); assert_eq!(network.extract_collection_id().await, 1);
} }
@@ -4808,7 +4814,7 @@ mod test {
..Collection::default() ..Collection::default()
}]); }]);
app_arc.lock().await.data.radarr_data.collections = filtered_collections; app_arc.lock().await.data.radarr_data.collections = filtered_collections;
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_eq!(network.extract_collection_id().await, 1); assert_eq!(network.extract_collection_id().await, 1);
} }
@@ -4826,7 +4832,7 @@ mod test {
id: 1, id: 1,
..Movie::default() ..Movie::default()
}]); }]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_str_eq!( assert_str_eq!(
network.append_movie_id_param("/test", None).await, network.append_movie_id_param("/test", None).await,
@@ -4847,7 +4853,7 @@ mod test {
id: 1, id: 1,
..Movie::default() ..Movie::default()
}]); }]);
let mut network = Network::new(&app_arc, CancellationToken::new()); let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
assert_str_eq!( assert_str_eq!(
network.append_movie_id_param("/test", Some(11)).await, network.append_movie_id_param("/test", Some(11)).await,
@@ -4858,7 +4864,7 @@ mod test {
#[tokio::test] #[tokio::test]
async fn test_radarr_request_props_from_default_radarr_config() { async fn test_radarr_request_props_from_default_radarr_config() {
let app_arc = Arc::new(Mutex::new(App::default())); let app_arc = Arc::new(Mutex::new(App::default()));
let network = Network::new(&app_arc, CancellationToken::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let request_props = network let request_props = network
.radarr_request_props_from("/test", RequestMethod::Get, None::<()>) .radarr_request_props_from("/test", RequestMethod::Get, None::<()>)
@@ -4873,6 +4879,8 @@ mod test {
host: "192.168.0.123".to_owned(), host: "192.168.0.123".to_owned(),
port: Some(8080), port: Some(8080),
api_token: "testToken1234".to_owned(), api_token: "testToken1234".to_owned(),
use_ssl: false,
ssl_cert_path: None,
}; };
} }
@@ -4884,14 +4892,16 @@ mod test {
host: "192.168.0.123".to_owned(), host: "192.168.0.123".to_owned(),
port: Some(8080), port: Some(8080),
api_token: api_token.clone(), api_token: api_token.clone(),
use_ssl: true,
ssl_cert_path: None,
}; };
let network = Network::new(&app_arc, CancellationToken::new()); let network = Network::new(&app_arc, CancellationToken::new(), Client::new());
let request_props = network let request_props = network
.radarr_request_props_from("/test", RequestMethod::Get, None::<()>) .radarr_request_props_from("/test", RequestMethod::Get, None::<()>)
.await; .await;
assert_str_eq!(request_props.uri, "http://192.168.0.123:8080/api/v3/test"); assert_str_eq!(request_props.uri, "https://192.168.0.123:8080/api/v3/test");
assert_eq!(request_props.method, RequestMethod::Get); assert_eq!(request_props.method, RequestMethod::Get);
assert_eq!(request_props.body, None); assert_eq!(request_props.body, None);
assert_str_eq!(request_props.api_token, api_token); assert_str_eq!(request_props.api_token, api_token);
@@ -4987,6 +4997,8 @@ mod test {
host, host,
port, port,
api_token: "test1234".to_owned(), api_token: "test1234".to_owned(),
use_ssl: false,
ssl_cert_path: None,
}; };
app.config.radarr = radarr_config; app.config.radarr = radarr_config;
let app_arc = Arc::new(Mutex::new(app)); let app_arc = Arc::new(Mutex::new(app));
+4 -4
View File
@@ -1,6 +1,6 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use ratatui::layout::{Alignment, Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::{Style, Stylize};
use ratatui::text::{Line, Text}; use ratatui::text::{Line, Text};
use ratatui::widgets::Clear; use ratatui::widgets::Clear;
@@ -83,7 +83,7 @@ fn draw_header_row(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.select(app.server_tabs.index); .select(app.server_tabs.index);
let help = Paragraph::new(help_text) let help = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Right); .right_aligned();
f.render_widget(tabs, tabs_area); f.render_widget(tabs, tabs_area);
f.render_widget(help, help_area); f.render_widget(help, help_area);
@@ -170,7 +170,7 @@ fn draw_tabs(f: &mut Frame<'_>, area: Rect, title: &str, tab_state: &TabState) -
.select(tab_state.index); .select(tab_state.index);
let help = Paragraph::new(Text::from(tab_state.get_active_tab_help().help())) let help = Paragraph::new(Text::from(tab_state.get_active_tab_help().help()))
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Right); .right_aligned();
f.render_widget(tabs, tabs_area); f.render_widget(tabs, tabs_area);
f.render_widget(help, help_area); f.render_widget(help, help_area);
@@ -197,7 +197,7 @@ pub fn draw_input_box_popup(
let help = Paragraph::new("<esc> cancel") let help = Paragraph::new("<esc> cancel")
.help() .help()
.alignment(Alignment::Center) .centered()
.block(borderless_block()); .block(borderless_block());
f.render_widget(help, help_area); f.render_widget(help, help_area);
} }
@@ -259,7 +259,7 @@ fn draw_movie_overview(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
.wrap(Wrap { trim: false }); .wrap(Wrap { trim: false });
let help_paragraph = Paragraph::new(help_text) let help_paragraph = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Center); .centered();
f.render_widget(paragraph, paragraph_area); f.render_widget(paragraph, paragraph_area);
f.render_widget(help_paragraph, help_area); f.render_widget(help_paragraph, help_area);
@@ -1,9 +1,12 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use ratatui::layout::{Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::widgets::ListItem; use ratatui::text::Text;
use ratatui::widgets::{ListItem, Paragraph};
use ratatui::Frame; use ratatui::Frame;
use crate::app::context_clues::build_context_clue_string;
use crate::app::radarr::radarr_context_clues::CONFIRMATION_PROMPT_CONTEXT_CLUES;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::modals::EditCollectionModal; use crate::models::servarr_data::radarr::modals::EditCollectionModal;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
@@ -110,7 +113,7 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
let selected_minimum_availability = minimum_availability_list.current_selection(); let selected_minimum_availability = minimum_availability_list.current_selection();
let selected_quality_profile = quality_profile_list.current_selection(); let selected_quality_profile = quality_profile_list.current_selection();
let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, root_folder_area, search_on_add_area, _, buttons_area] = let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, root_folder_area, search_on_add_area, _, buttons_area, help_area] =
Layout::vertical([ Layout::vertical([
Constraint::Length(6), Constraint::Length(6),
Constraint::Length(3), Constraint::Length(3),
@@ -118,8 +121,9 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0), Constraint::Fill(1),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(1),
]) ])
.margin(1) .margin(1)
.areas(area); .areas(area);
@@ -127,6 +131,8 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area); .areas(buttons_area);
let help_text = Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
let prompt_paragraph = layout_paragraph_borderless(&collection_overview); let prompt_paragraph = layout_paragraph_borderless(&collection_overview);
let monitored_checkbox = Checkbox::new("Monitored") let monitored_checkbox = Checkbox::new("Monitored")
.highlighted(selected_block == &ActiveRadarrBlock::EditCollectionToggleMonitored) .highlighted(selected_block == &ActiveRadarrBlock::EditCollectionToggleMonitored)
@@ -169,6 +175,7 @@ fn draw_edit_collection_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>
f.render_widget(search_on_add_checkbox, search_on_add_area); f.render_widget(search_on_add_checkbox, search_on_add_area);
f.render_widget(save_button, save_area); f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area); f.render_widget(cancel_button, cancel_area);
f.render_widget(help_paragraph, help_area);
} }
fn draw_edit_collection_select_minimum_availability_popup(f: &mut Frame<'_>, app: &mut App<'_>) { fn draw_edit_collection_select_minimum_availability_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
+17 -8
View File
@@ -1,5 +1,7 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use crate::app::context_clues::build_context_clue_string;
use crate::app::radarr::radarr_context_clues::CONFIRMATION_PROMPT_CONTEXT_CLUES;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::models::Route; use crate::models::Route;
@@ -14,6 +16,8 @@ use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size; use crate::ui::widgets::popup::Size;
use crate::ui::{draw_popup_over, DrawUi}; use crate::ui::{draw_popup_over, DrawUi};
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::text::Text;
use ratatui::widgets::Paragraph;
use ratatui::Frame; use ratatui::Frame;
#[cfg(test)] #[cfg(test)]
@@ -50,32 +54,36 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditIndexerConfirmPrompt; let highlight_yes_no = selected_block == &ActiveRadarrBlock::EditIndexerConfirmPrompt;
let edit_indexer_modal_option = &app.data.radarr_data.edit_indexer_modal; let edit_indexer_modal_option = &app.data.radarr_data.edit_indexer_modal;
let protocol = &app.data.radarr_data.indexers.current_selection().protocol; let protocol = &app.data.radarr_data.indexers.current_selection().protocol;
let help_text = Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
if edit_indexer_modal_option.is_some() { if edit_indexer_modal_option.is_some() {
let edit_indexer_modal = edit_indexer_modal_option.as_ref().unwrap(); let edit_indexer_modal = edit_indexer_modal_option.as_ref().unwrap();
let [settings_area, buttons_area] = let [settings_area, _, buttons_area, help_area] = Layout::vertical([
Layout::vertical([Constraint::Fill(0), Constraint::Length(3)]) Constraint::Length(15),
.margin(1) Constraint::Fill(1),
.areas(area); Constraint::Length(3),
Constraint::Length(1),
])
.margin(1)
.areas(area);
let [left_side_area, right_side_area] = let [left_side_area, right_side_area] =
Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]) Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])
.margin(1) .margin(1)
.areas(settings_area); .areas(settings_area);
let [name_area, rss_area, auto_search_area, interactive_search_area, _] = Layout::vertical([ let [name_area, rss_area, auto_search_area, interactive_search_area] = Layout::vertical([
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0),
]) ])
.areas(left_side_area); .areas(left_side_area);
let [url_area, api_key_area, seed_ratio_area, tags_area, _] = Layout::vertical([ let [url_area, api_key_area, seed_ratio_area, tags_area] = Layout::vertical([
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0),
]) ])
.areas(right_side_area); .areas(right_side_area);
@@ -161,6 +169,7 @@ fn draw_edit_indexer_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
f.render_widget(interactive_search_checkbox, interactive_search_area); f.render_widget(interactive_search_checkbox, interactive_search_area);
f.render_widget(save_button, save_area); f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area); f.render_widget(cancel_button, cancel_area);
f.render_widget(help_paragraph, help_area);
} }
} else { } else {
f.render_widget(LoadingBlock::new(app.is_loading, block), area); f.render_widget(LoadingBlock::new(app.is_loading, block), area);
@@ -1,8 +1,12 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::text::Text;
use ratatui::widgets::Paragraph;
use ratatui::Frame; use ratatui::Frame;
use crate::app::context_clues::build_context_clue_string;
use crate::app::radarr::radarr_context_clues::CONFIRMATION_PROMPT_CONTEXT_CLUES;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS, ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
@@ -52,33 +56,37 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
let selected_block = app.data.radarr_data.selected_block.get_active_block(); let selected_block = app.data.radarr_data.selected_block.get_active_block();
let highlight_yes_no = selected_block == &ActiveRadarrBlock::IndexerSettingsConfirmPrompt; let highlight_yes_no = selected_block == &ActiveRadarrBlock::IndexerSettingsConfirmPrompt;
let indexer_settings_option = &app.data.radarr_data.indexer_settings; let indexer_settings_option = &app.data.radarr_data.indexer_settings;
let help_text = Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
if indexer_settings_option.is_some() { if indexer_settings_option.is_some() {
let indexer_settings = indexer_settings_option.as_ref().unwrap(); let indexer_settings = indexer_settings_option.as_ref().unwrap();
let [settings_area, buttons_area] = let [settings_area, _, buttons_area, help_area] = Layout::vertical([
Layout::vertical([Constraint::Fill(0), Constraint::Length(3)]) Constraint::Length(15),
.margin(1) Constraint::Fill(1),
.areas(area); Constraint::Length(3),
Constraint::Length(1),
])
.margin(1)
.areas(area);
let [left_side_area, right_side_area] = let [left_side_area, right_side_area] =
Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]) Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)])
.margin(1) .margin(1)
.areas(settings_area); .areas(settings_area);
let [min_age_area, retention_area, max_size_area, prefer_flags_area, _] = Layout::vertical([ let [min_age_area, retention_area, max_size_area, prefer_flags_area] = Layout::vertical([
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0),
]) ])
.areas(left_side_area); .areas(left_side_area);
let [availability_delay_area, rss_sync_interval_area, whitelisted_sub_tags_area, allow_hardcoded_subs_area, _] = let [availability_delay_area, rss_sync_interval_area, whitelisted_sub_tags_area, allow_hardcoded_subs_area] =
Layout::vertical([ Layout::vertical([
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0),
]) ])
.areas(right_side_area); .areas(right_side_area);
@@ -162,6 +170,7 @@ fn draw_edit_indexer_settings_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area:
f.render_widget(allow_hardcoded_subs_checkbox, allow_hardcoded_subs_area); f.render_widget(allow_hardcoded_subs_checkbox, allow_hardcoded_subs_area);
f.render_widget(save_button, save_area); f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area); f.render_widget(cancel_button, cancel_area);
f.render_widget(help_paragraph, help_area);
} else { } else {
f.render_widget(LoadingBlock::new(app.is_loading, block), area); f.render_widget(LoadingBlock::new(app.is_loading, block), area);
} }
+13 -7
View File
@@ -1,12 +1,14 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Cell, ListItem, Paragraph, Row}; use ratatui::widgets::{Cell, ListItem, Paragraph, Row};
use ratatui::Frame; use ratatui::Frame;
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES}; use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
use crate::app::radarr::radarr_context_clues::ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES; use crate::app::radarr::radarr_context_clues::{
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
};
use crate::models::radarr_models::AddMovieSearchResult; use crate::models::radarr_models::AddMovieSearchResult;
use crate::models::servarr_data::radarr::modals::AddMovieModal; use crate::models::servarr_data::radarr::modals::AddMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS}; use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ADD_MOVIE_BLOCKS};
@@ -209,7 +211,7 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let help_text = Text::from(build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES).help()); let help_text = Text::from(build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text) let help_paragraph = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Center); .centered();
search_box.show_cursor(f, search_box_area); search_box.show_cursor(f, search_box_area);
f.render_widget(layout_block(), results_area); f.render_widget(layout_block(), results_area);
@@ -220,7 +222,7 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let help_text = Text::from(build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES).help()); let help_text = Text::from(build_context_clue_string(&BARE_POPUP_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text) let help_paragraph = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Center); .centered();
let error_message = Message::new("No movies found matching your query!"); let error_message = Message::new("No movies found matching your query!");
let error_message_popup = Popup::new(error_message).size(Size::Message); let error_message_popup = Popup::new(error_message).size(Size::Message);
@@ -240,7 +242,7 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
Text::from(build_context_clue_string(&ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES).help()); Text::from(build_context_clue_string(&ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text) let help_paragraph = Paragraph::new(help_text)
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Center); .centered();
let search_results_table = ManagarrTable::new( let search_results_table = ManagarrTable::new(
app.data.radarr_data.add_searched_movies.as_mut(), app.data.radarr_data.add_searched_movies.as_mut(),
search_results_row_mapping, search_results_row_mapping,
@@ -369,7 +371,7 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
f.render_widget(title_block_centered(&title), area); f.render_widget(title_block_centered(&title), area);
let [paragraph_area, root_folder_area, monitor_area, min_availability_area, quality_profile_area, tags_area, _, buttons_area] = let [paragraph_area, root_folder_area, monitor_area, min_availability_area, quality_profile_area, tags_area, _, buttons_area, help_area] =
Layout::vertical([ Layout::vertical([
Constraint::Length(6), Constraint::Length(6),
Constraint::Length(3), Constraint::Length(3),
@@ -377,14 +379,18 @@ fn draw_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0), Constraint::Fill(1),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(1),
]) ])
.margin(1) .margin(1)
.areas(area); .areas(area);
let prompt_paragraph = layout_paragraph_borderless(&prompt); let prompt_paragraph = layout_paragraph_borderless(&prompt);
let help_text = Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
f.render_widget(prompt_paragraph, paragraph_area); f.render_widget(prompt_paragraph, paragraph_area);
f.render_widget(help_paragraph, help_area);
let [add_area, cancel_area] = let [add_area, cancel_area] =
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
+10 -3
View File
@@ -2,9 +2,12 @@ use std::sync::atomic::Ordering;
use ratatui::layout::{Constraint, Rect}; use ratatui::layout::{Constraint, Rect};
use ratatui::prelude::Layout; use ratatui::prelude::Layout;
use ratatui::widgets::ListItem; use ratatui::text::Text;
use ratatui::widgets::{ListItem, Paragraph};
use ratatui::Frame; use ratatui::Frame;
use crate::app::context_clues::build_context_clue_string;
use crate::app::radarr::radarr_context_clues::CONFIRMATION_PROMPT_CONTEXT_CLUES;
use crate::app::App; use crate::app::App;
use crate::models::servarr_data::radarr::modals::EditMovieModal; use crate::models::servarr_data::radarr::modals::EditMovieModal;
use crate::models::servarr_data::radarr::radarr_data::{ use crate::models::servarr_data::radarr::radarr_data::{
@@ -113,7 +116,7 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
let selected_minimum_availability = minimum_availability_list.current_selection(); let selected_minimum_availability = minimum_availability_list.current_selection();
let selected_quality_profile = quality_profile_list.current_selection(); let selected_quality_profile = quality_profile_list.current_selection();
let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, path_area, tags_area, _, buttons_area] = let [paragraph_area, monitored_area, min_availability_area, quality_profile_area, path_area, tags_area, _, buttons_area, help_area] =
Layout::vertical([ Layout::vertical([
Constraint::Length(6), Constraint::Length(6),
Constraint::Length(3), Constraint::Length(3),
@@ -121,8 +124,9 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(3), Constraint::Length(3),
Constraint::Fill(0), Constraint::Fill(1),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(1),
]) ])
.margin(1) .margin(1)
.areas(area); .areas(area);
@@ -130,6 +134,8 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]) Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
.areas(buttons_area); .areas(buttons_area);
let help_text = Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
let prompt_paragraph = layout_paragraph_borderless(&movie_overview); let prompt_paragraph = layout_paragraph_borderless(&movie_overview);
let monitored_checkbox = Checkbox::new("Monitored") let monitored_checkbox = Checkbox::new("Monitored")
.checked(monitored.unwrap_or_default()) .checked(monitored.unwrap_or_default())
@@ -181,6 +187,7 @@ fn draw_edit_movie_confirmation_prompt(f: &mut Frame<'_>, app: &mut App<'_>, are
f.render_widget(quality_profile_drop_down_button, quality_profile_area); f.render_widget(quality_profile_drop_down_button, quality_profile_area);
f.render_widget(save_button, save_area); f.render_widget(save_button, save_area);
f.render_widget(cancel_button, cancel_area); f.render_widget(cancel_button, cancel_area);
f.render_widget(help_paragraph, help_area);
} }
fn draw_edit_movie_select_minimum_availability_popup(f: &mut Frame<'_>, app: &mut App<'_>) { fn draw_edit_movie_select_minimum_availability_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
+2 -2
View File
@@ -1,6 +1,6 @@
use std::iter; use std::iter;
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::style::{Style, Stylize}; use ratatui::style::{Style, Stylize};
use ratatui::text::{Line, Span, Text}; use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Cell, Paragraph, Row, Wrap}; use ratatui::widgets::{Cell, Paragraph, Row, Wrap};
@@ -510,7 +510,7 @@ fn draw_manual_search_confirm_prompt(f: &mut Frame<'_>, app: &mut App<'_>) {
let content_paragraph = Paragraph::new(lines_vec) let content_paragraph = Paragraph::new(lines_vec)
.block(borderless_block()) .block(borderless_block())
.wrap(Wrap { trim: false }) .wrap(Wrap { trim: false })
.alignment(Alignment::Left); .left_aligned();
let confirmation_prompt = ConfirmationPrompt::new() let confirmation_prompt = ConfirmationPrompt::new()
.title(title) .title(title)
.prompt(&prompt) .prompt(&prompt)
+7 -3
View File
@@ -1,7 +1,7 @@
use std::iter; use std::iter;
use chrono::{Duration, Utc}; use chrono::{Duration, Utc};
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::prelude::Stylize; use ratatui::prelude::Stylize;
use ratatui::text::Text; use ratatui::text::Text;
use ratatui::widgets::{Paragraph, Row}; use ratatui::widgets::{Paragraph, Row};
@@ -192,7 +192,11 @@ fn draw_downloads_context(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
size, size,
.. ..
} = &downloads_vec[i]; } = &downloads_vec[i];
let percent = 1f64 - (*sizeleft as f64 / *size as f64); let percent = if *size == 0 {
0.0
} else {
1f64 - (*sizeleft as f64 / *size as f64)
};
let download_gauge = line_gauge_with_title(title, percent); let download_gauge = line_gauge_with_title(title, percent);
f.render_widget(download_gauge, download_item_areas[i]); f.render_widget(download_gauge, download_item_areas[i]);
@@ -244,6 +248,6 @@ fn draw_radarr_logo(f: &mut Frame<'_>, area: Rect) {
let logo = Paragraph::new(logo_text) let logo = Paragraph::new(logo_text)
.light_yellow() .light_yellow()
.block(layout_block().default()) .block(layout_block().default())
.alignment(Alignment::Center); .centered();
f.render_widget(logo, area); f.render_widget(logo, area);
} }
+2 -2
View File
@@ -1,7 +1,7 @@
use std::ops::Sub; use std::ops::Sub;
use chrono::Utc; use chrono::Utc;
use ratatui::layout::{Alignment, Layout}; use ratatui::layout::Layout;
use ratatui::style::Style; use ratatui::style::Style;
use ratatui::text::{Span, Text}; use ratatui::text::{Span, Text};
use ratatui::widgets::{Cell, Paragraph, Row}; use ratatui::widgets::{Cell, Paragraph, Row};
@@ -204,7 +204,7 @@ fn draw_help(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
); );
let help_paragraph = Paragraph::new(help_text) let help_paragraph = Paragraph::new(help_text)
.block(layout_block_top_border()) .block(layout_block_top_border())
.alignment(Alignment::Left); .left_aligned();
f.render_widget(help_paragraph, area); f.render_widget(help_paragraph, area);
} }
+1 -1
View File
@@ -43,7 +43,7 @@ pub fn layout_paragraph_borderless(string: &str) -> Paragraph<'_> {
.primary() .primary()
.bold() .bold()
.wrap(Wrap { trim: false }) .wrap(Wrap { trim: false })
.alignment(Alignment::Center) .centered()
} }
pub fn borderless_block<'a>() -> Block<'a> { pub fn borderless_block<'a>() -> Block<'a> {
+5 -5
View File
@@ -1,7 +1,7 @@
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_block, style_block_highlight}; use crate::ui::utils::{layout_block, style_block_highlight};
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Alignment, Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::prelude::{Style, Text, Widget}; use ratatui::prelude::{Style, Text, Widget};
use ratatui::style::Styled; use ratatui::style::Styled;
use ratatui::widgets::Paragraph; use ratatui::widgets::Paragraph;
@@ -58,11 +58,11 @@ impl<'a> Button<'a> {
if let Some(icon) = self.icon { if let Some(icon) = self.icon {
layout_block().style(style).render(area, buf); layout_block().style(style).render(area, buf);
Paragraph::new(Text::from(self.title)) Paragraph::new(Text::from(self.title))
.alignment(Alignment::Left) .left_aligned()
.style(style) .style(style)
.render(title_area, buf); .render(title_area, buf);
Paragraph::new(Text::from(format!("{icon} "))) Paragraph::new(Text::from(format!("{icon} ")))
.alignment(Alignment::Right) .right_aligned()
.style(style) .style(style)
.render(icon_area, buf); .render(icon_area, buf);
} }
@@ -72,7 +72,7 @@ impl<'a> Button<'a> {
let [label_area, button_area] = let [label_area, button_area] =
Layout::horizontal([Constraint::Percentage(48), Constraint::Percentage(48)]).areas(area); Layout::horizontal([Constraint::Percentage(48), Constraint::Percentage(48)]).areas(area);
let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", self.label.unwrap()))) let label_paragraph = Paragraph::new(Text::from(format!("\n{}: ", self.label.unwrap())))
.alignment(Alignment::Right) .right_aligned()
.primary(); .primary();
if self.icon.is_some() { if self.icon.is_some() {
@@ -87,7 +87,7 @@ impl<'a> Button<'a> {
fn render_button(self, area: Rect, buf: &mut Buffer) { fn render_button(self, area: Rect, buf: &mut Buffer) {
Paragraph::new(Text::from(self.title)) Paragraph::new(Text::from(self.title))
.block(layout_block()) .block(layout_block())
.alignment(Alignment::Center) .centered()
.style(style_block_highlight(self.is_selected)) .style(style_block_highlight(self.is_selected))
.render(area, buf); .render(area, buf);
} }
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{borderless_block, layout_block, style_block_highlight}; use crate::ui::utils::{borderless_block, layout_block, style_block_highlight};
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::prelude::Text; use ratatui::prelude::Text;
use ratatui::style::Stylize; use ratatui::style::Stylize;
use ratatui::widgets::{Paragraph, Widget}; use ratatui::widgets::{Paragraph, Widget};
@@ -47,13 +47,13 @@ impl<'a> Checkbox<'a> {
Paragraph::new(Text::from(format!("\n{}: ", self.label))) Paragraph::new(Text::from(format!("\n{}: ", self.label)))
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Right) .right_aligned()
.primary() .primary()
.render(label_area, buf); .render(label_area, buf);
Paragraph::new(Text::from(check)) Paragraph::new(Text::from(check))
.block(layout_block()) .block(layout_block())
.alignment(Alignment::Center) .centered()
.style(style_block_highlight(self.is_highlighted).bold()) .style(style_block_highlight(self.is_highlighted).bold())
.render(checkbox_box_area, buf); .render(checkbox_box_area, buf);
} }
+27 -8
View File
@@ -1,9 +1,12 @@
use crate::app::context_clues::build_context_clue_string;
use crate::app::radarr::radarr_context_clues::CONFIRMATION_PROMPT_CONTEXT_CLUES;
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{layout_paragraph_borderless, title_block_centered}; use crate::ui::utils::{layout_paragraph_borderless, title_block_centered};
use crate::ui::widgets::button::Button; use crate::ui::widgets::button::Button;
use crate::ui::widgets::checkbox::Checkbox; use crate::ui::widgets::checkbox::Checkbox;
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Constraint, Flex, Layout, Rect}; use ratatui::layout::{Constraint, Flex, Layout, Rect};
use ratatui::text::Text;
use ratatui::widgets::{Paragraph, Widget}; use ratatui::widgets::{Paragraph, Widget};
use std::iter; use std::iter;
@@ -64,12 +67,16 @@ impl<'a> ConfirmationPrompt<'a> {
fn render_confirmation_prompt_with_checkboxes(self, area: Rect, buf: &mut Buffer) { fn render_confirmation_prompt_with_checkboxes(self, area: Rect, buf: &mut Buffer) {
title_block_centered(self.title).render(area, buf); title_block_centered(self.title).render(area, buf);
let help_text =
Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
if let Some(checkboxes) = self.checkboxes { if let Some(checkboxes) = self.checkboxes {
let mut constraints = vec![ let mut constraints = vec![
Constraint::Length(4), Constraint::Length(4),
Constraint::Fill(0), Constraint::Fill(1),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(1),
]; ];
constraints.splice( constraints.splice(
1..1, 1..1,
@@ -81,6 +88,7 @@ impl<'a> ConfirmationPrompt<'a> {
.areas(chunks[checkboxes.len() + 2]); .areas(chunks[checkboxes.len() + 2]);
layout_paragraph_borderless(self.prompt).render(chunks[0], buf); layout_paragraph_borderless(self.prompt).render(chunks[0], buf);
help_paragraph.render(chunks[checkboxes.len() + 3], buf);
checkboxes checkboxes
.into_iter() .into_iter()
@@ -102,26 +110,37 @@ impl<'a> ConfirmationPrompt<'a> {
fn render_confirmation_prompt(self, area: Rect, buf: &mut Buffer) { fn render_confirmation_prompt(self, area: Rect, buf: &mut Buffer) {
title_block_centered(self.title).render(area, buf); title_block_centered(self.title).render(area, buf);
let help_text =
Text::from(build_context_clue_string(&CONFIRMATION_PROMPT_CONTEXT_CLUES).help());
let help_paragraph = Paragraph::new(help_text).centered();
let [prompt_area, buttons_area] = if let Some(content_paragraph) = self.content { let [prompt_area, buttons_area] = if let Some(content_paragraph) = self.content {
let [prompt_area, content_area, _, buttons_area] = Layout::vertical([ let [prompt_area, content_area, _, buttons_area, help_area] = Layout::vertical([
Constraint::Length(4), Constraint::Length(4),
Constraint::Length(7), Constraint::Length(7),
Constraint::Fill(0), Constraint::Fill(1),
Constraint::Length(3), Constraint::Length(3),
Constraint::Length(1),
]) ])
.margin(1) .margin(1)
.areas(area); .areas(area);
content_paragraph.render(content_area, buf); content_paragraph.render(content_area, buf);
help_paragraph.render(help_area, buf);
[prompt_area, buttons_area] [prompt_area, buttons_area]
} else { } else {
let [prompt_area, buttons_area] = let [prompt_area, buttons_area, _, help_area] = Layout::vertical([
Layout::vertical([Constraint::Percentage(72), Constraint::Length(3)]) Constraint::Percentage(72),
.margin(1) Constraint::Length(3),
.flex(Flex::SpaceBetween) Constraint::Fill(0),
.areas(area); Constraint::Min(1),
])
.margin(1)
.flex(Flex::SpaceBetween)
.areas(area);
help_paragraph.render(help_area, buf);
[prompt_area, buttons_area] [prompt_area, buttons_area]
}; };
+2 -2
View File
@@ -1,5 +1,5 @@
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Alignment, Constraint, Layout, Position, Rect}; use ratatui::layout::{Constraint, Layout, Position, Rect};
use ratatui::prelude::Text; use ratatui::prelude::Text;
use ratatui::style::{Style, Styled, Stylize}; use ratatui::style::{Style, Styled, Stylize};
use ratatui::widgets::{Block, Paragraph, Widget}; use ratatui::widgets::{Block, Paragraph, Widget};
@@ -114,7 +114,7 @@ impl<'a> InputBox<'a> {
Paragraph::new(Text::from(format!("\n{label}: "))) Paragraph::new(Text::from(format!("\n{label}: ")))
.block(borderless_block()) .block(borderless_block())
.alignment(Alignment::Right) .right_aligned()
.primary() .primary()
.render(label_area, buf); .render(label_area, buf);
input_box_paragraph.render(text_box_area, buf); input_box_paragraph.render(text_box_area, buf);
+3 -3
View File
@@ -1,7 +1,7 @@
use crate::ui::styles::ManagarrStyle; use crate::ui::styles::ManagarrStyle;
use crate::ui::utils::{background_block, centered_rect, layout_block_top_border}; use crate::ui::utils::{background_block, centered_rect, layout_block_top_border};
use ratatui::buffer::Buffer; use ratatui::buffer::Buffer;
use ratatui::layout::{Alignment, Constraint, Layout, Rect}; use ratatui::layout::{Constraint, Layout, Rect};
use ratatui::prelude::Text; use ratatui::prelude::Text;
use ratatui::widgets::{Block, Clear, Paragraph, Widget}; use ratatui::widgets::{Block, Clear, Paragraph, Widget};
@@ -27,7 +27,7 @@ impl Size {
pub fn to_percent(&self) -> (u16, u16) { pub fn to_percent(&self) -> (u16, u16) {
match self { match self {
Size::SmallPrompt => (20, 20), Size::SmallPrompt => (20, 20),
Size::Prompt => (35, 35), Size::Prompt => (37, 37),
Size::LargePrompt => (70, 45), Size::LargePrompt => (70, 45),
Size::Message => (25, 8), Size::Message => (25, 8),
Size::NarrowMessage => (50, 20), Size::NarrowMessage => (50, 20),
@@ -100,7 +100,7 @@ impl<'a, T: Widget> Popup<'a, T> {
Paragraph::new(Text::from(format!(" {footer}").help())) Paragraph::new(Text::from(format!(" {footer}").help()))
.block(layout_block_top_border()) .block(layout_block_top_border())
.alignment(Alignment::Left) .left_aligned()
.render(help_footer_area, buf); .render(help_footer_area, buf);
content_area content_area
+1 -1
View File
@@ -7,7 +7,7 @@ mod tests {
#[test] #[test]
fn test_dimensions_to_percent() { fn test_dimensions_to_percent() {
assert_eq!(Size::SmallPrompt.to_percent(), (20, 20)); assert_eq!(Size::SmallPrompt.to_percent(), (20, 20));
assert_eq!(Size::Prompt.to_percent(), (35, 35)); assert_eq!(Size::Prompt.to_percent(), (37, 37));
assert_eq!(Size::LargePrompt.to_percent(), (70, 45)); assert_eq!(Size::LargePrompt.to_percent(), (70, 45));
assert_eq!(Size::Message.to_percent(), (25, 8)); assert_eq!(Size::Message.to_percent(), (25, 8));
assert_eq!(Size::NarrowMessage.to_percent(), (50, 20)); assert_eq!(Size::NarrowMessage.to_percent(), (50, 20));