Disallow adding folders to projects and opening the terminal in remote projects (#11261)

Conrad Irwin and Mikayla created

Release Notes:

- Fixed broken UI in remote projects

---------

Co-authored-by: Mikayla <mikayla@zed.dev>

Change summary

crates/project_panel/src/project_panel.rs  | 11 +++--
crates/terminal_view/src/terminal_panel.rs | 44 ++++++++++++++---------
crates/workspace/src/workspace.rs          |  7 +++
crates/zed/src/zed.rs                      |  4 +
4 files changed, 43 insertions(+), 23 deletions(-)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -430,6 +430,7 @@ impl ProjectPanel {
             let worktree_id = worktree.id();
             let is_local = project.is_local();
             let is_read_only = project.is_read_only();
+            let is_remote = project.is_remote();
 
             let context_menu = ContextMenu::build(cx, |menu, cx| {
                 menu.context(self.focus_handle.clone()).when_else(
@@ -476,10 +477,12 @@ impl ProjectPanel {
                             })
                             .when(is_local & is_root, |menu| {
                                 menu.separator()
-                                    .action(
-                                        "Add Folder to Project…",
-                                        Box::new(workspace::AddFolderToProject),
-                                    )
+                                    .when(!is_remote, |menu| {
+                                        menu.action(
+                                            "Add Folder to Project…",
+                                            Box::new(workspace::AddFolderToProject),
+                                        )
+                                    })
                                     .entry(
                                         "Remove from Project",
                                         None,

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -317,10 +317,15 @@ impl TerminalPanel {
         let Some(terminal_panel) = workspace.panel::<Self>(cx) else {
             return;
         };
+
         terminal_panel.update(cx, |panel, cx| {
-            panel.add_terminal(Some(action.working_directory.clone()), None, cx)
+            panel.add_terminal(
+                Some(action.working_directory.clone()),
+                None,
+                RevealStrategy::Always,
+                cx,
+            )
         });
-        workspace.focus_panel::<Self>(cx);
     }
 
     fn spawn_task(&mut self, spawn_in_terminal: &SpawnInTerminal, cx: &mut ViewContext<Self>) {
@@ -429,19 +434,7 @@ impl TerminalPanel {
         cx: &mut ViewContext<Self>,
     ) {
         let reveal = spawn_task.reveal;
-        self.add_terminal(working_directory, Some(spawn_task), cx);
-        match reveal {
-            RevealStrategy::Always => {
-                let task_workspace = self.workspace.clone();
-                cx.spawn(|_, mut cx| async move {
-                    task_workspace
-                        .update(&mut cx, |workspace, cx| workspace.focus_panel::<Self>(cx))
-                        .ok()
-                })
-                .detach();
-            }
-            RevealStrategy::Never => {}
-        }
+        self.add_terminal(working_directory, Some(spawn_task), reveal, cx);
     }
 
     /// Create a new Terminal in the current working directory or the user's home directory
@@ -453,8 +446,10 @@ impl TerminalPanel {
         let Some(terminal_panel) = workspace.panel::<Self>(cx) else {
             return;
         };
-        terminal_panel.update(cx, |this, cx| this.add_terminal(None, None, cx));
-        workspace.focus_panel::<Self>(cx);
+
+        terminal_panel.update(cx, |this, cx| {
+            this.add_terminal(None, None, RevealStrategy::Always, cx)
+        });
     }
 
     fn terminals_for_task(
@@ -488,13 +483,23 @@ impl TerminalPanel {
         &mut self,
         working_directory: Option<PathBuf>,
         spawn_task: Option<SpawnInTerminal>,
+        reveal_strategy: RevealStrategy,
         cx: &mut ViewContext<Self>,
     ) {
         let workspace = self.workspace.clone();
         self.pending_terminals_to_add += 1;
+
         cx.spawn(|terminal_panel, mut cx| async move {
             let pane = terminal_panel.update(&mut cx, |this, _| this.pane.clone())?;
             workspace.update(&mut cx, |workspace, cx| {
+                if workspace.project().read(cx).is_remote() {
+                    workspace.show_error(
+                        &anyhow::anyhow!("Cannot open terminals on remote projects (yet!)"),
+                        cx,
+                    );
+                    return;
+                };
+
                 let working_directory = if let Some(working_directory) = working_directory {
                     Some(working_directory)
                 } else {
@@ -522,6 +527,9 @@ impl TerminalPanel {
                         pane.add_item(terminal, true, focus, None, cx);
                     });
                 }
+                if reveal_strategy == RevealStrategy::Always {
+                    workspace.focus_panel::<Self>(cx);
+                }
             })?;
             terminal_panel.update(&mut cx, |this, cx| {
                 this.pending_terminals_to_add = this.pending_terminals_to_add.saturating_sub(1);
@@ -736,7 +744,7 @@ impl Panel for TerminalPanel {
 
     fn set_active(&mut self, active: bool, cx: &mut ViewContext<Self>) {
         if active && self.has_no_terminals(cx) {
-            self.add_terminal(None, None, cx)
+            self.add_terminal(None, None, RevealStrategy::Never, cx);
         }
     }
 

crates/workspace/src/workspace.rs 🔗

@@ -1693,6 +1693,13 @@ impl Workspace {
     }
 
     fn add_folder_to_project(&mut self, _: &AddFolderToProject, cx: &mut ViewContext<Self>) {
+        if self.project.read(cx).is_remote() {
+            self.show_error(
+                &anyhow!("Folders cannot yet be added to remote projects"),
+                cx,
+            );
+            return;
+        }
         let paths = cx.prompt_for_paths(PathPromptOptions {
             files: false,
             directories: true,

crates/zed/src/zed.rs 🔗

@@ -215,7 +215,9 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
             workspace_handle.update(&mut cx, |workspace, cx| {
                 workspace.add_panel(assistant_panel, cx);
                 workspace.add_panel(project_panel, cx);
-                workspace.add_panel(terminal_panel, cx);
+                if !workspace.project().read(cx).is_remote() {
+                    workspace.add_panel(terminal_panel, cx);
+                }
                 workspace.add_panel(channels_panel, cx);
                 workspace.add_panel(chat_panel, cx);
                 workspace.add_panel(notification_panel, cx);