Position and style the channel editor correctly

Fix a bug where some channel updates would be lost
Add channel name sanitization before storing in the database
This commit is contained in:
Mikayla 2023-08-08 12:46:13 -07:00
parent b708824d37
commit bbe4a9b388
No known key found for this signature in database
3 changed files with 95 additions and 12 deletions

View File

@ -13,6 +13,7 @@
"cmd-up": "menu::SelectFirst", "cmd-up": "menu::SelectFirst",
"cmd-down": "menu::SelectLast", "cmd-down": "menu::SelectLast",
"enter": "menu::Confirm", "enter": "menu::Confirm",
"ctrl-enter": "menu::ShowContextMenu",
"cmd-enter": "menu::SecondaryConfirm", "cmd-enter": "menu::SecondaryConfirm",
"escape": "menu::Cancel", "escape": "menu::Cancel",
"ctrl-c": "menu::Cancel", "ctrl-c": "menu::Cancel",
@ -550,6 +551,13 @@
"alt-shift-f": "project_panel::NewSearchInDirectory" "alt-shift-f": "project_panel::NewSearchInDirectory"
} }
}, },
{
"context": "CollabPanel",
"bindings": {
"ctrl-backspace": "collab_panel::Remove",
"space": "menu::Confirm"
}
},
{ {
"context": "ChannelModal", "context": "ChannelModal",
"bindings": { "bindings": {

View File

@ -15,7 +15,7 @@ use gpui::{
actions, actions,
elements::{ elements::{
Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState, Canvas, ChildView, Empty, Flex, Image, Label, List, ListOffset, ListState,
MouseEventHandler, Orientation, Padding, ParentElement, Stack, Svg, MouseEventHandler, Orientation, OverlayPositionMode, Padding, ParentElement, Stack, Svg,
}, },
geometry::{ geometry::{
rect::RectF, rect::RectF,
@ -64,7 +64,7 @@ struct ManageMembers {
channel_id: u64, channel_id: u64,
} }
actions!(collab_panel, [ToggleFocus]); actions!(collab_panel, [ToggleFocus, Remove, Secondary]);
impl_actions!( impl_actions!(
collab_panel, collab_panel,
@ -82,7 +82,9 @@ pub fn init(_client: Arc<Client>, cx: &mut AppContext) {
cx.add_action(CollabPanel::select_next); cx.add_action(CollabPanel::select_next);
cx.add_action(CollabPanel::select_prev); cx.add_action(CollabPanel::select_prev);
cx.add_action(CollabPanel::confirm); cx.add_action(CollabPanel::confirm);
cx.add_action(CollabPanel::remove_channel); cx.add_action(CollabPanel::remove);
cx.add_action(CollabPanel::remove_channel_action);
cx.add_action(CollabPanel::show_inline_context_menu);
cx.add_action(CollabPanel::new_subchannel); cx.add_action(CollabPanel::new_subchannel);
cx.add_action(CollabPanel::invite_members); cx.add_action(CollabPanel::invite_members);
cx.add_action(CollabPanel::manage_members); cx.add_action(CollabPanel::manage_members);
@ -113,6 +115,7 @@ pub struct CollabPanel {
subscriptions: Vec<Subscription>, subscriptions: Vec<Subscription>,
collapsed_sections: Vec<Section>, collapsed_sections: Vec<Section>,
workspace: WeakViewHandle<Workspace>, workspace: WeakViewHandle<Workspace>,
context_menu_on_selected: bool,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -274,7 +277,26 @@ impl CollabPanel {
) )
} }
ListEntry::Channel(channel) => { ListEntry::Channel(channel) => {
this.render_channel(&*channel, &theme.collab_panel, is_selected, cx) let channel_row = this.render_channel(
&*channel,
&theme.collab_panel,
is_selected,
cx,
);
if is_selected && this.context_menu_on_selected {
Stack::new()
.with_child(channel_row)
.with_child(
ChildView::new(&this.context_menu, cx)
.aligned()
.bottom()
.right(),
)
.into_any()
} else {
return channel_row;
}
} }
ListEntry::ChannelInvite(channel) => Self::render_channel_invite( ListEntry::ChannelInvite(channel) => Self::render_channel_invite(
channel.clone(), channel.clone(),
@ -332,6 +354,7 @@ impl CollabPanel {
collapsed_sections: Vec::default(), collapsed_sections: Vec::default(),
workspace: workspace.weak_handle(), workspace: workspace.weak_handle(),
client: workspace.app_state().client.clone(), client: workspace.app_state().client.clone(),
context_menu_on_selected: true,
list_state, list_state,
}; };
@ -1321,6 +1344,7 @@ impl CollabPanel {
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> AnyElement<Self> { ) -> AnyElement<Self> {
let channel_id = channel.id; let channel_id = channel.id;
MouseEventHandler::<Channel, Self>::new(channel.id as usize, cx, |state, cx| { MouseEventHandler::<Channel, Self>::new(channel.id as usize, cx, |state, cx| {
Flex::row() Flex::row()
.with_child( .with_child(
@ -1367,7 +1391,7 @@ impl CollabPanel {
this.join_channel(channel_id, cx); this.join_channel(channel_id, cx);
}) })
.on_click(MouseButton::Right, move |e, this, cx| { .on_click(MouseButton::Right, move |e, this, cx| {
this.deploy_channel_context_menu(e.position, channel_id, cx); this.deploy_channel_context_menu(Some(e.position), channel_id, cx);
}) })
.into_any() .into_any()
} }
@ -1573,15 +1597,27 @@ impl CollabPanel {
fn deploy_channel_context_menu( fn deploy_channel_context_menu(
&mut self, &mut self,
position: Vector2F, position: Option<Vector2F>,
channel_id: u64, channel_id: u64,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
if self.channel_store.read(cx).is_user_admin(channel_id) { if self.channel_store.read(cx).is_user_admin(channel_id) {
self.context_menu_on_selected = position.is_none();
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 {
OverlayPositionMode::Local
} else {
OverlayPositionMode::Window
});
context_menu.show( context_menu.show(
position, position.unwrap_or_default(),
gpui::elements::AnchorCorner::BottomLeft, if self.context_menu_on_selected {
gpui::elements::AnchorCorner::TopRight
} else {
gpui::elements::AnchorCorner::BottomLeft
},
vec![ vec![
ContextMenuItem::action("New Channel", NewChannel { channel_id }), ContextMenuItem::action("New Channel", NewChannel { channel_id }),
ContextMenuItem::action("Remove Channel", RemoveChannel { channel_id }), ContextMenuItem::action("Remove Channel", RemoveChannel { channel_id }),
@ -1591,6 +1627,8 @@ impl CollabPanel {
cx, cx,
); );
}); });
cx.notify();
} }
} }
@ -1755,6 +1793,33 @@ impl CollabPanel {
self.show_channel_modal(action.channel_id, channel_modal::Mode::ManageMembers, cx); self.show_channel_modal(action.channel_id, channel_modal::Mode::ManageMembers, cx);
} }
// TODO: Make join into a toggle
// TODO: Make enter work on channel editor
fn remove(&mut self, _: &Remove, cx: &mut ViewContext<Self>) {
if let Some(channel) = self.selected_channel() {
self.remove_channel(channel.id, cx)
}
}
fn rename(&mut self, _: &menu::SecondaryConfirm, cx: &mut ViewContext<Self>) {}
fn show_inline_context_menu(&mut self, _: &menu::ShowContextMenu, cx: &mut ViewContext<Self>) {
let Some(channel) = self.selected_channel() else {
return;
};
self.deploy_channel_context_menu(None, channel.id, cx);
}
fn selected_channel(&self) -> Option<&Arc<Channel>> {
self.selection
.and_then(|ix| self.entries.get(ix))
.and_then(|entry| match entry {
ListEntry::Channel(channel) => Some(channel),
_ => None,
})
}
fn show_channel_modal( fn show_channel_modal(
&mut self, &mut self,
channel_id: ChannelId, channel_id: ChannelId,
@ -1788,8 +1853,11 @@ impl CollabPanel {
.detach(); .detach();
} }
fn remove_channel(&mut self, action: &RemoveChannel, cx: &mut ViewContext<Self>) { fn remove_channel_action(&mut self, action: &RemoveChannel, cx: &mut ViewContext<Self>) {
let channel_id = action.channel_id; self.remove_channel(action.channel_id, cx)
}
fn remove_channel(&mut self, channel_id: ChannelId, cx: &mut ViewContext<Self>) {
let channel_store = self.channel_store.clone(); let channel_store = self.channel_store.clone();
if let Some(channel) = channel_store.read(cx).channel_for_id(channel_id) { if let Some(channel) = channel_store.read(cx).channel_for_id(channel_id) {
let prompt_message = format!( let prompt_message = format!(
@ -1818,6 +1886,9 @@ impl CollabPanel {
} }
} }
// Should move to the filter editor if clicking on it
// Should move selection to the channel editor if activating it
fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext<Self>) { fn remove_contact(&mut self, user_id: u64, github_login: &str, cx: &mut ViewContext<Self>) {
let user_store = self.user_store.clone(); let user_store = self.user_store.clone();
let prompt_message = format!( let prompt_message = format!(
@ -1969,7 +2040,10 @@ impl View for CollabPanel {
.with_width(self.size(cx)) .with_width(self.size(cx))
.into_any(), .into_any(),
) )
.with_child(ChildView::new(&self.context_menu, cx)) .with_children(
(!self.context_menu_on_selected)
.then(|| ChildView::new(&self.context_menu, cx)),
)
.into_any() .into_any()
}) })
.on_click(MouseButton::Left, |_, _, cx| cx.focus_self()) .on_click(MouseButton::Left, |_, _, cx| cx.focus_self())

View File

@ -7,6 +7,7 @@ gpui::actions!(
SelectPrev, SelectPrev,
SelectNext, SelectNext,
SelectFirst, SelectFirst,
SelectLast SelectLast,
ShowContextMenu
] ]
); );