From d97c20d5ac70f7055989487d44918abf2aada2a5 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Thu, 3 Sep 2026 12:00:40 -0600 Subject: [PATCH] feat(readarr): reach the book file info tab from the book details tabs The book details handler already accepted the book file info block, but the tab state declared only three tabs, so left and right could never reach it. Add the File tab between History and Manual Search, backed by a new context clue static covering refresh, delete book file, and esc. --- src/app/readarr/readarr_context_clues.rs | 9 ++++++ .../readarr/readarr_context_clues_tests.rs | 30 +++++++++++++++++-- .../library/book_details_handler_tests.rs | 3 +- src/models/servarr_data/readarr/modals.rs | 9 +++++- .../servarr_data/readarr/modals_tests.rs | 28 ++++++++++++----- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/app/readarr/readarr_context_clues.rs b/src/app/readarr/readarr_context_clues.rs index 44f3a2bf..aad10fec 100644 --- a/src/app/readarr/readarr_context_clues.rs +++ b/src/app/readarr/readarr_context_clues.rs @@ -124,6 +124,15 @@ pub static BOOK_HISTORY_CONTEXT_CLUES: [ContextClue; 7] = [ (DEFAULT_KEYBINDINGS.esc, "cancel filter/close"), ]; +pub static BOOK_FILE_CONTEXT_CLUES: [ContextClue; 3] = [ + ( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc, + ), + (DEFAULT_KEYBINDINGS.delete, "delete book file"), + (DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc), +]; + pub static MANUAL_BOOK_SEARCH_CONTEXT_CLUES: [ContextClue; 5] = [ ( DEFAULT_KEYBINDINGS.refresh, diff --git a/src/app/readarr/readarr_context_clues_tests.rs b/src/app/readarr/readarr_context_clues_tests.rs index b0ef4ec0..47cb11af 100644 --- a/src/app/readarr/readarr_context_clues_tests.rs +++ b/src/app/readarr/readarr_context_clues_tests.rs @@ -9,8 +9,9 @@ mod tests { use crate::app::readarr::readarr_context_clues::{ ADD_AUTHOR_SEARCH_RESULTS_CONTEXT_CLUES, AUTHOR_DETAILS_CONTEXT_CLUES, AUTHOR_HISTORY_CONTEXT_CLUES, AUTHORS_CONTEXT_CLUES, BOOK_DETAILS_CONTEXT_CLUES, - BOOK_HISTORY_CONTEXT_CLUES, EDITION_DETAILS_CONTEXT_CLUES, MANUAL_AUTHOR_SEARCH_CONTEXT_CLUES, - MANUAL_BOOK_SEARCH_CONTEXT_CLUES, ReadarrContextClueProvider, + BOOK_FILE_CONTEXT_CLUES, BOOK_HISTORY_CONTEXT_CLUES, EDITION_DETAILS_CONTEXT_CLUES, + MANUAL_AUTHOR_SEARCH_CONTEXT_CLUES, MANUAL_BOOK_SEARCH_CONTEXT_CLUES, + ReadarrContextClueProvider, }; use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock; use crate::models::servarr_data::readarr::modals::BookDetailsModal; @@ -316,6 +317,28 @@ mod tests { assert_none!(book_history_context_clues_iter.next()); } + #[test] + fn test_book_file_context_clues() { + let mut book_file_context_clues_iter = BOOK_FILE_CONTEXT_CLUES.iter(); + + assert_some_eq_x!( + book_file_context_clues_iter.next(), + &( + DEFAULT_KEYBINDINGS.refresh, + DEFAULT_KEYBINDINGS.refresh.desc + ) + ); + assert_some_eq_x!( + book_file_context_clues_iter.next(), + &(DEFAULT_KEYBINDINGS.delete, "delete book file") + ); + assert_some_eq_x!( + book_file_context_clues_iter.next(), + &(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc) + ); + assert_none!(book_file_context_clues_iter.next()); + } + #[test] fn test_manual_book_search_context_clues() { let mut manual_book_search_context_clues_iter = MANUAL_BOOK_SEARCH_CONTEXT_CLUES.iter(); @@ -389,7 +412,8 @@ mod tests { #[rstest] #[case(0, ActiveReadarrBlock::BookDetails, &BOOK_DETAILS_CONTEXT_CLUES)] #[case(1, ActiveReadarrBlock::BookHistory, &BOOK_HISTORY_CONTEXT_CLUES)] - #[case(2, ActiveReadarrBlock::ManualBookSearch, &MANUAL_BOOK_SEARCH_CONTEXT_CLUES)] + #[case(2, ActiveReadarrBlock::BookFileInfo, &BOOK_FILE_CONTEXT_CLUES)] + #[case(3, ActiveReadarrBlock::ManualBookSearch, &MANUAL_BOOK_SEARCH_CONTEXT_CLUES)] fn test_readarr_context_clue_provider_book_details_tabs( #[case] index: usize, #[case] active_readarr_block: ActiveReadarrBlock, diff --git a/src/handlers/readarr_handlers/library/book_details_handler_tests.rs b/src/handlers/readarr_handlers/library/book_details_handler_tests.rs index 886ebdef..e539fb12 100644 --- a/src/handlers/readarr_handlers/library/book_details_handler_tests.rs +++ b/src/handlers/readarr_handlers/library/book_details_handler_tests.rs @@ -208,7 +208,8 @@ mod tests { #[rstest] #[case(ActiveReadarrBlock::BookDetails, ActiveReadarrBlock::BookHistory)] - #[case(ActiveReadarrBlock::BookHistory, ActiveReadarrBlock::ManualBookSearch)] + #[case(ActiveReadarrBlock::BookHistory, ActiveReadarrBlock::BookFileInfo)] + #[case(ActiveReadarrBlock::BookFileInfo, ActiveReadarrBlock::ManualBookSearch)] #[case(ActiveReadarrBlock::ManualBookSearch, ActiveReadarrBlock::BookDetails)] fn test_book_details_tabs_left_right_action( #[case] left_block: ActiveReadarrBlock, diff --git a/src/models/servarr_data/readarr/modals.rs b/src/models/servarr_data/readarr/modals.rs index 30b0a817..b696796d 100644 --- a/src/models/servarr_data/readarr/modals.rs +++ b/src/models/servarr_data/readarr/modals.rs @@ -1,6 +1,7 @@ use super::readarr_data::{ActiveReadarrBlock, ReadarrData}; use crate::app::readarr::readarr_context_clues::{ - BOOK_DETAILS_CONTEXT_CLUES, BOOK_HISTORY_CONTEXT_CLUES, MANUAL_BOOK_SEARCH_CONTEXT_CLUES, + BOOK_DETAILS_CONTEXT_CLUES, BOOK_FILE_CONTEXT_CLUES, BOOK_HISTORY_CONTEXT_CLUES, + MANUAL_BOOK_SEARCH_CONTEXT_CLUES, }; use crate::models::readarr_models::{BookFile, Edition, ReadarrHistoryItem, ReadarrRelease}; use crate::models::servarr_data::modals::EditIndexerModal; @@ -253,6 +254,12 @@ impl Default for BookDetailsModal { contextual_help: Some(&BOOK_HISTORY_CONTEXT_CLUES), config: None, }, + TabRoute { + title: "File".to_string(), + route: ActiveReadarrBlock::BookFileInfo.into(), + contextual_help: Some(&BOOK_FILE_CONTEXT_CLUES), + config: None, + }, TabRoute { title: "Manual Search".to_string(), route: ActiveReadarrBlock::ManualBookSearch.into(), diff --git a/src/models/servarr_data/readarr/modals_tests.rs b/src/models/servarr_data/readarr/modals_tests.rs index 3d7f7c7a..c6695a15 100644 --- a/src/models/servarr_data/readarr/modals_tests.rs +++ b/src/models/servarr_data/readarr/modals_tests.rs @@ -1,7 +1,8 @@ #[cfg(test)] mod tests { use crate::app::readarr::readarr_context_clues::{ - BOOK_DETAILS_CONTEXT_CLUES, BOOK_HISTORY_CONTEXT_CLUES, MANUAL_BOOK_SEARCH_CONTEXT_CLUES, + BOOK_DETAILS_CONTEXT_CLUES, BOOK_FILE_CONTEXT_CLUES, BOOK_HISTORY_CONTEXT_CLUES, + MANUAL_BOOK_SEARCH_CONTEXT_CLUES, }; use crate::models::readarr_models::{Author, MonitorType, NewItemMonitorType}; use crate::models::servarr_data::modals::EditIndexerModal; @@ -268,7 +269,7 @@ mod tests { assert_is_empty!(book_details_modal.book_releases); assert_is_empty!(book_details_modal.book_history); - assert_eq!(book_details_modal.book_details_tabs.tabs.len(), 3); + assert_eq!(book_details_modal.book_details_tabs.tabs.len(), 4); assert_str_eq!( book_details_modal.book_details_tabs.tabs[0].title, @@ -298,19 +299,30 @@ mod tests { ); assert_none!(book_details_modal.book_details_tabs.tabs[1].config); - assert_str_eq!( - book_details_modal.book_details_tabs.tabs[2].title, - "Manual Search" - ); + assert_str_eq!(book_details_modal.book_details_tabs.tabs[2].title, "File"); assert_eq!( book_details_modal.book_details_tabs.tabs[2].route, - ActiveReadarrBlock::ManualBookSearch.into() + ActiveReadarrBlock::BookFileInfo.into() ); assert_some_eq_x!( &book_details_modal.book_details_tabs.tabs[2].contextual_help, - &MANUAL_BOOK_SEARCH_CONTEXT_CLUES + &BOOK_FILE_CONTEXT_CLUES ); assert_none!(book_details_modal.book_details_tabs.tabs[2].config); + + assert_str_eq!( + book_details_modal.book_details_tabs.tabs[3].title, + "Manual Search" + ); + assert_eq!( + book_details_modal.book_details_tabs.tabs[3].route, + ActiveReadarrBlock::ManualBookSearch.into() + ); + assert_some_eq_x!( + &book_details_modal.book_details_tabs.tabs[3].contextual_help, + &MANUAL_BOOK_SEARCH_CONTEXT_CLUES + ); + assert_none!(book_details_modal.book_details_tabs.tabs[3].config); } #[test]