feat(network): Support for fetching all Sonarr tasks

This commit is contained in:
2024-11-22 16:35:39 -07:00
parent 539ad75fe6
commit c54bd2bab0
17 changed files with 267 additions and 64 deletions
+2 -2
View File
@@ -12,7 +12,7 @@ use tokio::sync::Mutex;
use crate::app::App;
use crate::cli::CliCommandHandler;
use crate::models::radarr_models::{ReleaseDownloadBody, TaskName};
use crate::models::radarr_models::{RadarrTaskName, ReleaseDownloadBody};
use crate::network::radarr_network::RadarrEvent;
use crate::network::NetworkTrait;
use anyhow::Result;
@@ -107,7 +107,7 @@ pub enum RadarrCommand {
value_enum,
required = true
)]
task_name: TaskName,
task_name: RadarrTaskName,
},
#[command(
about = "Test the indexer with the given ID. Note that a successful test returns an empty JSON body; i.e. '{}'"
+4 -4
View File
@@ -261,8 +261,8 @@ mod tests {
},
models::{
radarr_models::{
BlocklistItem, BlocklistResponse, IndexerSettings, RadarrSerdeable, ReleaseDownloadBody,
TaskName,
BlocklistItem, BlocklistResponse, IndexerSettings, RadarrSerdeable, RadarrTaskName,
ReleaseDownloadBody,
},
Serdeable,
},
@@ -389,7 +389,7 @@ mod tests {
#[tokio::test]
async fn test_start_task_command() {
let expected_task_name = TaskName::ApplicationCheckUpdate;
let expected_task_name = RadarrTaskName::ApplicationCheckUpdate;
let mut mock_network = MockNetworkTrait::new();
mock_network
.expect_handle_network_event()
@@ -404,7 +404,7 @@ mod tests {
});
let app_arc = Arc::new(Mutex::new(App::default()));
let start_task_command = RadarrCommand::StartTask {
task_name: TaskName::ApplicationCheckUpdate,
task_name: RadarrTaskName::ApplicationCheckUpdate,
};
let result = RadarrCliHandler::with(&app_arc, start_task_command, &mut mock_network)
@@ -8,7 +8,7 @@ mod tests {
use crate::event::Key;
use crate::handlers::radarr_handlers::system::system_details_handler::SystemDetailsHandler;
use crate::handlers::KeyEventHandler;
use crate::models::radarr_models::Task;
use crate::models::radarr_models::RadarrTask;
use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS,
};
@@ -74,7 +74,7 @@ mod tests {
.data
.radarr_data
.tasks
.set_items(simple_stateful_iterable_vec!(Task, String, name));
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
@@ -102,7 +102,7 @@ mod tests {
.data
.radarr_data
.tasks
.set_items(simple_stateful_iterable_vec!(Task, String, name));
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
@@ -318,7 +318,7 @@ mod tests {
.data
.radarr_data
.tasks
.set_items(extended_stateful_iterable_vec!(Task, String, name));
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
SystemDetailsHandler::with(
&DEFAULT_KEYBINDINGS.end.key,
@@ -357,7 +357,7 @@ mod tests {
.data
.radarr_data
.tasks
.set_items(extended_stateful_iterable_vec!(Task, String, name));
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
SystemDetailsHandler::with(
&DEFAULT_KEYBINDINGS.end.key,
@@ -789,7 +789,11 @@ mod tests {
app.is_loading = is_ready;
app.push_navigation_stack(ActiveRadarrBlock::System.into());
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemDetailsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::SystemTasks, &None)
.handle();
@@ -9,7 +9,7 @@ mod tests {
use crate::event::Key;
use crate::handlers::radarr_handlers::system::SystemHandler;
use crate::handlers::KeyEventHandler;
use crate::models::radarr_models::Task;
use crate::models::radarr_models::RadarrTask;
use crate::models::servarr_data::radarr::radarr_data::{
ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS,
};
@@ -105,7 +105,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.update.key,
@@ -135,7 +139,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.update.key,
@@ -160,7 +168,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.events.key,
@@ -190,7 +202,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.events.key,
@@ -215,7 +231,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
app.push_navigation_stack(ActiveRadarrBlock::System.into());
SystemHandler::with(
@@ -244,7 +264,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
app.push_navigation_stack(ActiveRadarrBlock::System.into());
SystemHandler::with(
@@ -271,7 +295,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.logs.key,
@@ -309,7 +337,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.logs.key,
@@ -335,7 +367,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.tasks.key,
@@ -365,7 +401,11 @@ mod tests {
.radarr_data
.queued_events
.set_items(vec![QueueEvent::default()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
SystemHandler::with(
&DEFAULT_KEYBINDINGS.tasks.key,
@@ -430,7 +470,11 @@ mod tests {
fn test_system_handler_is_not_ready_when_logs_is_empty() {
let mut app = App::default();
app.is_loading = false;
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
app
.data
.radarr_data
@@ -473,7 +517,11 @@ mod tests {
let mut app = App::default();
app.is_loading = false;
app.data.radarr_data.logs.set_items(vec!["test".into()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
let system_handler = SystemHandler::with(
&DEFAULT_KEYBINDINGS.update.key,
@@ -490,7 +538,11 @@ mod tests {
let mut app = App::default();
app.is_loading = false;
app.data.radarr_data.logs.set_items(vec!["test".into()]);
app.data.radarr_data.tasks.set_items(vec![Task::default()]);
app
.data
.radarr_data
.tasks
.set_items(vec![RadarrTask::default()]);
app
.data
.radarr_data
+6 -6
View File
@@ -435,9 +435,9 @@ pub struct SystemStatus {
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct Task {
pub struct RadarrTask {
pub name: String,
pub task_name: TaskName,
pub task_name: RadarrTaskName,
#[serde(deserialize_with = "super::from_i64")]
pub interval: i64,
pub last_execution: DateTime<Utc>,
@@ -447,7 +447,7 @@ pub struct Task {
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy, ValueEnum)]
#[serde(rename_all = "PascalCase")]
pub enum TaskName {
pub enum RadarrTaskName {
#[default]
ApplicationCheckUpdate,
Backup,
@@ -462,7 +462,7 @@ pub enum TaskName {
RssSync,
}
impl Display for TaskName {
impl Display for RadarrTaskName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let task_name = serde_json::to_string(&self)
.expect("Unable to serialize task name")
@@ -514,7 +514,7 @@ pub enum RadarrSerdeable {
SecurityConfig(SecurityConfig),
SystemStatus(SystemStatus),
Tags(Vec<Tag>),
Tasks(Vec<Task>),
Tasks(Vec<RadarrTask>),
Updates(Vec<Update>),
AddMovieSearchResults(Vec<AddMovieSearchResult>),
IndexerTestResults(Vec<IndexerTestResult>),
@@ -555,7 +555,7 @@ serde_enum_from!(
SecurityConfig(SecurityConfig),
SystemStatus(SystemStatus),
Tags(Vec<Tag>),
Tasks(Vec<Task>),
Tasks(Vec<RadarrTask>),
Updates(Vec<Update>),
AddMovieSearchResults(Vec<AddMovieSearchResult>),
IndexerTestResults(Vec<IndexerTestResult>),
+4 -4
View File
@@ -8,7 +8,7 @@ mod tests {
AddMovieSearchResult, BlocklistItem, BlocklistResponse, Collection, Credit, DiskSpace,
DownloadRecord, DownloadsResponse, Indexer, IndexerSettings, IndexerTestResult,
MinimumAvailability, Monitor, Movie, MovieHistoryItem, QualityProfile, RadarrSerdeable,
Release, SystemStatus, Tag, Task, TaskName, Update,
RadarrTask, RadarrTaskName, Release, SystemStatus, Tag, Update,
},
servarr_models::{HostConfig, Log, LogResponse, QueueEvent, RootFolder, SecurityConfig},
EnumDisplayStyle, Serdeable,
@@ -17,7 +17,7 @@ mod tests {
#[test]
fn test_task_name_display() {
assert_str_eq!(
TaskName::ApplicationCheckUpdate.to_string(),
RadarrTaskName::ApplicationCheckUpdate.to_string(),
"ApplicationCheckUpdate"
);
}
@@ -383,9 +383,9 @@ mod tests {
#[test]
fn test_radarr_serdeable_from_tasks() {
let tasks = vec![Task {
let tasks = vec![RadarrTask {
name: "test".to_owned(),
..Task::default()
..RadarrTask::default()
}];
let radarr_serdeable: RadarrSerdeable = tasks.clone().into();
@@ -7,7 +7,7 @@ use crate::app::radarr::radarr_context_clues::{
};
use crate::models::radarr_models::{
AddMovieSearchResult, BlocklistItem, Collection, CollectionMovie, DownloadRecord,
IndexerSettings, Movie, Task,
IndexerSettings, Movie, RadarrTask,
};
use crate::models::servarr_data::radarr::modals::{
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem,
@@ -48,7 +48,7 @@ pub struct RadarrData<'a> {
pub collection_movies: StatefulTable<CollectionMovie>,
pub logs: StatefulList<HorizontallyScrollableText>,
pub log_details: StatefulList<HorizontallyScrollableText>,
pub tasks: StatefulTable<Task>,
pub tasks: StatefulTable<RadarrTask>,
pub queued_events: StatefulTable<QueueEvent>,
pub updates: ScrollableText,
pub main_tabs: TabState,
@@ -5,7 +5,7 @@ use strum::EnumIter;
use crate::models::{
servarr_models::{DiskSpace, Indexer, QueueEvent, RootFolder},
sonarr_models::{
BlocklistItem, DownloadRecord, IndexerSettings, Season, Series, SonarrHistoryItem,
BlocklistItem, DownloadRecord, IndexerSettings, Season, Series, SonarrHistoryItem, SonarrTask,
},
stateful_list::StatefulList,
stateful_table::StatefulTable,
@@ -36,6 +36,7 @@ pub struct SonarrData {
pub series_history: Option<StatefulTable<SonarrHistoryItem>>,
pub start_time: DateTime<Utc>,
pub tags_map: BiMap<i64, String>,
pub tasks: StatefulTable<SonarrTask>,
pub version: String,
}
@@ -59,6 +60,7 @@ impl Default for SonarrData {
series_history: None,
start_time: DateTime::default(),
tags_map: BiMap::default(),
tasks: StatefulTable::default(),
version: String::new(),
}
}
@@ -51,6 +51,7 @@ mod tests {
assert!(sonarr_data.series_history.is_none());
assert_eq!(sonarr_data.start_time, <DateTime<Utc>>::default());
assert!(sonarr_data.tags_map.is_empty());
assert!(sonarr_data.tasks.is_empty());
assert!(sonarr_data.version.is_empty());
}
}
+40
View File
@@ -388,6 +388,44 @@ pub struct SonarrHistoryItem {
pub data: SonarrHistoryData,
}
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct SonarrTask {
pub name: String,
pub task_name: SonarrTaskName,
#[serde(deserialize_with = "super::from_i64")]
pub interval: i64,
pub last_execution: DateTime<Utc>,
pub last_duration: String,
pub next_execution: DateTime<Utc>,
}
#[derive(Default, Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy, ValueEnum)]
#[serde(rename_all = "PascalCase")]
pub enum SonarrTaskName {
#[default]
ApplicationUpdateCheck,
Backup,
CheckHealth,
CleanUpRecycleBin,
Housekeeping,
ImportListSync,
MessagingCleanup,
RefreshMonitoredDownloads,
RefreshSeries,
RssSync,
UpdateSceneMapping,
}
impl Display for SonarrTaskName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let task_name = serde_json::to_string(&self)
.expect("Unable to serialize task name")
.replace('"', "");
write!(f, "{task_name}")
}
}
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
#[serde(untagged)]
#[allow(clippy::large_enum_variant)]
@@ -412,6 +450,7 @@ pub enum SonarrSerdeable {
SystemStatus(SystemStatus),
Tag(Tag),
Tags(Vec<Tag>),
Tasks(Vec<SonarrTask>),
BlocklistResponse(BlocklistResponse),
LogResponse(LogResponse),
}
@@ -450,6 +489,7 @@ serde_enum_from!(
SystemStatus(SystemStatus),
Tag(Tag),
Tags(Vec<Tag>),
Tasks(Vec<SonarrTask>),
BlocklistResponse(BlocklistResponse),
LogResponse(LogResponse),
}
+21 -1
View File
@@ -11,7 +11,7 @@ mod tests {
sonarr_models::{
BlocklistItem, BlocklistResponse, DownloadRecord, DownloadsResponse, Episode,
IndexerSettings, Series, SeriesStatus, SeriesType, SonarrHistoryEventType, SonarrHistoryItem,
SonarrSerdeable, SystemStatus,
SonarrSerdeable, SonarrTask, SonarrTaskName, SystemStatus,
},
EnumDisplayStyle, Serdeable,
};
@@ -117,6 +117,14 @@ mod tests {
);
}
#[test]
fn test_task_name_display() {
assert_str_eq!(
SonarrTaskName::ApplicationUpdateCheck.to_string(),
"ApplicationUpdateCheck"
);
}
#[test]
fn test_sonarr_serdeable_from() {
let sonarr_serdeable = SonarrSerdeable::Value(json!({}));
@@ -406,4 +414,16 @@ mod tests {
assert_eq!(sonarr_serdeable, SonarrSerdeable::Tags(tags));
}
#[test]
fn test_sonarr_serdeable_from_tasks() {
let tasks = vec![SonarrTask {
name: "test".to_owned(),
..SonarrTask::default()
}];
let sonarr_serdeable: SonarrSerdeable = tasks.clone().into();
assert_eq!(sonarr_serdeable, SonarrSerdeable::Tasks(tasks));
}
}
+7 -7
View File
@@ -10,8 +10,8 @@ use crate::models::radarr_models::{
AddMovieBody, AddMovieSearchResult, AddOptions, BlocklistResponse, Collection, CollectionMovie,
CommandBody, Credit, CreditType, DeleteMovieParams, DownloadRecord, DownloadsResponse,
EditCollectionParams, EditIndexerParams, EditMovieParams, IndexerSettings, IndexerTestResult,
Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, ReleaseDownloadBody, SystemStatus,
Task, TaskName, Update,
Movie, MovieCommandBody, MovieHistoryItem, RadarrSerdeable, RadarrTask, RadarrTaskName,
ReleaseDownloadBody, SystemStatus, Update,
};
use crate::models::servarr_data::radarr::modals::{
AddMovieModal, EditCollectionModal, EditIndexerModal, EditMovieModal, IndexerTestResultModalItem,
@@ -73,7 +73,7 @@ pub enum RadarrEvent {
GetUpdates,
HealthCheck,
SearchNewMovie(Option<String>),
StartTask(Option<TaskName>),
StartTask(Option<RadarrTaskName>),
TestIndexer(Option<i64>),
TestAllIndexers,
TriggerAutomaticSearch(Option<i64>),
@@ -243,7 +243,7 @@ impl<'a, 'b> Network<'a, 'b> {
.map(RadarrSerdeable::from),
RadarrEvent::GetStatus => self.get_radarr_status().await.map(RadarrSerdeable::from),
RadarrEvent::GetTags => self.get_radarr_tags().await.map(RadarrSerdeable::from),
RadarrEvent::GetTasks => self.get_tasks().await.map(RadarrSerdeable::from),
RadarrEvent::GetTasks => self.get_radarr_tasks().await.map(RadarrSerdeable::from),
RadarrEvent::GetUpdates => self.get_updates().await.map(RadarrSerdeable::from),
RadarrEvent::HealthCheck => self
.get_radarr_healthcheck()
@@ -1855,7 +1855,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_tasks(&mut self) -> Result<Vec<Task>> {
async fn get_radarr_tasks(&mut self) -> Result<Vec<RadarrTask>> {
info!("Fetching Radarr tasks");
let event = RadarrEvent::GetTasks;
@@ -1864,7 +1864,7 @@ impl<'a, 'b> Network<'a, 'b> {
.await;
self
.handle_request::<(), Vec<Task>>(request_props, |tasks_vec, mut app| {
.handle_request::<(), Vec<RadarrTask>>(request_props, |tasks_vec, mut app| {
app.data.radarr_data.tasks.set_items(tasks_vec);
})
.await
@@ -2006,7 +2006,7 @@ impl<'a, 'b> Network<'a, 'b> {
}
}
async fn start_task(&mut self, task: Option<TaskName>) -> Result<Value> {
async fn start_task(&mut self, task: Option<RadarrTaskName>) -> Result<Value> {
let event = RadarrEvent::StartTask(None);
let task_name = if let Some(t_name) = task {
t_name
+10 -10
View File
@@ -733,9 +733,9 @@ mod test {
.data
.radarr_data
.tasks
.set_items(vec![Task {
task_name: TaskName::default(),
..Task::default()
.set_items(vec![RadarrTask {
task_name: RadarrTaskName::default(),
..RadarrTask::default()
}]);
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
@@ -767,7 +767,7 @@ mod test {
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let RadarrSerdeable::Value(value) = network
.handle_radarr_event(RadarrEvent::StartTask(Some(TaskName::default())))
.handle_radarr_event(RadarrEvent::StartTask(Some(RadarrTaskName::default())))
.await
.unwrap()
{
@@ -2666,7 +2666,7 @@ mod test {
}
#[tokio::test]
async fn test_handle_get_tasks_event() {
async fn test_handle_get_radarr_tasks_event() {
let tasks_json = json!([{
"name": "Application Check Update",
"taskName": "ApplicationCheckUpdate",
@@ -2683,20 +2683,20 @@ mod test {
"nextExecution": "2023-05-20T21:29:16Z",
"lastDuration": "00:00:00.5111547",
}]);
let response: Vec<Task> = serde_json::from_value(tasks_json.clone()).unwrap();
let response: Vec<RadarrTask> = serde_json::from_value(tasks_json.clone()).unwrap();
let timestamp = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap());
let expected_tasks = vec![
Task {
RadarrTask {
name: "Application Check Update".to_owned(),
task_name: TaskName::ApplicationCheckUpdate,
task_name: RadarrTaskName::ApplicationCheckUpdate,
interval: 360,
last_execution: timestamp,
next_execution: timestamp,
last_duration: "00:00:00.5111547".to_owned(),
},
Task {
RadarrTask {
name: "Backup".to_owned(),
task_name: TaskName::Backup,
task_name: RadarrTaskName::Backup,
interval: 10080,
last_execution: timestamp,
next_execution: timestamp,
+19 -1
View File
@@ -15,7 +15,7 @@ use crate::{
},
sonarr_models::{
BlocklistResponse, DownloadRecord, DownloadsResponse, Episode, IndexerSettings, Series,
SonarrHistoryItem, SonarrHistoryWrapper, SonarrSerdeable, SystemStatus,
SonarrHistoryItem, SonarrHistoryWrapper, SonarrSerdeable, SonarrTask, SystemStatus,
},
stateful_table::StatefulTable,
HorizontallyScrollableText, Route, Scrollable, ScrollableText,
@@ -60,6 +60,7 @@ pub enum SonarrEvent {
GetSeriesHistory(Option<i64>),
GetStatus,
GetTags,
GetTasks,
HealthCheck,
ListSeries,
MarkHistoryItemAsFailed(i64),
@@ -88,6 +89,7 @@ impl NetworkResource for SonarrEvent {
SonarrEvent::GetSeasonReleases(_) | SonarrEvent::GetEpisodeReleases(_) => "/release",
SonarrEvent::GetSeriesHistory(_) => "/history/series",
SonarrEvent::GetStatus => "/system/status",
SonarrEvent::GetTasks => "/system/task",
SonarrEvent::HealthCheck => "/health",
SonarrEvent::ListSeries | SonarrEvent::GetSeriesDetails(_) => "/series",
SonarrEvent::MarkHistoryItemAsFailed(_) => "/history/failed",
@@ -202,6 +204,7 @@ impl<'a, 'b> Network<'a, 'b> {
.map(SonarrSerdeable::from),
SonarrEvent::GetStatus => self.get_sonarr_status().await.map(SonarrSerdeable::from),
SonarrEvent::GetTags => self.get_sonarr_tags().await.map(SonarrSerdeable::from),
SonarrEvent::GetTasks => self.get_sonarr_tasks().await.map(SonarrSerdeable::from),
SonarrEvent::HealthCheck => self
.get_sonarr_healthcheck()
.await
@@ -1156,6 +1159,21 @@ impl<'a, 'b> Network<'a, 'b> {
.await
}
async fn get_sonarr_tasks(&mut self) -> Result<Vec<SonarrTask>> {
info!("Fetching Sonarr tasks");
let event = SonarrEvent::GetTasks;
let request_props = self
.request_props_from(event, RequestMethod::Get, None::<()>, None, None)
.await;
self
.handle_request::<(), Vec<SonarrTask>>(request_props, |tasks_vec, mut app| {
app.data.sonarr_data.tasks.set_items(tasks_vec);
})
.await
}
async fn mark_sonarr_history_item_as_failed(&mut self, history_item_id: i64) -> Result<Value> {
info!("Marking the Sonarr history item with ID: {history_item_id} as 'failed'");
let event = SonarrEvent::MarkHistoryItemAsFailed(history_item_id);
+67 -1
View File
@@ -20,13 +20,14 @@ mod test {
DiskSpace, HostConfig, Indexer, IndexerField, Language, LogResponse, Quality, QualityProfile,
QualityWrapper, QueueEvent, Release, RootFolder, SecurityConfig, Tag,
};
use crate::models::sonarr_models::SystemStatus;
use crate::models::sonarr_models::{
BlocklistItem, DownloadRecord, DownloadsResponse, Episode, EpisodeFile, MediaInfo,
SonarrTaskName,
};
use crate::models::sonarr_models::{
BlocklistResponse, SonarrHistoryData, SonarrHistoryItem, SonarrHistoryWrapper,
};
use crate::models::sonarr_models::{SonarrTask, SystemStatus};
use crate::models::stateful_table::StatefulTable;
use crate::models::HorizontallyScrollableText;
use crate::models::{sonarr_models::SonarrSerdeable, stateful_table::SortOption};
@@ -217,6 +218,7 @@ mod test {
#[case(SonarrEvent::GetLogs(Some(500)), "/log")]
#[case(SonarrEvent::GetQualityProfiles, "/qualityprofile")]
#[case(SonarrEvent::GetStatus, "/system/status")]
#[case(SonarrEvent::GetTasks, "/system/task")]
#[case(SonarrEvent::MarkHistoryItemAsFailed(0), "/history/failed")]
fn test_resource(#[case] event: SonarrEvent, #[case] expected_uri: String) {
assert_str_eq!(event.resource(), expected_uri);
@@ -3675,6 +3677,70 @@ mod test {
}
}
#[tokio::test]
async fn test_handle_get_sonarr_tasks_event() {
let tasks_json = json!([{
"name": "Application Update Check",
"taskName": "ApplicationUpdateCheck",
"interval": 360,
"lastExecution": "2023-05-20T21:29:16Z",
"nextExecution": "2023-05-20T21:29:16Z",
"lastDuration": "00:00:00.5111547",
},
{
"name": "Backup",
"taskName": "Backup",
"interval": 10080,
"lastExecution": "2023-05-20T21:29:16Z",
"nextExecution": "2023-05-20T21:29:16Z",
"lastDuration": "00:00:00.5111547",
}]);
let response: Vec<SonarrTask> = serde_json::from_value(tasks_json.clone()).unwrap();
let timestamp = DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:16Z").unwrap());
let expected_tasks = vec![
SonarrTask {
name: "Application Update Check".to_owned(),
task_name: SonarrTaskName::ApplicationUpdateCheck,
interval: 360,
last_execution: timestamp,
next_execution: timestamp,
last_duration: "00:00:00.5111547".to_owned(),
},
SonarrTask {
name: "Backup".to_owned(),
task_name: SonarrTaskName::Backup,
interval: 10080,
last_execution: timestamp,
next_execution: timestamp,
last_duration: "00:00:00.5111547".to_owned(),
},
];
let (async_server, app_arc, _server) = mock_servarr_api(
RequestMethod::Get,
None,
Some(tasks_json),
None,
SonarrEvent::GetTasks,
None,
None,
)
.await;
let mut network = Network::new(&app_arc, CancellationToken::new(), Client::new());
if let SonarrSerdeable::Tasks(tasks) = network
.handle_sonarr_event(SonarrEvent::GetTasks)
.await
.unwrap()
{
async_server.assert_async().await;
assert_eq!(
app_arc.lock().await.data.sonarr_data.tasks.items,
expected_tasks
);
assert_eq!(tasks, response);
}
}
#[tokio::test]
async fn test_handle_mark_sonarr_history_item_as_failed_event() {
let expected_history_item_id = 1;
+3 -3
View File
@@ -12,7 +12,7 @@ use ratatui::{
};
use crate::app::App;
use crate::models::radarr_models::Task;
use crate::models::radarr_models::RadarrTask;
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
use crate::models::servarr_models::QueueEvent;
use crate::ui::radarr_ui::radarr_ui_utils::{convert_to_minutes_hours_days, style_log_list_item};
@@ -91,7 +91,7 @@ pub(super) fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area:
}
fn draw_tasks(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let tasks_row_mapping = |task: &Task| {
let tasks_row_mapping = |task: &RadarrTask| {
let task_props = extract_task_props(task);
Row::new(vec![
@@ -218,7 +218,7 @@ pub(super) struct TaskProps {
pub(super) next_execution: String,
}
pub(super) fn extract_task_props(task: &Task) -> TaskProps {
pub(super) fn extract_task_props(task: &RadarrTask) -> TaskProps {
let interval = convert_to_minutes_hours_days(task.interval);
let last_duration = &task.last_duration[..8];
let next_execution =
+2 -2
View File
@@ -6,7 +6,7 @@ use ratatui::Frame;
use crate::app::context_clues::{build_context_clue_string, BARE_POPUP_CONTEXT_CLUES};
use crate::app::radarr::radarr_context_clues::SYSTEM_TASKS_CONTEXT_CLUES;
use crate::app::App;
use crate::models::radarr_models::Task;
use crate::models::radarr_models::RadarrTask;
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, SYSTEM_DETAILS_BLOCKS};
use crate::models::Route;
use crate::ui::radarr_ui::radarr_ui_utils::style_log_list_item;
@@ -108,7 +108,7 @@ fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>) {
fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
let help_footer = Some(build_context_clue_string(&SYSTEM_TASKS_CONTEXT_CLUES));
let tasks_row_mapping = |task: &Task| {
let tasks_row_mapping = |task: &RadarrTask| {
let task_props = extract_task_props(task);
Row::new(vec![