Add a `Show All Channels` button to the collab panel (#48826)

Joseph T. Lyons created

This makes it easy to see all the activity that is happening in a more
condensed view.
Helps you fend off endless scrolling in the collaboration panel when
trying to find the meeting room. ⚔️


https://github.com/user-attachments/assets/5b538636-5672-42a4-a831-ffe303051c84

- [X] Tests or screenshots needed?
- [ ] Code Reviewed
- [X] Manual QA

Release Notes:

- Added a `Show All Channels` button to the collab panel to filter down
to only channels with participants.

Change summary

crates/collab_ui/src/collab_panel.rs | 50 +++++++++++++++++++++++++----
1 file changed, 43 insertions(+), 7 deletions(-)

Detailed changes

crates/collab_ui/src/collab_panel.rs 🔗

@@ -227,6 +227,7 @@ pub struct CollabPanel {
     subscriptions: Vec<Subscription>,
     collapsed_sections: Vec<Section>,
     collapsed_channels: Vec<ChannelId>,
+    filter_active_channels: bool,
     workspace: WeakEntity<Workspace>,
 }
 
@@ -359,6 +360,7 @@ impl CollabPanel {
                 match_candidates: Vec::default(),
                 collapsed_sections: vec![Section::Offline],
                 collapsed_channels: Vec::default(),
+                filter_active_channels: false,
                 workspace: workspace.weak_handle(),
                 client: workspace.app_state().client.clone(),
             };
@@ -679,13 +681,23 @@ impl CollabPanel {
 
             channels.retain(|chan| channel_ids_of_matches_or_parents.contains(&chan.id));
 
+            if self.filter_active_channels {
+                let active_channel_ids_or_ancestors: HashSet<_> = channel_store
+                    .ordered_channels()
+                    .map(|(_, channel)| channel)
+                    .filter(|channel| !channel_store.channel_participants(channel.id).is_empty())
+                    .flat_map(|channel| channel.parent_path.iter().copied().chain(Some(channel.id)))
+                    .collect();
+                channels.retain(|channel| active_channel_ids_or_ancestors.contains(&channel.id));
+            }
+
             if let Some(state) = &self.channel_editing_state
                 && matches!(state, ChannelEditingState::Create { location: None, .. })
             {
                 self.entries.push(ListEntry::ChannelEditor { depth: 0 });
             }
 
-            let should_respect_collapse = query.is_empty();
+            let should_respect_collapse = query.is_empty() && !self.filter_active_channels;
             let mut collapse_depth = None;
 
             for (idx, channel) in channels.into_iter().enumerate() {
@@ -2554,12 +2566,36 @@ impl CollabPanel {
                     .tooltip(Tooltip::text("Search for new contact"))
                     .into_any_element(),
             ),
-            Section::Channels => Some(
-                IconButton::new("add-channel", IconName::Plus)
-                    .on_click(cx.listener(|this, _, window, cx| this.new_root_channel(window, cx)))
-                    .tooltip(Tooltip::text("Create a channel"))
-                    .into_any_element(),
-            ),
+            Section::Channels => {
+                Some(
+                    h_flex()
+                        .gap_1()
+                        .child(
+                            IconButton::new("filter-active-channels", IconName::ListFilter)
+                                .toggle_state(self.filter_active_channels)
+                                .when(!self.filter_active_channels, |button| {
+                                    button.visible_on_hover("section-header")
+                                })
+                                .on_click(cx.listener(|this, _, _window, cx| {
+                                    this.filter_active_channels = !this.filter_active_channels;
+                                    this.update_entries(true, cx);
+                                }))
+                                .tooltip(Tooltip::text(if self.filter_active_channels {
+                                    "Show All Channels"
+                                } else {
+                                    "Show Active Channels"
+                                })),
+                        )
+                        .child(
+                            IconButton::new("add-channel", IconName::Plus)
+                                .on_click(cx.listener(|this, _, window, cx| {
+                                    this.new_root_channel(window, cx)
+                                }))
+                                .tooltip(Tooltip::text("Create a channel")),
+                        )
+                        .into_any_element(),
+                )
+            }
             _ => None,
         };