diff --git a/src/ui/readarr_ui/mod.rs b/src/ui/readarr_ui/mod.rs index b4463fcd..a1e68c53 100644 --- a/src/ui/readarr_ui/mod.rs +++ b/src/ui/readarr_ui/mod.rs @@ -25,6 +25,7 @@ use super::{ use crate::ui::readarr_ui::blocklist::BlocklistUi; use crate::ui::readarr_ui::downloads::DownloadsUi; use crate::ui::readarr_ui::root_folders::RootFoldersUi; +use crate::ui::readarr_ui::system::SystemUi; use crate::ui::utils::{extract_monitored_disk_space_vec, extract_monitored_root_folders}; use crate::{ app::App, @@ -44,6 +45,7 @@ mod history; mod library; mod readarr_ui_utils; mod root_folders; +mod system; #[cfg(test)] #[path = "readarr_ui_tests.rs"] @@ -66,6 +68,7 @@ impl DrawUi for ReadarrUi { _ if BlocklistUi::accepts(route) => BlocklistUi::draw(f, app, content_area), _ if HistoryUi::accepts(route) => HistoryUi::draw(f, app, content_area), _ if RootFoldersUi::accepts(route) => RootFoldersUi::draw(f, app, content_area), + _ if SystemUi::accepts(route) => SystemUi::draw(f, app, content_area), _ => (), } } diff --git a/src/ui/readarr_ui/snapshots/managarr__ui__readarr_ui__readarr_ui_tests__tests__snapshot_tests__readarr_tabs_System.snap b/src/ui/readarr_ui/snapshots/managarr__ui__readarr_ui__readarr_ui_tests__tests__snapshot_tests__readarr_tabs_System.snap index d3f01721..8ee87793 100644 --- a/src/ui/readarr_ui/snapshots/managarr__ui__readarr_ui__readarr_ui_tests__tests__snapshot_tests__readarr_tabs_System.snap +++ b/src/ui/readarr_ui/snapshots/managarr__ui__readarr_ui__readarr_ui_tests__tests__snapshot_tests__readarr_tabs_System.snap @@ -4,51 +4,51 @@ expression: output --- ╭ Authors ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ Library │ Downloads │ Blocklist │ History │ Root Folders │ Indexers │ System │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ -│ │ +│╭ Tasks ───────────────────────────────────────────────────────────────────────╮╭ Queued Events ──────────────────────────────────────────────────────────────╮│ +││Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration ││ +││Backup 1 hour now 59 minutes ││manual completed Refresh Monitored 4 minutes ago 4 minutes a 00:03:03 ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +││ ││ ││ +│╰────────────────────────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────────────────────╯│ +│╭ Logs ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮│ +││2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|No list items to process ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +││ ││ +│╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯│ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/mod.rs b/src/ui/readarr_ui/system/mod.rs new file mode 100644 index 00000000..2c4f3059 --- /dev/null +++ b/src/ui/readarr_ui/system/mod.rs @@ -0,0 +1,203 @@ +use std::ops::Sub; + +#[cfg(not(test))] +use chrono::Utc; +use ratatui::text::{Span, Text}; +use ratatui::widgets::{Cell, Row}; +use ratatui::{ + Frame, + layout::{Constraint, Layout, Rect}, + widgets::ListItem, +}; + +use crate::app::App; +use crate::models::Route; +use crate::models::readarr_models::ReadarrTask; +use crate::models::servarr_data::readarr::readarr_data::ActiveReadarrBlock; +use crate::models::servarr_models::QueueEvent; +use crate::ui::DrawUi; +use crate::ui::readarr_ui::system::system_details_ui::SystemDetailsUi; +use crate::ui::styles::{ManagarrStyle, default_style}; +#[cfg(test)] +use crate::ui::ui_test_utils::test_utils::Utc; +use crate::ui::utils::{convert_to_minutes_hours_days, style_log_list_item, title_block}; +use crate::ui::widgets::loading_block::LoadingBlock; +use crate::ui::widgets::managarr_table::ManagarrTable; +use crate::ui::widgets::selectable_list::SelectableList; + +mod system_details_ui; + +#[cfg(test)] +#[path = "system_ui_tests.rs"] +mod system_ui_tests; + +pub(super) const TASK_TABLE_HEADERS: [&str; 4] = + ["Name", "Interval", "Last Execution", "Next Execution"]; + +pub(super) const TASK_TABLE_CONSTRAINTS: [Constraint; 4] = [ + Constraint::Percentage(30), + Constraint::Percentage(23), + Constraint::Percentage(23), + Constraint::Percentage(23), +]; + +pub(super) struct SystemUi; + +impl DrawUi for SystemUi { + fn accepts(route: Route) -> bool { + let Route::Readarr(active_readarr_block, _) = route else { + return false; + }; + SystemDetailsUi::accepts(route) || active_readarr_block == ActiveReadarrBlock::System + } + + fn draw(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let route = app.get_current_route(); + draw_system_ui_layout(f, app, area); + + if SystemDetailsUi::accepts(route) { + SystemDetailsUi::draw(f, app, area); + } + } +} + +fn draw_system_ui_layout(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let [activities_area, logs_area] = + Layout::vertical([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]).areas(area); + + let [tasks_area, events_area] = + Layout::horizontal([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)]).areas(activities_area); + + draw_tasks(f, app, tasks_area); + draw_queued_events(f, app, events_area); + draw_logs(f, app, logs_area); +} + +fn draw_tasks(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let tasks_row_mapping = |task: &ReadarrTask| { + let task_props = extract_task_props(task); + + Row::new(vec![ + Cell::from(task_props.name), + Cell::from(task_props.interval), + Cell::from(task_props.last_execution), + Cell::from(task_props.next_execution), + ]) + .primary() + }; + let tasks_table = ManagarrTable::new(Some(&mut app.data.readarr_data.tasks), tasks_row_mapping) + .block(title_block("Tasks")) + .loading(app.is_loading) + .highlight_rows(false) + .headers(TASK_TABLE_HEADERS) + .constraints(TASK_TABLE_CONSTRAINTS); + + f.render_widget(tasks_table, area); +} + +pub(super) fn draw_queued_events(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let events_row_mapping = |event: &QueueEvent| { + let queued = convert_to_minutes_hours_days(Utc::now().sub(event.queued).num_minutes()); + let queued_string = if queued != "now" { + format!("{queued} ago") + } else { + queued + }; + let started_string = if let Some(date_time) = event.started { + let started = convert_to_minutes_hours_days(Utc::now().sub(date_time).num_minutes()); + + if started != "now" { + format!("{started} ago") + } else { + started + } + } else { + String::new() + }; + + let duration = if let Some(dur) = &event.duration { + &dur[..8] + } else { + "" + }; + + Row::new(vec![ + Cell::from(event.trigger.clone()), + Cell::from(event.status.clone()), + Cell::from(event.command_name.clone()), + Cell::from(queued_string), + Cell::from(started_string), + Cell::from(duration.to_owned()), + ]) + .primary() + }; + let events_table = ManagarrTable::new( + Some(&mut app.data.readarr_data.queued_events), + events_row_mapping, + ) + .block(title_block("Queued Events")) + .loading(app.is_loading) + .highlight_rows(false) + .headers(["Trigger", "Status", "Name", "Queued", "Started", "Duration"]) + .constraints([ + Constraint::Percentage(13), + Constraint::Percentage(13), + Constraint::Percentage(30), + Constraint::Percentage(16), + Constraint::Percentage(14), + Constraint::Percentage(14), + ]); + + f.render_widget(events_table, area); +} + +fn draw_logs(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let block = title_block("Logs"); + + if app.data.readarr_data.logs.items.is_empty() { + f.render_widget(LoadingBlock::new(app.is_loading, block), area); + return; + } + + let logs_box = SelectableList::new(&mut app.data.readarr_data.logs, |log| { + let log_line = log.to_string(); + let level = extract_log_level(&log_line); + + style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level) + }) + .block(block) + .highlight_style(default_style()); + + f.render_widget(logs_box, area); +} + +pub(super) fn extract_log_level(log_line: &str) -> String { + log_line.split('|').collect::>()[1].to_string() +} + +pub(super) struct TaskProps { + pub(super) name: String, + pub(super) interval: String, + pub(super) last_execution: String, + pub(super) next_execution: String, +} + +pub(super) fn extract_task_props(task: &ReadarrTask) -> TaskProps { + let interval = convert_to_minutes_hours_days(task.interval); + let next_execution = + convert_to_minutes_hours_days((task.next_execution - Utc::now()).num_minutes()); + let last_execution = + convert_to_minutes_hours_days((Utc::now() - task.last_execution).num_minutes()); + let last_execution_string = if last_execution != "now" { + format!("{last_execution} ago") + } else { + last_execution + }; + + TaskProps { + name: task.name.clone(), + interval, + last_execution: last_execution_string, + next_execution, + } +} diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemLogs.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemLogs.snap new file mode 100644 index 00000000..77cc4918 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemLogs.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Log Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemQueuedEvents.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemQueuedEvents.snap new file mode 100644 index 00000000..06f90228 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemQueuedEvents.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + + + + + ╭ Queued Events ────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemTasks.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemTasks.snap new file mode 100644 index 00000000..42783c04 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__empty_SystemTasks.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemLogs.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemLogs.snap new file mode 100644 index 00000000..aed87ded --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemLogs.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Log Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemQueuedEvents.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemQueuedEvents.snap new file mode 100644 index 00000000..bd8e76f4 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemQueuedEvents.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + + + + + ╭ Queued Events ────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemTasks.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemTasks.snap new file mode 100644 index 00000000..1f14d555 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemTasks.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemUpdates.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemUpdates.snap new file mode 100644 index 00000000..944d9739 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__loading_SystemUpdates.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Updates ───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemLogs.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemLogs.snap new file mode 100644 index 00000000..ca13cf1d --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemLogs.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Log Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha │ + │2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta │ + │2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemQueuedEvents.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemQueuedEvents.snap new file mode 100644 index 00000000..7fa24517 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemQueuedEvents.snap @@ -0,0 +1,44 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + + + + + ╭ Queued Events ────────────────────────────────────────────────────────────────────────────────╮ + │Trigger Status Name Queued Started Duration │ + │manual completed queued event one 1 hour ago 30 minutes ag 00:29:14 │ + │scheduled started queued event two 15 minutes ago 4 minutes ago 01:02:03 │ + │external queued queued event three 1 minute ago │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTaskStartConfirmPrompt.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTaskStartConfirmPrompt.snap new file mode 100644 index 00000000..4cd6d8c4 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTaskStartConfirmPrompt.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ Name Interval Last Execution Next Execution │ + │=> Backup task 2 hours 30 minutes ago 1 hour │ + │ Rss sync task 15 minutes 8 minutes ago 3 minutes │ + │ Housekeeping task 1 day 4 hours ago 18 hours │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ ╭────────────────────── Start Task ───────────────────────╮ │ + │ │ Do you want to manually start this task: Backup task? │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │╭────────────────────────────╮╭───────────────────────────╮│ │ + │ ││ Yes ││ No ││ │ + │ │╰────────────────────────────╯╰───────────────────────────╯│ │ + │ ╰───────────────────────────────────────────────────────────╯ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTasks.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTasks.snap new file mode 100644 index 00000000..2950c7dd --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemTasks.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ Name Interval Last Execution Next Execution │ + │=> Backup task 2 hours 30 minutes ago 1 hour │ + │ Rss sync task 15 minutes 8 minutes ago 3 minutes │ + │ Housekeeping task 1 day 4 hours ago 18 hours │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemUpdates.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemUpdates.snap new file mode 100644 index 00000000..0a4cb97d --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__popup_SystemUpdates.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Updates ───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │The latest version of Sonarr is already installed │ + │ │ + │4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed) │ + │--------------------------------------------------------------------------------------------------------------------------│ + │New: │ + │ * Cool new thing │ + │Fixed: │ + │ * Some bugs killed │ + │ │ + │ │ + │3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed) │ + │--------------------------------------------------------------------------------------------------------------------------│ + │New: │ + │ * Cool new thing (old) │ + │ * Other cool new thing (old) │ + │ │ + │ │ + │2.1.0 - 2023-04-15 02:02:53 UTC │ + │--------------------------------------------------------------------------------------------------------------------------│ + │Fixed: │ + │ * Killed bug 1 │ + │ * Fixed bug 2 │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_task_start_confirm_prompt_names_the_selected_task.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_task_start_confirm_prompt_names_the_selected_task.snap new file mode 100644 index 00000000..bece945f --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_task_start_confirm_prompt_names_the_selected_task.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ Name Interval Last Execution Next Execution │ + │ Backup task 2 hours 30 minutes ago 1 hour │ + │ Rss sync task 15 minutes 8 minutes ago 3 minutes │ + │=> Housekeeping task 1 day 4 hours ago 18 hours │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ ╭────────────────────── Start Task ───────────────────────╮ │ + │ │Do you want to manually start this task: Housekeeping task?│ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │ │ │ + │ │╭────────────────────────────╮╭───────────────────────────╮│ │ + │ ││ Yes ││ No ││ │ + │ │╰────────────────────────────╯╰───────────────────────────╯│ │ + │ ╰───────────────────────────────────────────────────────────╯ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_is_loading_when_updates_are_present.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_is_loading_when_updates_are_present.snap new file mode 100644 index 00000000..944d9739 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_is_loading_when_updates_are_present.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Updates ───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_loading_when_empty.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_loading_when_empty.snap new file mode 100644 index 00000000..944d9739 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_details_ui__system_details_ui_tests__tests__snapshot_tests__system_details_ui_updates_popup_loading_when_empty.snap @@ -0,0 +1,48 @@ +--- +source: src/ui/readarr_ui/system/system_details_ui_tests.rs +expression: output +--- + + + + + + + ╭ Updates ───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ + │ │ + │ │ + │ Loading ... │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + │ │ + ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemLogs.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemLogs.snap new file mode 100644 index 00000000..1587e814 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemLogs.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ╭ Log Details ───────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ +│ │2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha │ │ +│ │2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta │ │ +│ │2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +╰───────────────────│ │────────────────────╯ +╭ Logs ───────────│ │────────────────────╮ +│2025-12-16 16:40:59│ │ │ +│2025-12-16 16:41:12│ │ │ +│2025-12-16 16:41:30│ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemQueuedEvents.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemQueuedEvents.snap new file mode 100644 index 00000000..45db2d79 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemQueuedEvents.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ╭ Queued Events ────────────────────────────────────────────────────────────────────────────────╮ │ +│ │Trigger Status Name Queued Started Duration │ │ +│ │manual completed queued event one 1 hour ago 30 minutes ag 00:29:14 │ │ +│ │scheduled started queued event two 15 minutes ago 4 minutes ago 01:02:03 │ │ +│ │external queued queued event three 1 minute ago │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +╰────────────────────────────────│ │────────────────────────────────╯ +╭ Logs ────────────────────────│ │────────────────────────────────╮ +│2025-12-16 16:40:59 UTC|INFO|Imp│ │ │ +│2025-12-16 16:41:12 UTC|WARN|Boo│ │ │ +│2025-12-16 16:41:30 UTC|FATAL|Co│ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────╯ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTaskStartConfirmPrompt.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTaskStartConfirmPrompt.snap new file mode 100644 index 00000000..610f58ba --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTaskStartConfirmPrompt.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ +│ │ Name Interval Last Execution Next Execution │ │ +│ │=> Backup task 2 hours 30 minutes ago 1 hour │ │ +│ │ Rss sync task 15 minutes 8 minutes ago 3 minutes │ │ +│ │ Housekeeping task 1 day 4 hours ago 18 hours │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ ╭────────────────────── Start Task ───────────────────────╮ │ │ +│ │ │ Do you want to manually start this task: Backup task? │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +│ │ │ │ │ │ +╰───────────────────│ │ │ │────────────────────╯ +╭ Logs ───────────│ │ │ │────────────────────╮ +│2025-12-16 16:40:59│ │ │ │ │ +│2025-12-16 16:41:12│ │ │ │ │ +│2025-12-16 16:41:30│ │ │ │ │ +│ │ │ │ │ │ +│ │ │╭────────────────────────────╮╭───────────────────────────╮│ │ │ +│ │ ││ Yes ││ No ││ │ │ +│ │ │╰────────────────────────────╯╰───────────────────────────╯│ │ │ +│ │ ╰───────────────────────────────────────────────────────────╯ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTasks.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTasks.snap new file mode 100644 index 00000000..6d027532 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemTasks.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ╭ Tasks ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ +│ │ Name Interval Last Execution Next Execution │ │ +│ │=> Backup task 2 hours 30 minutes ago 1 hour │ │ +│ │ Rss sync task 15 minutes 8 minutes ago 3 minutes │ │ +│ │ Housekeeping task 1 day 4 hours ago 18 hours │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +╰───────────────────│ │────────────────────╯ +╭ Logs ───────────│ │────────────────────╮ +│2025-12-16 16:40:59│ │ │ +│2025-12-16 16:41:12│ │ │ +│2025-12-16 16:41:30│ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemUpdates.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemUpdates.snap new file mode 100644 index 00000000..c14b945c --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__popups_over_system_ui_SystemUpdates.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ╭ Updates ───────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │ +│ │The latest version of Sonarr is already installed │ │ +│ │ │ │ +│ │4.3.2.1 - 2023-04-15 02:02:53 UTC (Currently Installed) │ │ +│ │--------------------------------------------------------------------------------------------------------------------------│ │ +│ │New: │ │ +│ │ * Cool new thing │ │ +│ │Fixed: │ │ +│ │ * Some bugs killed │ │ +│ │ │ │ +│ │ │ │ +│ │3.2.1.0 - 2023-04-15 02:02:53 UTC (Previously Installed) │ │ +│ │--------------------------------------------------------------------------------------------------------------------------│ │ +│ │New: │ │ +│ │ * Cool new thing (old) │ │ +│ │ * Other cool new thing (old) │ │ +│ │ │ │ +│ │ │ │ +╰───────────────────│2.1.0 - 2023-04-15 02:02:53 UTC │────────────────────╯ +╭ Logs ───────────│--------------------------------------------------------------------------------------------------------------------------│────────────────────╮ +│2025-12-16 16:40:59│Fixed: │ │ +│2025-12-16 16:41:12│ * Killed bug 1 │ │ +│2025-12-16 16:41:30│ * Fixed bug 2 │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ │ │ │ +│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_logs_loading.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_logs_loading.snap new file mode 100644 index 00000000..dcab9378 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_logs_loading.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│ ││ │ +│ ││ │ +│ Loading ... ││ Loading ... │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +╰─────────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +╭ Logs ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ Loading ... │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab.snap new file mode 100644 index 00000000..262148f0 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│Name Interval Last Execution Next Execution ││Trigger Status Name Queued Started Duration │ +│Backup task 2 hours 30 minutes ago 1 hour ││manual completed queued event one 1 hour ago 30 minutes 00:29:14 │ +│Rss sync task 15 minutes 8 minutes ago 3 minutes ││scheduled started queued event two 15 minutes ag 4 minutes a 01:02:03 │ +│Housekeeping task 1 day 4 hours ago 18 hours ││external queued queued event three 1 minute ago │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +╰─────────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +╭ Logs ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha │ +│2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta │ +│2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_empty.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_empty.snap new file mode 100644 index 00000000..c7a4efc5 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_empty.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +╰─────────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +╭ Logs ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_loading.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_loading.snap new file mode 100644 index 00000000..dcab9378 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_loading.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│ ││ │ +│ ││ │ +│ Loading ... ││ Loading ... │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +╰─────────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +╭ Logs ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│ │ +│ │ +│ Loading ... │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_task_and_events_loading.snap b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_task_and_events_loading.snap new file mode 100644 index 00000000..867ae2a1 --- /dev/null +++ b/src/ui/readarr_ui/system/snapshots/managarr__ui__readarr_ui__system__system_ui_tests__tests__snapshot_tests__system_ui_renders_system_tab_task_and_events_loading.snap @@ -0,0 +1,54 @@ +--- +source: src/ui/readarr_ui/system/system_ui_tests.rs +expression: output +--- +╭ Tasks ────────────────────────────────────────────────────────────────────────╮╭ Queued Events ───────────────────────────────────────────────────────────────╮ +│ ││ │ +│ ││ │ +│ Loading ... ││ Loading ... │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +│ ││ │ +╰─────────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────────────────────────────────────────────────────────╯ +╭ Logs ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ +│2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha │ +│2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta │ +│2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +│ │ +╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/src/ui/readarr_ui/system/system_details_ui.rs b/src/ui/readarr_ui/system/system_details_ui.rs new file mode 100644 index 00000000..7473ae91 --- /dev/null +++ b/src/ui/readarr_ui/system/system_details_ui.rs @@ -0,0 +1,147 @@ +use ratatui::Frame; +use ratatui::layout::Rect; +use ratatui::text::{Span, Text}; +use ratatui::widgets::{Cell, ListItem, Paragraph, Row}; + +use crate::app::App; +use crate::models::Route; +use crate::models::readarr_models::ReadarrTask; +use crate::models::servarr_data::readarr::readarr_data::{ + ActiveReadarrBlock, SYSTEM_DETAILS_BLOCKS, +}; +use crate::ui::readarr_ui::system::{ + TASK_TABLE_CONSTRAINTS, TASK_TABLE_HEADERS, draw_queued_events, extract_log_level, + extract_task_props, +}; +use crate::ui::styles::ManagarrStyle; +use crate::ui::utils::{borderless_block, style_log_list_item, title_block}; +use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt; +use crate::ui::widgets::loading_block::LoadingBlock; +use crate::ui::widgets::managarr_table::ManagarrTable; +use crate::ui::widgets::popup::{Popup, Size}; +use crate::ui::widgets::selectable_list::SelectableList; +use crate::ui::{DrawUi, draw_popup}; + +#[cfg(test)] +#[path = "system_details_ui_tests.rs"] +mod system_details_ui_tests; + +pub(super) struct SystemDetailsUi; + +impl DrawUi for SystemDetailsUi { + fn accepts(route: Route) -> bool { + let Route::Readarr(active_readarr_block, _) = route else { + return false; + }; + SYSTEM_DETAILS_BLOCKS.contains(&active_readarr_block) + } + + fn draw(f: &mut Frame<'_>, app: &mut App<'_>, _area: Rect) { + if let Route::Readarr(active_readarr_block, _) = app.get_current_route() { + match active_readarr_block { + ActiveReadarrBlock::SystemLogs => { + draw_logs_popup(f, app); + } + ActiveReadarrBlock::SystemTasks | ActiveReadarrBlock::SystemTaskStartConfirmPrompt => { + draw_popup(f, app, draw_tasks_popup, Size::Large) + } + ActiveReadarrBlock::SystemQueuedEvents => { + draw_popup(f, app, draw_queued_events, Size::Medium) + } + ActiveReadarrBlock::SystemUpdates => { + draw_updates_popup(f, app); + } + _ => (), + } + } + } +} + +fn draw_logs_popup(f: &mut Frame<'_>, app: &mut App<'_>) { + let block = title_block("Log Details"); + + if app.data.readarr_data.log_details.items.is_empty() { + let loading = LoadingBlock::new(app.is_loading, borderless_block()); + let popup = Popup::new(loading).size(Size::Large).block(block).margin(1); + + f.render_widget(popup, f.area()); + return; + } + + let logs_list = SelectableList::new(&mut app.data.readarr_data.log_details, |log| { + let log_line = log.to_string(); + let level = extract_log_level(&log.text); + + style_log_list_item(ListItem::new(Text::from(Span::raw(log_line))), level) + }) + .block(borderless_block()); + let popup = Popup::new(logs_list) + .size(Size::Large) + .block(block) + .margin(1); + + f.render_widget(popup, f.area()); +} + +fn draw_tasks_popup(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) { + let tasks_row_mapping = |task: &ReadarrTask| { + let task_props = extract_task_props(task); + + Row::new(vec![ + Cell::from(task_props.name), + Cell::from(task_props.interval), + Cell::from(task_props.last_execution), + Cell::from(task_props.next_execution), + ]) + .primary() + }; + let tasks_table = ManagarrTable::new(Some(&mut app.data.readarr_data.tasks), tasks_row_mapping) + .loading(app.is_loading) + .margin(1) + .headers(TASK_TABLE_HEADERS) + .constraints(TASK_TABLE_CONSTRAINTS); + + f.render_widget(title_block("Tasks"), area); + f.render_widget(tasks_table, area); + + if matches!( + app.get_current_route(), + Route::Readarr(ActiveReadarrBlock::SystemTaskStartConfirmPrompt, _) + ) { + let prompt = format!( + "Do you want to manually start this task: {}?", + app.data.readarr_data.tasks.current_selection().name + ); + let confirmation_prompt = ConfirmationPrompt::new() + .title("Start Task") + .prompt(&prompt) + .yes_no_value(app.data.readarr_data.prompt_confirm); + + f.render_widget( + Popup::new(confirmation_prompt).size(Size::MediumPrompt), + f.area(), + ); + } +} + +fn draw_updates_popup(f: &mut Frame<'_>, app: &mut App<'_>) { + let updates = app.data.readarr_data.updates.get_text(); + let block = title_block("Updates"); + + if !updates.is_empty() && !app.is_loading { + let updates_paragraph = Paragraph::new(Text::from(updates)) + .block(borderless_block()) + .scroll((app.data.readarr_data.updates.offset, 0)); + let popup = Popup::new(updates_paragraph) + .size(Size::Large) + .block(block) + .margin(1); + + f.render_widget(popup, f.area()); + } else { + let loading = LoadingBlock::new(app.is_loading, borderless_block()); + let popup = Popup::new(loading).size(Size::Large).block(block).margin(1); + + f.render_widget(popup, f.area()); + } +} diff --git a/src/ui/readarr_ui/system/system_details_ui_tests.rs b/src/ui/readarr_ui/system/system_details_ui_tests.rs new file mode 100644 index 00000000..4fa1d960 --- /dev/null +++ b/src/ui/readarr_ui/system/system_details_ui_tests.rs @@ -0,0 +1,242 @@ +#[cfg(test)] +mod tests { + use chrono::DateTime; + use strum::IntoEnumIterator; + + use crate::app::App; + use crate::models::HorizontallyScrollableText; + use crate::models::readarr_models::{ReadarrTask, ReadarrTaskName}; + use crate::models::servarr_data::readarr::readarr_data::{ + ActiveReadarrBlock, SYSTEM_DETAILS_BLOCKS, + }; + use crate::models::servarr_models::QueueEvent; + + use crate::ui::DrawUi; + use crate::ui::readarr_ui::system::system_details_ui::SystemDetailsUi; + use crate::ui::ui_test_utils::test_utils::render_to_string_with_app; + + #[test] + fn test_system_details_ui_accepts() { + ActiveReadarrBlock::iter().for_each(|active_readarr_block| { + if SYSTEM_DETAILS_BLOCKS.contains(&active_readarr_block) { + assert!(SystemDetailsUi::accepts(active_readarr_block.into())); + } else { + assert!(!SystemDetailsUi::accepts(active_readarr_block.into())); + } + }); + } + + mod snapshot_tests { + use super::*; + use crate::models::ScrollableText; + use crate::ui::ui_test_utils::test_utils::TerminalSize; + use rstest::rstest; + + #[rstest] + fn test_system_details_ui_popups( + #[values( + ActiveReadarrBlock::SystemLogs, + ActiveReadarrBlock::SystemQueuedEvents, + ActiveReadarrBlock::SystemTasks, + ActiveReadarrBlock::SystemTaskStartConfirmPrompt, + ActiveReadarrBlock::SystemUpdates + )] + active_readarr_block: ActiveReadarrBlock, + ) { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.push_navigation_stack(active_readarr_block.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(format!("popup_{active_readarr_block}"), output); + } + + #[test] + fn test_system_details_ui_task_start_confirm_prompt_names_the_selected_task() { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.data.readarr_data.tasks.select_index(Some(2)); + app.push_navigation_stack(ActiveReadarrBlock::SystemTaskStartConfirmPrompt.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + assert!(output.contains("Do you want to manually start this task: Housekeeping task?")); + insta::assert_snapshot!(output); + } + + #[test] + fn test_system_details_ui_updates_popup_is_loading_when_updates_are_present() { + let mut app = App::test_default_fully_populated(); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::SystemUpdates.into()); + + assert!(!app.data.readarr_data.updates.get_text().is_empty()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[rstest] + fn test_system_details_ui_loading( + #[values( + ActiveReadarrBlock::SystemLogs, + ActiveReadarrBlock::SystemQueuedEvents, + ActiveReadarrBlock::SystemTasks, + ActiveReadarrBlock::SystemUpdates + )] + active_readarr_block: ActiveReadarrBlock, + ) { + let mut app = App::test_default(); + app.is_loading = true; + app.push_navigation_stack(active_readarr_block.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(format!("loading_{active_readarr_block}"), output); + } + + #[test] + fn test_system_details_ui_updates_popup_loading_when_empty() { + let mut app = App::test_default_fully_populated(); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::SystemUpdates.into()); + app.data.readarr_data.updates = ScrollableText::with_string("".to_string()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[rstest] + fn test_system_details_ui_popups_empty( + #[values( + ActiveReadarrBlock::SystemLogs, + ActiveReadarrBlock::SystemQueuedEvents, + ActiveReadarrBlock::SystemTasks + )] + active_readarr_block: ActiveReadarrBlock, + ) { + let mut app = App::test_default(); + app.push_navigation_stack(active_readarr_block.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemDetailsUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(format!("empty_{active_readarr_block}"), output); + } + } + + fn populate_system_data(app: &mut App<'_>) { + app.data.readarr_data.tasks.set_items(tasks_vec()); + app + .data + .readarr_data + .queued_events + .set_items(queued_events_vec()); + app.data.readarr_data.logs.set_items(log_lines_vec()); + app.data.readarr_data.log_details.set_items(log_lines_vec()); + } + + fn tasks_vec() -> Vec { + vec![ + ReadarrTask { + name: "Backup task".to_owned(), + task_name: ReadarrTaskName::Backup, + interval: 120, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:00:00Z").unwrap(), + ), + last_duration: "00:00:00.5111547".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T22:30:00Z").unwrap(), + ), + }, + ReadarrTask { + name: "Rss sync task".to_owned(), + task_name: ReadarrTaskName::RssSync, + interval: 15, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:22:00Z").unwrap(), + ), + last_duration: "00:00:01.2233445".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:33:00Z").unwrap(), + ), + }, + ReadarrTask { + name: "Housekeeping task".to_owned(), + task_name: ReadarrTaskName::Housekeeping, + interval: 1440, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T17:30:00Z").unwrap(), + ), + last_duration: "00:00:09.9887766".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-21T15:30:00Z").unwrap(), + ), + }, + ] + } + + fn queued_events_vec() -> Vec { + vec![ + QueueEvent { + trigger: "manual".to_owned(), + name: "event name one".to_owned(), + command_name: "queued event one".to_owned(), + status: "completed".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T20:30:00Z").unwrap()), + started: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:00:00Z").unwrap(), + )), + ended: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:29:14Z").unwrap(), + )), + duration: Some("00:29:14.1234567".to_owned()), + }, + QueueEvent { + trigger: "scheduled".to_owned(), + name: "event name two".to_owned(), + command_name: "queued event two".to_owned(), + status: "started".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:15:00Z").unwrap()), + started: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:26:00Z").unwrap(), + )), + ended: None, + duration: Some("01:02:03.7654321".to_owned()), + }, + QueueEvent { + trigger: "external".to_owned(), + name: "event name three".to_owned(), + command_name: "queued event three".to_owned(), + status: "queued".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:00Z").unwrap()), + started: None, + ended: None, + duration: None, + }, + ] + } + + fn log_lines_vec() -> Vec { + vec![ + "2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha".into(), + "2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta".into(), + "2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma".into(), + ] + } +} diff --git a/src/ui/readarr_ui/system/system_ui_tests.rs b/src/ui/readarr_ui/system/system_ui_tests.rs new file mode 100644 index 00000000..4716ac80 --- /dev/null +++ b/src/ui/readarr_ui/system/system_ui_tests.rs @@ -0,0 +1,266 @@ +#[cfg(test)] +mod tests { + use chrono::DateTime; + use strum::IntoEnumIterator; + + use crate::app::App; + use crate::models::HorizontallyScrollableText; + use crate::models::readarr_models::{ReadarrTask, ReadarrTaskName}; + use crate::models::servarr_data::readarr::readarr_data::{ + ActiveReadarrBlock, SYSTEM_DETAILS_BLOCKS, + }; + use crate::models::servarr_models::QueueEvent; + use crate::ui::DrawUi; + use crate::ui::readarr_ui::system::SystemUi; + use crate::ui::ui_test_utils::test_utils::render_to_string_with_app; + + #[test] + fn test_system_ui_accepts() { + let mut system_ui_blocks = Vec::new(); + system_ui_blocks.push(ActiveReadarrBlock::System); + system_ui_blocks.extend(SYSTEM_DETAILS_BLOCKS); + + ActiveReadarrBlock::iter().for_each(|active_readarr_block| { + if system_ui_blocks.contains(&active_readarr_block) { + assert!(SystemUi::accepts(active_readarr_block.into())); + } else { + assert!(!SystemUi::accepts(active_readarr_block.into())); + } + }); + } + + mod test_extract_log_level { + use pretty_assertions::assert_str_eq; + + use crate::ui::readarr_ui::system::extract_log_level; + + #[test] + fn test_extract_log_level_returns_the_field_after_the_timestamp() { + let level = extract_log_level("2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|Message"); + + assert_str_eq!(level, "INFO"); + } + + #[test] + fn test_extract_log_level_preserves_case() { + let level = extract_log_level("2025-12-16 16:41:30 UTC|FaTaL|CommandExecutor|Message"); + + assert_str_eq!(level, "FaTaL"); + } + + #[test] + fn test_extract_log_level_ignores_later_fields() { + let level = extract_log_level("timestamp|WARN|logger|message|with|extra|pipes"); + + assert_str_eq!(level, "WARN"); + } + + #[test] + fn test_extract_log_level_returns_an_empty_string_when_the_level_is_absent() { + let level = extract_log_level("2025-12-16 16:41:12 UTC||BookScanService|Message"); + + assert_str_eq!(level, ""); + } + } + + mod snapshot_tests { + use crate::models::stateful_list::StatefulList; + use crate::ui::ui_test_utils::test_utils::TerminalSize; + use rstest::rstest; + + use super::*; + + #[test] + fn test_system_ui_renders_system_tab_loading() { + let mut app = App::test_default(); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::System.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[test] + fn test_system_ui_renders_logs_loading() { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.is_loading = true; + app.push_navigation_stack(ActiveReadarrBlock::System.into()); + app.data.readarr_data.logs = StatefulList::default(); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[test] + fn test_system_ui_renders_system_tab_task_and_events_loading() { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.push_navigation_stack(ActiveReadarrBlock::System.into()); + app.is_loading = true; + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[test] + fn test_system_ui_renders_system_tab() { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.push_navigation_stack(ActiveReadarrBlock::System.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[test] + fn test_system_ui_renders_system_tab_empty() { + let mut app = App::test_default(); + app.push_navigation_stack(ActiveReadarrBlock::System.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!(output); + } + + #[rstest] + fn test_system_details_ui_renders_popups_over_system_ui( + #[values( + ActiveReadarrBlock::SystemLogs, + ActiveReadarrBlock::SystemQueuedEvents, + ActiveReadarrBlock::SystemTasks, + ActiveReadarrBlock::SystemTaskStartConfirmPrompt, + ActiveReadarrBlock::SystemUpdates + )] + active_readarr_block: ActiveReadarrBlock, + ) { + let mut app = App::test_default_fully_populated(); + populate_system_data(&mut app); + app.push_navigation_stack(active_readarr_block.into()); + + let output = render_to_string_with_app(TerminalSize::Large, &mut app, |f, app| { + SystemUi::draw(f, app, f.area()); + }); + + insta::assert_snapshot!( + format!("popups_over_system_ui_{active_readarr_block}"), + output + ); + } + } + + fn populate_system_data(app: &mut App<'_>) { + app.data.readarr_data.tasks.set_items(tasks_vec()); + app + .data + .readarr_data + .queued_events + .set_items(queued_events_vec()); + app.data.readarr_data.logs.set_items(log_lines_vec()); + app.data.readarr_data.log_details.set_items(log_lines_vec()); + } + + fn tasks_vec() -> Vec { + vec![ + ReadarrTask { + name: "Backup task".to_owned(), + task_name: ReadarrTaskName::Backup, + interval: 120, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:00:00Z").unwrap(), + ), + last_duration: "00:00:00.5111547".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T22:30:00Z").unwrap(), + ), + }, + ReadarrTask { + name: "Rss sync task".to_owned(), + task_name: ReadarrTaskName::RssSync, + interval: 15, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:22:00Z").unwrap(), + ), + last_duration: "00:00:01.2233445".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:33:00Z").unwrap(), + ), + }, + ReadarrTask { + name: "Housekeeping task".to_owned(), + task_name: ReadarrTaskName::Housekeeping, + interval: 1440, + last_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T17:30:00Z").unwrap(), + ), + last_duration: "00:00:09.9887766".to_owned(), + next_execution: DateTime::from( + DateTime::parse_from_rfc3339("2023-05-21T15:30:00Z").unwrap(), + ), + }, + ] + } + + fn queued_events_vec() -> Vec { + vec![ + QueueEvent { + trigger: "manual".to_owned(), + name: "event name one".to_owned(), + command_name: "queued event one".to_owned(), + status: "completed".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T20:30:00Z").unwrap()), + started: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:00:00Z").unwrap(), + )), + ended: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:29:14Z").unwrap(), + )), + duration: Some("00:29:14.1234567".to_owned()), + }, + QueueEvent { + trigger: "scheduled".to_owned(), + name: "event name two".to_owned(), + command_name: "queued event two".to_owned(), + status: "started".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:15:00Z").unwrap()), + started: Some(DateTime::from( + DateTime::parse_from_rfc3339("2023-05-20T21:26:00Z").unwrap(), + )), + ended: None, + duration: Some("01:02:03.7654321".to_owned()), + }, + QueueEvent { + trigger: "external".to_owned(), + name: "event name three".to_owned(), + command_name: "queued event three".to_owned(), + status: "queued".to_owned(), + queued: DateTime::from(DateTime::parse_from_rfc3339("2023-05-20T21:29:00Z").unwrap()), + started: None, + ended: None, + duration: None, + }, + ] + } + + fn log_lines_vec() -> Vec { + vec![ + "2025-12-16 16:40:59 UTC|INFO|ImportListSyncService|log line alpha".into(), + "2025-12-16 16:41:12 UTC|WARN|BookScanService|log line beta".into(), + "2025-12-16 16:41:30 UTC|FATAL|CommandExecutor|log line gamma".into(), + ] + } +}