diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index cd065d701f9f018595cb082f247271a0c9fdfa75..ac0498ce7cb0fbedf25dd76b999347b25a5efeef 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -3894,7 +3894,6 @@ impl AcpThreadView { return self.render_permission_buttons_legacy(options, entry_ix, tool_call_id, cx); } - // Get granularity options (all options except the old deny option which we no longer generate) let granularity_options: Vec<_> = options .iter() .filter(|o| { @@ -3912,18 +3911,15 @@ impl AcpThreadView { .copied() .unwrap_or_else(|| granularity_options.len().saturating_sub(1)); - // Get the selected option let selected_option = granularity_options .get(selected_index) .or(granularity_options.last()) .copied(); - // The dropdown label should match the selected option let dropdown_label: SharedString = selected_option .map(|o| o.name.clone().into()) .unwrap_or_else(|| "Only this time".into()); - // Prepare data for button click handlers let (allow_option_id, allow_option_kind, deny_option_id, deny_option_kind) = if let Some(option) = selected_option { let option_id_str = option.option_id.0.to_string(); @@ -3950,7 +3946,6 @@ impl AcpThreadView { option_id_str.replace("allow", "deny") }; - // Determine the kinds let allow_kind = option.kind; let deny_kind = match option.kind { acp::PermissionOptionKind::AllowOnce => acp::PermissionOptionKind::RejectOnce, @@ -3975,19 +3970,16 @@ impl AcpThreadView { ) }; - div() + h_flex() + .w_full() .p_1() + .gap_2() + .justify_between() .border_t_1() .border_color(self.tool_card_border_color(cx)) - .w_full() - .h_flex() - .items_center() - .justify_between() - .gap_2() .child( - // Left side: Allow and Deny buttons h_flex() - .gap_1() + .gap_0p5() .child( Button::new(("allow-btn", entry_ix), "Allow") .icon(IconName::Check) @@ -3995,19 +3987,15 @@ impl AcpThreadView { .icon_position(IconPosition::Start) .icon_size(IconSize::XSmall) .label_size(LabelSize::Small) - .map(|btn| { - if is_first { - btn.key_binding( - KeyBinding::for_action_in( - &AllowOnce as &dyn Action, - &self.focus_handle, - cx, - ) - .map(|kb| kb.size(rems_from_px(10.))), + .when(is_first, |this| { + this.key_binding( + KeyBinding::for_action_in( + &AllowOnce as &dyn Action, + &self.focus_handle, + cx, ) - } else { - btn - } + .map(|kb| kb.size(rems_from_px(10.))), + ) }) .on_click(cx.listener({ let tool_call_id = tool_call_id.clone(); @@ -4031,19 +4019,15 @@ impl AcpThreadView { .icon_position(IconPosition::Start) .icon_size(IconSize::XSmall) .label_size(LabelSize::Small) - .map(|btn| { - if is_first { - btn.key_binding( - KeyBinding::for_action_in( - &RejectOnce as &dyn Action, - &self.focus_handle, - cx, - ) - .map(|kb| kb.size(rems_from_px(10.))), + .when(is_first, |this| { + this.key_binding( + KeyBinding::for_action_in( + &RejectOnce as &dyn Action, + &self.focus_handle, + cx, ) - } else { - btn - } + .map(|kb| kb.size(rems_from_px(10.))), + ) }) .on_click(cx.listener({ let tool_call_id = tool_call_id.clone(); @@ -4061,18 +4045,15 @@ impl AcpThreadView { })), ), ) - .child( - // Right side: Granularity dropdown - self.render_permission_granularity_dropdown( - &granularity_options, - dropdown_label, - entry_ix, - tool_call_id, - selected_index, - is_first, - cx, - ), - ) + .child(self.render_permission_granularity_dropdown( + &granularity_options, + dropdown_label, + entry_ix, + tool_call_id, + selected_index, + is_first, + cx, + )) } fn render_permission_granularity_dropdown( @@ -4085,8 +4066,6 @@ impl AcpThreadView { is_first: bool, cx: &Context, ) -> impl IntoElement { - // Collect option info for the menu builder closure - // Each item is (index, display_name) let menu_options: Vec<(usize, SharedString)> = granularity_options .iter() .enumerate() @@ -4098,23 +4077,18 @@ impl AcpThreadView { .trigger( Button::new(("granularity-trigger", entry_ix), current_label) .icon(IconName::ChevronDown) - .icon_position(IconPosition::End) .icon_size(IconSize::XSmall) + .icon_color(Color::Muted) .label_size(LabelSize::Small) - .style(ButtonStyle::Subtle) - .map(|btn| { - if is_first { - btn.key_binding( - KeyBinding::for_action_in( - &crate::OpenPermissionDropdown as &dyn Action, - &self.focus_handle, - cx, - ) - .map(|kb| kb.size(rems_from_px(10.))), + .when(is_first, |this| { + this.key_binding( + KeyBinding::for_action_in( + &crate::OpenPermissionDropdown as &dyn Action, + &self.focus_handle, + cx, ) - } else { - btn - } + .map(|kb| kb.size(rems_from_px(10.))), + ) }), ) .menu(move |window, cx| { @@ -4128,38 +4102,20 @@ impl AcpThreadView { let tool_call_id_for_entry = tool_call_id.clone(); let is_selected = index == selected_index; - menu = menu.custom_entry( - { - let display_name = display_name.clone(); - move |_window, _cx| { - h_flex() - .w_full() - .justify_between() - .child( - Label::new(display_name.clone()).size(LabelSize::Small), - ) - .when(is_selected, |this| { - this.child( - Icon::new(IconName::Check) - .size(IconSize::Small) - .color(Color::Accent), - ) - }) - .into_any_element() - } - }, - { - let tool_call_id = tool_call_id_for_entry.clone(); - move |window, cx| { - window.dispatch_action( - SelectPermissionGranularity { - tool_call_id: tool_call_id.0.to_string(), - index, - } - .boxed_clone(), - cx, - ); - } + menu = menu.toggleable_entry( + display_name, + is_selected, + IconPosition::End, + None, + move |window, cx| { + window.dispatch_action( + SelectPermissionGranularity { + tool_call_id: tool_call_id_for_entry.0.to_string(), + index, + } + .boxed_clone(), + cx, + ); }, ); }