Compare commits

...

1 Commits

Author SHA1 Message Date
Ahmed Ibrahim
07493e40ad TUI: reset running state after undo 2026-01-27 12:17:44 -08:00
2 changed files with 49 additions and 4 deletions

View File

@@ -1576,7 +1576,10 @@ impl ChatWidget {
fn on_undo_started(&mut self, event: UndoStartedEvent) {
self.bottom_pane.ensure_status_indicator();
self.bottom_pane.set_interrupt_hint_visible(false);
self.agent_turn_running = true;
self.update_task_running_state();
self.bottom_pane.set_interrupt_hint_visible(true);
self.request_redraw();
let message = event
.message
.unwrap_or_else(|| "Undo in progress...".to_string());
@@ -1585,6 +1588,8 @@ impl ChatWidget {
fn on_undo_completed(&mut self, event: UndoCompletedEvent) {
let UndoCompletedEvent { success, message } = event;
self.agent_turn_running = false;
self.update_task_running_state();
self.bottom_pane.hide_status_indicator();
let message = message.unwrap_or_else(|| {
if success {
@@ -1598,6 +1603,7 @@ impl ChatWidget {
} else {
self.add_error_message(message);
}
self.maybe_send_next_queued_input();
}
fn on_stream_error(&mut self, message: String, additional_details: Option<String>) {

View File

@@ -2536,6 +2536,45 @@ async fn undo_success_events_render_info_messages() {
);
}
#[tokio::test]
async fn undo_completed_clears_running_and_sends_next_queued_input() {
let (mut chat, _rx, mut op_rx) = make_chatwidget_manual(None).await;
chat.thread_id = Some(ThreadId::new());
chat.agent_turn_running = true;
chat.update_task_running_state();
assert!(chat.bottom_pane.is_task_running());
chat.queue_user_message(UserMessage {
text: "next".to_string(),
local_images: Vec::new(),
text_elements: Vec::new(),
});
assert_eq!(chat.queued_user_messages.len(), 1);
chat.handle_codex_event(Event {
id: "undo-complete".to_string(),
msg: EventMsg::UndoCompleted(UndoCompletedEvent {
success: true,
message: None,
}),
});
assert!(!chat.bottom_pane.is_task_running());
assert!(chat.queued_user_messages.is_empty());
let op = next_submit_op(&mut op_rx);
let actual_items = match op {
Op::UserTurn { items, .. } => items,
other => panic!("expected Op::UserTurn, got {other:?}"),
};
let expected_items = vec![UserInput::Text {
text: "next".to_string(),
text_elements: Vec::new(),
}];
assert_eq!(actual_items, expected_items);
}
#[tokio::test]
async fn undo_failure_events_render_error_message() {
let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(None).await;
@@ -2572,7 +2611,7 @@ async fn undo_failure_events_render_error_message() {
}
#[tokio::test]
async fn undo_started_hides_interrupt_hint() {
async fn undo_started_shows_interrupt_hint() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(None).await;
chat.handle_codex_event(Event {
@@ -2585,8 +2624,8 @@ async fn undo_started_hides_interrupt_hint() {
.status_widget()
.expect("status indicator should be active");
assert!(
!status.interrupt_hint_visible(),
"undo should hide the interrupt hint because the operation cannot be cancelled"
status.interrupt_hint_visible(),
"undo should show the interrupt hint while work is in progress"
);
}