diff --git a/crates/collab/src/tests/following_tests.rs b/crates/collab/src/tests/following_tests.rs index bfebd0d2571ed28cc674a6d5a455cb098a0dfba0..28fcc99271a1ad0ef06c37386b96bd59e4f7936c 100644 --- a/crates/collab/src/tests/following_tests.rs +++ b/crates/collab/src/tests/following_tests.rs @@ -22,6 +22,8 @@ use workspace::{ SplitDirection, Workspace, }; +use super::TestClient; + #[gpui::test(iterations = 10)] async fn test_basic_following( cx_a: &mut TestAppContext, @@ -1996,3 +1998,82 @@ async fn test_following_to_channel_notes_without_a_shared_project( ); }); } + +async fn join_channel( + channel_id: u64, + client: &TestClient, + cx: &mut TestAppContext, +) -> anyhow::Result<()> { + cx.update(|cx| workspace::join_channel(channel_id, client.app_state.clone(), None, cx)) + .await +} + +async fn share_workspace( + workspace: &View, + cx: &mut VisualTestContext, +) -> anyhow::Result { + let project = workspace.update(cx, |workspace, _| workspace.project().clone()); + cx.read(ActiveCall::global) + .update(cx, |call, cx| call.share_project(project, cx)) + .await +} + +#[gpui::test] +async fn test_following_to_channel_notes_other_workspace( + cx_a: &mut TestAppContext, + cx_b: &mut TestAppContext, +) { + let (_, client_a, client_b, channel) = TestServer::start2(cx_a, cx_b).await; + + let mut cx_a2 = cx_a.clone(); + let (workspace_a, cx_a) = client_a.build_test_workspace(cx_a).await; + join_channel(channel, &client_a, cx_a).await.unwrap(); + share_workspace(&workspace_a, cx_a).await.unwrap(); + + // a opens 1.txt + cx_a.simulate_keystrokes("cmd-p 1 enter"); + cx_a.run_until_parked(); + workspace_a.update(cx_a, |workspace, cx| { + let editor = workspace.active_item(cx).unwrap(); + assert_eq!(editor.tab_description(0, cx).unwrap(), "1.txt"); + }); + + // b joins channel and is following a + join_channel(channel, &client_b, cx_b).await.unwrap(); + cx_b.run_until_parked(); + let (workspace_b, cx_b) = client_b.active_workspace(cx_b); + workspace_b.update(cx_b, |workspace, cx| { + let editor = workspace.active_item(cx).unwrap(); + assert_eq!(editor.tab_description(0, cx).unwrap(), "1.txt"); + }); + + // a opens a second workspace and the channel notes + let (workspace_a2, cx_a2) = client_a.build_test_workspace(&mut cx_a2).await; + cx_a2.update(|cx| cx.activate_window()); + cx_a2 + .update(|cx| ChannelView::open(channel, None, workspace_a2, cx)) + .await + .unwrap(); + cx_a2.run_until_parked(); + + // b should follow a to the channel notes + workspace_b.update(cx_b, |workspace, cx| { + let editor = workspace.active_item_as::(cx).unwrap(); + assert_eq!(editor.read(cx).channel(cx).unwrap().id, channel); + }); + + // a returns to the shared project + cx_a.update(|cx| cx.activate_window()); + cx_a.run_until_parked(); + + workspace_a.update(cx_a, |workspace, cx| { + let editor = workspace.active_item(cx).unwrap(); + assert_eq!(editor.tab_description(0, cx).unwrap(), "1.txt"); + }); + + // b should follow a back + workspace_b.update(cx_b, |workspace, cx| { + let editor = workspace.active_item_as::(cx).unwrap(); + assert_eq!(editor.tab_description(0, cx).unwrap(), "1.txt"); + }); +} diff --git a/crates/collab/src/tests/test_server.rs b/crates/collab/src/tests/test_server.rs index 13fd15e3f445020af324cdaba03aa0b686c70956..69e338b6ea45eb0bf298de386c2602732fa0b718 100644 --- a/crates/collab/src/tests/test_server.rs +++ b/crates/collab/src/tests/test_server.rs @@ -123,7 +123,12 @@ impl TestServer { let client_a = server.create_client(cx_a, "user_a").await; let client_b = server.create_client(cx_b, "user_b").await; let channel_id = server - .make_channel("a", None, (&client_a, cx_a), &mut [(&client_b, cx_b)]) + .make_channel( + "test-channel", + None, + (&client_a, cx_a), + &mut [(&client_b, cx_b)], + ) .await; cx_a.run_until_parked(); diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index 29175983d3f6e48afe8f048fd221195fc29e3770..2d0177c34323d2e6e6c243ec5e6d7852513269d8 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -562,14 +562,23 @@ impl CollabTitlebarItem { } fn window_activation_changed(&mut self, cx: &mut ViewContext) { - let project = if cx.is_window_active() { - Some(self.project.clone()) - } else { - None - }; - ActiveCall::global(cx) - .update(cx, |call, cx| call.set_location(project.as_ref(), cx)) - .detach_and_log_err(cx); + if cx.is_window_active() { + ActiveCall::global(cx) + .update(cx, |call, cx| call.set_location(Some(&self.project), cx)) + .detach_and_log_err(cx); + return; + } + + if cx.active_window().is_none() { + ActiveCall::global(cx) + .update(cx, |call, cx| call.set_location(None, cx)) + .detach_and_log_err(cx); + } + self.workspace + .update(cx, |workspace, cx| { + workspace.update_active_view_for_followers(cx); + }) + .ok(); } fn active_call_changed(&mut self, cx: &mut ViewContext) { diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index 908ea1d168c22fcfbeeb0417bd40baec9f0ae1c9..d5d8aed39dd300f3e5dd9eccd549d79272b2bae9 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -666,6 +666,7 @@ pub trait ProjectItem: Item { Self: Sized; } +#[derive(Debug)] pub enum FollowEvent { Unfollow, } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 23c9b84f010a7b6f78b6a861339f2f33acd90a49..6ca74875b76f896ecc9ae8c4b8f500f5b8261bc2 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2910,25 +2910,27 @@ impl Workspace { Ok(()) } - fn update_active_view_for_followers(&mut self, cx: &mut WindowContext) { + pub fn update_active_view_for_followers(&mut self, cx: &mut WindowContext) { let mut is_project_item = true; let mut update = proto::UpdateActiveView::default(); - if let Some(item) = self.active_item(cx) { - if item.focus_handle(cx).contains_focused(cx) { - if let Some(item) = item.to_followable_item_handle(cx) { - is_project_item = item.is_project_item(cx); - update = proto::UpdateActiveView { - id: item - .remote_id(&self.app_state.client, cx) - .map(|id| id.to_proto()), - leader_id: self.leader_for_pane(&self.active_pane), - }; + if cx.is_window_active() { + if let Some(item) = self.active_item(cx) { + if item.focus_handle(cx).contains_focused(cx) { + if let Some(item) = item.to_followable_item_handle(cx) { + is_project_item = item.is_project_item(cx); + update = proto::UpdateActiveView { + id: item + .remote_id(&self.app_state.client, cx) + .map(|id| id.to_proto()), + leader_id: self.leader_for_pane(&self.active_pane), + }; + } } } } - if update.id != self.last_active_view_id { + if &update.id != &self.last_active_view_id { self.last_active_view_id = update.id.clone(); self.update_followers( is_project_item,