[UX] Search results "No results found" message should distinguish "no raw results" from "filters excluded all results" with a clear-filters action
Problem
When the user runs a search that returns results, then applies a repo or language filter in the side panel that excludes all matches, the results panel shows a bare "No results found" with no indication that the filters are the cause. The user can see the same message whether (a) the query genuinely matched nothing or (b) the query matched files but the active filters are excluding them. There's no quick way to recover from case (b) without remembering which filters are active and backtracking to the filter panel.
Background
packages/web/src/app/(app)/search/components/searchResultsPage.tsx:382-391:
{filteredFileMatches.length > 0 ? (
<SearchResultsPanel ... />
) : isStreaming ? (
<div>Searching...</div>
) : (
<div className="flex flex-col items-center justify-center h-full">
<p className="text-sm text-muted-foreground">No results found</p>
</div>
)}
filteredFileMatches is the post-filter list (derived from fileMatches via useFilteredMatches, which reads repos and langs URL query params). fileMatches is the raw search result. The current code collapses both cases into the same message because the page doesn't know whether the empty filteredFileMatches came from a query that matched nothing or from filters that excluded everything.
A separate, distinct message at searchResultsPage.tsx:354 ("No results") fires when the raw search returned 0 files. So we have two "empty" states with two messages, but the post-filter empty state doesn't tell the user that the filters are the culprit.
Current behavior
A user runs repo:github file:.ts$ (returns 5 files), then opens the filter panel and selects only the python language. The result panel goes blank with "No results found". The user wonders if the query is broken. They have to find the filter panel and clear the language filter manually. The filter panel is collapsed by default (controlled by filterPanelRef.current?.collapse()), so this can be a long round-trip.
Expected behavior
When the raw search returned matches but the filters excluded all of them:
- The empty-state message says "No results match the active filters" (or similar) instead of "No results found".
- A "Clear filters" button is rendered next to the message. Clicking it removes the
repos and langs URL query params and re-runs the search with all results visible.
When the raw search returned 0 files (the existing "No results" case), the message is unchanged — no filter-clearing affordance, since the filters couldn't have caused the empty result.
Proposed solution
- In
searchResultsPage.tsx, derive hasActiveFilters from the repos and langs URL query params (reuse useGetSelectedFromQuery from the filter panel; it's already wired up). When fileMatches.length > 0 AND filteredFileMatches.length === 0 AND hasActiveFilters, render a different empty state:
<div className="flex flex-col items-center justify-center h-full gap-3">
<p className="text-sm text-muted-foreground">No results match the active filters.</p>
<Button variant="outline" size="sm" onClick={onClearFilters}>
Clear filters
</Button>
</div>
-
onClearFilters removes repos and langs from the URL via router.replace(...) (the page already uses useRouter for the "load more" URL update). No re-fetch needed; React Query re-derives filteredFileMatches from the now-empty filter set.
-
The header bar's "No results" message at line 354 is unchanged — that case means the search itself returned nothing, and filters couldn't have caused it.
Alternatives considered
- Auto-clear filters when the user clicks "Clear filters" in the filter panel itself. Rejected: the filter panel already has a "clear" affordance per checkbox, but there's no single "clear all" button and no "no results match your filters" signal anywhere. The empty-state is the natural place to surface the "this is filterable" hint.
- Make the filter panel auto-expand when the user lands on a no-results-while-filtered state. Useful but bigger change. The empty-state button is the smaller fix.
- Show a tooltip on the "No results found" text that explains filters are active. Tooltips on empty states are easy to miss; a button is actionable.
Scope
- 1 file modified (
searchResultsPage.tsx).
- 1 new component or inline JSX for the empty state.
- 1 new test (or extend an existing one).
- No API, no schema, no migration.
Acceptance criteria
Backward compatibility
Pure UI change. No API, no schema, no behavior change for users who don't apply filters.
Risks
Minimal. The "Clear filters" button just removes URL query params — a well-trodden path in this codebase (the "load more" button on the same page already does similar URL manipulation).
[UX] Search results "No results found" message should distinguish "no raw results" from "filters excluded all results" with a clear-filters action
Problem
When the user runs a search that returns results, then applies a repo or language filter in the side panel that excludes all matches, the results panel shows a bare "No results found" with no indication that the filters are the cause. The user can see the same message whether (a) the query genuinely matched nothing or (b) the query matched files but the active filters are excluding them. There's no quick way to recover from case (b) without remembering which filters are active and backtracking to the filter panel.
Background
packages/web/src/app/(app)/search/components/searchResultsPage.tsx:382-391:filteredFileMatchesis the post-filter list (derived fromfileMatchesviauseFilteredMatches, which readsreposandlangsURL query params).fileMatchesis the raw search result. The current code collapses both cases into the same message because the page doesn't know whether the emptyfilteredFileMatchescame from a query that matched nothing or from filters that excluded everything.A separate, distinct message at
searchResultsPage.tsx:354("No results") fires when the raw search returned 0 files. So we have two "empty" states with two messages, but the post-filter empty state doesn't tell the user that the filters are the culprit.Current behavior
A user runs
repo:github file:.ts$(returns 5 files), then opens the filter panel and selects only thepythonlanguage. The result panel goes blank with "No results found". The user wonders if the query is broken. They have to find the filter panel and clear the language filter manually. The filter panel is collapsed by default (controlled byfilterPanelRef.current?.collapse()), so this can be a long round-trip.Expected behavior
When the raw search returned matches but the filters excluded all of them:
reposandlangsURL query params and re-runs the search with all results visible.When the raw search returned 0 files (the existing "No results" case), the message is unchanged — no filter-clearing affordance, since the filters couldn't have caused the empty result.
Proposed solution
searchResultsPage.tsx, derivehasActiveFiltersfrom thereposandlangsURL query params (reuseuseGetSelectedFromQueryfrom the filter panel; it's already wired up). WhenfileMatches.length > 0ANDfilteredFileMatches.length === 0ANDhasActiveFilters, render a different empty state:onClearFiltersremovesreposandlangsfrom the URL viarouter.replace(...)(the page already usesuseRouterfor the "load more" URL update). No re-fetch needed; React Query re-derivesfilteredFileMatchesfrom the now-empty filter set.The header bar's "No results" message at line 354 is unchanged — that case means the search itself returned nothing, and filters couldn't have caused it.
Alternatives considered
Scope
searchResultsPage.tsx).Acceptance criteria
reposandlangsURL query params and the panel re-renders with all raw matches visible.Backward compatibility
Pure UI change. No API, no schema, no behavior change for users who don't apply filters.
Risks
Minimal. The "Clear filters" button just removes URL query params — a well-trodden path in this codebase (the "load more" button on the same page already does similar URL manipulation).