From 61e7032e542c8ce5b9253f4a708b78ac70c5ec6b Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Fri, 6 Mar 2026 09:20:29 -0300 Subject: [PATCH] agent_ui: Adjust panel toolbar design for v2 (#50927) Adding some adjustments so the toolbar looks more like the designs we've been working on. All that changes here are only valid for the v2 feature flag. Haven't changed anything for today's production version. Release Notes: - N/A --- crates/agent_ui/src/agent_panel.rs | 774 ++++++++++++++++------------- 1 file changed, 436 insertions(+), 338 deletions(-) diff --git a/crates/agent_ui/src/agent_panel.rs b/crates/agent_ui/src/agent_panel.rs index 1937b2693e3923e46efc59ab959a7939b733cbdd..76636e64ad30d507e5320c54e158a155dde63383 100644 --- a/crates/agent_ui/src/agent_panel.rs +++ b/crates/agent_ui/src/agent_panel.rs @@ -73,8 +73,9 @@ use search::{BufferSearchBar, buffer_search}; use settings::{Settings, update_settings_file}; use theme::ThemeSettings; use ui::{ - Button, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, KeyBinding, PopoverMenu, - PopoverMenuHandle, SpinnerLabel, Tab, Tooltip, prelude::*, utils::WithRemSize, + Button, ButtonLike, Callout, ContextMenu, ContextMenuEntry, DocumentationSide, KeyBinding, + PopoverMenu, PopoverMenuHandle, SpinnerLabel, Tab, TintColor, Tooltip, prelude::*, + utils::WithRemSize, }; use util::ResultExt as _; use workspace::{ @@ -416,17 +417,10 @@ impl From for AgentType { impl StartThreadIn { fn label(&self) -> SharedString { match self { - Self::LocalProject => "Local Project".into(), + Self::LocalProject => "Current Project".into(), Self::NewWorktree => "New Worktree".into(), } } - - fn icon(&self) -> IconName { - match self { - Self::LocalProject => IconName::Screen, - Self::NewWorktree => IconName::GitBranchPlus, - } - } } #[derive(Clone, Debug)] @@ -3114,12 +3108,11 @@ impl AgentPanel { }; let trigger_button = Button::new("thread-target-trigger", trigger_label) - .label_size(LabelSize::Small) - .color(Color::Muted) .icon(icon) .icon_size(IconSize::XSmall) .icon_position(IconPosition::End) .icon_color(Color::Muted) + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) .disabled(is_creating); let dock_position = AgentSettings::get_global(cx).dock; @@ -3132,21 +3125,16 @@ impl AgentPanel { PopoverMenu::new("thread-target-selector") .trigger(trigger_button) - .anchor(gpui::Corner::BottomRight) - .with_handle(self.start_thread_in_menu_handle.clone()) .menu(move |window, cx| { - let current_target = current_target; - Some(ContextMenu::build(window, cx, move |menu, _window, _cx| { - let is_local_selected = current_target == StartThreadIn::LocalProject; - let is_new_worktree_selected = current_target == StartThreadIn::NewWorktree; + let is_local_selected = current_target == StartThreadIn::LocalProject; + let is_new_worktree_selected = current_target == StartThreadIn::NewWorktree; + Some(ContextMenu::build(window, cx, move |menu, _window, _cx| { let new_worktree_disabled = !has_git_repo || is_via_collab; menu.header("Start Thread In…") .item( - ContextMenuEntry::new("Local Project") - .icon(StartThreadIn::LocalProject.icon()) - .icon_color(Color::Muted) + ContextMenuEntry::new("Current Project") .toggleable(IconPosition::End, is_local_selected) .handler(|window, cx| { window @@ -3155,8 +3143,6 @@ impl AgentPanel { ) .item({ let entry = ContextMenuEntry::new("New Worktree") - .icon(StartThreadIn::NewWorktree.icon()) - .icon_color(Color::Muted) .toggleable(IconPosition::End, is_new_worktree_selected) .disabled(new_worktree_disabled) .handler(|window, cx| { @@ -3182,6 +3168,12 @@ impl AgentPanel { }) })) }) + .with_handle(self.start_thread_in_menu_handle.clone()) + .anchor(Corner::TopLeft) + .offset(gpui::Point { + x: px(1.0), + y: px(1.0), + }) } fn render_toolbar(&self, window: &mut Window, cx: &mut Context) -> impl IntoElement { @@ -3209,77 +3201,179 @@ impl AgentPanel { | ActiveView::Configuration => None, }; - let new_thread_menu = PopoverMenu::new("new_thread_menu") - .trigger_with_tooltip( - IconButton::new("new_thread_menu_btn", IconName::Plus).icon_size(IconSize::Small), - { - let focus_handle = focus_handle.clone(); - move |_window, cx| { - Tooltip::for_action_in( - "New Thread…", - &ToggleNewThreadMenu, - &focus_handle, - cx, + let new_thread_menu_builder: Rc< + dyn Fn(&mut Window, &mut App) -> Option>, + > = { + let selected_agent = self.selected_agent.clone(); + let is_agent_selected = move |agent_type: AgentType| selected_agent == agent_type; + + let workspace = self.workspace.clone(); + let is_via_collab = workspace + .update(cx, |workspace, cx| { + workspace.project().read(cx).is_via_collab() + }) + .unwrap_or_default(); + + let focus_handle = focus_handle.clone(); + let agent_server_store = agent_server_store; + + Rc::new(move |window, cx| { + telemetry::event!("New Thread Clicked"); + + let active_thread = active_thread.clone(); + Some(ContextMenu::build(window, cx, |menu, _window, cx| { + menu.context(focus_handle.clone()) + .when_some(active_thread, |this, active_thread| { + let thread = active_thread.read(cx); + + if !thread.is_empty() { + let session_id = thread.id().clone(); + this.item( + ContextMenuEntry::new("New From Summary") + .icon(IconName::ThreadFromSummary) + .icon_color(Color::Muted) + .handler(move |window, cx| { + window.dispatch_action( + Box::new(NewNativeAgentThreadFromSummary { + from_session_id: session_id.clone(), + }), + cx, + ); + }), + ) + } else { + this + } + }) + .item( + ContextMenuEntry::new("Zed Agent") + .when( + is_agent_selected(AgentType::NativeAgent) + | is_agent_selected(AgentType::TextThread), + |this| { + this.action(Box::new(NewExternalAgentThread { + agent: None, + })) + }, + ) + .icon(IconName::ZedAgent) + .icon_color(Color::Muted) + .handler({ + let workspace = workspace.clone(); + move |window, cx| { + if let Some(workspace) = workspace.upgrade() { + workspace.update(cx, |workspace, cx| { + if let Some(panel) = + workspace.panel::(cx) + { + panel.update(cx, |panel, cx| { + panel.new_agent_thread( + AgentType::NativeAgent, + window, + cx, + ); + }); + } + }); + } + } + }), ) - } - }, - ) - .anchor(Corner::TopRight) - .with_handle(self.new_thread_menu_handle.clone()) - .menu({ - let selected_agent = self.selected_agent.clone(); - let is_agent_selected = move |agent_type: AgentType| selected_agent == agent_type; + .item( + ContextMenuEntry::new("Text Thread") + .action(NewTextThread.boxed_clone()) + .icon(IconName::TextThread) + .icon_color(Color::Muted) + .handler({ + let workspace = workspace.clone(); + move |window, cx| { + if let Some(workspace) = workspace.upgrade() { + workspace.update(cx, |workspace, cx| { + if let Some(panel) = + workspace.panel::(cx) + { + panel.update(cx, |panel, cx| { + panel.new_agent_thread( + AgentType::TextThread, + window, + cx, + ); + }); + } + }); + } + } + }), + ) + .separator() + .header("External Agents") + .map(|mut menu| { + let agent_server_store = agent_server_store.read(cx); + let registry_store = + project::AgentRegistryStore::try_global(cx); + let registry_store_ref = + registry_store.as_ref().map(|s| s.read(cx)); + + struct AgentMenuItem { + id: ExternalAgentServerName, + display_name: SharedString, + } - let workspace = self.workspace.clone(); - let is_via_collab = workspace - .update(cx, |workspace, cx| { - workspace.project().read(cx).is_via_collab() - }) - .unwrap_or_default(); + let agent_items = agent_server_store + .external_agents() + .map(|name| { + let display_name = agent_server_store + .agent_display_name(name) + .or_else(|| { + registry_store_ref + .as_ref() + .and_then(|store| store.agent(name.0.as_ref())) + .map(|a| a.name().clone()) + }) + .unwrap_or_else(|| name.0.clone()); + AgentMenuItem { + id: name.clone(), + display_name, + } + }) + .sorted_unstable_by_key(|e| e.display_name.to_lowercase()) + .collect::>(); - move |window, cx| { - telemetry::event!("New Thread Clicked"); - - let active_thread = active_thread.clone(); - Some(ContextMenu::build(window, cx, |menu, _window, cx| { - menu.context(focus_handle.clone()) - .when_some(active_thread, |this, active_thread| { - let thread = active_thread.read(cx); - - if !thread.is_empty() { - let session_id = thread.id().clone(); - this.item( - ContextMenuEntry::new("New From Summary") - .icon(IconName::ThreadFromSummary) - .icon_color(Color::Muted) - .handler(move |window, cx| { - window.dispatch_action( - Box::new(NewNativeAgentThreadFromSummary { - from_session_id: session_id.clone(), - }), - cx, - ); - }), - ) + for item in &agent_items { + let mut entry = + ContextMenuEntry::new(item.display_name.clone()); + + let icon_path = agent_server_store + .agent_icon(&item.id) + .or_else(|| { + registry_store_ref + .as_ref() + .and_then(|store| store.agent(item.id.0.as_str())) + .and_then(|a| a.icon_path().cloned()) + }); + + if let Some(icon_path) = icon_path { + entry = entry.custom_icon_svg(icon_path); } else { - this + entry = entry.icon(IconName::Sparkle); } - }) - .item( - ContextMenuEntry::new("Zed Agent") + + entry = entry .when( - is_agent_selected(AgentType::NativeAgent) - | is_agent_selected(AgentType::TextThread), + is_agent_selected(AgentType::Custom { + name: item.id.0.clone(), + }), |this| { - this.action(Box::new(NewExternalAgentThread { - agent: None, - })) + this.action(Box::new( + NewExternalAgentThread { agent: None }, + )) }, ) - .icon(IconName::ZedAgent) .icon_color(Color::Muted) + .disabled(is_via_collab) .handler({ let workspace = workspace.clone(); + let agent_id = item.id.clone(); move |window, cx| { if let Some(workspace) = workspace.upgrade() { workspace.update(cx, |workspace, cx| { @@ -3288,7 +3382,9 @@ impl AgentPanel { { panel.update(cx, |panel, cx| { panel.new_agent_thread( - AgentType::NativeAgent, + AgentType::Custom { + name: agent_id.0.clone(), + }, window, cx, ); @@ -3297,16 +3393,84 @@ impl AgentPanel { }); } } - }), - ) - .item( - ContextMenuEntry::new("Text Thread") - .action(NewTextThread.boxed_clone()) - .icon(IconName::TextThread) + }); + + menu = menu.item(entry); + } + + menu + }) + .separator() + .map(|mut menu| { + let agent_server_store = agent_server_store.read(cx); + let registry_store = + project::AgentRegistryStore::try_global(cx); + let registry_store_ref = + registry_store.as_ref().map(|s| s.read(cx)); + + let previous_built_in_ids: &[ExternalAgentServerName] = + &[CLAUDE_AGENT_NAME.into(), CODEX_NAME.into(), GEMINI_NAME.into()]; + + let promoted_items = previous_built_in_ids + .iter() + .filter(|id| { + !agent_server_store.external_agents.contains_key(*id) + }) + .filter_map(|name| { + let display_name = registry_store_ref + .as_ref() + .and_then(|store| store.agent(name.0.as_ref())) + .map(|a| a.name().clone())?; + Some((name.clone(), display_name)) + }) + .sorted_unstable_by_key(|(_, display_name)| display_name.to_lowercase()) + .collect::>(); + + for (agent_id, display_name) in &promoted_items { + let mut entry = + ContextMenuEntry::new(display_name.clone()); + + let icon_path = registry_store_ref + .as_ref() + .and_then(|store| store.agent(agent_id.0.as_str())) + .and_then(|a| a.icon_path().cloned()); + + if let Some(icon_path) = icon_path { + entry = entry.custom_icon_svg(icon_path); + } else { + entry = entry.icon(IconName::Sparkle); + } + + entry = entry .icon_color(Color::Muted) + .disabled(is_via_collab) .handler({ let workspace = workspace.clone(); + let agent_id = agent_id.clone(); move |window, cx| { + let fs = ::global(cx); + let agent_id_string = + agent_id.to_string(); + settings::update_settings_file( + fs, + cx, + move |settings, _| { + let agent_servers = settings + .agent_servers + .get_or_insert_default(); + agent_servers.entry(agent_id_string).or_insert_with(|| { + settings::CustomAgentServerSettings::Registry { + default_mode: None, + default_model: None, + env: Default::default(), + favorite_models: Vec::new(), + default_config_options: Default::default(), + favorite_config_option_values: Default::default(), + } + }); + }, + ); + if let Some(workspace) = workspace.upgrade() { workspace.update(cx, |workspace, cx| { if let Some(panel) = @@ -3314,7 +3478,9 @@ impl AgentPanel { { panel.update(cx, |panel, cx| { panel.new_agent_thread( - AgentType::TextThread, + AgentType::Custom { + name: agent_id.0.clone(), + }, window, cx, ); @@ -3323,215 +3489,29 @@ impl AgentPanel { }); } } - }), - ) - .separator() - .header("External Agents") - .map(|mut menu| { - let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); - - struct AgentMenuItem { - id: ExternalAgentServerName, - display_name: SharedString, - } - - let agent_items = agent_server_store - .external_agents() - .map(|name| { - let display_name = agent_server_store - .agent_display_name(name) - .or_else(|| { - registry_store_ref - .as_ref() - .and_then(|store| store.agent(name.0.as_ref())) - .map(|a| a.name().clone()) - }) - .unwrap_or_else(|| name.0.clone()); - AgentMenuItem { - id: name.clone(), - display_name, - } - }) - .sorted_unstable_by_key(|e| e.display_name.to_lowercase()) - .collect::>(); - - for item in &agent_items { - let mut entry = - ContextMenuEntry::new(item.display_name.clone()); + }); - let icon_path = agent_server_store - .agent_icon(&item.id) - .or_else(|| { - registry_store_ref - .as_ref() - .and_then(|store| store.agent(item.id.0.as_str())) - .and_then(|a| a.icon_path().cloned()) - }); - - if let Some(icon_path) = icon_path { - entry = entry.custom_icon_svg(icon_path); - } else { - entry = entry.icon(IconName::Sparkle); - } + menu = menu.item(entry); + } - entry = entry - .when( - is_agent_selected(AgentType::Custom { - name: item.id.0.clone(), - }), - |this| { - this.action(Box::new( - NewExternalAgentThread { agent: None }, - )) - }, + menu + }) + .item( + ContextMenuEntry::new("Add More Agents") + .icon(IconName::Plus) + .icon_color(Color::Muted) + .handler({ + move |window, cx| { + window.dispatch_action( + Box::new(zed_actions::AcpRegistry), + cx, ) - .icon_color(Color::Muted) - .disabled(is_via_collab) - .handler({ - let workspace = workspace.clone(); - let agent_id = item.id.clone(); - move |window, cx| { - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.new_agent_thread( - AgentType::Custom { - name: agent_id.0.clone(), - }, - window, - cx, - ); - }); - } - }); - } - } - }); - - menu = menu.item(entry); - } - - menu - }) - .separator() - .map(|mut menu| { - let agent_server_store = agent_server_store.read(cx); - let registry_store = - project::AgentRegistryStore::try_global(cx); - let registry_store_ref = - registry_store.as_ref().map(|s| s.read(cx)); - - let previous_built_in_ids: &[ExternalAgentServerName] = - &[CLAUDE_AGENT_NAME.into(), CODEX_NAME.into(), GEMINI_NAME.into()]; - - let promoted_items = previous_built_in_ids - .iter() - .filter(|id| { - !agent_server_store.external_agents.contains_key(*id) - }) - .filter_map(|name| { - let display_name = registry_store_ref - .as_ref() - .and_then(|store| store.agent(name.0.as_ref())) - .map(|a| a.name().clone())?; - Some((name.clone(), display_name)) - }) - .sorted_unstable_by_key(|(_, display_name)| display_name.to_lowercase()) - .collect::>(); - - for (agent_id, display_name) in &promoted_items { - let mut entry = - ContextMenuEntry::new(display_name.clone()); - - let icon_path = registry_store_ref - .as_ref() - .and_then(|store| store.agent(agent_id.0.as_str())) - .and_then(|a| a.icon_path().cloned()); - - if let Some(icon_path) = icon_path { - entry = entry.custom_icon_svg(icon_path); - } else { - entry = entry.icon(IconName::Sparkle); } - - entry = entry - .icon_color(Color::Muted) - .disabled(is_via_collab) - .handler({ - let workspace = workspace.clone(); - let agent_id = agent_id.clone(); - move |window, cx| { - let fs = ::global(cx); - let agent_id_string = - agent_id.to_string(); - settings::update_settings_file( - fs, - cx, - move |settings, _| { - let agent_servers = settings - .agent_servers - .get_or_insert_default(); - agent_servers.entry(agent_id_string).or_insert_with(|| { - settings::CustomAgentServerSettings::Registry { - default_mode: None, - default_model: None, - env: Default::default(), - favorite_models: Vec::new(), - default_config_options: Default::default(), - favorite_config_option_values: Default::default(), - } - }); - }, - ); - - if let Some(workspace) = workspace.upgrade() { - workspace.update(cx, |workspace, cx| { - if let Some(panel) = - workspace.panel::(cx) - { - panel.update(cx, |panel, cx| { - panel.new_agent_thread( - AgentType::Custom { - name: agent_id.0.clone(), - }, - window, - cx, - ); - }); - } - }); - } - } - }); - - menu = menu.item(entry); - } - - menu - }) - .item( - ContextMenuEntry::new("Add More Agents") - .icon(IconName::Plus) - .icon_color(Color::Muted) - .handler({ - move |window, cx| { - window.dispatch_action( - Box::new(zed_actions::AcpRegistry), - cx, - ) - } - }), - ) - })) - } - }); + }), + ) + })) + }) + }; let is_thread_loading = self .active_connection_view() @@ -3539,6 +3519,9 @@ impl AgentPanel { .unwrap_or(false); let has_custom_icon = selected_agent_custom_icon.is_some(); + let selected_agent_custom_icon_for_button = selected_agent_custom_icon.clone(); + let selected_agent_builtin_icon = self.selected_agent.icon(); + let selected_agent_label_for_tooltip = selected_agent_label.clone(); let selected_agent = div() .id("selected_agent_icon") @@ -3552,7 +3535,12 @@ impl AgentPanel { }) }) .tooltip(move |_, cx| { - Tooltip::with_meta(selected_agent_label.clone(), None, "Selected Agent", cx) + Tooltip::with_meta( + selected_agent_label_for_tooltip.clone(), + None, + "Selected Agent", + cx, + ) }); let selected_agent = if is_thread_loading { @@ -3571,50 +3559,160 @@ impl AgentPanel { let show_history_menu = self.history_kind_for_selected_agent(cx).is_some(); let has_v2_flag = cx.has_flag::(); + let is_empty_state = !self.active_thread_has_messages(cx); - h_flex() - .id("agent-panel-toolbar") - .h(Tab::container_height(cx)) - .max_w_full() - .flex_none() - .justify_between() - .gap_2() - .bg(cx.theme().colors().tab_bar_background) - .border_b_1() - .border_color(cx.theme().colors().border) - .child( - h_flex() - .size_full() - .gap(DynamicSpacing::Base04.rems(cx)) - .pl(DynamicSpacing::Base04.rems(cx)) - .child(match &self.active_view { - ActiveView::History { .. } | ActiveView::Configuration => { - self.render_toolbar_back_button(cx).into_any_element() + let is_in_history_or_config = matches!( + &self.active_view, + ActiveView::History { .. } | ActiveView::Configuration + ); + + let use_v2_empty_toolbar = has_v2_flag && is_empty_state && !is_in_history_or_config; + + if use_v2_empty_toolbar { + let (chevron_icon, icon_color, label_color) = + if self.new_thread_menu_handle.is_deployed() { + (IconName::ChevronUp, Color::Accent, Color::Accent) + } else { + (IconName::ChevronDown, Color::Muted, Color::Default) + }; + + let agent_icon_element: AnyElement = + if let Some(icon_path) = selected_agent_custom_icon_for_button { + Icon::from_external_svg(icon_path) + .size(IconSize::Small) + .color(icon_color) + .into_any_element() + } else { + let icon_name = selected_agent_builtin_icon.unwrap_or(IconName::ZedAgent); + Icon::new(icon_name) + .size(IconSize::Small) + .color(icon_color) + .into_any_element() + }; + + let agent_selector_button = ButtonLike::new("agent-selector-trigger") + .selected_style(ButtonStyle::Tinted(TintColor::Accent)) + .child( + h_flex() + .gap_1() + .child(agent_icon_element) + .child(Label::new(selected_agent_label).color(label_color)) + .child( + Icon::new(chevron_icon) + .color(icon_color) + .size(IconSize::XSmall), + ), + ); + + let agent_selector_menu = PopoverMenu::new("new_thread_menu") + .trigger(agent_selector_button) + .menu({ + let builder = new_thread_menu_builder.clone(); + move |window, cx| builder(window, cx) + }) + .with_handle(self.new_thread_menu_handle.clone()) + .anchor(Corner::TopLeft) + .offset(gpui::Point { + x: px(1.0), + y: px(1.0), + }); + + h_flex() + .id("agent-panel-toolbar") + .h(Tab::container_height(cx)) + .max_w_full() + .flex_none() + .justify_between() + .gap_2() + .bg(cx.theme().colors().tab_bar_background) + .border_b_1() + .border_color(cx.theme().colors().border) + .child( + h_flex() + .size_full() + .gap(DynamicSpacing::Base04.rems(cx)) + .pl(DynamicSpacing::Base04.rems(cx)) + .child(selected_agent) + .child(agent_selector_menu) + .child(self.render_start_thread_in_selector(cx)), + ) + .child( + h_flex() + .flex_none() + .gap(DynamicSpacing::Base02.rems(cx)) + .pl(DynamicSpacing::Base04.rems(cx)) + .pr(DynamicSpacing::Base06.rems(cx)) + .when(show_history_menu, |this| { + this.child(self.render_recent_entries_menu( + IconName::MenuAltTemp, + Corner::TopRight, + cx, + )) + }) + .child(self.render_panel_options_menu(window, cx)), + ) + .into_any_element() + } else { + let new_thread_menu = PopoverMenu::new("new_thread_menu") + .trigger_with_tooltip( + IconButton::new("new_thread_menu_btn", IconName::Plus) + .icon_size(IconSize::Small), + { + move |_window, cx| { + Tooltip::for_action_in( + "New Thread\u{2026}", + &ToggleNewThreadMenu, + &focus_handle, + cx, + ) } - _ => selected_agent.into_any_element(), - }) - .child(self.render_title_view(window, cx)), - ) - .child( - h_flex() - .flex_none() - .gap(DynamicSpacing::Base02.rems(cx)) - .pl(DynamicSpacing::Base04.rems(cx)) - .pr(DynamicSpacing::Base06.rems(cx)) - .when( - has_v2_flag && !self.active_thread_has_messages(cx), - |this| this.child(self.render_start_thread_in_selector(cx)), - ) - .child(new_thread_menu) - .when(show_history_menu, |this| { - this.child(self.render_recent_entries_menu( - IconName::MenuAltTemp, - Corner::TopRight, - cx, - )) - }) - .child(self.render_panel_options_menu(window, cx)), - ) + }, + ) + .anchor(Corner::TopRight) + .with_handle(self.new_thread_menu_handle.clone()) + .menu(move |window, cx| new_thread_menu_builder(window, cx)); + + h_flex() + .id("agent-panel-toolbar") + .h(Tab::container_height(cx)) + .max_w_full() + .flex_none() + .justify_between() + .gap_2() + .bg(cx.theme().colors().tab_bar_background) + .border_b_1() + .border_color(cx.theme().colors().border) + .child( + h_flex() + .size_full() + .gap(DynamicSpacing::Base04.rems(cx)) + .pl(DynamicSpacing::Base04.rems(cx)) + .child(match &self.active_view { + ActiveView::History { .. } | ActiveView::Configuration => { + self.render_toolbar_back_button(cx).into_any_element() + } + _ => selected_agent.into_any_element(), + }) + .child(self.render_title_view(window, cx)), + ) + .child( + h_flex() + .flex_none() + .gap(DynamicSpacing::Base02.rems(cx)) + .pl(DynamicSpacing::Base04.rems(cx)) + .pr(DynamicSpacing::Base06.rems(cx)) + .child(new_thread_menu) + .when(show_history_menu, |this| { + this.child(self.render_recent_entries_menu( + IconName::MenuAltTemp, + Corner::TopRight, + cx, + )) + }) + .child(self.render_panel_options_menu(window, cx)), + ) + .into_any_element() + } } fn render_worktree_creation_status(&self, cx: &mut Context) -> Option {