feat(lidarr): add a scrollable overview popup to artist details

An artist's overview renders as one line of a description box that does
not scroll, so a long overview overflows with no way to read the rest.
Pressing v on the artist details Albums tab now opens a popup holding
the full overview.

The popup owns its own ScrollableText, built fresh from the artist's
overview when it opens and torn down on Esc so a reopened popup starts
at the top. Scrolling mutates only that owned state. The background
paragraph renders the Artist record's overview, which carries no scroll
offset, so it cannot scroll along with the popup.

Cite the existing view keybinding from the artist details context clues
and give the popup its own clue set so it does not inherit the hints of
the view underneath.

Enrich the shared artist fixture to a multi-paragraph overview, and the
blocklist response fixtures that embed the same artist, so a scrolled
popup is distinguishable from an unscrolled one.
This commit is contained in:
Dark-Alex-17 committed 2026-09-08 21:05:50 -06:00
1 parent 27c458307f
commit ca04498717
59 files changed
+1521 -134

No files matched your search

+15 -3
View File
@@ -7,8 +7,8 @@ use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::models::Route;
use crate::models::servarr_data::lidarr::lidarr_data::{
ADD_ARTIST_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS,
ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS,
EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS, TRACK_DETAILS_BLOCKS,
ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS,
EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS, INDEXER_SETTINGS_BLOCKS, TRACK_DETAILS_BLOCKS,
};
#[cfg(test)]
@@ -39,7 +39,7 @@ pub static ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
(DEFAULT_KEYBINDINGS.esc, "edit search"),
];
pub static ARTIST_DETAILS_CONTEXT_CLUES: [ContextClue; 8] = [
pub static ARTIST_DETAILS_CONTEXT_CLUES: [ContextClue; 9] = [
(
DEFAULT_KEYBINDINGS.refresh,
DEFAULT_KEYBINDINGS.refresh.desc,
@@ -56,6 +56,15 @@ pub static ARTIST_DETAILS_CONTEXT_CLUES: [ContextClue; 8] = [
DEFAULT_KEYBINDINGS.auto_search,
DEFAULT_KEYBINDINGS.auto_search.desc,
),
(DEFAULT_KEYBINDINGS.view, "view overview"),
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
];
pub static ARTIST_OVERVIEW_CONTEXT_CLUES: [ContextClue; 2] = [
(
DEFAULT_KEYBINDINGS.refresh,
DEFAULT_KEYBINDINGS.refresh.desc,
),
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
];
@@ -172,6 +181,9 @@ impl ContextClueProvider for LidarrContextClueProvider {
.lidarr_data
.artist_info_tabs
.get_active_route_contextual_help(),
_ if ARTIST_OVERVIEW_BLOCKS.contains(&active_lidarr_block) => {
Some(&ARTIST_OVERVIEW_CONTEXT_CLUES)
}
_ if ALBUM_DETAILS_BLOCKS.contains(&active_lidarr_block) => app
.data
.lidarr_data
+35 -2
View File
@@ -9,8 +9,9 @@ mod tests {
use crate::app::lidarr::lidarr_context_clues::{
ADD_ARTIST_SEARCH_RESULTS_CONTEXT_CLUES, ALBUM_DETAILS_CONTEXT_CLUES,
ALBUM_HISTORY_CONTEXT_CLUES, ARTIST_DETAILS_CONTEXT_CLUES, ARTIST_HISTORY_CONTEXT_CLUES,
ARTISTS_CONTEXT_CLUES, LidarrContextClueProvider, MANUAL_ALBUM_SEARCH_CONTEXT_CLUES,
MANUAL_ARTIST_SEARCH_CONTEXT_CLUES, TRACK_DETAILS_CONTEXT_CLUES, TRACK_HISTORY_CONTEXT_CLUES,
ARTIST_OVERVIEW_CONTEXT_CLUES, ARTISTS_CONTEXT_CLUES, LidarrContextClueProvider,
MANUAL_ALBUM_SEARCH_CONTEXT_CLUES, MANUAL_ARTIST_SEARCH_CONTEXT_CLUES,
TRACK_DETAILS_CONTEXT_CLUES, TRACK_HISTORY_CONTEXT_CLUES,
};
use crate::models::servarr_data::lidarr::lidarr_data::{
ADD_ROOT_FOLDER_BLOCKS, ActiveLidarrBlock, EDIT_ARTIST_BLOCKS, EDIT_INDEXER_BLOCKS,
@@ -114,6 +115,10 @@ mod tests {
DEFAULT_KEYBINDINGS.auto_search.desc,
)
);
assert_some_eq_x!(
artist_details_context_clues_iter.next(),
&(DEFAULT_KEYBINDINGS.view, "view overview")
);
assert_some_eq_x!(
artist_details_context_clues_iter.next(),
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
@@ -121,6 +126,24 @@ mod tests {
assert_none!(artist_details_context_clues_iter.next());
}
#[test]
fn test_artist_overview_context_clues() {
let mut artist_overview_context_clues_iter = ARTIST_OVERVIEW_CONTEXT_CLUES.iter();
assert_some_eq_x!(
artist_overview_context_clues_iter.next(),
&(
DEFAULT_KEYBINDINGS.refresh,
DEFAULT_KEYBINDINGS.refresh.desc
)
);
assert_some_eq_x!(
artist_overview_context_clues_iter.next(),
&(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)
);
assert_none!(artist_overview_context_clues_iter.next());
}
#[test]
fn test_add_artist_search_results_context_clues() {
let mut add_artist_search_results_context_clues_iter =
@@ -471,6 +494,16 @@ mod tests {
assert_some_eq_x!(context_clues, expected_context_clues);
}
#[test]
fn test_lidarr_context_clue_provider_artist_overview_block() {
let mut app = App::test_default();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
let context_clues = LidarrContextClueProvider::get_context_clues(&mut app);
assert_some_eq_x!(context_clues, &ARTIST_OVERVIEW_CONTEXT_CLUES);
}
#[test]
fn test_lidarr_context_clue_provider_artists_block() {
let mut app = App::test_default();
@@ -1,3 +1,4 @@
use super::artist_overview_handler::ArtistOverviewHandler;
use crate::app::App;
use crate::event::Key;
use crate::handlers::lidarr_handlers::history::history_sorting_options;
@@ -9,9 +10,10 @@ use crate::models::servarr_data::lidarr::lidarr_data::{
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_SELECTION_BLOCKS,
EDIT_ARTIST_SELECTION_BLOCKS,
};
use crate::models::servarr_data::lidarr::modals::ArtistOverviewModal;
use crate::models::servarr_models::ReleaseDownloadBody;
use crate::models::stateful_table::SortOption;
use crate::models::{BlockSelectionState, Route};
use crate::models::{BlockSelectionState, Route, ScrollableText};
use crate::network::lidarr_network::LidarrEvent;
use serde_json::Number;
@@ -34,10 +36,36 @@ impl ArtistDetailsHandler<'_, '_> {
fn extract_album_id(&self) -> i64 {
self.app.data.lidarr_data.albums.current_selection().id
}
fn build_artist_overview_modal(&mut self) {
let overview = self
.app
.data
.lidarr_data
.artists
.current_selection()
.overview
.clone()
.unwrap_or_default();
self.app.data.lidarr_data.artist_overview_modal = Some(ArtistOverviewModal {
overview: ScrollableText::with_string(overview),
});
}
}
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler<'a, 'b> {
fn handle(&mut self) {
if ArtistOverviewHandler::accepts(self.active_lidarr_block) {
return ArtistOverviewHandler::new(
self.key,
self.app,
self.active_lidarr_block,
self._context,
)
.handle();
}
let albums_table_handling_config =
TableHandlingConfig::new(ActiveLidarrBlock::ArtistDetails.into())
.searching_block(ActiveLidarrBlock::SearchAlbums.into())
@@ -78,7 +106,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
}
fn accepts(active_block: ActiveLidarrBlock) -> bool {
ARTIST_DETAILS_BLOCKS.contains(&active_block)
ArtistOverviewHandler::accepts(active_block) || ARTIST_DETAILS_BLOCKS.contains(&active_block)
}
fn ignore_special_keys(&self) -> bool {
@@ -292,6 +320,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistDetailsHandler
self.app.data.lidarr_data.selected_block =
BlockSelectionState::new(EDIT_ARTIST_SELECTION_BLOCKS);
}
_ if matches_key!(view, key) => {
self.build_artist_overview_modal();
self
.app
.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
}
_ if matches_key!(toggle_monitoring, key)
&& !self.app.data.lidarr_data.albums.is_empty() =>
{
@@ -15,9 +15,10 @@ mod tests {
use crate::models::HorizontallyScrollableText;
use crate::models::lidarr_models::{LidarrHistoryItem, LidarrRelease};
use crate::models::servarr_data::lidarr::lidarr_data::{
ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock,
};
use crate::models::servarr_models::{Quality, QualityWrapper};
use crate::test_handler_delegation;
mod test_handle_delete {
use super::*;
@@ -450,6 +451,7 @@ mod tests {
use crate::assert_navigation_pushed;
use crate::handlers::KeyEventHandler;
use crate::handlers::lidarr_handlers::library::artist_details_handler::ArtistDetailsHandler;
use crate::handlers::lidarr_handlers::library::artist_overview_handler::ArtistOverviewHandler;
use crate::models::lidarr_models::Artist;
use crate::models::servarr_data::lidarr::lidarr_data::{
ActiveLidarrBlock, EDIT_ARTIST_SELECTION_BLOCKS,
@@ -458,7 +460,7 @@ mod tests {
use crate::network::lidarr_network::LidarrEvent;
use crate::network::lidarr_network::lidarr_network_test_utils::test_utils::torrent_release;
use crate::{assert_modal_absent, assert_modal_present, assert_navigation_popped};
use pretty_assertions::assert_eq;
use pretty_assertions::{assert_eq, assert_str_eq};
use rstest::rstest;
#[rstest]
@@ -524,6 +526,161 @@ mod tests {
assert_modal_absent!(app.data.lidarr_data.edit_artist_modal);
}
#[test]
fn test_artist_details_view_key_opens_the_artist_overview() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = None;
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
assert_navigation_pushed!(app, ActiveLidarrBlock::ArtistOverview.into());
assert_modal_present!(app.data.lidarr_data.artist_overview_modal);
}
#[test]
fn test_artist_details_view_key_builds_the_overview_from_the_selected_artist() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = None;
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
let overview = &app
.data
.lidarr_data
.artist_overview_modal
.as_ref()
.unwrap()
.overview;
assert_eq!(overview.offset, 0);
assert_eq!(
overview.get_text(),
app
.data
.lidarr_data
.artists
.current_selection()
.overview
.clone()
.unwrap()
);
}
#[test]
fn test_artist_details_view_key_for_an_artist_with_no_overview() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = None;
let mut artist = app.data.lidarr_data.artists.current_selection().clone();
artist.overview = None;
app.data.lidarr_data.artists.set_items(vec![artist]);
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
assert_navigation_pushed!(app, ActiveLidarrBlock::ArtistOverview.into());
assert_str_eq!(
app
.data
.lidarr_data
.artist_overview_modal
.as_ref()
.unwrap()
.overview
.get_text(),
""
);
}
#[test]
fn test_artist_details_view_key_reopens_the_artist_overview_at_the_top() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = None;
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.end.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
assert_navigation_pushed!(app, ActiveLidarrBlock::ArtistOverview.into());
assert_eq!(
app
.data
.lidarr_data
.artist_overview_modal
.as_ref()
.unwrap()
.overview
.offset,
0
);
}
#[test]
fn test_artist_details_view_key_no_op_when_not_ready() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = None;
app.is_loading = true;
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
ArtistDetailsHandler::new(
DEFAULT_KEYBINDINGS.view.key,
&mut app,
ActiveLidarrBlock::ArtistDetails,
None,
)
.handle();
assert_eq!(
app.get_current_route(),
ActiveLidarrBlock::ArtistDetails.into()
);
assert_modal_absent!(app.data.lidarr_data.artist_overview_modal);
}
#[test]
fn test_artist_details_toggle_monitoring_key() {
let mut app = App::test_default_fully_populated();
@@ -813,8 +970,11 @@ mod tests {
#[test]
fn test_artist_details_handler_accepts() {
let mut artist_details_blocks = ARTIST_DETAILS_BLOCKS.to_vec();
artist_details_blocks.extend(ARTIST_OVERVIEW_BLOCKS);
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
if ARTIST_DETAILS_BLOCKS.contains(&active_lidarr_block) {
if artist_details_blocks.contains(&active_lidarr_block) {
assert!(ArtistDetailsHandler::accepts(active_lidarr_block));
} else {
assert!(!ArtistDetailsHandler::accepts(active_lidarr_block));
@@ -822,6 +982,15 @@ mod tests {
});
}
#[test]
fn test_delegates_artist_overview_blocks_to_artist_overview_handler() {
test_handler_delegation!(
ArtistDetailsHandler,
ActiveLidarrBlock::ArtistDetails,
ActiveLidarrBlock::ArtistOverview
);
}
#[test]
fn test_extract_artist_id() {
let mut app = App::test_default_fully_populated();
@@ -0,0 +1,109 @@
use crate::app::App;
use crate::event::Key;
use crate::handlers::KeyEventHandler;
use crate::matches_key;
use crate::models::servarr_data::lidarr::lidarr_data::{ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock};
use crate::models::{Route, Scrollable, ScrollableText};
#[cfg(test)]
#[path = "artist_overview_handler_tests.rs"]
mod artist_overview_handler_tests;
pub(super) struct ArtistOverviewHandler<'a, 'b> {
key: Key,
app: &'a mut App<'b>,
active_lidarr_block: ActiveLidarrBlock,
_context: Option<ActiveLidarrBlock>,
}
impl ArtistOverviewHandler<'_, '_> {
fn overview(&mut self) -> &mut ScrollableText {
&mut self
.app
.data
.lidarr_data
.artist_overview_modal
.as_mut()
.expect("Artist overview modal is undefined")
.overview
}
}
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveLidarrBlock> for ArtistOverviewHandler<'a, 'b> {
fn accepts(active_block: ActiveLidarrBlock) -> bool {
ARTIST_OVERVIEW_BLOCKS.contains(&active_block)
}
fn ignore_special_keys(&self) -> bool {
self.app.ignore_special_keys_for_textbox_input
}
fn new(
key: Key,
app: &'a mut App<'b>,
active_block: ActiveLidarrBlock,
_context: Option<ActiveLidarrBlock>,
) -> ArtistOverviewHandler<'a, 'b> {
ArtistOverviewHandler {
key,
app,
active_lidarr_block: active_block,
_context,
}
}
fn get_key(&self) -> Key {
self.key
}
fn is_ready(&self) -> bool {
if self.app.is_loading {
return false;
}
self.app.data.lidarr_data.artist_overview_modal.is_some()
}
fn handle_scroll_up(&mut self) {
self.overview().scroll_up();
}
fn handle_scroll_down(&mut self) {
self.overview().scroll_down();
}
fn handle_home(&mut self) {
self.overview().scroll_to_top();
}
fn handle_end(&mut self) {
self.overview().scroll_to_bottom();
}
fn handle_delete(&mut self) {}
fn handle_left_right_action(&mut self) {}
fn handle_submit(&mut self) {}
fn handle_esc(&mut self) {
self.app.pop_navigation_stack();
self.app.data.lidarr_data.artist_overview_modal = None;
}
fn handle_char_key_event(&mut self) {
if matches_key!(refresh, self.key) {
self
.app
.pop_and_push_navigation_stack(self.active_lidarr_block.into());
}
}
fn app_mut(&mut self) -> &mut App<'b> {
self.app
}
fn current_route(&self) -> Route {
self.app.get_current_route()
}
}
@@ -0,0 +1,393 @@
#[cfg(test)]
mod tests {
use strum::IntoEnumIterator;
use crate::app::App;
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
use crate::handlers::KeyEventHandler;
use crate::handlers::lidarr_handlers::library::artist_overview_handler::ArtistOverviewHandler;
use crate::models::ScrollableText;
use crate::models::servarr_data::lidarr::lidarr_data::{
ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock,
};
use crate::models::servarr_data::lidarr::modals::ArtistOverviewModal;
mod test_handle_scroll_up_and_down {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_artist_overview_scroll_up() {
let mut app = app_with_artist_overview();
set_offset(&mut app, 2);
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 1);
}
#[test]
fn test_artist_overview_scroll_up_no_op_when_not_ready() {
let mut app = app_with_artist_overview();
set_offset(&mut app, 2);
app.is_loading = true;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 2);
}
#[test]
fn test_artist_overview_scroll_down() {
let mut app = app_with_artist_overview();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.down.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 1);
}
#[test]
fn test_artist_overview_scroll_down_no_op_when_not_ready() {
let mut app = app_with_artist_overview();
app.is_loading = true;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.down.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 0);
}
}
mod test_handle_home_end {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_artist_overview_home() {
let mut app = app_with_artist_overview();
set_offset(&mut app, 3);
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.home.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 0);
}
#[test]
fn test_artist_overview_end() {
let mut app = app_with_artist_overview();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.end.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 5);
}
#[test]
fn test_artist_overview_home_no_op_when_not_ready() {
let mut app = app_with_artist_overview();
set_offset(&mut app, 3);
app.is_loading = true;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.home.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 3);
}
#[test]
fn test_artist_overview_end_no_op_when_not_ready() {
let mut app = app_with_artist_overview();
app.is_loading = true;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.end.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 0);
}
}
mod test_handle_esc {
use super::*;
use crate::{assert_modal_absent, assert_navigation_popped};
#[test]
fn test_artist_overview_esc_tears_down_the_artist_overview_modal() {
let mut app = app_with_artist_overview();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
assert_modal_absent!(app.data.lidarr_data.artist_overview_modal);
}
#[test]
fn test_artist_overview_esc_tears_down_the_modal_even_when_loading() {
let mut app = app_with_artist_overview();
app.is_loading = true;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.esc.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_navigation_popped!(app, ActiveLidarrBlock::ArtistDetails.into());
assert_modal_absent!(app.data.lidarr_data.artist_overview_modal);
}
}
mod test_handle_key_char {
use super::*;
use crate::assert_navigation_pushed;
#[test]
fn test_artist_overview_refresh_key() {
let mut app = app_with_artist_overview();
app.is_routing = false;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.refresh.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_navigation_pushed!(app, ActiveLidarrBlock::ArtistOverview.into());
assert!(app.is_routing);
}
#[test]
fn test_artist_overview_refresh_key_no_op_when_not_ready() {
let mut app = app_with_artist_overview();
app.is_loading = true;
app.is_routing = false;
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.refresh.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert!(!app.is_routing);
}
}
#[test]
fn test_scrolling_the_overview_does_not_mutate_the_artist_record() {
let mut app = app_with_artist_overview();
let overview_before = app
.data
.lidarr_data
.artists
.current_selection()
.overview
.clone();
ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.down.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
)
.handle();
assert_eq!(overview_offset(&app), 1);
assert_eq!(
app.data.lidarr_data.artists.current_selection().overview,
overview_before
);
}
#[test]
fn test_artist_overview_handler_accepts() {
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
if ARTIST_OVERVIEW_BLOCKS.contains(&active_lidarr_block) {
assert!(
ArtistOverviewHandler::accepts(active_lidarr_block),
"{active_lidarr_block} is not accepted by the ArtistOverviewHandler"
);
} else {
assert!(
!ArtistOverviewHandler::accepts(active_lidarr_block),
"{active_lidarr_block} is wrongly accepted by the ArtistOverviewHandler"
);
}
});
}
#[test]
fn test_artist_overview_handler_dispatches_no_network_events() {
let mut app = app_with_artist_overview();
for key in [
DEFAULT_KEYBINDINGS.up.key,
DEFAULT_KEYBINDINGS.down.key,
DEFAULT_KEYBINDINGS.home.key,
DEFAULT_KEYBINDINGS.end.key,
DEFAULT_KEYBINDINGS.delete.key,
DEFAULT_KEYBINDINGS.left.key,
DEFAULT_KEYBINDINGS.right.key,
DEFAULT_KEYBINDINGS.submit.key,
DEFAULT_KEYBINDINGS.refresh.key,
] {
ArtistOverviewHandler::new(key, &mut app, ActiveLidarrBlock::ArtistOverview, None).handle();
assert_none!(app.data.lidarr_data.prompt_confirm_action);
assert!(!app.data.lidarr_data.prompt_confirm);
}
}
#[test]
fn test_artist_overview_handler_is_not_ready_when_loading() {
let mut app = app_with_artist_overview();
app.is_loading = true;
let handler = ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
);
assert!(!handler.is_ready());
}
#[test]
fn test_artist_overview_handler_is_not_ready_when_the_modal_is_absent() {
let mut app = app_with_artist_overview();
app.data.lidarr_data.artist_overview_modal = None;
let handler = ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
);
assert!(!handler.is_ready());
}
#[test]
fn test_artist_overview_handler_is_ready() {
let mut app = app_with_artist_overview();
let handler = ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
);
assert!(handler.is_ready());
}
#[test]
fn test_artist_overview_handler_ignores_special_keys_for_textbox_input() {
let mut app = app_with_artist_overview();
app.ignore_special_keys_for_textbox_input = true;
let handler = ArtistOverviewHandler::new(
DEFAULT_KEYBINDINGS.up.key,
&mut app,
ActiveLidarrBlock::ArtistOverview,
None,
);
assert!(handler.ignore_special_keys());
}
fn app_with_artist_overview() -> App<'static> {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artist_overview_modal = Some(ArtistOverviewModal {
overview: ScrollableText::with_string(
"some interesting description of the artist\r\n\
\r\n\
She was born in Madison, Wisconsin: a city she has never really left.\r\n\
\r\n\
Her first album took her seven years to finish.\r\n"
.to_owned(),
),
});
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
app
}
fn overview_offset(app: &App<'_>) -> u16 {
app
.data
.lidarr_data
.artist_overview_modal
.as_ref()
.unwrap()
.overview
.offset
}
fn set_offset(app: &mut App<'_>, offset: u16) {
app
.data
.lidarr_data
.artist_overview_modal
.as_mut()
.unwrap()
.overview
.offset = offset;
}
}
@@ -13,9 +13,9 @@ mod tests {
use crate::handlers::lidarr_handlers::library::{LibraryHandler, artists_sorting_options};
use crate::models::lidarr_models::{Album, Artist, ArtistStatistics, ArtistStatus};
use crate::models::servarr_data::lidarr::lidarr_data::{
ADD_ARTIST_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS,
LIBRARY_BLOCKS, TRACK_DETAILS_BLOCKS,
ADD_ARTIST_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS,
ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS,
EDIT_ARTIST_SELECTION_BLOCKS, LIBRARY_BLOCKS, TRACK_DETAILS_BLOCKS,
};
use crate::models::servarr_data::lidarr::modals::EditArtistModal;
use crate::network::lidarr_network::LidarrEvent;
@@ -29,6 +29,7 @@ mod tests {
let mut library_handler_blocks = Vec::new();
library_handler_blocks.extend(LIBRARY_BLOCKS);
library_handler_blocks.extend(ARTIST_DETAILS_BLOCKS);
library_handler_blocks.extend(ARTIST_OVERVIEW_BLOCKS);
library_handler_blocks.extend(DELETE_ARTIST_BLOCKS);
library_handler_blocks.extend(DELETE_ALBUM_BLOCKS);
library_handler_blocks.extend(EDIT_ARTIST_BLOCKS);
@@ -21,6 +21,7 @@ use crate::handlers::table_handler::{TableHandlingConfig, handle_table};
mod add_artist_handler;
mod album_details_handler;
mod artist_details_handler;
mod artist_overview_handler;
mod delete_album_handler;
mod delete_artist_handler;
mod edit_artist_handler;
+13 -1
View File
@@ -1,6 +1,8 @@
use serde_json::Number;
use super::modals::{AddArtistModal, AddRootFolderModal, AlbumDetailsModal, EditArtistModal};
use super::modals::{
AddArtistModal, AddRootFolderModal, AlbumDetailsModal, ArtistOverviewModal, EditArtistModal,
};
use crate::app::context_clues::{
BLOCKLIST_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES,
ROOT_FOLDERS_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
@@ -64,6 +66,7 @@ pub struct LidarrData<'a> {
pub album_details_modal: Option<AlbumDetailsModal>,
pub artist_history: StatefulTable<LidarrHistoryItem>,
pub artist_info_tabs: TabState,
pub artist_overview_modal: Option<ArtistOverviewModal>,
pub artists: StatefulTable<Artist>,
pub blocklist: StatefulTable<BlocklistItem>,
pub delete_files: bool,
@@ -150,6 +153,7 @@ impl<'a> Default for LidarrData<'a> {
albums: StatefulTable::default(),
album_details_modal: None,
artist_history: StatefulTable::default(),
artist_overview_modal: None,
artists: StatefulTable::default(),
blocklist: StatefulTable::default(),
delete_files: false,
@@ -354,8 +358,13 @@ impl LidarrData<'_> {
let mut indexer_test_all_results = StatefulTable::default();
indexer_test_all_results.set_items(vec![indexer_test_result()]);
let artist_overview_modal = ArtistOverviewModal {
overview: ScrollableText::with_string(artist().overview.unwrap_or_default()),
};
let mut lidarr_data = LidarrData {
album_details_modal: Some(album_details_modal),
artist_overview_modal: Some(artist_overview_modal),
delete_files: true,
disk_space_vec: vec![diskspace()],
quality_profile_map: quality_profile_map(),
@@ -428,6 +437,7 @@ pub enum ActiveLidarrBlock {
ArtistHistory,
ArtistHistoryDetails,
ArtistHistorySortPrompt,
ArtistOverview,
ArtistsSortPrompt,
AddArtistAlreadyInLibrary,
AddArtistConfirmPrompt,
@@ -579,6 +589,8 @@ pub static ARTIST_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
ActiveLidarrBlock::UpdateAndScanArtistPrompt,
];
pub static ARTIST_OVERVIEW_BLOCKS: [ActiveLidarrBlock; 1] = [ActiveLidarrBlock::ArtistOverview];
pub static ALBUM_DETAILS_BLOCKS: [ActiveLidarrBlock; 15] = [
ActiveLidarrBlock::AlbumDetails,
ActiveLidarrBlock::AlbumHistory,
@@ -11,12 +11,12 @@ mod tests {
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
use crate::models::servarr_data::lidarr::lidarr_data::{
ADD_ARTIST_BLOCKS, ADD_ARTIST_SELECTION_BLOCKS, ADD_ROOT_FOLDER_BLOCKS, ALBUM_DETAILS_BLOCKS,
ARTIST_DETAILS_BLOCKS, BLOCKLIST_BLOCKS, DELETE_ALBUM_BLOCKS, DELETE_ALBUM_SELECTION_BLOCKS,
DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS, DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS,
EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS, EDIT_INDEXER_NZB_SELECTION_BLOCKS,
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS, INDEXER_SETTINGS_BLOCKS,
INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS, ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS,
TRACK_DETAILS_BLOCKS,
ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS, BLOCKLIST_BLOCKS, DELETE_ALBUM_BLOCKS,
DELETE_ALBUM_SELECTION_BLOCKS, DELETE_ARTIST_BLOCKS, DELETE_ARTIST_SELECTION_BLOCKS,
DOWNLOADS_BLOCKS, EDIT_ARTIST_BLOCKS, EDIT_ARTIST_SELECTION_BLOCKS, EDIT_INDEXER_BLOCKS,
EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS, HISTORY_BLOCKS,
INDEXER_SETTINGS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS, INDEXERS_BLOCKS,
ROOT_FOLDERS_BLOCKS, SYSTEM_DETAILS_BLOCKS, TRACK_DETAILS_BLOCKS,
};
use crate::models::{
BlockSelectionState, Route,
@@ -149,6 +149,7 @@ mod tests {
assert_none!(lidarr_data.album_details_modal);
assert_is_empty!(lidarr_data.artists);
assert_is_empty!(lidarr_data.artist_history);
assert_none!(lidarr_data.artist_overview_modal);
assert_is_empty!(lidarr_data.blocklist);
assert!(!lidarr_data.delete_files);
assert_is_empty!(lidarr_data.disk_space_vec);
@@ -318,6 +319,17 @@ mod tests {
assert!(ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::UpdateAndScanArtistPrompt));
}
#[test]
fn test_artist_details_blocks_excludes_artist_overview() {
assert!(!ARTIST_DETAILS_BLOCKS.contains(&ActiveLidarrBlock::ArtistOverview));
}
#[test]
fn test_artist_overview_blocks_contents() {
assert_eq!(ARTIST_OVERVIEW_BLOCKS.len(), 1);
assert!(ARTIST_OVERVIEW_BLOCKS.contains(&ActiveLidarrBlock::ArtistOverview));
}
#[test]
fn test_album_details_blocks_contents() {
assert_eq!(ALBUM_DETAILS_BLOCKS.len(), 15);
+6
View File
@@ -294,3 +294,9 @@ impl Default for TrackDetailsModal {
}
}
}
#[derive(Default)]
#[cfg_attr(test, derive(Debug))]
pub struct ArtistOverviewModal {
pub overview: ScrollableText,
}
@@ -7,7 +7,7 @@ mod tests {
use crate::models::lidarr_models::{Artist, MonitorType, NewItemMonitorType};
use crate::models::servarr_data::lidarr::lidarr_data::{ActiveLidarrBlock, LidarrData};
use crate::models::servarr_data::lidarr::modals::{
AddArtistModal, AlbumDetailsModal, EditArtistModal, TrackDetailsModal,
AddArtistModal, AlbumDetailsModal, ArtistOverviewModal, EditArtistModal, TrackDetailsModal,
};
use crate::models::servarr_data::modals::EditIndexerModal;
use crate::models::servarr_models::{Indexer, IndexerField, RootFolder};
@@ -307,4 +307,11 @@ mod tests {
);
assert_eq!(track_details_modal.track_details_tabs.tabs[1].config, None);
}
#[test]
fn test_artist_overview_modal_default() {
let artist_overview_modal = ArtistOverviewModal::default();
assert_is_empty!(artist_overview_modal.overview);
}
}
@@ -97,7 +97,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -136,7 +136,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -248,7 +248,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -286,7 +286,7 @@ mod tests {
"artistName": "Alex",
"foreignArtistId": "test-foreign-id",
"status": "continuing",
"overview": "some interesting description of the artist",
"overview": "some interesting description of the artist\r\n\r\nShe was born in Madison, Wisconsin: a city she has never really left.\r\n\r\nHer first album took her seven years to finish.\r\n",
"artistType": "Person",
"disambiguation": "American pianist",
"path": "/nfs/music/test-artist",
@@ -110,7 +110,14 @@ pub mod test_utils {
artist_name: "Alex".into(),
foreign_artist_id: "test-foreign-id".to_owned(),
status: ArtistStatus::Continuing,
overview: Some("some interesting description of the artist".to_owned()),
overview: Some(
"some interesting description of the artist\r\n\
\r\n\
She was born in Madison, Wisconsin: a city she has never really left.\r\n\
\r\n\
Her first album took her seven years to finish.\r\n"
.to_owned(),
),
artist_type: Some("Person".to_owned()),
disambiguation: Some("American pianist".to_owned()),
members: Some(vec![member()]),
@@ -12,6 +12,7 @@ use crate::models::Route;
use crate::models::lidarr_models::{Album, LidarrHistoryItem, LidarrRelease};
use crate::models::servarr_data::lidarr::lidarr_data::{ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock};
use crate::ui::lidarr_ui::library::album_details_ui::AlbumDetailsUi;
use crate::ui::lidarr_ui::library::artist_overview_ui::ArtistOverviewUi;
use crate::ui::lidarr_ui::library::delete_album_ui::DeleteAlbumUi;
use crate::ui::lidarr_ui::lidarr_ui_utils::create_history_event_details;
use crate::ui::styles::{ManagarrStyle, secondary_style};
@@ -43,6 +44,7 @@ impl DrawUi for ArtistDetailsUi {
};
AlbumDetailsUi::accepts(route)
|| DeleteAlbumUi::accepts(route)
|| ArtistOverviewUi::accepts(route)
|| ARTIST_DETAILS_BLOCKS.contains(&active_lidarr_block)
}
@@ -122,6 +124,10 @@ impl DrawUi for ArtistDetailsUi {
if AlbumDetailsUi::accepts(route) {
AlbumDetailsUi::draw(f, app, area);
}
if ArtistOverviewUi::accepts(route) {
ArtistOverviewUi::draw(f, app, area);
}
}
}
}
@@ -3,8 +3,8 @@ mod tests {
use strum::IntoEnumIterator;
use crate::models::servarr_data::lidarr::lidarr_data::{
ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock, DELETE_ALBUM_BLOCKS,
TRACK_DETAILS_BLOCKS,
ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock,
DELETE_ALBUM_BLOCKS, TRACK_DETAILS_BLOCKS,
};
use crate::ui::DrawUi;
use crate::ui::lidarr_ui::library::artist_details_ui::ArtistDetailsUi;
@@ -15,6 +15,7 @@ mod tests {
blocks.extend(DELETE_ALBUM_BLOCKS);
blocks.extend(ALBUM_DETAILS_BLOCKS);
blocks.extend(TRACK_DETAILS_BLOCKS);
blocks.extend(ARTIST_OVERVIEW_BLOCKS);
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
if blocks.contains(&active_lidarr_block) {
@@ -26,6 +27,7 @@ mod tests {
}
mod snapshot_tests {
use pretty_assertions::assert_str_eq;
use rstest::rstest;
use crate::app::App;
@@ -138,6 +140,46 @@ mod tests {
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_details_ui_renders_artist_overview_over_artist_details() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistDetailsUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_scrolling_the_artist_overview_does_not_scroll_the_artist_details_background() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistDetails.into());
let before = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistDetailsUi::draw(f, app, f.area());
});
app
.data
.lidarr_data
.artist_overview_modal
.as_mut()
.unwrap()
.overview
.offset = 3;
let after = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistDetailsUi::draw(f, app, f.area());
});
assert_str_eq!(before, after);
assert_contains!(
before,
"Overview: some interesting description of the artist"
);
}
#[test]
fn test_artist_details_ui_renders_update_and_scan_prompt_over_artist_details() {
let mut app = App::test_default_fully_populated();
@@ -0,0 +1,87 @@
use crate::app::App;
use crate::models::Route;
use crate::models::lidarr_models::Artist;
use crate::models::servarr_data::lidarr::lidarr_data::ARTIST_OVERVIEW_BLOCKS;
use crate::ui::styles::{primary_style, unmonitored_style};
use crate::ui::utils::title_block_centered;
use crate::ui::widgets::loading_block::LoadingBlock;
use crate::ui::widgets::popup::Size;
use crate::ui::{DrawUi, draw_popup};
use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::text::{Line, Span, Text};
use ratatui::widgets::{Paragraph, Wrap};
#[cfg(test)]
#[path = "artist_overview_ui_tests.rs"]
mod artist_overview_ui_tests;
pub(super) struct ArtistOverviewUi;
impl DrawUi for ArtistOverviewUi {
fn accepts(route: Route) -> bool {
let Route::Lidarr(active_lidarr_block, _) = route else {
return false;
};
ARTIST_OVERVIEW_BLOCKS.contains(&active_lidarr_block)
}
fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) {
if app.data.lidarr_data.artist_overview_modal.is_some() {
let draw_artist_overview_popup = |f: &mut Frame<'_>, app: &mut App<'_>, popup_area: Rect| {
draw_artist_overview(f, app, popup_area);
};
draw_popup(f, app, draw_artist_overview_popup, Size::Large);
}
}
}
fn draw_artist_overview(f: &mut Frame<'_>, app: &App<'_>, area: Rect) {
let block = title_block_centered("Overview");
match app.data.lidarr_data.artist_overview_modal.as_ref() {
Some(artist_overview_modal) if !app.is_loading => {
let style = if app.data.lidarr_data.artists.is_empty() {
primary_style()
} else {
style_from_artist(app.data.lidarr_data.artists.current_selection())
};
let overview = &artist_overview_modal.overview;
let text = Text::from(
overview
.items
.iter()
.map(|line| overview_line(line, style))
.collect::<Vec<Line<'static>>>(),
);
let paragraph = Paragraph::new(text)
.block(block)
.wrap(Wrap { trim: false })
.scroll((overview.offset, 0));
f.render_widget(paragraph, area);
}
_ => f.render_widget(
LoadingBlock::new(
app.is_loading || app.data.lidarr_data.artist_overview_modal.is_none(),
block,
),
area,
),
}
}
fn style_from_artist(artist: &Artist) -> Style {
if !artist.monitored {
return unmonitored_style();
}
primary_style()
}
fn overview_line(line: &str, style: Style) -> Line<'static> {
Line::from(Span::styled(line.trim_end().to_owned(), style))
}
@@ -0,0 +1,205 @@
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use ratatui::style::Modifier;
use ratatui::text::Line;
use strum::IntoEnumIterator;
use crate::app::App;
use crate::models::lidarr_models::Artist;
use crate::models::servarr_data::lidarr::lidarr_data::{
ARTIST_OVERVIEW_BLOCKS, ActiveLidarrBlock,
};
use crate::ui::DrawUi;
use crate::ui::lidarr_ui::library::artist_overview_ui::{
ArtistOverviewUi, overview_line, style_from_artist,
};
use crate::ui::styles::{primary_style, unmonitored_style};
use crate::ui::ui_test_utils::test_utils::render_to_string_with_app;
#[test]
fn test_artist_overview_ui_accepts() {
ActiveLidarrBlock::iter().for_each(|active_lidarr_block| {
if ARTIST_OVERVIEW_BLOCKS.contains(&active_lidarr_block) {
assert!(ArtistOverviewUi::accepts(active_lidarr_block.into()));
} else {
assert!(!ArtistOverviewUi::accepts(active_lidarr_block.into()));
}
});
}
#[test]
fn test_style_from_artist_monitored() {
let artist = Artist {
monitored: true,
..Artist::default()
};
let style = style_from_artist(&artist);
assert_eq!(style, primary_style());
}
#[test]
fn test_style_from_artist_unmonitored() {
let artist = Artist {
monitored: false,
..Artist::default()
};
let style = style_from_artist(&artist);
assert_eq!(style, unmonitored_style());
}
#[test]
fn test_overview_line_does_not_split_a_label_from_a_colon_in_the_prose() {
let line = overview_line(
"She was born in Madison, Wisconsin: a city she has never really left.",
primary_style(),
);
assert_eq!(
span_contents(&line),
vec!["She was born in Madison, Wisconsin: a city she has never really left."]
);
}
#[test]
fn test_overview_line_renders_the_prose_without_bolding_it() {
let line = overview_line("Overview: a prose line", primary_style());
assert_eq!(line.spans.len(), 1);
assert!(!line.spans[0].style.add_modifier.contains(Modifier::BOLD));
}
#[test]
fn test_overview_line_applies_the_given_style() {
let line = overview_line("an unmonitored artist", unmonitored_style());
assert_eq!(line.spans[0].style.fg, unmonitored_style().fg);
}
#[test]
fn test_overview_line_trims_a_trailing_carriage_return() {
let line = overview_line(
"Her first album took her seven years to finish.\r",
primary_style(),
);
assert_eq!(
span_contents(&line),
vec!["Her first album took her seven years to finish."]
);
}
#[test]
fn test_overview_line_renders_a_carriage_return_only_line_as_blank() {
let line = overview_line("\r", primary_style());
assert_eq!(span_contents(&line), vec![""]);
}
fn span_contents(line: &Line<'_>) -> Vec<String> {
line
.spans
.iter()
.map(|span| span.content.to_string())
.collect()
}
mod snapshot_tests {
use crate::models::ScrollableText;
use crate::models::servarr_data::lidarr::modals::ArtistOverviewModal;
use crate::models::stateful_table::StatefulTable;
use crate::ui::ui_test_utils::test_utils::TerminalSize;
use super::*;
#[test]
fn test_artist_overview_ui_renders() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_overview_ui_renders_loading() {
let mut app = App::test_default_fully_populated();
app.is_loading = true;
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_overview_ui_renders_scrolled() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
app
.data
.lidarr_data
.artist_overview_modal
.as_mut()
.unwrap()
.overview
.offset = 2;
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_overview_ui_renders_an_artist_with_no_overview() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
app.data.lidarr_data.artist_overview_modal = Some(ArtistOverviewModal {
overview: ScrollableText::with_string(String::new()),
});
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_overview_ui_renders_nothing_when_the_artist_overview_modal_is_undefined() {
let mut app = App::test_default_fully_populated();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
app.data.lidarr_data.artist_overview_modal = None;
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
insta::assert_snapshot!(output);
}
#[test]
fn test_artist_overview_ui_renders_with_zero_artists() {
let mut app = App::test_default_fully_populated();
app.data.lidarr_data.artists = StatefulTable::default();
app.push_navigation_stack(ActiveLidarrBlock::ArtistOverview.into());
let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| {
ArtistOverviewUi::draw(f, app, f.area());
});
assert_contains!(output, "some interesting description of the artist");
}
}
}
+4 -3
View File
@@ -4,9 +4,9 @@ mod tests {
use crate::models::lidarr_models::{Artist, ArtistStatistics, ArtistStatus};
use crate::models::servarr_data::lidarr::lidarr_data::{
ADD_ARTIST_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ActiveLidarrBlock,
DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS, LIBRARY_BLOCKS,
TRACK_DETAILS_BLOCKS,
ADD_ARTIST_BLOCKS, ALBUM_DETAILS_BLOCKS, ARTIST_DETAILS_BLOCKS, ARTIST_OVERVIEW_BLOCKS,
ActiveLidarrBlock, DELETE_ALBUM_BLOCKS, DELETE_ARTIST_BLOCKS, EDIT_ARTIST_BLOCKS,
LIBRARY_BLOCKS, TRACK_DETAILS_BLOCKS,
};
use crate::ui::DrawUi;
use crate::ui::lidarr_ui::library::{LibraryUi, decorate_artist_row_with_style};
@@ -23,6 +23,7 @@ mod tests {
library_ui_blocks.extend(EDIT_ARTIST_BLOCKS);
library_ui_blocks.extend(ADD_ARTIST_BLOCKS);
library_ui_blocks.extend(ARTIST_DETAILS_BLOCKS);
library_ui_blocks.extend(ARTIST_OVERVIEW_BLOCKS);
library_ui_blocks.extend(ALBUM_DETAILS_BLOCKS);
library_ui_blocks.extend(TRACK_DETAILS_BLOCKS);
+1
View File
@@ -31,6 +31,7 @@ use crate::{
mod add_artist_ui;
mod album_details_ui;
mod artist_details_ui;
mod artist_overview_ui;
mod delete_album_ui;
mod delete_artist_ui;
mod edit_artist_ui;
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭─────────────────────────────────── Details ───────────────────────────────────╮ │
│Size on Disk: 0.00 GB │Source Title: Test source title │ │
│Albums: 1 ╭─────────────────────────────────── Details ───────────────────────────────────╮ │
│Tracks: 15/15 │Source Title: Test source title │ │
│╭ Artist Details ─────────────│Event Type: grabbed │───────────────────────────────╮│
││ Albums │ History │ Manual Sear│Quality: Lossless │ ││
││───────────────────────────────│Date: 2023-01-01 00:00:00 UTC │───────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Size on Disk: 0.00 GB │Do you want to trigger an automatic search of your indexers│ │
│Albums: 1 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Tracks: 15/15 │Do you want to trigger an automatic search of your indexers│ │
│╭ Artist Details ───────────────────────│ for all monitored album(s) for the artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Size on Disk: 0.00 GB │Do you want to trigger an automatic search of your indexers│ │
│Albums: 1 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Tracks: 15/15 │Do you want to trigger an automatic search of your indexers│ │
│╭ Artist Details ───────────────────────│ for all monitored album(s) for the artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Size on Disk: 0.00 GB │Do you want to trigger an automatic search of your indexers│ │
│Albums: 1 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Tracks: 15/15 │Do you want to trigger an automatic search of your indexers│ │
│╭ Artist Details ───────────────────────│ for all monitored album(s) for the artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -16,10 +17,9 @@ expression: output
│Path: /nfs/music/test-artist │
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 ╭───────────────── Download Rejected Release ──────────────────╮ │
│Tracks: 15/15 │ Do you really want to download the rejected release: Test │ │
│Size on Disk: 0.00 GB │ Release? │ │
│Monitored: Yes ╭───────────────── Download Rejected Release ──────────────────╮ │
│Albums: 1 │ Do you really want to download the rejected release: Test │ │
│Tracks: 15/15 │ Release? │ │
│╭ Artist Details ──────────────────────│ │───────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││────────────────────────────────────────│Rejection reasons: │───────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────────── Update and Scan ────────────────────╮ │
│Size on Disk: 0.00 GB │ Do you want to trigger an update and disk scan for the │ │
│Albums: 1 ╭──────────────────── Update and Scan ────────────────────╮ │
│Tracks: 15/15 │ Do you want to trigger an update and disk scan for the │ │
│╭ Artist Details ───────────────────────│ artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────────── Update and Scan ────────────────────╮ │
│Size on Disk: 0.00 GB │ Do you want to trigger an update and disk scan for the │ │
│Albums: 1 ╭──────────────────── Update and Scan ────────────────────╮ │
│Tracks: 15/15 │ Do you want to trigger an update and disk scan for the │ │
│╭ Artist Details ───────────────────────│ artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────────── Update and Scan ────────────────────╮ │
│Size on Disk: 0.00 GB │ Do you want to trigger an update and disk scan for the │ │
│Albums: 1 ╭──────────────────── Update and Scan ────────────────────╮ │
│Tracks: 15/15 │ Do you want to trigger an update and disk scan for the │ │
│╭ Artist Details ───────────────────────│ artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -0,0 +1,52 @@
---
source: src/ui/lidarr_ui/library/artist_details_ui_tests.rs
expression: output
---
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years╭─────────────────────────────────────────────────────── Overview ───────────────────────────────────────────────────────╮ │
│Disambiguat│some interesting description of the artist │ │
│Type: Perso│ │ │
│Status: Con│She was born in Madison, Wisconsin: a city she has never really left. │ │
│Genres: sou│ │ │
│Rating: 84%│Her first album took her seven years to finish. │ │
│Path: /nfs/│ │ │
│Quality Pro│ │ │
│Metadata Pr│ │ │
│Monitored: │ │ │
│Albums: 1 │ │ │
│Tracks: 15/│ │ │
│╭ Artist D│ │───────────╮│
││ Albums │ │ │ ││
││──────────│ │───────────││
││ Monitor│ │ ││
││=> 🏷 │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ │ │ ││
││ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ││
││ ││
││ ││
│╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯│
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Size on Disk: 0.00 GB │Do you want to trigger an automatic search of your indexers│ │
│Albums: 1 ╭──────────────── Automatic Artist Search ────────────────╮ │
│Tracks: 15/15 │Do you want to trigger an automatic search of your indexers│ │
│╭ Artist Details ───────────────────────│ for all monitored album(s) for the artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭───────────────────── Delete Album ──────────────────────╮ │
│Size on Disk: 0.00 GB │ Do you really want to delete the album: │ │
│Albums: 1 ╭───────────────────── Delete Album ──────────────────────╮ │
│Tracks: 15/15 │ Do you really want to delete the album: │ │
│╭ Artist Details ───────────────────────│ Test Album? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭──────────────────── Update and Scan ────────────────────╮ │
│Size on Disk: 0.00 GB │ Do you want to trigger an update and disk scan for the │ │
│Albums: 1 ╭──────────────────── Update and Scan ────────────────────╮ │
│Tracks: 15/15 │ Do you want to trigger an update and disk scan for the │ │
│╭ Artist Details ───────────────────────│ artist: Alex? │───────────────────────────────────────────╮│
││ Albums │ History │ Manual Search │ │ ││
││─────────────────────────────────────────│ │───────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -17,9 +18,8 @@ expression: output
│Quality Profile: Lossless │
│Metadata Profile: Standard │
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 ╭─────────────────────────────────── Details ───────────────────────────────────╮ │
│Size on Disk: 0.00 GB │Source Title: Test source title │ │
│Albums: 1 ╭─────────────────────────────────── Details ───────────────────────────────────╮ │
│Tracks: 15/15 │Source Title: Test source title │ │
│╭ Artist Details ─────────────│Event Type: grabbed │───────────────────────────────╮│
││ Albums │ History │ Manual Sear│Quality: Lossless │ ││
││───────────────────────────────│Date: 2023-01-01 00:00:00 UTC │───────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -7,7 +7,8 @@ expression: output
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││
@@ -0,0 +1,48 @@
---
source: src/ui/lidarr_ui/library/artist_overview_ui_tests.rs
expression: output
---
╭─────────────────────────────────────────────────────── Overview ───────────────────────────────────────────────────────╮
│some interesting description of the artist │
│ │
│She was born in Madison, Wisconsin: a city she has never really left. │
│ │
│Her first album took her seven years to finish. │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,48 @@
---
source: src/ui/lidarr_ui/library/artist_overview_ui_tests.rs
expression: output
---
╭─────────────────────────────────────────────────────── Overview ───────────────────────────────────────────────────────╮
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,48 @@
---
source: src/ui/lidarr_ui/library/artist_overview_ui_tests.rs
expression: output
---
╭─────────────────────────────────────────────────────── Overview ───────────────────────────────────────────────────────╮
│ │
│ │
│ Loading ... │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -0,0 +1,48 @@
---
source: src/ui/lidarr_ui/library/artist_overview_ui_tests.rs
expression: output
---
╭─────────────────────────────────────────────────────── Overview ───────────────────────────────────────────────────────╮
│She was born in Madison, Wisconsin: a city she has never really left. │
│ │
│Her first album took her seven years to finish. │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
@@ -7,8 +7,9 @@ expression: output
=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Disambiguation: Ame╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to fini╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Disambiguation: Ame│ │ │
│Type: Person │ │ │
│Status: Continuing │ │ │
│Genres: soundtrack │ │ │
@@ -16,10 +17,9 @@ expression: output
│Path: /nfs/music/te│ │ │
│Quality Profile: Lo│ │ │
│Metadata Profile: S│ │ │
│Monitored: Yes │ │ │
│Albums: 1 │ ╭───╮ │ │
│Tracks: 15/15 │ Monitored: │ ✔ │ │ │
│Size on Disk: 0.00 │ ╰───╯ │ │
│Monitored: Yes │ ╭───╮ │ │
│Albums: 1 │ Monitored: │ ✔ │ │ │
│Tracks: 15/15 │ ╰───╯ │ │
│╭ Artist Details │ ╭─────────────────────────────────────────────────╮ │────────────────────╮│
││ Albums │ History │ Monitor New Albums: │All Albums ▼ │ │ ││
││──────────────────│ ╰─────────────────────────────────────────────────╯ │────────────────────││
@@ -7,8 +7,9 @@ expression: output
=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Disambiguation: Ame╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to fini╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Disambiguation: Ame│ │ │
│Type: Person │ │ │
│Status: Continuing │ │ │
│Genres: soundtrack │ │ │
@@ -16,10 +17,9 @@ expression: output
│Path: /nfs/music/te│ │ │
│Quality Profile: Lo│ │ │
│Metadata Profile: S│ │ │
│Monitored: Yes │ │ │
│Albums: 1 │ ╭───╮ │ │
│Tracks: 15/15 │ Monitored: │ ✔ │ │ │
│Size on Disk: 0.00 │ ╰───╯ │ │
│Monitored: Yes │ ╭───╮ │ │
│Albums: 1 │ Monitored: │ ✔ │ │ │
│Tracks: 15/15 │ ╰───╯ │ │
│╭ Artist Details │ ╭─────────────────────────────────────────────────╮ │────────────────────╮│
││ Albums │ History │ Monitor New Albums: │All Albums ▼ │ │ ││
││──────────────────│ ╰─────────────────────────────────────────────────╯ │────────────────────││
@@ -7,8 +7,9 @@ expression: output
=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Disambiguation: Ame╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to fini╭─────────────────────────────────── Edit - Alex (American pianist) ────────────────────────────────────╮ │
│Disambiguation: Ame│ │ │
│Type: Person │ │ │
│Status: Continuing │ │ │
│Genres: soundtrack │ │ │
@@ -16,10 +17,9 @@ expression: output
│Path: /nfs/music/te│ │ │
│Quality Profile: Lo│ │ │
│Metadata Profile: S│ │ │
│Monitored: Yes │ │ │
│Albums: 1 │ ╭───╮ │ │
│Tracks: 15/15 │ Monitored: │ ✔ │ │ │
│Size on Disk: 0.00 │ ╰───╯ │ │
│Monitored: Yes │ ╭───╮ │ │
│Albums: 1 │ Monitored: │ ✔ │ │ │
│Tracks: 15/15 │ ╰───╯ │ │
│╭ Artist Details │ ╭─────────────────────────────────────────────────╮ │────────────────────╮│
││ Albums │ History │ Monitor New Albums: │All Albums ▼ │ │ ││
││──────────────────│ ╰─────────────────────────────────────────────────╯ │────────────────────││
@@ -7,7 +7,8 @@ expression: output
=> Alex Person Continuing Lossless Standard 1 15/15 0.00 GB 🏷 alex
╭ Alex ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│Artist: Alex │
│Overview: some interesting description of the artist │
│Overview: some interesting description of the artistShe was born in Madison, Wisconsin: a city she has never really left.Her first album took her │
│seven years to finish. │
│Disambiguation: American pianist │
│Type: Person │
│Status: Continuing │
@@ -19,7 +20,6 @@ expression: output
│Monitored: Yes │
│Albums: 1 │
│Tracks: 15/15 │
│Size on Disk: 0.00 GB │
│╭ Artist Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│
││ Albums │ History │ Manual Search ││
││─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────││