recent_projects: Surface project opening errors to user (#41308)

Lukas Wirth created

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/recent_projects/src/recent_projects.rs    | 137 +++++++++--------
crates/recent_projects/src/remote_connections.rs |   5 
crates/remote/src/remote_client.rs               |  10 
3 files changed, 77 insertions(+), 75 deletions(-)

Detailed changes

crates/recent_projects/src/recent_projects.rs 🔗

@@ -28,7 +28,8 @@ use ui::{KeyBinding, ListItem, ListItemSpacing, Tooltip, prelude::*, tooltip_con
 use util::{ResultExt, paths::PathExt};
 use workspace::{
     CloseIntent, HistoryManager, ModalView, OpenOptions, PathList, SerializedWorkspaceLocation,
-    WORKSPACE_DB, Workspace, WorkspaceId, with_active_or_new_workspace,
+    WORKSPACE_DB, Workspace, WorkspaceId, notifications::DetachAndPromptErr,
+    with_active_or_new_workspace,
 };
 use zed_actions::{OpenRecent, OpenRemote};
 
@@ -420,77 +421,79 @@ impl PickerDelegate for RecentProjectsDelegate {
             } else {
                 !secondary
             };
-            workspace
-                .update(cx, |workspace, cx| {
-                    if workspace.database_id() == Some(*candidate_workspace_id) {
-                        Task::ready(Ok(()))
-                    } else {
-                        match candidate_workspace_location.clone() {
-                            SerializedWorkspaceLocation::Local => {
-                                let paths = candidate_workspace_paths.paths().to_vec();
-                                if replace_current_window {
-                                    cx.spawn_in(window, async move |workspace, cx| {
-                                        let continue_replacing = workspace
-                                            .update_in(cx, |workspace, window, cx| {
-                                                workspace.prepare_to_close(
-                                                    CloseIntent::ReplaceWindow,
-                                                    window,
-                                                    cx,
-                                                )
-                                            })?
-                                            .await?;
-                                        if continue_replacing {
+            workspace.update(cx, |workspace, cx| {
+                if workspace.database_id() == Some(*candidate_workspace_id) {
+                    return;
+                }
+                match candidate_workspace_location.clone() {
+                    SerializedWorkspaceLocation::Local => {
+                        let paths = candidate_workspace_paths.paths().to_vec();
+                        if replace_current_window {
+                            cx.spawn_in(window, async move |workspace, cx| {
+                                let continue_replacing = workspace
+                                    .update_in(cx, |workspace, window, cx| {
+                                        workspace.prepare_to_close(
+                                            CloseIntent::ReplaceWindow,
+                                            window,
+                                            cx,
+                                        )
+                                    })?
+                                    .await?;
+                                if continue_replacing {
+                                    workspace
+                                        .update_in(cx, |workspace, window, cx| {
                                             workspace
-                                                .update_in(cx, |workspace, window, cx| {
-                                                    workspace.open_workspace_for_paths(
-                                                        true, paths, window, cx,
-                                                    )
-                                                })?
-                                                .await
-                                        } else {
-                                            Ok(())
-                                        }
-                                    })
+                                                .open_workspace_for_paths(true, paths, window, cx)
+                                        })?
+                                        .await
                                 } else {
-                                    workspace.open_workspace_for_paths(false, paths, window, cx)
+                                    Ok(())
                                 }
-                            }
-                            SerializedWorkspaceLocation::Remote(mut connection) => {
-                                let app_state = workspace.app_state().clone();
-
-                                let replace_window = if replace_current_window {
-                                    window.window_handle().downcast::<Workspace>()
-                                } else {
-                                    None
-                                };
-
-                                let open_options = OpenOptions {
-                                    replace_window,
-                                    ..Default::default()
-                                };
-
-                                if let RemoteConnectionOptions::Ssh(connection) = &mut connection {
-                                    SshSettings::get_global(cx)
-                                        .fill_connection_options_from_settings(connection);
-                                };
-
-                                let paths = candidate_workspace_paths.paths().to_vec();
-
-                                cx.spawn_in(window, async move |_, cx| {
-                                    open_remote_project(
-                                        connection.clone(),
-                                        paths,
-                                        app_state,
-                                        open_options,
-                                        cx,
-                                    )
-                                    .await
-                                })
-                            }
+                            })
+                        } else {
+                            workspace.open_workspace_for_paths(false, paths, window, cx)
                         }
                     }
-                })
-                .detach_and_log_err(cx);
+                    SerializedWorkspaceLocation::Remote(mut connection) => {
+                        let app_state = workspace.app_state().clone();
+
+                        let replace_window = if replace_current_window {
+                            window.window_handle().downcast::<Workspace>()
+                        } else {
+                            None
+                        };
+
+                        let open_options = OpenOptions {
+                            replace_window,
+                            ..Default::default()
+                        };
+
+                        if let RemoteConnectionOptions::Ssh(connection) = &mut connection {
+                            SshSettings::get_global(cx)
+                                .fill_connection_options_from_settings(connection);
+                        };
+
+                        let paths = candidate_workspace_paths.paths().to_vec();
+
+                        cx.spawn_in(window, async move |_, cx| {
+                            open_remote_project(
+                                connection.clone(),
+                                paths,
+                                app_state,
+                                open_options,
+                                cx,
+                            )
+                            .await
+                        })
+                    }
+                }
+                .detach_and_prompt_err(
+                    "Failed to open project",
+                    window,
+                    cx,
+                    |_, _, _| None,
+                );
+            });
             cx.emit(DismissEvent);
         }
     }

crates/recent_projects/src/remote_connections.rs 🔗

@@ -483,7 +483,7 @@ impl remote::RemoteClientDelegate for RemoteClientDelegate {
         cx: &mut AsyncApp,
     ) -> Task<anyhow::Result<PathBuf>> {
         cx.spawn(async move |cx| {
-            let binary_path = AutoUpdater::download_remote_server_release(
+            AutoUpdater::download_remote_server_release(
                 platform.os,
                 platform.arch,
                 release_channel,
@@ -500,8 +500,7 @@ impl remote::RemoteClientDelegate for RemoteClientDelegate {
                     platform.os,
                     platform.arch,
                 )
-            })?;
-            Ok(binary_path)
+            })
         })
     }
 

crates/remote/src/remote_client.rs 🔗

@@ -528,6 +528,7 @@ impl RemoteClient {
         let reconnect_task = cx.spawn(async move |this, cx| {
             macro_rules! failed {
                 ($error:expr, $attempts:expr, $ssh_connection:expr, $delegate:expr) => {
+                    delegate.set_status(Some(&format!("{error:#}", error = $error)), cx);
                     return State::ReconnectFailed {
                         error: anyhow!($error),
                         attempts: $attempts,
@@ -999,11 +1000,10 @@ impl ConnectionPool {
         let connection = self.connections.get(&opts);
         match connection {
             Some(ConnectionPoolEntry::Connecting(task)) => {
-                let delegate = delegate.clone();
-                cx.spawn(async move |cx| {
-                    delegate.set_status(Some("Waiting for existing connection attempt"), cx);
-                })
-                .detach();
+                delegate.set_status(
+                    Some("Waiting for existing connection attempt"),
+                    &mut cx.to_async(),
+                );
                 return task.clone();
             }
             Some(ConnectionPoolEntry::Connected(ssh)) => {