Skip to content

Commit

Permalink
ssh: Add session state indicator to title bar (zed-industries#18645)
Browse files Browse the repository at this point in the history
![image](https://github.com/user-attachments/assets/0ed6f59c-e0e7-49e6-8db7-f09ec5cdf653)
The indicator turns yellow when ssh client is trying to reconnect. Note
that the state tracking is probably not ideal (we'll see how it pans out
once we start dog-fooding), but at the very least "green=good" should be
a decent mental model for now.

Release Notes:

- N/A
  • Loading branch information
osiewicz authored and noaccOS committed Oct 19, 2024
1 parent 05022ab commit 1320fed
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
9 changes: 8 additions & 1 deletion crates/project/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,10 @@ impl Project {
server.ssh_connection_string.is_some()
}

pub fn ssh_connection_string(&self, cx: &ModelContext<Self>) -> Option<SharedString> {
pub fn ssh_connection_string(&self, cx: &AppContext) -> Option<SharedString> {
if let Some(ssh_state) = &self.ssh_client {
return Some(ssh_state.connection_string().into());
}
let dev_server_id = self.dev_server_project_id()?;
dev_server_projects::Store::global(cx)
.read(cx)
Expand All @@ -1226,6 +1229,10 @@ impl Project {
.clone()
}

pub fn ssh_is_connected(&self) -> Option<bool> {
Some(!self.ssh_client.as_ref()?.is_reconnect_underway())
}

pub fn replica_id(&self) -> ReplicaId {
match self.client_state {
ProjectClientState::Remote { replica_id, .. } => replica_id,
Expand Down
1 change: 1 addition & 0 deletions crates/recent_projects/src/ssh_connections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ impl SshClientDelegate {
if release_channel == ReleaseChannel::Dev
&& platform.arch == std::env::consts::ARCH
&& platform.os == std::env::consts::OS
&& false
{
use smol::process::{Command, Stdio};

Expand Down
16 changes: 13 additions & 3 deletions crates/remote/src/ssh_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use std::{
time::Instant,
};
use tempfile::TempDir;
use util::maybe;

#[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, serde::Serialize, serde::Deserialize,
Expand All @@ -48,7 +49,7 @@ pub struct SshSocket {
socket_path: PathBuf,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct SshConnectionOptions {
pub host: String,
pub username: Option<String>,
Expand Down Expand Up @@ -250,6 +251,7 @@ struct SshRemoteClientState {
pub struct SshRemoteClient {
client: Arc<ChannelClient>,
inner_state: Mutex<Option<SshRemoteClientState>>,
connection_options: SshConnectionOptions,
}

impl SshRemoteClient {
Expand All @@ -265,15 +267,15 @@ impl SshRemoteClient {
let this = Arc::new(Self {
client,
inner_state: Mutex::new(None),
connection_options: connection_options.clone(),
});

let inner_state = {
let (proxy, proxy_incoming_tx, proxy_outgoing_rx) =
ChannelForwarder::new(incoming_tx, outgoing_rx, cx);

let (ssh_connection, ssh_process) =
Self::establish_connection(connection_options.clone(), delegate.clone(), cx)
.await?;
Self::establish_connection(connection_options, delegate.clone(), cx).await?;

let multiplex_task = Self::multiplex(
Arc::downgrade(&this),
Expand Down Expand Up @@ -505,6 +507,13 @@ impl SshRemoteClient {
self.client.clone().into()
}

pub fn connection_string(&self) -> String {
self.connection_options.connection_string()
}

pub fn is_reconnect_underway(&self) -> bool {
maybe!({ Some(self.inner_state.try_lock()?.is_none()) }).unwrap_or_default()
}
#[cfg(any(test, feature = "test-support"))]
pub fn fake(
client_cx: &mut gpui::TestAppContext,
Expand All @@ -519,6 +528,7 @@ impl SshRemoteClient {
Arc::new(Self {
client,
inner_state: Mutex::new(None),
connection_options: SshConnectionOptions::default(),
})
}),
server_cx.update(|cx| ChannelClient::new(client_to_server_rx, server_to_client_tx, cx)),
Expand Down
45 changes: 44 additions & 1 deletion crates/title_bar/src/title_bar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use gpui::{
StatefulInteractiveElement, Styled, Subscription, View, ViewContext, VisualContext, WeakView,
};
use project::{Project, RepositoryEntry};
use recent_projects::RecentProjects;
use recent_projects::{OpenRemote, RecentProjects};
use rpc::proto::{self, DevServerStatus};
use smallvec::SmallVec;
use std::sync::Arc;
Expand Down Expand Up @@ -262,6 +262,46 @@ impl TitleBar {
self
}

fn render_ssh_project_host(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
let host = self.project.read(cx).ssh_connection_string(cx)?;
let meta = SharedString::from(format!("Connected to: {host}"));
let indicator_color = if self.project.read(cx).ssh_is_connected()? {
Color::Success
} else {
Color::Warning
};
let indicator = div()
.absolute()
.w_1_4()
.h_1_4()
.right_0p5()
.bottom_0p5()
.p_1()
.rounded_2xl()
.bg(indicator_color.color(cx));

Some(
div()
.child(
IconButton::new("ssh-server-icon", IconName::Server)
.tooltip(move |cx| {
Tooltip::with_meta(
"Remote Project",
Some(&OpenRemote),
meta.clone(),
cx,
)
})
.shape(ui::IconButtonShape::Square)
.on_click(|_, cx| {
cx.dispatch_action(OpenRemote.boxed_clone());
}),
)
.child(indicator)
.into_any_element(),
)
}

pub fn render_project_host(&self, cx: &mut ViewContext<Self>) -> Option<AnyElement> {
if let Some(dev_server) =
self.project
Expand Down Expand Up @@ -296,6 +336,9 @@ impl TitleBar {
.into_any_element(),
);
}
if self.project.read(cx).is_via_ssh() {
return self.render_ssh_project_host(cx);
}

if self.project.read(cx).is_disconnected() {
return Some(
Expand Down

0 comments on commit 1320fed

Please sign in to comment.