Workspace persistence for SSH projects (#17996)
TODOs: - [x] Add tests to `workspace/src/persistence.rs` - [x] Add a icon for ssh projects - [x] Fix all `TODO` comments - [x] Use `port` if it's passed in the ssh connection options In next PRs: - Make sure unsaved buffers are persisted/restored, along with other items/layout - Handle multiple paths/worktrees correctly Release Notes: - N/A --------- Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
This commit is contained in:
parent
7d0a7541bf
commit
e9f2e72ff0
12 changed files with 592 additions and 141 deletions
|
@ -49,15 +49,19 @@ use node_runtime::NodeRuntime;
|
|||
use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
|
||||
pub use pane::*;
|
||||
pub use pane_group::*;
|
||||
use persistence::{model::SerializedWorkspace, SerializedWindowBounds, DB};
|
||||
pub use persistence::{
|
||||
model::{ItemId, LocalPaths, SerializedDevServerProject, SerializedWorkspaceLocation},
|
||||
WorkspaceDb, DB as WORKSPACE_DB,
|
||||
};
|
||||
use persistence::{
|
||||
model::{SerializedSshProject, SerializedWorkspace},
|
||||
SerializedWindowBounds, DB,
|
||||
};
|
||||
use postage::stream::Stream;
|
||||
use project::{
|
||||
DirectoryLister, Project, ProjectEntryId, ProjectPath, ResolvedPath, Worktree, WorktreeId,
|
||||
};
|
||||
use remote::{SshConnectionOptions, SshSession};
|
||||
use serde::Deserialize;
|
||||
use session::AppSession;
|
||||
use settings::Settings;
|
||||
|
@ -756,6 +760,7 @@ pub struct Workspace {
|
|||
render_disconnected_overlay:
|
||||
Option<Box<dyn Fn(&mut Self, &mut ViewContext<Self>) -> AnyElement>>,
|
||||
serializable_items_tx: UnboundedSender<Box<dyn SerializableItemHandle>>,
|
||||
serialized_ssh_project: Option<SerializedSshProject>,
|
||||
_items_serializer: Task<Result<()>>,
|
||||
session_id: Option<String>,
|
||||
}
|
||||
|
@ -1054,6 +1059,7 @@ impl Workspace {
|
|||
serializable_items_tx,
|
||||
_items_serializer,
|
||||
session_id: Some(session_id),
|
||||
serialized_ssh_project: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1440,6 +1446,10 @@ impl Workspace {
|
|||
self.on_prompt_for_open_path = Some(prompt)
|
||||
}
|
||||
|
||||
pub fn set_serialized_ssh_project(&mut self, serialized_ssh_project: SerializedSshProject) {
|
||||
self.serialized_ssh_project = Some(serialized_ssh_project);
|
||||
}
|
||||
|
||||
pub fn set_render_disconnected_overlay(
|
||||
&mut self,
|
||||
render: impl Fn(&mut Self, &mut ViewContext<Self>) -> AnyElement + 'static,
|
||||
|
@ -4097,7 +4107,9 @@ impl Workspace {
|
|||
}
|
||||
}
|
||||
|
||||
let location = if let Some(local_paths) = self.local_paths(cx) {
|
||||
let location = if let Some(ssh_project) = &self.serialized_ssh_project {
|
||||
Some(SerializedWorkspaceLocation::Ssh(ssh_project.clone()))
|
||||
} else if let Some(local_paths) = self.local_paths(cx) {
|
||||
if !local_paths.is_empty() {
|
||||
Some(SerializedWorkspaceLocation::from_local_paths(local_paths))
|
||||
} else {
|
||||
|
@ -5476,6 +5488,70 @@ pub fn join_hosted_project(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn open_ssh_project(
|
||||
window: WindowHandle<Workspace>,
|
||||
connection_options: SshConnectionOptions,
|
||||
session: Arc<SshSession>,
|
||||
app_state: Arc<AppState>,
|
||||
paths: Vec<PathBuf>,
|
||||
cx: &mut AppContext,
|
||||
) -> Task<Result<()>> {
|
||||
cx.spawn(|mut cx| async move {
|
||||
// TODO: Handle multiple paths
|
||||
let path = paths.iter().next().cloned().unwrap_or_default();
|
||||
|
||||
let serialized_ssh_project = persistence::DB
|
||||
.get_or_create_ssh_project(
|
||||
connection_options.host.clone(),
|
||||
connection_options.port,
|
||||
path.to_string_lossy().to_string(),
|
||||
connection_options.username.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let project = cx.update(|cx| {
|
||||
project::Project::ssh(
|
||||
session,
|
||||
app_state.client.clone(),
|
||||
app_state.node_runtime.clone(),
|
||||
app_state.user_store.clone(),
|
||||
app_state.languages.clone(),
|
||||
app_state.fs.clone(),
|
||||
cx,
|
||||
)
|
||||
})?;
|
||||
|
||||
for path in paths {
|
||||
project
|
||||
.update(&mut cx, |project, cx| {
|
||||
project.find_or_create_worktree(&path, true, cx)
|
||||
})?
|
||||
.await?;
|
||||
}
|
||||
|
||||
let serialized_workspace =
|
||||
persistence::DB.workspace_for_ssh_project(&serialized_ssh_project);
|
||||
|
||||
let workspace_id =
|
||||
if let Some(workspace_id) = serialized_workspace.map(|workspace| workspace.id) {
|
||||
workspace_id
|
||||
} else {
|
||||
persistence::DB.next_id().await?
|
||||
};
|
||||
|
||||
cx.update_window(window.into(), |_, cx| {
|
||||
cx.replace_root_view(|cx| {
|
||||
let mut workspace =
|
||||
Workspace::new(Some(workspace_id), project, app_state.clone(), cx);
|
||||
workspace.set_serialized_ssh_project(serialized_ssh_project);
|
||||
workspace
|
||||
});
|
||||
})?;
|
||||
|
||||
window.update(&mut cx, |_, cx| cx.activate_window())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn join_dev_server_project(
|
||||
dev_server_project_id: DevServerProjectId,
|
||||
project_id: ProjectId,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue