From a8a6cbdd1ce8ca3ba8f1184ede6c401078240d31 Mon Sep 17 00:00:00 2001 From: Weiller Carvalho <99501431+weillercarvalho@users.noreply.github.com> Date: Thu, 20 Nov 2025 18:20:03 -0300 Subject: [PATCH] fix: route feedback issue links by category (#6840) ## Summary - TUI feedback note now only links to the bug-report template when the category is bug/bad result. - Good result/other feedback shows a thank-you+thread ID instead of funneling people to file a bug. - Added a helper + unit test so future changes keep the behavior consistent. ## Testing - just fmt - just fix -p codex-tui - cargo test -p codex-tui Fixes #6839 --- codex-rs/tui/src/bottom_pane/feedback_view.rs | 58 ++++++++++++++++--- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/codex-rs/tui/src/bottom_pane/feedback_view.rs b/codex-rs/tui/src/bottom_pane/feedback_view.rs index a8476df0a..8a42e563c 100644 --- a/codex-rs/tui/src/bottom_pane/feedback_view.rs +++ b/codex-rs/tui/src/bottom_pane/feedback_view.rs @@ -26,7 +26,8 @@ use super::popup_consts::standard_popup_hint_line; use super::textarea::TextArea; use super::textarea::TextAreaState; -const BASE_ISSUE_URL: &str = "https://github.com/openai/codex/issues/new?template=2-bug-report.yml"; +const BASE_BUG_ISSUE_URL: &str = + "https://github.com/openai/codex/issues/new?template=2-bug-report.yml"; /// Minimal input overlay to collect an optional feedback note, then upload /// both logs and rollout with classification + metadata. @@ -88,26 +89,38 @@ impl FeedbackNoteView { match result { Ok(()) => { - let issue_url = format!("{BASE_ISSUE_URL}&steps=Uploaded%20thread:%20{thread_id}"); let prefix = if self.include_logs { "• Feedback uploaded." } else { "• Feedback recorded (no logs)." }; - self.app_event_tx.send(AppEvent::InsertHistoryCell(Box::new( - history_cell::PlainHistoryCell::new(vec![ - Line::from(format!( - "{prefix} Please open an issue using the following URL:" - )), + let issue_url = issue_url_for_category(self.category, &thread_id); + let mut lines = vec![Line::from(match issue_url.as_ref() { + Some(_) => format!("{prefix} Please open an issue using the following URL:"), + None => format!("{prefix} Thanks for the feedback!"), + })]; + if let Some(url) = issue_url { + lines.extend([ "".into(), - Line::from(vec![" ".into(), issue_url.cyan().underlined()]), + Line::from(vec![" ".into(), url.cyan().underlined()]), "".into(), Line::from(vec![ " Or mention your thread ID ".into(), std::mem::take(&mut thread_id).bold(), " in an existing issue.".into(), ]), - ]), + ]); + } else { + lines.extend([ + "".into(), + Line::from(vec![ + " Thread ID: ".into(), + std::mem::take(&mut thread_id).bold(), + ]), + ]); + } + self.app_event_tx.send(AppEvent::InsertHistoryCell(Box::new( + history_cell::PlainHistoryCell::new(lines), ))); } Err(e) => { @@ -320,6 +333,15 @@ fn feedback_classification(category: FeedbackCategory) -> &'static str { } } +fn issue_url_for_category(category: FeedbackCategory, thread_id: &str) -> Option { + match category { + FeedbackCategory::Bug | FeedbackCategory::BadResult | FeedbackCategory::Other => Some( + format!("{BASE_BUG_ISSUE_URL}&steps=Uploaded%20thread:%20{thread_id}"), + ), + FeedbackCategory::GoodResult => None, + } +} + // Build the selection popup params for feedback categories. pub(crate) fn feedback_selection_params( app_event_tx: AppEventSender, @@ -514,4 +536,22 @@ mod tests { let rendered = render(&view, 60); insta::assert_snapshot!("feedback_view_other", rendered); } + + #[test] + fn issue_url_available_for_bug_bad_result_and_other() { + let bug_url = issue_url_for_category(FeedbackCategory::Bug, "thread-1"); + assert!( + bug_url + .as_deref() + .is_some_and(|url| url.contains("template=2-bug-report")) + ); + + let bad_result_url = issue_url_for_category(FeedbackCategory::BadResult, "thread-2"); + assert!(bad_result_url.is_some()); + + let other_url = issue_url_for_category(FeedbackCategory::Other, "thread-3"); + assert!(other_url.is_some()); + + assert!(issue_url_for_category(FeedbackCategory::GoodResult, "t").is_none()); + } }