Added the ability to edit existing indexers with basic options, added a tags column to the indexers table, and fixed a bug in the counter fields that displayed the cursor next to the integer instead of on it to make understanding the counter easier. Also upgraded to confy v0.60.0 and rust version to 1.75

This commit is contained in:
2024-01-19 15:45:41 -07:00
parent 3d249cc51c
commit 2ec4472efc
29 changed files with 3513 additions and 362 deletions
@@ -0,0 +1,431 @@
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App;
use crate::event::Key;
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
use crate::network::radarr_network::RadarrEvent;
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
#[cfg(test)]
#[path = "edit_indexer_handler_tests.rs"]
mod edit_indexer_handler_tests;
pub(super) struct EditIndexerHandler<'a, 'b> {
key: &'a Key,
app: &'a mut App<'b>,
active_radarr_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
}
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'a, 'b> {
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
EDIT_INDEXER_BLOCKS.contains(active_block)
}
fn with(
key: &'a Key,
app: &'a mut App<'b>,
active_block: &'a ActiveRadarrBlock,
_context: &'a Option<ActiveRadarrBlock>,
) -> EditIndexerHandler<'a, 'b> {
EditIndexerHandler {
key,
app,
active_radarr_block: active_block,
_context,
}
}
fn get_key(&self) -> &Key {
self.key
}
fn handle_scroll_up(&mut self) {
if self.active_radarr_block == &ActiveRadarrBlock::EditIndexerPrompt {
self.app.data.radarr_data.selected_block.previous();
}
}
fn handle_scroll_down(&mut self) {
if self.active_radarr_block == &ActiveRadarrBlock::EditIndexerPrompt {
self.app.data.radarr_data.selected_block.next();
}
}
fn handle_home(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerNameInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.name
.scroll_home();
}
ActiveRadarrBlock::EditIndexerUrlInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.url
.scroll_home();
}
ActiveRadarrBlock::EditIndexerApiKeyInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.api_key
.scroll_home();
}
ActiveRadarrBlock::EditIndexerSeedRatioInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.seed_ratio
.scroll_home();
}
ActiveRadarrBlock::EditIndexerTagsInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.tags
.scroll_home();
}
_ => (),
}
}
fn handle_end(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerNameInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.name
.reset_offset();
}
ActiveRadarrBlock::EditIndexerUrlInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.url
.reset_offset();
}
ActiveRadarrBlock::EditIndexerApiKeyInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.api_key
.reset_offset();
}
ActiveRadarrBlock::EditIndexerSeedRatioInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.seed_ratio
.reset_offset();
}
ActiveRadarrBlock::EditIndexerTagsInput => {
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.tags
.reset_offset();
}
_ => (),
}
}
fn handle_delete(&mut self) {}
fn handle_left_right_action(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerPrompt => {
if self.app.data.radarr_data.selected_block.get_active_block()
== &ActiveRadarrBlock::EditIndexerConfirmPrompt
{
handle_prompt_toggle(self.app, self.key);
} else {
let len = self.app.data.radarr_data.selected_block.blocks.len();
let idx = self.app.data.radarr_data.selected_block.index;
self.app.data.radarr_data.selected_block.index = (idx + 5) % len;
}
}
ActiveRadarrBlock::EditIndexerNameInput => {
handle_text_box_left_right_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.name
);
}
ActiveRadarrBlock::EditIndexerUrlInput => {
handle_text_box_left_right_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.url
);
}
ActiveRadarrBlock::EditIndexerApiKeyInput => {
handle_text_box_left_right_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.api_key
);
}
ActiveRadarrBlock::EditIndexerSeedRatioInput => {
handle_text_box_left_right_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.seed_ratio
);
}
ActiveRadarrBlock::EditIndexerTagsInput => {
handle_text_box_left_right_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.tags
);
}
_ => (),
}
}
fn handle_submit(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerPrompt => {
let selected_block = *self.app.data.radarr_data.selected_block.get_active_block();
match selected_block {
ActiveRadarrBlock::EditIndexerConfirmPrompt => {
let radarr_data = &mut self.app.data.radarr_data;
if radarr_data.prompt_confirm {
radarr_data.prompt_confirm_action = Some(RadarrEvent::EditIndexer);
self.app.should_refresh = true;
} else {
radarr_data.edit_indexer_modal = None;
}
self.app.pop_navigation_stack();
}
ActiveRadarrBlock::EditIndexerNameInput
| ActiveRadarrBlock::EditIndexerUrlInput
| ActiveRadarrBlock::EditIndexerApiKeyInput
| ActiveRadarrBlock::EditIndexerSeedRatioInput
| ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.push_navigation_stack(selected_block.into());
self.app.should_ignore_quit_key = true;
}
ActiveRadarrBlock::EditIndexerToggleEnableRss => {
let indexer = self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap();
indexer.enable_rss = Some(!indexer.enable_rss.unwrap_or_default());
}
ActiveRadarrBlock::EditIndexerToggleEnableAutomaticSearch => {
let indexer = self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap();
indexer.enable_automatic_search =
Some(!indexer.enable_automatic_search.unwrap_or_default());
}
ActiveRadarrBlock::EditIndexerToggleEnableInteractiveSearch => {
let indexer = self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap();
indexer.enable_interactive_search =
Some(!indexer.enable_interactive_search.unwrap_or_default());
}
_ => (),
}
}
ActiveRadarrBlock::EditIndexerNameInput
| ActiveRadarrBlock::EditIndexerUrlInput
| ActiveRadarrBlock::EditIndexerApiKeyInput
| ActiveRadarrBlock::EditIndexerSeedRatioInput
| ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false;
}
_ => (),
}
}
fn handle_esc(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerPrompt => {
self.app.pop_navigation_stack();
self.app.data.radarr_data.prompt_confirm = false;
self.app.data.radarr_data.edit_indexer_modal = None;
}
ActiveRadarrBlock::EditIndexerNameInput
| ActiveRadarrBlock::EditIndexerUrlInput
| ActiveRadarrBlock::EditIndexerApiKeyInput
| ActiveRadarrBlock::EditIndexerSeedRatioInput
| ActiveRadarrBlock::EditIndexerTagsInput => {
self.app.pop_navigation_stack();
self.app.should_ignore_quit_key = false;
}
_ => self.app.pop_navigation_stack(),
}
}
fn handle_char_key_event(&mut self) {
match self.active_radarr_block {
ActiveRadarrBlock::EditIndexerNameInput => {
handle_text_box_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.name
);
}
ActiveRadarrBlock::EditIndexerUrlInput => {
handle_text_box_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.url
);
}
ActiveRadarrBlock::EditIndexerApiKeyInput => {
handle_text_box_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.api_key
);
}
ActiveRadarrBlock::EditIndexerSeedRatioInput => {
handle_text_box_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.seed_ratio
);
}
ActiveRadarrBlock::EditIndexerTagsInput => {
handle_text_box_keys!(
self,
self.key,
self
.app
.data
.radarr_data
.edit_indexer_modal
.as_mut()
.unwrap()
.tags
);
}
_ => (),
}
}
}
File diff suppressed because it is too large Load Diff
@@ -46,7 +46,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
match self.active_radarr_block {
ActiveRadarrBlock::IndexerSettingsPrompt => {
self.app.data.radarr_data.selected_block.previous()
self.app.data.radarr_data.selected_block.previous();
}
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput => {
indexer_settings.minimum_age += 1;
@@ -166,7 +166,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
ActiveRadarrBlock::IndexerSettingsConfirmPrompt => {
let radarr_data = &mut self.app.data.radarr_data;
if radarr_data.prompt_confirm {
radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateIndexerSettings);
radarr_data.prompt_confirm_action = Some(RadarrEvent::EditAllIndexerSettings);
self.app.should_refresh = true;
} else {
radarr_data.indexer_settings = None;
@@ -456,7 +456,7 @@ mod tests {
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
assert_eq!(
app.data.radarr_data.prompt_confirm_action,
Some(RadarrEvent::UpdateIndexerSettings)
Some(RadarrEvent::EditAllIndexerSettings)
);
assert!(app.data.radarr_data.indexer_settings.is_some());
assert!(app.should_refresh);
@@ -7,10 +7,10 @@ mod tests {
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App;
use crate::event::Key;
use crate::handlers::radarr_handlers::indexers::{IndexersHandler, TestAllIndexersHandler};
use crate::handlers::radarr_handlers::indexers::IndexersHandler;
use crate::handlers::KeyEventHandler;
use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXERS_BLOCKS, INDEXER_SETTINGS_BLOCKS,
ActiveRadarrBlock, EDIT_INDEXER_BLOCKS, INDEXERS_BLOCKS, INDEXER_SETTINGS_BLOCKS,
};
use crate::test_handler_delegation;
@@ -147,7 +147,14 @@ mod tests {
}
mod test_handle_submit {
use crate::models::radarr_models::{Indexer, IndexerField};
use crate::models::servarr_data::radarr::modals::EditIndexerModal;
use crate::models::servarr_data::radarr::radarr_data::{
RadarrData, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
};
use bimap::BiMap;
use pretty_assertions::assert_eq;
use serde_json::{Number, Value};
use crate::network::radarr_network::RadarrEvent;
@@ -155,16 +162,85 @@ mod tests {
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
#[test]
fn test_indexer_submit_aka_edit() {
#[rstest]
fn test_edit_indexer_submit(#[values(true, false)] torrent_protocol: bool) {
let mut app = App::default();
let protocol = if torrent_protocol {
"torrent".to_owned()
} else {
"usenet".to_owned()
};
let mut expected_edit_indexer_modal = EditIndexerModal {
name: "Test".into(),
enable_rss: Some(true),
enable_automatic_search: Some(true),
enable_interactive_search: Some(true),
url: "https://test.com".into(),
api_key: "1234".into(),
tags: "usenet, test".into(),
..EditIndexerModal::default()
};
let mut radarr_data = RadarrData {
tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]),
..RadarrData::default()
};
let mut fields = vec![
IndexerField {
name: Some("baseUrl".to_owned()),
value: Some(Value::String("https://test.com".to_owned())),
},
IndexerField {
name: Some("apiKey".to_owned()),
value: Some(Value::String("1234".to_owned())),
},
];
if torrent_protocol {
fields.push(IndexerField {
name: Some("seedCriteria.seedRatio".to_owned()),
value: Some(Value::from(1.2f64)),
});
expected_edit_indexer_modal.seed_ratio = "1.2".into();
}
let indexer = Indexer {
name: Some("Test".to_owned()),
enable_rss: true,
enable_automatic_search: true,
enable_interactive_search: true,
protocol,
tags: vec![Number::from(1), Number::from(2)],
fields: Some(fields),
..Indexer::default()
};
radarr_data.indexers.set_items(vec![indexer]);
app.data.radarr_data = radarr_data;
IndexersHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
assert_eq!(
app.get_current_route(),
&ActiveRadarrBlock::EditIndexer.into()
&ActiveRadarrBlock::EditIndexerPrompt.into()
);
assert_eq!(
app.data.radarr_data.edit_indexer_modal,
Some((&app.data.radarr_data).into())
);
assert_eq!(
app.data.radarr_data.edit_indexer_modal,
Some(expected_edit_indexer_modal)
);
if torrent_protocol {
assert_eq!(
app.data.radarr_data.selected_block.blocks,
&EDIT_INDEXER_TORRENT_SELECTION_BLOCKS
);
} else {
assert_eq!(
app.data.radarr_data.selected_block.blocks,
&EDIT_INDEXER_NZB_SELECTION_BLOCKS
);
}
}
#[test]
@@ -322,6 +398,29 @@ mod tests {
}
}
#[rstest]
fn test_delegates_edit_indexer_blocks_to_edit_indexer_handler(
#[values(
ActiveRadarrBlock::EditIndexerPrompt,
ActiveRadarrBlock::EditIndexerConfirmPrompt,
ActiveRadarrBlock::EditIndexerApiKeyInput,
ActiveRadarrBlock::EditIndexerNameInput,
ActiveRadarrBlock::EditIndexerSeedRatioInput,
ActiveRadarrBlock::EditIndexerToggleEnableRss,
ActiveRadarrBlock::EditIndexerToggleEnableAutomaticSearch,
ActiveRadarrBlock::EditIndexerToggleEnableInteractiveSearch,
ActiveRadarrBlock::EditIndexerUrlInput,
ActiveRadarrBlock::EditIndexerTagsInput
)]
active_radarr_block: ActiveRadarrBlock,
) {
test_handler_delegation!(
IndexersHandler,
ActiveRadarrBlock::Indexers,
active_radarr_block
);
}
#[rstest]
fn test_delegates_indexer_settings_blocks_to_indexer_settings_handler(
#[values(
@@ -348,7 +447,7 @@ mod tests {
#[test]
fn test_delegates_test_all_indexers_block_to_test_all_indexers_handler() {
test_handler_delegation!(
TestAllIndexersHandler,
IndexersHandler,
ActiveRadarrBlock::Indexers,
ActiveRadarrBlock::TestAllIndexers
);
@@ -359,6 +458,8 @@ mod tests {
let mut indexers_blocks = Vec::new();
indexers_blocks.extend(INDEXERS_BLOCKS);
indexers_blocks.extend(INDEXER_SETTINGS_BLOCKS);
indexers_blocks.extend(EDIT_INDEXER_BLOCKS);
indexers_blocks.push(ActiveRadarrBlock::TestAllIndexers);
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
if indexers_blocks.contains(&active_radarr_block) {
+28 -3
View File
@@ -2,15 +2,18 @@ use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::app::App;
use crate::event::Key;
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
ActiveRadarrBlock, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
};
use crate::models::{BlockSelectionState, Scrollable};
use crate::network::radarr_network::RadarrEvent;
mod edit_indexer_handler;
mod edit_indexer_settings_handler;
mod test_all_indexers_handler;
@@ -28,6 +31,10 @@ pub(super) struct IndexersHandler<'a, 'b> {
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a, 'b> {
fn handle(&mut self) {
match self.active_radarr_block {
_ if EditIndexerHandler::accepts(self.active_radarr_block) => {
EditIndexerHandler::with(self.key, self.app, self.active_radarr_block, self.context)
.handle()
}
_ if IndexerSettingsHandler::accepts(self.active_radarr_block) => {
IndexerSettingsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
.handle()
@@ -41,7 +48,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
}
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
IndexerSettingsHandler::accepts(active_block) || INDEXERS_BLOCKS.contains(active_block)
EditIndexerHandler::accepts(active_block)
|| IndexerSettingsHandler::accepts(active_block)
|| TestAllIndexersHandler::accepts(active_block)
|| INDEXERS_BLOCKS.contains(active_block)
}
fn with(
@@ -115,7 +125,22 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
ActiveRadarrBlock::Indexers => {
self
.app
.push_navigation_stack(ActiveRadarrBlock::EditIndexer.into());
.push_navigation_stack(ActiveRadarrBlock::EditIndexerPrompt.into());
self.app.data.radarr_data.edit_indexer_modal = Some((&self.app.data.radarr_data).into());
let protocol = &self
.app
.data
.radarr_data
.indexers
.current_selection()
.protocol;
if protocol == "torrent" {
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_INDEXER_TORRENT_SELECTION_BLOCKS);
} else {
self.app.data.radarr_data.selected_block =
BlockSelectionState::new(&EDIT_INDEXER_NZB_SELECTION_BLOCKS);
}
}
_ => (),
}