remote config fixes (#12178)

Conrad Irwin created

Release Notes:

- N/A

Change summary

crates/recent_projects/src/dev_servers.rs     | 166 ++++++++++----------
crates/recent_projects/src/recent_projects.rs |   4 
crates/terminal_view/src/terminal_view.rs     |   2 
crates/workspace/src/notifications.rs         |  21 ++
4 files changed, 107 insertions(+), 86 deletions(-)

Detailed changes

crates/recent_projects/src/dev_servers.rs 🔗

@@ -49,9 +49,9 @@ pub struct DevServerProjects {
     _dev_server_subscription: Subscription,
 }
 
-#[derive(Default, Clone)]
+#[derive(Default)]
 struct CreateDevServer {
-    creating: bool,
+    creating: Option<Task<()>>,
     dev_server_id: Option<DevServerId>,
     access_token: Option<String>,
     manual_setup: bool,
@@ -316,60 +316,75 @@ impl DevServerProjects {
         let workspace = self.workspace.clone();
         let store = dev_server_projects::Store::global(cx);
 
-        cx.spawn({
-            |this, mut cx| async move {
-                let result = dev_server.await;
-
-                match result {
-                    Ok(dev_server) => {
-                        if let Some(ssh_connection_string) = ssh_connection_string {
-                            spawn_ssh_task(
-                                workspace
-                                    .upgrade()
-                                    .ok_or_else(|| anyhow!("workspace dropped"))?,
-                                store,
-                                DevServerId(dev_server.dev_server_id),
-                                ssh_connection_string,
-                                dev_server.access_token.clone(),
-                                &mut cx,
-                            )
-                            .await
-                            .log_err();
+        let task = cx
+            .spawn({
+                |this, mut cx| async move {
+                    let result = dev_server.await;
+
+                    match result {
+                        Ok(dev_server) => {
+                            if let Some(ssh_connection_string) = ssh_connection_string {
+                                this.update(&mut cx, |this, cx| {
+                                    if let Mode::CreateDevServer(CreateDevServer {
+                                        access_token,
+                                        dev_server_id,
+                                        ..
+                                    }) = &mut this.mode
+                                    {
+                                        access_token.replace(dev_server.access_token.clone());
+                                        dev_server_id
+                                            .replace(DevServerId(dev_server.dev_server_id));
+                                    }
+                                    cx.notify();
+                                })?;
+
+                                spawn_ssh_task(
+                                    workspace
+                                        .upgrade()
+                                        .ok_or_else(|| anyhow!("workspace dropped"))?,
+                                    store,
+                                    DevServerId(dev_server.dev_server_id),
+                                    ssh_connection_string,
+                                    dev_server.access_token.clone(),
+                                    &mut cx,
+                                )
+                                .await
+                                .log_err();
+                            }
+
+                            this.update(&mut cx, |this, cx| {
+                                this.focus_handle.focus(cx);
+                                this.mode = Mode::CreateDevServer(CreateDevServer {
+                                    creating: None,
+                                    dev_server_id: Some(DevServerId(dev_server.dev_server_id)),
+                                    access_token: Some(dev_server.access_token),
+                                    manual_setup,
+                                });
+                                cx.notify();
+                            })?;
+                            Ok(())
                         }
+                        Err(e) => {
+                            this.update(&mut cx, |this, cx| {
+                                this.mode = Mode::CreateDevServer(CreateDevServer {
+                                    creating: None,
+                                    dev_server_id: existing_id,
+                                    access_token: None,
+                                    manual_setup,
+                                });
+                                cx.notify()
+                            })
+                            .log_err();
 
-                        this.update(&mut cx, |this, cx| {
-                            this.focus_handle.focus(cx);
-                            this.mode = Mode::CreateDevServer(CreateDevServer {
-                                creating: false,
-                                dev_server_id: Some(DevServerId(dev_server.dev_server_id)),
-                                access_token: Some(dev_server.access_token),
-                                manual_setup,
-                            });
-                            cx.notify();
-                        })?;
-                        Ok(())
-                    }
-                    Err(e) => {
-                        this.update(&mut cx, |this, cx| {
-                            this.mode = Mode::CreateDevServer(CreateDevServer {
-                                creating: false,
-                                dev_server_id: existing_id,
-                                access_token: None,
-                                manual_setup,
-                            });
-                            cx.notify()
-                        })
-                        .log_err();
-
-                        return Err(e);
+                            return Err(e);
+                        }
                     }
                 }
-            }
-        })
-        .detach_and_prompt_err("Failed to create server", cx, |_, _| None);
+            })
+            .prompt_err("Failed to create server", cx, |_, _| None);
 
         self.mode = Mode::CreateDevServer(CreateDevServer {
-            creating: true,
+            creating: Some(task),
             dev_server_id: existing_id,
             access_token,
             manual_setup,
@@ -471,7 +486,7 @@ impl DevServerProjects {
                 self.create_dev_server_project(create_project.dev_server_id, cx);
             }
             Mode::CreateDevServer(state) => {
-                if !state.creating {
+                if state.creating.is_none() || state.dev_server_id.is_some() {
                     self.create_or_update_dev_server(
                         state.manual_setup,
                         state.dev_server_id,
@@ -548,7 +563,7 @@ impl DevServerProjects {
                                         .on_click(cx.listener(move |this, _, cx| {
                                             this.mode = Mode::CreateDevServer(CreateDevServer {
                                                 dev_server_id: Some(dev_server_id),
-                                                creating: false,
+                                                creating: None,
                                                 access_token: None,
                                                 manual_setup,
                                             });
@@ -683,16 +698,14 @@ impl DevServerProjects {
     }
 
     fn render_create_dev_server(
-        &mut self,
-        state: CreateDevServer,
+        &self,
+        state: &CreateDevServer,
         cx: &mut ViewContext<Self>,
     ) -> impl IntoElement {
-        let CreateDevServer {
-            creating,
-            dev_server_id,
-            access_token,
-            manual_setup,
-        } = state.clone();
+        let creating = state.creating.is_some();
+        let dev_server_id = state.dev_server_id;
+        let access_token = state.access_token.clone();
+        let manual_setup = state.manual_setup;
 
         let status = dev_server_id
             .map(|id| self.dev_server_store.read(cx).dev_server_status(id))
@@ -738,13 +751,11 @@ impl DevServerProjects {
                                 Label::new("Connect via SSH (default)"),
                                 !manual_setup,
                                 cx.listener({
-                                    let state = state.clone();
                                     move |this, _, cx| {
-                                    this.mode = Mode::CreateDevServer(CreateDevServer {
-                                        manual_setup: false,
-                                        ..state.clone()
-                                    });
-                                    cx.notify()
+                                        if let Mode::CreateDevServer(CreateDevServer{ manual_setup, .. }) = &mut this.mode {
+                                            *manual_setup = false;
+                                        }
+                                        cx.notify()
                                     }
                                 }),
                             ))
@@ -753,13 +764,11 @@ impl DevServerProjects {
                                 Label::new("Manual Setup"),
                                 manual_setup,
                                 cx.listener({
-                                    let state = state.clone();
                                     move |this, _, cx| {
-                                    this.mode = Mode::CreateDevServer(CreateDevServer {
-                                        manual_setup: true,
-                                        ..state.clone()
-                                    });
-                                    cx.notify()
+                                        if let Mode::CreateDevServer(CreateDevServer{ manual_setup, .. }) = &mut this.mode {
+                                            *manual_setup = true;
+                                        }
+                                        cx.notify()
                                 }}),
                             )))
                             .when(dev_server_id.is_none(), |el| {
@@ -807,10 +816,10 @@ impl DevServerProjects {
                             cx.notify();
                         }))
                 } else {
-                    Button::new("create-dev-server", if manual_setup { "Create"} else { "Connect"})
+                    Button::new("create-dev-server", if manual_setup { if dev_server_id.is_some() { "Update" } else { "Create"} } else { if dev_server_id.is_some() { "Reconnect" } else { "Connect"} })
                         .style(ButtonStyle::Filled)
                         .layer(ElevationIndex::ModalSurface)
-                        .disabled(creating)
+                        .disabled(creating && dev_server_id.is_none())
                         .on_click(cx.listener({
                             let access_token = access_token.clone();
                             move |this, _, cx| {
@@ -975,18 +984,15 @@ impl Render for DevServerProjects {
             .on_mouse_down_out(cx.listener(|this, _, cx| {
                 if matches!(this.mode, Mode::Default(None)) {
                     cx.emit(DismissEvent)
-                } else {
-                    this.focus_handle(cx).focus(cx);
-                    cx.stop_propagation()
                 }
             }))
             .w(rems(34.))
             .max_h(rems(40.))
             .child(match &self.mode {
                 Mode::Default(_) => self.render_default(cx).into_any_element(),
-                Mode::CreateDevServer(state) => self
-                    .render_create_dev_server(state.clone(), cx)
-                    .into_any_element(),
+                Mode::CreateDevServer(state) => {
+                    self.render_create_dev_server(state, cx).into_any_element()
+                }
             })
     }
 }

crates/recent_projects/src/recent_projects.rs 🔗

@@ -535,7 +535,7 @@ impl PickerDelegate for RecentProjectsDelegate {
                         .when_some(KeyBinding::for_action(&OpenRemote, cx), |button, key| {
                             button.child(key)
                         })
-                        .child(Label::new("Connect…").color(Color::Muted))
+                        .child(Label::new("New remote project…").color(Color::Muted))
                         .on_click(|_, cx| cx.dispatch_action(OpenRemote.boxed_clone())),
                 )
                 .child(
@@ -544,7 +544,7 @@ impl PickerDelegate for RecentProjectsDelegate {
                             KeyBinding::for_action(&workspace::Open, cx),
                             |button, key| button.child(key),
                         )
-                        .child(Label::new("Open folder…").color(Color::Muted))
+                        .child(Label::new("Open local folder…").color(Color::Muted))
                         .on_click(|_, cx| cx.dispatch_action(workspace::Open.boxed_clone())),
                 )
                 .into_any(),

crates/terminal_view/src/terminal_view.rs 🔗

@@ -283,7 +283,7 @@ impl TerminalView {
             cx.spawn(|this, mut cx| async move {
                 Timer::after(CURSOR_BLINK_INTERVAL).await;
                 this.update(&mut cx, |this, cx| this.blink_cursors(epoch, cx))
-                    .log_err();
+                    .ok();
             })
             .detach();
         }

crates/workspace/src/notifications.rs 🔗

@@ -512,6 +512,13 @@ where
 }
 
 pub trait DetachAndPromptErr {
+    fn prompt_err(
+        self,
+        msg: &str,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
+    ) -> Task<()>;
+
     fn detach_and_prompt_err(
         self,
         msg: &str,
@@ -524,12 +531,12 @@ impl<R> DetachAndPromptErr for Task<anyhow::Result<R>>
 where
     R: 'static,
 {
-    fn detach_and_prompt_err(
+    fn prompt_err(
         self,
         msg: &str,
         cx: &mut WindowContext,
         f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
-    ) {
+    ) -> Task<()> {
         let msg = msg.to_owned();
         cx.spawn(|mut cx| async move {
             if let Err(err) = self.await {
@@ -543,6 +550,14 @@ where
                 }
             }
         })
-        .detach();
+    }
+
+    fn detach_and_prompt_err(
+        self,
+        msg: &str,
+        cx: &mut WindowContext,
+        f: impl FnOnce(&anyhow::Error, &mut WindowContext) -> Option<String> + 'static,
+    ) {
+        self.prompt_err(msg, cx, f).detach();
     }
 }