1use gpui::{EventEmitter, Focusable, actions};
2use ui::{
3 App, Context, IconName, IntoElement, Label, LabelCommon as _, LabelSize, ListItem,
4 ListItemSpacing, ParentElement, Render, RenderOnce, Styled, Toggleable as _, Window, div,
5 h_flex, px,
6};
7use workspace::{Panel, Workspace, dock::PanelEvent};
8
9actions!(
10 agents,
11 [
12 /// Toggle the visibility of the agents panel.
13 ToggleAgentsPanel
14 ]
15);
16
17pub fn init(cx: &mut App) {
18 // init_settings(cx);
19
20 cx.observe_new(|workspace: &mut Workspace, _, _| {
21 workspace.register_action(|workspace, _: &ToggleAgentsPanel, window, cx| {
22 workspace.toggle_panel_focus::<AgentsPanel>(window, cx);
23 });
24 })
25 .detach();
26}
27
28pub struct AgentsPanel {
29 focus_handle: gpui::FocusHandle,
30}
31
32impl AgentsPanel {
33 pub fn new(cx: &mut ui::Context<Self>) -> Self {
34 let focus_handle = cx.focus_handle();
35 Self { focus_handle }
36 }
37}
38
39impl Panel for AgentsPanel {
40 fn persistent_name() -> &'static str {
41 "AgentsPanel"
42 }
43
44 fn panel_key() -> &'static str {
45 "AgentsPanel"
46 }
47
48 fn position(&self, window: &ui::Window, cx: &ui::App) -> workspace::dock::DockPosition {
49 workspace::dock::DockPosition::Left
50 }
51
52 fn position_is_valid(&self, position: workspace::dock::DockPosition) -> bool {
53 match position {
54 workspace::dock::DockPosition::Left | workspace::dock::DockPosition::Right => true,
55 workspace::dock::DockPosition::Bottom => false,
56 }
57 }
58
59 fn set_position(
60 &mut self,
61 _position: workspace::dock::DockPosition,
62 _window: &mut ui::Window,
63 _cx: &mut ui::Context<Self>,
64 ) {
65 // TODO!
66 }
67
68 fn size(&self, _window: &ui::Window, _cx: &ui::App) -> ui::Pixels {
69 // TODO!
70 px(300.0)
71 }
72
73 fn set_size(
74 &mut self,
75 _size: Option<ui::Pixels>,
76 _window: &mut ui::Window,
77 _cx: &mut ui::Context<Self>,
78 ) {
79 // TODO!
80 }
81
82 fn icon(&self, _window: &ui::Window, _cx: &ui::App) -> Option<ui::IconName> {
83 //todo!
84 Some(IconName::ZedAssistant)
85 }
86
87 fn icon_tooltip(&self, _window: &ui::Window, _cx: &ui::App) -> Option<&'static str> {
88 //todo!
89 Some("Agents panel")
90 }
91
92 fn toggle_action(&self) -> Box<dyn gpui::Action> {
93 Box::new(ToggleAgentsPanel)
94 }
95
96 fn activation_priority(&self) -> u32 {
97 1
98 }
99
100 fn starts_open(&self, _window: &Window, _cx: &App) -> bool {
101 true
102 }
103 fn enabled(&self, _cx: &App) -> bool {
104 true
105 }
106}
107
108impl EventEmitter<PanelEvent> for AgentsPanel {}
109
110impl Focusable for AgentsPanel {
111 fn focus_handle(&self, _cx: &ui::App) -> gpui::FocusHandle {
112 self.focus_handle.clone()
113 }
114}
115
116#[derive(IntoElement)]
117struct AgentThreadSummary {
118 title: gpui::SharedString,
119 worktree_branch: Option<gpui::SharedString>,
120 diff: AgentThreadDiff,
121}
122
123#[derive(IntoElement)]
124struct AgentThreadDiff {
125 removed: usize,
126 modified: usize,
127 added: usize,
128}
129
130impl Render for AgentsPanel {
131 fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
132 let agent_threads = vec![
133 AgentThreadSummary {
134 title: "Building the agents panel".into(),
135 worktree_branch: Some("new-threads-pane".into()),
136 diff: AgentThreadDiff {
137 removed: 0,
138 modified: 0,
139 added: 1,
140 },
141 },
142 AgentThreadSummary {
143 title: "Integrate Delta DB".into(),
144 worktree_branch: Some("integrate-deltadb".into()),
145 diff: AgentThreadDiff {
146 removed: 2,
147 modified: 10,
148 added: 3,
149 },
150 },
151 ];
152
153 div().size_full().children(agent_threads)
154 }
155}
156
157impl RenderOnce for AgentThreadSummary {
158 fn render(self, _window: &mut Window, _cx: &mut ui::App) -> impl IntoElement {
159 ListItem::new("list-item")
160 .rounded()
161 .spacing(ListItemSpacing::Sparse)
162 .start_slot(
163 h_flex()
164 .w_full()
165 .gap_2()
166 .justify_between()
167 .child(Label::new(self.title).size(LabelSize::Default).truncate())
168 .children(
169 self.worktree_branch
170 .map(|branch| Label::new(branch).size(LabelSize::Small).truncate()),
171 )
172 .child(self.diff),
173 )
174 }
175}
176
177impl RenderOnce for AgentThreadDiff {
178 fn render(self, _window: &mut Window, _cx: &mut ui::App) -> impl IntoElement {
179 Label::new(format!("{}:{}:{}", self.added, self.modified, self.removed))
180 }
181}