Refactored the ErrorMessage widget into a generic Message widget for enhanced reuse. Added support for testing a single indexer at a time.
This commit is contained in:
@@ -23,6 +23,7 @@ generate_keybindings! {
|
||||
logs,
|
||||
tasks,
|
||||
test,
|
||||
test_all,
|
||||
refresh,
|
||||
update,
|
||||
events,
|
||||
@@ -102,6 +103,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
||||
key: Key::Char('t'),
|
||||
desc: "test",
|
||||
},
|
||||
test_all: KeyBinding {
|
||||
key: Key::Char('T'),
|
||||
desc: "test all",
|
||||
},
|
||||
refresh: KeyBinding {
|
||||
key: Key::Ctrl('r'),
|
||||
desc: "refresh",
|
||||
|
||||
@@ -22,6 +22,7 @@ mod test {
|
||||
#[case(DEFAULT_KEYBINDINGS.logs, Key::Char('l'), "logs")]
|
||||
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
||||
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
||||
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
||||
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")]
|
||||
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")]
|
||||
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")]
|
||||
|
||||
@@ -49,6 +49,11 @@ impl<'a> App<'a> {
|
||||
.dispatch_network_event(RadarrEvent::GetIndexerSettings.into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::TestIndexer => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::TestIndexer.into())
|
||||
.await;
|
||||
}
|
||||
ActiveRadarrBlock::TestAllIndexers => {
|
||||
self
|
||||
.dispatch_network_event(RadarrEvent::TestAllIndexers.into())
|
||||
|
||||
@@ -52,7 +52,7 @@ pub static ROOT_FOLDERS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||
),
|
||||
];
|
||||
|
||||
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 7] = [
|
||||
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||
(DEFAULT_KEYBINDINGS.submit, "edit indexer"),
|
||||
(
|
||||
@@ -60,7 +60,8 @@ pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||
DEFAULT_KEYBINDINGS.settings.desc,
|
||||
),
|
||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||
(DEFAULT_KEYBINDINGS.test, "test all indexers"),
|
||||
(DEFAULT_KEYBINDINGS.test, "test indexer"),
|
||||
(DEFAULT_KEYBINDINGS.test_all, "test all indexers"),
|
||||
(
|
||||
DEFAULT_KEYBINDINGS.refresh,
|
||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||
|
||||
@@ -177,6 +177,11 @@ mod tests {
|
||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||
|
||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test);
|
||||
assert_str_eq!(*description, "test indexer");
|
||||
|
||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||
|
||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test_all);
|
||||
assert_str_eq!(*description, "test all indexers");
|
||||
|
||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||
|
||||
@@ -161,6 +161,22 @@ mod tests {
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_test_indexer_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
app
|
||||
.dispatch_by_radarr_block(&ActiveRadarrBlock::TestIndexer)
|
||||
.await;
|
||||
|
||||
assert!(app.is_loading);
|
||||
assert_eq!(
|
||||
sync_network_rx.recv().await.unwrap(),
|
||||
RadarrEvent::TestIndexer.into()
|
||||
);
|
||||
assert_eq!(app.tick_count, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_dispatch_by_test_all_indexers_block() {
|
||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||
|
||||
@@ -312,6 +312,19 @@ mod tests {
|
||||
assert!(!app.data.radarr_data.prompt_confirm);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_test_indexer_esc() {
|
||||
let mut app = App::default();
|
||||
app.data.radarr_data.indexer_test_error = Some("test result".to_owned());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||
app.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
||||
|
||||
IndexersHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::TestIndexer, &None).handle();
|
||||
|
||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
||||
assert_eq!(app.data.radarr_data.indexer_test_error, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default_esc() {
|
||||
let mut app = App::default();
|
||||
@@ -391,6 +404,24 @@ mod tests {
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
&ActiveRadarrBlock::TestIndexer.into()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_test_all_key() {
|
||||
let mut app = App::default();
|
||||
|
||||
IndexersHandler::with(
|
||||
&DEFAULT_KEYBINDINGS.test_all.key,
|
||||
&mut app,
|
||||
&ActiveRadarrBlock::Indexers,
|
||||
&None,
|
||||
)
|
||||
.handle();
|
||||
|
||||
assert_eq!(
|
||||
app.get_current_route(),
|
||||
&ActiveRadarrBlock::TestAllIndexers.into()
|
||||
|
||||
@@ -152,6 +152,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
||||
self.app.pop_navigation_stack();
|
||||
self.app.data.radarr_data.prompt_confirm = false;
|
||||
}
|
||||
ActiveRadarrBlock::TestIndexer => {
|
||||
self.app.pop_navigation_stack();
|
||||
self.app.data.radarr_data.indexer_test_error = None;
|
||||
}
|
||||
_ => handle_clear_errors(self.app),
|
||||
}
|
||||
}
|
||||
@@ -169,6 +173,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
||||
self.app.should_refresh = true;
|
||||
}
|
||||
_ if *key == DEFAULT_KEYBINDINGS.test.key => {
|
||||
self
|
||||
.app
|
||||
.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
||||
}
|
||||
_ if *key == DEFAULT_KEYBINDINGS.test_all.key => {
|
||||
self
|
||||
.app
|
||||
.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
|
||||
|
||||
@@ -59,6 +59,7 @@ pub struct RadarrData<'a> {
|
||||
pub edit_indexer_modal: Option<EditIndexerModal>,
|
||||
pub edit_root_folder: Option<HorizontallyScrollableText>,
|
||||
pub indexer_settings: Option<IndexerSettings>,
|
||||
pub indexer_test_error: Option<String>,
|
||||
pub indexer_test_all_results: Option<StatefulTable<IndexerTestResultModalItem>>,
|
||||
pub movie_details_modal: Option<MovieDetailsModal>,
|
||||
pub prompt_confirm: bool,
|
||||
@@ -107,6 +108,7 @@ impl<'a> Default for RadarrData<'a> {
|
||||
edit_indexer_modal: None,
|
||||
edit_root_folder: None,
|
||||
indexer_settings: None,
|
||||
indexer_test_error: None,
|
||||
indexer_test_all_results: None,
|
||||
movie_details_modal: None,
|
||||
prompt_confirm: false,
|
||||
@@ -279,6 +281,7 @@ pub enum ActiveRadarrBlock {
|
||||
SystemTasks,
|
||||
SystemTaskStartConfirmPrompt,
|
||||
SystemUpdates,
|
||||
TestIndexer,
|
||||
TestAllIndexers,
|
||||
UpdateAndScanPrompt,
|
||||
UpdateAllCollectionsPrompt,
|
||||
@@ -309,10 +312,11 @@ pub static COLLECTIONS_BLOCKS: [ActiveRadarrBlock; 7] = [
|
||||
ActiveRadarrBlock::FilterCollectionsError,
|
||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt,
|
||||
];
|
||||
pub static INDEXERS_BLOCKS: [ActiveRadarrBlock; 3] = [
|
||||
pub static INDEXERS_BLOCKS: [ActiveRadarrBlock; 4] = [
|
||||
ActiveRadarrBlock::AddIndexer,
|
||||
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||
ActiveRadarrBlock::Indexers,
|
||||
ActiveRadarrBlock::TestIndexer,
|
||||
];
|
||||
pub static ROOT_FOLDERS_BLOCKS: [ActiveRadarrBlock; 3] = [
|
||||
ActiveRadarrBlock::RootFolders,
|
||||
|
||||
@@ -81,6 +81,7 @@ mod tests {
|
||||
assert!(radarr_data.edit_root_folder.is_none());
|
||||
assert!(radarr_data.edit_indexer_modal.is_none());
|
||||
assert!(radarr_data.indexer_settings.is_none());
|
||||
assert!(radarr_data.indexer_test_error.is_none());
|
||||
assert!(radarr_data.indexer_test_all_results.is_none());
|
||||
assert!(radarr_data.movie_details_modal.is_none());
|
||||
assert!(radarr_data.prompt_confirm_action.is_none());
|
||||
@@ -280,10 +281,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_indexers_blocks_contents() {
|
||||
assert_eq!(INDEXERS_BLOCKS.len(), 3);
|
||||
assert_eq!(INDEXERS_BLOCKS.len(), 4);
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::AddIndexer));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::DeleteIndexerPrompt));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::Indexers));
|
||||
assert!(INDEXERS_BLOCKS.contains(&ActiveRadarrBlock::TestIndexer));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -63,6 +63,7 @@ pub enum RadarrEvent {
|
||||
HealthCheck,
|
||||
SearchNewMovie,
|
||||
StartTask,
|
||||
TestIndexer,
|
||||
TestAllIndexers,
|
||||
TriggerAutomaticSearch,
|
||||
UpdateAllMovies,
|
||||
@@ -99,6 +100,7 @@ impl RadarrEvent {
|
||||
RadarrEvent::GetTags => "/tag",
|
||||
RadarrEvent::GetTasks => "/system/task",
|
||||
RadarrEvent::GetUpdates => "/update",
|
||||
RadarrEvent::TestIndexer => "/indexer/test",
|
||||
RadarrEvent::TestAllIndexers => "/indexer/testall",
|
||||
RadarrEvent::StartTask
|
||||
| RadarrEvent::GetQueuedEvents
|
||||
@@ -153,6 +155,7 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
RadarrEvent::HealthCheck => self.get_healthcheck().await,
|
||||
RadarrEvent::SearchNewMovie => self.search_movie().await,
|
||||
RadarrEvent::StartTask => self.start_task().await,
|
||||
RadarrEvent::TestIndexer => self.test_indexer().await,
|
||||
RadarrEvent::TestAllIndexers => self.test_all_indexers().await,
|
||||
RadarrEvent::TriggerAutomaticSearch => self.trigger_automatic_search().await,
|
||||
RadarrEvent::UpdateAllMovies => self.update_all_movies().await,
|
||||
@@ -1524,6 +1527,61 @@ impl<'a, 'b> Network<'a, 'b> {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn test_indexer(&mut self) {
|
||||
let id = self
|
||||
.app
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexers
|
||||
.current_selection()
|
||||
.id;
|
||||
info!("Testing Radarr indexer with ID: {id}");
|
||||
|
||||
info!("Fetching indexer details for indexer with ID: {id}");
|
||||
|
||||
let request_props = self
|
||||
.radarr_request_props_from(
|
||||
format!("{}/{id}", RadarrEvent::GetIndexers.resource()).as_str(),
|
||||
RequestMethod::Get,
|
||||
None::<()>,
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut test_body: Value = Value::default();
|
||||
|
||||
self
|
||||
.handle_request::<(), Value>(request_props, |detailed_indexer_body, _| {
|
||||
test_body = detailed_indexer_body;
|
||||
})
|
||||
.await;
|
||||
|
||||
info!("Testing indexer");
|
||||
|
||||
let mut request_props = self
|
||||
.radarr_request_props_from(
|
||||
RadarrEvent::TestIndexer.resource(),
|
||||
RequestMethod::Post,
|
||||
Some(test_body),
|
||||
)
|
||||
.await;
|
||||
request_props.ignore_status_code = true;
|
||||
|
||||
self
|
||||
.handle_request::<Value, Value>(request_props, |test_results, mut app| {
|
||||
if test_results.as_object().is_none() {
|
||||
app.data.radarr_data.indexer_test_error = Some(
|
||||
test_results.as_array().unwrap()[0]
|
||||
.get("errorMessage")
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
);
|
||||
};
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn test_all_indexers(&mut self) {
|
||||
info!("Testing all indexers");
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ mod test {
|
||||
#[case(RadarrEvent::GetTags, "/tag")]
|
||||
#[case(RadarrEvent::GetTasks, "/system/task")]
|
||||
#[case(RadarrEvent::GetUpdates, "/update")]
|
||||
#[case(RadarrEvent::TestIndexer, "/indexer/test")]
|
||||
#[case(RadarrEvent::TestAllIndexers, "/indexer/testall")]
|
||||
#[case(RadarrEvent::HealthCheck, "/health")]
|
||||
fn test_resource(#[case] event: RadarrEvent, #[case] expected_uri: String) {
|
||||
@@ -686,6 +687,139 @@ mod test {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_test_indexer_event_error() {
|
||||
let indexer_details_json = json!({
|
||||
"enableRss": true,
|
||||
"enableAutomaticSearch": true,
|
||||
"enableInteractiveSearch": true,
|
||||
"name": "Test Indexer",
|
||||
"fields": [
|
||||
{
|
||||
"name": "baseUrl",
|
||||
"value": "https://test.com",
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "seedCriteria.seedRatio",
|
||||
"value": "1.2",
|
||||
},
|
||||
],
|
||||
"tags": [1],
|
||||
"id": 1
|
||||
});
|
||||
let response_json = json!([
|
||||
{
|
||||
"isWarning": false,
|
||||
"propertyName": "",
|
||||
"errorMessage": "test failure",
|
||||
"severity": "error"
|
||||
}]);
|
||||
let resource = format!("{}/1", RadarrEvent::GetIndexers.resource());
|
||||
let (async_details_server, app_arc, mut server) = mock_radarr_api(
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(indexer_details_json.clone()),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
let async_test_server = server
|
||||
.mock(
|
||||
"POST",
|
||||
format!("/api/v3{}", RadarrEvent::TestIndexer.resource()).as_str(),
|
||||
)
|
||||
.with_status(400)
|
||||
.match_header("X-Api-Key", "test1234")
|
||||
.match_body(Matcher::Json(indexer_details_json))
|
||||
.with_body(response_json.to_string())
|
||||
.create_async()
|
||||
.await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexers
|
||||
.set_items(vec![indexer()]);
|
||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||
|
||||
network.handle_radarr_event(RadarrEvent::TestIndexer).await;
|
||||
|
||||
async_details_server.assert_async().await;
|
||||
async_test_server.assert_async().await;
|
||||
assert_eq!(
|
||||
app_arc.lock().await.data.radarr_data.indexer_test_error,
|
||||
Some("\"test failure\"".to_owned())
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_test_indexer_event_success() {
|
||||
let indexer_details_json = json!({
|
||||
"enableRss": true,
|
||||
"enableAutomaticSearch": true,
|
||||
"enableInteractiveSearch": true,
|
||||
"name": "Test Indexer",
|
||||
"fields": [
|
||||
{
|
||||
"name": "baseUrl",
|
||||
"value": "https://test.com",
|
||||
},
|
||||
{
|
||||
"name": "apiKey",
|
||||
"value": "",
|
||||
},
|
||||
{
|
||||
"name": "seedCriteria.seedRatio",
|
||||
"value": "1.2",
|
||||
},
|
||||
],
|
||||
"tags": [1],
|
||||
"id": 1
|
||||
});
|
||||
let resource = format!("{}/1", RadarrEvent::GetIndexers.resource());
|
||||
let (async_details_server, app_arc, mut server) = mock_radarr_api(
|
||||
RequestMethod::Get,
|
||||
None,
|
||||
Some(indexer_details_json.clone()),
|
||||
None,
|
||||
&resource,
|
||||
)
|
||||
.await;
|
||||
let async_test_server = server
|
||||
.mock(
|
||||
"POST",
|
||||
format!("/api/v3{}", RadarrEvent::TestIndexer.resource()).as_str(),
|
||||
)
|
||||
.with_status(200)
|
||||
.match_header("X-Api-Key", "test1234")
|
||||
.match_body(Matcher::Json(indexer_details_json))
|
||||
.with_body("{}")
|
||||
.create_async()
|
||||
.await;
|
||||
app_arc
|
||||
.lock()
|
||||
.await
|
||||
.data
|
||||
.radarr_data
|
||||
.indexers
|
||||
.set_items(vec![indexer()]);
|
||||
let mut network = Network::new(&app_arc, CancellationToken::new());
|
||||
|
||||
network.handle_radarr_event(RadarrEvent::TestIndexer).await;
|
||||
|
||||
async_details_server.assert_async().await;
|
||||
async_test_server.assert_async().await;
|
||||
assert_eq!(
|
||||
app_arc.lock().await.data.radarr_data.indexer_test_error,
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_handle_test_all_indexers_event() {
|
||||
let indexers = vec![
|
||||
|
||||
@@ -13,8 +13,8 @@ use crate::ui::radarr_ui::collections::edit_collection_ui::EditCollectionUi;
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
||||
use crate::ui::widgets::error_message::ErrorMessage;
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi};
|
||||
|
||||
@@ -52,7 +52,7 @@ impl DrawUi for CollectionsUi {
|
||||
Size::InputBox,
|
||||
),
|
||||
ActiveRadarrBlock::SearchCollectionError => {
|
||||
let popup = Popup::new(ErrorMessage::new("Collection not found!")).size(Size::Error);
|
||||
let popup = Popup::new(Message::new("Collection not found!")).size(Size::Message);
|
||||
|
||||
draw_collections(f, app, area);
|
||||
f.render_widget(popup, f.size());
|
||||
@@ -66,10 +66,10 @@ impl DrawUi for CollectionsUi {
|
||||
Size::InputBox,
|
||||
),
|
||||
ActiveRadarrBlock::FilterCollectionsError => {
|
||||
let popup = Popup::new(ErrorMessage::new(
|
||||
let popup = Popup::new(Message::new(
|
||||
"No collections found matching the given filter!",
|
||||
))
|
||||
.size(Size::Error);
|
||||
.size(Size::Message);
|
||||
|
||||
draw_collections(f, app, area);
|
||||
f.render_widget(popup, f.size());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use ratatui::layout::{Constraint, Rect};
|
||||
use ratatui::style::{Style, Stylize};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Cell, Row};
|
||||
use ratatui::Frame;
|
||||
@@ -11,9 +12,11 @@ use crate::ui::radarr_ui::indexers::edit_indexer_ui::EditIndexerUi;
|
||||
use crate::ui::radarr_ui::indexers::indexer_settings_ui::IndexerSettingsUi;
|
||||
use crate::ui::radarr_ui::indexers::test_all_indexers_ui::TestAllIndexersUi;
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::layout_block_top_border;
|
||||
use crate::ui::utils::{layout_block_top_border, 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::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use crate::ui::DrawUi;
|
||||
|
||||
@@ -43,6 +46,28 @@ impl DrawUi for IndexersUi {
|
||||
let route = *app.get_current_route();
|
||||
let mut indexers_matchers = |active_radarr_block| match active_radarr_block {
|
||||
ActiveRadarrBlock::Indexers => draw_indexers(f, app, area),
|
||||
ActiveRadarrBlock::TestIndexer => {
|
||||
draw_indexers(f, app, area);
|
||||
if app.is_loading {
|
||||
let loading_popup = Popup::new(LoadingBlock::new(
|
||||
app.is_loading,
|
||||
title_block("Testing Indexer"),
|
||||
))
|
||||
.size(Size::LargeMessage);
|
||||
f.render_widget(loading_popup, f.size());
|
||||
} else {
|
||||
let popup = if let Some(result) = app.data.radarr_data.indexer_test_error.as_ref() {
|
||||
Popup::new(Message::new(result.clone())).size(Size::LargeMessage)
|
||||
} else {
|
||||
let message = Message::new("Indexer test succeeded!")
|
||||
.title("Success")
|
||||
.style(Style::new().success().bold());
|
||||
Popup::new(message).size(Size::Message)
|
||||
};
|
||||
|
||||
f.render_widget(popup, f.size());
|
||||
}
|
||||
}
|
||||
ActiveRadarrBlock::DeleteIndexerPrompt => {
|
||||
let prompt = format!(
|
||||
"Do you really want to delete this indexer: \n{}?",
|
||||
|
||||
@@ -17,9 +17,9 @@ use crate::ui::utils::{
|
||||
title_block_centered,
|
||||
};
|
||||
use crate::ui::widgets::button::Button;
|
||||
use crate::ui::widgets::error_message::ErrorMessage;
|
||||
use crate::ui::widgets::input_box::InputBox;
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use crate::ui::widgets::selectable_list::SelectableList;
|
||||
use crate::ui::{draw_popup_over, DrawUi};
|
||||
@@ -79,8 +79,7 @@ impl DrawUi for AddMovieUi {
|
||||
ActiveRadarrBlock::AddMovieAlreadyInLibrary => {
|
||||
draw_add_movie_search(f, app, area);
|
||||
f.render_widget(
|
||||
Popup::new(ErrorMessage::new("This film is already in your library"))
|
||||
.size(Size::Error),
|
||||
Popup::new(Message::new("This film is already in your library")).size(Size::Message),
|
||||
f.size(),
|
||||
);
|
||||
}
|
||||
@@ -220,8 +219,8 @@ fn draw_add_movie_search(f: &mut Frame<'_>, app: &mut App<'_>, area: Rect) {
|
||||
let help_paragraph = Paragraph::new(help_text)
|
||||
.block(borderless_block())
|
||||
.alignment(Alignment::Center);
|
||||
let error_message = ErrorMessage::new("No movies found matching your query!");
|
||||
let error_message_popup = Popup::new(error_message).size(Size::Error);
|
||||
let error_message = Message::new("No movies found matching your query!");
|
||||
let error_message_popup = Popup::new(error_message).size(Size::Message);
|
||||
|
||||
f.render_widget(layout_block(), results_area);
|
||||
f.render_widget(error_message_popup, f.size());
|
||||
|
||||
@@ -13,8 +13,8 @@ use crate::ui::radarr_ui::library::edit_movie_ui::EditMovieUi;
|
||||
use crate::ui::radarr_ui::library::movie_details_ui::MovieDetailsUi;
|
||||
use crate::ui::utils::{get_width_from_percentage, layout_block_top_border};
|
||||
use crate::ui::widgets::confirmation_prompt::ConfirmationPrompt;
|
||||
use crate::ui::widgets::error_message::ErrorMessage;
|
||||
use crate::ui::widgets::managarr_table::ManagarrTable;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use crate::ui::widgets::popup::{Popup, Size};
|
||||
use crate::ui::{draw_input_box_popup, draw_popup_over, DrawUi};
|
||||
use crate::utils::{convert_runtime, convert_to_gb};
|
||||
@@ -57,7 +57,7 @@ impl DrawUi for LibraryUi {
|
||||
Size::InputBox,
|
||||
),
|
||||
ActiveRadarrBlock::SearchMovieError => {
|
||||
let popup = Popup::new(ErrorMessage::new("Movie not found!")).size(Size::Error);
|
||||
let popup = Popup::new(Message::new("Movie not found!")).size(Size::Message);
|
||||
|
||||
draw_library(f, app, area);
|
||||
f.render_widget(popup, f.size());
|
||||
@@ -71,10 +71,8 @@ impl DrawUi for LibraryUi {
|
||||
Size::InputBox,
|
||||
),
|
||||
ActiveRadarrBlock::FilterMoviesError => {
|
||||
let popup = Popup::new(ErrorMessage::new(
|
||||
"No movies found matching the given filter!",
|
||||
))
|
||||
.size(Size::Error);
|
||||
let popup = Popup::new(Message::new("No movies found matching the given filter!"))
|
||||
.size(Size::Message);
|
||||
|
||||
draw_library(f, app, area);
|
||||
f.render_widget(popup, f.size());
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::title_block_centered;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::{Alignment, Rect};
|
||||
use ratatui::style::Stylize;
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Paragraph, Widget};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "error_message_tests.rs"]
|
||||
mod error_message_tests;
|
||||
|
||||
pub struct ErrorMessage<'a> {
|
||||
text: Text<'a>,
|
||||
}
|
||||
|
||||
impl<'a> ErrorMessage<'a> {
|
||||
pub fn new<T>(message: T) -> Self
|
||||
where
|
||||
T: Into<Text<'a>>,
|
||||
{
|
||||
ErrorMessage {
|
||||
text: message.into(),
|
||||
}
|
||||
}
|
||||
|
||||
fn render_error_message(self, area: Rect, buf: &mut Buffer) {
|
||||
Paragraph::new(self.text)
|
||||
.failure()
|
||||
.alignment(Alignment::Center)
|
||||
.block(title_block_centered("Error").failure().bold())
|
||||
.render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for ErrorMessage<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
self.render_error_message(area, buf);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ui::widgets::error_message::ErrorMessage;
|
||||
use pretty_assertions::assert_eq;
|
||||
use ratatui::text::Text;
|
||||
|
||||
#[test]
|
||||
fn test_error_message_new() {
|
||||
let message = "This is an error message";
|
||||
let error_message = ErrorMessage::new(message);
|
||||
|
||||
assert_eq!(error_message.text, Text::from(message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::utils::title_block_centered;
|
||||
use ratatui::buffer::Buffer;
|
||||
use ratatui::layout::{Alignment, Rect};
|
||||
use ratatui::style::{Style, Stylize};
|
||||
use ratatui::text::Text;
|
||||
use ratatui::widgets::{Paragraph, Widget, Wrap};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "message_tests.rs"]
|
||||
mod message_tests;
|
||||
|
||||
pub struct Message<'a> {
|
||||
text: Text<'a>,
|
||||
title: &'a str,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl<'a> Message<'a> {
|
||||
pub fn new<T>(message: T) -> Self
|
||||
where
|
||||
T: Into<Text<'a>>,
|
||||
{
|
||||
Message {
|
||||
text: message.into(),
|
||||
title: "Error",
|
||||
style: Style::new().failure().bold(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn title(mut self, title: &'a str) -> Self {
|
||||
self.title = title;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn style(mut self, style: Style) -> Self {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
fn render_message(self, area: Rect, buf: &mut Buffer) {
|
||||
Paragraph::new(self.text)
|
||||
.style(self.style)
|
||||
.alignment(Alignment::Center)
|
||||
.block(title_block_centered(self.title).style(self.style))
|
||||
.wrap(Wrap { trim: true })
|
||||
.render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Message<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
self.render_message(area, buf);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::ui::styles::ManagarrStyle;
|
||||
use crate::ui::widgets::message::Message;
|
||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||
use ratatui::style::{Style, Stylize};
|
||||
use ratatui::text::Text;
|
||||
|
||||
#[test]
|
||||
fn test_error_message_new() {
|
||||
let test_message = "This is a message";
|
||||
|
||||
let message = Message::new(test_message);
|
||||
|
||||
assert_eq!(message.text, Text::from(test_message));
|
||||
assert_str_eq!(message.title, "Error");
|
||||
assert_eq!(message.style, Style::new().failure().bold());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_title() {
|
||||
let test_message = "This is a message";
|
||||
let title = "Success";
|
||||
|
||||
let message = Message::new(test_message).title(title);
|
||||
|
||||
assert_str_eq!(message.title, title);
|
||||
assert_eq!(message.text, Text::from(test_message));
|
||||
assert_eq!(message.style, Style::new().failure().bold());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_message_style() {
|
||||
let test_message = "This is a message";
|
||||
let style = Style::new().success().bold();
|
||||
|
||||
let message = Message::new(test_message).style(style);
|
||||
|
||||
assert_eq!(message.style, style);
|
||||
assert_eq!(message.text, Text::from(test_message));
|
||||
assert_str_eq!(message.title, "Error");
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
pub(super) mod button;
|
||||
pub(super) mod checkbox;
|
||||
pub(super) mod confirmation_prompt;
|
||||
pub(super) mod error_message;
|
||||
pub(super) mod input_box;
|
||||
pub(super) mod loading_block;
|
||||
pub(super) mod managarr_table;
|
||||
pub(super) mod message;
|
||||
pub(super) mod popup;
|
||||
pub(super) mod selectable_list;
|
||||
|
||||
@@ -12,7 +12,8 @@ mod popup_tests;
|
||||
pub enum Size {
|
||||
Prompt,
|
||||
LargePrompt,
|
||||
Error,
|
||||
Message,
|
||||
LargeMessage,
|
||||
InputBox,
|
||||
Dropdown,
|
||||
Small,
|
||||
@@ -25,7 +26,8 @@ impl Size {
|
||||
match self {
|
||||
Size::Prompt => (35, 35),
|
||||
Size::LargePrompt => (70, 45),
|
||||
Size::Error => (25, 8),
|
||||
Size::Message => (25, 8),
|
||||
Size::LargeMessage => (25, 25),
|
||||
Size::InputBox => (30, 13),
|
||||
Size::Dropdown => (20, 30),
|
||||
Size::Small => (40, 40),
|
||||
|
||||
@@ -8,7 +8,8 @@ mod tests {
|
||||
fn test_dimensions_to_percent() {
|
||||
assert_eq!(Size::Prompt.to_percent(), (35, 35));
|
||||
assert_eq!(Size::LargePrompt.to_percent(), (70, 45));
|
||||
assert_eq!(Size::Error.to_percent(), (25, 8));
|
||||
assert_eq!(Size::Message.to_percent(), (25, 8));
|
||||
assert_eq!(Size::LargeMessage.to_percent(), (25, 25));
|
||||
assert_eq!(Size::InputBox.to_percent(), (30, 13));
|
||||
assert_eq!(Size::Dropdown.to_percent(), (20, 30));
|
||||
assert_eq!(Size::Small.to_percent(), (40, 40));
|
||||
|
||||
Reference in New Issue
Block a user