Detailed changes
@@ -5,7 +5,7 @@ pub mod room;
use anyhow::{anyhow, Result};
use audio::Audio;
use call_settings::CallSettings;
-use client::{proto, Client, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE};
+use client::{proto, ChannelId, Client, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE};
use collections::HashSet;
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
use gpui::{
@@ -107,7 +107,7 @@ impl ActiveCall {
}
}
- pub fn channel_id(&self, cx: &AppContext) -> Option<u64> {
+ pub fn channel_id(&self, cx: &AppContext) -> Option<ChannelId> {
self.room()?.read(cx).channel_id()
}
@@ -336,7 +336,7 @@ impl ActiveCall {
pub fn join_channel(
&mut self,
- channel_id: u64,
+ channel_id: ChannelId,
cx: &mut ModelContext<Self>,
) -> Task<Result<Option<Model<Room>>>> {
if let Some(room) = self.room().cloned() {
@@ -487,7 +487,7 @@ impl ActiveCall {
pub fn report_call_event_for_room(
operation: &'static str,
room_id: u64,
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
client: &Arc<Client>,
) {
let telemetry = client.telemetry();
@@ -497,7 +497,7 @@ pub fn report_call_event_for_room(
pub fn report_call_event_for_channel(
operation: &'static str,
- channel_id: u64,
+ channel_id: ChannelId,
client: &Arc<Client>,
cx: &AppContext,
) {
@@ -6,7 +6,7 @@ use anyhow::{anyhow, Result};
use audio::{Audio, Sound};
use client::{
proto::{self, PeerId},
- Client, ParticipantIndex, TypedEnvelope, User, UserStore,
+ ChannelId, Client, ParticipantIndex, TypedEnvelope, User, UserStore,
};
use collections::{BTreeMap, HashMap, HashSet};
use fs::Fs;
@@ -27,7 +27,7 @@ pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Event {
RoomJoined {
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
},
ParticipantLocationChanged {
participant_id: proto::PeerId,
@@ -53,13 +53,13 @@ pub enum Event {
project_id: u64,
},
Left {
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
},
}
pub struct Room {
id: u64,
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
live_kit: Option<LiveKitRoom>,
status: RoomStatus,
shared_projects: HashSet<WeakModel<Project>>,
@@ -84,7 +84,7 @@ pub struct Room {
impl EventEmitter<Event> for Room {}
impl Room {
- pub fn channel_id(&self) -> Option<u64> {
+ pub fn channel_id(&self) -> Option<ChannelId> {
self.channel_id
}
@@ -106,7 +106,7 @@ impl Room {
fn new(
id: u64,
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
live_kit_connection_info: Option<proto::LiveKitConnectionInfo>,
client: Arc<Client>,
user_store: Model<UserStore>,
@@ -273,13 +273,17 @@ impl Room {
}
pub(crate) async fn join_channel(
- channel_id: u64,
+ channel_id: ChannelId,
client: Arc<Client>,
user_store: Model<UserStore>,
cx: AsyncAppContext,
) -> Result<Model<Self>> {
Self::from_join_response(
- client.request(proto::JoinChannel { channel_id }).await?,
+ client
+ .request(proto::JoinChannel {
+ channel_id: channel_id.0,
+ })
+ .await?,
client,
user_store,
cx,
@@ -337,7 +341,7 @@ impl Room {
let room = cx.new_model(|cx| {
Self::new(
room_proto.id,
- response.channel_id,
+ response.channel_id.map(ChannelId),
response.live_kit_connection_info,
client,
user_store,
@@ -11,7 +11,7 @@ pub use channel_chat::{
mentions_to_proto, ChannelChat, ChannelChatEvent, ChannelMessage, ChannelMessageId,
MessageParams,
};
-pub use channel_store::{Channel, ChannelEvent, ChannelId, ChannelMembership, ChannelStore};
+pub use channel_store::{Channel, ChannelEvent, ChannelMembership, ChannelStore, HostedProjectId};
#[cfg(test)]
mod channel_store_tests;
@@ -1,6 +1,6 @@
-use crate::{Channel, ChannelId, ChannelStore};
+use crate::{Channel, ChannelStore};
use anyhow::Result;
-use client::{Client, Collaborator, UserStore, ZED_ALWAYS_ACTIVE};
+use client::{ChannelId, Client, Collaborator, UserStore, ZED_ALWAYS_ACTIVE};
use collections::HashMap;
use gpui::{AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task};
use language::proto::serialize_version;
@@ -51,7 +51,7 @@ impl ChannelBuffer {
) -> Result<Model<Self>> {
let response = client
.request(proto::JoinChannelBuffer {
- channel_id: channel.id,
+ channel_id: channel.id.0,
})
.await?;
let buffer_id = BufferId::new(response.buffer_id)?;
@@ -68,7 +68,7 @@ impl ChannelBuffer {
})?;
buffer.update(&mut cx, |buffer, cx| buffer.apply_ops(operations, cx))??;
- let subscription = client.subscribe_to_entity(channel.id)?;
+ let subscription = client.subscribe_to_entity(channel.id.0)?;
anyhow::Ok(cx.new_model(|cx| {
cx.subscribe(&buffer, Self::on_buffer_update).detach();
@@ -97,7 +97,7 @@ impl ChannelBuffer {
}
self.client
.send(proto::LeaveChannelBuffer {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
})
.log_err();
}
@@ -191,7 +191,7 @@ impl ChannelBuffer {
let operation = language::proto::serialize_operation(operation);
self.client
.send(proto::UpdateChannelBuffer {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
operations: vec![operation],
})
.log_err();
@@ -1,9 +1,9 @@
-use crate::{Channel, ChannelId, ChannelStore};
+use crate::{Channel, ChannelStore};
use anyhow::{anyhow, Result};
use client::{
proto,
user::{User, UserStore},
- Client, Subscription, TypedEnvelope, UserId,
+ ChannelId, Client, Subscription, TypedEnvelope, UserId,
};
use collections::HashSet;
use futures::lock::Mutex;
@@ -104,10 +104,12 @@ impl ChannelChat {
mut cx: AsyncAppContext,
) -> Result<Model<Self>> {
let channel_id = channel.id;
- let subscription = client.subscribe_to_entity(channel_id).unwrap();
+ let subscription = client.subscribe_to_entity(channel_id.0).unwrap();
let response = client
- .request(proto::JoinChannelChat { channel_id })
+ .request(proto::JoinChannelChat {
+ channel_id: channel_id.0,
+ })
.await?;
let handle = cx.new_model(|cx| {
@@ -143,7 +145,7 @@ impl ChannelChat {
fn release(&mut self, _: &mut AppContext) {
self.rpc
.send(proto::LeaveChannelChat {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
})
.log_err();
}
@@ -200,7 +202,7 @@ impl ChannelChat {
Ok(cx.spawn(move |this, mut cx| async move {
let outgoing_message_guard = outgoing_messages_lock.lock().await;
let request = rpc.request(proto::SendChannelMessage {
- channel_id,
+ channel_id: channel_id.0,
body: message.text,
nonce: Some(nonce.into()),
mentions: mentions_to_proto(&message.mentions),
@@ -220,7 +222,7 @@ impl ChannelChat {
pub fn remove_message(&mut self, id: u64, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
let response = self.rpc.request(proto::RemoveChannelMessage {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
message_id: id,
});
cx.spawn(move |this, mut cx| async move {
@@ -245,7 +247,7 @@ impl ChannelChat {
async move {
let response = rpc
.request(proto::GetChannelMessages {
- channel_id,
+ channel_id: channel_id.0,
before_message_id,
})
.await?;
@@ -323,7 +325,7 @@ impl ChannelChat {
{
self.rpc
.send(proto::AckChannelMessage {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
message_id: latest_message_id,
})
.ok();
@@ -401,7 +403,11 @@ impl ChannelChat {
let channel_id = self.channel_id;
cx.spawn(move |this, mut cx| {
async move {
- let response = rpc.request(proto::JoinChannelChat { channel_id }).await?;
+ let response = rpc
+ .request(proto::JoinChannelChat {
+ channel_id: channel_id.0,
+ })
+ .await?;
Self::handle_loaded_messages(
this.clone(),
user_store.clone(),
@@ -418,7 +424,7 @@ impl ChannelChat {
for pending_message in pending_messages {
let request = rpc.request(proto::SendChannelMessage {
- channel_id,
+ channel_id: channel_id.0,
body: pending_message.body,
mentions: mentions_to_proto(&pending_message.mentions),
nonce: Some(pending_message.nonce.into()),
@@ -461,7 +467,7 @@ impl ChannelChat {
if self.acknowledged_message_ids.insert(id) {
self.rpc
.send(proto::AckChannelMessage {
- channel_id: self.channel_id,
+ channel_id: self.channel_id.0,
message_id: id,
})
.ok();
@@ -3,7 +3,7 @@ mod channel_index;
use crate::{channel_buffer::ChannelBuffer, channel_chat::ChannelChat, ChannelMessage};
use anyhow::{anyhow, Result};
use channel_index::ChannelIndex;
-use client::{Client, Subscription, User, UserId, UserStore};
+use client::{ChannelId, Client, Subscription, User, UserId, UserStore};
use collections::{hash_map, HashMap, HashSet};
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
use gpui::{
@@ -19,15 +19,16 @@ use rpc::{
use std::{mem, sync::Arc, time::Duration};
use util::{async_maybe, maybe, ResultExt};
+pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
+
pub fn init(client: &Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
let channel_store =
cx.new_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx));
cx.set_global(GlobalChannelStore(channel_store));
}
-pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
-
-pub type ChannelId = u64;
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
+pub struct HostedProjectId(pub u64);
#[derive(Debug, Clone, Default)]
struct NotesVersion {
@@ -35,11 +36,31 @@ struct NotesVersion {
version: clock::Global,
}
+#[derive(Debug, Clone)]
+pub struct HostedProject {
+ id: HostedProjectId,
+ channel_id: ChannelId,
+ name: SharedString,
+ _visibility: proto::ChannelVisibility,
+}
+
+impl From<proto::HostedProject> for HostedProject {
+ fn from(project: proto::HostedProject) -> Self {
+ Self {
+ id: HostedProjectId(project.id),
+ channel_id: ChannelId(project.channel_id),
+ _visibility: project.visibility(),
+ name: project.name.into(),
+ }
+ }
+}
+
pub struct ChannelStore {
pub channel_index: ChannelIndex,
channel_invitations: Vec<Arc<Channel>>,
channel_participants: HashMap<ChannelId, Vec<Arc<User>>>,
channel_states: HashMap<ChannelId, ChannelState>,
+ hosted_projects: HashMap<HostedProjectId, HostedProject>,
outgoing_invites: HashSet<(ChannelId, UserId)>,
update_channels_tx: mpsc::UnboundedSender<proto::UpdateChannels>,
@@ -58,7 +79,7 @@ pub struct Channel {
pub id: ChannelId,
pub name: SharedString,
pub visibility: proto::ChannelVisibility,
- pub parent_path: Vec<u64>,
+ pub parent_path: Vec<ChannelId>,
}
#[derive(Default)]
@@ -68,6 +89,7 @@ pub struct ChannelState {
observed_chat_message: Option<u64>,
observed_notes_versions: Option<NotesVersion>,
role: Option<ChannelRole>,
+ projects: HashSet<HostedProjectId>,
}
impl Channel {
@@ -92,10 +114,7 @@ impl Channel {
}
pub fn root_id(&self) -> ChannelId {
- self.parent_path
- .first()
- .map(|id| *id as ChannelId)
- .unwrap_or(self.id)
+ self.parent_path.first().copied().unwrap_or(self.id)
}
pub fn slug(str: &str) -> String {
@@ -199,6 +218,7 @@ impl ChannelStore {
channel_invitations: Vec::default(),
channel_index: ChannelIndex::default(),
channel_participants: Default::default(),
+ hosted_projects: Default::default(),
outgoing_invites: Default::default(),
opened_buffers: Default::default(),
opened_chats: Default::default(),
@@ -285,6 +305,19 @@ impl ChannelStore {
self.channel_index.by_id().get(&channel_id)
}
+ pub fn projects_for_id(&self, channel_id: ChannelId) -> Vec<(SharedString, HostedProjectId)> {
+ let mut projects: Vec<(SharedString, HostedProjectId)> = self
+ .channel_states
+ .get(&channel_id)
+ .map(|state| state.projects.clone())
+ .unwrap_or_default()
+ .into_iter()
+ .flat_map(|id| Some((self.hosted_projects.get(&id)?.name.clone(), id)))
+ .collect();
+ projects.sort();
+ projects
+ }
+
pub fn has_open_channel_buffer(&self, channel_id: ChannelId, _cx: &AppContext) -> bool {
if let Some(buffer) = self.opened_buffers.get(&channel_id) {
if let OpenedModelHandle::Open(buffer) = buffer {
@@ -562,13 +595,16 @@ impl ChannelStore {
let name = name.trim_start_matches("#").to_owned();
cx.spawn(move |this, mut cx| async move {
let response = client
- .request(proto::CreateChannel { name, parent_id })
+ .request(proto::CreateChannel {
+ name,
+ parent_id: parent_id.map(|cid| cid.0),
+ })
.await?;
let channel = response
.channel
.ok_or_else(|| anyhow!("missing channel in response"))?;
- let channel_id = channel.id;
+ let channel_id = ChannelId(channel.id);
this.update(&mut cx, |this, cx| {
let task = this.update_channels(
@@ -600,7 +636,10 @@ impl ChannelStore {
let client = self.client.clone();
cx.spawn(move |_, _| async move {
let _ = client
- .request(proto::MoveChannel { channel_id, to })
+ .request(proto::MoveChannel {
+ channel_id: channel_id.0,
+ to: to.0,
+ })
.await?;
Ok(())
@@ -617,7 +656,7 @@ impl ChannelStore {
cx.spawn(move |_, _| async move {
let _ = client
.request(proto::SetChannelVisibility {
- channel_id,
+ channel_id: channel_id.0,
visibility: visibility.into(),
})
.await?;
@@ -642,7 +681,7 @@ impl ChannelStore {
cx.spawn(move |this, mut cx| async move {
let result = client
.request(proto::InviteChannelMember {
- channel_id,
+ channel_id: channel_id.0,
user_id,
role: role.into(),
})
@@ -674,7 +713,7 @@ impl ChannelStore {
cx.spawn(move |this, mut cx| async move {
let result = client
.request(proto::RemoveChannelMember {
- channel_id,
+ channel_id: channel_id.0,
user_id,
})
.await;
@@ -704,7 +743,7 @@ impl ChannelStore {
cx.spawn(move |this, mut cx| async move {
let result = client
.request(proto::SetChannelMemberRole {
- channel_id,
+ channel_id: channel_id.0,
user_id,
role: role.into(),
})
@@ -730,7 +769,10 @@ impl ChannelStore {
let name = new_name.to_string();
cx.spawn(move |this, mut cx| async move {
let channel = client
- .request(proto::RenameChannel { channel_id, name })
+ .request(proto::RenameChannel {
+ channel_id: channel_id.0,
+ name,
+ })
.await?
.channel
.ok_or_else(|| anyhow!("missing channel in response"))?;
@@ -763,7 +805,10 @@ impl ChannelStore {
let client = self.client.clone();
cx.background_executor().spawn(async move {
client
- .request(proto::RespondToChannelInvite { channel_id, accept })
+ .request(proto::RespondToChannelInvite {
+ channel_id: channel_id.0,
+ accept,
+ })
.await?;
Ok(())
})
@@ -778,7 +823,9 @@ impl ChannelStore {
let user_store = self.user_store.downgrade();
cx.spawn(move |_, mut cx| async move {
let response = client
- .request(proto::GetChannelMembers { channel_id })
+ .request(proto::GetChannelMembers {
+ channel_id: channel_id.0,
+ })
.await?;
let user_ids = response.members.iter().map(|m| m.user_id).collect();
@@ -806,7 +853,11 @@ impl ChannelStore {
pub fn remove_channel(&self, channel_id: ChannelId) -> impl Future<Output = Result<()>> {
let client = self.client.clone();
async move {
- client.request(proto::DeleteChannel { channel_id }).await?;
+ client
+ .request(proto::DeleteChannel {
+ channel_id: channel_id.0,
+ })
+ .await?;
Ok(())
}
}
@@ -843,19 +894,23 @@ impl ChannelStore {
for buffer_version in message.payload.observed_channel_buffer_version {
let version = language::proto::deserialize_version(&buffer_version.version);
this.acknowledge_notes_version(
- buffer_version.channel_id,
+ ChannelId(buffer_version.channel_id),
buffer_version.epoch,
&version,
cx,
);
}
for message_id in message.payload.observed_channel_message_id {
- this.acknowledge_message_id(message_id.channel_id, message_id.message_id, cx);
+ this.acknowledge_message_id(
+ ChannelId(message_id.channel_id),
+ message_id.message_id,
+ cx,
+ );
}
for membership in message.payload.channel_memberships {
if let Some(role) = ChannelRole::from_i32(membership.role) {
this.channel_states
- .entry(membership.channel_id)
+ .entry(ChannelId(membership.channel_id))
.or_insert_with(|| ChannelState::default())
.set_role(role)
}
@@ -888,7 +943,7 @@ impl ChannelStore {
let channel_buffer = buffer.read(cx);
let buffer = channel_buffer.buffer().read(cx);
buffer_versions.push(proto::ChannelBufferVersion {
- channel_id: channel_buffer.channel_id,
+ channel_id: channel_buffer.channel_id.0,
epoch: channel_buffer.epoch(),
version: language::proto::serialize_version(&buffer.version()),
});
@@ -919,7 +974,7 @@ impl ChannelStore {
if let Some(remote_buffer) = response
.buffers
.iter_mut()
- .find(|buffer| buffer.channel_id == channel_id)
+ .find(|buffer| buffer.channel_id == channel_id.0)
{
let channel_id = channel_buffer.channel_id;
let remote_version =
@@ -955,7 +1010,7 @@ impl ChannelStore {
{
client
.send(proto::UpdateChannelBuffer {
- channel_id,
+ channel_id: channel_id.0,
operations: chunk,
})
.ok();
@@ -1010,12 +1065,12 @@ impl ChannelStore {
) -> Option<Task<Result<()>>> {
if !payload.remove_channel_invitations.is_empty() {
self.channel_invitations
- .retain(|channel| !payload.remove_channel_invitations.contains(&channel.id));
+ .retain(|channel| !payload.remove_channel_invitations.contains(&channel.id.0));
}
for channel in payload.channel_invitations {
match self
.channel_invitations
- .binary_search_by_key(&channel.id, |c| c.id)
+ .binary_search_by_key(&channel.id, |c| c.id.0)
{
Ok(ix) => {
Arc::make_mut(&mut self.channel_invitations[ix]).name = channel.name.into()
@@ -1023,10 +1078,14 @@ impl ChannelStore {
Err(ix) => self.channel_invitations.insert(
ix,
Arc::new(Channel {
- id: channel.id,
+ id: ChannelId(channel.id),
visibility: channel.visibility(),
name: channel.name.into(),
- parent_path: channel.parent_path,
+ parent_path: channel
+ .parent_path
+ .into_iter()
+ .map(|cid| ChannelId(cid))
+ .collect(),
}),
),
}
@@ -1035,20 +1094,27 @@ impl ChannelStore {
let channels_changed = !payload.channels.is_empty()
|| !payload.delete_channels.is_empty()
|| !payload.latest_channel_message_ids.is_empty()
- || !payload.latest_channel_buffer_versions.is_empty();
+ || !payload.latest_channel_buffer_versions.is_empty()
+ || !payload.hosted_projects.is_empty()
+ || !payload.deleted_hosted_projects.is_empty();
if channels_changed {
if !payload.delete_channels.is_empty() {
- self.channel_index.delete_channels(&payload.delete_channels);
+ let delete_channels: Vec<ChannelId> = payload
+ .delete_channels
+ .into_iter()
+ .map(|cid| ChannelId(cid))
+ .collect();
+ self.channel_index.delete_channels(&delete_channels);
self.channel_participants
- .retain(|channel_id, _| !&payload.delete_channels.contains(channel_id));
+ .retain(|channel_id, _| !delete_channels.contains(&channel_id));
- for channel_id in &payload.delete_channels {
+ for channel_id in &delete_channels {
let channel_id = *channel_id;
if payload
.channels
.iter()
- .any(|channel| channel.id == channel_id)
+ .any(|channel| channel.id == channel_id.0)
{
continue;
}
@@ -1064,7 +1130,7 @@ impl ChannelStore {
let mut index = self.channel_index.bulk_insert();
for channel in payload.channels {
- let id = channel.id;
+ let id = ChannelId(channel.id);
let channel_changed = index.insert(channel);
if channel_changed {
@@ -1079,17 +1145,45 @@ impl ChannelStore {
for latest_buffer_version in payload.latest_channel_buffer_versions {
let version = language::proto::deserialize_version(&latest_buffer_version.version);
self.channel_states
- .entry(latest_buffer_version.channel_id)
+ .entry(ChannelId(latest_buffer_version.channel_id))
.or_default()
.update_latest_notes_version(latest_buffer_version.epoch, &version)
}
for latest_channel_message in payload.latest_channel_message_ids {
self.channel_states
- .entry(latest_channel_message.channel_id)
+ .entry(ChannelId(latest_channel_message.channel_id))
.or_default()
.update_latest_message_id(latest_channel_message.message_id);
}
+
+ for hosted_project in payload.hosted_projects {
+ let hosted_project: HostedProject = hosted_project.into();
+ if let Some(old_project) = self
+ .hosted_projects
+ .insert(hosted_project.id, hosted_project.clone())
+ {
+ self.channel_states
+ .entry(old_project.channel_id)
+ .or_default()
+ .remove_hosted_project(old_project.id);
+ }
+ self.channel_states
+ .entry(hosted_project.channel_id)
+ .or_default()
+ .add_hosted_project(hosted_project.id);
+ }
+
+ for hosted_project_id in payload.deleted_hosted_projects {
+ let hosted_project_id = HostedProjectId(hosted_project_id);
+
+ if let Some(old_project) = self.hosted_projects.remove(&hosted_project_id) {
+ self.channel_states
+ .entry(old_project.channel_id)
+ .or_default()
+ .remove_hosted_project(old_project.id);
+ }
+ }
}
cx.notify();
@@ -1129,7 +1223,7 @@ impl ChannelStore {
participants.sort_by_key(|u| u.id);
this.channel_participants
- .insert(entry.channel_id, participants);
+ .insert(ChannelId(entry.channel_id), participants);
}
cx.notify();
@@ -1207,4 +1301,12 @@ impl ChannelState {
version: version.clone(),
});
}
+
+ fn add_hosted_project(&mut self, project_id: HostedProjectId) {
+ self.projects.insert(project_id);
+ }
+
+ fn remove_hosted_project(&mut self, project_id: HostedProjectId) {
+ self.projects.remove(&project_id);
+ }
}
@@ -1,4 +1,5 @@
-use crate::{Channel, ChannelId};
+use crate::Channel;
+use client::ChannelId;
use collections::BTreeMap;
use rpc::proto;
use std::sync::Arc;
@@ -50,27 +51,32 @@ pub struct ChannelPathsInsertGuard<'a> {
impl<'a> ChannelPathsInsertGuard<'a> {
pub fn insert(&mut self, channel_proto: proto::Channel) -> bool {
let mut ret = false;
- if let Some(existing_channel) = self.channels_by_id.get_mut(&channel_proto.id) {
+ let parent_path = channel_proto
+ .parent_path
+ .iter()
+ .map(|cid| ChannelId(*cid))
+ .collect();
+ if let Some(existing_channel) = self.channels_by_id.get_mut(&ChannelId(channel_proto.id)) {
let existing_channel = Arc::make_mut(existing_channel);
ret = existing_channel.visibility != channel_proto.visibility()
|| existing_channel.name != channel_proto.name
- || existing_channel.parent_path != channel_proto.parent_path;
+ || existing_channel.parent_path != parent_path;
existing_channel.visibility = channel_proto.visibility();
existing_channel.name = channel_proto.name.into();
- existing_channel.parent_path = channel_proto.parent_path.into();
+ existing_channel.parent_path = parent_path;
} else {
self.channels_by_id.insert(
- channel_proto.id,
+ ChannelId(channel_proto.id),
Arc::new(Channel {
- id: channel_proto.id,
+ id: ChannelId(channel_proto.id),
visibility: channel_proto.visibility(),
name: channel_proto.name.into(),
- parent_path: channel_proto.parent_path,
+ parent_path,
}),
);
- self.insert_root(channel_proto.id);
+ self.insert_root(ChannelId(channel_proto.id));
}
ret
}
@@ -94,7 +100,7 @@ impl<'a> Drop for ChannelPathsInsertGuard<'a> {
fn channel_path_sorting_key<'a>(
id: ChannelId,
channels_by_id: &'a BTreeMap<ChannelId, Arc<Channel>>,
-) -> impl Iterator<Item = (&str, u64)> {
+) -> impl Iterator<Item = (&str, ChannelId)> {
let (parent_path, name) = channels_by_id
.get(&id)
.map_or((&[] as &[_], None), |channel| {
@@ -1,6 +1,6 @@
mod event_coalescer;
-use crate::TelemetrySettings;
+use crate::{ChannelId, TelemetrySettings};
use chrono::{DateTime, Utc};
use clock::SystemClock;
use futures::Future;
@@ -278,12 +278,12 @@ impl Telemetry {
self: &Arc<Self>,
operation: &'static str,
room_id: Option<u64>,
- channel_id: Option<u64>,
+ channel_id: Option<ChannelId>,
) {
let event = Event::Call(CallEvent {
operation: operation.to_string(),
room_id,
- channel_id,
+ channel_id: channel_id.map(|cid| cid.0),
});
self.report_event(event)
@@ -15,6 +15,15 @@ use util::TryFutureExt as _;
pub type UserId = u64;
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
+pub struct ChannelId(pub u64);
+
+impl std::fmt::Display for ChannelId {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ParticipantIndex(pub u32);
@@ -375,3 +375,13 @@ CREATE TABLE extension_versions (
CREATE UNIQUE INDEX "index_extensions_external_id" ON "extensions" ("external_id");
CREATE INDEX "index_extensions_total_download_count" ON "extensions" ("total_download_count");
+
+CREATE TABLE hosted_projects (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ channel_id INTEGER NOT NULL REFERENCES channels(id),
+ name TEXT NOT NULL,
+ visibility TEXT NOT NULL,
+ deleted_at TIMESTAMP NULL
+);
+CREATE INDEX idx_hosted_projects_on_channel_id ON hosted_projects (channel_id);
+CREATE UNIQUE INDEX uix_hosted_projects_on_channel_id_and_name ON hosted_projects (channel_id, name) WHERE (deleted_at IS NULL);
@@ -0,0 +1,11 @@
+-- Add migration script here
+
+CREATE TABLE hosted_projects (
+ id INT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
+ channel_id INT NOT NULL REFERENCES channels(id),
+ name TEXT NOT NULL,
+ visibility TEXT NOT NULL,
+ deleted_at TIMESTAMP NULL
+);
+CREATE INDEX idx_hosted_projects_on_channel_id ON hosted_projects (channel_id);
+CREATE UNIQUE INDEX uix_hosted_projects_on_channel_id_and_name ON hosted_projects (channel_id, name) WHERE (deleted_at IS NULL);
@@ -587,6 +587,7 @@ pub struct ChannelsForUser {
pub channels: Vec<Channel>,
pub channel_memberships: Vec<channel_member::Model>,
pub channel_participants: HashMap<ChannelId, Vec<UserId>>,
+ pub hosted_projects: Vec<proto::HostedProject>,
pub observed_buffer_versions: Vec<proto::ChannelBufferVersion>,
pub observed_channel_messages: Vec<proto::ChannelMessageId>,
@@ -88,6 +88,7 @@ id_type!(FlagId);
id_type!(ExtensionId);
id_type!(NotificationId);
id_type!(NotificationKindId);
+id_type!(HostedProjectId);
/// ChannelRole gives you permissions for both channels and calls.
#[derive(Eq, PartialEq, Copy, Clone, Debug, EnumIter, DeriveActiveEnum, Default, Hash)]
@@ -6,6 +6,7 @@ pub mod channels;
pub mod contacts;
pub mod contributors;
pub mod extensions;
+pub mod hosted_projects;
pub mod messages;
pub mod notifications;
pub mod projects;
@@ -652,9 +652,14 @@ impl Database {
.observed_channel_messages(&channel_ids, user_id, &*tx)
.await?;
+ let hosted_projects = self
+ .get_hosted_projects(&channel_ids, &roles_by_channel_id, &*tx)
+ .await?;
+
Ok(ChannelsForUser {
channel_memberships,
channels,
+ hosted_projects,
channel_participants,
latest_buffer_versions,
latest_channel_messages,
@@ -0,0 +1,42 @@
+use rpc::proto;
+
+use super::*;
+
+impl Database {
+ pub async fn get_hosted_projects(
+ &self,
+ channel_ids: &Vec<ChannelId>,
+ roles: &HashMap<ChannelId, ChannelRole>,
+ tx: &DatabaseTransaction,
+ ) -> Result<Vec<proto::HostedProject>> {
+ Ok(hosted_project::Entity::find()
+ .filter(hosted_project::Column::ChannelId.is_in(channel_ids.iter().map(|id| id.0)))
+ .all(&*tx)
+ .await?
+ .into_iter()
+ .flat_map(|project| {
+ if project.deleted_at.is_some() {
+ return None;
+ }
+ match project.visibility {
+ ChannelVisibility::Public => {}
+ ChannelVisibility::Members => {
+ let is_visible = roles
+ .get(&project.channel_id)
+ .map(|role| role.can_see_all_descendants())
+ .unwrap_or(false);
+ if !is_visible {
+ return None;
+ }
+ }
+ };
+ Some(proto::HostedProject {
+ id: project.id.to_proto(),
+ channel_id: project.channel_id.to_proto(),
+ name: project.name.clone(),
+ visibility: project.visibility.into(),
+ })
+ })
+ .collect())
+ }
+}
@@ -14,6 +14,7 @@ pub mod extension;
pub mod extension_version;
pub mod feature_flag;
pub mod follower;
+pub mod hosted_project;
pub mod language_server;
pub mod notification;
pub mod notification_kind;
@@ -0,0 +1,18 @@
+use crate::db::{ChannelId, ChannelVisibility, HostedProjectId};
+use sea_orm::entity::prelude::*;
+
+#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
+#[sea_orm(table_name = "hosted_projects")]
+pub struct Model {
+ #[sea_orm(primary_key)]
+ pub id: HostedProjectId,
+ pub channel_id: ChannelId,
+ pub name: String,
+ pub visibility: ChannelVisibility,
+ pub deleted_at: Option<DateTime>,
+}
+
+impl ActiveModelBehavior for ActiveModel {}
+
+#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
+pub enum Relation {}
@@ -3396,6 +3396,9 @@ fn build_channels_update(
for channel in channel_invites {
update.channel_invitations.push(channel.to_proto());
}
+ for project in channels.hosted_projects {
+ update.hosted_projects.push(project);
+ }
update
}
@@ -1,4 +1,5 @@
use call::Room;
+use client::ChannelId;
use gpui::{Model, TestAppContext};
mod channel_buffer_tests;
@@ -43,6 +44,6 @@ fn room_participants(room: &Model<Room>, cx: &mut TestAppContext) -> RoomPartici
})
}
-fn channel_id(room: &Model<Room>, cx: &mut TestAppContext) -> Option<u64> {
+fn channel_id(room: &Model<Room>, cx: &mut TestAppContext) -> Option<ChannelId> {
cx.read(|cx| room.read(cx).channel_id())
}
@@ -183,7 +183,7 @@ async fn test_channel_requires_zed_cla(cx_a: &mut TestAppContext, cx_b: &mut Tes
server
.app_state
.db
- .set_channel_requires_zed_cla(ChannelId::from_proto(parent_channel_id), true)
+ .set_channel_requires_zed_cla(ChannelId::from_proto(parent_channel_id.0), true)
.await
.unwrap();
@@ -100,13 +100,13 @@ async fn test_basic_channel_messages(
Notification::ChannelMessageMention {
message_id,
sender_id: client_a.id(),
- channel_id,
+ channel_id: channel_id.0,
}
);
assert_eq!(
store.notification_at(1).unwrap().notification,
Notification::ChannelInvitation {
- channel_id,
+ channel_id: channel_id.0,
channel_name: "the-channel".to_string(),
inviter_id: client_a.id()
}
@@ -4,8 +4,8 @@ use crate::{
tests::{room_participants, RoomParticipants, TestServer},
};
use call::ActiveCall;
-use channel::{ChannelId, ChannelMembership, ChannelStore};
-use client::User;
+use channel::{ChannelMembership, ChannelStore};
+use client::{ChannelId, User};
use futures::future::try_join_all;
use gpui::{BackgroundExecutor, Model, SharedString, TestAppContext};
use rpc::{
@@ -281,7 +281,7 @@ async fn test_core_channels(
.app_state
.db
.rename_channel(
- db::ChannelId::from_proto(channel_a_id),
+ db::ChannelId::from_proto(channel_a_id.0),
UserId::from_proto(client_a.id()),
"channel-a-renamed",
)
@@ -1444,7 +1444,7 @@ fn assert_channels(
fn assert_channels_list_shape(
channel_store: &Model<ChannelStore>,
cx: &TestAppContext,
- expected_channels: &[(u64, usize)],
+ expected_channels: &[(ChannelId, usize)],
) {
let actual = cx.read(|cx| {
channel_store.read_with(cx, |store, _| {
@@ -1,5 +1,6 @@
use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
use call::{ActiveCall, ParticipantLocation};
+use client::ChannelId;
use collab_ui::{
channel_view::ChannelView,
notifications::project_shared_notification::ProjectSharedNotification,
@@ -2000,7 +2001,7 @@ async fn test_following_to_channel_notes_without_a_shared_project(
}
async fn join_channel(
- channel_id: u64,
+ channel_id: ChannelId,
client: &TestClient,
cx: &mut TestAppContext,
) -> anyhow::Result<()> {
@@ -137,7 +137,7 @@ async fn test_notifications(
assert_eq!(
entry.notification,
Notification::ChannelInvitation {
- channel_id,
+ channel_id: channel_id.0,
channel_name: "the-channel".to_string(),
inviter_id: client_a.id()
}
@@ -253,7 +253,7 @@ impl RandomizedTest for RandomChannelBufferTest {
.channel_buffers()
.deref()
.iter()
- .find(|b| b.read(cx).channel_id == channel_id.to_proto())
+ .find(|b| b.read(cx).channel_id.0 == channel_id.to_proto())
{
let channel_buffer = channel_buffer.read(cx);
@@ -8,7 +8,8 @@ use anyhow::anyhow;
use call::ActiveCall;
use channel::{ChannelBuffer, ChannelStore};
use client::{
- self, proto::PeerId, Client, Connection, Credentials, EstablishConnectionError, UserStore,
+ self, proto::PeerId, ChannelId, Client, Connection, Credentials, EstablishConnectionError,
+ UserStore,
};
use clock::FakeSystemClock;
use collab_ui::channel_view::ChannelView;
@@ -120,7 +121,7 @@ impl TestServer {
pub async fn start2(
cx_a: &mut TestAppContext,
cx_b: &mut TestAppContext,
- ) -> (TestServer, TestClient, TestClient, u64) {
+ ) -> (TestServer, TestClient, TestClient, ChannelId) {
let mut server = Self::start(cx_a.executor()).await;
let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await;
@@ -353,10 +354,10 @@ impl TestServer {
pub async fn make_channel(
&self,
channel: &str,
- parent: Option<u64>,
+ parent: Option<ChannelId>,
admin: (&TestClient, &mut TestAppContext),
members: &mut [(&TestClient, &mut TestAppContext)],
- ) -> u64 {
+ ) -> ChannelId {
let (_, admin_cx) = admin;
let channel_id = admin_cx
.read(ChannelStore::global)
@@ -399,7 +400,7 @@ impl TestServer {
channel: &str,
client: &TestClient,
cx: &mut TestAppContext,
- ) -> u64 {
+ ) -> ChannelId {
let channel_id = self
.make_channel(channel, None, (client, cx), &mut [])
.await;
@@ -423,7 +424,7 @@ impl TestServer {
&self,
channels: &[(&str, Option<&str>)],
creator: (&TestClient, &mut TestAppContext),
- ) -> Vec<u64> {
+ ) -> Vec<ChannelId> {
let mut observed_channels = HashMap::default();
let mut result = Vec::new();
for (channel, parent) in channels {
@@ -677,7 +678,7 @@ impl TestClient {
pub async fn host_workspace(
&self,
workspace: &View<Workspace>,
- channel_id: u64,
+ channel_id: ChannelId,
cx: &mut VisualTestContext,
) {
cx.update(|cx| {
@@ -698,7 +699,7 @@ impl TestClient {
pub async fn join_workspace<'a>(
&'a self,
- channel_id: u64,
+ channel_id: ChannelId,
cx: &'a mut TestAppContext,
) -> (View<Workspace>, &'a mut VisualTestContext) {
cx.update(|cx| workspace::join_channel(channel_id, self.app_state.clone(), None, cx))
@@ -777,7 +778,7 @@ impl TestClient {
}
pub fn open_channel_notes(
- channel_id: u64,
+ channel_id: ChannelId,
cx: &mut VisualTestContext,
) -> Task<anyhow::Result<View<ChannelView>>> {
let window = cx.update(|cx| cx.active_window().unwrap().downcast::<Workspace>().unwrap());
@@ -1,9 +1,9 @@
use anyhow::Result;
use call::report_call_event_for_channel;
-use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelId, ChannelStore};
+use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelStore};
use client::{
proto::{self, PeerId},
- Collaborator, ParticipantIndex,
+ ChannelId, Collaborator, ParticipantIndex,
};
use collections::HashMap;
use editor::{
@@ -454,7 +454,7 @@ impl FollowableItem for ChannelView {
Some(proto::view::Variant::ChannelView(
proto::view::ChannelView {
- channel_id: channel_buffer.channel_id,
+ channel_id: channel_buffer.channel_id.0,
editor: if let Some(proto::view::Variant::Editor(proto)) =
self.editor.read(cx).to_state_proto(cx)
{
@@ -480,7 +480,8 @@ impl FollowableItem for ChannelView {
unreachable!()
};
- let open = ChannelView::open_in_pane(state.channel_id, None, pane, workspace, cx);
+ let open =
+ ChannelView::open_in_pane(ChannelId(state.channel_id), None, pane, workspace, cx);
Some(cx.spawn(|mut cx| async move {
let this = open.await?;
@@ -2,7 +2,7 @@ use crate::{collab_panel, ChatPanelSettings};
use anyhow::Result;
use call::{room, ActiveCall};
use channel::{ChannelChat, ChannelChatEvent, ChannelMessage, ChannelMessageId, ChannelStore};
-use client::Client;
+use client::{ChannelId, Client};
use collections::HashMap;
use db::kvp::KEY_VALUE_STORE;
use editor::Editor;
@@ -169,7 +169,7 @@ impl ChatPanel {
})
}
- pub fn channel_id(&self, cx: &AppContext) -> Option<u64> {
+ pub fn channel_id(&self, cx: &AppContext) -> Option<ChannelId> {
self.active_chat
.as_ref()
.map(|(chat, _)| chat.read(cx).channel_id)
@@ -710,7 +710,7 @@ impl ChatPanel {
pub fn select_channel(
&mut self,
- selected_channel_id: u64,
+ selected_channel_id: ChannelId,
scroll_to_message_id: Option<u64>,
cx: &mut ViewContext<ChatPanel>,
) -> Task<Result<()>> {
@@ -1,6 +1,6 @@
use anyhow::Result;
-use channel::{ChannelId, ChannelMembership, ChannelStore, MessageParams};
-use client::UserId;
+use channel::{ChannelMembership, ChannelStore, MessageParams};
+use client::{ChannelId, UserId};
use collections::{HashMap, HashSet};
use editor::{AnchorRangeExt, CompletionProvider, Editor, EditorElement, EditorStyle};
use fuzzy::StringMatchCandidate;
@@ -131,7 +131,7 @@ impl MessageEditor {
pub fn set_channel(
&mut self,
- channel_id: u64,
+ channel_id: ChannelId,
channel_name: Option<SharedString>,
cx: &mut ViewContext<Self>,
) {
@@ -7,8 +7,8 @@ use crate::{
CollaborationPanelSettings,
};
use call::ActiveCall;
-use channel::{Channel, ChannelEvent, ChannelId, ChannelStore};
-use client::{Client, Contact, User, UserStore};
+use channel::{Channel, ChannelEvent, ChannelStore, HostedProjectId};
+use client::{ChannelId, Client, Contact, User, UserStore};
use contact_finder::ContactFinder;
use db::kvp::KEY_VALUE_STORE;
use editor::{Editor, EditorElement, EditorStyle};
@@ -184,6 +184,10 @@ enum ListEntry {
ChannelEditor {
depth: usize,
},
+ HostedProject {
+ id: HostedProjectId,
+ name: SharedString,
+ },
Contact {
contact: Arc<Contact>,
calling: bool,
@@ -326,7 +330,10 @@ impl CollabPanel {
panel.width = serialized_panel.width;
panel.collapsed_channels = serialized_panel
.collapsed_channels
- .unwrap_or_else(|| Vec::new());
+ .unwrap_or_else(|| Vec::new())
+ .iter()
+ .map(|cid| ChannelId(*cid))
+ .collect();
cx.notify();
});
}
@@ -344,7 +351,9 @@ impl CollabPanel {
COLLABORATION_PANEL_KEY.into(),
serde_json::to_string(&SerializedCollabPanel {
width,
- collapsed_channels: Some(collapsed_channels),
+ collapsed_channels: Some(
+ collapsed_channels.iter().map(|cid| cid.0).collect(),
+ ),
})?,
)
.await?;
@@ -563,6 +572,7 @@ impl CollabPanel {
}
}
+ let hosted_projects = channel_store.projects_for_id(channel.id);
let has_children = channel_store
.channel_at_index(mat.candidate_id + 1)
.map_or(false, |next_channel| {
@@ -596,6 +606,10 @@ impl CollabPanel {
});
}
}
+
+ for (name, id) in hosted_projects {
+ self.entries.push(ListEntry::HostedProject { id, name })
+ }
}
}
@@ -1023,6 +1037,33 @@ impl CollabPanel {
.tooltip(move |cx| Tooltip::text("Open Chat", cx))
}
+ fn render_channel_project(
+ &self,
+ id: HostedProjectId,
+ name: &SharedString,
+ is_selected: bool,
+ cx: &mut ViewContext<Self>,
+ ) -> impl IntoElement {
+ ListItem::new(ElementId::NamedInteger(
+ "channel-project".into(),
+ id.0 as usize,
+ ))
+ .indent_level(2)
+ .indent_step_size(px(20.))
+ .selected(is_selected)
+ .on_click(cx.listener(move |_this, _, _cx| {
+ // todo!()
+ }))
+ .start_slot(
+ h_flex()
+ .relative()
+ .gap_1()
+ .child(IconButton::new(0, IconName::FileTree)),
+ )
+ .child(Label::new(name.clone()))
+ .tooltip(move |cx| Tooltip::text("Open Project", cx))
+ }
+
fn has_subchannels(&self, ix: usize) -> bool {
self.entries.get(ix).map_or(false, |entry| {
if let ListEntry::Channel { has_children, .. } = entry {
@@ -1486,6 +1527,12 @@ impl CollabPanel {
ListEntry::ChannelChat { channel_id } => {
self.join_channel_chat(*channel_id, cx)
}
+ ListEntry::HostedProject {
+ id: _id,
+ name: _name,
+ } => {
+ // todo!()
+ }
ListEntry::OutgoingRequest(_) => {}
ListEntry::ChannelEditor { .. } => {}
@@ -1923,7 +1970,7 @@ impl CollabPanel {
fn respond_to_channel_invite(
&mut self,
- channel_id: u64,
+ channel_id: ChannelId,
accept: bool,
cx: &mut ViewContext<Self>,
) {
@@ -1942,7 +1989,7 @@ impl CollabPanel {
.detach_and_prompt_err("Call failed", cx, |_, _| None);
}
- fn join_channel(&self, channel_id: u64, cx: &mut ViewContext<Self>) {
+ fn join_channel(&self, channel_id: ChannelId, cx: &mut ViewContext<Self>) {
let Some(workspace) = self.workspace.upgrade() else {
return;
};
@@ -2089,6 +2136,10 @@ impl CollabPanel {
ListEntry::ChannelChat { channel_id } => self
.render_channel_chat(*channel_id, is_selected, cx)
.into_any_element(),
+
+ ListEntry::HostedProject { id, name } => self
+ .render_channel_project(*id, name, is_selected, cx)
+ .into_any_element(),
}
}
@@ -2405,7 +2456,7 @@ impl CollabPanel {
.tooltip(|cx| Tooltip::text("Accept invite", cx)),
];
- ListItem::new(("channel-invite", channel.id as usize))
+ ListItem::new(("channel-invite", channel.id.0 as usize))
.selected(is_selected)
.child(
h_flex()
@@ -2497,7 +2548,7 @@ impl CollabPanel {
div()
.h_6()
- .id(channel_id as usize)
+ .id(channel_id.0 as usize)
.group("")
.flex()
.w_full()
@@ -2525,7 +2576,7 @@ impl CollabPanel {
this.move_channel(dragged_channel.id, channel_id, cx);
}))
.child(
- ListItem::new(channel_id as usize)
+ ListItem::new(channel_id.0 as usize)
// Add one level of depth for the disclosure arrow.
.indent_level(depth + 1)
.indent_step_size(px(20.))
@@ -2572,7 +2623,7 @@ impl CollabPanel {
)
.child(
h_flex()
- .id(channel_id as usize)
+ .id(channel_id.0 as usize)
.child(Label::new(channel.name.clone()))
.children(face_pile.map(|face_pile| face_pile.p_1())),
),
@@ -2826,6 +2877,11 @@ impl PartialEq for ListEntry {
return channel_1.id == channel_2.id;
}
}
+ ListEntry::HostedProject { id, .. } => {
+ if let ListEntry::HostedProject { id: other_id, .. } = other {
+ return id == other_id;
+ }
+ }
ListEntry::ChannelNotes { channel_id } => {
if let ListEntry::ChannelNotes {
channel_id: other_id,
@@ -1,7 +1,7 @@
-use channel::{ChannelId, ChannelMembership, ChannelStore};
+use channel::{ChannelMembership, ChannelStore};
use client::{
proto::{self, ChannelRole, ChannelVisibility},
- User, UserId, UserStore,
+ ChannelId, User, UserId, UserStore,
};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
@@ -1,7 +1,7 @@
use crate::{chat_panel::ChatPanel, NotificationPanelSettings};
use anyhow::Result;
use channel::ChannelStore;
-use client::{Client, Notification, User, UserStore};
+use client::{ChannelId, Client, Notification, User, UserStore};
use collections::HashMap;
use db::kvp::KEY_VALUE_STORE;
use futures::StreamExt;
@@ -357,7 +357,7 @@ impl NotificationPanel {
"{} invited you to join the #{channel_name} channel",
inviter.github_login
),
- needs_response: channel_store.has_channel_invitation(channel_id),
+ needs_response: channel_store.has_channel_invitation(ChannelId(channel_id)),
actor: Some(inviter),
can_navigate: false,
})
@@ -368,7 +368,7 @@ impl NotificationPanel {
message_id,
} => {
let sender = user_store.get_cached_user(sender_id)?;
- let channel = channel_store.channel_for_id(channel_id)?;
+ let channel = channel_store.channel_for_id(ChannelId(channel_id))?;
let message = self
.notification_store
.read(cx)
@@ -432,7 +432,7 @@ impl NotificationPanel {
if let Some(panel) = workspace.focus_panel::<ChatPanel>(cx) {
panel.update(cx, |panel, cx| {
panel
- .select_channel(channel_id, Some(message_id), cx)
+ .select_channel(ChannelId(channel_id), Some(message_id), cx)
.detach_and_log_err(cx);
});
}
@@ -454,7 +454,7 @@ impl NotificationPanel {
panel.is_scrolled_to_bottom()
&& panel
.active_chat()
- .map_or(false, |chat| chat.read(cx).channel_id == *channel_id)
+ .map_or(false, |chat| chat.read(cx).channel_id.0 == *channel_id)
} else {
false
};
@@ -1,6 +1,6 @@
use anyhow::{Context, Result};
use channel::{ChannelMessage, ChannelMessageId, ChannelStore};
-use client::{Client, UserStore};
+use client::{ChannelId, Client, UserStore};
use collections::HashMap;
use db::smol::stream::StreamExt;
use gpui::{
@@ -413,7 +413,7 @@ impl NotificationStore {
Notification::ChannelInvitation { channel_id, .. } => {
self.channel_store
.update(cx, |store, cx| {
- store.respond_to_channel_invite(channel_id, response, cx)
+ store.respond_to_channel_invite(ChannelId(channel_id), response, cx)
})
.detach();
}
@@ -12,7 +12,7 @@ message Envelope {
uint32 id = 1;
optional uint32 responding_to = 2;
optional PeerId original_sender_id = 3;
-
+
/*
When you are adding a new message type, instead of adding it in semantic order
and bumping the message ID's of everything that follows, add it at the end of the
@@ -56,7 +56,7 @@ message Envelope {
GetDefinitionResponse get_definition_response = 33;
GetTypeDefinition get_type_definition = 34;
GetTypeDefinitionResponse get_type_definition_response = 35;
-
+
GetReferences get_references = 36;
GetReferencesResponse get_references_response = 37;
GetDocumentHighlights get_document_highlights = 38;
@@ -192,7 +192,7 @@ message Envelope {
LspExtExpandMacroResponse lsp_ext_expand_macro_response = 155;
SetRoomParticipantRole set_room_participant_role = 156;
- UpdateUserChannels update_user_channels = 157;
+ UpdateUserChannels update_user_channels = 157;
GetImplementation get_implementation = 162;
GetImplementationResponse get_implementation_response = 163;
@@ -1026,6 +1026,9 @@ message UpdateChannels {
repeated ChannelParticipants channel_participants = 7;
repeated ChannelMessageId latest_channel_message_ids = 8;
repeated ChannelBufferVersion latest_channel_buffer_versions = 9;
+
+ repeated HostedProject hosted_projects = 10;
+ repeated uint64 deleted_hosted_projects = 11;
}
message UpdateUserChannels {
@@ -1054,6 +1057,13 @@ message ChannelParticipants {
repeated uint64 participant_user_ids = 2;
}
+message HostedProject {
+ uint64 id = 1;
+ uint64 channel_id = 2;
+ string name = 3;
+ ChannelVisibility visibility = 4;
+}
+
message JoinChannel {
uint64 channel_id = 1;
}
@@ -15,7 +15,7 @@ use anyhow::{anyhow, Context as _, Result};
use call::{call_settings::CallSettings, ActiveCall};
use client::{
proto::{self, ErrorCode, PeerId},
- Client, ErrorExt, Status, TypedEnvelope, UserStore,
+ ChannelId, Client, ErrorExt, Status, TypedEnvelope, UserStore,
};
use collections::{hash_map, HashMap, HashSet};
use derive_more::{Deref, DerefMut};
@@ -4117,7 +4117,7 @@ pub async fn last_opened_workspace_paths() -> Option<WorkspaceLocation> {
actions!(collab, [OpenChannelNotes]);
async fn join_channel_internal(
- channel_id: u64,
+ channel_id: ChannelId,
app_state: &Arc<AppState>,
requesting_window: Option<WindowHandle<Workspace>>,
active_call: &Model<ActiveCall>,
@@ -4257,7 +4257,7 @@ async fn join_channel_internal(
}
pub fn join_channel(
- channel_id: u64,
+ channel_id: ChannelId,
app_state: Arc<AppState>,
requesting_window: Option<WindowHandle<Workspace>>,
cx: &mut AppContext,
@@ -323,8 +323,10 @@ fn main() {
cx.spawn(|cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
- cx.update(|cx| workspace::join_channel(channel_id, app_state, None, cx))?
- .await?;
+ cx.update(|cx| {
+ workspace::join_channel(client::ChannelId(channel_id), app_state, None, cx)
+ })?
+ .await?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
@@ -343,7 +345,7 @@ fn main() {
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
cx.update_window(workspace_window.into(), |_, cx| {
- ChannelView::open(channel_id, heading, workspace, cx)
+ ChannelView::open(client::ChannelId(channel_id), heading, workspace, cx)
})?
.await?;
anyhow::Ok(())
@@ -378,7 +380,12 @@ fn main() {
cx.update(|mut cx| {
cx.spawn(|cx| async move {
cx.update(|cx| {
- workspace::join_channel(channel_id, app_state, None, cx)
+ workspace::join_channel(
+ client::ChannelId(channel_id),
+ app_state,
+ None,
+ cx,
+ )
})?
.await?;
anyhow::Ok(())
@@ -397,7 +404,12 @@ fn main() {
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
cx.update_window(workspace_window.into(), |_, cx| {
- ChannelView::open(channel_id, heading, workspace, cx)
+ ChannelView::open(
+ client::ChannelId(channel_id),
+ heading,
+ workspace,
+ cx,
+ )
})?
.await?;
anyhow::Ok(())