workspace: Fix SSH remote restore on second open + Fix panel not opening automatically on new SSH remote (#27830)

Closes #26902

- We used to serialize SSH remote only when opened via recent entries,
and not on first time. This broke restore, when opening same folder for
second time from recent entries. Once opened for second time, restoring
used to. work correctly. This PR fixes this by serializing when opened
for first time.

- We didn't handle window replace post worktree creation in first time
flow, this resulted in project panel not opening automatically like it
does with recent entries, or local projects. This PR fixes it by
following same flow as recent entries.

Release Notes:

- Fixed SSH remote not restoring when opening for second time.
- Fixed project panel not opening when opening new SSH remote folder.
This commit is contained in:
Smit Barmase 2025-04-01 14:05:28 +05:30 committed by GitHub
parent 5343f1cdaf
commit 8be5ed22f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 137 additions and 94 deletions

View file

@ -6279,7 +6279,7 @@ pub fn create_and_open_local_file(
})
}
pub fn open_ssh_project(
pub fn open_ssh_project_with_new_connection(
window: WindowHandle<Workspace>,
connection_options: SshConnectionOptions,
cancel_rx: oneshot::Receiver<()>,
@ -6320,70 +6320,120 @@ pub fn open_ssh_project(
)
})?;
let toolchains = DB.toolchains(workspace_id).await?;
for (toolchain, worktree_id, path) in toolchains {
project
.update(cx, |this, cx| {
this.activate_toolchain(ProjectPath { worktree_id, path }, toolchain, cx)
})?
.await;
}
let mut project_paths_to_open = vec![];
let mut project_path_errors = vec![];
for path in paths {
let result = cx
.update(|cx| Workspace::project_path_for_path(project.clone(), &path, true, cx))?
.await;
match result {
Ok((_, project_path)) => {
project_paths_to_open.push((path.clone(), Some(project_path)));
}
Err(error) => {
project_path_errors.push(error);
}
};
}
if project_paths_to_open.is_empty() {
return Err(project_path_errors
.pop()
.unwrap_or_else(|| anyhow!("no paths given")));
}
cx.update_window(window.into(), |_, window, cx| {
window.replace_root(cx, |window, cx| {
telemetry::event!("SSH Project Opened");
let mut workspace =
Workspace::new(Some(workspace_id), project, app_state.clone(), window, cx);
workspace.set_serialized_ssh_project(serialized_ssh_project);
workspace
});
})?;
window
.update(cx, |_, window, cx| {
window.activate_window();
open_items(serialized_workspace, project_paths_to_open, window, cx)
})?
.await?;
window.update(cx, |workspace, _, cx| {
for error in project_path_errors {
if error.error_code() == proto::ErrorCode::DevServerProjectPathDoesNotExist {
if let Some(path) = error.error_tag("path") {
workspace.show_error(&anyhow!("'{path}' does not exist"), cx)
}
} else {
workspace.show_error(&error, cx)
}
}
})
open_ssh_project_inner(
project,
paths,
serialized_ssh_project,
workspace_id,
serialized_workspace,
app_state,
window,
cx,
)
.await
})
}
pub fn open_ssh_project_with_existing_connection(
connection_options: SshConnectionOptions,
project: Entity<Project>,
paths: Vec<PathBuf>,
app_state: Arc<AppState>,
window: WindowHandle<Workspace>,
cx: &mut AsyncApp,
) -> Task<Result<()>> {
cx.spawn(async move |cx| {
let (serialized_ssh_project, workspace_id, serialized_workspace) =
serialize_ssh_project(connection_options.clone(), paths.clone(), &cx).await?;
open_ssh_project_inner(
project,
paths,
serialized_ssh_project,
workspace_id,
serialized_workspace,
app_state,
window,
cx,
)
.await
})
}
async fn open_ssh_project_inner(
project: Entity<Project>,
paths: Vec<PathBuf>,
serialized_ssh_project: SerializedSshProject,
workspace_id: WorkspaceId,
serialized_workspace: Option<SerializedWorkspace>,
app_state: Arc<AppState>,
window: WindowHandle<Workspace>,
cx: &mut AsyncApp,
) -> Result<()> {
let toolchains = DB.toolchains(workspace_id).await?;
for (toolchain, worktree_id, path) in toolchains {
project
.update(cx, |this, cx| {
this.activate_toolchain(ProjectPath { worktree_id, path }, toolchain, cx)
})?
.await;
}
let mut project_paths_to_open = vec![];
let mut project_path_errors = vec![];
for path in paths {
let result = cx
.update(|cx| Workspace::project_path_for_path(project.clone(), &path, true, cx))?
.await;
match result {
Ok((_, project_path)) => {
project_paths_to_open.push((path.clone(), Some(project_path)));
}
Err(error) => {
project_path_errors.push(error);
}
};
}
if project_paths_to_open.is_empty() {
return Err(project_path_errors
.pop()
.unwrap_or_else(|| anyhow!("no paths given")));
}
cx.update_window(window.into(), |_, window, cx| {
window.replace_root(cx, |window, cx| {
telemetry::event!("SSH Project Opened");
let mut workspace =
Workspace::new(Some(workspace_id), project, app_state.clone(), window, cx);
workspace.set_serialized_ssh_project(serialized_ssh_project);
workspace
});
})?;
window
.update(cx, |_, window, cx| {
window.activate_window();
open_items(serialized_workspace, project_paths_to_open, window, cx)
})?
.await?;
window.update(cx, |workspace, _, cx| {
for error in project_path_errors {
if error.error_code() == proto::ErrorCode::DevServerProjectPathDoesNotExist {
if let Some(path) = error.error_tag("path") {
workspace.show_error(&anyhow!("'{path}' does not exist"), cx)
}
} else {
workspace.show_error(&error, cx)
}
}
})?;
Ok(())
}
fn serialize_ssh_project(
connection_options: SshConnectionOptions,
paths: Vec<PathBuf>,