agents_panel.rs

  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}