CMS: Create shared FilterOptions component to use throughout overviews#1794
Open
johan-bell wants to merge 8 commits into
Open
CMS: Create shared FilterOptions component to use throughout overviews#1794johan-bell wants to merge 8 commits into
johan-bell wants to merge 8 commits into
Conversation
The same search-box + group-multiselect + responsive mobile/desktop filter bar was independently reimplemented across five overview pages, some as inline markup, some as separate Mobile/Desktop file pairs. Add one shared component: search (with optional debounce), an optional group filter with removable tag chips, and a slot for page-specific extra filters. Not a fit for ContentOverview, which has enough extra dimensions (status, translation, tags, sort, a min-length search) to warrant its own dedicated filter panel.
Replaces ~130 lines of inline desktop/mobile filter markup with the shared component. No behavior change.
Same ~130-line duplicate filter bar as AuthProviderOverview, plus one extra control (the auth-provider select) wired through the extra-filters slot. No behavior change.
Removes UserFilterOptions.vue and its Mobile/Desktop pair (232 lines) in favor of the shared component; UserOverviewQueryOptions moves inline since it was only consumed here. Search debounce (500ms) is now owned by FilterOptions' debounceMs prop. Behavior-equivalent coverage moves to FilterOptions.spec.ts.
Removes GroupFilterOptions.vue and its Mobile/Desktop pair (206 lines) in favor of the shared component. Group-specific fields (orderBy, orderDirection) stay owned by GroupOverview's own resetQueryOptions, wired through FilterOptions' reset event.
…tions Redirect only had a bare debounced search box (no group filter); swaps it for FilterOptions in search-only mode (groups prop omitted), which also picks up a reset button Redirect didn't previously have.
Lets a page reuse just the responsive shell (desktop row / mobile Adjustments-button-and-modal / reset wiring) without adopting the built-in search-debounce or group-filter/chip behavior: the search slot replaces the built-in input entirely, selected-filters renders a page-owned chip list in the same below-the-row spot the built-in group chips use. The search model becomes optional (default "") since a page using the search slot has no reason to bind it.
…shell Removes FilterOptionsDesktop.vue and FilterOptionsMobile.vue (161 lines); their content moves into the shared component's search / extra-filters / extra-filters-mobile / selected-filters slots. ContentOverview.vue's own props/model contract is unchanged. All filter logic (status, translation, tags, sort, the min-length Enter/Esc search) is untouched — only which component renders the responsive shell changes.
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.
Closes #1266, #1795
What
The same filter bar — search box, optional group multi-select with removable tag chips, and a responsive mobile/desktop layout — was independently reimplemented five times across the CMS's overview pages:
AuthProviderOverview.vue/AutoGroupMappingOverview.vue— inlined directly in the page (~130 near-identical lines each)UserFilterOptions.vue+ its ownUserFilterOptionsMobile.vue/UserFilterOptionsDesktop.vuepairGroupFilterOptions.vue+ its ownGroupFilterOptionsMobile.vue/GroupFilterOptionsDesktop.vuepairRedirectOverview.vue— a simpler bare search box (no group filter)Added one shared
cms/src/components/common/FilterOptions.vue:search/selectedGroupsv-models, an optionaldebounceMs, and anextra-filtersslot (rendered inline on desktop and inside the mobile filter modal — with an optionalextra-filters-mobileoverride) for page-specific controls like AutoGroupMapping's auth-provider select. All five pages above now use it; the old bespoke components are deleted.ContentOverview (#1795)
ContentOverview/FilterOptions.vuewas initially left untouched — its filter panel has enough extra dimensions (status, translation, tags, sort) and a fundamentally different search interaction (min-3-character + explicit "Go" button + separate "X" clear, vs. everywhere else's auto-debounce) that folding it into the same behavior wasn't a drop-in fit.Rather than generalizing the shared component's behavior to match Content (a
searchModeprop, as originally proposed in #1795), it turned out cleaner to reuse just its shell:#searchslot — when provided, replaces the built-in debounced search input entirely. Thesearchmodel is now optional (default"") since a page using this slot has no reason to bind it.#selected-filtersslot — renders a page-owned chip list in the same below-the-row spot the built-in group-filter chips use.extra-filters/extra-filters-mobilenow carry all of Content's filter dimensions, including its own group filter — the shared component's built-in group filter/chips are unused for this page.ContentOverview/FilterOptions.vuekeeps 100% of its existing filter logic (status/translation/tags/sort state, the min-length Enter/Esc search, sessionStorage persistence) — only the component rendering the responsive shell changes.ContentOverview.vue's own props/model contract is untouched.FilterOptionsDesktop.vue/FilterOptionsMobile.vueare deleted.Net effect
-838 deleted / +51 modified (5-page migration) + the shell-slot extension and Content migration = large net reduction while removing all six duplicated filter-bar implementations.
No behavior change on any page, other than: Redirect and AuthProvider/AutoGroupMapping now get a reset button consistently (Redirect didn't have one before); User's and Redirect's search debounce is now owned by the shared component's
debounceMsprop instead of hand-rolleddebouncedWatchin each page.Tests
cms/src/components/common/FilterOptions.spec.ts(12 tests): group filter visibility, debounced vs. immediate search commit, tag removal, reset, mobile layout + modal, extra-filters slot (incl. mobile fallback), thesearch/selected-filtersslot overrides.GroupOverview.spec.ts,UserOverview.spec.ts,RedirectOverview.spec.ts,ContentOverview.spec.tsall pass unmodified against the migrated pages.AuthProviderOverview.vueandAutoGroupMappingOverview.vuehave no dedicated spec files (pre-existing gap, not introduced here) — recommend a manual pass on both filter bars before merge.Full cms suite: 932/932 passing.
npm run lintandnpm run type-checkclean.