From f2f3d9faf6f22aa4995f2df045286068b693d5c2 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:02:01 -0300 Subject: [PATCH] Add adjustments to agent v2 pane changes (#44885) Follow-up to https://github.com/zed-industries/zed/pull/44190. Release Notes: - N/A --- assets/icons/zed_agent_two.svg | 5 ++ crates/agent_ui_v2/src/agent_thread_pane.rs | 99 ++++++++++----------- crates/agent_ui_v2/src/agents_panel.rs | 2 +- crates/icons/src/icons.rs | 1 + crates/ui/src/components/tab_bar.rs | 1 + crates/workspace/src/pane.rs | 74 ++++++++++----- 6 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 assets/icons/zed_agent_two.svg diff --git a/assets/icons/zed_agent_two.svg b/assets/icons/zed_agent_two.svg new file mode 100644 index 0000000000000000000000000000000000000000..c352be84d2f1bea6da1f6a5be70b9420f019b6d6 --- /dev/null +++ b/assets/icons/zed_agent_two.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/crates/agent_ui_v2/src/agent_thread_pane.rs b/crates/agent_ui_v2/src/agent_thread_pane.rs index cfe861ef09c51af511554b3d15a1c810a793ed15..72886f87eca38c630ec29b9b410930f1d3936b50 100644 --- a/crates/agent_ui_v2/src/agent_thread_pane.rs +++ b/crates/agent_ui_v2/src/agent_thread_pane.rs @@ -13,13 +13,12 @@ use settings::DockSide; use settings::Settings as _; use std::rc::Rc; use std::sync::Arc; -use ui::{ - App, Clickable as _, Context, DynamicSpacing, IconButton, IconName, IconSize, IntoElement, - Label, LabelCommon as _, LabelSize, Render, Tab, Window, div, +use ui::{Tab, Tooltip, prelude::*}; +use workspace::{ + Workspace, + dock::{ClosePane, MinimizePane, UtilityPane, UtilityPanePosition}, + utility_pane::UtilityPaneSlot, }; -use workspace::Workspace; -use workspace::dock::{ClosePane, MinimizePane, UtilityPane, UtilityPanePosition}; -use workspace::utility_pane::UtilityPaneSlot; pub const DEFAULT_UTILITY_PANE_WIDTH: Pixels = gpui::px(400.0); @@ -169,58 +168,56 @@ impl AgentThreadPane { let toggle_icon = self.toggle_icon(cx); let title = self.title(cx); - let make_toggle_button = |workspace: WeakEntity, cx: &App| { - div().px(DynamicSpacing::Base06.rems(cx)).child( - IconButton::new("toggle_utility_pane", toggle_icon) - .icon_size(IconSize::Small) - .on_click(move |_, window, cx| { - workspace - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane(slot, window, cx) - }) - .ok(); - }), - ) - }; - - let make_close_button = |id: &'static str, cx: &mut Context| { - let on_click = cx.listener(|this, _: &gpui::ClickEvent, _window, cx| { - cx.emit(ClosePane); - this.thread_view = None; - cx.notify(); - }); - div().px(DynamicSpacing::Base06.rems(cx)).child( - IconButton::new(id, IconName::Close) - .icon_size(IconSize::Small) - .on_click(on_click), - ) - }; - - let make_title_label = |title: SharedString, cx: &App| { - div() - .px(DynamicSpacing::Base06.rems(cx)) - .child(Label::new(title).size(LabelSize::Small)) + let pane_toggle_button = |workspace: WeakEntity| { + IconButton::new("toggle_utility_pane", toggle_icon) + .icon_size(IconSize::Small) + .tooltip(Tooltip::text("Toggle Agent Pane")) + .on_click(move |_, window, cx| { + workspace + .update(cx, |workspace, cx| { + workspace.toggle_utility_pane(slot, window, cx) + }) + .ok(); + }) }; - div() + h_flex() .id("utility-pane-header") - .flex() - .flex_none() - .items_center() .w_full() .h(Tab::container_height(cx)) - .when(slot == UtilityPaneSlot::Left, |this| { - this.child(make_toggle_button(workspace.clone(), cx)) - .child(make_title_label(title.clone(), cx)) - .child(div().flex_grow()) - .child(make_close_button("close_utility_pane_left", cx)) - }) + .px_1p5() + .gap(DynamicSpacing::Base06.rems(cx)) .when(slot == UtilityPaneSlot::Right, |this| { - this.child(make_close_button("close_utility_pane_right", cx)) - .child(make_title_label(title.clone(), cx)) - .child(div().flex_grow()) - .child(make_toggle_button(workspace.clone(), cx)) + this.flex_row_reverse() }) + .flex_none() + .border_b_1() + .border_color(cx.theme().colors().border) + .child(pane_toggle_button(workspace)) + .child( + h_flex() + .size_full() + .min_w_0() + .gap_1() + .map(|this| { + if slot == UtilityPaneSlot::Right { + this.flex_row_reverse().justify_start() + } else { + this.justify_between() + } + }) + .child(Label::new(title).truncate()) + .child( + IconButton::new("close_btn", IconName::Close) + .icon_size(IconSize::Small) + .tooltip(Tooltip::text("Close Agent Pane")) + .on_click(cx.listener(|this, _: &gpui::ClickEvent, _window, cx| { + cx.emit(ClosePane); + this.thread_view = None; + cx.notify() + })), + ), + ) } } diff --git a/crates/agent_ui_v2/src/agents_panel.rs b/crates/agent_ui_v2/src/agents_panel.rs index ace5e73f56b9eff4292f34263bfe08a94e2d6050..a7afdddda43514ade40b7fd9dfd8bcd8ace33dc7 100644 --- a/crates/agent_ui_v2/src/agents_panel.rs +++ b/crates/agent_ui_v2/src/agents_panel.rs @@ -411,7 +411,7 @@ impl Panel for AgentsPanel { } fn icon(&self, _window: &Window, cx: &App) -> Option { - (self.enabled(cx) && AgentSettings::get_global(cx).button).then_some(IconName::ZedAgent) + (self.enabled(cx) && AgentSettings::get_global(cx).button).then_some(IconName::ZedAgentTwo) } fn icon_tooltip(&self, _window: &Window, _cx: &App) -> Option<&'static str> { diff --git a/crates/icons/src/icons.rs b/crates/icons/src/icons.rs index bf4c74f984ff4aa8f06d6408957eddabcf5f94ed..23ae7a6d928d98aafe48d28cfe5626bbf76d29b8 100644 --- a/crates/icons/src/icons.rs +++ b/crates/icons/src/icons.rs @@ -260,6 +260,7 @@ pub enum IconName { XCircle, XCircleFilled, ZedAgent, + ZedAgentTwo, ZedAssistant, ZedBurnMode, ZedBurnModeOn, diff --git a/crates/ui/src/components/tab_bar.rs b/crates/ui/src/components/tab_bar.rs index 681f9a726e0d5f4796325a4533fca909617f1e08..86598b8c6f1ab3a479313c7775405863e9e3b49b 100644 --- a/crates/ui/src/components/tab_bar.rs +++ b/crates/ui/src/components/tab_bar.rs @@ -162,6 +162,7 @@ impl RenderOnce for TabBar { .when(!self.end_children.is_empty(), |div| { div.child( h_flex() + .h_full() .flex_none() .pl(DynamicSpacing::Base04.rems(cx)) .gap(DynamicSpacing::Base04.rems(cx)) diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index ee57f06937ee2781e8d1b965b5e498f5a31ad80d..50ba58926ece8818ac5a4f44103c3b86eb2b672d 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -3047,6 +3047,8 @@ impl Pane { }; let focus_handle = self.focus_handle.clone(); + let is_pane_focused = self.has_focus(window, cx); + let navigate_backward = IconButton::new("navigate_backward", IconName::ArrowLeft) .icon_size(IconSize::Small) .on_click({ @@ -3076,15 +3078,27 @@ impl Pane { let toggle_icon = pane.toggle_icon(cx); let workspace_handle = self.workspace.clone(); - IconButton::new("open_aside_left", toggle_icon) - .icon_size(IconSize::Small) - .on_click(move |_, window, cx| { - workspace_handle - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane(UtilityPaneSlot::Left, window, cx) - }) - .ok(); - }) + h_flex() + .h_full() + .pr_1p5() + .border_r_1() + .border_color(cx.theme().colors().border) + .child( + IconButton::new("open_aside_left", toggle_icon) + .icon_size(IconSize::Small) + .tooltip(Tooltip::text("Toggle Agent Pane")) // TODO: Probably want to make this generic + .on_click(move |_, window, cx| { + workspace_handle + .update(cx, |workspace, cx| { + workspace.toggle_utility_pane( + UtilityPaneSlot::Left, + window, + cx, + ) + }) + .ok(); + }), + ) .into_any_element() }) }; @@ -3095,15 +3109,29 @@ impl Pane { let toggle_icon = pane.toggle_icon(cx); let workspace_handle = self.workspace.clone(); - IconButton::new("open_aside_right", toggle_icon) - .icon_size(IconSize::Small) - .on_click(move |_, window, cx| { - workspace_handle - .update(cx, |workspace, cx| { - workspace.toggle_utility_pane(UtilityPaneSlot::Right, window, cx) - }) - .ok(); + h_flex() + .h_full() + .when(is_pane_focused, |this| { + this.pl(DynamicSpacing::Base04.rems(cx)) + .border_l_1() + .border_color(cx.theme().colors().border) }) + .child( + IconButton::new("open_aside_right", toggle_icon) + .icon_size(IconSize::Small) + .tooltip(Tooltip::text("Toggle Agent Pane")) // TODO: Probably want to make this generic + .on_click(move |_, window, cx| { + workspace_handle + .update(cx, |workspace, cx| { + workspace.toggle_utility_pane( + UtilityPaneSlot::Right, + window, + cx, + ) + }) + .ok(); + }), + ) .into_any_element() }) }; @@ -3196,8 +3224,8 @@ impl Pane { self.display_nav_history_buttons.unwrap_or_default(), |tab_bar| { tab_bar - .pre_end_child(navigate_backward) - .pre_end_child(navigate_forward) + .start_child(navigate_backward) + .start_child(navigate_forward) }, ) .map(|tab_bar| { @@ -6756,13 +6784,13 @@ mod tests { let tab_bar_scroll_handle = pane.update_in(cx, |pane, _window, _cx| pane.tab_bar_scroll_handle.clone()); assert_eq!(tab_bar_scroll_handle.children_count(), 6); - let tab_bounds = cx.debug_bounds("TAB-3").unwrap(); + let tab_bounds = cx.debug_bounds("TAB-4").unwrap(); let new_tab_button_bounds = cx.debug_bounds("ICON-Plus").unwrap(); let scroll_bounds = tab_bar_scroll_handle.bounds(); let scroll_offset = tab_bar_scroll_handle.offset(); - assert!(tab_bounds.right() <= scroll_bounds.right() + scroll_offset.x); - // -35.0 is the magic number for this setup - assert_eq!(scroll_offset.x, px(-35.0)); + assert!(tab_bounds.right() <= scroll_bounds.right()); + // -43.0 is the magic number for this setup + assert_eq!(scroll_offset.x, px(-43.0)); assert!( !tab_bounds.intersects(&new_tab_button_bounds), "Tab should not overlap with the new tab button, if this is failing check if there's been a redesign!"