Add move, link, and unlink operations
This commit is contained in:
parent
77cdbdb12a
commit
439f627d9a
3 changed files with 275 additions and 69 deletions
|
@ -146,7 +146,7 @@ impl ChannelStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn channel_at_index(&self, ix: usize) -> Option<(&Arc<Channel>, &Arc<[ChannelId]>)> {
|
pub fn channel_at_index(&self, ix: usize) -> Option<(&Arc<Channel>, &ChannelPath)> {
|
||||||
let path = self.channel_index.get(ix)?;
|
let path = self.channel_index.get(ix)?;
|
||||||
let id = path.last().unwrap();
|
let id = path.last().unwrap();
|
||||||
let channel = self.channel_for_id(*id).unwrap();
|
let channel = self.channel_for_id(*id).unwrap();
|
||||||
|
|
|
@ -1,13 +1,38 @@
|
||||||
use std::sync::Arc;
|
use std::{sync::Arc, ops::Deref};
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use rpc::proto;
|
use rpc::proto;
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::{ChannelId, Channel};
|
use crate::{ChannelId, Channel};
|
||||||
|
|
||||||
pub type ChannelPath = Arc<[ChannelId]>;
|
|
||||||
pub type ChannelsById = HashMap<ChannelId, Arc<Channel>>;
|
pub type ChannelsById = HashMap<ChannelId, Arc<Channel>>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct ChannelPath(Arc<[ChannelId]>);
|
||||||
|
|
||||||
|
impl Deref for ChannelPath {
|
||||||
|
type Target = [ChannelId];
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelPath {
|
||||||
|
pub fn parent_id(&self) -> Option<ChannelId> {
|
||||||
|
self.0.len().checked_sub(2).map(|i| {
|
||||||
|
self.0[i]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ChannelPath {
|
||||||
|
fn default() -> Self {
|
||||||
|
ChannelPath(Arc::from([]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ChannelIndex {
|
pub struct ChannelIndex {
|
||||||
paths: Vec<ChannelPath>,
|
paths: Vec<ChannelPath>,
|
||||||
|
@ -99,7 +124,7 @@ impl<'a> ChannelPathsUpsertGuard<'a> {
|
||||||
if path.ends_with(&[parent_id]) {
|
if path.ends_with(&[parent_id]) {
|
||||||
let mut new_path = path.to_vec();
|
let mut new_path = path.to_vec();
|
||||||
new_path.push(channel_id);
|
new_path.push(channel_id);
|
||||||
self.paths.insert(ix + 1, new_path.into());
|
self.paths.insert(ix + 1, ChannelPath(new_path.into()));
|
||||||
ix += 1;
|
ix += 1;
|
||||||
}
|
}
|
||||||
ix += 1;
|
ix += 1;
|
||||||
|
@ -107,7 +132,7 @@ impl<'a> ChannelPathsUpsertGuard<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_root(&mut self, channel_id: ChannelId) {
|
fn insert_root(&mut self, channel_id: ChannelId) {
|
||||||
self.paths.push(Arc::from([channel_id]));
|
self.paths.push(ChannelPath(Arc::from([channel_id])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use anyhow::Result;
|
||||||
use call::ActiveCall;
|
use call::ActiveCall;
|
||||||
use channel::{Channel, ChannelEvent, ChannelId, ChannelStore, ChannelPath};
|
use channel::{Channel, ChannelEvent, ChannelId, ChannelStore, ChannelPath};
|
||||||
use channel_modal::ChannelModal;
|
use channel_modal::ChannelModal;
|
||||||
|
use channel::{Channel, ChannelEvent, ChannelId, ChannelPath, ChannelStore};
|
||||||
use client::{proto::PeerId, Client, Contact, User, UserStore};
|
use client::{proto::PeerId, Client, Contact, User, UserStore};
|
||||||
use contact_finder::ContactFinder;
|
use contact_finder::ContactFinder;
|
||||||
use context_menu::{ContextMenu, ContextMenuItem};
|
use context_menu::{ContextMenu, ContextMenuItem};
|
||||||
|
@ -40,7 +41,7 @@ use menu::{Confirm, SelectNext, SelectPrev};
|
||||||
use project::{Fs, Project};
|
use project::{Fs, Project};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
use std::{borrow::Cow, mem, sync::Arc, hash::Hash};
|
use std::{borrow::Cow, hash::Hash, mem, sync::Arc};
|
||||||
use theme::{components::ComponentExt, IconButton};
|
use theme::{components::ComponentExt, IconButton};
|
||||||
use util::{iife, ResultExt, TryFutureExt};
|
use util::{iife, ResultExt, TryFutureExt};
|
||||||
use workspace::{
|
use workspace::{
|
||||||
|
@ -95,18 +96,25 @@ struct OpenChannelBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct CopyChannel {
|
struct LinkChannel {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct CutChannel {
|
struct MoveChannel {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
parent_id: Option<ChannelId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
struct PasteChannel {
|
struct PutChannel {
|
||||||
|
to: ChannelId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
struct UnlinkChannel {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
parent_id: ChannelId,
|
||||||
}
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
|
@ -132,9 +140,10 @@ impl_actions!(
|
||||||
OpenChannelNotes,
|
OpenChannelNotes,
|
||||||
JoinChannelCall,
|
JoinChannelCall,
|
||||||
OpenChannelBuffer,
|
OpenChannelBuffer,
|
||||||
CopyChannel,
|
LinkChannel,
|
||||||
CutChannel,
|
MoveChannel,
|
||||||
PasteChannel,
|
PutChannel,
|
||||||
|
UnlinkChannel
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -143,18 +152,24 @@ const COLLABORATION_PANEL_KEY: &'static str = "CollaborationPanel";
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
pub struct ChannelLocation<'a> {
|
pub struct ChannelLocation<'a> {
|
||||||
channel: ChannelId,
|
channel: ChannelId,
|
||||||
parent: Cow<'a, ChannelPath>,
|
path: Cow<'a, ChannelPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(ChannelId, ChannelPath)> for ChannelLocation<'static> {
|
impl From<(ChannelId, ChannelPath)> for ChannelLocation<'static> {
|
||||||
fn from(value: (ChannelId, ChannelPath)) -> Self {
|
fn from(value: (ChannelId, ChannelPath)) -> Self {
|
||||||
ChannelLocation { channel: value.0, parent: Cow::Owned(value.1) }
|
ChannelLocation {
|
||||||
|
channel: value.0,
|
||||||
|
path: Cow::Owned(value.1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<(ChannelId, &'a ChannelPath)> for ChannelLocation<'a> {
|
impl<'a> From<(ChannelId, &'a ChannelPath)> for ChannelLocation<'a> {
|
||||||
fn from(value: (ChannelId, &'a ChannelPath)) -> Self {
|
fn from(value: (ChannelId, &'a ChannelPath)) -> Self {
|
||||||
ChannelLocation { channel: value.0, parent: Cow::Borrowed(value.1) }
|
ChannelLocation {
|
||||||
|
channel: value.0,
|
||||||
|
path: Cow::Borrowed(value.1),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,25 +197,54 @@ pub fn init(cx: &mut AppContext) {
|
||||||
cx.add_action(CollabPanel::open_channel_notes);
|
cx.add_action(CollabPanel::open_channel_notes);
|
||||||
cx.add_action(CollabPanel::open_channel_buffer);
|
cx.add_action(CollabPanel::open_channel_buffer);
|
||||||
|
|
||||||
cx.add_action(|panel: &mut CollabPanel, action: &CopyChannel, _: &mut ViewContext<CollabPanel>| {
|
cx.add_action(
|
||||||
panel.copy = Some(ChannelCopy::Copy(action.channel_id));
|
|panel: &mut CollabPanel, action: &LinkChannel, _: &mut ViewContext<CollabPanel>| {
|
||||||
});
|
panel.copy = Some(ChannelCopy::Link(action.channel_id));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
cx.add_action(|panel: &mut CollabPanel, action: &CutChannel, _: &mut ViewContext<CollabPanel>| {
|
cx.add_action(
|
||||||
// panel.copy = Some(ChannelCopy::Cut(action.channel_id));
|
|panel: &mut CollabPanel, action: &MoveChannel, _: &mut ViewContext<CollabPanel>| {
|
||||||
|
panel.copy = Some(ChannelCopy::Move {
|
||||||
|
channel_id: action.channel_id,
|
||||||
|
parent_id: action.parent_id,
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
cx.add_action(|panel: &mut CollabPanel, action: &PasteChannel, cx: &mut ViewContext<CollabPanel>| {
|
cx.add_action(
|
||||||
if let Some(copy) = &panel.copy {
|
|panel: &mut CollabPanel, action: &PutChannel, cx: &mut ViewContext<CollabPanel>| {
|
||||||
|
if let Some(copy) = panel.copy.take() {
|
||||||
match copy {
|
match copy {
|
||||||
ChannelCopy::Cut {..} => todo!(),
|
ChannelCopy::Move {
|
||||||
ChannelCopy::Copy(channel) => panel.channel_store.update(cx, |channel_store, cx| {
|
channel_id,
|
||||||
channel_store.move_channel(*channel, None, Some(action.channel_id), cx).detach_and_log_err(cx)
|
parent_id,
|
||||||
|
} => panel.channel_store.update(cx, |channel_store, cx| {
|
||||||
|
channel_store
|
||||||
|
.move_channel(channel_id, parent_id, Some(action.to), cx)
|
||||||
|
.detach_and_log_err(cx)
|
||||||
}),
|
}),
|
||||||
|
ChannelCopy::Link(channel) => {
|
||||||
|
panel.channel_store.update(cx, |channel_store, cx| {
|
||||||
|
channel_store
|
||||||
|
.move_channel(channel, None, Some(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
|
||||||
|
.move_channel(action.channel_id, Some(action.parent_id), None, cx)
|
||||||
|
.detach_and_log_err(cx)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -224,12 +268,22 @@ impl ChannelEditingState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
enum ChannelCopy {
|
enum ChannelCopy {
|
||||||
Cut {
|
Move {
|
||||||
channel_id: u64,
|
channel_id: u64,
|
||||||
parent_id: Option<u64>,
|
parent_id: Option<u64>,
|
||||||
},
|
},
|
||||||
Copy(u64),
|
Link(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChannelCopy {
|
||||||
|
fn channel_id(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
ChannelCopy::Move { channel_id, .. } => *channel_id,
|
||||||
|
ChannelCopy::Link(channel_id) => *channel_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CollabPanel {
|
pub struct CollabPanel {
|
||||||
|
@ -304,7 +358,7 @@ enum ListEntry {
|
||||||
Channel {
|
Channel {
|
||||||
channel: Arc<Channel>,
|
channel: Arc<Channel>,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
path: Arc<[ChannelId]>,
|
path: ChannelPath,
|
||||||
},
|
},
|
||||||
ChannelNotes {
|
ChannelNotes {
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
|
@ -422,7 +476,11 @@ impl CollabPanel {
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ListEntry::Channel { channel, depth, path } => {
|
ListEntry::Channel {
|
||||||
|
channel,
|
||||||
|
depth,
|
||||||
|
path,
|
||||||
|
} => {
|
||||||
let channel_row = this.render_channel(
|
let channel_row = this.render_channel(
|
||||||
&*channel,
|
&*channel,
|
||||||
*depth,
|
*depth,
|
||||||
|
@ -583,7 +641,13 @@ impl CollabPanel {
|
||||||
.log_err()
|
.log_err()
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
Some(serde_json::from_str::<SerializedCollabPanel>(&panel)?)
|
match serde_json::from_str::<SerializedCollabPanel>(&panel) {
|
||||||
|
Ok(panel) => Some(panel),
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to deserialize collaboration panel: {}", err);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -773,20 +837,13 @@ impl CollabPanel {
|
||||||
executor.clone(),
|
executor.clone(),
|
||||||
));
|
));
|
||||||
if let Some(state) = &self.channel_editing_state {
|
if let Some(state) = &self.channel_editing_state {
|
||||||
if matches!(
|
if matches!(state, ChannelEditingState::Create { location: None, .. }) {
|
||||||
state,
|
|
||||||
ChannelEditingState::Create {
|
|
||||||
location: None,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
self.entries.push(ListEntry::ChannelEditor { depth: 0 });
|
self.entries.push(ListEntry::ChannelEditor { depth: 0 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut collapse_depth = None;
|
let mut collapse_depth = None;
|
||||||
for mat in matches {
|
for mat in matches {
|
||||||
let (channel, path) =
|
let (channel, path) = channel_store.channel_at_index(mat.candidate_id).unwrap();
|
||||||
channel_store.channel_at_index(mat.candidate_id).unwrap();
|
|
||||||
let depth = path.len() - 1;
|
let depth = path.len() - 1;
|
||||||
|
|
||||||
let location: ChannelLocation<'_> = (channel.id, path).into();
|
let location: ChannelLocation<'_> = (channel.id, path).into();
|
||||||
|
@ -805,9 +862,10 @@ impl CollabPanel {
|
||||||
}
|
}
|
||||||
|
|
||||||
match &self.channel_editing_state {
|
match &self.channel_editing_state {
|
||||||
Some(ChannelEditingState::Create { location: parent_id, .. })
|
Some(ChannelEditingState::Create {
|
||||||
if *parent_id == Some(location) =>
|
location: parent_id,
|
||||||
{
|
..
|
||||||
|
}) if *parent_id == Some(location) => {
|
||||||
self.entries.push(ListEntry::Channel {
|
self.entries.push(ListEntry::Channel {
|
||||||
channel: channel.clone(),
|
channel: channel.clone(),
|
||||||
depth,
|
depth,
|
||||||
|
@ -817,7 +875,8 @@ impl CollabPanel {
|
||||||
.push(ListEntry::ChannelEditor { depth: depth + 1 });
|
.push(ListEntry::ChannelEditor { depth: depth + 1 });
|
||||||
}
|
}
|
||||||
Some(ChannelEditingState::Rename { location, .. })
|
Some(ChannelEditingState::Rename { location, .. })
|
||||||
if location.channel == channel.id && location.parent == Cow::Borrowed(path) =>
|
if location.channel == channel.id
|
||||||
|
&& location.path == Cow::Borrowed(path) =>
|
||||||
{
|
{
|
||||||
self.entries.push(ListEntry::ChannelEditor { depth });
|
self.entries.push(ListEntry::ChannelEditor { depth });
|
||||||
}
|
}
|
||||||
|
@ -825,7 +884,7 @@ impl CollabPanel {
|
||||||
self.entries.push(ListEntry::Channel {
|
self.entries.push(ListEntry::Channel {
|
||||||
channel: channel.clone(),
|
channel: channel.clone(),
|
||||||
depth,
|
depth,
|
||||||
path: path.clone()
|
path: path.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1638,7 +1697,7 @@ impl CollabPanel {
|
||||||
let disclosed = {
|
let disclosed = {
|
||||||
let location = ChannelLocation {
|
let location = ChannelLocation {
|
||||||
channel: channel_id,
|
channel: channel_id,
|
||||||
parent: Cow::Borrowed(&path),
|
path: Cow::Borrowed(&path),
|
||||||
};
|
};
|
||||||
has_children.then(|| !self.collapsed_channels.binary_search(&location).is_ok())
|
has_children.then(|| !self.collapsed_channels.binary_search(&location).is_ok())
|
||||||
};
|
};
|
||||||
|
@ -1725,7 +1784,12 @@ impl CollabPanel {
|
||||||
)
|
)
|
||||||
.align_children_center()
|
.align_children_center()
|
||||||
.styleable_component()
|
.styleable_component()
|
||||||
.disclosable(disclosed, Box::new(ToggleCollapse { location: (channel_id, path.clone()).into() }))
|
.disclosable(
|
||||||
|
disclosed,
|
||||||
|
Box::new(ToggleCollapse {
|
||||||
|
location: (channel_id, path.clone()).into(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
.with_id(id(&path) as usize)
|
.with_id(id(&path) as usize)
|
||||||
.with_style(theme.disclosure.clone())
|
.with_style(theme.disclosure.clone())
|
||||||
.element()
|
.element()
|
||||||
|
@ -1742,7 +1806,11 @@ impl CollabPanel {
|
||||||
this.join_channel_chat(channel_id, cx);
|
this.join_channel_chat(channel_id, cx);
|
||||||
})
|
})
|
||||||
.on_click(MouseButton::Right, move |e, this, cx| {
|
.on_click(MouseButton::Right, move |e, this, cx| {
|
||||||
this.deploy_channel_context_menu(Some(e.position), &(channel_id, path.clone()).into(), cx);
|
this.deploy_channel_context_menu(
|
||||||
|
Some(e.position),
|
||||||
|
&(channel_id, path.clone()).into(),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
})
|
})
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.into_any()
|
.into_any()
|
||||||
|
@ -1994,6 +2062,16 @@ impl CollabPanel {
|
||||||
) {
|
) {
|
||||||
self.context_menu_on_selected = position.is_none();
|
self.context_menu_on_selected = position.is_none();
|
||||||
|
|
||||||
|
let copy_channel = self
|
||||||
|
.copy
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|copy| {
|
||||||
|
self.channel_store
|
||||||
|
.read(cx)
|
||||||
|
.channel_for_id(copy.channel_id())
|
||||||
|
})
|
||||||
|
.map(|channel| channel.name.clone());
|
||||||
|
|
||||||
self.context_menu.update(cx, |context_menu, cx| {
|
self.context_menu.update(cx, |context_menu, cx| {
|
||||||
context_menu.set_position_mode(if self.context_menu_on_selected {
|
context_menu.set_position_mode(if self.context_menu_on_selected {
|
||||||
OverlayPositionMode::Local
|
OverlayPositionMode::Local
|
||||||
|
@ -2008,22 +2086,96 @@ impl CollabPanel {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut items = vec![
|
let mut items = vec![
|
||||||
ContextMenuItem::action(expand_action_name, ToggleCollapse { location: location.clone() }),
|
ContextMenuItem::action(
|
||||||
ContextMenuItem::action("Open Notes", OpenChannelBuffer { channel_id: location.channel }),
|
expand_action_name,
|
||||||
|
ToggleCollapse {
|
||||||
|
location: location.clone(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Open Notes",
|
||||||
|
OpenChannelBuffer {
|
||||||
|
channel_id: location.channel,
|
||||||
|
},
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
if self.channel_store.read(cx).is_user_admin(location.channel) {
|
if self.channel_store.read(cx).is_user_admin(location.channel) {
|
||||||
|
let parent_id = location.path.parent_id();
|
||||||
|
|
||||||
items.extend([
|
items.extend([
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("New Subchannel", NewChannel { location: location.clone() }),
|
ContextMenuItem::action(
|
||||||
ContextMenuItem::action("Rename", RenameChannel { location: location.clone() }),
|
"New Subchannel",
|
||||||
ContextMenuItem::action("Copy", CopyChannel { channel_id: location.channel }),
|
NewChannel {
|
||||||
ContextMenuItem::action("Paste", PasteChannel { channel_id: location.channel }),
|
location: location.clone(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Rename",
|
||||||
|
RenameChannel {
|
||||||
|
location: location.clone(),
|
||||||
|
},
|
||||||
|
),
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("Invite Members", InviteMembers { channel_id: location.channel }),
|
]);
|
||||||
ContextMenuItem::action("Manage Members", ManageMembers { channel_id: location.channel }),
|
|
||||||
|
if let Some(parent) = parent_id {
|
||||||
|
items.push(ContextMenuItem::action(
|
||||||
|
"Unlink from parent",
|
||||||
|
UnlinkChannel {
|
||||||
|
channel_id: location.channel,
|
||||||
|
parent_id: parent,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
items.extend([
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Link to new parent",
|
||||||
|
LinkChannel {
|
||||||
|
channel_id: location.channel,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Move",
|
||||||
|
MoveChannel {
|
||||||
|
channel_id: location.channel,
|
||||||
|
parent_id,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if let Some(copy_channel) = copy_channel {
|
||||||
|
items.push(ContextMenuItem::action(
|
||||||
|
format!("Put '#{}'", copy_channel),
|
||||||
|
PutChannel {
|
||||||
|
to: location.channel,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
items.extend([
|
||||||
ContextMenuItem::Separator,
|
ContextMenuItem::Separator,
|
||||||
ContextMenuItem::action("Delete", RemoveChannel { channel_id: location.channel }),
|
ContextMenuItem::action(
|
||||||
|
"Invite Members",
|
||||||
|
InviteMembers {
|
||||||
|
channel_id: location.channel,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Manage Members",
|
||||||
|
ManageMembers {
|
||||||
|
channel_id: location.channel,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ContextMenuItem::Separator,
|
||||||
|
ContextMenuItem::action(
|
||||||
|
"Delete",
|
||||||
|
RemoveChannel {
|
||||||
|
channel_id: location.channel,
|
||||||
|
},
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2162,7 +2314,11 @@ impl CollabPanel {
|
||||||
|
|
||||||
self.channel_store
|
self.channel_store
|
||||||
.update(cx, |channel_store, cx| {
|
.update(cx, |channel_store, cx| {
|
||||||
channel_store.create_channel(&channel_name, location.as_ref().map(|location| location.channel), cx)
|
channel_store.create_channel(
|
||||||
|
&channel_name,
|
||||||
|
location.as_ref().map(|location| location.channel),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -2206,7 +2362,10 @@ impl CollabPanel {
|
||||||
_: &CollapseSelectedChannel,
|
_: &CollapseSelectedChannel,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let Some((channel_id, path)) = self.selected_channel().map(|(channel, parent)| (channel.id, parent)) else {
|
let Some((channel_id, path)) = self
|
||||||
|
.selected_channel()
|
||||||
|
.map(|(channel, parent)| (channel.id, parent))
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2216,11 +2375,19 @@ impl CollabPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toggle_channel_collapsed(&ToggleCollapse { location: (channel_id, path).into() }, cx)
|
self.toggle_channel_collapsed(
|
||||||
|
&ToggleCollapse {
|
||||||
|
location: (channel_id, path).into(),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext<Self>) {
|
fn expand_selected_channel(&mut self, _: &ExpandSelectedChannel, cx: &mut ViewContext<Self>) {
|
||||||
let Some((channel_id, path)) = self.selected_channel().map(|(channel, parent)| (channel.id, parent)) else {
|
let Some((channel_id, path)) = self
|
||||||
|
.selected_channel()
|
||||||
|
.map(|(channel, parent)| (channel.id, parent))
|
||||||
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2230,7 +2397,12 @@ impl CollabPanel {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toggle_channel_collapsed(&ToggleCollapse { location: (channel_id, path).into() }, cx)
|
self.toggle_channel_collapsed(
|
||||||
|
&ToggleCollapse {
|
||||||
|
location: (channel_id, path).into(),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapse, cx: &mut ViewContext<Self>) {
|
fn toggle_channel_collapsed(&mut self, action: &ToggleCollapse, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -2335,7 +2507,10 @@ impl CollabPanel {
|
||||||
if !channel_store.is_user_admin(action.location.channel) {
|
if !channel_store.is_user_admin(action.location.channel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(channel) = channel_store.channel_for_id(action.location.channel).cloned() {
|
if let Some(channel) = channel_store
|
||||||
|
.channel_for_id(action.location.channel)
|
||||||
|
.cloned()
|
||||||
|
{
|
||||||
self.channel_editing_state = Some(ChannelEditingState::Rename {
|
self.channel_editing_state = Some(ChannelEditingState::Rename {
|
||||||
location: action.location.to_owned(),
|
location: action.location.to_owned(),
|
||||||
pending_name: None,
|
pending_name: None,
|
||||||
|
@ -2368,7 +2543,11 @@ impl CollabPanel {
|
||||||
self.selection
|
self.selection
|
||||||
.and_then(|ix| self.entries.get(ix))
|
.and_then(|ix| self.entries.get(ix))
|
||||||
.and_then(|entry| match entry {
|
.and_then(|entry| match entry {
|
||||||
ListEntry::Channel { channel, path: parent, .. } => Some((channel, parent)),
|
ListEntry::Channel {
|
||||||
|
channel,
|
||||||
|
path: parent,
|
||||||
|
..
|
||||||
|
} => Some((channel, parent)),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2759,7 +2938,9 @@ impl PartialEq for ListEntry {
|
||||||
path: parent_2,
|
path: parent_2,
|
||||||
} = other
|
} = other
|
||||||
{
|
{
|
||||||
return channel_1.id == channel_2.id && depth_1 == depth_2 && parent_1 == parent_2;
|
return channel_1.id == channel_2.id
|
||||||
|
&& depth_1 == depth_2
|
||||||
|
&& parent_1 == parent_2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ListEntry::ChannelNotes { channel_id } => {
|
ListEntry::ChannelNotes { channel_id } => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue