agent: Refine feedback message input (#27948)

<img
src="https://github.com/user-attachments/assets/cde37a88-9973-4c27-80b7-459f5e986c74"
width="650" />

Release Notes:

- N/A

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
This commit is contained in:
Danilo Leal 2025-04-02 17:41:07 -03:00 committed by GitHub
parent b9f10c0adb
commit d23c2d4b02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 105 additions and 76 deletions

View file

@ -657,6 +657,15 @@
"alt-enter": "editor::Newline" "alt-enter": "editor::Newline"
} }
}, },
{
"context": "AgentFeedbackMessageEditor > Editor",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel",
"enter": "menu::Confirm",
"alt-enter": "editor::Newline"
}
},
{ {
"context": "ContextStrip", "context": "ContextStrip",
"bindings": { "bindings": {

View file

@ -317,6 +317,15 @@
"alt-enter": "editor::Newline" "alt-enter": "editor::Newline"
} }
}, },
{
"context": "AgentFeedbackMessageEditor > Editor",
"use_key_equivalents": true,
"bindings": {
"escape": "menu::Cancel",
"enter": "menu::Confirm",
"alt-enter": "editor::Newline"
}
},
{ {
"context": "ContextStrip", "context": "ContextStrip",
"use_key_equivalents": true, "use_key_equivalents": true,

View file

@ -55,8 +55,7 @@ pub struct ActiveThread {
notifications: Vec<WindowHandle<AgentNotification>>, notifications: Vec<WindowHandle<AgentNotification>>,
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
notification_subscriptions: HashMap<WindowHandle<AgentNotification>, Vec<Subscription>>, notification_subscriptions: HashMap<WindowHandle<AgentNotification>, Vec<Subscription>>,
showing_feedback_comments: bool, feedback_message_editor: Option<Entity<Editor>>,
feedback_comments_editor: Option<Entity<Editor>>,
} }
struct RenderedMessage { struct RenderedMessage {
@ -371,8 +370,7 @@ impl ActiveThread {
notifications: Vec::new(), notifications: Vec::new(),
_subscriptions: subscriptions, _subscriptions: subscriptions,
notification_subscriptions: HashMap::default(), notification_subscriptions: HashMap::default(),
showing_feedback_comments: false, feedback_message_editor: None,
feedback_comments_editor: None,
}; };
for message in thread.read(cx).messages().cloned().collect::<Vec<_>>() { for message in thread.read(cx).messages().cloned().collect::<Vec<_>>() {
@ -923,37 +921,37 @@ impl ActiveThread {
} }
fn handle_show_feedback_comments(&mut self, window: &mut Window, cx: &mut Context<Self>) { fn handle_show_feedback_comments(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.showing_feedback_comments = true; if self.feedback_message_editor.is_some() {
return;
if self.feedback_comments_editor.is_none() {
let buffer = cx.new(|cx| {
let empty_string = String::new();
MultiBuffer::singleton(cx.new(|cx| Buffer::local(empty_string, cx)), cx)
});
let editor = cx.new(|cx| {
Editor::new(
editor::EditorMode::AutoHeight { max_lines: 4 },
buffer,
None,
window,
cx,
)
});
self.feedback_comments_editor = Some(editor);
} }
let buffer = cx.new(|cx| {
let empty_string = String::new();
MultiBuffer::singleton(cx.new(|cx| Buffer::local(empty_string, cx)), cx)
});
let editor = cx.new(|cx| {
let mut editor = Editor::new(
editor::EditorMode::AutoHeight { max_lines: 4 },
buffer,
None,
window,
cx,
);
editor.set_placeholder_text(
"What went wrong? Share your feedback so we can improve.",
cx,
);
editor
});
editor.read(cx).focus_handle(cx).focus(window);
self.feedback_message_editor = Some(editor);
cx.notify(); cx.notify();
} }
fn handle_submit_comments( fn submit_feedback_message(&mut self, cx: &mut Context<Self>) {
&mut self, let Some(editor) = self.feedback_message_editor.clone() else {
_: &ClickEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(editor) = self.feedback_comments_editor.clone() else {
return; return;
}; };
@ -968,8 +966,7 @@ impl ActiveThread {
telemetry::event!("Assistant Thread Feedback Comments", thread_id, comments); telemetry::event!("Assistant Thread Feedback Comments", thread_id, comments);
} }
self.showing_feedback_comments = false; self.feedback_message_editor = None;
self.feedback_comments_editor = None;
let this = cx.entity().downgrade(); let this = cx.entity().downgrade();
cx.spawn(async move |_, cx| { cx.spawn(async move |_, cx| {
@ -979,17 +976,6 @@ impl ActiveThread {
.detach_and_log_err(cx); .detach_and_log_err(cx);
} }
fn handle_cancel_comments(
&mut self,
_: &ClickEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
self.showing_feedback_comments = false;
self.feedback_comments_editor = None;
cx.notify();
}
fn render_message(&self, ix: usize, window: &mut Window, cx: &mut Context<Self>) -> AnyElement { fn render_message(&self, ix: usize, window: &mut Window, cx: &mut Context<Self>) -> AnyElement {
let message_id = self.messages[ix]; let message_id = self.messages[ix];
let Some(message) = self.thread.read(cx).message(message_id) else { let Some(message) = self.thread.read(cx).message(message_id) else {
@ -1398,51 +1384,76 @@ impl ActiveThread {
.when( .when(
show_feedback && !self.thread.read(cx).is_generating(), show_feedback && !self.thread.read(cx).is_generating(),
|parent| { |parent| {
parent parent.child(feedback_items).when_some(
.child(feedback_items) self.feedback_message_editor.clone(),
.when(self.showing_feedback_comments, |parent| { |parent, feedback_editor| {
let focus_handle = feedback_editor.focus_handle(cx);
parent.child( parent.child(
v_flex() v_flex()
.gap_1() .key_context("AgentFeedbackMessageEditor")
.px_4() .on_action(cx.listener(|this, _: &menu::Cancel, _, cx| {
.child( this.feedback_message_editor = None;
Label::new( cx.notify();
"Please share your feedback to help us improve:", }))
) .on_action(cx.listener(|this, _: &menu::Confirm, _, cx| {
.size(LabelSize::Small), this.submit_feedback_message(cx);
) cx.notify();
.child( }))
div() .on_action(cx.listener(Self::confirm_editing_message))
.p_2() .mx_4()
.rounded_md() .mb_3()
.border_1() .p_2()
.border_color(cx.theme().colors().border) .rounded_md()
.bg(cx.theme().colors().editor_background) .border_1()
.child( .border_color(cx.theme().colors().border)
self.feedback_comments_editor .bg(cx.theme().colors().editor_background)
.as_ref() .child(feedback_editor)
.unwrap()
.clone(),
),
)
.child( .child(
h_flex() h_flex()
.gap_1() .gap_1()
.justify_end() .justify_end()
.pb_2()
.child( .child(
Button::new("cancel-comments", "Cancel").on_click( Button::new("dismiss-feedback-message", "Cancel")
cx.listener(Self::handle_cancel_comments), .label_size(LabelSize::Small)
), .key_binding(
KeyBinding::for_action_in(
&menu::Cancel,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(10.))),
)
.on_click(cx.listener(|this, _, _, cx| {
this.feedback_message_editor = None;
cx.notify();
})),
) )
.child( .child(
Button::new("submit-comments", "Submit").on_click( Button::new(
cx.listener(Self::handle_submit_comments), "submit-feedback-message",
), "Share Feedback",
)
.style(ButtonStyle::Tinted(ui::TintColor::Accent))
.label_size(LabelSize::Small)
.key_binding(
KeyBinding::for_action_in(
&menu::Confirm,
&focus_handle,
window,
cx,
)
.map(|kb| kb.size(rems_from_px(10.))),
)
.on_click(cx.listener(|this, _, _, cx| {
this.submit_feedback_message(cx);
cx.notify();
})),
), ),
), ),
) )
}) },
)
}, },
) )
.into_any() .into_any()