diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 28c863ef0ba77bc04b3021112213a5a680a7a635..fadc6a36427a9cd78cbaf1e36d7122b6416530fd 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -1669,7 +1669,12 @@ mod tests { } #[gpui::test(iterations = 10)] - async fn test_share_project(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) { + async fn test_share_project( + deterministic: Arc, + cx_a: &mut TestAppContext, + cx_b: &mut TestAppContext, + cx_b2: &mut TestAppContext, + ) { let (window_b, _) = cx_b.add_window(|_| EmptyView); let lang_registry = Arc::new(LanguageRegistry::test()); let fs = FakeFs::new(cx_a.background()); @@ -1701,6 +1706,9 @@ mod tests { cx, ) }); + let project_id = project_a + .read_with(cx_a, |project, _| project.next_remote_id()) + .await; let (worktree_a, _) = project_a .update(cx_a, |p, cx| { p.find_or_create_local_worktree("/a", true, cx) @@ -1776,14 +1784,41 @@ mod tests { // .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 0) // .await; - // Dropping the client B's project removes client B from client A's collaborators. + // Client B can join again on a different window because they are already a participant. + let client_b2 = server.create_client(cx_b2, "user_b").await; + let project_b2 = Project::remote( + project_id, + client_b2.client.clone(), + client_b2.user_store.clone(), + lang_registry.clone(), + FakeFs::new(cx_b2.background()), + &mut cx_b2.to_async(), + ) + .await + .unwrap(); + deterministic.run_until_parked(); + project_a.read_with(cx_a, |project, _| { + assert_eq!(project.collaborators().len(), 2); + }); + project_b.read_with(cx_b, |project, _| { + assert_eq!(project.collaborators().len(), 2); + }); + project_b2.read_with(cx_b2, |project, _| { + assert_eq!(project.collaborators().len(), 2); + }); + + // Dropping client B's first project removes only that from client A's collaborators. cx_b.update(move |_| { drop(client_b.project.take()); drop(project_b); }); - project_a - .condition(&cx_a, |project, _| project.collaborators().is_empty()) - .await; + deterministic.run_until_parked(); + project_a.read_with(cx_a, |project, _| { + assert_eq!(project.collaborators().len(), 1); + }); + project_b2.read_with(cx_b2, |project, _| { + assert_eq!(project.collaborators().len(), 1); + }); } #[gpui::test(iterations = 10)] diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 33e37dc900165a06fac3615ea50f19e6c7ea0ebb..e6eb2dcf771fd4f8ff8924f60145834e6b2a768c 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -3805,11 +3805,19 @@ impl Project { mut cx: AsyncAppContext, ) -> Result<()> { let user_id = message.payload.requester_id; - let user_store = this.read_with(&cx, |this, _| this.user_store.clone()); - let user = user_store - .update(&mut cx, |store, cx| store.fetch_user(user_id, cx)) - .await?; - this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user))); + if this.read_with(&cx, |project, _| { + project.collaborators.values().any(|c| c.user.id == user_id) + }) { + this.update(&mut cx, |this, cx| { + this.respond_to_join_request(user_id, true, cx) + }); + } else { + let user_store = this.read_with(&cx, |this, _| this.user_store.clone()); + let user = user_store + .update(&mut cx, |store, cx| store.fetch_user(user_id, cx)) + .await?; + this.update(&mut cx, |_, cx| cx.emit(Event::ContactRequestedJoin(user))); + } Ok(()) }