Compare commits
3 Commits
additional
...
test-threa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e984c18257 | ||
|
|
3166569c9a | ||
|
|
440bb2ff04 |
@@ -3,6 +3,7 @@ mod agent_configuration;
|
||||
mod agent_diff;
|
||||
mod agent_model_selector;
|
||||
mod agent_panel;
|
||||
pub mod agents_panel;
|
||||
mod buffer_codegen;
|
||||
mod context;
|
||||
mod context_picker;
|
||||
@@ -249,6 +250,7 @@ pub fn init(
|
||||
cx: &mut App,
|
||||
) {
|
||||
AgentSettings::register(cx);
|
||||
agents_panel::init(cx);
|
||||
|
||||
assistant_text_thread::init(client.clone(), cx);
|
||||
rules_library::init(cx);
|
||||
|
||||
181
crates/agent_ui/src/agents_panel.rs
Normal file
181
crates/agent_ui/src/agents_panel.rs
Normal file
@@ -0,0 +1,181 @@
|
||||
use gpui::{EventEmitter, Focusable, actions};
|
||||
use ui::{
|
||||
App, Context, IconName, IntoElement, Label, LabelCommon as _, LabelSize, ListItem,
|
||||
ListItemSpacing, ParentElement, Render, RenderOnce, Styled, Toggleable as _, Window, div,
|
||||
h_flex, px,
|
||||
};
|
||||
use workspace::{Panel, Workspace, dock::PanelEvent};
|
||||
|
||||
actions!(
|
||||
agents,
|
||||
[
|
||||
/// Toggle the visibility of the agents panel.
|
||||
ToggleAgentsPanel
|
||||
]
|
||||
);
|
||||
|
||||
pub fn init(cx: &mut App) {
|
||||
// init_settings(cx);
|
||||
|
||||
cx.observe_new(|workspace: &mut Workspace, _, _| {
|
||||
workspace.register_action(|workspace, _: &ToggleAgentsPanel, window, cx| {
|
||||
workspace.toggle_panel_focus::<AgentsPanel>(window, cx);
|
||||
});
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub struct AgentsPanel {
|
||||
focus_handle: gpui::FocusHandle,
|
||||
}
|
||||
|
||||
impl AgentsPanel {
|
||||
pub fn new(cx: &mut ui::Context<Self>) -> Self {
|
||||
let focus_handle = cx.focus_handle();
|
||||
Self { focus_handle }
|
||||
}
|
||||
}
|
||||
|
||||
impl Panel for AgentsPanel {
|
||||
fn persistent_name() -> &'static str {
|
||||
"AgentsPanel"
|
||||
}
|
||||
|
||||
fn panel_key() -> &'static str {
|
||||
"AgentsPanel"
|
||||
}
|
||||
|
||||
fn position(&self, window: &ui::Window, cx: &ui::App) -> workspace::dock::DockPosition {
|
||||
workspace::dock::DockPosition::Left
|
||||
}
|
||||
|
||||
fn position_is_valid(&self, position: workspace::dock::DockPosition) -> bool {
|
||||
match position {
|
||||
workspace::dock::DockPosition::Left | workspace::dock::DockPosition::Right => true,
|
||||
workspace::dock::DockPosition::Bottom => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn set_position(
|
||||
&mut self,
|
||||
_position: workspace::dock::DockPosition,
|
||||
_window: &mut ui::Window,
|
||||
_cx: &mut ui::Context<Self>,
|
||||
) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
fn size(&self, _window: &ui::Window, _cx: &ui::App) -> ui::Pixels {
|
||||
// TODO!
|
||||
px(300.0)
|
||||
}
|
||||
|
||||
fn set_size(
|
||||
&mut self,
|
||||
_size: Option<ui::Pixels>,
|
||||
_window: &mut ui::Window,
|
||||
_cx: &mut ui::Context<Self>,
|
||||
) {
|
||||
// TODO!
|
||||
}
|
||||
|
||||
fn icon(&self, _window: &ui::Window, _cx: &ui::App) -> Option<ui::IconName> {
|
||||
//todo!
|
||||
Some(IconName::ZedAssistant)
|
||||
}
|
||||
|
||||
fn icon_tooltip(&self, _window: &ui::Window, _cx: &ui::App) -> Option<&'static str> {
|
||||
//todo!
|
||||
Some("Agents panel")
|
||||
}
|
||||
|
||||
fn toggle_action(&self) -> Box<dyn gpui::Action> {
|
||||
Box::new(ToggleAgentsPanel)
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
fn starts_open(&self, _window: &Window, _cx: &App) -> bool {
|
||||
true
|
||||
}
|
||||
fn enabled(&self, _cx: &App) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for AgentsPanel {}
|
||||
|
||||
impl Focusable for AgentsPanel {
|
||||
fn focus_handle(&self, _cx: &ui::App) -> gpui::FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
struct AgentThreadSummary {
|
||||
title: gpui::SharedString,
|
||||
worktree_branch: Option<gpui::SharedString>,
|
||||
diff: AgentThreadDiff,
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
struct AgentThreadDiff {
|
||||
removed: usize,
|
||||
modified: usize,
|
||||
added: usize,
|
||||
}
|
||||
|
||||
impl Render for AgentsPanel {
|
||||
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let agent_threads = vec![
|
||||
AgentThreadSummary {
|
||||
title: "Building the agents panel".into(),
|
||||
worktree_branch: Some("new-threads-pane".into()),
|
||||
diff: AgentThreadDiff {
|
||||
removed: 0,
|
||||
modified: 0,
|
||||
added: 1,
|
||||
},
|
||||
},
|
||||
AgentThreadSummary {
|
||||
title: "Integrate Delta DB".into(),
|
||||
worktree_branch: Some("integrate-deltadb".into()),
|
||||
diff: AgentThreadDiff {
|
||||
removed: 2,
|
||||
modified: 10,
|
||||
added: 3,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
div().size_full().children(agent_threads)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for AgentThreadSummary {
|
||||
fn render(self, _window: &mut Window, _cx: &mut ui::App) -> impl IntoElement {
|
||||
ListItem::new("list-item")
|
||||
.rounded()
|
||||
.spacing(ListItemSpacing::Sparse)
|
||||
.start_slot(
|
||||
h_flex()
|
||||
.w_full()
|
||||
.gap_2()
|
||||
.justify_between()
|
||||
.child(Label::new(self.title).size(LabelSize::Default).truncate())
|
||||
.children(
|
||||
self.worktree_branch
|
||||
.map(|branch| Label::new(branch).size(LabelSize::Small).truncate()),
|
||||
)
|
||||
.child(self.diff),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for AgentThreadDiff {
|
||||
fn render(self, _window: &mut Window, _cx: &mut ui::App) -> impl IntoElement {
|
||||
Label::new(format!("{}:{}:{}", self.added, self.modified, self.removed))
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ pub struct TabBar {
|
||||
start_children: SmallVec<[AnyElement; 2]>,
|
||||
children: SmallVec<[AnyElement; 2]>,
|
||||
end_children: SmallVec<[AnyElement; 2]>,
|
||||
pre_end_children: SmallVec<[AnyElement; 2]>,
|
||||
scroll_handle: Option<ScrollHandle>,
|
||||
}
|
||||
|
||||
@@ -20,6 +21,7 @@ impl TabBar {
|
||||
start_children: SmallVec::new(),
|
||||
children: SmallVec::new(),
|
||||
end_children: SmallVec::new(),
|
||||
pre_end_children: SmallVec::new(),
|
||||
scroll_handle: None,
|
||||
}
|
||||
}
|
||||
@@ -70,6 +72,15 @@ impl TabBar {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn pre_end_child(mut self, end_child: impl IntoElement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.pre_end_children
|
||||
.push(end_child.into_element().into_any());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn end_children(mut self, end_children: impl IntoIterator<Item = impl IntoElement>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
@@ -137,18 +148,31 @@ impl RenderOnce for TabBar {
|
||||
.children(self.children),
|
||||
),
|
||||
)
|
||||
.when(!self.end_children.is_empty(), |this| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.flex_none()
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.px(DynamicSpacing::Base06.rems(cx))
|
||||
.border_b_1()
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.children(self.end_children),
|
||||
)
|
||||
})
|
||||
.when(
|
||||
!self.end_children.is_empty() || !self.pre_end_children.is_empty(),
|
||||
|this| {
|
||||
this.child(
|
||||
h_flex()
|
||||
.flex_none()
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.px(DynamicSpacing::Base06.rems(cx))
|
||||
.children(self.pre_end_children)
|
||||
.border_color(cx.theme().colors().border)
|
||||
.border_b_1()
|
||||
.when(!self.end_children.is_empty(), |div| {
|
||||
div.child(
|
||||
h_flex()
|
||||
.flex_none()
|
||||
.pl(DynamicSpacing::Base04.rems(cx))
|
||||
.gap(DynamicSpacing::Base04.rems(cx))
|
||||
.border_l_1()
|
||||
.border_color(cx.theme().colors().border)
|
||||
.children(self.end_children),
|
||||
)
|
||||
}),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ use settings::SettingsStore;
|
||||
use std::sync::Arc;
|
||||
use ui::{ContextMenu, Divider, DividerColor, IconButton, Tooltip, h_flex};
|
||||
use ui::{prelude::*, right_click_menu};
|
||||
use util::ResultExt as _;
|
||||
|
||||
pub(crate) const RESIZE_HANDLE_SIZE: Pixels = px(6.);
|
||||
|
||||
@@ -882,7 +883,13 @@ impl Render for PanelButtons {
|
||||
.enumerate()
|
||||
.filter_map(|(i, entry)| {
|
||||
let icon = entry.panel.icon(window, cx)?;
|
||||
let icon_tooltip = entry.panel.icon_tooltip(window, cx)?;
|
||||
let icon_tooltip = entry
|
||||
.panel
|
||||
.icon_tooltip(window, cx)
|
||||
.ok_or_else(|| {
|
||||
anyhow::anyhow!("can't render a panel button without an icon tooltip")
|
||||
})
|
||||
.log_err()?;
|
||||
let name = entry.panel.persistent_name();
|
||||
let panel = entry.panel.clone();
|
||||
|
||||
|
||||
@@ -3040,6 +3040,17 @@ impl Pane {
|
||||
move |_window, cx| Tooltip::for_action_in("Go Back", &GoBack, &focus_handle, cx)
|
||||
});
|
||||
|
||||
let open_aside = IconButton::new("open_aside", IconName::Thread)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click({
|
||||
let workspace = self.workspace.clone();
|
||||
move |_, window, cx| {
|
||||
workspace
|
||||
.update(cx, |workspace, cx| workspace.toggle_panelet(window, cx))
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
|
||||
let navigate_forward = IconButton::new("navigate_forward", IconName::ArrowRight)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click({
|
||||
@@ -3080,13 +3091,23 @@ impl Pane {
|
||||
}
|
||||
let unpinned_tabs = tab_items.split_off(self.pinned_tab_count);
|
||||
let pinned_tabs = tab_items;
|
||||
|
||||
let render_aside_toggle = self
|
||||
.workspace
|
||||
.upgrade()
|
||||
.map(|entity| !entity.read(cx).panelet)
|
||||
.unwrap_or(false);
|
||||
|
||||
TabBar::new("tab_bar")
|
||||
.when(render_aside_toggle, |tab_bar| {
|
||||
tab_bar.start_child(open_aside)
|
||||
})
|
||||
.when(
|
||||
self.display_nav_history_buttons.unwrap_or_default(),
|
||||
|tab_bar| {
|
||||
tab_bar
|
||||
.start_child(navigate_backward)
|
||||
.start_child(navigate_forward)
|
||||
.pre_end_child(navigate_backward)
|
||||
.pre_end_child(navigate_forward)
|
||||
},
|
||||
)
|
||||
.map(|tab_bar| {
|
||||
|
||||
63
crates/workspace/src/panelet.rs
Normal file
63
crates/workspace/src/panelet.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
use gpui::WeakEntity;
|
||||
use ui::{
|
||||
ActiveTheme as _, Clickable, Context, DynamicSpacing, IconButton, IconName, IconSize,
|
||||
InteractiveElement as _, IntoElement, ParentElement as _, RenderOnce, Styled as _, Tab, Window,
|
||||
div, px,
|
||||
};
|
||||
|
||||
use crate::Workspace;
|
||||
|
||||
impl Workspace {
|
||||
pub fn toggle_panelet(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
|
||||
self.panelet = !self.panelet;
|
||||
// self.
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct Panelet {
|
||||
workspace: WeakEntity<Workspace>,
|
||||
}
|
||||
|
||||
impl Panelet {
|
||||
pub fn new(cx: &mut Context<Workspace>) -> Self {
|
||||
let workspace = cx.weak_entity();
|
||||
Self { workspace }
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for Panelet {
|
||||
fn render(self, _window: &mut Window, cx: &mut ui::App) -> impl IntoElement {
|
||||
div()
|
||||
.h_full()
|
||||
.bg(cx.theme().colors().tab_bar_background)
|
||||
.w(px(400.0))
|
||||
.border_color(cx.theme().colors().border)
|
||||
.border_r_1()
|
||||
.child(
|
||||
div()
|
||||
.pt_1()
|
||||
.id("panelet")
|
||||
.flex()
|
||||
.flex_none()
|
||||
.w_full()
|
||||
.h(Tab::container_height(cx))
|
||||
.child(
|
||||
div().px(DynamicSpacing::Base06.rems(cx)).child(
|
||||
IconButton::new("open_panelet", IconName::Thread)
|
||||
.icon_size(IconSize::Small)
|
||||
.on_click(move |_, window, cx| {
|
||||
self.workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
workspace.toggle_panelet(window, cx)
|
||||
})
|
||||
.ok();
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
// .child(
|
||||
// // todo!(put content here)
|
||||
// )
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ mod modal_layer;
|
||||
pub mod notifications;
|
||||
pub mod pane;
|
||||
pub mod pane_group;
|
||||
mod panelet;
|
||||
mod path_list;
|
||||
mod persistence;
|
||||
pub mod searchable;
|
||||
@@ -126,11 +127,14 @@ pub use workspace_settings::{
|
||||
};
|
||||
use zed_actions::{Spawn, feedback::FileBugReport};
|
||||
|
||||
use crate::persistence::{
|
||||
SerializedAxis,
|
||||
model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},
|
||||
};
|
||||
use crate::{item::ItemBufferKind, notifications::NotificationId};
|
||||
use crate::{
|
||||
panelet::Panelet,
|
||||
persistence::{
|
||||
SerializedAxis,
|
||||
model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},
|
||||
},
|
||||
};
|
||||
|
||||
pub const SERIALIZATION_THROTTLE_TIME: Duration = Duration::from_millis(200);
|
||||
|
||||
@@ -1180,6 +1184,7 @@ pub struct Workspace {
|
||||
scheduled_tasks: Vec<Task<()>>,
|
||||
last_open_dock_positions: Vec<DockPosition>,
|
||||
removing: bool,
|
||||
panelet: bool,
|
||||
}
|
||||
|
||||
impl EventEmitter<Event> for Workspace {}
|
||||
@@ -1524,6 +1529,7 @@ impl Workspace {
|
||||
scheduled_tasks: Vec::new(),
|
||||
last_open_dock_positions: Vec::new(),
|
||||
removing: false,
|
||||
panelet: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6698,6 +6704,11 @@ impl Render for Workspace {
|
||||
window,
|
||||
cx,
|
||||
))
|
||||
.when(self.panelet, |this| {
|
||||
this.child(
|
||||
Panelet::new(cx)
|
||||
)
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
|
||||
@@ -9,6 +9,7 @@ mod quick_action_bar;
|
||||
#[cfg(target_os = "windows")]
|
||||
pub(crate) mod windows_only_instance;
|
||||
|
||||
use agent_ui::agents_panel::AgentsPanel;
|
||||
use agent_ui::{AgentDiffToolbar, AgentPanelDelegate};
|
||||
use anyhow::Context as _;
|
||||
pub use app_menus::*;
|
||||
@@ -590,6 +591,7 @@ fn initialize_panels(
|
||||
cx.clone(),
|
||||
);
|
||||
let debug_panel = DebugPanel::load(workspace_handle.clone(), cx);
|
||||
let agents_panel = cx.new(|cx| AgentsPanel::new(cx)).unwrap();
|
||||
|
||||
let (
|
||||
project_panel,
|
||||
@@ -611,9 +613,10 @@ fn initialize_panels(
|
||||
|
||||
workspace_handle.update_in(cx, |workspace, window, cx| {
|
||||
workspace.add_panel(project_panel, window, cx);
|
||||
workspace.add_panel(agents_panel, window, cx);
|
||||
workspace.add_panel(git_panel, window, cx);
|
||||
workspace.add_panel(outline_panel, window, cx);
|
||||
workspace.add_panel(terminal_panel, window, cx);
|
||||
workspace.add_panel(git_panel, window, cx);
|
||||
workspace.add_panel(channels_panel, window, cx);
|
||||
workspace.add_panel(notification_panel, window, cx);
|
||||
workspace.add_panel(debug_panel, window, cx);
|
||||
|
||||
Reference in New Issue
Block a user