fix: Enable quit on Docker connect error screen

This commit is contained in:
Jack Wills
2026-02-07 12:52:35 +00:00
parent ae7f3f4a94
commit 5f942eb2e9
7 changed files with 87 additions and 64 deletions
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+15 -11
View File
@@ -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<String> {
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()),
+20 -15
View File
@@ -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,6 +55,8 @@ 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)
@@ -61,12 +65,7 @@ pub fn draw(
} else {
format!(" ( {} ) {SUFFIX_QUIT}", keymap.quit.0)
};
format!("\n\n{clear_text}\n\n{quit_text}")
};
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,21 +129,24 @@ 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) {
match (row_index, result_cell_index) {
(0 | 10, _) | (_, 0 | 49) => {
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);
}
}
}
}
}
#[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,16 +164,19 @@ 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) {
match (row_index, result_cell_index) {
(0 | 10, _) | (_, 0 | 59) => {
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);
}
}
}
}
}
#[test]
/// Test that the clearable error popup is centered, red background, white border, white text, and displays the correct text
@@ -3,11 +3,13 @@ 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 │ "
" │ │ "
" ╰──────────────────────────────────────────────╯ "
" "
@@ -3,11 +3,13 @@ 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 │ "
" │ │ "
" ╰────────────────────────────────────────────────────────╯ "
" "
+14 -4
View File
@@ -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<String>) -> Result<(), AppError> {
async fn err_loop(&mut self, host: Option<String>) -> 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?;
}