feat: Created a History tab in the Radarr UI and created a list history command and mark-history-item-as-failed command for Radarr
This commit is contained in:
@@ -62,6 +62,11 @@ impl App<'_> {
|
||||
.dispatch_network_event(RadarrEvent::GetDownloads(500).into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::History => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::GetHistory(500).into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::Indexers => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::GetTags.into())
|
||||
|
||||
@@ -3,8 +3,8 @@ mod tests {
|
||||
use crate::app::App;
|
||||
use crate::app::context_clues::{
|
||||
BARE_POPUP_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
|
||||
ContextClue, ContextClueProvider, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
ContextClue, ContextClueProvider, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES,
|
||||
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::app::radarr::radarr_context_clues::{
|
||||
@@ -459,9 +459,10 @@ mod tests {
|
||||
#[case(1, ActiveRadarrBlock::Collections, &COLLECTIONS_CONTEXT_CLUES)]
|
||||
#[case(2, ActiveRadarrBlock::Downloads, &DOWNLOADS_CONTEXT_CLUES)]
|
||||
#[case(3, ActiveRadarrBlock::Blocklist, &BLOCKLIST_CONTEXT_CLUES)]
|
||||
#[case(4, ActiveRadarrBlock::RootFolders, &ROOT_FOLDERS_CONTEXT_CLUES)]
|
||||
#[case(5, ActiveRadarrBlock::Indexers, &INDEXERS_CONTEXT_CLUES)]
|
||||
#[case(6, ActiveRadarrBlock::System, &SYSTEM_CONTEXT_CLUES)]
|
||||
#[case(4, ActiveRadarrBlock::History, &HISTORY_CONTEXT_CLUES)]
|
||||
#[case(5, ActiveRadarrBlock::RootFolders, &ROOT_FOLDERS_CONTEXT_CLUES)]
|
||||
#[case(6, ActiveRadarrBlock::Indexers, &INDEXERS_CONTEXT_CLUES)]
|
||||
#[case(7, ActiveRadarrBlock::System, &SYSTEM_CONTEXT_CLUES)]
|
||||
fn test_radarr_context_clue_provider_radarr_blocks_context_clues(
|
||||
#[case] index: usize,
|
||||
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||
|
||||
@@ -147,6 +147,23 @@ mod tests {
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_history_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
app
|
||||
.dispatch_by_radarr_block(&ActiveRadarrBlock::History)
|
||||
.await;
|
||||
|
||||
assert!(app.is_loading);
|
||||
assert_eq!(
|
||||
sync_network_rx.recv().await.unwrap(),
|
||||
RadarrEvent::GetHistory(500).into()
|
||||
);
|
||||
assert!(!app.data.radarr_data.prompt_confirm);
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_root_folders_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
@@ -29,6 +29,11 @@ pub enum RadarrListCommand {
|
||||
},
|
||||
#[command(about = "List disk space details for all provisioned root folders in Radarr")]
|
||||
DiskSpace,
|
||||
#[command(about = "Fetch all Radarr history events")]
|
||||
History {
|
||||
#[arg(long, help = "How many history events to fetch", default_value_t = 500)]
|
||||
events: u64,
|
||||
},
|
||||
#[command(about = "List all Radarr indexers")]
|
||||
Indexers,
|
||||
#[command(about = "Fetch Radarr logs")]
|
||||
@@ -121,6 +126,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrListCommand> for RadarrListCommandH
|
||||
.await?;
|
||||
serde_json::to_string_pretty(&resp)?
|
||||
}
|
||||
RadarrListCommand::History { events: items } => {
|
||||
let resp = self
|
||||
.network
|
||||
.handle_network_event(RadarrEvent::GetHistory(items).into())
|
||||
.await?;
|
||||
serde_json::to_string_pretty(&resp)?
|
||||
}
|
||||
RadarrListCommand::Indexers => {
|
||||
let resp = self
|
||||
.network
|
||||
|
||||
@@ -111,6 +111,29 @@ mod tests {
|
||||
assert_eq!(refresh_command, expected_args);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_history_events_flag_requires_arguments() {
|
||||
let result =
|
||||
Cli::command().try_get_matches_from(["managarr", "radarr", "list", "history", "--events"]);
|
||||
|
||||
assert_err!(&result);
|
||||
assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_history_default_values() {
|
||||
let expected_args = RadarrListCommand::History { events: 500 };
|
||||
let result = Cli::try_parse_from(["managarr", "radarr", "list", "history"]);
|
||||
|
||||
assert_ok!(&result);
|
||||
|
||||
let Some(Command::Radarr(RadarrCommand::List(history_command))) = result.unwrap().command
|
||||
else {
|
||||
panic!("Unexpected command type");
|
||||
};
|
||||
assert_eq!(history_command, expected_args);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_list_logs_default_values() {
|
||||
let expected_args = RadarrListCommand::Logs {
|
||||
@@ -233,6 +256,32 @@ mod tests {
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_list_history_command() {
|
||||
let expected_events = 1000;
|
||||
let mut mock_network = MockNetworkTrait::new();
|
||||
mock_network
|
||||
.expect_handle_network_event()
|
||||
.with(eq::<NetworkEvent>(
|
||||
RadarrEvent::GetHistory(expected_events).into(),
|
||||
))
|
||||
.times(1)
|
||||
.returning(|_| {
|
||||
Ok(Serdeable::Radarr(RadarrSerdeable::Value(
|
||||
json!({"testResponse": "response"}),
|
||||
)))
|
||||
});
|
||||
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||
let list_history_command = RadarrListCommand::History { events: 1000 };
|
||||
|
||||
let result =
|
||||
RadarrListCommandHandler::with(&app_arc, list_history_command, &mut mock_network)
|
||||
.handle()
|
||||
.await;
|
||||
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_list_logs_command() {
|
||||
let expected_events = 1000;
|
||||
|
||||
@@ -64,6 +64,15 @@ pub enum RadarrCommand {
|
||||
Refresh(RadarrRefreshCommand),
|
||||
#[command(about = "Clear the blocklist")]
|
||||
ClearBlocklist,
|
||||
#[command(about = "Mark the Radarr history item with the given ID as 'failed'")]
|
||||
MarkHistoryItemAsFailed {
|
||||
#[arg(
|
||||
long,
|
||||
help = "The Radarr ID of the history item you wish to mark as 'failed'",
|
||||
required = true
|
||||
)]
|
||||
history_item_id: i64,
|
||||
},
|
||||
#[command(about = "Manually download the given release for the specified movie ID")]
|
||||
DownloadRelease {
|
||||
#[arg(long, help = "The GUID of the release to download", required = true)]
|
||||
@@ -208,6 +217,15 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, RadarrCommand> for RadarrCliHandler<'a, '
|
||||
.await?;
|
||||
serde_json::to_string_pretty(&resp)?
|
||||
}
|
||||
RadarrCommand::MarkHistoryItemAsFailed { history_item_id } => {
|
||||
let _ = self
|
||||
.network
|
||||
.handle_network_event(RadarrEvent::MarkHistoryItemAsFailed(history_item_id).into())
|
||||
.await?;
|
||||
serde_json::to_string_pretty(
|
||||
&serde_json::json!({"message": "Radarr history item marked as 'failed'"}),
|
||||
)?
|
||||
}
|
||||
RadarrCommand::DownloadRelease {
|
||||
guid,
|
||||
indexer_id,
|
||||
|
||||
@@ -31,6 +31,31 @@ mod tests {
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mark_history_item_as_failed_requires_history_item_id() {
|
||||
let result =
|
||||
Cli::command().try_get_matches_from(["managarr", "radarr", "mark-history-item-as-failed"]);
|
||||
|
||||
assert_err!(&result);
|
||||
assert_eq!(
|
||||
result.unwrap_err().kind(),
|
||||
ErrorKind::MissingRequiredArgument
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mark_history_item_as_failed_requirements_satisfied() {
|
||||
let result = Cli::command().try_get_matches_from([
|
||||
"managarr",
|
||||
"radarr",
|
||||
"mark-history-item-as-failed",
|
||||
"--history-item-id",
|
||||
"1",
|
||||
]);
|
||||
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_release_requires_movie_id() {
|
||||
let result = Cli::command().try_get_matches_from([
|
||||
@@ -327,6 +352,36 @@ mod tests {
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_mark_history_item_as_failed_command() {
|
||||
let expected_history_item_id = 1;
|
||||
let mut mock_network = MockNetworkTrait::new();
|
||||
mock_network
|
||||
.expect_handle_network_event()
|
||||
.with(eq::<NetworkEvent>(
|
||||
RadarrEvent::MarkHistoryItemAsFailed(expected_history_item_id).into(),
|
||||
))
|
||||
.times(1)
|
||||
.returning(|_| {
|
||||
Ok(Serdeable::Radarr(RadarrSerdeable::Value(
|
||||
json!({"testResponse": "response"}),
|
||||
)))
|
||||
});
|
||||
let app_arc = Arc::new(Mutex::new(App::test_default()));
|
||||
let mark_history_item_as_failed_command =
|
||||
RadarrCommand::MarkHistoryItemAsFailed { history_item_id: 1 };
|
||||
|
||||
let result = RadarrCliHandler::with(
|
||||
&app_arc,
|
||||
mark_history_item_as_failed_command,
|
||||
&mut mock_network,
|
||||
)
|
||||
.handle()
|
||||
.await;
|
||||
|
||||
assert_ok!(&result);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_download_release_command() {
|
||||
let expected_release_download_body = RadarrReleaseDownloadBody {
|
||||
|
||||
@@ -356,6 +356,9 @@ mod test_utils {
|
||||
.radarr_data
|
||||
.movies
|
||||
.set_items(vec![$crate::models::radarr_models::Movie::default()]);
|
||||
app.data.radarr_data.history.set_items(vec![
|
||||
$crate::models::radarr_models::RadarrHistoryItem::default(),
|
||||
]);
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
|
||||
@@ -91,9 +91,9 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
app.data.radarr_data.main_tabs.get_active_route(),
|
||||
ActiveRadarrBlock::RootFolders.into()
|
||||
ActiveRadarrBlock::History.into()
|
||||
);
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::RootFolders.into());
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::History.into());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use chrono::DateTime;
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use rstest::rstest;
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||
use crate::assert_navigation_pushed;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::radarr_handlers::history::{HistoryHandler, history_sorting_options};
|
||||
use crate::models::radarr_models::{RadarrHistoryEventType, RadarrHistoryItem};
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, HISTORY_BLOCKS};
|
||||
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
||||
|
||||
mod test_handle_left_right_action {
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
use crate::assert_navigation_pushed;
|
||||
|
||||
#[rstest]
|
||||
fn test_history_tab_left(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(4);
|
||||
|
||||
HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.left.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.data.radarr_data.main_tabs.get_active_route(),
|
||||
ActiveRadarrBlock::Blocklist.into()
|
||||
);
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::Blocklist.into());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_history_tab_right(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(4);
|
||||
|
||||
HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.right.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.data.radarr_data.main_tabs.get_active_route(),
|
||||
ActiveRadarrBlock::RootFolders.into()
|
||||
);
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
ActiveRadarrBlock::RootFolders.into()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_submit {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
|
||||
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||
|
||||
#[test]
|
||||
fn test_history_submit() {
|
||||
let mut app = App::test_default();
|
||||
app.data.radarr_data.history.set_items(history_vec());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
|
||||
HistoryHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::History, None).handle();
|
||||
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::HistoryItemDetails.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_submit_no_op_when_not_ready() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
app.data.radarr_data.history.set_items(history_vec());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
|
||||
HistoryHandler::new(SUBMIT_KEY, &mut app, ActiveRadarrBlock::History, None).handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::History.into());
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_esc {
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
|
||||
use crate::models::servarr_data::radarr::radarr_data::radarr_test_utils::utils::create_test_radarr_data;
|
||||
|
||||
use super::*;
|
||||
use crate::assert_navigation_popped;
|
||||
|
||||
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||
|
||||
#[test]
|
||||
fn test_esc_history_item_details() {
|
||||
let mut app = App::test_default();
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.history
|
||||
.set_items(vec![RadarrHistoryItem::default()]);
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::HistoryItemDetails.into());
|
||||
|
||||
HistoryHandler::new(
|
||||
ESC_KEY,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::HistoryItemDetails,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_popped!(app, ActiveRadarrBlock::History.into());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.error = "test error".to_owned().into();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.data.radarr_data = create_test_radarr_data();
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.history
|
||||
.set_items(vec![RadarrHistoryItem::default()]);
|
||||
|
||||
HistoryHandler::new(ESC_KEY, &mut app, ActiveRadarrBlock::History, None).handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::History.into());
|
||||
assert_is_empty!(app.error.text);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_handle_key_char {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::assert_navigation_pushed;
|
||||
|
||||
#[test]
|
||||
fn test_refresh_history_key() {
|
||||
let mut app = App::test_default();
|
||||
app.data.radarr_data.history.set_items(history_vec());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
|
||||
HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.refresh.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::History.into());
|
||||
assert!(app.should_refresh);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_refresh_history_key_no_op_when_not_ready() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
app.data.radarr_data.history.set_items(history_vec());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
|
||||
HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.refresh.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), ActiveRadarrBlock::History.into());
|
||||
assert!(!app.should_refresh);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_sorting_options_source_title() {
|
||||
let expected_cmp_fn: fn(&RadarrHistoryItem, &RadarrHistoryItem) -> Ordering = |a, b| {
|
||||
a.source_title
|
||||
.text
|
||||
.to_lowercase()
|
||||
.cmp(&b.source_title.text.to_lowercase())
|
||||
};
|
||||
let mut expected_history_vec = history_vec();
|
||||
expected_history_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = history_sorting_options()[0].clone();
|
||||
let mut sorted_history_vec = history_vec();
|
||||
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||
assert_str_eq!(sort_option.name, "Source Title");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_sorting_options_event_type() {
|
||||
let expected_cmp_fn: fn(&RadarrHistoryItem, &RadarrHistoryItem) -> Ordering = |a, b| {
|
||||
a.event_type
|
||||
.to_string()
|
||||
.to_lowercase()
|
||||
.cmp(&b.event_type.to_string().to_lowercase())
|
||||
};
|
||||
let mut expected_history_vec = history_vec();
|
||||
expected_history_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = history_sorting_options()[1].clone();
|
||||
let mut sorted_history_vec = history_vec();
|
||||
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||
assert_str_eq!(sort_option.name, "Event Type");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_sorting_options_language() {
|
||||
let expected_cmp_fn: fn(&RadarrHistoryItem, &RadarrHistoryItem) -> Ordering = |a, b| {
|
||||
let default_language = Language {
|
||||
id: 1,
|
||||
name: "_".to_owned(),
|
||||
};
|
||||
let language_a = a.languages.first().unwrap_or(&default_language);
|
||||
let language_b = b.languages.first().unwrap_or(&default_language);
|
||||
|
||||
language_a.cmp(language_b)
|
||||
};
|
||||
let mut expected_history_vec = history_vec();
|
||||
expected_history_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = history_sorting_options()[2].clone();
|
||||
let mut sorted_history_vec = history_vec();
|
||||
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||
assert_str_eq!(sort_option.name, "Language");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_sorting_options_quality() {
|
||||
let expected_cmp_fn: fn(&RadarrHistoryItem, &RadarrHistoryItem) -> Ordering = |a, b| {
|
||||
a.quality
|
||||
.quality
|
||||
.name
|
||||
.to_lowercase()
|
||||
.cmp(&b.quality.quality.name.to_lowercase())
|
||||
};
|
||||
let mut expected_history_vec = history_vec();
|
||||
expected_history_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = history_sorting_options()[3].clone();
|
||||
let mut sorted_history_vec = history_vec();
|
||||
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||
assert_str_eq!(sort_option.name, "Quality");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_sorting_options_date() {
|
||||
let expected_cmp_fn: fn(&RadarrHistoryItem, &RadarrHistoryItem) -> Ordering =
|
||||
|a, b| a.date.cmp(&b.date);
|
||||
let mut expected_history_vec = history_vec();
|
||||
expected_history_vec.sort_by(expected_cmp_fn);
|
||||
|
||||
let sort_option = history_sorting_options()[4].clone();
|
||||
let mut sorted_history_vec = history_vec();
|
||||
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||
|
||||
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||
assert_str_eq!(sort_option.name, "Date");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_handler_accepts() {
|
||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||
if HISTORY_BLOCKS.contains(&active_radarr_block) {
|
||||
assert!(HistoryHandler::accepts(active_radarr_block));
|
||||
} else {
|
||||
assert!(!HistoryHandler::accepts(active_radarr_block));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_history_handler_ignore_special_keys(
|
||||
#[values(true, false)] ignore_special_keys_for_textbox_input: bool,
|
||||
) {
|
||||
let mut app = App::test_default();
|
||||
app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
|
||||
let handler = HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::default(),
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
handler.ignore_special_keys(),
|
||||
ignore_special_keys_for_textbox_input
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_handler_not_ready_when_loading() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.is_loading = true;
|
||||
|
||||
let handler = HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(!handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_handler_not_ready_when_history_is_empty() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.is_loading = false;
|
||||
|
||||
let handler = HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(!handler.is_ready());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_handler_ready_when_not_loading_and_history_is_not_empty() {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
app.is_loading = false;
|
||||
app
|
||||
.data
|
||||
.radarr_data
|
||||
.history
|
||||
.set_items(vec![RadarrHistoryItem::default()]);
|
||||
|
||||
let handler = HistoryHandler::new(
|
||||
DEFAULT_KEYBINDINGS.esc.key,
|
||||
&mut app,
|
||||
ActiveRadarrBlock::History,
|
||||
None,
|
||||
);
|
||||
|
||||
assert!(handler.is_ready());
|
||||
}
|
||||
|
||||
fn history_vec() -> Vec<RadarrHistoryItem> {
|
||||
vec![
|
||||
RadarrHistoryItem {
|
||||
id: 3,
|
||||
source_title: "test 1".into(),
|
||||
movie_id: 1,
|
||||
event_type: RadarrHistoryEventType::Grabbed,
|
||||
languages: vec![Language {
|
||||
id: 1,
|
||||
name: "telgu".to_owned(),
|
||||
}],
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "HD - 1080p".to_owned(),
|
||||
},
|
||||
},
|
||||
date: DateTime::from(DateTime::parse_from_rfc3339("2024-01-10T07:28:45Z").unwrap()),
|
||||
..RadarrHistoryItem::default()
|
||||
},
|
||||
RadarrHistoryItem {
|
||||
id: 2,
|
||||
source_title: "test 2".into(),
|
||||
movie_id: 2,
|
||||
event_type: RadarrHistoryEventType::DownloadFolderImported,
|
||||
languages: vec![Language {
|
||||
id: 3,
|
||||
name: "chinese".to_owned(),
|
||||
}],
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "SD - 720p".to_owned(),
|
||||
},
|
||||
},
|
||||
date: DateTime::from(DateTime::parse_from_rfc3339("2024-02-10T07:28:45Z").unwrap()),
|
||||
..RadarrHistoryItem::default()
|
||||
},
|
||||
RadarrHistoryItem {
|
||||
id: 1,
|
||||
source_title: "test 3".into(),
|
||||
movie_id: 3,
|
||||
event_type: RadarrHistoryEventType::MovieFileDeleted,
|
||||
languages: vec![Language {
|
||||
id: 1,
|
||||
name: "english".to_owned(),
|
||||
}],
|
||||
quality: QualityWrapper {
|
||||
quality: Quality {
|
||||
name: "HD - 1080p".to_owned(),
|
||||
},
|
||||
},
|
||||
date: DateTime::from(DateTime::parse_from_rfc3339("2024-03-10T07:28:45Z").unwrap()),
|
||||
..RadarrHistoryItem::default()
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
use crate::app::App;
|
||||
use crate::event::Key;
|
||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||
use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
|
||||
use crate::handlers::{KeyEventHandler, handle_clear_errors};
|
||||
use crate::matches_key;
|
||||
use crate::models::Route;
|
||||
use crate::models::radarr_models::RadarrHistoryItem;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, HISTORY_BLOCKS};
|
||||
use crate::models::servarr_models::Language;
|
||||
use crate::models::stateful_table::SortOption;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "history_handler_tests.rs"]
|
||||
mod history_handler_tests;
|
||||
|
||||
pub(super) struct HistoryHandler<'a, 'b> {
|
||||
key: Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_radarr_block: ActiveRadarrBlock,
|
||||
_context: Option<ActiveRadarrBlock>,
|
||||
}
|
||||
|
||||
impl HistoryHandler<'_, '_> {}
|
||||
|
||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for HistoryHandler<'a, 'b> {
|
||||
fn handle(&mut self) {
|
||||
let history_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::History.into())
|
||||
.sorting_block(ActiveRadarrBlock::HistorySortPrompt.into())
|
||||
.sort_options(history_sorting_options())
|
||||
.searching_block(ActiveRadarrBlock::SearchHistory.into())
|
||||
.search_error_block(ActiveRadarrBlock::SearchHistoryError.into())
|
||||
.search_field_fn(|history| &history.source_title.text)
|
||||
.filtering_block(ActiveRadarrBlock::FilterHistory.into())
|
||||
.filter_error_block(ActiveRadarrBlock::FilterHistoryError.into())
|
||||
.filter_field_fn(|history| &history.source_title.text);
|
||||
|
||||
if !handle_table(
|
||||
self,
|
||||
|app| &mut app.data.radarr_data.history,
|
||||
history_table_handling_config,
|
||||
) {
|
||||
self.handle_key_event();
|
||||
}
|
||||
}
|
||||
|
||||
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||
HISTORY_BLOCKS.contains(&active_block)
|
||||
}
|
||||
|
||||
fn new(
|
||||
key: Key,
|
||||
app: &'a mut App<'b>,
|
||||
active_block: ActiveRadarrBlock,
|
||||
context: Option<ActiveRadarrBlock>,
|
||||
) -> Self {
|
||||
HistoryHandler {
|
||||
key,
|
||||
app,
|
||||
active_radarr_block: active_block,
|
||||
_context: context,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_key(&self) -> Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
fn ignore_special_keys(&self) -> bool {
|
||||
self.app.ignore_special_keys_for_textbox_input
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> bool {
|
||||
!self.app.is_loading && !self.app.data.radarr_data.history.is_empty()
|
||||
}
|
||||
|
||||
fn handle_scroll_up(&mut self) {}
|
||||
|
||||
fn handle_scroll_down(&mut self) {}
|
||||
|
||||
fn handle_home(&mut self) {}
|
||||
|
||||
fn handle_end(&mut self) {}
|
||||
|
||||
fn handle_delete(&mut self) {}
|
||||
|
||||
fn handle_left_right_action(&mut self) {
|
||||
if self.active_radarr_block == ActiveRadarrBlock::History {
|
||||
handle_change_tab_left_right_keys(self.app, self.key)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_submit(&mut self) {
|
||||
if self.active_radarr_block == ActiveRadarrBlock::History {
|
||||
self
|
||||
.app
|
||||
.push_navigation_stack(ActiveRadarrBlock::HistoryItemDetails.into());
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_esc(&mut self) {
|
||||
if self.active_radarr_block == ActiveRadarrBlock::HistoryItemDetails {
|
||||
self.app.pop_navigation_stack();
|
||||
} else {
|
||||
handle_clear_errors(self.app);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_char_key_event(&mut self) {
|
||||
let key = self.key;
|
||||
if self.active_radarr_block == ActiveRadarrBlock::History {
|
||||
match self.key {
|
||||
_ if matches_key!(refresh, key) => {
|
||||
self.app.should_refresh = true;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn app_mut(&mut self) -> &mut App<'b> {
|
||||
self.app
|
||||
}
|
||||
|
||||
fn current_route(&self) -> Route {
|
||||
self.app.get_current_route()
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::handlers::radarr_handlers) fn history_sorting_options()
|
||||
-> Vec<SortOption<RadarrHistoryItem>> {
|
||||
vec![
|
||||
SortOption {
|
||||
name: "Source Title",
|
||||
cmp_fn: Some(|a, b| {
|
||||
a.source_title
|
||||
.text
|
||||
.to_lowercase()
|
||||
.cmp(&b.source_title.text.to_lowercase())
|
||||
}),
|
||||
},
|
||||
SortOption {
|
||||
name: "Event Type",
|
||||
cmp_fn: Some(|a, b| {
|
||||
a.event_type
|
||||
.to_string()
|
||||
.to_lowercase()
|
||||
.cmp(&b.event_type.to_string().to_lowercase())
|
||||
}),
|
||||
},
|
||||
SortOption {
|
||||
name: "Language",
|
||||
cmp_fn: Some(|a, b| {
|
||||
let default_language = Language {
|
||||
id: 1,
|
||||
name: "_".to_owned(),
|
||||
};
|
||||
let language_a = a.languages.first().unwrap_or(&default_language);
|
||||
let language_b = b.languages.first().unwrap_or(&default_language);
|
||||
|
||||
language_a.cmp(language_b)
|
||||
}),
|
||||
},
|
||||
SortOption {
|
||||
name: "Quality",
|
||||
cmp_fn: Some(|a, b| {
|
||||
a.quality
|
||||
.quality
|
||||
.name
|
||||
.to_lowercase()
|
||||
.cmp(&b.quality.quality.name.to_lowercase())
|
||||
}),
|
||||
},
|
||||
SortOption {
|
||||
name: "Date",
|
||||
cmp_fn: Some(|a, b| a.date.cmp(&b.date)),
|
||||
},
|
||||
]
|
||||
}
|
||||
@@ -65,7 +65,7 @@ mod tests {
|
||||
fn test_indexers_tab_left(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(5);
|
||||
app.data.radarr_data.main_tabs.set_index(6);
|
||||
|
||||
IndexersHandler::new(
|
||||
DEFAULT_KEYBINDINGS.left.key,
|
||||
@@ -86,7 +86,7 @@ mod tests {
|
||||
fn test_indexers_tab_right(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(5);
|
||||
app.data.radarr_data.main_tabs.set_index(6);
|
||||
|
||||
IndexersHandler::new(
|
||||
DEFAULT_KEYBINDINGS.right.key,
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::handlers::KeyEventHandler;
|
||||
use crate::handlers::radarr_handlers::blocklist::BlocklistHandler;
|
||||
use crate::handlers::radarr_handlers::collections::CollectionsHandler;
|
||||
use crate::handlers::radarr_handlers::downloads::DownloadsHandler;
|
||||
use crate::handlers::radarr_handlers::history::HistoryHandler;
|
||||
use crate::handlers::radarr_handlers::indexers::IndexersHandler;
|
||||
use crate::handlers::radarr_handlers::library::LibraryHandler;
|
||||
use crate::handlers::radarr_handlers::root_folders::RootFoldersHandler;
|
||||
@@ -13,6 +14,7 @@ use crate::{App, Key, matches_key};
|
||||
mod blocklist;
|
||||
mod collections;
|
||||
mod downloads;
|
||||
mod history;
|
||||
mod indexers;
|
||||
mod library;
|
||||
mod root_folders;
|
||||
@@ -51,6 +53,9 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
||||
_ if DownloadsHandler::accepts(self.active_radarr_block) => {
|
||||
DownloadsHandler::new(self.key, self.app, self.active_radarr_block, self.context).handle()
|
||||
}
|
||||
_ if HistoryHandler::accepts(self.active_radarr_block) => {
|
||||
HistoryHandler::new(self.key, self.app, self.active_radarr_block, self.context).handle()
|
||||
}
|
||||
_ if RootFoldersHandler::accepts(self.active_radarr_block) => {
|
||||
RootFoldersHandler::new(self.key, self.app, self.active_radarr_block, self.context).handle()
|
||||
}
|
||||
|
||||
@@ -16,10 +16,11 @@ mod tests {
|
||||
#[case(0, ActiveRadarrBlock::System, ActiveRadarrBlock::Collections)]
|
||||
#[case(1, ActiveRadarrBlock::Movies, ActiveRadarrBlock::Downloads)]
|
||||
#[case(2, ActiveRadarrBlock::Collections, ActiveRadarrBlock::Blocklist)]
|
||||
#[case(3, ActiveRadarrBlock::Downloads, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(4, ActiveRadarrBlock::Blocklist, ActiveRadarrBlock::Indexers)]
|
||||
#[case(5, ActiveRadarrBlock::RootFolders, ActiveRadarrBlock::System)]
|
||||
#[case(6, ActiveRadarrBlock::Indexers, ActiveRadarrBlock::Movies)]
|
||||
#[case(3, ActiveRadarrBlock::Downloads, ActiveRadarrBlock::History)]
|
||||
#[case(4, ActiveRadarrBlock::Blocklist, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(5, ActiveRadarrBlock::History, ActiveRadarrBlock::Indexers)]
|
||||
#[case(6, ActiveRadarrBlock::RootFolders, ActiveRadarrBlock::System)]
|
||||
#[case(7, ActiveRadarrBlock::Indexers, ActiveRadarrBlock::Movies)]
|
||||
fn test_radarr_handler_change_tab_left_right_keys(
|
||||
#[case] index: usize,
|
||||
#[case] left_block: ActiveRadarrBlock,
|
||||
@@ -51,10 +52,11 @@ mod tests {
|
||||
#[case(0, ActiveRadarrBlock::System, ActiveRadarrBlock::Collections)]
|
||||
#[case(1, ActiveRadarrBlock::Movies, ActiveRadarrBlock::Downloads)]
|
||||
#[case(2, ActiveRadarrBlock::Collections, ActiveRadarrBlock::Blocklist)]
|
||||
#[case(3, ActiveRadarrBlock::Downloads, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(4, ActiveRadarrBlock::Blocklist, ActiveRadarrBlock::Indexers)]
|
||||
#[case(5, ActiveRadarrBlock::RootFolders, ActiveRadarrBlock::System)]
|
||||
#[case(6, ActiveRadarrBlock::Indexers, ActiveRadarrBlock::Movies)]
|
||||
#[case(3, ActiveRadarrBlock::Downloads, ActiveRadarrBlock::History)]
|
||||
#[case(4, ActiveRadarrBlock::Blocklist, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(5, ActiveRadarrBlock::History, ActiveRadarrBlock::Indexers)]
|
||||
#[case(6, ActiveRadarrBlock::RootFolders, ActiveRadarrBlock::System)]
|
||||
#[case(7, ActiveRadarrBlock::Indexers, ActiveRadarrBlock::Movies)]
|
||||
fn test_radarr_handler_change_tab_left_right_keys_alt_navigation(
|
||||
#[case] index: usize,
|
||||
#[case] left_block: ActiveRadarrBlock,
|
||||
@@ -88,9 +90,10 @@ mod tests {
|
||||
#[case(1, ActiveRadarrBlock::Collections)]
|
||||
#[case(2, ActiveRadarrBlock::Downloads)]
|
||||
#[case(3, ActiveRadarrBlock::Blocklist)]
|
||||
#[case(4, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(5, ActiveRadarrBlock::Indexers)]
|
||||
#[case(6, ActiveRadarrBlock::System)]
|
||||
#[case(4, ActiveRadarrBlock::History)]
|
||||
#[case(5, ActiveRadarrBlock::RootFolders)]
|
||||
#[case(6, ActiveRadarrBlock::Indexers)]
|
||||
#[case(7, ActiveRadarrBlock::System)]
|
||||
fn test_radarr_handler_change_tab_left_right_keys_alt_navigation_no_op_when_ignoring_quit_key(
|
||||
#[case] index: usize,
|
||||
#[case] block: ActiveRadarrBlock,
|
||||
@@ -281,6 +284,26 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_delegates_history_blocks_to_history_handler(
|
||||
#[values(
|
||||
ActiveRadarrBlock::History,
|
||||
ActiveRadarrBlock::HistoryItemDetails,
|
||||
ActiveRadarrBlock::HistorySortPrompt,
|
||||
ActiveRadarrBlock::FilterHistory,
|
||||
ActiveRadarrBlock::FilterHistoryError,
|
||||
ActiveRadarrBlock::SearchHistory,
|
||||
ActiveRadarrBlock::SearchHistoryError
|
||||
)]
|
||||
active_radarr_block: ActiveRadarrBlock,
|
||||
) {
|
||||
test_handler_delegation!(
|
||||
RadarrHandler,
|
||||
ActiveRadarrBlock::History,
|
||||
active_radarr_block
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_handler_accepts() {
|
||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||
|
||||
@@ -130,7 +130,7 @@ mod tests {
|
||||
fn test_root_folders_tab_left(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(4);
|
||||
app.data.radarr_data.main_tabs.set_index(5);
|
||||
|
||||
RootFoldersHandler::new(
|
||||
DEFAULT_KEYBINDINGS.left.key,
|
||||
@@ -142,16 +142,16 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
app.data.radarr_data.main_tabs.get_active_route(),
|
||||
ActiveRadarrBlock::Blocklist.into()
|
||||
ActiveRadarrBlock::History.into()
|
||||
);
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::Blocklist.into());
|
||||
assert_navigation_pushed!(app, ActiveRadarrBlock::History.into());
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_root_folders_tab_right(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(4);
|
||||
app.data.radarr_data.main_tabs.set_index(5);
|
||||
|
||||
RootFoldersHandler::new(
|
||||
DEFAULT_KEYBINDINGS.right.key,
|
||||
|
||||
@@ -26,7 +26,7 @@ mod tests {
|
||||
fn test_system_tab_left(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(6);
|
||||
app.data.radarr_data.main_tabs.set_index(7);
|
||||
|
||||
SystemHandler::new(
|
||||
DEFAULT_KEYBINDINGS.left.key,
|
||||
@@ -47,7 +47,7 @@ mod tests {
|
||||
fn test_system_tab_right(#[values(true, false)] is_ready: bool) {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = is_ready;
|
||||
app.data.radarr_data.main_tabs.set_index(6);
|
||||
app.data.radarr_data.main_tabs.set_index(7);
|
||||
|
||||
SystemHandler::new(
|
||||
DEFAULT_KEYBINDINGS.right.key,
|
||||
|
||||
@@ -408,6 +408,69 @@ pub struct SystemStatus {
|
||||
pub start_time: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RadarrHistoryWrapper {
|
||||
pub records: Vec<RadarrHistoryItem>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RadarrHistoryData {
|
||||
pub indexer: Option<String>,
|
||||
pub release_group: Option<String>,
|
||||
pub nzb_info_url: Option<String>,
|
||||
pub download_client: Option<String>,
|
||||
pub download_client_name: Option<String>,
|
||||
pub age: Option<String>,
|
||||
pub published_date: Option<DateTime<Utc>>,
|
||||
pub message: Option<String>,
|
||||
pub reason: Option<String>,
|
||||
pub dropped_path: Option<String>,
|
||||
pub imported_path: Option<String>,
|
||||
pub source_path: Option<String>,
|
||||
pub path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq, Display, EnumDisplayStyle,
|
||||
)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[strum(serialize_all = "camelCase")]
|
||||
pub enum RadarrHistoryEventType {
|
||||
#[default]
|
||||
Unknown,
|
||||
Grabbed,
|
||||
#[display_style(name = "Download Folder Imported")]
|
||||
DownloadFolderImported,
|
||||
#[display_style(name = "Download Failed")]
|
||||
DownloadFailed,
|
||||
#[display_style(name = "Movie File Deleted")]
|
||||
MovieFileDeleted,
|
||||
#[display_style(name = "Movie Folder Imported")]
|
||||
MovieFolderImported,
|
||||
#[display_style(name = "Movie File Renamed")]
|
||||
MovieFileRenamed,
|
||||
#[display_style(name = "Download Ignored")]
|
||||
DownloadIgnored,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RadarrHistoryItem {
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub id: i64,
|
||||
pub source_title: HorizontallyScrollableText,
|
||||
#[serde(deserialize_with = "super::from_i64")]
|
||||
pub movie_id: i64,
|
||||
pub quality: QualityWrapper,
|
||||
pub languages: Vec<Language>,
|
||||
pub date: DateTime<Utc>,
|
||||
pub event_type: RadarrHistoryEventType,
|
||||
#[serde(default)]
|
||||
pub data: RadarrHistoryData,
|
||||
}
|
||||
|
||||
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RadarrTask {
|
||||
@@ -461,6 +524,7 @@ serde_enum_from!(
|
||||
Credits(Vec<Credit>),
|
||||
DiskSpaces(Vec<DiskSpace>),
|
||||
DownloadsResponse(DownloadsResponse),
|
||||
HistoryWrapper(RadarrHistoryWrapper),
|
||||
HostConfig(HostConfig),
|
||||
Indexers(Vec<Indexer>),
|
||||
IndexerSettings(IndexerSettings),
|
||||
|
||||
@@ -3,6 +3,9 @@ mod tests {
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::models::radarr_models::{
|
||||
RadarrHistoryEventType, RadarrHistoryItem, RadarrHistoryWrapper,
|
||||
};
|
||||
use crate::models::{
|
||||
Serdeable,
|
||||
radarr_models::{
|
||||
@@ -61,6 +64,66 @@ mod tests {
|
||||
assert_str_eq!(MovieMonitor::None.to_display_str(), "None");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_display() {
|
||||
assert_str_eq!(RadarrHistoryEventType::Unknown.to_string(), "unknown");
|
||||
assert_str_eq!(RadarrHistoryEventType::Grabbed.to_string(), "grabbed");
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadFolderImported.to_string(),
|
||||
"downloadFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadFailed.to_string(),
|
||||
"downloadFailed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFileDeleted.to_string(),
|
||||
"movieFileDeleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFolderImported.to_string(),
|
||||
"movieFolderImported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFileRenamed.to_string(),
|
||||
"movieFileRenamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadIgnored.to_string(),
|
||||
"downloadIgnored"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_history_event_type_to_display_str() {
|
||||
assert_str_eq!(RadarrHistoryEventType::Unknown.to_display_str(), "Unknown");
|
||||
assert_str_eq!(RadarrHistoryEventType::Grabbed.to_display_str(), "Grabbed");
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadFolderImported.to_display_str(),
|
||||
"Download Folder Imported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadFailed.to_display_str(),
|
||||
"Download Failed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFileDeleted.to_display_str(),
|
||||
"Movie File Deleted"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFolderImported.to_display_str(),
|
||||
"Movie Folder Imported"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::MovieFileRenamed.to_display_str(),
|
||||
"Movie File Renamed"
|
||||
);
|
||||
assert_str_eq!(
|
||||
RadarrHistoryEventType::DownloadIgnored.to_display_str(),
|
||||
"Download Ignored"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_download_record_default_indexer_value() {
|
||||
let json = r#"{
|
||||
@@ -235,6 +298,23 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_serdeable_from_history_wrapper() {
|
||||
let history_wrapper = RadarrHistoryWrapper {
|
||||
records: vec![RadarrHistoryItem {
|
||||
id: 1,
|
||||
..RadarrHistoryItem::default()
|
||||
}],
|
||||
};
|
||||
|
||||
let radarr_serdeable: RadarrSerdeable = history_wrapper.clone().into();
|
||||
|
||||
assert_eq!(
|
||||
radarr_serdeable,
|
||||
RadarrSerdeable::HistoryWrapper(history_wrapper)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_radarr_serdeable_from_log_response() {
|
||||
let log_response = LogResponse {
|
||||
|
||||
@@ -15,6 +15,7 @@ use crate::models::{HorizontallyScrollableText, ScrollableText};
|
||||
mod modals_tests;
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct MovieDetailsModal {
|
||||
pub movie_details: ScrollableText,
|
||||
pub file_details: String,
|
||||
@@ -97,6 +98,7 @@ impl From<&RadarrData<'_>> for EditIndexerModal {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct EditMovieModal {
|
||||
pub minimum_availability_list: StatefulList<MinimumAvailability>,
|
||||
pub quality_profile_list: StatefulList<String>,
|
||||
@@ -157,6 +159,7 @@ impl From<&RadarrData<'_>> for EditMovieModal {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct AddMovieModal {
|
||||
pub root_folder_list: StatefulList<RootFolder>,
|
||||
pub monitor_list: StatefulList<MovieMonitor>,
|
||||
@@ -186,6 +189,7 @@ impl From<&RadarrData<'_>> for AddMovieModal {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
#[cfg_attr(test, derive(Debug))]
|
||||
pub struct EditCollectionModal {
|
||||
pub monitored: Option<bool>,
|
||||
pub minimum_availability_list: StatefulList<MinimumAvailability>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::app::context_clues::{
|
||||
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::app::radarr::radarr_context_clues::{
|
||||
@@ -8,7 +8,7 @@ use crate::app::radarr::radarr_context_clues::{
|
||||
};
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord,
|
||||
IndexerSettings, Movie, RadarrTask,
|
||||
IndexerSettings, Movie, RadarrHistoryItem, RadarrTask,
|
||||
};
|
||||
use crate::models::servarr_data::modals::{EditIndexerModal, IndexerTestResultModalItem};
|
||||
use crate::models::servarr_data::radarr::modals::{
|
||||
@@ -34,7 +34,8 @@ use {
|
||||
crate::network::radarr_network::radarr_network_test_utils::test_utils::{
|
||||
add_movie_search_result, blocklist_item, cast_credit, collection, collection_movie,
|
||||
crew_credit, download_record, indexer, log_line, movie, movie_history_item,
|
||||
quality_profile_map, tags_map, task, torrent_release, updates, usenet_release,
|
||||
quality_profile_map, radarr_history_item, tags_map, task, torrent_release, updates,
|
||||
usenet_release,
|
||||
},
|
||||
crate::network::servarr_test_utils::diskspace,
|
||||
crate::network::servarr_test_utils::indexer_test_result,
|
||||
@@ -62,6 +63,7 @@ pub struct RadarrData<'a> {
|
||||
pub downloads: StatefulTable<DownloadRecord>,
|
||||
pub indexers: StatefulTable<Indexer>,
|
||||
pub blocklist: StatefulTable<BlocklistItem>,
|
||||
pub history: StatefulTable<RadarrHistoryItem>,
|
||||
pub quality_profile_map: BiMap<i64, String>,
|
||||
pub tags_map: BiMap<i64, String>,
|
||||
pub collections: StatefulTable<Collection>,
|
||||
@@ -135,6 +137,7 @@ impl<'a> Default for RadarrData<'a> {
|
||||
downloads: StatefulTable::default(),
|
||||
indexers: StatefulTable::default(),
|
||||
blocklist: StatefulTable::default(),
|
||||
history: StatefulTable::default(),
|
||||
quality_profile_map: BiMap::default(),
|
||||
tags_map: BiMap::default(),
|
||||
collections: StatefulTable::default(),
|
||||
@@ -184,6 +187,12 @@ impl<'a> Default for RadarrData<'a> {
|
||||
contextual_help: Some(&BLOCKLIST_CONTEXT_CLUES),
|
||||
config: None,
|
||||
},
|
||||
TabRoute {
|
||||
title: "History".to_string(),
|
||||
route: ActiveRadarrBlock::History.into(),
|
||||
contextual_help: Some(&HISTORY_CONTEXT_CLUES),
|
||||
config: None,
|
||||
},
|
||||
TabRoute {
|
||||
title: "Root Folders".to_string(),
|
||||
route: ActiveRadarrBlock::RootFolders.into(),
|
||||
@@ -387,6 +396,10 @@ impl RadarrData<'_> {
|
||||
radarr_data.downloads.set_items(vec![download_record()]);
|
||||
radarr_data.blocklist.set_items(vec![blocklist_item()]);
|
||||
radarr_data.blocklist.sorting(vec![sort_option!(id)]);
|
||||
radarr_data.history.set_items(vec![radarr_history_item()]);
|
||||
radarr_data.history.sorting(vec![sort_option!(id)]);
|
||||
radarr_data.history.search = Some("Something".into());
|
||||
radarr_data.history.filter = Some("Something".into());
|
||||
radarr_data.indexers.set_items(vec![indexer()]);
|
||||
radarr_data.indexers.sorting(vec![sort_option!(id)]);
|
||||
radarr_data.indexers.search = Some("Something".into());
|
||||
@@ -420,6 +433,13 @@ pub enum ActiveRadarrBlock {
|
||||
BlocklistClearAllItemsPrompt,
|
||||
BlocklistItemDetails,
|
||||
BlocklistSortPrompt,
|
||||
History,
|
||||
HistoryItemDetails,
|
||||
HistorySortPrompt,
|
||||
FilterHistory,
|
||||
FilterHistoryError,
|
||||
SearchHistory,
|
||||
SearchHistoryError,
|
||||
Collections,
|
||||
CollectionsSortPrompt,
|
||||
CollectionDetails,
|
||||
@@ -538,6 +558,15 @@ pub static BLOCKLIST_BLOCKS: [ActiveRadarrBlock; 5] = [
|
||||
ActiveRadarrBlock::BlocklistClearAllItemsPrompt,
|
||||
ActiveRadarrBlock::BlocklistSortPrompt,
|
||||
];
|
||||
pub static HISTORY_BLOCKS: [ActiveRadarrBlock; 7] = [
|
||||
ActiveRadarrBlock::History,
|
||||
ActiveRadarrBlock::HistoryItemDetails,
|
||||
ActiveRadarrBlock::HistorySortPrompt,
|
||||
ActiveRadarrBlock::FilterHistory,
|
||||
ActiveRadarrBlock::FilterHistoryError,
|
||||
ActiveRadarrBlock::SearchHistory,
|
||||
ActiveRadarrBlock::SearchHistoryError,
|
||||
];
|
||||
pub static ADD_MOVIE_BLOCKS: [ActiveRadarrBlock; 10] = [
|
||||
ActiveRadarrBlock::AddMovieSearchInput,
|
||||
ActiveRadarrBlock::AddMovieSearchResults,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
mod tests {
|
||||
mod radarr_data_tests {
|
||||
use crate::app::context_clues::{
|
||||
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
|
||||
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES,
|
||||
INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||
};
|
||||
use crate::app::radarr::radarr_context_clues::{
|
||||
COLLECTIONS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES,
|
||||
@@ -105,41 +105,42 @@ mod tests {
|
||||
fn test_radarr_data_defaults() {
|
||||
let radarr_data = RadarrData::default();
|
||||
|
||||
assert!(radarr_data.root_folders.items.is_empty());
|
||||
assert_is_empty!(radarr_data.root_folders.items);
|
||||
assert_eq!(radarr_data.disk_space_vec, Vec::new());
|
||||
assert!(radarr_data.version.is_empty());
|
||||
assert_is_empty!(radarr_data.version);
|
||||
assert_eq!(radarr_data.start_time, <DateTime<Utc>>::default());
|
||||
assert!(radarr_data.movies.is_empty());
|
||||
assert_is_empty!(radarr_data.movies);
|
||||
assert_eq!(radarr_data.selected_block, BlockSelectionState::default());
|
||||
assert!(radarr_data.downloads.items.is_empty());
|
||||
assert!(radarr_data.indexers.items.is_empty());
|
||||
assert!(radarr_data.blocklist.items.is_empty());
|
||||
assert!(radarr_data.quality_profile_map.is_empty());
|
||||
assert!(radarr_data.tags_map.is_empty());
|
||||
assert!(radarr_data.collections.items.is_empty());
|
||||
assert!(radarr_data.collection_movies.items.is_empty());
|
||||
assert!(radarr_data.logs.items.is_empty());
|
||||
assert!(radarr_data.log_details.items.is_empty());
|
||||
assert!(radarr_data.tasks.items.is_empty());
|
||||
assert!(radarr_data.queued_events.items.is_empty());
|
||||
assert!(radarr_data.updates.get_text().is_empty());
|
||||
assert!(radarr_data.add_movie_search.is_none());
|
||||
assert!(radarr_data.add_movie_modal.is_none());
|
||||
assert!(radarr_data.add_searched_movies.is_none());
|
||||
assert!(radarr_data.edit_movie_modal.is_none());
|
||||
assert!(radarr_data.edit_collection_modal.is_none());
|
||||
assert!(radarr_data.edit_root_folder.is_none());
|
||||
assert!(radarr_data.edit_indexer_modal.is_none());
|
||||
assert!(radarr_data.indexer_settings.is_none());
|
||||
assert!(radarr_data.indexer_test_errors.is_none());
|
||||
assert!(radarr_data.indexer_test_all_results.is_none());
|
||||
assert!(radarr_data.movie_details_modal.is_none());
|
||||
assert!(radarr_data.prompt_confirm_action.is_none());
|
||||
assert_is_empty!(radarr_data.downloads.items);
|
||||
assert_is_empty!(radarr_data.indexers.items);
|
||||
assert_is_empty!(radarr_data.blocklist.items);
|
||||
assert_is_empty!(radarr_data.history.items);
|
||||
assert_is_empty!(radarr_data.quality_profile_map);
|
||||
assert_is_empty!(radarr_data.tags_map);
|
||||
assert_is_empty!(radarr_data.collections.items);
|
||||
assert_is_empty!(radarr_data.collection_movies.items);
|
||||
assert_is_empty!(radarr_data.logs.items);
|
||||
assert_is_empty!(radarr_data.log_details.items);
|
||||
assert_is_empty!(radarr_data.tasks.items);
|
||||
assert_is_empty!(radarr_data.queued_events.items);
|
||||
assert_is_empty!(radarr_data.updates.get_text());
|
||||
assert_none!(&radarr_data.add_movie_search);
|
||||
assert_none!(&radarr_data.add_movie_modal);
|
||||
assert_none!(&radarr_data.add_searched_movies);
|
||||
assert_none!(&radarr_data.edit_movie_modal);
|
||||
assert_none!(&radarr_data.edit_collection_modal);
|
||||
assert_none!(&radarr_data.edit_root_folder);
|
||||
assert_none!(&radarr_data.edit_indexer_modal);
|
||||
assert_none!(&radarr_data.indexer_settings);
|
||||
assert_none!(&radarr_data.indexer_test_errors);
|
||||
assert_none!(&radarr_data.indexer_test_all_results);
|
||||
assert_none!(&radarr_data.movie_details_modal);
|
||||
assert_none!(&radarr_data.prompt_confirm_action);
|
||||
assert!(!radarr_data.prompt_confirm);
|
||||
assert!(!radarr_data.delete_movie_files);
|
||||
assert!(!radarr_data.add_list_exclusion);
|
||||
|
||||
assert_eq!(radarr_data.main_tabs.tabs.len(), 7);
|
||||
assert_eq!(radarr_data.main_tabs.tabs.len(), 8);
|
||||
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[0].title, "Library");
|
||||
assert_eq!(
|
||||
@@ -189,42 +190,54 @@ mod tests {
|
||||
);
|
||||
assert_eq!(radarr_data.main_tabs.tabs[3].config, None);
|
||||
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "Root Folders");
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[4].title, "History");
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[4].route,
|
||||
ActiveRadarrBlock::RootFolders.into()
|
||||
ActiveRadarrBlock::History.into()
|
||||
);
|
||||
assert!(radarr_data.main_tabs.tabs[4].contextual_help.is_some());
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[4].contextual_help.unwrap(),
|
||||
&ROOT_FOLDERS_CONTEXT_CLUES
|
||||
&HISTORY_CONTEXT_CLUES
|
||||
);
|
||||
assert_eq!(radarr_data.main_tabs.tabs[4].config, None);
|
||||
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "Indexers");
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[5].title, "Root Folders");
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[5].route,
|
||||
ActiveRadarrBlock::Indexers.into()
|
||||
ActiveRadarrBlock::RootFolders.into()
|
||||
);
|
||||
assert!(radarr_data.main_tabs.tabs[5].contextual_help.is_some());
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[5].contextual_help.unwrap(),
|
||||
&INDEXERS_CONTEXT_CLUES
|
||||
&ROOT_FOLDERS_CONTEXT_CLUES
|
||||
);
|
||||
assert_eq!(radarr_data.main_tabs.tabs[5].config, None);
|
||||
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[6].title, "System");
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[6].title, "Indexers");
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[6].route,
|
||||
ActiveRadarrBlock::System.into()
|
||||
ActiveRadarrBlock::Indexers.into()
|
||||
);
|
||||
assert!(radarr_data.main_tabs.tabs[6].contextual_help.is_some());
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[6].contextual_help.unwrap(),
|
||||
&SYSTEM_CONTEXT_CLUES
|
||||
&INDEXERS_CONTEXT_CLUES
|
||||
);
|
||||
assert_eq!(radarr_data.main_tabs.tabs[6].config, None);
|
||||
|
||||
assert_str_eq!(radarr_data.main_tabs.tabs[7].title, "System");
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[7].route,
|
||||
ActiveRadarrBlock::System.into()
|
||||
);
|
||||
assert!(radarr_data.main_tabs.tabs[7].contextual_help.is_some());
|
||||
assert_eq!(
|
||||
radarr_data.main_tabs.tabs[7].contextual_help.unwrap(),
|
||||
&SYSTEM_CONTEXT_CLUES
|
||||
);
|
||||
assert_eq!(radarr_data.main_tabs.tabs[7].config, None);
|
||||
|
||||
assert_eq!(radarr_data.movie_info_tabs.tabs.len(), 6);
|
||||
|
||||
assert_str_eq!(radarr_data.movie_info_tabs.tabs[0].title, "Details");
|
||||
@@ -334,8 +347,8 @@ mod tests {
|
||||
DELETE_MOVIE_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_COLLECTION_BLOCKS,
|
||||
EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS, EDIT_INDEXER_NZB_SELECTION_BLOCKS,
|
||||
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, EDIT_MOVIE_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS,
|
||||
INDEXER_SETTINGS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, LIBRARY_BLOCKS,
|
||||
MOVIE_DETAILS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||
HISTORY_BLOCKS, INDEXER_SETTINGS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS,
|
||||
LIBRARY_BLOCKS, MOVIE_DETAILS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@@ -388,6 +401,18 @@ mod tests {
|
||||
assert!(BLOCKLIST_BLOCKS.contains(&ActiveRadarrBlock::BlocklistSortPrompt));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_history_blocks_contents() {
|
||||
assert_eq!(HISTORY_BLOCKS.len(), 7);
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::History));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::HistoryItemDetails));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::HistorySortPrompt));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::FilterHistory));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::FilterHistoryError));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::SearchHistory));
|
||||
assert!(HISTORY_BLOCKS.contains(&ActiveRadarrBlock::SearchHistoryError));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_movie_blocks_contents() {
|
||||
assert_eq!(ADD_MOVIE_BLOCKS.len(), 10);
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
use crate::models::Route;
|
||||
use crate::models::radarr_models::RadarrHistoryWrapper;
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::network::radarr_network::RadarrEvent;
|
||||
use crate::network::{Network, RequestMethod};
|
||||
use anyhow::Result;
|
||||
use log::info;
|
||||
use serde_json::Value;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "radarr_history_network_tests.rs"]
|
||||
mod radarr_history_network_tests;
|
||||
|
||||
impl Network<'_, '_> {
|
||||
pub(in crate::network::radarr_network) async fn get_radarr_history(
|
||||
&mut self,
|
||||
events: u64,
|
||||
) -> Result<RadarrHistoryWrapper> {
|
||||
info!("Fetching all Radarr history events");
|
||||
let event = RadarrEvent::GetHistory(events);
|
||||
|
||||
let params = format!("pageSize={events}&sortDirection=descending&sortKey=date");
|
||||
let request_props = self
|
||||
.request_props_from(event, RequestMethod::Get, None::<()>, None, Some(params))
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), RadarrHistoryWrapper>(request_props, |history_response, mut app| {
|
||||
if !matches!(
|
||||
app.get_current_route(),
|
||||
Route::Radarr(ActiveRadarrBlock::HistorySortPrompt, _)
|
||||
) {
|
||||
let mut history_vec = history_response.records;
|
||||
history_vec.sort_by(|a, b| a.id.cmp(&b.id));
|
||||
app.data.radarr_data.history.set_items(history_vec);
|
||||
app.data.radarr_data.history.apply_sorting_toggle(false);
|
||||
}
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub(in crate::network::radarr_network) async fn mark_radarr_history_item_as_failed(
|
||||
&mut self,
|
||||
history_item_id: i64,
|
||||
) -> Result<Value> {
|
||||
info!("Marking the Radarr history item with ID: {history_item_id} as 'failed'");
|
||||
let event = RadarrEvent::MarkHistoryItemAsFailed(history_item_id);
|
||||
|
||||
let request_props = self
|
||||
.request_props_from(
|
||||
event,
|
||||
RequestMethod::Post,
|
||||
None,
|
||||
Some(format!("/{history_item_id}")),
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
self
|
||||
.handle_request::<(), Value>(request_props, |_, _| ())
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::models::radarr_models::{RadarrHistoryItem, RadarrHistoryWrapper, RadarrSerdeable};
|
||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||
use crate::models::stateful_table::SortOption;
|
||||
use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
|
||||
use crate::network::radarr_network::RadarrEvent;
|
||||
use crate::network::radarr_network::radarr_network_test_utils::test_utils::radarr_history_item;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rstest::rstest;
|
||||
use serde_json::json;
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_handle_get_radarr_history_event(#[values(true, false)] use_custom_sorting: bool) {
|
||||
let history_json = json!({"records": [{
|
||||
"id": 123,
|
||||
"sourceTitle": "z movie",
|
||||
"movieId": 1007,
|
||||
"quality": { "quality": { "name": "HD - 1080p" } },
|
||||
"languages": [{ "id": 1, "name": "English" }],
|
||||
"date": "2022-12-30T07:37:56Z",
|
||||
"eventType": "grabbed",
|
||||
"data": {
|
||||
"indexer": "DrunkenSlug (Prowlarr)",
|
||||
"releaseGroup": "SPARKS",
|
||||
"downloadClient": "transmission",
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 456,
|
||||
"sourceTitle": "A Movie",
|
||||
"movieId": 2001,
|
||||
"quality": { "quality": { "name": "HD - 1080p" } },
|
||||
"languages": [{ "id": 1, "name": "English" }],
|
||||
"date": "2022-12-30T07:37:56Z",
|
||||
"eventType": "grabbed",
|
||||
"data": {
|
||||
"indexer": "DrunkenSlug (Prowlarr)",
|
||||
"releaseGroup": "SPARKS",
|
||||
"downloadClient": "transmission",
|
||||
}
|
||||
}]});
|
||||
let response: RadarrHistoryWrapper = serde_json::from_value(history_json.clone()).unwrap();
|
||||
let mut expected_history_items = vec![
|
||||
RadarrHistoryItem {
|
||||
id: 123,
|
||||
movie_id: 1007,
|
||||
source_title: "z movie".into(),
|
||||
..radarr_history_item()
|
||||
},
|
||||
RadarrHistoryItem {
|
||||
id: 456,
|
||||
movie_id: 2001,
|
||||
source_title: "A Movie".into(),
|
||||
..radarr_history_item()
|
||||
},
|
||||
];
|
||||
let (mock, app, _server) = MockServarrApi::get()
|
||||
.returns(history_json)
|
||||
.query("pageSize=500&sortDirection=descending&sortKey=date")
|
||||
.build_for(RadarrEvent::GetHistory(500))
|
||||
.await;
|
||||
app.lock().await.data.radarr_data.history.sort_asc = true;
|
||||
if use_custom_sorting {
|
||||
let cmp_fn = |a: &RadarrHistoryItem, b: &RadarrHistoryItem| {
|
||||
a.source_title
|
||||
.text
|
||||
.to_lowercase()
|
||||
.cmp(&b.source_title.text.to_lowercase())
|
||||
};
|
||||
expected_history_items.sort_by(cmp_fn);
|
||||
|
||||
let history_sort_option = SortOption {
|
||||
name: "Source Title",
|
||||
cmp_fn: Some(cmp_fn),
|
||||
};
|
||||
app
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.history
|
||||
.sorting(vec![history_sort_option]);
|
||||
}
|
||||
let mut network = test_network(&app);
|
||||
|
||||
let RadarrSerdeable::HistoryWrapper(history) = network
|
||||
.handle_radarr_event(RadarrEvent::GetHistory(500))
|
||||
.await
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("Expected HistoryWrapper")
|
||||
};
|
||||
mock.assert_async().await;
|
||||
assert_eq!(
|
||||
app.lock().await.data.radarr_data.history.items,
|
||||
expected_history_items
|
||||
);
|
||||
assert!(app.lock().await.data.radarr_data.history.sort_asc);
|
||||
assert_eq!(history, response);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_get_radarr_history_event_no_op_when_user_is_selecting_sort_options() {
|
||||
let history_json = json!({"records": [{
|
||||
"id": 123,
|
||||
"sourceTitle": "z movie",
|
||||
"movieId": 1007,
|
||||
"quality": { "quality": { "name": "Bluray-1080p" } },
|
||||
"languages": [{ "id": 1, "name": "English" }],
|
||||
"date": "2024-02-10T07:28:45Z",
|
||||
"eventType": "grabbed",
|
||||
"data": {
|
||||
"indexer": "DrunkenSlug (Prowlarr)",
|
||||
"releaseGroup": "SPARKS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 456,
|
||||
"sourceTitle": "A Movie",
|
||||
"movieId": 2001,
|
||||
"quality": { "quality": { "name": "Bluray-1080p" } },
|
||||
"languages": [{ "id": 1, "name": "English" }],
|
||||
"date": "2024-02-10T07:28:45Z",
|
||||
"eventType": "grabbed",
|
||||
"data": {
|
||||
"indexer": "DrunkenSlug (Prowlarr)",
|
||||
"releaseGroup": "SPARKS"
|
||||
}
|
||||
}]});
|
||||
let response: RadarrHistoryWrapper = serde_json::from_value(history_json.clone()).unwrap();
|
||||
let (mock, app, _server) = MockServarrApi::get()
|
||||
.returns(history_json)
|
||||
.query("pageSize=500&sortDirection=descending&sortKey=date")
|
||||
.build_for(RadarrEvent::GetHistory(500))
|
||||
.await;
|
||||
app.lock().await.data.radarr_data.history.sort_asc = true;
|
||||
app
|
||||
.lock()
|
||||
.await
|
||||
.push_navigation_stack(ActiveRadarrBlock::HistorySortPrompt.into());
|
||||
let cmp_fn = |a: &RadarrHistoryItem, b: &RadarrHistoryItem| {
|
||||
a.source_title
|
||||
.text
|
||||
.to_lowercase()
|
||||
.cmp(&b.source_title.text.to_lowercase())
|
||||
};
|
||||
let history_sort_option = SortOption {
|
||||
name: "Source Title",
|
||||
cmp_fn: Some(cmp_fn),
|
||||
};
|
||||
app
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.history
|
||||
.sorting(vec![history_sort_option]);
|
||||
let mut network = test_network(&app);
|
||||
|
||||
let RadarrSerdeable::HistoryWrapper(history) = network
|
||||
.handle_radarr_event(RadarrEvent::GetHistory(500))
|
||||
.await
|
||||
.unwrap()
|
||||
else {
|
||||
panic!("Expected HistoryWrapper")
|
||||
};
|
||||
mock.assert_async().await;
|
||||
assert_is_empty!(app.lock().await.data.radarr_data.history);
|
||||
assert!(app.lock().await.data.radarr_data.history.sort_asc);
|
||||
assert_eq!(history, response);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_mark_radarr_history_item_as_failed_event() {
|
||||
let expected_history_item_id = 1;
|
||||
let (mock, app, _server) = MockServarrApi::post()
|
||||
.returns(json!({}))
|
||||
.path("/1")
|
||||
.build_for(RadarrEvent::MarkHistoryItemAsFailed(
|
||||
expected_history_item_id,
|
||||
))
|
||||
.await;
|
||||
let mut network = test_network(&app);
|
||||
|
||||
let result = network
|
||||
.handle_radarr_event(RadarrEvent::MarkHistoryItemAsFailed(
|
||||
expected_history_item_id,
|
||||
))
|
||||
.await;
|
||||
|
||||
mock.assert_async().await;
|
||||
assert_ok!(result);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ use super::NetworkResource;
|
||||
mod blocklist;
|
||||
mod collections;
|
||||
mod downloads;
|
||||
mod history;
|
||||
mod indexers;
|
||||
mod library;
|
||||
mod root_folders;
|
||||
@@ -47,10 +48,12 @@ pub enum RadarrEvent {
|
||||
GetBlocklist,
|
||||
GetCollections,
|
||||
GetDownloads(u64),
|
||||
GetHistory(u64),
|
||||
GetHostConfig,
|
||||
GetIndexers,
|
||||
GetAllIndexerSettings,
|
||||
GetLogs(u64),
|
||||
MarkHistoryItemAsFailed(i64),
|
||||
GetMovieCredits(i64),
|
||||
GetMovieDetails(i64),
|
||||
GetMovieHistory(i64),
|
||||
@@ -86,7 +89,9 @@ impl NetworkResource for RadarrEvent {
|
||||
RadarrEvent::GetBlocklist => "/blocklist?page=1&pageSize=10000",
|
||||
RadarrEvent::GetCollections | RadarrEvent::EditCollection(_) => "/collection",
|
||||
RadarrEvent::GetDownloads(_) | RadarrEvent::DeleteDownload(_) => "/queue",
|
||||
RadarrEvent::GetHistory(_) => "/history",
|
||||
RadarrEvent::GetHostConfig | RadarrEvent::GetSecurityConfig => "/config/host",
|
||||
RadarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
|
||||
RadarrEvent::GetIndexers | RadarrEvent::EditIndexer(_) | RadarrEvent::DeleteIndexer(_) => {
|
||||
"/indexer"
|
||||
}
|
||||
@@ -199,6 +204,10 @@ impl Network<'_, '_> {
|
||||
.get_radarr_downloads(count)
|
||||
.await
|
||||
.map(RadarrSerdeable::from),
|
||||
RadarrEvent::GetHistory(events) => self
|
||||
.get_radarr_history(events)
|
||||
.await
|
||||
.map(RadarrSerdeable::from),
|
||||
RadarrEvent::GetHostConfig => self
|
||||
.get_radarr_host_config()
|
||||
.await
|
||||
@@ -208,6 +217,10 @@ impl Network<'_, '_> {
|
||||
.get_radarr_logs(events)
|
||||
.await
|
||||
.map(RadarrSerdeable::from),
|
||||
RadarrEvent::MarkHistoryItemAsFailed(history_item_id) => self
|
||||
.mark_radarr_history_item_as_failed(history_item_id)
|
||||
.await
|
||||
.map(RadarrSerdeable::from),
|
||||
RadarrEvent::GetMovieCredits(movie_id) => {
|
||||
self.get_credits(movie_id).await.map(RadarrSerdeable::from)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ pub mod test_utils {
|
||||
use crate::models::radarr_models::{
|
||||
AddMovieSearchResult, BlocklistItem, BlocklistItemMovie, Collection, CollectionMovie, Credit,
|
||||
CreditType, DownloadRecord, DownloadsResponse, IndexerSettings, MediaInfo, MinimumAvailability,
|
||||
Movie, MovieCollection, MovieFile, MovieHistoryItem, RadarrRelease, RadarrTask, RadarrTaskName,
|
||||
Rating, RatingsList,
|
||||
Movie, MovieCollection, MovieFile, MovieHistoryItem, RadarrHistoryData, RadarrHistoryEventType,
|
||||
RadarrHistoryItem, RadarrRelease, RadarrTask, RadarrTaskName, Rating, RatingsList,
|
||||
};
|
||||
use crate::models::servarr_models::{
|
||||
Indexer, IndexerField, Language, Quality, QualityWrapper, RootFolder,
|
||||
@@ -313,6 +313,24 @@ pub mod test_utils {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn radarr_history_item() -> RadarrHistoryItem {
|
||||
RadarrHistoryItem {
|
||||
id: 1,
|
||||
source_title: HorizontallyScrollableText::from("Test"),
|
||||
movie_id: 1,
|
||||
quality: quality_wrapper(),
|
||||
languages: vec![language()],
|
||||
date: DateTime::from(DateTime::parse_from_rfc3339("2022-12-30T07:37:56Z").unwrap()),
|
||||
event_type: RadarrHistoryEventType::Grabbed,
|
||||
data: RadarrHistoryData {
|
||||
indexer: Some("DrunkenSlug (Prowlarr)".to_owned()),
|
||||
release_group: Some("SPARKS".to_owned()),
|
||||
download_client: Some("transmission".to_owned()),
|
||||
..RadarrHistoryData::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn download_record() -> DownloadRecord {
|
||||
DownloadRecord {
|
||||
title: "Test Download Title".to_owned(),
|
||||
|
||||
@@ -136,7 +136,9 @@ mod test {
|
||||
#[case(RadarrEvent::ClearBlocklist, "/blocklist/bulk")]
|
||||
#[case(RadarrEvent::DeleteBlocklistItem(1), "/blocklist")]
|
||||
#[case(RadarrEvent::GetBlocklist, "/blocklist?page=1&pageSize=10000")]
|
||||
#[case(RadarrEvent::GetHistory(500), "/history")]
|
||||
#[case(RadarrEvent::GetLogs(500), "/log")]
|
||||
#[case(RadarrEvent::MarkHistoryItemAsFailed(1), "/history/failed")]
|
||||
#[case(RadarrEvent::SearchNewMovie(String::new()), "/movie/lookup")]
|
||||
#[case(RadarrEvent::GetMovieCredits(0), "/credit")]
|
||||
#[case(RadarrEvent::GetMovieHistory(0), "/history/movie")]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, HISTORY_BLOCKS};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::radarr_ui::history::HistoryUi;
|
||||
use crate::ui::ui_test_utils::test_utils::render_to_string_with_app;
|
||||
|
||||
#[test]
|
||||
fn test_history_ui_accepts() {
|
||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||
if HISTORY_BLOCKS.contains(&active_radarr_block) {
|
||||
assert!(HistoryUi::accepts(active_radarr_block.into()));
|
||||
} else {
|
||||
assert!(!HistoryUi::accepts(active_radarr_block.into()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
mod snapshot_tests {
|
||||
use crate::ui::ui_test_utils::test_utils::TerminalSize;
|
||||
use rstest::rstest;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_history_ui_renders_loading() {
|
||||
let mut app = App::test_default();
|
||||
app.is_loading = true;
|
||||
app.push_navigation_stack(ActiveRadarrBlock::History.into());
|
||||
|
||||
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
|
||||
HistoryUi::draw(f, app, f.area());
|
||||
});
|
||||
|
||||
insta::assert_snapshot!(output);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_history_ui_renders_empty(
|
||||
#[values(ActiveRadarrBlock::History, ActiveRadarrBlock::HistoryItemDetails)]
|
||||
active_radarr_block: ActiveRadarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default();
|
||||
app.push_navigation_stack(active_radarr_block.into());
|
||||
|
||||
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
|
||||
HistoryUi::draw(f, app, f.area());
|
||||
});
|
||||
|
||||
insta::assert_snapshot!(format!("loading_history_tab_{active_radarr_block}"), output);
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
fn test_history_ui_renders(
|
||||
#[values(
|
||||
ActiveRadarrBlock::History,
|
||||
ActiveRadarrBlock::HistoryItemDetails,
|
||||
ActiveRadarrBlock::HistorySortPrompt,
|
||||
ActiveRadarrBlock::FilterHistory,
|
||||
ActiveRadarrBlock::FilterHistoryError,
|
||||
ActiveRadarrBlock::SearchHistory,
|
||||
ActiveRadarrBlock::SearchHistoryError
|
||||
)]
|
||||
active_radarr_block: ActiveRadarrBlock,
|
||||
) {
|
||||
let mut app = App::test_default_fully_populated();
|
||||
app.push_navigation_stack(active_radarr_block.into());
|
||||
|
||||
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
|
||||
HistoryUi::draw(f, app, f.area());
|
||||
});
|
||||
|
||||
insta::assert_snapshot!(format!("history_tab_{active_radarr_block}"), output);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
use crate::app::App;
|
||||
use crate::models::Route;
|
||||
use crate::models::radarr_models::RadarrHistoryItem;
|
||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, HISTORY_BLOCKS};
|
||||
use crate::ui::DrawUi;
|
||||
use crate::ui::styles::{ManagarrStyle, secondary_style};
|
||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use ratatui::Frame;
|
||||
use ratatui::layout::{Alignment, Constraint, Rect};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
|
||||
use super::radarr_ui_utils::create_history_event_details;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "history_ui_tests.rs"]
|
||||
mod history_ui_tests;
|
||||
|
||||
pub(super) struct HistoryUi;
|
||||
|
||||
impl DrawUi for HistoryUi {
|
||||
fn accepts(route: Route) -> bool {
|
||||
if let Route::Radarr(active_radarr_block, _) = route {
|
||||
return HISTORY_BLOCKS.contains(&active_radarr_block);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
|
||||
draw_history_table(f, app, area);
|
||||
|
||||
if active_radarr_block == ActiveRadarrBlock::HistoryItemDetails {
|
||||
draw_history_item_details_popup(f, app);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_history_table(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let current_selection = if app.data.radarr_data.history.items.is_empty() {
|
||||
RadarrHistoryItem::default()
|
||||
} else {
|
||||
app.data.radarr_data.history.current_selection().clone()
|
||||
};
|
||||
if let Route::Radarr(active_radarr_block, _) = app.get_current_route() {
|
||||
let history_row_mapping = |history_item: &RadarrHistoryItem| {
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
languages,
|
||||
quality,
|
||||
event_type,
|
||||
date,
|
||||
..
|
||||
} = history_item;
|
||||
|
||||
source_title.scroll_left_or_reset(
|
||||
get_width_from_percentage(area, 40),
|
||||
current_selection == *history_item,
|
||||
app.ui_scroll_tick_count == 0,
|
||||
);
|
||||
|
||||
Row::new(vec![
|
||||
Cell::from(source_title.to_string()),
|
||||
Cell::from(event_type.to_string()),
|
||||
Cell::from(
|
||||
languages
|
||||
.iter()
|
||||
.map(|language| language.name.to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
.join(","),
|
||||
),
|
||||
Cell::from(quality.quality.name.to_owned()),
|
||||
Cell::from(date.to_string()),
|
||||
])
|
||||
.primary()
|
||||
};
|
||||
let history_table =
|
||||
ManagarrTable::new(Some(&mut app.data.radarr_data.history), history_row_mapping)
|
||||
.block(layout_block_top_border())
|
||||
.loading(app.is_loading)
|
||||
.sorting(active_radarr_block == ActiveRadarrBlock::HistorySortPrompt)
|
||||
.searching(active_radarr_block == ActiveRadarrBlock::SearchHistory)
|
||||
.search_produced_empty_results(active_radarr_block == ActiveRadarrBlock::SearchHistoryError)
|
||||
.filtering(active_radarr_block == ActiveRadarrBlock::FilterHistory)
|
||||
.filter_produced_empty_results(active_radarr_block == ActiveRadarrBlock::FilterHistoryError)
|
||||
.headers(["Source Title", "Event Type", "Language", "Quality", "Date"])
|
||||
.constraints([
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(15),
|
||||
Constraint::Percentage(12),
|
||||
Constraint::Percentage(13),
|
||||
Constraint::Percentage(20),
|
||||
]);
|
||||
|
||||
if [
|
||||
ActiveRadarrBlock::SearchHistory,
|
||||
ActiveRadarrBlock::FilterHistory,
|
||||
]
|
||||
.contains(&active_radarr_block)
|
||||
{
|
||||
history_table.show_cursor(f, area);
|
||||
}
|
||||
|
||||
f.render_widget(history_table, area);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_history_item_details_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
|
||||
let current_selection = if app.data.radarr_data.history.items.is_empty() {
|
||||
RadarrHistoryItem::default()
|
||||
} else {
|
||||
app.data.radarr_data.history.current_selection().clone()
|
||||
};
|
||||
|
||||
let line_vec = create_history_event_details(current_selection);
|
||||
let text = Text::from(line_vec);
|
||||
|
||||
let message = Message::new(text)
|
||||
.title("Details")
|
||||
.style(secondary_style())
|
||||
.alignment(Alignment::Left);
|
||||
|
||||
f.render_widget(Popup::new(message).size(Size::NarrowLongMessage), f.area());
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭───────────────── Filter ──────────────────╮
|
||||
│Something │
|
||||
╰─────────────────────────────────────────────╯
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭─────────────── Error ───────────────╮
|
||||
│The given filter produced empty results│
|
||||
│ │
|
||||
╰───────────────────────────────────────╯
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭─────────────────────────────────── Details ───────────────────────────────────╮
|
||||
│Source Title: Test │
|
||||
│Event Type: grabbed │
|
||||
│Indexer: DrunkenSlug (Prowlarr) │
|
||||
│Release Group: SPARKS │
|
||||
│NZB Info URL: │
|
||||
│Download Client: transmission │
|
||||
│Age: 0 days │
|
||||
│Published Date: 1970-01-01 00:00:00 UTC │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────────────────────────────────╯
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭───────────────────────────────╮
|
||||
│Something │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰───────────────────────────────╯
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭───────────────── Search ──────────────────╮
|
||||
│Something │
|
||||
╰─────────────────────────────────────────────╯
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
Source Title ▼ Event Type Language Quality Date
|
||||
=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭─────────────── Error ───────────────╮
|
||||
│ No items found matching search │
|
||||
│ │
|
||||
╰───────────────────────────────────────╯
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Loading ...
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/history/history_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
╭─────────────────────────────────── Details ───────────────────────────────────╮
|
||||
│Source Title: │
|
||||
│Event Type: unknown │
|
||||
│ │
|
||||
│No additional data available │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰─────────────────────────────────────────────────────────────────────────────────╯
|
||||
@@ -21,6 +21,7 @@ use crate::ui::draw_tabs;
|
||||
use crate::ui::radarr_ui::blocklist::BlocklistUi;
|
||||
use crate::ui::radarr_ui::collections::CollectionsUi;
|
||||
use crate::ui::radarr_ui::downloads::DownloadsUi;
|
||||
use crate::ui::radarr_ui::history::HistoryUi;
|
||||
use crate::ui::radarr_ui::indexers::IndexersUi;
|
||||
use crate::ui::radarr_ui::library::LibraryUi;
|
||||
use crate::ui::radarr_ui::root_folders::RootFoldersUi;
|
||||
@@ -35,10 +36,12 @@ use crate::utils::convert_to_gb;
|
||||
mod blocklist;
|
||||
mod collections;
|
||||
mod downloads;
|
||||
mod history;
|
||||
mod indexers;
|
||||
mod library;
|
||||
#[cfg(test)]
|
||||
mod radarr_ui_tests;
|
||||
mod radarr_ui_utils;
|
||||
mod root_folders;
|
||||
mod system;
|
||||
|
||||
@@ -61,6 +64,7 @@ impl DrawUi for RadarrUi {
|
||||
_ if RootFoldersUi::accepts(route) => RootFoldersUi::draw(f, app, content_area),
|
||||
_ if SystemUi::accepts(route) => SystemUi::draw(f, app, content_area),
|
||||
_ if BlocklistUi::accepts(route) => BlocklistUi::draw(f, app, content_area),
|
||||
_ if HistoryUi::accepts(route) => HistoryUi::draw(f, app, content_area),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,10 @@ mod tests {
|
||||
#[case(ActiveRadarrBlock::Collections, 1)]
|
||||
#[case(ActiveRadarrBlock::Downloads, 2)]
|
||||
#[case(ActiveRadarrBlock::Blocklist, 3)]
|
||||
#[case(ActiveRadarrBlock::RootFolders, 4)]
|
||||
#[case(ActiveRadarrBlock::Indexers, 5)]
|
||||
#[case(ActiveRadarrBlock::System, 6)]
|
||||
#[case(ActiveRadarrBlock::History, 4)]
|
||||
#[case(ActiveRadarrBlock::RootFolders, 5)]
|
||||
#[case(ActiveRadarrBlock::Indexers, 6)]
|
||||
#[case(ActiveRadarrBlock::System, 7)]
|
||||
fn test_radarr_ui_renders_radarr_tabs(
|
||||
#[case] active_radarr_block: ActiveRadarrBlock,
|
||||
#[case] index: usize,
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
use ratatui::text::Line;
|
||||
|
||||
use crate::models::radarr_models::{RadarrHistoryData, RadarrHistoryEventType, RadarrHistoryItem};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "radarr_ui_utils_tests.rs"]
|
||||
mod radarr_ui_utils_tests;
|
||||
|
||||
pub(super) fn create_history_event_details(history_item: RadarrHistoryItem) -> Vec<Line<'static>> {
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
event_type,
|
||||
data,
|
||||
..
|
||||
} = history_item;
|
||||
let RadarrHistoryData {
|
||||
indexer,
|
||||
release_group,
|
||||
nzb_info_url,
|
||||
download_client,
|
||||
download_client_name,
|
||||
age,
|
||||
published_date,
|
||||
dropped_path,
|
||||
imported_path,
|
||||
message,
|
||||
reason,
|
||||
source_path,
|
||||
path,
|
||||
..
|
||||
} = data;
|
||||
|
||||
let mut lines = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start())),
|
||||
Line::from(format!("Event Type: {}", event_type)),
|
||||
];
|
||||
|
||||
match event_type {
|
||||
RadarrHistoryEventType::Grabbed => {
|
||||
lines.push(Line::from(format!(
|
||||
"Indexer: {}",
|
||||
indexer.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Release Group: {}",
|
||||
release_group.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"NZB Info URL: {}",
|
||||
nzb_info_url.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client
|
||||
.or(download_client_name)
|
||||
.unwrap_or_default()
|
||||
.trim_start()
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Age: {} days",
|
||||
age.unwrap_or("0".to_owned()).trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Published Date: {}",
|
||||
published_date.unwrap_or_default().to_string().trim_start(),
|
||||
)));
|
||||
}
|
||||
RadarrHistoryEventType::DownloadFolderImported => {
|
||||
lines.push(Line::from(format!(
|
||||
"Dropped Path: {}",
|
||||
dropped_path.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Imported Path: {}",
|
||||
imported_path.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client
|
||||
.or(download_client_name)
|
||||
.unwrap_or_default()
|
||||
.trim_start()
|
||||
)));
|
||||
}
|
||||
RadarrHistoryEventType::DownloadFailed => {
|
||||
lines.push(Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client
|
||||
.or(download_client_name)
|
||||
.unwrap_or_default()
|
||||
.trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Message: {}",
|
||||
message.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
}
|
||||
RadarrHistoryEventType::MovieFileDeleted => {
|
||||
lines.push(Line::from(format!(
|
||||
"Reason: {}",
|
||||
reason.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
}
|
||||
RadarrHistoryEventType::MovieFileRenamed => {
|
||||
lines.push(Line::from(format!(
|
||||
"Source Path: {}",
|
||||
source_path.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
lines.push(Line::from(format!(
|
||||
"Destination Path: {}",
|
||||
path.unwrap_or_default().trim_start(),
|
||||
)));
|
||||
}
|
||||
_ => {
|
||||
lines.push(Line::from(String::new()));
|
||||
lines.push(Line::from("No additional data available"));
|
||||
}
|
||||
}
|
||||
|
||||
lines
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::Utc;
|
||||
use ratatui::text::Line;
|
||||
|
||||
use crate::models::radarr_models::RadarrHistoryEventType;
|
||||
use crate::models::radarr_models::{RadarrHistoryData, RadarrHistoryItem};
|
||||
use crate::ui::radarr_ui::radarr_ui_utils::create_history_event_details;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_create_grabbed_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::Grabbed);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
data,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let RadarrHistoryData {
|
||||
indexer,
|
||||
release_group,
|
||||
nzb_info_url,
|
||||
download_client,
|
||||
download_client_name,
|
||||
age,
|
||||
published_date,
|
||||
..
|
||||
} = data;
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start(),)),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(format!(
|
||||
"Indexer: {}",
|
||||
indexer.unwrap_or_default().trim_start(),
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Release Group: {}",
|
||||
release_group.unwrap_or_default().trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"NZB Info URL: {}",
|
||||
nzb_info_url.unwrap_or_default().trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client
|
||||
.or(download_client_name)
|
||||
.unwrap_or_default()
|
||||
.trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Age: {} days",
|
||||
age.unwrap_or("0".to_owned()).trim_start(),
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Published Date: {}",
|
||||
published_date.unwrap_or_default().to_string().trim_start()
|
||||
)),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_download_folder_imported_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::DownloadFolderImported);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
data,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let RadarrHistoryData {
|
||||
dropped_path,
|
||||
imported_path,
|
||||
download_client,
|
||||
..
|
||||
} = data;
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start(),)),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(format!(
|
||||
"Dropped Path: {}",
|
||||
dropped_path.unwrap_or_default().trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Imported Path: {}",
|
||||
imported_path.unwrap_or_default().trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client.unwrap_or_default().trim_start(),
|
||||
)),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_download_failed_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::DownloadFailed);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
data,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let RadarrHistoryData {
|
||||
message,
|
||||
download_client,
|
||||
..
|
||||
} = data;
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start())),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(format!(
|
||||
"Download Client: {}",
|
||||
download_client.unwrap_or_default().trim_start()
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Message: {}",
|
||||
message.unwrap_or_default().trim_start()
|
||||
)),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_movie_file_deleted_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::MovieFileDeleted);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
data,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let RadarrHistoryData { reason, .. } = data;
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start(),)),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(format!(
|
||||
"Reason: {}",
|
||||
reason.unwrap_or_default().trim_start(),
|
||||
)),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_movie_file_renamed_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::MovieFileRenamed);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
data,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let RadarrHistoryData {
|
||||
source_path, path, ..
|
||||
} = data;
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start(),)),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(format!(
|
||||
"Source Path: {}",
|
||||
source_path.unwrap_or_default().trim_start(),
|
||||
)),
|
||||
Line::from(format!(
|
||||
"Destination Path: {}",
|
||||
path.unwrap_or_default().trim_start(),
|
||||
)),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_no_data_history_event_details() {
|
||||
let history_item = radarr_history_item(RadarrHistoryEventType::Unknown);
|
||||
let RadarrHistoryItem {
|
||||
source_title,
|
||||
event_type,
|
||||
..
|
||||
} = history_item.clone();
|
||||
let expected_vec = vec![
|
||||
Line::from(format!("Source Title: {}", source_title.text.trim_start(),)),
|
||||
Line::from(format!("Event Type: {event_type}")),
|
||||
Line::from(String::new()),
|
||||
Line::from("No additional data available"),
|
||||
];
|
||||
|
||||
let history_details_vec = create_history_event_details(history_item);
|
||||
|
||||
assert_eq!(expected_vec, history_details_vec);
|
||||
}
|
||||
|
||||
fn radarr_history_item(event_type: RadarrHistoryEventType) -> RadarrHistoryItem {
|
||||
RadarrHistoryItem {
|
||||
source_title: "test.source.title".into(),
|
||||
event_type,
|
||||
data: radarr_history_data(),
|
||||
..RadarrHistoryItem::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn radarr_history_data() -> RadarrHistoryData {
|
||||
RadarrHistoryData {
|
||||
dropped_path: Some("/dropped/test".into()),
|
||||
imported_path: Some("/imported/test".into()),
|
||||
indexer: Some("Test Indexer".into()),
|
||||
release_group: Some("test release group".into()),
|
||||
nzb_info_url: Some("test url".into()),
|
||||
download_client: Some("test download client".into()),
|
||||
download_client_name: None,
|
||||
age: Some("1".into()),
|
||||
published_date: Some(Utc::now()),
|
||||
message: Some("test message".into()),
|
||||
reason: Some("test reason".into()),
|
||||
source_path: Some("/source/path".into()),
|
||||
path: Some("/path".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Movie Title ▼ Source Title Languages Quality Formats Date │
|
||||
│=> Test z movie English HD - 1080p English 2024-02-10 07:28:45 UTC │
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Collection ▼ Number of Movies Root Folder Path Quality Profile Search on Add Monitored │
|
||||
│=> Test Collection 1 /nfs/movies HD - 1080p Yes 🏷 │
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Title Percent Complete Size Output Path Indexer Download Client │
|
||||
│=> Test Download Title 50% 3.30 GB /nfs/movies/Test kickass torrents transmission │
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
---
|
||||
source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Source Title ▼ Event Type Language Quality Date │
|
||||
│=> Test grabbed English HD - 1080p 2022-12-30 07:37:56 UTC │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Indexer ▼ RSS Automatic Search Interactive Search Priority Tags │
|
||||
│=> Test Indexer Enabled Enabled Enabled 25 alex │
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Title ▼ Year Studio Runtime Rating Language Size Quality Profile Monitored Tags │
|
||||
│=> Test 2023 21st Century Alex 2h 0m R English 3.30 GB HD - 1080p 🏷 alex │
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Path Free Space Unmapped Folders │
|
||||
│=> /nfs 204800.00 GB 0 │
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ source: src/ui/radarr_ui/radarr_ui_tests.rs
|
||||
expression: output
|
||||
---
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│╭ Tasks ───────────────────────────────────────────────────────────────────────╮╭ Queued Events ──────────────────────────────────────────────────────────────╮│
|
||||
││Name Interval Last Execution Last Duration Next Execution ││Trigger Status Name Queued Started Duration ││
|
||||
││Backup 1 hour now 00:00:17 59 minutes ││manual completed Refresh Monitored 4 minutes ago 4 minutes a 00:03:03 ││
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ expression: output
|
||||
│ ││ ││ │
|
||||
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Title ▼ Year Studio Runtime Rating Language Size Quality Profile Monitored Tags │
|
||||
│=> Test 2023 21st Century Alex 2h 0m R English 3.30 GB HD - 1080p 🏷 alex │
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ expression: output
|
||||
│ ││ ││ │
|
||||
╰───────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────╯╰──────────────────╯
|
||||
╭ Movies ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ Root Folders │ Indexers │ System │
|
||||
│ Library │ Collections │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │
|
||||
│───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────│
|
||||
│ Title ▼ Year Studio Runtime Rating Language Size Quality Profile Monitored Tags │
|
||||
│=> Test 2023 21st Century Alex 2h 0m R English 3.30 GB HD - 1080p 🏷 alex │
|
||||
|
||||
Reference in New Issue
Block a user