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.
This commit is contained in:
Leosvel Pérez Espinosa 2025-06-20 10:12:38 +02:00 committed by GitHub
parent bd898d3220
commit 6b2175bfcb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 1 deletions

View File

@ -37,4 +37,5 @@ pub enum Action {
ToggleDebugMode,
SendConsoleMessage(String),
ConsoleMessengerAvailable(bool),
EndCommand,
}

View File

@ -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<String> {
self.components
.iter()
.find_map(|c| c.as_any().downcast_ref::<TasksList>())
.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];