Show active filters as removable chips with a full reset link#144
Open
loevgaard wants to merge 1 commit into
Open
Show active filters as removable chips with a full reset link#144loevgaard wants to merge 1 commit into
loevgaard wants to merge 1 commit into
Conversation
Applied filters now render as chips above the search results: clicking a chip's X removes that single filter, and a "Reset all filters" link clears every filter while keeping the query and sorting. The chips also render on the no-results page, where the filter form is gone, so users can un-filter their way back to results. Chips are computed server side from the request's `f` query parameters by the new ActiveFiltersProvider (exposed to templates via the `ssm_active_filters()` Twig function) and are plain links, so they work without JavaScript; search.js intercepts their clicks and reuses the existing fetch/swap/pushState flow. The search form prefills range inputs with the facet bounds and submits them on every interaction, so a range chip is only shown when a bound actually narrows the facet's stats. That required SearchEngine to merge facetStats across the disjunctive facet queries the same way it already merged facetDistribution — as a side effect, range inputs now prefill with bounds that exclude their own filter. Resolves #51
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #144 +/- ##
============================================
+ Coverage 37.92% 41.11% +3.18%
- Complexity 711 768 +57
============================================
Files 131 135 +4
Lines 2286 2403 +117
============================================
+ Hits 867 988 +121
+ Misses 1419 1415 -4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Resolves #51
What
Applied filters now render as chips above the search results, matching the mockup in the issue:
pushStateflow; the chips are plain links, so they degrade to full page loads without JavaScript).q), the sorting (s), and any unrelated query parameters.p).How
ActiveFiltersProvider(src/Provider/ActiveFilters/) computes the chips server side from the request'sfquery parameters. Filter types are resolved through the index metadata (the same source the form/filter builders use), and the value guards mirrorArrayFilterBuilder/BooleanFilterBuilder/FloatFilterBuilder, so a chip is only shown for a filter the engine would actually apply. Unknown facet names are skipped.ssm_active_filters()Twig function (SearchRuntime) and a newsearch/_active_filters.html.twigpartial, included inside#search-formin_results.html.twigand_no_results.html.twigso it is re-rendered on every AJAX swap.search.jsgains a shared#navigate(url)(extracted from#submitForm), a publicnavigate(), click delegation for the chip links (wired before the form check so it also works on the no-results<div>), newonFilterRemove/onFiltersResetoptions, and newsearch:filter-removed/search:filters-resetevents. All additive.active_filters.facet.*keys with a humanized fallback for untranslated custom facets; range chips read e.g. "Price: from 50". New translation keys added to all 12 locales.Behavior change: disjunctive facetStats
The range inputs are prefilled with the facet's bounds and submitted with every form interaction, so the URL always carries
f[price][min|max]even when the user never touched them — naively that would render a phantom "Price" chip after any interaction. A range chip is therefore only shown when a bound actually narrows the facet's stats.For that comparison to work,
SearchEngine::provideSearchResult()now mergesfacetStatsacross the disjunctive per-facet queries the same way it already mergesfacetDistribution(previously the stats came only from the fully-filtered main query, against which a user-set bound never registers as narrowing). Side effect: range inputs now prefill with bounds that exclude their own filter, which is the standard disjunctive faceting behavior.Notes for extenders
_results.html.twig/_no_results.html.twigkeep their current markup and can opt in with one include line; opting out with stock templates is overriding_active_filters.html.twigwith an empty file.ActiveFiltersProviderInterfaceis aliased, so chip computation can be decorated/replaced.f[onSale]=0) filters tofalsebut gets no chip — that state is unreachable through the shipped UI.Testing
SearchEngineTest(disjunctive stats merge) andActiveFiltersProviderTest(15 cases: choice/bool/range chips, narrowing suppression, invalid values, unknown facets, reset URL, taxon-style paths).ActiveFiltersProviderTestproves the wiring + real Meilisearch stats end to end, including the "prefilled bounds produce no chip" case.search.spec.ts(6 tests) covering chip rendering, removal, the phantom-price-chip guard, the no-results rescue, and reset keeping query + sorting.All suites pass locally: 66 unit, 13 functional, 20 e2e; PHPStan (level max), ECS, Rector,
lint:container,lint:twig,composer validate --strictandcomposer normalize --dry-runare clean.