agent_ui: Fix thread archive and agent panel for empty window threads (#51924)

Danilo Leal created

This PR ensures threads created on an empty window (i.e., no
paths/worktrees associated with it) can still be displayed in the thread
archive view. They can't be unarchived, though, as we don't know where
we'd insert it, even if we had a project on the window. Lastly, I'm also
hiding the "current worktree"/"new git worktree" menu from the agent
panel if we don't have any paths as those options don't make sense in
this case.

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- N/A

Change summary

crates/agent_ui/src/agent_panel.rs          |  5 ++++-
crates/agent_ui/src/threads_archive_view.rs | 14 ++++++--------
crates/sidebar/src/sidebar.rs               |  3 ---
3 files changed, 10 insertions(+), 12 deletions(-)

Detailed changes

crates/agent_ui/src/agent_panel.rs 🔗

@@ -3664,6 +3664,7 @@ impl AgentPanel {
 
     fn render_toolbar(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
         let agent_server_store = self.project.read(cx).agent_server_store().clone();
+        let has_visible_worktrees = self.project.read(cx).visible_worktrees(cx).next().is_some();
         let focus_handle = self.focus_handle(cx);
 
         let (selected_agent_custom_icon, selected_agent_label) =
@@ -4024,7 +4025,9 @@ impl AgentPanel {
                         .gap(DynamicSpacing::Base04.rems(cx))
                         .pl(DynamicSpacing::Base04.rems(cx))
                         .child(agent_selector_menu)
-                        .child(self.render_start_thread_in_selector(cx)),
+                        .when(has_visible_worktrees, |this| {
+                            this.child(self.render_start_thread_in_selector(cx))
+                        }),
                 )
                 .child(
                     h_flex()

crates/agent_ui/src/threads_archive_view.rs 🔗

@@ -137,7 +137,6 @@ pub struct ThreadsArchiveView {
     _refresh_history_task: Task<()>,
     _update_items_task: Option<Task<()>>,
     is_loading: bool,
-    has_open_project: bool,
 }
 
 impl ThreadsArchiveView {
@@ -146,7 +145,6 @@ impl ThreadsArchiveView {
         agent_server_store: Entity<AgentServerStore>,
         thread_store: Entity<ThreadStore>,
         fs: Arc<dyn Fs>,
-        has_open_project: bool,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> Self {
@@ -184,7 +182,6 @@ impl ThreadsArchiveView {
             _refresh_history_task: Task::ready(()),
             _update_items_task: None,
             is_loading: true,
-            has_open_project,
         };
         this.set_selected_agent(Agent::NativeAgent, window, cx);
         this
@@ -247,7 +244,9 @@ impl ThreadsArchiveView {
         let today = Local::now().naive_local().date();
 
         self._update_items_task.take();
-        let unarchived_ids_task = SidebarThreadMetadataStore::global(cx).read(cx).list_ids(cx);
+        let unarchived_ids_task = SidebarThreadMetadataStore::global(cx)
+            .read(cx)
+            .list_sidebar_ids(cx);
         self._update_items_task = Some(cx.spawn(async move |this, cx| {
             let unarchived_session_ids = unarchived_ids_task.await.unwrap_or_default();
 
@@ -432,8 +431,8 @@ impl ThreadsArchiveView {
             return;
         };
 
-        let thread_has_project = session.work_dirs.as_ref().is_some_and(|p| !p.is_empty());
-        if !thread_has_project && !self.has_open_project {
+        let can_unarchive = session.work_dirs.as_ref().is_some_and(|p| !p.is_empty());
+        if !can_unarchive {
             return;
         }
 
@@ -485,8 +484,7 @@ impl ThreadsArchiveView {
                     }
                 });
 
-                let thread_has_project = session.work_dirs.as_ref().is_some_and(|p| !p.is_empty());
-                let can_unarchive = thread_has_project || self.has_open_project;
+                let can_unarchive = session.work_dirs.as_ref().is_some_and(|p| !p.is_empty());
 
                 let supports_delete = self
                     .history

crates/sidebar/src/sidebar.rs 🔗

@@ -2663,15 +2663,12 @@ impl Sidebar {
             .agent_server_store()
             .clone();
 
-        let has_open_project = !workspace_path_list(&active_workspace, cx).is_empty();
-
         let archive_view = cx.new(|cx| {
             ThreadsArchiveView::new(
                 agent_connection_store,
                 agent_server_store,
                 thread_store,
                 fs,
-                has_open_project,
                 window,
                 cx,
             )