Skip to content

feat(sonarqube): add "ALL" toggle for filtered remote scope search - #9282

Open
DoDiODev wants to merge 2 commits into
apache:mainfrom
DoDiODev:pr/sonarqube-search-select-all
Open

DoDiODev wants to merge 2 commits into
apache:mainfrom
DoDiODev:pr/sonarqube-search-select-all

Conversation

@DoDiODev

@DoDiODev DoDiODev commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When adding data scopes to a SonarQube connection (Connection → Add Data
Scope
), the search box only lets you pick the matching projects one by one.
With a few hundred projects sharing a prefix this is tedious.

This PR adds an "ALL" checkbox as the first entry of the search result
list. It selects or deselects all projects matching the search term, not
only the page that is currently loaded. The feature is opt-in per plugin and
is only switched on for SonarQube.

Backend (feat(sonarqube): return total count from search-remote-scopes)

  • DsRemoteApiScopeSearchHelper can now return the total number of matches
    as count in the search-remote-scopes response.
    • New function type DsSearchRemoteScopesWithCount and constructor
      NewDsRemoteApiScopeSearchHelperWithCount.
    • The existing NewDsRemoteApiScopeSearchHelper wraps its function and
      reports the total as unknown (-1). In that case count is omitted from
      the response. No other plugin changes; the response of all other
      plugins is unchanged.
    • DsRemoteApiScopeList documents the optional count field (Swagger).
  • SonarQube: querySonarqubeProjects also returns paging.total from
    api/components/search_projects, and the search endpoint uses the new
    constructor.

config-ui (feat(config-ui): add "ALL" toggle to the SonarQube remote scope search)

  • New optional plugin config flag dataScope.searchSelectAll, set to true
    for SonarQube only.
  • The "ALL" row is rendered via renderTitle of MillerColumnsSelect, so it
    sits inside the list, before the first item, and looks like a list item.
    The built-in showSelectAll of miller-columns-select is not used: it only
    covers the already loaded items and replaces the whole selection.
  • Behaviour of the checkbox:
    • Label shows the number of matches, e.g. ALL (237) (from count, or the
      list length once the whole result is loaded).
    • Tri-state: checked / indeterminate / unchecked. Scopes that already exist
      (disabled entries) are ignored.
    • If not all pages are loaded yet, a click loads the remaining pages first
      (spinner shown). With count the loop stops exactly at the last page;
      without it, it stops at the first short page. Limit: 100 pages × 100.
      If the limit is hit, a warning asks to refine the search.
    • Selection outside the current filter is always kept. Clicking again only
      removes the filtered entries.
    • If the search term changes while loading, the stale result is discarded.
  • Small fixes in search-remote.tsx: results are de-duplicated when the next
    page is appended, and the memoised disabledIds is reused.
  • API.scope.searchRemote: count is now typed as optional.

Question for reviewers

The new behaviour is opt-in and currently enabled for SonarQube only. Should
it become the default for all plugins with a remote search? That covers:

  1. Showing the number of matches behind the checkbox (ALL (n)), and
  2. Loading all pages of the search result when "ALL" is clicked, instead
    of acting only on the loaded items.

The helper extension is already generic. Each plugin would only need to
return the total from its search function (many remote APIs report it, for
example GitHub search total_count or Jira total; this would need to be
checked per plugin). Without a
total, the UI falls back to "load until a short page" and shows the count
only after everything is loaded. Plugins that use NewDsRemoteApiScopeSearchHelper
today: azuredevops_go, bamboo, bitbucket, bitbucket_server, circleci,
gh-copilot, github, gitlab, grafana_irm, incidentio, jira, pagerduty, rootly,
slack, sonarqube, tapd, teambition, tempo, testmo, trello.

If you agree, I would prefer a follow-up PR: drop the searchSelectAll flag
(or flip its default) and add count plugin by plugin. That keeps this PR
small. I'm also happy to change it here if you prefer.

Does this close any open issues?

N/A

Screenshots

Bild 29 10 26 um 14 15 Bild 29 10 26 um 14 17

Other Information

  • Backwards compatible: count is only added to the response when a plugin
    reports it; existing clients ignore unknown fields.
  • Tests:
    • Go: new unit tests for the helper (count present / omitted, legacy
      wrapper) and for querySonarqubeProjects (mocked ApiClient; checks
      paging.total, filter, p, ps).
    • config-ui: Vitest unit tests for the select-all helpers and component
      tests for the "ALL" row (15/15). tsc and eslint pass.
  • Fork CI on the same change (golangci-lint, unit-test, e2e on MySQL,
    config-ui, license header, Grafana check; 14/14 jobs green):
    https://github.com/DoDiODev/devlake/actions/runs/40840628487

Add an optional, non-breaking way for plugins to report the total number
of matching scopes in the search-remote-scopes response:

- helpers: new DsSearchRemoteScopesWithCount function type and
  NewDsRemoteApiScopeSearchHelperWithCount constructor. The existing
  NewDsRemoteApiScopeSearchHelper wraps legacy search functions with an
  unknown total (-1), so no other plugin needs to change.
- The response body contains "count" only if the plugin reports it.
- DsRemoteApiScopeList documents the optional count field.
- sonarqube: pass paging.total of api/components/search_projects through.

Signed-off-by: DoDiODev <DoDiDev@proton.me>
When searching remote scopes, an "ALL" entry is rendered as the first row
of the result list (same placement as showSelectAll of
miller-columns-select). It (de)selects every match of the current search:

- loads all remaining pages on demand, stopping at the backend-reported
  count or, for plugins without count, at the first short page
- keeps the selection outside of the filter and skips already added
  (disabled) scopes
- shows the number of matches, a tri-state checkbox and a warning if the
  page limit was reached
- discards results that arrive after the search query changed

The feature is opt-in via dataScope.searchSelectAll and only enabled for
SonarQube. Duplicates are removed when appending further search pages.

Signed-off-by: DoDiODev <DoDiDev@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant