diff --git a/crates/recent_projects/src/dev_servers.rs b/crates/recent_projects/src/dev_servers.rs index 21d424bbd5..056f12297f 100644 --- a/crates/recent_projects/src/dev_servers.rs +++ b/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>, dev_server_id: Option, access_token: Option, 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; + 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 { - 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(); + 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, ) -> 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() + } }) } } diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index d4ba73a696..a1b95bec7e 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/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(), diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 543c90678d..5fd7844300 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/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(); } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index c7ea762e15..76924303e3 100644 --- a/crates/workspace/src/notifications.rs +++ b/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 + 'static, + ) -> Task<()>; + fn detach_and_prompt_err( self, msg: &str, @@ -524,12 +531,12 @@ impl DetachAndPromptErr for Task> 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 + '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 + 'static, + ) { + self.prompt_err(msg, cx, f).detach(); } }