fix(search): preserve incompatible filters as inactive when switching data sources#2360
fix(search): preserve incompatible filters as inactive when switching data sources#2360elizabetdev wants to merge 4 commits into
Conversation
Previously, swapping the active source on the search page silently dropped any filter whose field doesn't exist on the new source (e.g. SeverityText going from Logs to Traces) and surfaced a transient yellow toast. The selection — and the user's context for switching back — was lost. Now invalid filters stay visible in the ActiveFilterPills bar with a muted, strikethrough, dashed-border style and a tooltip explaining why they aren't applied. They're excluded from the rendered query so it stays valid, and re-apply automatically if the user switches back. - ActiveFilterPills: new optional invalidFields prop (with invalidFieldReason override for tooltip copy). - useSearchPageFilterState: new optional validFields input; exposes computed invalidFields and strips invalid keys at query-serialization time so UI state and URL stay decoupled. - DBSearchPage: pass current source columns as validFields and remove the imperative retainCompatibleFilters drop-on-source-change flow. Co-authored-by: Cursor <cursoragent@cursor.com>
- Changed the border style for invalid filters from a muted dashed line to a standard dashed line. - Adjusted the opacity of invalid filters from 0.55 to 0.75 for better visibility. These updates enhance the visual distinction of invalid filters in the ActiveFilterPills component, improving user experience when interacting with filter states.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: f68cdad The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🟡 Tier 3 — StandardIntroduces new logic, modifies core functionality, or touches areas with non-trivial risk. Why this tier:
Review process: Full human review — logic, architecture, edge cases. Stats
|
Co-authored-by: Cursor <cursoragent@cursor.com>
E2E Test Results✅ All tests passed • 192 passed • 3 skipped • 1295s
Tests ran across 4 shards in parallel. |
Deep ReviewScope: PR #2360 — preserve incompatible filters as inactive when switching data sources. ~250 changed non-test source lines across 3 files plus tests. 🔴 P0/P1 — must fix
🟡 P2 — recommended
🔵 P3 nitpicks (10)
Reviewers (10): correctness, testing, maintainability, project-standards, agent-native, learnings-researcher, kieran-typescript, julik-frontend-races, api-contract, adversarial. Testing gaps:
Note (pre-existing, not blocking): A user switching to a source whose |
The "Source switching — filter preservation" suite previously asserted that incompatible filters were dropped and a yellow toast appeared on source change. With the inactive-pill behavior, filters are now preserved as inactive (data-invalid="true") and the toast is gone. - Add `data-testid="active-filter-pill-<field>"` on each pill so page objects can locate them deterministically. - Add `getActiveFilterPill(field)` and `getInactiveFilterPill(field)` helpers on `SearchPage`; drop the obsolete `getDroppedFiltersToast`. - Rewrite the two affected tests to assert pill-inactive state + the filter being stripped from the URL. - Add a third test covering the round-trip reactivation when the user switches back to a compatible source. Co-authored-by: Cursor <cursoragent@cursor.com>
…2361) ## Summary Refreshes `ActiveFilterPills` so it can render filters that are present in state but not currently applied to the query (e.g. the column doesn't exist on the active source) in a clearly muted, "inactive" style — without changing any behavior for existing call sites. - **Inactive pill style**: dashed `--color-border-emphasis` border, transparent background, `0.75` opacity, strikethrough label/operator/value, and a multi-line tooltip explaining why the filter isn't applied (with an `invalidFieldReason` override hook). - **Excluded (`!=`) pill refresh**: now uses the `--color-bg-danger` / `--color-text-danger` design tokens instead of raw Mantine red, so the variant follows the theme. - **A11y / testability**: - `data-testid="active-filter-pill-<field>"` on every pill for deterministic E2E selection. - `data-invalid="true"` on inactive pills. - `aria-label="Remove filter"` on the close button. - **API**: two new _optional_ props on `ActiveFilterPills` — `invalidFields?: Set<string>` and `invalidFieldReason?: (field) => string`. Existing callers don't change. This PR is purely the component-level work. The feature wiring (search page state, query stripping, source-switch flow) lives in #2360, which is moved to draft for reference. <img width="857" height="175" alt="filters@2x" src="https://github.com/user-attachments/assets/9d597a58-1934-4eb3-b4bf-cc63f41ef706" /> ## Test plan - [ ] `yarn ci:unit` in `packages/app` still passes. - [ ] Visual check: with `invalidFields` passed in, pills render dashed / strikethrough / muted and the tooltip explains why. - [ ] Visual check: excluded (`!=`) pills still read as the "danger" variant via the new tokens. - [ ] Existing call sites (no `invalidFields` prop) behave identically to before. Made with [Cursor](https://cursor.com)
Summary
When the user switched the active source on the search page (e.g. Logs → Traces), any filter whose field doesn't exist on the new source was silently dropped. A transient yellow toast announced it, but the user's selection — and the context for switching back — was gone.
This PR keeps those filters visible in the
ActiveFilterPillsbar with a muted, strikethrough, dashed-border style and a tooltip explaining why they aren't applied. They're excluded from the rendered query so it stays valid, and re-apply automatically if the user switches back to a compatible source.Visual treatment
For an inactive pill:
0.75var(--color-border-emphasis))No yellow warning color / warning icon — nothing is broken, it's just informational. Yellow gets noisy when many filters become invalid at once.
API changes
ActiveFilterPills— new optional props:invalidFields?: Set<string>— fields whose pills should render in the inactive stateinvalidFieldReason?: (field: string) => string— override the tooltip copyuseSearchPageFilterState— new optionalvalidFields?: Set<string>input; exposes computedinvalidFields. Invalid keys are stripped at query-serialization time so UI state and URL stay decoupled.DBSearchPage— passes current source columns asvalidFieldsand removes the imperativeretainCompatibleFiltersdrop-on-source-change flow (and its toast notification).All colors and borders use semantic CSS vars (
--color-bg-danger,--color-text-danger,--color-border-emphasis, etc.) peragent_docs/themes.md.Test plan
SeverityTextfilter on a Logs source, switch to a Traces source. The pill should remain visible with a muted/strikethrough/dashed appearance. Tooltip should explain why.LogAttributes.user). It should be treated as valid as long as the root column exists.Clear allclears both active and inactive pills.yarn ci:unit(added/updated tests forActiveFilterPillsanduseSearchPageFilterState)Made with Cursor