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.
This commit is contained in:
Dark-Alex-17 committed 2026-09-03 12:00:40 -06:00
1 parent 751ff6ecf5
commit d97c20d5ac
5 files changed
+66 -13

No files matched your search

+9
View File
@@ -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,
+27 -3
View File
@@ -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,
@@ -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,
+8 -1
View File
@@ -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(),
@@ -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]