mirror of
https://github.com/openai/codex.git
synced 2026-09-20 12:47:38 +00:00
Show a loading message when opening tasks from the agents overview (#45983)
## Why Task attachment awaits server requests while the event handler cannot process scheduled frames. Prompts and chat widget replacement can also clear the terminal during loading. ## What changed Draw a bold `Loading task…` message immediately when attaching a task, and redraw it after folder selection, trust prompts, and chat widget replacement. Schedule a frame to restore the normal view afterward. ## Testing Extend the cold-resume test to verify that a loading message appears before server requests complete, survives widget replacement, and is replaced on the next draw. GitOrigin-RevId: cb2e73efe38758025964aa53f52127a2b2609fca
This commit is contained in:
@@ -8,6 +8,9 @@ pub(crate) use new::PendingWorktree;
|
||||
#[path = "agents_overview_errors.rs"]
|
||||
mod errors;
|
||||
|
||||
#[path = "agents_overview_loading.rs"]
|
||||
mod loading;
|
||||
|
||||
use super::agents_overview_view::AgentsOverviewGroup;
|
||||
use super::agents_overview_view::AgentsOverviewRow;
|
||||
use super::agents_overview_view::AgentsOverviewView;
|
||||
@@ -332,6 +335,7 @@ impl App {
|
||||
self.chat_widget.pre_draw_tick();
|
||||
return Ok(AppRunControl::Continue);
|
||||
}
|
||||
loading::draw(tui)?;
|
||||
if self.primary_thread_id != Some(root_thread_id) {
|
||||
let previous_displayed_thread_id = self.current_displayed_thread_id();
|
||||
if let Some(id) = previous_displayed_thread_id
|
||||
@@ -456,6 +460,8 @@ impl App {
|
||||
}
|
||||
local_settings = crate::local_settings::LocalSettings::from(&resume_config);
|
||||
}
|
||||
// Folder selection and trust prompts can replace or clear the loading frame.
|
||||
loading::draw(tui)?;
|
||||
let baseline_approval = resume_config.permissions.approval_policy.value();
|
||||
let baseline_permissions =
|
||||
RuntimePermissionProfileOverride::from_config(&resume_config);
|
||||
@@ -608,6 +614,8 @@ impl App {
|
||||
self.add_agents_overview_error(format!("Failed to attach to task: {error}"));
|
||||
return Ok(AppRunControl::Continue);
|
||||
}
|
||||
// Replacing the widget clears the terminal before the remaining server requests.
|
||||
loading::draw(tui)?;
|
||||
if read_only {
|
||||
self.ensure_thread_channel(root_thread_id)
|
||||
.mark_external_writer();
|
||||
|
||||
19
codex-rs/tui/src/app/agents_overview_loading.rs
Normal file
19
codex-rs/tui/src/app/agents_overview_loading.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
//! Transient feedback while command-center selection waits for a session to load.
|
||||
//! Draw directly because the app event handler cannot process scheduled frames while awaiting.
|
||||
|
||||
use crate::tui::Tui;
|
||||
use ratatui::style::Stylize;
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::Paragraph;
|
||||
|
||||
pub(super) fn draw(tui: &mut Tui) -> std::io::Result<()> {
|
||||
tui.draw(u16::MAX, |frame| {
|
||||
let lines = textwrap::wrap("Loading task…", usize::from(frame.area().width.max(1)))
|
||||
.into_iter()
|
||||
.map(|line| Line::from(line.into_owned().bold()))
|
||||
.collect::<Vec<_>>();
|
||||
frame.render_widget_ref(&Paragraph::new(lines), frame.area());
|
||||
})?;
|
||||
tui.frame_requester().schedule_frame();
|
||||
Ok(())
|
||||
}
|
||||
@@ -1830,8 +1830,40 @@ async fn overview_cold_resume_honors_working_directory_selection() -> Result<()>
|
||||
test_path_buf("/").abs()
|
||||
};
|
||||
let mut tui = crate::tui::test_support::make_test_tui()?;
|
||||
// On this current-thread runtime, the server cannot answer until we yield. Cancel the
|
||||
// pending selection to release its terminal borrow and inspect what the user sees now.
|
||||
let mut selection =
|
||||
Box::pin(app.select_agents_overview_thread(&mut tui, &mut app_server, thread_id));
|
||||
assert!(futures::poll!(&mut selection).is_pending());
|
||||
drop(selection);
|
||||
let pending_loading =
|
||||
crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal).clone();
|
||||
app.select_agents_overview_thread(&mut tui, &mut app_server, thread_id)
|
||||
.await?;
|
||||
// The widget replacement clears the terminal; feedback must remain until the next draw.
|
||||
let loading =
|
||||
crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal).clone();
|
||||
assert_eq!(pending_loading, loading);
|
||||
let loading_text = loading
|
||||
.content
|
||||
.chunks(usize::from(loading.area.width))
|
||||
.map(|row| {
|
||||
row.iter()
|
||||
.map(ratatui::buffer::Cell::symbol)
|
||||
.collect::<String>()
|
||||
})
|
||||
.map(|line| line.trim_end().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(loading_text.trim_end(), @"Loading task…");
|
||||
}
|
||||
app.handle_tui_event(&mut tui, &mut app_server, TuiEvent::Draw)
|
||||
.await?;
|
||||
assert_ne!(
|
||||
crate::custom_terminal::test_support::last_rendered_buffer(&tui.terminal),
|
||||
&loading,
|
||||
);
|
||||
let observed = app_server
|
||||
.resume_thread(
|
||||
&app.local_settings,
|
||||
|
||||
Reference in New Issue
Block a user