From 6b2175bfcbd4f2b30cf84aca71319c635dd73cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Fri, 20 Jun 2025 10:12:38 +0200 Subject: [PATCH] fix(core): do not auto-exit tui when there are multiple failed tasks (#31631) ## Current Behavior When the user hasn't interacted with the TUI and has not disabled the auto-exit functionality, it will always auto-exit regardless of the number of failed tasks. ## Expected Behavior When the user hasn't interacted with the TUI and has not disabled the auto-exit functionality, it should not auto-exit if there are multiple failed tasks. Additionally, as long as no terminal output panes are open (e.g., the run one command will always display the initiating task terminal pane), it should focus and open the first failed task. If all tasks succeed or there's only one failure, it should continue to auto-exit. --- packages/nx/src/native/tui/action.rs | 1 + packages/nx/src/native/tui/app.rs | 42 +++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/nx/src/native/tui/action.rs b/packages/nx/src/native/tui/action.rs index 12598a2207..bfd1fa6949 100644 --- a/packages/nx/src/native/tui/action.rs +++ b/packages/nx/src/native/tui/action.rs @@ -37,4 +37,5 @@ pub enum Action { ToggleDebugMode, SendConsoleMessage(String), ConsoleMessengerAvailable(bool), + EndCommand, } diff --git a/packages/nx/src/native/tui/app.rs b/packages/nx/src/native/tui/app.rs index 68108e9b27..783073cf59 100644 --- a/packages/nx/src/native/tui/app.rs +++ b/packages/nx/src/native/tui/app.rs @@ -229,11 +229,32 @@ impl App { .as_ref() .and_then(|c| c.end_running_tasks()); - // If the user has interacted with the app, or auto-exit is disabled, do nothing + self.dispatch_action(Action::EndCommand); + } + + // Internal method to handle Action::EndCommand + fn handle_end_command(&mut self) { + // If the user has interacted with the app or auto-exit is disabled, do nothing if self.user_has_interacted || !self.tui_config.auto_exit.should_exit_automatically() { return; } + let failed_task_names = self.get_failed_task_names(); + // If there are more than 1 failed tasks, do not auto-exit + if failed_task_names.len() > 1 { + // If there are no visible panes (e.g. run one would have a pane open by default), focus the first failed task + if !self.has_visible_panes() { + self.selection_manager + .lock() + .unwrap() + .select_task(failed_task_names.first().unwrap().clone()); + + // Display the task logs but keep focus on the task list to allow the user to navigate the failed tasks + self.toggle_output_visibility(); + } + return; + } + if self.tasks.len() > 1 { self.begin_exit_countdown() } else { @@ -1070,6 +1091,9 @@ impl App { trace!("No console connection available"); } } + Action::EndCommand => { + self.handle_end_command(); + } _ => {} } @@ -1138,6 +1162,22 @@ impl App { self.pane_tasks.iter().any(|t| t.is_some()) } + /// Returns the names of tasks that have failed. + fn get_failed_task_names(&self) -> Vec { + self.components + .iter() + .find_map(|c| c.as_any().downcast_ref::()) + .map(|tasks_list| { + tasks_list + .tasks + .iter() + .filter(|task| task.status == TaskStatus::Failure) + .map(|task| task.name.clone()) + .collect() + }) + .unwrap_or_else(Vec::new) + } + /// Clears all output panes and resets their associated state. fn clear_all_panes(&mut self) { self.pane_tasks = [None, None];