From 5f942eb2e963660bd7fe9d80fa7ba8a83754803a Mon Sep 17 00:00:00 2001 From: Jack Wills <32690432+mrjackwills@users.noreply.github.com> Date: Sat, 7 Feb 2026 12:52:35 +0000 Subject: [PATCH] fix: Enable quit on Docker connect error screen --- src/app_data/container_state.rs | 2 +- src/app_error.rs | 2 +- src/main.rs | 26 ++++---- src/ui/draw_blocks/error.rs | 63 ++++++++++--------- ...raw_blocks_error_docker_connect_error.snap | 20 +++--- ...rror_docker_connect_error_custom_host.snap | 20 +++--- src/ui/mod.rs | 18 ++++-- 7 files changed, 87 insertions(+), 64 deletions(-) diff --git a/src/app_data/container_state.rs b/src/app_data/container_state.rs index 547c578..6125db1 100644 --- a/src/app_data/container_state.rs +++ b/src/app_data/container_state.rs @@ -420,7 +420,7 @@ impl fmt::Display for State { } /// Items for the container control list -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum DockerCommand { Pause, Restart, diff --git a/src/app_error.rs b/src/app_error.rs index 74d7d3c..ce4b5f6 100644 --- a/src/app_error.rs +++ b/src/app_error.rs @@ -2,7 +2,7 @@ use crate::app_data::DockerCommand; use std::fmt; /// app errors to set in global state -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum AppError { DockerCommand(DockerCommand), DockerExec, diff --git a/src/main.rs b/src/main.rs index 4a42ce1..8ad73f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,15 +42,17 @@ fn setup_tracing() { tracing_subscriber::fmt().with_max_level(Level::INFO).init(); } -/// Read the optional docker_host path, the DOCKER_HOST env take priority over cli or config +/// Read the optional docker_host path /// Bollard will use DOCKER_HOST env, so might be pointless here, although it will fix it's priority over any config setting fn read_docker_host(config: &Config) -> Option { - if let Ok(env) = std::env::var(DOCKER_HOST) + if let Some(x) = &config.host { + Some(x.to_string()) + } else if let Ok(env) = std::env::var(DOCKER_HOST) && !env.trim().is_empty() { Some(env) } else { - config.host.as_ref().cloned() + None } } @@ -174,23 +176,24 @@ mod tests { /// Default test config, has timestamps turned off pub fn gen_config() -> Config { Config { + app_colors: AppColors::new(), color_logs: false, + dir_save: None, + dir_config: None, docker_interval_ms: 1000, gui: true, host: None, - show_std_err: false, in_container: false, - save_dir: None, + keymap: Keymap::new(), log_search_case_sensitive: true, raw_logs: false, - show_self: false, - app_colors: AppColors::new(), - keymap: Keymap::new(), - timestamp_format: "HH:MM:SS.NNNNN dd-mm-yyyy".to_owned(), - show_timestamp: false, - use_cli: false, show_logs: true, + show_self: false, + show_std_err: false, + show_timestamp: false, + timestamp_format: "HH:MM:SS.NNNNN dd-mm-yyyy".to_owned(), timezone: None, + use_cli: false, } } @@ -216,6 +219,7 @@ mod tests { containers: StatefulList::new(containers.to_vec()), hidden_containers: vec![], current_sorted_id: vec![], + inspect_data: None, error: None, sorted_by: None, rerender: Arc::new(Rerender::new()), diff --git a/src/ui/draw_blocks/error.rs b/src/ui/draw_blocks/error.rs index b2c1381..01a2d55 100644 --- a/src/ui/draw_blocks/error.rs +++ b/src/ui/draw_blocks/error.rs @@ -32,19 +32,21 @@ pub fn draw( .title_alignment(Alignment::Center) .borders(Borders::ALL); - let to_push = if matches!(error, AppError::DockerConnect) { + let mut text = format!("\n{error}"); + + if error == &AppError::DockerConnect { let s = if let Some(host) = host { format!(" @ \"{host}\"") } else { String::new() }; - format!( + text.push_str(&format!( "{}\n\n {}::v{} closing in {:02} seconds", s, NAME, VERSION, seconds.unwrap_or(5), - ) + )) } else { let clear_text = if keymap.clear == Keymap::new().clear { format!("( {} ) {SUFFIX_CLEAR}", keymap.clear.0) @@ -53,20 +55,17 @@ pub fn draw( } else { format!(" ( {} ) {SUFFIX_CLEAR}", keymap.clear.0) }; + text.push_str(&format!("\n\n{clear_text}")); + } - let quit_text = if keymap.quit == Keymap::new().quit { - format!("( {} ) {SUFFIX_QUIT}", keymap.quit.0) - } else if let Some(secondary) = keymap.quit.1 { - format!(" ( {} | {secondary} ) {SUFFIX_QUIT}", keymap.quit.0) - } else { - format!(" ( {} ) {SUFFIX_QUIT}", keymap.quit.0) - }; - format!("\n\n{clear_text}\n\n{quit_text}") + let quit_text = if keymap.quit == Keymap::new().quit { + format!("( {} ) {SUFFIX_QUIT}", keymap.quit.0) + } else if let Some(secondary) = keymap.quit.1 { + format!(" ( {} | {secondary} ) {SUFFIX_QUIT}", keymap.quit.0) + } else { + format!(" ( {} ) {SUFFIX_QUIT}", keymap.quit.0) }; - - let mut text = format!("\n{error}"); - - text.push_str(to_push.as_str()); + text.push_str(&format!("\n\n{quit_text}")); // Find the maximum line width & height let padded_width = max_line_width(&text) + 8; @@ -113,7 +112,7 @@ mod tests { #[test] /// Test that the error popup is centered, red background, white border, white text, and displays the correct text fn test_draw_blocks_error_docker_connect_error() { - let mut setup = test_setup(46, 9, true, true); + let mut setup = test_setup(50, 11, true, true); setup .terminal .draw(|f| { @@ -130,12 +129,15 @@ mod tests { assert_snapshot!(setup.terminal.backend()); for (row_index, result_row) in get_result(&setup) { for (result_cell_index, result_cell) in result_row.iter().enumerate() { - if let (0 | 8, _) = (row_index, result_cell_index) { - assert_eq!(result_cell.bg, Color::Reset); - assert_eq!(result_cell.fg, Color::Reset); - } else { - assert_eq!(result_cell.bg, Color::Red); - assert_eq!(result_cell.fg, Color::White); + match (row_index, result_cell_index) { + (0 | 10, _) | (_, 0 | 49) => { + assert_eq!(result_cell.bg, Color::Reset); + assert_eq!(result_cell.fg, Color::Reset); + } + _ => { + assert_eq!(result_cell.bg, Color::Red); + assert_eq!(result_cell.fg, Color::White); + } } } } @@ -144,7 +146,7 @@ mod tests { #[test] /// Test that the error popup is centered, red background, white border, white text, and displays the correct text with the custom docker host address fn test_draw_blocks_error_docker_connect_error_custom_host() { - let mut setup = test_setup(46, 9, true, true); + let mut setup = test_setup(60, 11, true, true); setup .terminal @@ -162,12 +164,15 @@ mod tests { assert_snapshot!(setup.terminal.backend()); for (row_index, result_row) in get_result(&setup) { for (result_cell_index, result_cell) in result_row.iter().enumerate() { - if let (0 | 8, _) = (row_index, result_cell_index) { - assert_eq!(result_cell.bg, Color::Reset); - assert_eq!(result_cell.fg, Color::Reset); - } else { - assert_eq!(result_cell.bg, Color::Red); - assert_eq!(result_cell.fg, Color::White); + match (row_index, result_cell_index) { + (0 | 10, _) | (_, 0 | 59) => { + assert_eq!(result_cell.bg, Color::Reset); + assert_eq!(result_cell.fg, Color::Reset); + } + _ => { + assert_eq!(result_cell.bg, Color::Red); + assert_eq!(result_cell.fg, Color::White); + } } } } diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error.snap index 629c56a..6bd72ae 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error.snap @@ -2,12 +2,14 @@ source: src/ui/draw_blocks/error.rs expression: setup.terminal.backend() --- -" " -"╭────────────────── Error ───────────────────╮" -"│ │" -"│ Unable to access docker daemon │" -"│ │" -"│ oxker::v0.00.000 closing in 04 seconds │" -"│ │" -"╰────────────────────────────────────────────╯" -" " +" " +" ╭─────────────────── Error ────────────────────╮ " +" │ │ " +" │ Unable to access docker daemon │ " +" │ │ " +" │ oxker::v0.00.000 closing in 04 seconds │ " +" │ │ " +" │ ( q ) quit oxker │ " +" │ │ " +" ╰──────────────────────────────────────────────╯ " +" " diff --git a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error_custom_host.snap b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error_custom_host.snap index 0cc412b..9dabfef 100644 --- a/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error_custom_host.snap +++ b/src/ui/draw_blocks/snapshots/oxker__ui__draw_blocks__error__tests__draw_blocks_error_docker_connect_error_custom_host.snap @@ -2,12 +2,14 @@ source: src/ui/draw_blocks/error.rs expression: setup.terminal.backend() --- -" " -"╭────────────────── Error ───────────────────╮" -"│ │" -"│Unable to access docker daemon @ "/test/host│" -"│ │" -"│ oxker::v0.00.000 closing in 04 seconds │" -"│ │" -"╰────────────────────────────────────────────╯" -" " +" " +" ╭──────────────────────── Error ─────────────────────────╮ " +" │ │ " +" │ Unable to access docker daemon @ "/test/host.sock" │ " +" │ │ " +" │ oxker::v0.00.000 closing in 04 seconds │ " +" │ │ " +" │ ( q ) quit oxker │ " +" │ │ " +" ╰────────────────────────────────────────────────────────╯ " +" " diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 734a9aa..914ffe6 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -131,12 +131,12 @@ impl Ui { } /// Draw the the error message ui, for 5 seconds, with a countdown - fn err_loop(&mut self, host: Option) -> Result<(), AppError> { + async fn err_loop(&mut self, host: Option) -> Result<(), AppError> { let mut seconds = 5; let colors = self.app_data.lock().config.app_colors; let keymap = self.app_data.lock().config.keymap.clone(); let mut redraw = true; - loop { + while self.is_running.load(Ordering::SeqCst) { if self.now.elapsed() >= std::time::Duration::from_secs(1) { seconds -= 1; self.now = Instant::now(); @@ -163,8 +163,18 @@ impl Ui { { return Err(AppError::Terminal); } + if crossterm::event::poll(POLL_RATE).unwrap_or(false) + && let Ok(event) = event::read() + && let Event::Key(key) = event + && key.kind == event::KeyEventKind::Press + { + self.input_tx + .send(InputMessages::ButtonPress((key.code, key.modifiers))) + .await + .ok(); + } redraw = false; - std::thread::sleep(POLL_RATE); + // std::thread::sleep(POLL_RATE); } Ok(()) } @@ -278,7 +288,7 @@ impl Ui { .iter() .find(|s| matches!(s, Status::DockerConnect(_))) { - self.err_loop(msg.clone())?; + self.err_loop(msg.clone()).await?; } else { self.gui_loop().await?; }