fix: Sonarr network wasn't checking for the user to be using the sorting block when populating season details

This commit is contained in:
2026-01-19 14:50:01 -07:00
parent 5fa9b08347
commit 7add62b245
4 changed files with 140 additions and 144 deletions
@@ -1,4 +1,4 @@
use crate::models::servarr_data::sonarr::modals::{EpisodeDetailsModal, SeasonDetailsModal}; use crate::models::servarr_data::sonarr::modals::SeasonDetailsModal;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock; use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::servarr_models::Language; use crate::models::servarr_models::Language;
use crate::models::sonarr_models::{ use crate::models::sonarr_models::{
@@ -65,10 +65,6 @@ impl Network<'_, '_> {
app.get_current_route(), app.get_current_route(),
Route::Sonarr(ActiveSonarrBlock::EpisodesSortPrompt, _) Route::Sonarr(ActiveSonarrBlock::EpisodesSortPrompt, _)
) { ) {
if app.data.sonarr_data.season_details_modal.is_none() {
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
}
let season_episodes_vec = if !app.data.sonarr_data.seasons.is_empty() { let season_episodes_vec = if !app.data.sonarr_data.seasons.is_empty() {
let season_number = app let season_number = app
.data .data
@@ -85,22 +81,14 @@ impl Network<'_, '_> {
episode_vec episode_vec
}; };
app let season_details_modal = app
.data .data
.sonarr_data .sonarr_data
.season_details_modal .season_details_modal
.as_mut() .get_or_insert_default();
.unwrap()
.episodes season_details_modal.episodes.set_items(season_episodes_vec);
.set_items(season_episodes_vec); season_details_modal.episodes.apply_sorting_toggle(false);
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episodes
.apply_sorting_toggle(false);
} }
}) })
.await .await
@@ -125,16 +113,13 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<EpisodeFile>>(request_props, |episode_file_vec, mut app| { .handle_request::<(), Vec<EpisodeFile>>(request_props, |episode_file_vec, mut app| {
if app.data.sonarr_data.season_details_modal.is_none() { let season_details_modal = app
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
}
app
.data .data
.sonarr_data .sonarr_data
.season_details_modal .season_details_modal
.as_mut() .get_or_insert_default();
.unwrap()
season_details_modal
.episode_files .episode_files
.set_items(episode_file_vec); .set_items(episode_file_vec);
}) })
@@ -156,50 +141,19 @@ impl Network<'_, '_> {
self self
.handle_request::<(), SonarrHistoryWrapper>(request_props, |history_response, mut app| { .handle_request::<(), SonarrHistoryWrapper>(request_props, |history_response, mut app| {
if app.data.sonarr_data.season_details_modal.is_none() { let season_details_modal = app
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
}
if app
.data .data
.sonarr_data .sonarr_data
.season_details_modal .season_details_modal
.as_ref() .get_or_insert_default();
.unwrap() let episode_details_modal = season_details_modal
.episode_details_modal .episode_details_modal
.is_none() .get_or_insert_default();
{
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal = Some(EpisodeDetailsModal::default());
}
let mut history_vec = history_response.records; let mut history_vec = history_response.records;
history_vec.sort_by(|a, b| a.id.cmp(&b.id)); history_vec.sort_by(|a, b| a.id.cmp(&b.id));
app episode_details_modal.episode_history.set_items(history_vec);
.data episode_details_modal
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal
.as_mut()
.unwrap()
.episode_history
.set_items(history_vec);
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal
.as_mut()
.unwrap()
.episode_history .episode_history
.apply_sorting_toggle(false); .apply_sorting_toggle(false);
}) })
@@ -231,24 +185,6 @@ impl Network<'_, '_> {
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default()); app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
} }
if app
.data
.sonarr_data
.season_details_modal
.as_mut()
.expect("Season details modal is empty")
.episode_details_modal
.is_none()
{
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal = Some(EpisodeDetailsModal::default());
}
let Episode { let Episode {
id, id,
title, title,
@@ -271,10 +207,9 @@ impl Network<'_, '_> {
.sonarr_data .sonarr_data
.season_details_modal .season_details_modal
.as_mut() .as_mut()
.unwrap() .expect("Season details modal is empty")
.episode_details_modal .episode_details_modal
.as_mut() .get_or_insert_default();
.unwrap();
episode_details_modal.episode_details = ScrollableText::with_string(formatdoc!( episode_details_modal.episode_details = ScrollableText::with_string(formatdoc!(
" "
Title: {} Title: {}
@@ -366,42 +301,21 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<SonarrRelease>>(request_props, |release_vec, mut app| { .handle_request::<(), Vec<SonarrRelease>>(request_props, |release_vec, mut app| {
if app.data.sonarr_data.season_details_modal.is_none() { let season_details_modal = app
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default()); .data
} .sonarr_data
.season_details_modal
.get_or_insert_default();
let episode_details_modal = season_details_modal
.episode_details_modal
.get_or_insert_default();
let episode_releases_vec = release_vec let episode_releases_vec = release_vec
.into_iter() .into_iter()
.filter(|release| !release.full_season) .filter(|release| !release.full_season)
.collect(); .collect();
if app episode_details_modal
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal
.is_none()
{
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal = Some(EpisodeDetailsModal::default());
}
app
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.episode_details_modal
.as_mut()
.unwrap()
.episode_releases .episode_releases
.set_items(episode_releases_vec); .set_items(episode_releases_vec);
}) })
@@ -821,8 +821,7 @@ mod tests {
.path("/1") .path("/1")
.build_for(SonarrEvent::GetEpisodeDetails(1)) .build_for(SonarrEvent::GetEpisodeDetails(1))
.await; .await;
let mut episode_details_modal = EpisodeDetailsModal::default(); let episode_details_modal = EpisodeDetailsModal::default();
episode_details_modal.episode_details_tabs.next();
let mut season_details_modal = SeasonDetailsModal::default(); let mut season_details_modal = SeasonDetailsModal::default();
season_details_modal.episodes.set_items(vec![episode()]); season_details_modal.episodes.set_items(vec![episode()]);
season_details_modal.episode_details_modal = Some(episode_details_modal); season_details_modal.episode_details_modal = Some(episode_details_modal);
@@ -868,7 +867,7 @@ mod tests {
.unwrap() .unwrap()
.episode_details_tabs .episode_details_tabs
.get_active_route(), .get_active_route(),
ActiveSonarrBlock::EpisodeHistory.into() ActiveSonarrBlock::EpisodeDetails.into()
); );
assert_eq!(episode, response); assert_eq!(episode, response);
@@ -1,4 +1,5 @@
use crate::models::servarr_data::sonarr::modals::SeasonDetailsModal; use crate::models::Route;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::sonarr_models::{SonarrCommandBody, SonarrHistoryItem, SonarrRelease}; use crate::models::sonarr_models::{SonarrCommandBody, SonarrHistoryItem, SonarrRelease};
use crate::network::sonarr_network::SonarrEvent; use crate::network::sonarr_network::SonarrEvent;
use crate::network::{Network, RequestMethod}; use crate::network::{Network, RequestMethod};
@@ -111,21 +112,18 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<SonarrRelease>>(request_props, |release_vec, mut app| { .handle_request::<(), Vec<SonarrRelease>>(request_props, |release_vec, mut app| {
if app.data.sonarr_data.season_details_modal.is_none() { let season_details_modal = app
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default()); .data
} .sonarr_data
.season_details_modal
.get_or_insert_default();
let season_releases_vec = release_vec let season_releases_vec = release_vec
.into_iter() .into_iter()
.filter(|release| release.full_season) .filter(|release| release.full_season)
.collect(); .collect();
app season_details_modal
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.season_releases .season_releases
.set_items(season_releases_vec); .set_items(season_releases_vec);
}) })
@@ -147,28 +145,25 @@ impl Network<'_, '_> {
self self
.handle_request::<(), Vec<SonarrHistoryItem>>(request_props, |history_items, mut app| { .handle_request::<(), Vec<SonarrHistoryItem>>(request_props, |history_items, mut app| {
if app.data.sonarr_data.season_details_modal.is_none() { let is_sorting = matches!(
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default()); app.get_current_route(),
} Route::Sonarr(ActiveSonarrBlock::SeasonHistorySortPrompt, _)
);
let mut history_vec = history_items; let season_details_modal = app
history_vec.sort_by(|a, b| a.id.cmp(&b.id));
app
.data .data
.sonarr_data .sonarr_data
.season_details_modal .season_details_modal
.as_mut() .get_or_insert_default();
.unwrap()
.season_history if !is_sorting {
.set_items(history_vec); let mut history_vec = history_items;
app history_vec.sort_by(|a, b| a.id.cmp(&b.id));
.data season_details_modal.season_history.set_items(history_vec);
.sonarr_data season_details_modal
.season_details_modal .season_history
.as_mut() .apply_sorting_toggle(false);
.unwrap() }
.season_history
.apply_sorting_toggle(false);
}) })
.await .await
} }
@@ -1,6 +1,7 @@
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::models::servarr_data::sonarr::modals::SeasonDetailsModal; use crate::models::servarr_data::sonarr::modals::SeasonDetailsModal;
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
use crate::models::sonarr_models::{SonarrHistoryItem, SonarrRelease, SonarrSerdeable}; use crate::models::sonarr_models::{SonarrHistoryItem, SonarrRelease, SonarrSerdeable};
use crate::network::NetworkResource; use crate::network::NetworkResource;
use crate::network::network_tests::test_utils::{MockServarrApi, test_network}; use crate::network::network_tests::test_utils::{MockServarrApi, test_network};
@@ -466,6 +467,93 @@ mod tests {
assert_eq!(history, response); assert_eq!(history, response);
} }
#[tokio::test]
async fn test_handle_get_sonarr_season_history_event_no_op_when_user_is_selecting_sort_option() {
let history_json = json!([{
"id": 123,
"sourceTitle": "z episode",
"episodeId": 1007,
"quality": { "quality": { "name": "Bluray-1080p" } },
"languages": [{ "id": 1, "name": "English" }],
"date": "2024-02-10T07:28:45Z",
"eventType": "grabbed",
"data": {
"droppedPath": "/nfs/nzbget/completed/series/Coolness/something.cool.mkv",
"importedPath": "/nfs/tv/Coolness/Season 1/Coolness - S01E01 - Something Cool Bluray-1080p.mkv"
}
},
{
"id": 456,
"sourceTitle": "A Episode",
"episodeId": 2001,
"quality": { "quality": { "name": "Bluray-1080p" } },
"languages": [{ "id": 1, "name": "English" }],
"date": "2024-02-10T07:28:45Z",
"eventType": "grabbed",
"data": {
"droppedPath": "/nfs/nzbget/completed/series/Coolness/something.cool.mkv",
"importedPath": "/nfs/tv/Coolness/Season 1/Coolness - S01E01 - Something Cool Bluray-1080p.mkv"
}
}]);
let response: Vec<SonarrHistoryItem> = serde_json::from_value(history_json.clone()).unwrap();
let (mock, app, _server) = MockServarrApi::get()
.returns(history_json)
.query("seriesId=1&seasonNumber=1")
.build_for(SonarrEvent::GetSeasonHistory((1, 1)))
.await;
app.lock().await.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
app
.lock()
.await
.data
.sonarr_data
.season_details_modal
.as_mut()
.unwrap()
.season_history
.sort_asc = true;
app.lock().await.server_tabs.next();
app
.lock()
.await
.push_navigation_stack(ActiveSonarrBlock::SeasonHistorySortPrompt.into());
let mut network = test_network(&app);
let SonarrSerdeable::SonarrHistoryItems(history) = network
.handle_sonarr_event(SonarrEvent::GetSeasonHistory((1, 1)))
.await
.unwrap()
else {
panic!("Expected SonarrHistoryItems")
};
mock.assert_async().await;
assert_is_empty!(
app
.lock()
.await
.data
.sonarr_data
.season_details_modal
.as_ref()
.unwrap()
.season_history
.items
);
assert!(
app
.lock()
.await
.data
.sonarr_data
.season_details_modal
.as_ref()
.unwrap()
.season_history
.sort_asc
);
assert_eq!(history, response);
}
#[tokio::test] #[tokio::test]
async fn test_handle_trigger_automatic_season_search_event() { async fn test_handle_trigger_automatic_season_search_event() {
let (mock, app, _server) = MockServarrApi::post() let (mock, app, _server) = MockServarrApi::post()