diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f0b2c7b076..a19d2c5b58 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -35,9 +35,9 @@ use gpui::{ CursorStyle, ModifiersChangedEvent, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions, }, - AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AnyWindowHandle, AppContext, AsyncAppContext, - Entity, ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, - ViewHandle, WeakViewHandle, WindowContext, WindowHandle, + AnyModelHandle, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, + ModelContext, ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, + WeakViewHandle, WindowContext, WindowHandle, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use itertools::Itertools; @@ -4299,12 +4299,14 @@ pub fn join_channel( } if let Err(err) = result { - let prompt = active_window.unwrap().prompt( - PromptLevel::Critical, - &format!("Failed to join channel: {}", err), - &["Ok"], - &mut cx, - ); + let prompt = active_window.unwrap().update(&mut cx, |_, cx| { + cx.prompt( + PromptLevel::Critical, + &format!("Failed to join channel: {}", err), + &["Ok"], + ) + }); + if let Some(mut prompt) = prompt { prompt.next().await; } else { @@ -4317,17 +4319,39 @@ pub fn join_channel( }) } -pub fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option { +pub async fn get_any_active_workspace( + app_state: Arc, + mut cx: AsyncAppContext, +) -> Result> { + // find an existing workspace to focus and show call controls + let active_window = activate_any_workspace_window(&mut cx); + if active_window.is_none() { + cx.update(|cx| Workspace::new_local(vec![], app_state.clone(), None, cx)) + .await; + } + + let Some(active_window) = activate_any_workspace_window(&mut cx) else { + return Err(anyhow!("could not open zed"))?; + }; + + Ok(active_window) +} + +pub fn activate_any_workspace_window(cx: &mut AsyncAppContext) -> Option> { for window in cx.windows() { - let found = window.update(cx, |cx| { - let is_workspace = cx.root_view().clone().downcast::().is_some(); - if is_workspace { - cx.activate_window(); - } - is_workspace - }); - if found == Some(true) { - return Some(window); + if let Some(workspace) = window + .update(cx, |cx| { + cx.root_view() + .clone() + .downcast::() + .map(|workspace| { + cx.activate_window(); + workspace + }) + }) + .flatten() + { + return Some(workspace); } } None diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index a590db098a..5add524414 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -7,6 +7,7 @@ use cli::FORCE_CLI_MODE_ENV_VAR_NAME; use client::{ self, Client, TelemetrySettings, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN, }; +use collab_ui::channel_view::ChannelView; use db::kvp::KEY_VALUE_STORE; use editor::Editor; use futures::StreamExt; @@ -240,6 +241,20 @@ fn main() { }) .detach_and_log_err(cx) } + Ok(Some(OpenRequest::OpenChannelNotes { channel_id })) => { + triggered_authentication = true; + let app_state = app_state.clone(); + let client = client.clone(); + cx.spawn(|mut cx| async move { + // ignore errors here, we'll show a generic "not signed in" + let _ = authenticate(client, &cx).await; + let workspace = + workspace::get_any_active_workspace(app_state, cx.clone()).await?; + cx.update(|cx| ChannelView::open(channel_id, workspace, cx)) + .await + }) + .detach_and_log_err(cx) + } Ok(None) | Err(_) => cx .spawn({ let app_state = app_state.clone(); @@ -254,8 +269,10 @@ fn main() { while let Some(request) = open_rx.next().await { match request { OpenRequest::Paths { paths } => { - cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) - .detach(); + cx.update(|cx| { + workspace::open_paths(&paths, &app_state.clone(), None, cx) + }) + .detach(); } OpenRequest::CliConnection { connection } => { cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx)) @@ -266,6 +283,16 @@ fn main() { workspace::join_channel(channel_id, app_state.clone(), None, cx) }) .detach(), + OpenRequest::OpenChannelNotes { channel_id } => { + let app_state = app_state.clone(); + if let Ok(workspace) = + workspace::get_any_active_workspace(app_state, cx.clone()).await + { + cx.update(|cx| { + ChannelView::open(channel_id, workspace, cx).detach(); + }) + } + } } } } diff --git a/crates/zed/src/open_listener.rs b/crates/zed/src/open_listener.rs index 578d8cd69f..e0b360d0d7 100644 --- a/crates/zed/src/open_listener.rs +++ b/crates/zed/src/open_listener.rs @@ -32,6 +32,9 @@ pub enum OpenRequest { JoinChannel { channel_id: u64, }, + OpenChannelNotes { + channel_id: u64, + }, } pub struct OpenListener { @@ -85,7 +88,11 @@ impl OpenListener { if let Some(slug) = parts.next() { if let Some(id_str) = slug.split("-").last() { if let Ok(channel_id) = id_str.parse::() { - return Some(OpenRequest::JoinChannel { channel_id }); + if Some("notes") == parts.next() { + return Some(OpenRequest::OpenChannelNotes { channel_id }); + } else { + return Some(OpenRequest::JoinChannel { channel_id }); + } } } }