Fix search in linked groups projects dropdown
What does this MR do and why?
Fixes a bug in the Linked Groups Projects dropdown (used when selecting projects from groups linked to a Security Policy Project) where searching for a project that wasn't in the first page of results returned no matches.
Bug
When a linked group contains more than 20 projects, searching for any project beyond the first 20 returns "No results" — even though the project exists.
Steps to reproduce (before the fix):
- Open a policy editor where the scope dropdown is backed by
LinkedGroupsProjectsDropdown(e.g. a linked group with ≥ 21 projects). - Type the name of a project that sits at position 21 or later in that group.
- The dropdown shows nothing.
Root cause
The underlying GraphQL query get_spp_linked_groups_projects.query.graphql has asymmetric pagination:
securityPolicyProjectLinkedGroups(first: 20, after: $after) { # paginated, has pageInfo
nodes {
projects(includeSubgroups: true, first: 20, search: $search, ids: $projectIds) {
# no cursor, no count, no pageInfo — capped at 20 per group
nodes { … }
}
}
pageInfo { … }
}The outer securityPolicyProjectLinkedGroups is paginated with pageInfo, but the inner projects is capped at first: 20 with no cursor, no count, and no pageInfo.
The component used the group-level hasNextPage to infer whether all projects were loaded:
// before
allProjectsLoaded() {
return !this.hasNextPage;
},
reactiveVariables() {
if (this.allProjectsLoaded) {
return this.pathVariable; // ← drops `search` entirely
}
return { ...this.pathVariable, search: this.searchTerm };
},When all linked groups fit in a single page (the common case), hasNextPage was false, so allProjectsLoaded became true, so the search variable was dropped from the Apollo query. The Apollo query therefore did not re-run when the user typed, and only client-side filtering over the initially loaded 20 projects ran — missing everything past the first 20.
Fix
Force allProjectsLoaded to always be false so the search term always flows through to the backend:
// after
allProjectsLoaded() {
return false;
},And simplified the now-redundant allProjectsCount computed (it was just projects.length).
Why this is the right fix, not something smarter: Because the query exposes no cursor and no count for projects within a group, the frontend genuinely has no way to know whether it has loaded "all" projects for a group. The safe default is to always treat search as server-side.
Minor tradeoff: The footer's "Scroll to load more items" info icon (show-info-icon="!allProjectsLoaded") now shows unconditionally when withProjectCount is enabled. This is mildly misleading in the "there really are no more items" case, but given the underlying query can't distinguish those states, it's the conservative choice and matches the truth for any group with > 20 projects.
References
Screenshots or screen recordings
| Before | After |
|---|---|
How to set up and validate locally
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Related to #562260 (closed)