Detailed changes
@@ -19,17 +19,15 @@ fn test_update_channels(cx: &mut AppContext) {
id: 1,
name: "b".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Admin.into(),
},
proto::Channel {
id: 2,
name: "a".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Member.into(),
},
],
- channel_permissions: vec![proto::ChannelPermission {
- channel_id: 1,
- role: proto::ChannelRole::Admin.into(),
- }],
..Default::default()
},
cx,
@@ -52,11 +50,13 @@ fn test_update_channels(cx: &mut AppContext) {
id: 3,
name: "x".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Member.into(),
},
proto::Channel {
id: 4,
name: "y".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Member.into(),
},
],
insert_edge: vec![
@@ -97,16 +97,19 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
id: 0,
name: "a".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Admin.into(),
},
proto::Channel {
id: 1,
name: "b".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Admin.into(),
},
proto::Channel {
id: 2,
name: "c".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Admin.into(),
},
],
insert_edge: vec![
@@ -119,10 +122,6 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
channel_id: 2,
},
],
- channel_permissions: vec![proto::ChannelPermission {
- channel_id: 0,
- role: proto::ChannelRole::Admin.into(),
- }],
..Default::default()
},
cx,
@@ -166,6 +165,7 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
id: channel_id,
name: "the-channel".to_string(),
visibility: proto::ChannelVisibility::Members as i32,
+ role: proto::ChannelRole::Admin.into(),
}],
..Default::default()
});
@@ -419,7 +419,7 @@ impl Database {
}
let channels = channel::Entity::find()
- .filter(channel::Column::Id.is_in(role_for_channel.keys().cloned()))
+ .filter(channel::Column::Id.is_in(role_for_channel.keys().copied()))
.all(&*tx)
.await?;
@@ -633,6 +633,36 @@ impl Database {
.await
}
+ pub async fn get_channel_members_and_roles(
+ &self,
+ id: ChannelId,
+ ) -> Result<Vec<(UserId, ChannelRole)>> {
+ self.transaction(|tx| async move {
+ #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
+ enum QueryUserIdsAndRoles {
+ UserId,
+ Role,
+ }
+
+ let ancestor_ids = self.get_channel_ancestors(id, &*tx).await?;
+ let user_ids_and_roles = channel_member::Entity::find()
+ .distinct()
+ .filter(
+ channel_member::Column::ChannelId
+ .is_in(ancestor_ids.iter().copied())
+ .and(channel_member::Column::Accepted.eq(true)),
+ )
+ .select_only()
+ .column(channel_member::Column::UserId)
+ .column(channel_member::Column::Role)
+ .into_values::<_, QueryUserIdsAndRoles>()
+ .all(&*tx)
+ .await?;
+ Ok(user_ids_and_roles)
+ })
+ .await
+ }
+
pub async fn set_channel_member_role(
&self,
channel_id: ChannelId,
@@ -1138,9 +1168,6 @@ impl Database {
to: ChannelId,
) -> Result<ChannelGraph> {
self.transaction(|tx| async move {
- // Note that even with these maxed permissions, this linking operation
- // is still insecure because you can't remove someone's permissions to a
- // channel if they've linked the channel to one where they're an admin.
self.check_user_is_channel_admin(channel, user, &*tx)
.await?;
@@ -1327,6 +1354,23 @@ impl Database {
})
.await
}
+
+ pub async fn assert_root_channel(&self, channel: ChannelId) -> Result<()> {
+ self.transaction(|tx| async move {
+ let path = channel_path::Entity::find()
+ .filter(channel_path::Column::ChannelId.eq(channel))
+ .one(&*tx)
+ .await?
+ .ok_or_else(|| anyhow!("no such channel found"))?;
+
+ let mut id_parts = path.id_path.trim_matches('/').split('/');
+
+ (id_parts.next().is_some() && id_parts.next().is_none())
+ .then_some(())
+ .ok_or_else(|| anyhow!("channel is not a root channel").into())
+ })
+ .await
+ }
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
@@ -3,8 +3,8 @@ mod connection_pool;
use crate::{
auth,
db::{
- self, BufferId, ChannelId, ChannelsForUser, Database, MessageId, ProjectId, RoomId,
- ServerId, User, UserId,
+ self, BufferId, ChannelId, ChannelRole, ChannelVisibility, ChannelsForUser, Database,
+ MessageId, ProjectId, RoomId, ServerId, User, UserId,
},
executor::Executor,
AppState, Result,
@@ -38,8 +38,8 @@ use lazy_static::lazy_static;
use prometheus::{register_int_gauge, IntGauge};
use rpc::{
proto::{
- self, Ack, AnyTypedEnvelope, ChannelEdge, EntityMessage, EnvelopedMessage,
- LiveKitConnectionInfo, RequestMessage, UpdateChannelBufferCollaborators,
+ self, Ack, AnyTypedEnvelope, EntityMessage, EnvelopedMessage, LiveKitConnectionInfo,
+ RequestMessage, UpdateChannelBufferCollaborators,
},
Connection, ConnectionId, Peer, Receipt, TypedEnvelope,
};
@@ -2366,15 +2366,18 @@ async fn set_channel_visibility(
for member in members {
for connection_id in connection_pool.user_connection_ids(UserId::from_proto(member.user_id))
{
- let mut update = proto::UpdateChannels::default();
- update.channels.push(proto::Channel {
- id: channel.id.to_proto(),
- name: channel.name.clone(),
- visibility: channel.visibility.into(),
- role: member.role.into(),
- });
-
- session.peer.send(connection_id, update.clone())?;
+ session.peer.send(
+ connection_id,
+ proto::UpdateChannels {
+ channels: vec![proto::Channel {
+ id: channel.id.to_proto(),
+ name: channel.name.clone(),
+ visibility: channel.visibility.into(),
+ role: member.role.into(),
+ }],
+ ..Default::default()
+ },
+ )?;
}
}
@@ -2468,6 +2471,8 @@ async fn rename_channel(
Ok(())
}
+// TODO: Implement in terms of symlinks
+// Current behavior of this is more like 'Move root channel'
async fn link_channel(
request: proto::LinkChannel,
response: Response<proto::LinkChannel>,
@@ -2476,30 +2481,46 @@ async fn link_channel(
let db = session.db().await;
let channel_id = ChannelId::from_proto(request.channel_id);
let to = ChannelId::from_proto(request.to);
- let channels_to_send = db.link_channel(session.user_id, channel_id, to).await?;
- let members = db.get_channel_members(to).await?;
+ // TODO: Remove this restriction once we have symlinks
+ db.assert_root_channel(channel_id).await?;
+
+ let channels_to_send = db.link_channel(session.user_id, channel_id, to).await?;
+ let members = db.get_channel_members_and_roles(to).await?;
let connection_pool = session.connection_pool().await;
- let update = proto::UpdateChannels {
- channels: channels_to_send
- .channels
- .into_iter()
- .map(|channel| proto::Channel {
- id: channel.id.to_proto(),
- visibility: channel.visibility.into(),
- name: channel.name,
- // TODO: not all these members should be able to see all those channels
- // the channels in channels_to_send are from the admin point of view,
- // but any public guests should only get updates about public channels.
- role: todo!(),
- })
- .collect(),
- insert_edge: channels_to_send.edges,
- ..Default::default()
- };
- for member_id in members {
+
+ for (member_id, role) in members {
+ let build_channel_proto = |channel: &db::Channel| proto::Channel {
+ id: channel.id.to_proto(),
+ visibility: channel.visibility.into(),
+ name: channel.name.clone(),
+ role: role.into(),
+ };
+
for connection_id in connection_pool.user_connection_ids(member_id) {
- session.peer.send(connection_id, update.clone())?;
+ let channels: Vec<_> = if role == ChannelRole::Guest {
+ channels_to_send
+ .channels
+ .iter()
+ .filter(|channel| channel.visibility != ChannelVisibility::Public)
+ .map(build_channel_proto)
+ .collect()
+ } else {
+ channels_to_send
+ .channels
+ .iter()
+ .map(build_channel_proto)
+ .collect()
+ };
+
+ session.peer.send(
+ connection_id,
+ proto::UpdateChannels {
+ channels,
+ insert_edge: channels_to_send.edges.clone(),
+ ..Default::default()
+ },
+ )?;
}
}
@@ -2508,36 +2529,13 @@ async fn link_channel(
Ok(())
}
+// TODO: Implement in terms of symlinks
async fn unlink_channel(
- request: proto::UnlinkChannel,
- response: Response<proto::UnlinkChannel>,
- session: Session,
+ _request: proto::UnlinkChannel,
+ _response: Response<proto::UnlinkChannel>,
+ _session: Session,
) -> Result<()> {
- let db = session.db().await;
- let channel_id = ChannelId::from_proto(request.channel_id);
- let from = ChannelId::from_proto(request.from);
-
- db.unlink_channel(session.user_id, channel_id, from).await?;
-
- let members = db.get_channel_members(from).await?;
-
- let update = proto::UpdateChannels {
- delete_edge: vec![proto::ChannelEdge {
- channel_id: channel_id.to_proto(),
- parent_id: from.to_proto(),
- }],
- ..Default::default()
- };
- let connection_pool = session.connection_pool().await;
- for member_id in members {
- for connection_id in connection_pool.user_connection_ids(member_id) {
- session.peer.send(connection_id, update.clone())?;
- }
- }
-
- response.send(Ack {})?;
-
- Ok(())
+ Err(anyhow!("unimplemented").into())
}
async fn move_channel(
@@ -2554,7 +2552,7 @@ async fn move_channel(
.public_path_to_channel(from_parent)
.await?
.last()
- .cloned();
+ .copied();
let channels_to_send = db
.move_channel(session.user_id, channel_id, from_parent, to)
@@ -2574,6 +2572,7 @@ async fn move_channel(
.filter(|member| {
member.role() == proto::ChannelRole::Admin || member.role() == proto::ChannelRole::Guest
});
+
let members_to = db
.get_channel_participant_details(to, session.user_id)
.await?
@@ -1031,14 +1031,14 @@ async fn test_invite_access(
async fn test_channel_moving(
deterministic: Arc<Deterministic>,
cx_a: &mut TestAppContext,
- cx_b: &mut TestAppContext,
- cx_c: &mut TestAppContext,
+ _cx_b: &mut TestAppContext,
+ _cx_c: &mut TestAppContext,
) {
deterministic.forbid_parking();
let mut server = TestServer::start(&deterministic).await;
let client_a = server.create_client(cx_a, "user_a").await;
- let client_b = server.create_client(cx_b, "user_b").await;
- let client_c = server.create_client(cx_c, "user_c").await;
+ // let client_b = server.create_client(cx_b, "user_b").await;
+ // let client_c = server.create_client(cx_c, "user_c").await;
let channels = server
.make_channel_tree(
@@ -1091,187 +1091,188 @@ async fn test_channel_moving(
],
);
- client_a
- .channel_store()
- .update(cx_a, |channel_store, cx| {
- channel_store.link_channel(channel_d_id, channel_c_id, cx)
- })
- .await
- .unwrap();
-
- // Current shape for A:
- // /------\
- // a - b -- c -- d
- assert_channels_list_shape(
- client_a.channel_store(),
- cx_a,
- &[
- (channel_a_id, 0),
- (channel_b_id, 1),
- (channel_c_id, 2),
- (channel_d_id, 3),
- (channel_d_id, 2),
- ],
- );
-
- let b_channels = server
- .make_channel_tree(
- &[
- ("channel-mu", None),
- ("channel-gamma", Some("channel-mu")),
- ("channel-epsilon", Some("channel-mu")),
- ],
- (&client_b, cx_b),
- )
- .await;
- let channel_mu_id = b_channels[0];
- let channel_ga_id = b_channels[1];
- let channel_ep_id = b_channels[2];
-
- // Current shape for B:
- // /- ep
- // mu -- ga
- assert_channels_list_shape(
- client_b.channel_store(),
- cx_b,
- &[(channel_mu_id, 0), (channel_ep_id, 1), (channel_ga_id, 1)],
- );
-
- client_a
- .add_admin_to_channel((&client_b, cx_b), channel_b_id, cx_a)
- .await;
-
- // Current shape for B:
- // /- ep
- // mu -- ga
- // /---------\
- // b -- c -- d
- assert_channels_list_shape(
- client_b.channel_store(),
- cx_b,
- &[
- // New channels from a
- (channel_b_id, 0),
- (channel_c_id, 1),
- (channel_d_id, 2),
- (channel_d_id, 1),
- // B's old channels
- (channel_mu_id, 0),
- (channel_ep_id, 1),
- (channel_ga_id, 1),
- ],
- );
-
- client_b
- .add_admin_to_channel((&client_c, cx_c), channel_ep_id, cx_b)
- .await;
-
- // Current shape for C:
- // - ep
- assert_channels_list_shape(client_c.channel_store(), cx_c, &[(channel_ep_id, 0)]);
-
- client_b
- .channel_store()
- .update(cx_b, |channel_store, cx| {
- channel_store.link_channel(channel_b_id, channel_ep_id, cx)
- })
- .await
- .unwrap();
-
- // Current shape for B:
- // /---------\
- // /- ep -- b -- c -- d
- // mu -- ga
- assert_channels_list_shape(
- client_b.channel_store(),
- cx_b,
- &[
- (channel_mu_id, 0),
- (channel_ep_id, 1),
- (channel_b_id, 2),
- (channel_c_id, 3),
- (channel_d_id, 4),
- (channel_d_id, 3),
- (channel_ga_id, 1),
- ],
- );
-
- // Current shape for C:
- // /---------\
- // ep -- b -- c -- d
- assert_channels_list_shape(
- client_c.channel_store(),
- cx_c,
- &[
- (channel_ep_id, 0),
- (channel_b_id, 1),
- (channel_c_id, 2),
- (channel_d_id, 3),
- (channel_d_id, 2),
- ],
- );
-
- client_b
- .channel_store()
- .update(cx_b, |channel_store, cx| {
- channel_store.link_channel(channel_ga_id, channel_b_id, cx)
- })
- .await
- .unwrap();
-
- // Current shape for B:
- // /---------\
- // /- ep -- b -- c -- d
- // / \
- // mu ---------- ga
- assert_channels_list_shape(
- client_b.channel_store(),
- cx_b,
- &[
- (channel_mu_id, 0),
- (channel_ep_id, 1),
- (channel_b_id, 2),
- (channel_c_id, 3),
- (channel_d_id, 4),
- (channel_d_id, 3),
- (channel_ga_id, 3),
- (channel_ga_id, 1),
- ],
- );
-
- // Current shape for A:
- // /------\
- // a - b -- c -- d
- // \-- ga
- assert_channels_list_shape(
- client_a.channel_store(),
- cx_a,
- &[
- (channel_a_id, 0),
- (channel_b_id, 1),
- (channel_c_id, 2),
- (channel_d_id, 3),
- (channel_d_id, 2),
- (channel_ga_id, 2),
- ],
- );
-
- // Current shape for C:
- // /-------\
- // ep -- b -- c -- d
- // \-- ga
- assert_channels_list_shape(
- client_c.channel_store(),
- cx_c,
- &[
- (channel_ep_id, 0),
- (channel_b_id, 1),
- (channel_c_id, 2),
- (channel_d_id, 3),
- (channel_d_id, 2),
- (channel_ga_id, 2),
- ],
- );
+ // TODO: Restore this test once we have a way to make channel symlinks
+ // client_a
+ // .channel_store()
+ // .update(cx_a, |channel_store, cx| {
+ // channel_store.link_channel(channel_d_id, channel_c_id, cx)
+ // })
+ // .await
+ // .unwrap();
+
+ // // Current shape for A:
+ // // /------\
+ // // a - b -- c -- d
+ // assert_channels_list_shape(
+ // client_a.channel_store(),
+ // cx_a,
+ // &[
+ // (channel_a_id, 0),
+ // (channel_b_id, 1),
+ // (channel_c_id, 2),
+ // (channel_d_id, 3),
+ // (channel_d_id, 2),
+ // ],
+ // );
+ //
+ // let b_channels = server
+ // .make_channel_tree(
+ // &[
+ // ("channel-mu", None),
+ // ("channel-gamma", Some("channel-mu")),
+ // ("channel-epsilon", Some("channel-mu")),
+ // ],
+ // (&client_b, cx_b),
+ // )
+ // .await;
+ // let channel_mu_id = b_channels[0];
+ // let channel_ga_id = b_channels[1];
+ // let channel_ep_id = b_channels[2];
+
+ // // Current shape for B:
+ // // /- ep
+ // // mu -- ga
+ // assert_channels_list_shape(
+ // client_b.channel_store(),
+ // cx_b,
+ // &[(channel_mu_id, 0), (channel_ep_id, 1), (channel_ga_id, 1)],
+ // );
+
+ // client_a
+ // .add_admin_to_channel((&client_b, cx_b), channel_b_id, cx_a)
+ // .await;
+
+ // // Current shape for B:
+ // // /- ep
+ // // mu -- ga
+ // // /---------\
+ // // b -- c -- d
+ // assert_channels_list_shape(
+ // client_b.channel_store(),
+ // cx_b,
+ // &[
+ // // New channels from a
+ // (channel_b_id, 0),
+ // (channel_c_id, 1),
+ // (channel_d_id, 2),
+ // (channel_d_id, 1),
+ // // B's old channels
+ // (channel_mu_id, 0),
+ // (channel_ep_id, 1),
+ // (channel_ga_id, 1),
+ // ],
+ // );
+
+ // client_b
+ // .add_admin_to_channel((&client_c, cx_c), channel_ep_id, cx_b)
+ // .await;
+
+ // // Current shape for C:
+ // // - ep
+ // assert_channels_list_shape(client_c.channel_store(), cx_c, &[(channel_ep_id, 0)]);
+
+ // client_b
+ // .channel_store()
+ // .update(cx_b, |channel_store, cx| {
+ // channel_store.link_channel(channel_b_id, channel_ep_id, cx)
+ // })
+ // .await
+ // .unwrap();
+
+ // // Current shape for B:
+ // // /---------\
+ // // /- ep -- b -- c -- d
+ // // mu -- ga
+ // assert_channels_list_shape(
+ // client_b.channel_store(),
+ // cx_b,
+ // &[
+ // (channel_mu_id, 0),
+ // (channel_ep_id, 1),
+ // (channel_b_id, 2),
+ // (channel_c_id, 3),
+ // (channel_d_id, 4),
+ // (channel_d_id, 3),
+ // (channel_ga_id, 1),
+ // ],
+ // );
+
+ // // Current shape for C:
+ // // /---------\
+ // // ep -- b -- c -- d
+ // assert_channels_list_shape(
+ // client_c.channel_store(),
+ // cx_c,
+ // &[
+ // (channel_ep_id, 0),
+ // (channel_b_id, 1),
+ // (channel_c_id, 2),
+ // (channel_d_id, 3),
+ // (channel_d_id, 2),
+ // ],
+ // );
+
+ // client_b
+ // .channel_store()
+ // .update(cx_b, |channel_store, cx| {
+ // channel_store.link_channel(channel_ga_id, channel_b_id, cx)
+ // })
+ // .await
+ // .unwrap();
+
+ // // Current shape for B:
+ // // /---------\
+ // // /- ep -- b -- c -- d
+ // // / \
+ // // mu ---------- ga
+ // assert_channels_list_shape(
+ // client_b.channel_store(),
+ // cx_b,
+ // &[
+ // (channel_mu_id, 0),
+ // (channel_ep_id, 1),
+ // (channel_b_id, 2),
+ // (channel_c_id, 3),
+ // (channel_d_id, 4),
+ // (channel_d_id, 3),
+ // (channel_ga_id, 3),
+ // (channel_ga_id, 1),
+ // ],
+ // );
+
+ // // Current shape for A:
+ // // /------\
+ // // a - b -- c -- d
+ // // \-- ga
+ // assert_channels_list_shape(
+ // client_a.channel_store(),
+ // cx_a,
+ // &[
+ // (channel_a_id, 0),
+ // (channel_b_id, 1),
+ // (channel_c_id, 2),
+ // (channel_d_id, 3),
+ // (channel_d_id, 2),
+ // (channel_ga_id, 2),
+ // ],
+ // );
+
+ // // Current shape for C:
+ // // /-------\
+ // // ep -- b -- c -- d
+ // // \-- ga
+ // assert_channels_list_shape(
+ // client_c.channel_store(),
+ // cx_c,
+ // &[
+ // (channel_ep_id, 0),
+ // (channel_b_id, 1),
+ // (channel_c_id, 2),
+ // (channel_d_id, 3),
+ // (channel_d_id, 2),
+ // (channel_ga_id, 2),
+ // ],
+ // );
}
#[derive(Debug, PartialEq)]
@@ -120,22 +120,11 @@ struct StartLinkChannelFor {
parent_id: Option<ChannelId>,
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-struct LinkChannel {
- to: ChannelId,
-}
-
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct MoveChannel {
to: ChannelId,
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-struct UnlinkChannel {
- channel_id: ChannelId,
- parent_id: ChannelId,
-}
-
type DraggedChannel = (Channel, Option<ChannelId>);
actions!(
@@ -147,8 +136,7 @@ actions!(
CollapseSelectedChannel,
ExpandSelectedChannel,
StartMoveChannel,
- StartLinkChannel,
- MoveOrLinkToSelected,
+ MoveSelected,
InsertSpace,
]
);
@@ -166,11 +154,8 @@ impl_actions!(
JoinChannelCall,
JoinChannelChat,
CopyChannelLink,
- LinkChannel,
StartMoveChannelFor,
- StartLinkChannelFor,
MoveChannel,
- UnlinkChannel,
ToggleSelectedIx
]
);
@@ -185,7 +170,7 @@ struct ChannelMoveClipboard {
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum ClipboardIntent {
Move,
- Link,
+ // Link,
}
const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
@@ -238,18 +223,6 @@ pub fn init(cx: &mut AppContext) {
},
);
- cx.add_action(
- |panel: &mut CollabPanel,
- action: &StartLinkChannelFor,
- _: &mut ViewContext<CollabPanel>| {
- panel.channel_clipboard = Some(ChannelMoveClipboard {
- channel_id: action.channel_id,
- parent_id: action.parent_id,
- intent: ClipboardIntent::Link,
- })
- },
- );
-
cx.add_action(
|panel: &mut CollabPanel, _: &StartMoveChannel, _: &mut ViewContext<CollabPanel>| {
if let Some((_, path)) = panel.selected_channel() {
@@ -263,86 +236,51 @@ pub fn init(cx: &mut AppContext) {
);
cx.add_action(
- |panel: &mut CollabPanel, _: &StartLinkChannel, _: &mut ViewContext<CollabPanel>| {
- if let Some((_, path)) = panel.selected_channel() {
- panel.channel_clipboard = Some(ChannelMoveClipboard {
- channel_id: path.channel_id(),
- parent_id: path.parent_id(),
- intent: ClipboardIntent::Link,
- })
- }
- },
- );
-
- cx.add_action(
- |panel: &mut CollabPanel, _: &MoveOrLinkToSelected, cx: &mut ViewContext<CollabPanel>| {
+ |panel: &mut CollabPanel, _: &MoveSelected, cx: &mut ViewContext<CollabPanel>| {
let clipboard = panel.channel_clipboard.take();
if let Some(((selected_channel, _), clipboard)) =
panel.selected_channel().zip(clipboard)
{
match clipboard.intent {
- ClipboardIntent::Move if clipboard.parent_id.is_some() => {
- let parent_id = clipboard.parent_id.unwrap();
- panel.channel_store.update(cx, |channel_store, cx| {
- channel_store
- .move_channel(
- clipboard.channel_id,
- parent_id,
- selected_channel.id,
- cx,
- )
- .detach_and_log_err(cx)
- })
- }
- _ => panel.channel_store.update(cx, |channel_store, cx| {
- channel_store
- .link_channel(clipboard.channel_id, selected_channel.id, cx)
- .detach_and_log_err(cx)
+ ClipboardIntent::Move => panel.channel_store.update(cx, |channel_store, cx| {
+ match clipboard.parent_id {
+ Some(parent_id) => channel_store.move_channel(
+ clipboard.channel_id,
+ parent_id,
+ selected_channel.id,
+ cx,
+ ),
+ None => channel_store.link_channel(
+ clipboard.channel_id,
+ selected_channel.id,
+ cx,
+ ),
+ }
+ .detach_and_log_err(cx)
}),
}
}
},
);
- cx.add_action(
- |panel: &mut CollabPanel, action: &LinkChannel, cx: &mut ViewContext<CollabPanel>| {
- if let Some(clipboard) = panel.channel_clipboard.take() {
- panel.channel_store.update(cx, |channel_store, cx| {
- channel_store
- .link_channel(clipboard.channel_id, action.to, cx)
- .detach_and_log_err(cx)
- })
- }
- },
- );
-
cx.add_action(
|panel: &mut CollabPanel, action: &MoveChannel, cx: &mut ViewContext<CollabPanel>| {
if let Some(clipboard) = panel.channel_clipboard.take() {
panel.channel_store.update(cx, |channel_store, cx| {
- if let Some(parent) = clipboard.parent_id {
- channel_store
- .move_channel(clipboard.channel_id, parent, action.to, cx)
- .detach_and_log_err(cx)
- } else {
- channel_store
- .link_channel(clipboard.channel_id, action.to, cx)
- .detach_and_log_err(cx)
+ match clipboard.parent_id {
+ Some(parent_id) => channel_store.move_channel(
+ clipboard.channel_id,
+ parent_id,
+ action.to,
+ cx,
+ ),
+ None => channel_store.link_channel(clipboard.channel_id, action.to, cx),
}
+ .detach_and_log_err(cx)
})
}
},
);
-
- cx.add_action(
- |panel: &mut CollabPanel, action: &UnlinkChannel, cx: &mut ViewContext<CollabPanel>| {
- panel.channel_store.update(cx, |channel_store, cx| {
- channel_store
- .unlink_channel(action.channel_id, action.parent_id, cx)
- .detach_and_log_err(cx)
- })
- },
- );
}
#[derive(Debug)]
@@ -2235,33 +2173,23 @@ impl CollabPanel {
this.deploy_channel_context_menu(Some(e.position), &path, ix, cx);
}
})
- .on_up(MouseButton::Left, move |e, this, cx| {
+ .on_up(MouseButton::Left, move |_, this, cx| {
if let Some((_, dragged_channel)) = cx
.global::<DragAndDrop<Workspace>>()
.currently_dragged::<DraggedChannel>(cx.window())
{
- if e.modifiers.alt {
- this.channel_store.update(cx, |channel_store, cx| {
- channel_store
- .link_channel(dragged_channel.0.id, channel_id, cx)
- .detach_and_log_err(cx)
- })
- } else {
- this.channel_store.update(cx, |channel_store, cx| {
- match dragged_channel.1 {
- Some(parent_id) => channel_store.move_channel(
- dragged_channel.0.id,
- parent_id,
- channel_id,
- cx,
- ),
- None => {
- channel_store.link_channel(dragged_channel.0.id, channel_id, cx)
- }
- }
- .detach_and_log_err(cx)
- })
- }
+ this.channel_store.update(cx, |channel_store, cx| {
+ match dragged_channel.1 {
+ Some(parent_id) => channel_store.move_channel(
+ dragged_channel.0.id,
+ parent_id,
+ channel_id,
+ cx,
+ ),
+ None => channel_store.link_channel(dragged_channel.0.id, channel_id, cx),
+ }
+ .detach_and_log_err(cx)
+ })
}
})
.on_move({
@@ -2288,18 +2216,10 @@ impl CollabPanel {
})
.as_draggable(
(channel.clone(), path.parent_id()),
- move |modifiers, (channel, _), cx: &mut ViewContext<Workspace>| {
+ move |_, (channel, _), cx: &mut ViewContext<Workspace>| {
let theme = &theme::current(cx).collab_panel;
Flex::<Workspace>::row()
- .with_children(modifiers.alt.then(|| {
- Svg::new("icons/plus.svg")
- .with_color(theme.channel_hash.color)
- .constrained()
- .with_width(theme.channel_hash.width)
- .aligned()
- .left()
- }))
.with_child(
Svg::new("icons/hash.svg")
.with_color(theme.channel_hash.color)
@@ -2743,19 +2663,6 @@ impl CollabPanel {
},
),
ContextMenuItem::Separator,
- ]);
-
- if let Some(parent_id) = parent_id {
- items.push(ContextMenuItem::action(
- "Unlink from parent",
- UnlinkChannel {
- channel_id: path.channel_id(),
- parent_id,
- },
- ));
- }
-
- items.extend([
ContextMenuItem::action(
"Move this channel",
StartMoveChannelFor {
@@ -2763,13 +2670,6 @@ impl CollabPanel {
parent_id,
},
),
- ContextMenuItem::action(
- "Link this channel",
- StartLinkChannelFor {
- channel_id: path.channel_id(),
- parent_id,
- },
- ),
]);
if let Some(channel_name) = channel_name {
@@ -2780,12 +2680,6 @@ impl CollabPanel {
to: path.channel_id(),
},
));
- items.push(ContextMenuItem::action(
- format!("Link '#{}' here", channel_name),
- LinkChannel {
- to: path.channel_id(),
- },
- ));
}
items.extend([
@@ -970,10 +970,16 @@ message UpdateChannels {
repeated Channel channel_invitations = 5;
repeated uint64 remove_channel_invitations = 6;
repeated ChannelParticipants channel_participants = 7;
+ //repeated ChannelRoles channel_roles = 8;
repeated UnseenChannelMessage unseen_channel_messages = 9;
repeated UnseenChannelBufferChange unseen_channel_buffer_changes = 10;
}
+//message ChannelRoles {
+// ChannelRole role = 1;
+// uint64 channel_id = 2;
+//}
+
message UnseenChannelMessage {
uint64 channel_id = 1;
uint64 message_id = 2;