Skip to content

fix(api,ui-react): public keys search across all pages#6384

Merged
gustavosbarreto merged 2 commits into
masterfrom
fix/api-ui-react/public-key-filter
May 28, 2026
Merged

fix(api,ui-react): public keys search across all pages#6384
gustavosbarreto merged 2 commits into
masterfrom
fix/api-ui-react/public-key-filter

Conversation

@luizhf42

Copy link
Copy Markdown
Member

What

The public keys search box now finds matches across all server pages instead of only the page currently in view.

Why

The React UI was already sending a filter query parameter on GET /api/sshkeys/public-keys (the same shape /devices uses), but the API handler bound only Paginator and silently dropped the filter. The page then ran a client-side .filter() over the 10 rows the server returned, so searches for a name or fingerprint living on page 2+ returned nothing.

Changes

  • api: ListPublicKeys request now embeds query.Filters; the handler runs Unmarshal + ValidateFilters against a new PublicKeyFilterFields registry that restricts the filter to contains/eq/ne on name and fingerprint; the service appends Options().Match to the store call. The generic store Match already supports this without per-entity wiring, and the existing service test was updated to expect the third QueryOption.
  • ui-react: usePublicKeys accepts a search param and forwards buildPublicKeyFilter(search) to the filter query param. The page debounces the input (300ms), drops the old client-side .filter() block, and resets to page 1 in the SearchField onChange handler so a new search always starts from the first page of results.

Testing

  • Seed >10 keys in a namespace and search for a fragment that matches keys on page 2+. Pre-fix: zero hits while viewing page 1. Post-fix: all matches surface and the pager footer reflects the filtered total.
  • Search by a fingerprint fragment — same behavior, since the registry covers both fields.
  • Clear the search — the full paginated list is restored.
  • Delete the last key on page > 1 while filtered — the existing empty-page back-step still works.

The React UI was already sending a base64-encoded `filter` query
parameter on `/api/sshkeys/public-keys`, but the handler only bound
`Paginator` and silently dropped it. As a result client-side
`.filter()` on each 10-row page only matched keys already visible.

Embed `query.Filters` in the request, define `PublicKeyFilterFields`
restricting the filter to `contains`/`eq`/`ne` on `name` and
`fingerprint`, and wire `Options().Match` into the store call.
@luizhf42 luizhf42 requested review from a team as code owners May 27, 2026 19:53
@luizhf42 luizhf42 self-assigned this May 27, 2026
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Claude finished @luizhf42's task in 1m 3s —— View job


Code Review Complete

Reviewed 6 files across code quality, security, testing, Go/TypeScript patterns, and architecture — 1 issue found.

Bug: onboarding empty state shown on zero-result search

ui-react/apps/console/src/pages/public-keys/index.tsx:217 (high)

The guard if (!isLoading && publicKeys.length === 0) doesn't distinguish "no keys exist in the namespace" from "a search returned no results." Before this PR, filtering was client-side so publicKeys always held the full server page and this guard was safe. Now that filtering is server-side, a search that matches nothing returns publicKeys = [], which triggers the full "Add your first key" onboarding splash screen instead of the DataTable's "No keys matching …" message. The search field is also not rendered in the onboarding branch, so the user can't clear the search without reloading.

Fix — add && !debouncedSearch to the guard (debouncedSearch is already in scope at line 95):

- if (!isLoading && publicKeys.length === 0) {
+ if (!isLoading && publicKeys.length === 0 && !debouncedSearch) {

Fix this →


If you've addressed the feedback and want a new review, tag @shellhub-io/admin and a team member can trigger it.

@luizhf42 luizhf42 added kind/feature New feature or request area/ui area/api labels May 27, 2026
Forward the search input to the new `filter` query parameter on the
public keys list endpoint with a 300ms debounce, and drop the
client-side `.filter()` block that only matched keys on the current
page. Searching now surfaces matches across all server pages, and the
pager footer reflects the filtered total.
@luizhf42 luizhf42 force-pushed the fix/api-ui-react/public-key-filter branch from 501da4d to 9c25060 Compare May 27, 2026 20:02
@luizhf42

Copy link
Copy Markdown
Member Author

Bug: onboarding empty state shown on zero-result search

ui-react/apps/console/src/pages/public-keys/index.tsx:217 (high)

The guard if (!isLoading && publicKeys.length === 0) doesn't distinguish "no keys exist in the namespace" from "a search returned no results." Before this PR, filtering was client-side so publicKeys always held the full server page and this guard was safe. Now that filtering is server-side, a search that matches nothing returns publicKeys = [], which triggers the full "Add your first key" onboarding splash screen instead of the DataTable's "No keys matching …" message. The search field is also not rendered in the onboarding branch, so the user can't clear the search without reloading.

FIxed. Added !debouncedSearch to the guard.

@gustavosbarreto

Copy link
Copy Markdown
Member

/review

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Claude finished @gustavosbarreto's task in 5m 52s —— View job


Code Review Complete

Reviewed 6 files across code quality, security, testing, Go/TypeScript patterns, and architecture — no issues found.

The implementation cleanly follows established patterns:

  • API: Filter handling (UnmarshalValidateFiltersMatch) mirrors the existing device endpoint, with proper field/operator allowlisting via PublicKeyFilterFields.
  • Frontend: buildPublicKeyFilter follows the same structure as buildFilter in useDevices.ts. Debounce, page reset on search, and the !debouncedSearch onboarding guard are all correct.
  • Cross-repo: The pkg/api/requests/publickey.go change (embedding query.Filters in ListPublicKeys) has no impact on the cloud repo — ListPublicKeys is not used there, and PublicKeyList uses variadic QueryOption which is backward-compatible.
  • Tests: Service test mocks correctly updated for the additional Match query option.

If you push additional changes and want a new review, tag @shellhub-io/admin and a team member can trigger it.


@gustavosbarreto gustavosbarreto merged commit 207eae5 into master May 28, 2026
12 checks passed
@gustavosbarreto gustavosbarreto deleted the fix/api-ui-react/public-key-filter branch May 28, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants