feat: add server-side search and pagination for groups page#27271
Open
aqandrew wants to merge 7 commits into
Open
feat: add server-side search and pagination for groups page#27271aqandrew wants to merge 7 commits into
aqandrew wants to merge 7 commits into
Conversation
Add a paginated, server-side searchable groups endpoint and wire the
organization Groups page to it, matching the organization Members page
pattern (useSearchParams + usePaginatedQuery + useFilter with a
presentational view rendering Filter + PaginationContainer).
- database: new PaginatedOrganizationGroups query with COUNT(*) OVER(),
deterministic ORDER BY LOWER(name), OFFSET/LIMIT. dbauthz wrapper does a
single org-wide ActionRead check (no post-filter) to keep LIMIT/OFFSET and
the count consistent, mirroring PaginatedOrganizationMembers.
- codersdk: PaginatedGroupsResponse + GroupsPaginated client method.
- searchquery: minimal Groups(q) parser for free-text search.
- enterprise: paginatedGroups handler + /organizations/{organization}/paginated-groups route.
- frontend: getOrganizationPaginatedGroups API, paginatedGroupsByOrganization
query, GroupsFilter (search-only), GroupsPageView filter + pagination,
updated stories.
The legacy /groups endpoint and its post-filter are left untouched.
Generated with Coder Agents.
Docs preview📖 View docs preview for |
…onMembersPageView
…oups-search-pagination
Gate the Create group button on the canCreateGroup prop the container already passes, instead of re-deriving permissions via useGroupsSettings + organizationsPermissions inside the view. Calling useGroupsSettings coupled the presentational view to GroupsPageContext, which threw "useGroupsSettings should be used inside of GroupsPageContext" in Storybook.
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.
URL path: /organizations/:organization/groups
The main purpose of this PR is to add a search field and pagination controls to the groups page (DEVEX-434). To be able to add pagination, Coder Agents created a new paginated API endpoint to use when querying groups. All of the Go/SQL code is agent-generated--I gave it as close a look as I could as a frontend developer but I would appreciate some extra scrutiny there. 😅 I can split this into smaller PRs if it's easier
I also moved the "Create group" button down from
GroupsPageintoGroupsPageView, to keep visually consistent with the "Add users" button on the members page.See Storybook for what pagination looks like:
agent output below:
Summary
Adds a server-side, searchable, paginated groups endpoint and wires the
organization Groups page to it. This replaces the previous non-paginated
groupsByOrganizationfetch and matches the established organization Memberspage pattern: a container wires
useSearchParams+usePaginatedQuery+useFilter, and a presentational view renders<Filter>+<PaginationContainer>purely from props.Resolves DEVEX-434.
Changes
Database (OSS
coderd/database/)PaginatedOrganizationGroupsquery: reuses theGetGroupsorg/searchfilters and adds
COUNT(*) OVER(), deterministicORDER BY LOWER(name),and
OFFSET/LIMIT. Regenerated querier/mock/metrics.dbauthzwrapper authorizespolicy.ActionReadonrbac.ResourceGroup.InOrg(orgID)once, with no per-row post-filter,mirroring
PaginatedOrganizationMembers. This is required for SQLLIMIT/OFFSET+COUNT(*) OVER()to stay consistent, and is consistent withthe frontend already gating the whole page on the org-level
viewGroupspermission. The legacy
GetGroupspost-filter is left untouched.codersdk (
codersdk/groups.go)PaginatedGroupsResponse { Groups []Group; Count int }GroupsPaginated(ctx, orgID, UsersRequest)hitting/api/v2/organizations/{org}/paginated-groups.searchquery (
coderd/searchquery/search.go)Groups(q)parser (free-textSearchonly, rejects key:valuefilters via
ErrorExcessParams).Enterprise (
enterprise/coderd/)paginatedGroupshandler enriching each page group with members + totalcount, and the new route registered as a sibling of the existing groups
routes so it inherits the same license/entitlement middleware.
Frontend (
site/src/)getOrganizationPaginatedGroupsAPI + augmented response type keeping theoptional
ai_cost_controlfield.paginatedGroupsByOrganizationpaginated query.GroupsFiltersearch-only filter wrapper.GroupsPagecontainer now usesusePaginatedQuery+useFilter;GroupsPageViewrenders the filter above the table inside aPaginationContainer.stories).
Out of scope
GET /groupsendpoint andgroupsByUserIdInOrganizationstay onthe non-paginated query.
Verification
make gen,make fmt,make lint(via pre-commit) clean.go test ./enterprise/coderd/ -run TestPaginatedGroups(search filtering,page boundaries,
Count) passes.tscclean; biome lint clean.GroupsPageViewstories (12) pass, including the search-fieldand pagination-widget assertions.
Implementation plan (DEVEX-434)
Note: the plan referenced hand-editing
coderd/database/dbmem/dbmem.go, butdbmemhas since been removed from the repo (commit3c2f3d640b), so thatstep was obsolete and skipped; tests run against a real database. The plan's
GroupsPageView.tsxTODO placeholders were also already gone.The endpoint uses an org-wide
ActionReadauthorization check (no post-filter)to keep SQL
LIMIT/OFFSET+COUNT(*) OVER()consistent, mirroringPaginatedOrganizationMembers. See the PR summary for the full breakdown.Generated with Coder Agents.