Skip to content

feat: Persist and read variable-keyed filter state - #2964

Merged
pulpdrew merged 1 commit into
drew/name-based-var-statefrom
drew/name-based-var-state-2
Aug 26, 2026
Merged

feat: Persist and read variable-keyed filter state#2964
pulpdrew merged 1 commit into
drew/name-based-var-statefrom
drew/name-based-var-state-2

Conversation

@pulpdrew

@pulpdrew pulpdrew commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Part 2/2 in enabling variable-name-based dashboard filter state. This part updates the dashboard filter hooks to read and write state in the new variable-keyed format.

Why

Historically, dashboard filter selection state has been persisted (in the URL, dashboard documents, and exports) as keyed by the filter's expression, in the same format used by search-page filters. This has two problems:

  1. Filters that share an expression (eg. ServiceName from two different sources) must necessarily share a selection state despite being two dropdowns in the UI.
  2. Future "static custom values" filters will have no expression (since they're not queried) and thus would have no way to key their state

What

This change will persist dashboard filter selection state (that is, what values are selected in the filter's drop-down) based on the variableName of the filter, when it has one.

  • Existing expression-keyed filter state will be migrated on write. Existing URLs and saved filter states continue working.
  • Filters that are not variable-enabled continue being written in expression-keyed format
  • Variable-keyed state takes precedence over expression-keyed state, when both may apply to a single filter.

Screenshots or video

Updated banner showing URL state that doesn't correspond to the declared filters

Screenshot 2026-08-21 at 12 59 06 PM

How to test

  • Create a dashboard and add some filters. Make some of them variable enabled and some of them not
  • Select values for the filters
  • Try saving the default filter values, importing/exporting the dashboard, sharing the link, etc

Use a URL Decoder if you want to inspect the URL

References

  • Linear Issue: HDX-5052
  • Related PRs:

@changeset-bot

changeset-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 496e647

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes changesets to release 4 packages
Name Type
@hyperdx/common-utils Patch
@hyperdx/api Patch
@hyperdx/app Patch
@hyperdx/otel-collector Patch

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview Aug 26, 2026 11:29am
hyperdx-storybook Ready Ready Preview Aug 26, 2026 11:29am

Request Review

@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates dashboard filter selections toward variable-name-keyed persistence while retaining expression-keyed compatibility.

  • Resolves URL and saved filter entries to individual dashboard filters.
  • Writes variable-enabled selections under variable names and keeps legacy expression state where required.
  • Updates linked dropdown queries, ignored-filter warnings, preset dashboards, and regression coverage.

Confidence Score: 4/5

The PR is not yet safe to merge because linked filters with disjoint selections still cause dependent dropdowns to run without the required constraint.

The attempted intersection fix represents contradictory sibling selections as an empty inclusion set, while downstream predicate generation interprets that state as no condition and returns unfiltered dependent values.

Files Needing Attention: packages/app/src/hooks/useDashboardFilterValues.tsx and its linked-filter regression tests

Important Files Changed

Filename Overview
packages/app/src/hooks/useDashboardFilters.tsx Introduces per-filter selection resolution and variable-name-keyed persistence while retaining legacy expression handling.
packages/app/src/hooks/useDashboardFilterValues.tsx Adapts linked dropdown constraints to per-filter selections, but contradictory sibling selections still become an unconstrained lookup.
packages/app/src/DBDashboardPage.tsx Integrates the new filter-entry state and updates ignored-variable warnings.
packages/app/src/utils/queryParsers.ts Adds parsing support for the revised persisted filter-entry representation.
packages/app/tests/e2e/features/dashboard-filter-value-format.spec.ts Adds end-to-end coverage for variable-keyed persistence and compatibility behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[URL or saved filter entries] --> B[Resolve entries against dashboard filters]
  B --> C[Selection by filter ID]
  C --> D[Dashboard dropdowns]
  C --> E[Tile query filters and variables]
  C --> F[Persist variable-name or expression keys]
Loading

Fix all with Greploop Fix All in Claude Code Fix All in Conductor Fix All in Cursor Fix All in Codex

Reviews (10): Last reviewed commit: "feat: Persist and read variable-keyed fi..." | Re-trigger Greptile

Comment thread packages/app/src/hooks/useDashboardFilterValues.tsx
Comment thread packages/app/src/hooks/useDashboardFilters.tsx
Comment thread packages/app/src/DBDashboardPage.tsx
@pulpdrew pulpdrew changed the title Drew/name based var state 2 feat: Persist and read variable-keyed filter state Aug 21, 2026
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 315 passed • 1 skipped • 1221s

Status Count
✅ Passed 315
❌ Failed 0
⚠️ Flaky 1
⏭️ Skipped 1

Tests ran across 4 shards in parallel.

View full report →

@github-actions

Copy link
Copy Markdown
Contributor

🟡 Tier 3 — Standard

Introduces new logic, modifies core functionality, or touches areas with non-trivial risk.

Why this tier:

  • Diff size: 490 production lines changed (Tier 2 max: < 250)

Review process: Full human review — logic, architecture, edge cases.
SLA: First-pass feedback within 1 business day.

Stats
  • Production files changed: 7
  • Production lines changed: 490 (+ 1326 in test files, excluded from tier calculation)
  • Branch: drew/name-based-var-state-2
  • Author: pulpdrew

To override this classification, remove the review/tier-3 label and apply a different review/tier-* label. Manual overrides are preserved on subsequent pushes.

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Deep Review

Part 2/2 of the variable-keyed dashboard filter state migration. The change is well-structured, carries good inline documentation, and ships substantial unit + e2e coverage. No ship-blockers found. Two correctness edge cases around filters that share a SQL expression remain, both narrow and both introduced by this diff's new intersectSelections / rebuildEntries logic — safe to merge, but worth addressing or explicitly deferring.

✅ No critical issues found.

🟡 P2 -- recommended

  • packages/app/src/hooks/useDashboardFilterValues.tsx:79 -- intersectSelections collapses two non-empty disjoint sibling inclusions to an empty included set, which downstream key-value lookups read as "no inclusion constraint" (match all) rather than "match nothing".
    • Fix: Distinguish "both empty → unconstrained" from "non-empty but disjoint → match nothing" (e.g. carry a match-nothing sentinel) so a dependent third dropdown shows no options instead of every option.
    • correctness, testing, previous-comments
  • packages/app/src/hooks/useDashboardFilters.tsx:82 -- On the first post-migration edit of a plain filter, rebuildEntries re-resolves a variable-enabled sibling on the same expression off the just-written byExpression value, so an untouched sibling dropdown silently adopts the edited filter's new selection.
    • Fix: Resolve each variable-enabled filter against the pre-mutation parsed state (or the current selectionByFilterId) so a plain-filter edit cannot bleed into a sibling that shares its expression.
    • correctness

Reviewers (3): correctness, testing, previous-comments.

Testing gaps:

  • No test drives the disjoint (empty-intersection) branch of intersectSelections; the only sibling-intersection test uses overlapping sets.
  • No test guards the load-bearing rebuildEntries two-loop ordering for a variable-enabled filter colliding with a plain filter on the same expression in byExpression.

Comment thread packages/app/src/hooks/useDashboardFilterValues.tsx

@brandon-pereira brandon-pereira left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM: minor nit is that the spacing is not uniform on this warning (bottom spacing bigger than top, looks very noticeable in dark mode)

Image

MikeShi42
MikeShi42 previously approved these changes Aug 25, 2026
@pulpdrew
pulpdrew disabled auto-merge August 25, 2026 23:54
@pulpdrew
pulpdrew disabled auto-merge August 26, 2026 11:25
@pulpdrew
pulpdrew force-pushed the drew/name-based-var-state branch from 343abba to 754b5cd Compare August 26, 2026 11:26
@pulpdrew
pulpdrew force-pushed the drew/name-based-var-state-2 branch from a4cc2ed to 496e647 Compare August 26, 2026 11:26
@pulpdrew
pulpdrew merged commit 3ee6f38 into drew/name-based-var-state Aug 26, 2026
24 of 47 checks passed
Comment on lines +79 to +84
included:
a.included.size === 0
? b.included
: b.included.size === 0
? a.included
: new Set([...a.included].filter(v => b.included.has(v))),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Disjoint selections become unconstrained

When two sibling filters sharing an expression have disjoint non-empty selections, intersectSelections returns an empty inclusion set. Downstream predicate generation treats that set as no condition, causing the dependent dropdown to show unfiltered values instead of no matching values.

Knowledge Base Used: Dashboards and visualization

Fix in Claude Code Fix in Conductor Fix in Cursor Fix in Codex

kodiakhq Bot pushed a commit that referenced this pull request Aug 26, 2026
## Summary

Part 1/2 in enabling variable-name-based dashboard filter state. This part covers the types/schema changes and the MCP + API + Import paths.

### Why

Historically, dashboard filter selection state has been persisted (in the URL, dashboard documents, and exports) as keyed by the filter's expression, in the same format used by search-page filters. This has two problems:

1. Filters that share an expression (eg. ServiceName from two different sources) must necessarily share a selection state despite being two dropdowns in the UI.
2. Future "static custom values" filters will have no expression (since they're not queried) and thus would have no way to key their state

### What

This change will persist dashboard filter selection state (that is, what values are selected in the filter's drop-down) based on the variableName of the filter, when it has one.

- Existing expression-keyed filter state will be migrated on write. Existing URLs and saved filter states continue working.
- Filters that are not variable-enabled continue being written in expression-keyed format
- Variable-keyed state takes precedence over expression-keyed state, when both may apply to a single filter.

### Screenshots or video

### How to test

This will be easier to test on top of [PR 2/2](#2964)

- Create a dashboard and add some filters. Make some of them variable enabled and some of them not
- Select values for the filters
- Try saving the default filter values, importing/exporting the dashboard, sharing the link, etc
- Try editing the saved values through MCP + External API

### References



- Linear Issue: 
- Related PRs:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-3 Standard — full human review required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants