channel management fixes (#4066)

Conrad Irwin created

- Close modals when focus leaves
- Disallow self-management for admins

Release Notes:

- Fixes changing role of invited channel members

Change summary

crates/collab_ui/src/collab_panel/channel_modal.rs | 10 +++++
crates/workspace/src/modal_layer.rs                | 26 ++++++++--------
2 files changed, 22 insertions(+), 14 deletions(-)

Detailed changes

crates/collab_ui/src/collab_panel/channel_modal.rs 🔗

@@ -348,6 +348,10 @@ impl PickerDelegate for ChannelModalDelegate {
 
     fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
         if let Some((selected_user, role)) = self.user_at_index(self.selected_index) {
+            if Some(selected_user.id) == self.user_store.read(cx).current_user().map(|user| user.id)
+            {
+                return;
+            }
             match self.mode {
                 Mode::ManageMembers => {
                     self.show_context_menu(selected_user, role.unwrap_or(ChannelRole::Member), cx)
@@ -383,6 +387,7 @@ impl PickerDelegate for ChannelModalDelegate {
     ) -> Option<Self::ListItem> {
         let (user, role) = self.user_at_index(ix)?;
         let request_status = self.member_status(user.id, cx);
+        let is_me = self.user_store.read(cx).current_user().map(|user| user.id) == Some(user.id);
 
         Some(
             ListItem::new(ix)
@@ -406,7 +411,10 @@ impl PickerDelegate for ChannelModalDelegate {
                                 Some(ChannelRole::Guest) => Some(Label::new("Guest")),
                                 _ => None,
                             })
-                            .child(IconButton::new("ellipsis", IconName::Ellipsis))
+                            .when(!is_me, |el| {
+                                el.child(IconButton::new("ellipsis", IconName::Ellipsis))
+                            })
+                            .when(is_me, |el| el.child(Label::new("You").color(Color::Muted)))
                             .children(
                                 if let (Some((menu, _)), true) = (&self.context_menu, selected) {
                                     Some(

crates/workspace/src/modal_layer.rs 🔗

@@ -27,7 +27,7 @@ impl<V: ModalView> ModalViewHandle for View<V> {
 
 pub struct ActiveModal {
     modal: Box<dyn ModalViewHandle>,
-    _subscription: Subscription,
+    _subscriptions: [Subscription; 2],
     previous_focus_handle: Option<FocusHandle>,
     focus_handle: FocusHandle,
 }
@@ -61,13 +61,19 @@ impl ModalLayer {
     where
         V: ModalView,
     {
+        let focus_handle = cx.focus_handle();
         self.active_modal = Some(ActiveModal {
             modal: Box::new(new_modal.clone()),
-            _subscription: cx.subscribe(&new_modal, |this, _, _: &DismissEvent, cx| {
-                this.hide_modal(cx);
-            }),
+            _subscriptions: [
+                cx.subscribe(&new_modal, |this, _, _: &DismissEvent, cx| {
+                    this.hide_modal(cx);
+                }),
+                cx.on_focus_out(&focus_handle, |this, cx| {
+                    this.hide_modal(cx);
+                }),
+            ],
             previous_focus_handle: cx.focused(),
-            focus_handle: cx.focus_handle(),
+            focus_handle,
         });
         cx.focus_view(&new_modal);
         cx.notify();
@@ -108,7 +114,7 @@ impl ModalLayer {
 }
 
 impl Render for ModalLayer {
-    fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+    fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
         let Some(active_modal) = &self.active_modal else {
             return div();
         };
@@ -127,13 +133,7 @@ impl Render for ModalLayer {
                     .flex_col()
                     .items_center()
                     .track_focus(&active_modal.focus_handle)
-                    .child(
-                        h_flex()
-                            .on_mouse_down_out(cx.listener(|this, _, cx| {
-                                this.hide_modal(cx);
-                            }))
-                            .child(active_modal.modal.view()),
-                    ),
+                    .child(h_flex().child(active_modal.modal.view())),
             )
     }
 }