Remoting public alpha (#14541)

Conrad Irwin created

Release Notes:

- remoting: An alpha version of remote development is now available to
everyone. For more information on how to use it, and limitations see
https://zed.dev/docs/remote-development.

Change summary

Cargo.lock                                    |   1 
crates/recent_projects/Cargo.toml             |   1 
crates/recent_projects/src/dev_servers.rs     | 132 ++++++++++++--------
crates/recent_projects/src/recent_projects.rs |   6 
4 files changed, 77 insertions(+), 63 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -8525,7 +8525,6 @@ dependencies = [
  "client",
  "dev_server_projects",
  "editor",
- "feature_flags",
  "fuzzy",
  "gpui",
  "language",

crates/recent_projects/Cargo.toml 🔗

@@ -16,7 +16,6 @@ doctest = false
 anyhow.workspace = true
 client.workspace = true
 editor.workspace = true
-feature_flags.workspace = true
 fuzzy.workspace = true
 gpui.workspace = true
 markdown.workspace = true

crates/recent_projects/src/dev_servers.rs 🔗

@@ -2,10 +2,9 @@ use std::time::Duration;
 
 use anyhow::anyhow;
 use anyhow::Context;
+use client::Client;
 use dev_server_projects::{DevServer, DevServerId, DevServerProject, DevServerProjectId};
 use editor::Editor;
-use feature_flags::FeatureFlagAppExt;
-use feature_flags::FeatureFlagViewExt;
 use gpui::AsyncWindowContext;
 use gpui::Subscription;
 use gpui::Task;
@@ -33,6 +32,7 @@ use ui::{
 };
 use ui_input::{FieldLabelLayout, TextField};
 use util::ResultExt;
+use workspace::notifications::NotifyResultExt;
 use workspace::{notifications::DetachAndPromptErr, AppState, ModalView, Workspace, WORKSPACE_DB};
 
 use crate::open_dev_server_project;
@@ -70,20 +70,7 @@ enum Mode {
 }
 
 impl DevServerProjects {
-    pub fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
-        cx.observe_flag::<feature_flags::Remoting, _>(|enabled, workspace, _| {
-            if enabled {
-                Self::register_open_remote_action(workspace);
-            }
-        })
-        .detach();
-
-        if cx.has_flag::<feature_flags::Remoting>() {
-            Self::register_open_remote_action(workspace);
-        }
-    }
-
-    fn register_open_remote_action(workspace: &mut Workspace) {
+    pub fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
         workspace.register_action(|workspace, _: &OpenRemote, cx| {
             let handle = cx.view().downgrade();
             workspace.toggle_modal(cx, |cx| Self::new(cx, handle))
@@ -969,53 +956,86 @@ impl DevServerProjects {
             is_creating = Some(*creating);
             creating_dev_server = Some(*dev_server_id);
         };
+        let is_signed_out = Client::global(cx).status().borrow().is_signed_out();
 
         Modal::new("remote-projects", Some(self.scroll_handle.clone()))
             .header(
                 ModalHeader::new()
                     .show_dismiss_button(true)
-                    .child(Headline::new("Remote Projects").size(HeadlineSize::Small)),
+                    .child(Headline::new("Remote Projects (alpha)").size(HeadlineSize::Small)),
             )
-            .section(
-                Section::new().child(
-                    div().mb_4().child(
-                        List::new()
-                            .empty_message("No dev servers registered.")
-                            .header(Some(
-                                ListHeader::new("Dev Servers").end_slot(
-                                    Button::new("register-dev-server-button", "New Server")
-                                        .icon(IconName::Plus)
-                                        .icon_position(IconPosition::Start)
-                                        .tooltip(|cx| {
-                                            Tooltip::text("Register a new dev server", cx)
-                                        })
-                                        .on_click(cx.listener(|this, _, cx| {
-                                            this.mode =
-                                                Mode::CreateDevServer(CreateDevServer::default());
-                                            this.dev_server_name_input.update(
-                                                cx,
-                                                |text_field, cx| {
-                                                    text_field.editor().update(cx, |editor, cx| {
-                                                        editor.set_text("", cx);
-                                                    });
-                                                },
-                                            );
-                                            cx.notify();
-                                        })),
-                                ),
-                            ))
-                            .children(dev_servers.iter().map(|dev_server| {
-                                let creating = if creating_dev_server == Some(dev_server.id) {
-                                    is_creating
-                                } else {
-                                    None
-                                };
-                                self.render_dev_server(dev_server, creating, cx)
-                                    .into_any_element()
-                            })),
+            .when(is_signed_out, |modal| {
+                modal
+                    .section(Section::new().child(v_flex().mb_4().child(Label::new(
+                        "You are not currently signed in to Zed. Currently the remote development featuers are only available to signed in users. Please sign in to continue.",
+                    ))))
+                    .footer(
+                        ModalFooter::new().end_slot(
+                            Button::new("sign_in", "Sign in")
+                                .icon(IconName::Github)
+                                .icon_position(IconPosition::Start)
+                                .style(ButtonStyle::Filled)
+                                .full_width()
+                                .on_click(cx.listener(|_, _, cx| {
+                                    let client = Client::global(cx).clone();
+                                    cx.spawn(|_, mut cx| async move {
+                                        client
+                                            .authenticate_and_connect(true, &cx)
+                                            .await
+                                            .notify_async_err(&mut cx);
+                                    })
+                                    .detach();
+                                    cx.emit(gpui::DismissEvent);
+                                })),
+                        ),
+                    )
+            })
+            .when(!is_signed_out, |modal| {
+                modal.section(
+                    Section::new().child(
+                        div().mb_4().child(
+                            List::new()
+                                .empty_message("No dev servers registered.")
+                                .header(Some(
+                                    ListHeader::new("Dev Servers").end_slot(
+                                        Button::new("register-dev-server-button", "New Server")
+                                            .icon(IconName::Plus)
+                                            .icon_position(IconPosition::Start)
+                                            .tooltip(|cx| {
+                                                Tooltip::text("Register a new dev server", cx)
+                                            })
+                                            .on_click(cx.listener(|this, _, cx| {
+                                                this.mode = Mode::CreateDevServer(
+                                                    CreateDevServer::default(),
+                                                );
+                                                this.dev_server_name_input.update(
+                                                    cx,
+                                                    |text_field, cx| {
+                                                        text_field.editor().update(
+                                                            cx,
+                                                            |editor, cx| {
+                                                                editor.set_text("", cx);
+                                                            },
+                                                        );
+                                                    },
+                                                );
+                                                cx.notify();
+                                            })),
+                                    ),
+                                ))
+                                .children(dev_servers.iter().map(|dev_server| {
+                                    let creating = if creating_dev_server == Some(dev_server.id) {
+                                        is_creating
+                                    } else {
+                                        None
+                                    };
+                                    self.render_dev_server(dev_server, creating, cx)
+                                        .into_any_element()
+                                })),
+                        ),
                     ),
-                ),
-            )
+                )
+            })
     }
 }
 

crates/recent_projects/src/recent_projects.rs 🔗

@@ -5,7 +5,6 @@ use client::{DevServerProjectId, ProjectId};
 use dev_servers::reconnect_to_dev_server_project;
 pub use dev_servers::DevServerProjects;
 use disconnected_overlay::DisconnectedOverlay;
-use feature_flags::FeatureFlagAppExt;
 use fuzzy::{StringMatch, StringMatchCandidate};
 use gpui::{
     Action, AnyElement, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView,
@@ -518,9 +517,6 @@ impl PickerDelegate for RecentProjectsDelegate {
     }
 
     fn render_footer(&self, cx: &mut ViewContext<Picker<Self>>) -> Option<AnyElement> {
-        if !cx.has_flag::<feature_flags::Remoting>() {
-            return None;
-        }
         Some(
             h_flex()
                 .border_t_1()
@@ -534,7 +530,7 @@ impl PickerDelegate for RecentProjectsDelegate {
                         .when_some(KeyBinding::for_action(&OpenRemote, cx), |button, key| {
                             button.child(key)
                         })
-                        .child(Label::new("New remote project…").color(Color::Muted))
+                        .child(Label::new("Open remote folder…").color(Color::Muted))
                         .on_click(|_, cx| cx.dispatch_action(OpenRemote.boxed_clone())),
                 )
                 .child(