agent2: Add new "new thread" selector in the toolbar (#36133)
Release Notes: - N/A
This commit is contained in:
parent
9a375f1419
commit
cb0bc463f1
7 changed files with 526 additions and 328 deletions
|
@ -239,6 +239,7 @@
|
||||||
"ctrl-shift-a": "agent::ToggleContextPicker",
|
"ctrl-shift-a": "agent::ToggleContextPicker",
|
||||||
"ctrl-shift-j": "agent::ToggleNavigationMenu",
|
"ctrl-shift-j": "agent::ToggleNavigationMenu",
|
||||||
"ctrl-shift-i": "agent::ToggleOptionsMenu",
|
"ctrl-shift-i": "agent::ToggleOptionsMenu",
|
||||||
|
"ctrl-alt-shift-n": "agent::ToggleNewThreadMenu",
|
||||||
"shift-alt-escape": "agent::ExpandMessageEditor",
|
"shift-alt-escape": "agent::ExpandMessageEditor",
|
||||||
"ctrl->": "assistant::QuoteSelection",
|
"ctrl->": "assistant::QuoteSelection",
|
||||||
"ctrl-alt-e": "agent::RemoveAllContext",
|
"ctrl-alt-e": "agent::RemoveAllContext",
|
||||||
|
|
|
@ -279,6 +279,7 @@
|
||||||
"cmd-shift-a": "agent::ToggleContextPicker",
|
"cmd-shift-a": "agent::ToggleContextPicker",
|
||||||
"cmd-shift-j": "agent::ToggleNavigationMenu",
|
"cmd-shift-j": "agent::ToggleNavigationMenu",
|
||||||
"cmd-shift-i": "agent::ToggleOptionsMenu",
|
"cmd-shift-i": "agent::ToggleOptionsMenu",
|
||||||
|
"cmd-alt-shift-n": "agent::ToggleNewThreadMenu",
|
||||||
"shift-alt-escape": "agent::ExpandMessageEditor",
|
"shift-alt-escape": "agent::ExpandMessageEditor",
|
||||||
"cmd->": "assistant::QuoteSelection",
|
"cmd->": "assistant::QuoteSelection",
|
||||||
"cmd-alt-e": "agent::RemoveAllContext",
|
"cmd-alt-e": "agent::RemoveAllContext",
|
||||||
|
|
|
@ -12,12 +12,12 @@ use serde::{Deserialize, Serialize};
|
||||||
use crate::NewExternalAgentThread;
|
use crate::NewExternalAgentThread;
|
||||||
use crate::agent_diff::AgentDiffThread;
|
use crate::agent_diff::AgentDiffThread;
|
||||||
use crate::message_editor::{MAX_EDITOR_LINES, MIN_EDITOR_LINES};
|
use crate::message_editor::{MAX_EDITOR_LINES, MIN_EDITOR_LINES};
|
||||||
use crate::ui::NewThreadButton;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode,
|
AddContextServer, AgentDiffPane, ContinueThread, ContinueWithBurnMode,
|
||||||
DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread,
|
DeleteRecentlyOpenThread, ExpandMessageEditor, Follow, InlineAssistant, NewTextThread,
|
||||||
NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell,
|
NewThread, OpenActiveThreadAsMarkdown, OpenAgentDiff, OpenHistory, ResetTrialEndUpsell,
|
||||||
ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu, ToggleOptionsMenu,
|
ResetTrialUpsell, ToggleBurnMode, ToggleContextPicker, ToggleNavigationMenu,
|
||||||
|
ToggleNewThreadMenu, ToggleOptionsMenu,
|
||||||
acp::AcpThreadView,
|
acp::AcpThreadView,
|
||||||
active_thread::{self, ActiveThread, ActiveThreadEvent},
|
active_thread::{self, ActiveThread, ActiveThreadEvent},
|
||||||
agent_configuration::{AgentConfiguration, AssistantConfigurationEvent},
|
agent_configuration::{AgentConfiguration, AssistantConfigurationEvent},
|
||||||
|
@ -67,8 +67,8 @@ use theme::ThemeSettings;
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use ui::utils::WithRemSize;
|
use ui::utils::WithRemSize;
|
||||||
use ui::{
|
use ui::{
|
||||||
Banner, Callout, ContextMenu, ContextMenuEntry, ElevationIndex, KeyBinding, PopoverMenu,
|
Banner, ButtonLike, Callout, ContextMenu, ContextMenuEntry, ElevationIndex, KeyBinding,
|
||||||
PopoverMenuHandle, ProgressBar, Tab, Tooltip, prelude::*,
|
PopoverMenu, PopoverMenuHandle, ProgressBar, Tab, Tooltip, prelude::*,
|
||||||
};
|
};
|
||||||
use util::ResultExt as _;
|
use util::ResultExt as _;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
|
@ -86,6 +86,7 @@ const AGENT_PANEL_KEY: &str = "agent_panel";
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct SerializedAgentPanel {
|
struct SerializedAgentPanel {
|
||||||
width: Option<Pixels>,
|
width: Option<Pixels>,
|
||||||
|
selected_agent: Option<AgentType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
|
@ -179,6 +180,14 @@ pub fn init(cx: &mut App) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.register_action(|workspace, _: &ToggleNewThreadMenu, window, cx| {
|
||||||
|
if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
|
||||||
|
workspace.focus_panel::<AgentPanel>(window, cx);
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.toggle_new_thread_menu(&ToggleNewThreadMenu, window, cx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
.register_action(|workspace, _: &OpenOnboardingModal, window, cx| {
|
.register_action(|workspace, _: &OpenOnboardingModal, window, cx| {
|
||||||
AgentOnboardingModal::toggle(workspace, window, cx)
|
AgentOnboardingModal::toggle(workspace, window, cx)
|
||||||
})
|
})
|
||||||
|
@ -223,6 +232,36 @@ enum WhichFontSize {
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub enum AgentType {
|
||||||
|
#[default]
|
||||||
|
Zed,
|
||||||
|
TextThread,
|
||||||
|
Gemini,
|
||||||
|
ClaudeCode,
|
||||||
|
NativeAgent,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AgentType {
|
||||||
|
fn label(self) -> impl Into<SharedString> {
|
||||||
|
match self {
|
||||||
|
Self::Zed | Self::TextThread => "Zed",
|
||||||
|
Self::NativeAgent => "Agent 2",
|
||||||
|
Self::Gemini => "Gemini",
|
||||||
|
Self::ClaudeCode => "Claude Code",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn icon(self) -> IconName {
|
||||||
|
match self {
|
||||||
|
Self::Zed | Self::TextThread => IconName::AiZed,
|
||||||
|
Self::NativeAgent => IconName::ZedAssistant,
|
||||||
|
Self::Gemini => IconName::AiGemini,
|
||||||
|
Self::ClaudeCode => IconName::AiClaude,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveView {
|
impl ActiveView {
|
||||||
pub fn which_font_size_used(&self) -> WhichFontSize {
|
pub fn which_font_size_used(&self) -> WhichFontSize {
|
||||||
match self {
|
match self {
|
||||||
|
@ -453,16 +492,21 @@ pub struct AgentPanel {
|
||||||
zoomed: bool,
|
zoomed: bool,
|
||||||
pending_serialization: Option<Task<Result<()>>>,
|
pending_serialization: Option<Task<Result<()>>>,
|
||||||
onboarding: Entity<AgentPanelOnboarding>,
|
onboarding: Entity<AgentPanelOnboarding>,
|
||||||
|
selected_agent: AgentType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AgentPanel {
|
impl AgentPanel {
|
||||||
fn serialize(&mut self, cx: &mut Context<Self>) {
|
fn serialize(&mut self, cx: &mut Context<Self>) {
|
||||||
let width = self.width;
|
let width = self.width;
|
||||||
|
let selected_agent = self.selected_agent;
|
||||||
self.pending_serialization = Some(cx.background_spawn(async move {
|
self.pending_serialization = Some(cx.background_spawn(async move {
|
||||||
KEY_VALUE_STORE
|
KEY_VALUE_STORE
|
||||||
.write_kvp(
|
.write_kvp(
|
||||||
AGENT_PANEL_KEY.into(),
|
AGENT_PANEL_KEY.into(),
|
||||||
serde_json::to_string(&SerializedAgentPanel { width })?,
|
serde_json::to_string(&SerializedAgentPanel {
|
||||||
|
width,
|
||||||
|
selected_agent: Some(selected_agent),
|
||||||
|
})?,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
anyhow::Ok(())
|
anyhow::Ok(())
|
||||||
|
@ -531,6 +575,9 @@ impl AgentPanel {
|
||||||
if let Some(serialized_panel) = serialized_panel {
|
if let Some(serialized_panel) = serialized_panel {
|
||||||
panel.update(cx, |panel, cx| {
|
panel.update(cx, |panel, cx| {
|
||||||
panel.width = serialized_panel.width.map(|w| w.round());
|
panel.width = serialized_panel.width.map(|w| w.round());
|
||||||
|
if let Some(selected_agent) = serialized_panel.selected_agent {
|
||||||
|
panel.selected_agent = selected_agent;
|
||||||
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -732,6 +779,7 @@ impl AgentPanel {
|
||||||
zoomed: false,
|
zoomed: false,
|
||||||
pending_serialization: None,
|
pending_serialization: None,
|
||||||
onboarding,
|
onboarding,
|
||||||
|
selected_agent: AgentType::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,6 +1222,15 @@ impl AgentPanel {
|
||||||
self.agent_panel_menu_handle.toggle(window, cx);
|
self.agent_panel_menu_handle.toggle(window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn toggle_new_thread_menu(
|
||||||
|
&mut self,
|
||||||
|
_: &ToggleNewThreadMenu,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
|
self.new_thread_menu_handle.toggle(window, cx);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increase_font_size(
|
pub fn increase_font_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
action: &IncreaseBufferFontSize,
|
action: &IncreaseBufferFontSize,
|
||||||
|
@ -1581,6 +1638,17 @@ impl AgentPanel {
|
||||||
|
|
||||||
menu
|
menu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_selected_agent(&mut self, agent: AgentType, cx: &mut Context<Self>) {
|
||||||
|
if self.selected_agent != agent {
|
||||||
|
self.selected_agent = agent;
|
||||||
|
self.serialize(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn selected_agent(&self) -> AgentType {
|
||||||
|
self.selected_agent
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Focusable for AgentPanel {
|
impl Focusable for AgentPanel {
|
||||||
|
@ -1811,200 +1879,24 @@ impl AgentPanel {
|
||||||
.into_any()
|
.into_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render_panel_options_menu(
|
||||||
|
&self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> impl IntoElement {
|
||||||
let user_store = self.user_store.read(cx);
|
let user_store = self.user_store.read(cx);
|
||||||
let usage = user_store.model_request_usage();
|
let usage = user_store.model_request_usage();
|
||||||
|
|
||||||
let account_url = zed_urls::account_url(cx);
|
let account_url = zed_urls::account_url(cx);
|
||||||
|
|
||||||
let focus_handle = self.focus_handle(cx);
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
let go_back_button = div().child(
|
|
||||||
IconButton::new("go-back", IconName::ArrowLeft)
|
|
||||||
.icon_size(IconSize::Small)
|
|
||||||
.on_click(cx.listener(|this, _, window, cx| {
|
|
||||||
this.go_back(&workspace::GoBack, window, cx);
|
|
||||||
}))
|
|
||||||
.tooltip({
|
|
||||||
let focus_handle = focus_handle.clone();
|
|
||||||
move |window, cx| {
|
|
||||||
Tooltip::for_action_in(
|
|
||||||
"Go Back",
|
|
||||||
&workspace::GoBack,
|
|
||||||
&focus_handle,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let recent_entries_menu = div().child(
|
|
||||||
PopoverMenu::new("agent-nav-menu")
|
|
||||||
.trigger_with_tooltip(
|
|
||||||
IconButton::new("agent-nav-menu", IconName::MenuAlt)
|
|
||||||
.icon_size(IconSize::Small)
|
|
||||||
.style(ui::ButtonStyle::Subtle),
|
|
||||||
{
|
|
||||||
let focus_handle = focus_handle.clone();
|
|
||||||
move |window, cx| {
|
|
||||||
Tooltip::for_action_in(
|
|
||||||
"Toggle Panel Menu",
|
|
||||||
&ToggleNavigationMenu,
|
|
||||||
&focus_handle,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.anchor(Corner::TopLeft)
|
|
||||||
.with_handle(self.assistant_navigation_menu_handle.clone())
|
|
||||||
.menu({
|
|
||||||
let menu = self.assistant_navigation_menu.clone();
|
|
||||||
move |window, cx| {
|
|
||||||
if let Some(menu) = menu.as_ref() {
|
|
||||||
menu.update(cx, |_, cx| {
|
|
||||||
cx.defer_in(window, |menu, window, cx| {
|
|
||||||
menu.rebuild(window, cx);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
menu.clone()
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let full_screen_label = if self.is_zoomed(window, cx) {
|
let full_screen_label = if self.is_zoomed(window, cx) {
|
||||||
"Disable Full Screen"
|
"Disable Full Screen"
|
||||||
} else {
|
} else {
|
||||||
"Enable Full Screen"
|
"Enable Full Screen"
|
||||||
};
|
};
|
||||||
|
|
||||||
let active_thread = match &self.active_view {
|
PopoverMenu::new("agent-options-menu")
|
||||||
ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
|
|
||||||
ActiveView::ExternalAgentThread { .. }
|
|
||||||
| ActiveView::TextThread { .. }
|
|
||||||
| ActiveView::History
|
|
||||||
| 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),
|
|
||||||
Tooltip::text("New Thread…"),
|
|
||||||
)
|
|
||||||
.anchor(Corner::TopRight)
|
|
||||||
.with_handle(self.new_thread_menu_handle.clone())
|
|
||||||
.menu({
|
|
||||||
let focus_handle = focus_handle.clone();
|
|
||||||
move |window, cx| {
|
|
||||||
let active_thread = active_thread.clone();
|
|
||||||
Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
|
|
||||||
menu = menu
|
|
||||||
.context(focus_handle.clone())
|
|
||||||
.when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
|
|
||||||
this.header("Zed Agent")
|
|
||||||
})
|
|
||||||
.when_some(active_thread, |this, active_thread| {
|
|
||||||
let thread = active_thread.read(cx);
|
|
||||||
|
|
||||||
if !thread.is_empty() {
|
|
||||||
let thread_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(NewThread {
|
|
||||||
from_thread_id: Some(thread_id.clone()),
|
|
||||||
}),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.item(
|
|
||||||
ContextMenuEntry::new("New Thread")
|
|
||||||
.icon(IconName::Thread)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.action(NewThread::default().boxed_clone())
|
|
||||||
.handler(move |window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
NewThread::default().boxed_clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.item(
|
|
||||||
ContextMenuEntry::new("New Text Thread")
|
|
||||||
.icon(IconName::TextThread)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.action(NewTextThread.boxed_clone())
|
|
||||||
.handler(move |window, cx| {
|
|
||||||
window.dispatch_action(NewTextThread.boxed_clone(), cx);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
|
|
||||||
this.separator()
|
|
||||||
.header("External Agents")
|
|
||||||
.item(
|
|
||||||
ContextMenuEntry::new("New Gemini Thread")
|
|
||||||
.icon(IconName::AiGemini)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.handler(move |window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
NewExternalAgentThread {
|
|
||||||
agent: Some(crate::ExternalAgent::Gemini),
|
|
||||||
}
|
|
||||||
.boxed_clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.item(
|
|
||||||
ContextMenuEntry::new("New Claude Code Thread")
|
|
||||||
.icon(IconName::AiClaude)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.handler(move |window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
NewExternalAgentThread {
|
|
||||||
agent: Some(
|
|
||||||
crate::ExternalAgent::ClaudeCode,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.boxed_clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.item(
|
|
||||||
ContextMenuEntry::new("New Native Agent Thread")
|
|
||||||
.icon(IconName::ZedAssistant)
|
|
||||||
.icon_color(Color::Muted)
|
|
||||||
.handler(move |window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
NewExternalAgentThread {
|
|
||||||
agent: Some(
|
|
||||||
crate::ExternalAgent::NativeAgent,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.boxed_clone(),
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
menu
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let agent_panel_menu = PopoverMenu::new("agent-options-menu")
|
|
||||||
.trigger_with_tooltip(
|
.trigger_with_tooltip(
|
||||||
IconButton::new("agent-options-menu", IconName::Ellipsis)
|
IconButton::new("agent-options-menu", IconName::Ellipsis)
|
||||||
.icon_size(IconSize::Small),
|
.icon_size(IconSize::Small),
|
||||||
|
@ -2087,6 +1979,139 @@ impl AgentPanel {
|
||||||
menu
|
menu
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_recent_entries_menu(
|
||||||
|
&self,
|
||||||
|
icon: IconName,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> impl IntoElement {
|
||||||
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
|
PopoverMenu::new("agent-nav-menu")
|
||||||
|
.trigger_with_tooltip(
|
||||||
|
IconButton::new("agent-nav-menu", icon)
|
||||||
|
.icon_size(IconSize::Small)
|
||||||
|
.style(ui::ButtonStyle::Subtle),
|
||||||
|
{
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"Toggle Panel Menu",
|
||||||
|
&ToggleNavigationMenu,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.anchor(Corner::TopLeft)
|
||||||
|
.with_handle(self.assistant_navigation_menu_handle.clone())
|
||||||
|
.menu({
|
||||||
|
let menu = self.assistant_navigation_menu.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
if let Some(menu) = menu.as_ref() {
|
||||||
|
menu.update(cx, |_, cx| {
|
||||||
|
cx.defer_in(window, |menu, window, cx| {
|
||||||
|
menu.rebuild(window, cx);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
menu.clone()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_toolbar_back_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
|
IconButton::new("go-back", IconName::ArrowLeft)
|
||||||
|
.icon_size(IconSize::Small)
|
||||||
|
.on_click(cx.listener(|this, _, window, cx| {
|
||||||
|
this.go_back(&workspace::GoBack, window, cx);
|
||||||
|
}))
|
||||||
|
.tooltip({
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
|
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in("Go Back", &workspace::GoBack, &focus_handle, window, cx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_toolbar_old(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
|
let active_thread = match &self.active_view {
|
||||||
|
ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
|
||||||
|
ActiveView::ExternalAgentThread { .. }
|
||||||
|
| ActiveView::TextThread { .. }
|
||||||
|
| ActiveView::History
|
||||||
|
| 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),
|
||||||
|
Tooltip::text("New Thread…"),
|
||||||
|
)
|
||||||
|
.anchor(Corner::TopRight)
|
||||||
|
.with_handle(self.new_thread_menu_handle.clone())
|
||||||
|
.menu({
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
let active_thread = active_thread.clone();
|
||||||
|
Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
|
||||||
|
menu = menu
|
||||||
|
.context(focus_handle.clone())
|
||||||
|
.when_some(active_thread, |this, active_thread| {
|
||||||
|
let thread = active_thread.read(cx);
|
||||||
|
|
||||||
|
if !thread.is_empty() {
|
||||||
|
let thread_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(NewThread {
|
||||||
|
from_thread_id: Some(thread_id.clone()),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Thread")
|
||||||
|
.icon(IconName::Thread)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.action(NewThread::default().boxed_clone())
|
||||||
|
.handler(move |window, cx| {
|
||||||
|
window.dispatch_action(
|
||||||
|
NewThread::default().boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Text Thread")
|
||||||
|
.icon(IconName::TextThread)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.action(NewTextThread.boxed_clone())
|
||||||
|
.handler(move |window, cx| {
|
||||||
|
window.dispatch_action(NewTextThread.boxed_clone(), cx);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
menu
|
||||||
|
}))
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
h_flex()
|
h_flex()
|
||||||
|
@ -2105,8 +2130,12 @@ impl AgentPanel {
|
||||||
.pl_1()
|
.pl_1()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
.child(match &self.active_view {
|
.child(match &self.active_view {
|
||||||
ActiveView::History | ActiveView::Configuration => go_back_button,
|
ActiveView::History | ActiveView::Configuration => {
|
||||||
_ => recent_entries_menu,
|
self.render_toolbar_back_button(cx).into_any_element()
|
||||||
|
}
|
||||||
|
_ => self
|
||||||
|
.render_recent_entries_menu(IconName::MenuAlt, cx)
|
||||||
|
.into_any_element(),
|
||||||
})
|
})
|
||||||
.child(self.render_title_view(window, cx)),
|
.child(self.render_title_view(window, cx)),
|
||||||
)
|
)
|
||||||
|
@ -2123,11 +2152,308 @@ impl AgentPanel {
|
||||||
.border_l_1()
|
.border_l_1()
|
||||||
.border_color(cx.theme().colors().border)
|
.border_color(cx.theme().colors().border)
|
||||||
.child(new_thread_menu)
|
.child(new_thread_menu)
|
||||||
.child(agent_panel_menu),
|
.child(self.render_panel_options_menu(window, cx)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_toolbar_new(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let focus_handle = self.focus_handle(cx);
|
||||||
|
|
||||||
|
let active_thread = match &self.active_view {
|
||||||
|
ActiveView::Thread { thread, .. } => Some(thread.read(cx).thread().clone()),
|
||||||
|
ActiveView::ExternalAgentThread { .. }
|
||||||
|
| ActiveView::TextThread { .. }
|
||||||
|
| ActiveView::History
|
||||||
|
| ActiveView::Configuration => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_thread_menu = PopoverMenu::new("new_thread_menu")
|
||||||
|
.trigger_with_tooltip(
|
||||||
|
ButtonLike::new("new_thread_menu_btn").child(
|
||||||
|
h_flex()
|
||||||
|
.group("agent-selector")
|
||||||
|
.gap_1p5()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.relative()
|
||||||
|
.size_4()
|
||||||
|
.justify_center()
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.group_hover("agent-selector", |s| s.invisible())
|
||||||
|
.child(
|
||||||
|
Icon::new(self.selected_agent.icon())
|
||||||
|
.color(Color::Muted),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.absolute()
|
||||||
|
.invisible()
|
||||||
|
.group_hover("agent-selector", |s| s.visible())
|
||||||
|
.child(Icon::new(IconName::Plus)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(Label::new(self.selected_agent.label())),
|
||||||
|
),
|
||||||
|
{
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
|
move |window, cx| {
|
||||||
|
Tooltip::for_action_in(
|
||||||
|
"New…",
|
||||||
|
&ToggleNewThreadMenu,
|
||||||
|
&focus_handle,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.anchor(Corner::TopLeft)
|
||||||
|
.with_handle(self.new_thread_menu_handle.clone())
|
||||||
|
.menu({
|
||||||
|
let focus_handle = focus_handle.clone();
|
||||||
|
let workspace = self.workspace.clone();
|
||||||
|
|
||||||
|
move |window, cx| {
|
||||||
|
let active_thread = active_thread.clone();
|
||||||
|
Some(ContextMenu::build(window, cx, |mut menu, _window, cx| {
|
||||||
|
menu = menu
|
||||||
|
.context(focus_handle.clone())
|
||||||
|
.header("Zed Agent")
|
||||||
|
.when_some(active_thread, |this, active_thread| {
|
||||||
|
let thread = active_thread.read(cx);
|
||||||
|
|
||||||
|
if !thread.is_empty() {
|
||||||
|
let thread_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(NewThread {
|
||||||
|
from_thread_id: Some(thread_id.clone()),
|
||||||
|
}),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Thread")
|
||||||
|
.icon(IconName::Thread)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.action(NewThread::default().boxed_clone())
|
||||||
|
.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::<AgentPanel>(cx)
|
||||||
|
{
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.set_selected_agent(
|
||||||
|
AgentType::Zed,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.dispatch_action(
|
||||||
|
NewThread::default().boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Text Thread")
|
||||||
|
.icon(IconName::TextThread)
|
||||||
|
.icon_color(Color::Muted)
|
||||||
|
.action(NewTextThread.boxed_clone())
|
||||||
|
.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::<AgentPanel>(cx)
|
||||||
|
{
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.set_selected_agent(
|
||||||
|
AgentType::TextThread,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.dispatch_action(NewTextThread.boxed_clone(), cx);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Native Agent Thread")
|
||||||
|
.icon(IconName::ZedAssistant)
|
||||||
|
.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::<AgentPanel>(cx)
|
||||||
|
{
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.set_selected_agent(
|
||||||
|
AgentType::NativeAgent,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.dispatch_action(
|
||||||
|
NewExternalAgentThread {
|
||||||
|
agent: Some(crate::ExternalAgent::NativeAgent),
|
||||||
|
}
|
||||||
|
.boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.separator()
|
||||||
|
.header("External Agents")
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Gemini Thread")
|
||||||
|
.icon(IconName::AiGemini)
|
||||||
|
.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::<AgentPanel>(cx)
|
||||||
|
{
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.set_selected_agent(
|
||||||
|
AgentType::Gemini,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.dispatch_action(
|
||||||
|
NewExternalAgentThread {
|
||||||
|
agent: Some(crate::ExternalAgent::Gemini),
|
||||||
|
}
|
||||||
|
.boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.item(
|
||||||
|
ContextMenuEntry::new("New Claude Code Thread")
|
||||||
|
.icon(IconName::AiClaude)
|
||||||
|
.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::<AgentPanel>(cx)
|
||||||
|
{
|
||||||
|
panel.update(cx, |panel, cx| {
|
||||||
|
panel.set_selected_agent(
|
||||||
|
AgentType::ClaudeCode,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.dispatch_action(
|
||||||
|
NewExternalAgentThread {
|
||||||
|
agent: Some(crate::ExternalAgent::ClaudeCode),
|
||||||
|
}
|
||||||
|
.boxed_clone(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
menu
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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::Base08.rems(cx))
|
||||||
|
.child(match &self.active_view {
|
||||||
|
ActiveView::History | ActiveView::Configuration => {
|
||||||
|
self.render_toolbar_back_button(cx).into_any_element()
|
||||||
|
}
|
||||||
|
_ => h_flex()
|
||||||
|
.h_full()
|
||||||
|
.px(DynamicSpacing::Base04.rems(cx))
|
||||||
|
.border_r_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.child(new_thread_menu)
|
||||||
|
.into_any_element(),
|
||||||
|
})
|
||||||
|
.child(self.render_title_view(window, cx)),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.h_full()
|
||||||
|
.gap_2()
|
||||||
|
.children(self.render_token_count(cx))
|
||||||
|
.child(
|
||||||
|
h_flex()
|
||||||
|
.h_full()
|
||||||
|
.gap(DynamicSpacing::Base02.rems(cx))
|
||||||
|
.pl(DynamicSpacing::Base04.rems(cx))
|
||||||
|
.pr(DynamicSpacing::Base06.rems(cx))
|
||||||
|
.border_l_1()
|
||||||
|
.border_color(cx.theme().colors().border)
|
||||||
|
.child(self.render_recent_entries_menu(IconName::HistoryRerun, cx))
|
||||||
|
.child(self.render_panel_options_menu(window, cx)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
if cx.has_flag::<feature_flags::AcpFeatureFlag>() {
|
||||||
|
self.render_toolbar_new(window, cx).into_any_element()
|
||||||
|
} else {
|
||||||
|
self.render_toolbar_old(window, cx).into_any_element()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn render_token_count(&self, cx: &App) -> Option<AnyElement> {
|
fn render_token_count(&self, cx: &App) -> Option<AnyElement> {
|
||||||
match &self.active_view {
|
match &self.active_view {
|
||||||
ActiveView::Thread {
|
ActiveView::Thread {
|
||||||
|
@ -2576,138 +2902,6 @@ impl AgentPanel {
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
.child(self.render_empty_state_section_header("Start", None, cx))
|
|
||||||
.child(
|
|
||||||
v_flex()
|
|
||||||
.p_1()
|
|
||||||
.gap_2()
|
|
||||||
.child(
|
|
||||||
h_flex()
|
|
||||||
.w_full()
|
|
||||||
.gap_2()
|
|
||||||
.child(
|
|
||||||
NewThreadButton::new(
|
|
||||||
"new-thread-btn",
|
|
||||||
"New Thread",
|
|
||||||
IconName::Thread,
|
|
||||||
)
|
|
||||||
.keybinding(KeyBinding::for_action_in(
|
|
||||||
&NewThread::default(),
|
|
||||||
&self.focus_handle(cx),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
))
|
|
||||||
.on_click(
|
|
||||||
|window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
NewThread::default().boxed_clone(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
NewThreadButton::new(
|
|
||||||
"new-text-thread-btn",
|
|
||||||
"New Text Thread",
|
|
||||||
IconName::TextThread,
|
|
||||||
)
|
|
||||||
.keybinding(KeyBinding::for_action_in(
|
|
||||||
&NewTextThread,
|
|
||||||
&self.focus_handle(cx),
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
))
|
|
||||||
.on_click(
|
|
||||||
|window, cx| {
|
|
||||||
window.dispatch_action(Box::new(NewTextThread), cx)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.when(cx.has_flag::<feature_flags::AcpFeatureFlag>(), |this| {
|
|
||||||
this.child(
|
|
||||||
h_flex()
|
|
||||||
.w_full()
|
|
||||||
.gap_2()
|
|
||||||
.child(
|
|
||||||
NewThreadButton::new(
|
|
||||||
"new-gemini-thread-btn",
|
|
||||||
"New Gemini Thread",
|
|
||||||
IconName::AiGemini,
|
|
||||||
)
|
|
||||||
// .keybinding(KeyBinding::for_action_in(
|
|
||||||
// &OpenHistory,
|
|
||||||
// &self.focus_handle(cx),
|
|
||||||
// window,
|
|
||||||
// cx,
|
|
||||||
// ))
|
|
||||||
.on_click(
|
|
||||||
|window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
Box::new(NewExternalAgentThread {
|
|
||||||
agent: Some(
|
|
||||||
crate::ExternalAgent::Gemini,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
NewThreadButton::new(
|
|
||||||
"new-claude-thread-btn",
|
|
||||||
"New Claude Code Thread",
|
|
||||||
IconName::AiClaude,
|
|
||||||
)
|
|
||||||
// .keybinding(KeyBinding::for_action_in(
|
|
||||||
// &OpenHistory,
|
|
||||||
// &self.focus_handle(cx),
|
|
||||||
// window,
|
|
||||||
// cx,
|
|
||||||
// ))
|
|
||||||
.on_click(
|
|
||||||
|window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
Box::new(NewExternalAgentThread {
|
|
||||||
agent: Some(
|
|
||||||
crate::ExternalAgent::ClaudeCode,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
NewThreadButton::new(
|
|
||||||
"new-native-agent-thread-btn",
|
|
||||||
"New Native Agent Thread",
|
|
||||||
IconName::ZedAssistant,
|
|
||||||
)
|
|
||||||
// .keybinding(KeyBinding::for_action_in(
|
|
||||||
// &OpenHistory,
|
|
||||||
// &self.focus_handle(cx),
|
|
||||||
// window,
|
|
||||||
// cx,
|
|
||||||
// ))
|
|
||||||
.on_click(
|
|
||||||
|window, cx| {
|
|
||||||
window.dispatch_action(
|
|
||||||
Box::new(NewExternalAgentThread {
|
|
||||||
agent: Some(
|
|
||||||
crate::ExternalAgent::NativeAgent,
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.when_some(configuration_error.as_ref(), |this, err| {
|
.when_some(configuration_error.as_ref(), |this, err| {
|
||||||
this.child(self.render_configuration_error(err, &focus_handle, window, cx))
|
this.child(self.render_configuration_error(err, &focus_handle, window, cx))
|
||||||
})
|
})
|
||||||
|
|
|
@ -64,6 +64,8 @@ actions!(
|
||||||
NewTextThread,
|
NewTextThread,
|
||||||
/// Toggles the context picker interface for adding files, symbols, or other context.
|
/// Toggles the context picker interface for adding files, symbols, or other context.
|
||||||
ToggleContextPicker,
|
ToggleContextPicker,
|
||||||
|
/// Toggles the menu to create new agent threads.
|
||||||
|
ToggleNewThreadMenu,
|
||||||
/// Toggles the navigation menu for switching between threads and views.
|
/// Toggles the navigation menu for switching between threads and views.
|
||||||
ToggleNavigationMenu,
|
ToggleNavigationMenu,
|
||||||
/// Toggles the options menu for agent settings and preferences.
|
/// Toggles the options menu for agent settings and preferences.
|
||||||
|
|
|
@ -2,7 +2,7 @@ mod agent_notification;
|
||||||
mod burn_mode_tooltip;
|
mod burn_mode_tooltip;
|
||||||
mod context_pill;
|
mod context_pill;
|
||||||
mod end_trial_upsell;
|
mod end_trial_upsell;
|
||||||
mod new_thread_button;
|
// mod new_thread_button;
|
||||||
mod onboarding_modal;
|
mod onboarding_modal;
|
||||||
pub mod preview;
|
pub mod preview;
|
||||||
|
|
||||||
|
@ -10,5 +10,5 @@ pub use agent_notification::*;
|
||||||
pub use burn_mode_tooltip::*;
|
pub use burn_mode_tooltip::*;
|
||||||
pub use context_pill::*;
|
pub use context_pill::*;
|
||||||
pub use end_trial_upsell::*;
|
pub use end_trial_upsell::*;
|
||||||
pub use new_thread_button::*;
|
// pub use new_thread_button::*;
|
||||||
pub use onboarding_modal::*;
|
pub use onboarding_modal::*;
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub struct NewThreadButton {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NewThreadButton {
|
impl NewThreadButton {
|
||||||
pub fn new(id: impl Into<ElementId>, label: impl Into<SharedString>, icon: IconName) -> Self {
|
fn new(id: impl Into<ElementId>, label: impl Into<SharedString>, icon: IconName) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
label: label.into(),
|
label: label.into(),
|
||||||
|
@ -21,12 +21,12 @@ impl NewThreadButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keybinding(mut self, keybinding: Option<ui::KeyBinding>) -> Self {
|
fn keybinding(mut self, keybinding: Option<ui::KeyBinding>) -> Self {
|
||||||
self.keybinding = keybinding;
|
self.keybinding = keybinding;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_click<F>(mut self, handler: F) -> Self
|
fn on_click<F>(mut self, handler: F) -> Self
|
||||||
where
|
where
|
||||||
F: Fn(&mut Window, &mut App) + 'static,
|
F: Fn(&mut Window, &mut App) + 'static,
|
||||||
{
|
{
|
||||||
|
|
|
@ -761,7 +761,7 @@ impl Render for ComponentPreview {
|
||||||
)
|
)
|
||||||
.track_scroll(self.nav_scroll_handle.clone())
|
.track_scroll(self.nav_scroll_handle.clone())
|
||||||
.p_2p5()
|
.p_2p5()
|
||||||
.w(px(229.))
|
.w(px(231.)) // Matches perfectly with the size of the "Component Preview" tab, if that's the first one in the pane
|
||||||
.h_full()
|
.h_full()
|
||||||
.flex_1(),
|
.flex_1(),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue