Repository navigation
feat(groups): personal sections + search on /groups - #157
Merged
Merged
Conversation
mwoods79
added a commit
that referenced
this pull request
May 2, 2026
Fills the testing gaps flagged in PR #157: - LiveView: assert View-all link's actual href (not just text), and that it preserves the active search query - LiveView: search with no matches collapses both personal sections and shows the empty-state message - Resource: direct tests on :get_joined (returns joined groups, excludes owned groups, excludes unrelated groups, empty for users with no memberships) - GraphQL: joinedGroups query returns the right groups for the authenticated actor; empty for users with no memberships - Cucumber: feature for the headline flow (sections appear, anonymous users see no sections, View-all navigates to scoped view, search filters everything together)
Adds a read action that returns groups the actor has joined but does not own. Owners are filtered out so the action complements :get_by_owner without overlap (since owners are auto-added as members on creation). Exposed via domain wrapper, GraphQL (joined_groups), and JSON API at /groups/joined for parity with :get_by_owner.
Reworks /groups so authenticated users can quickly find their own groups without scanning the full directory. - Two personal sections at the top: "// Hosting" and "// Joined" rendered when the user has groups in that relationship - Each section caps at 6 cards and shows "View all →" when there are more, deep-linking to /groups?yours=hosting|joined - Search input (trigram similarity) filters all three queries in unison; clear control appears when query is non-empty - ?yours=hosting and ?yours=joined render a single full grid scoped to that relationship with a back link - Search query is preserved across the View all transition Hidden sections collapse cleanly: anonymous users and users with no relationships see the original directory layout unchanged.
Fills the testing gaps flagged in PR #157: - LiveView: assert View-all link's actual href (not just text), and that it preserves the active search query - LiveView: search with no matches collapses both personal sections and shows the empty-state message - Resource: direct tests on :get_joined (returns joined groups, excludes owned groups, excludes unrelated groups, empty for users with no memberships) - GraphQL: joinedGroups query returns the right groups for the authenticated actor; empty for users with no memberships - Cucumber: feature for the headline flow (sections appear, anonymous users see no sections, View-all navigates to scoped view, search filters everything together)
The :hosting and :joined scopes returned a literal "You aren't hosting any groups yet." regardless of whether a search query was active, so a user who hosts groups but searched for something that doesn't match saw copy implying they host nothing. Empty copy now branches on the search query first; the per-scope copy only runs when there's no active search.8000
- scoped_path now produces a stable `?yours=&q=` parameter order matching view_all_path, so navigating between the search input and View all no longer flickers the URL ordering - read_groups logs an Ash.read failure at warning level instead of silently returning [], so a permission/policy regression surfaces in logs rather than as a mysteriously empty section - Renames apply_search/read_groups parameters to ash_query so the Ash.Query and the user search string don't share the name `query` - Comment on list_all explains the deliberate public-only filter - Pipe convention nit on normalize_query
Anonymous users hitting /groups?yours=hosting or ?yours=joined directly saw a "Groups You Host" page with an empty state — discoverable but nonsensical. Redirect to /sign-in with a flash explaining what they were trying to see. The /groups index itself stays public; only the personal-scoped views require auth.
mwoods79
force-pushed
the
feat/groups-personal-sections
branch
from
May 2, 2026 04:53
22b7b4c to
40f81b3
Compare
mwoods79
added a commit
that referenced
this pull request
May 2, 2026
Fills the testing gaps flagged in PR #157: - LiveView: assert View-all link's actual href (not just text), and that it preserves the active search query - LiveView: search with no matches collapses both personal sections and shows the empty-state message - Resource: direct tests on :get_joined (returns joined groups, excludes owned groups, excludes unrelated groups, empty for users with no memberships) - GraphQL: joinedGroups query returns the right groups for the authenticated actor; empty for users with no memberships - Cucumber: feature for the headline flow (sections appear, anonymous users see no sections, View-all navigates to scoped view, search filters everything together)
This was referenced May 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks
/groupsso authenticated users can find their own groups without scanning the full directory, and adds the search bar that was missing.What's new on
/groups// HOSTING (n)section — groups you own// JOINED (n)section — groups you belong to but don't own (owners are filtered out so they don't double-count, since owners are auto-added as members on creation)View all →when count > 6, deep-linking to/groups?yours=hostingor/groups?yours=joined:searchaction's behavior) filters all three queries in unisonView alllink preserves the active search via&q=?yours=...) render a single full grid with an← All groupsback link and a context-appropriate page titleAPI surface
Per the API-first principle: the new behavior is reachable as a real action.
:get_joinedread action onGroup— filters byexists(group_members, user_id == ^actor(:id)) and owner_id != ^actor(:id)Communities.get_joined_groupsjoined_groups/groups/joinedTrade-offs worth flagging
// HOSTINGand the// All Groupsgrid below. Standard pattern (Meetup, GitHub) and intentional: sections are a shortcut, not a filter.Out of scope
/huddlz— natural follow-up, would mirror this structure with "Hosting upcoming" and "Attending upcoming" sections. Time-bounded data so the sections cap themselves.Test plan
/groupsas anonymous — no personal sections, full directory grid, search input visible/groupslogged in with no relationships — same as anonymous (no// Hosting/// Joinedheadings)/groupslogged in as owner —// Hostingsection appears with your group; not duplicated under// Joined/groupslogged in as member of someone else's group —// Joinedsection appears with that group/groups?yours=hosting— single grid, page title "Groups You Host", back link works/groups?yours=joined— single grid, page title "Groups You've Joined"/groups—View all →link visible in// Hosting, navigates to/groups?yours=hostingView all— destination URL preserves&q=