Skip to content

feat: Render static value list filter inputs - #3022

Open
pulpdrew wants to merge 1 commit into
drew/accept-static-value-filtersfrom
drew/show-static-filter-values
Open

feat: Render static value list filter inputs#3022
pulpdrew wants to merge 1 commit into
drew/accept-static-value-filtersfrom
drew/show-static-filter-values

Conversation

@pulpdrew

@pulpdrew pulpdrew commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR extends support for static custom value filters (introduced in #3017) by showing such filters in the UI and exposing selected options as variables.

Followup work includes:

  1. Allowing the user to create and edit static value list filters on the UI
  2. Support static value list filters in MCP (dependent on variable support in MCP feat: Support dashboard variables in MCP server #2951)

Screenshots or video

Screenshot 2026-08-28 at 2 59 41 PM Screenshot 2026-08-28 at 3 01 07 PM

How to test locally

  • Add a static type filter to a dashboard using the import below (or the API)
  • Validate that the dropdown and values for the filter appear in the UI, and that selected values are passed down to consuming charts.
Importable Dashboard
{
  "version": "0.1.0",
  "name": "Test Static Filters",
  "tiles": [
    {
      "id": "bd61ewiiu2fs52pkhwe9u",
      "x": 0,
      "y": 10,
      "w": 8,
      "h": 10,
      "config": {
        "name": "",
        "source": "Logs",
        "displayType": "line",
        "granularity": "auto",
        "alignDateRangeToGranularity": true,
        "select": [
          {
            "aggFn": "count",
            "aggCondition": "",
            "aggConditionLanguage": "lucene",
            "valueExpression": ""
          }
        ],
        "where": "",
        "whereLanguage": "lucene"
      }
    },
    {
      "id": "hmlgrh1me14q19ewy9pci",
      "x": 8,
      "y": 10,
      "w": 8,
      "h": 10,
      "config": {
        "name": "",
        "source": "Demo Logs",
        "displayType": "line",
        "granularity": "auto",
        "alignDateRangeToGranularity": true,
        "select": [
          {
            "aggFn": "count",
            "aggCondition": "",
            "aggConditionLanguage": "lucene",
            "valueExpression": ""
          }
        ],
        "where": "",
        "whereLanguage": "lucene"
      }
    },
    {
      "id": "7jwjomsz0pdmigm0kyorgp",
      "x": 0,
      "y": 0,
      "w": 9,
      "h": 10,
      "config": {
        "displayType": "table",
        "granularity": "auto",
        "alignDateRangeToGranularity": true,
        "configType": "sql",
        "sqlTemplate": "SELECT $env",
        "connection": "Local ClickHouse",
        "source": "Logs",
        "name": "Selected $env values"
      }
    }
  ],
  "filters": [
    {
      "id": "6a91d80f1e4e008c07f1c411",
      "name": "ServiceName (Traces)",
      "type": "QUERY_EXPRESSION",
      "expression": "ServiceName",
      "source": "JSON Traces"
    },
    {
      "id": "6a91d7081e4e008c07f1c265",
      "name": "Environment",
      "variableName": "env",
      "type": "STATIC_LIST",
      "options": [
        "dev",
        "staging",
        "prod"
      ],
      "isBroadcastEnabled": false,
      "isVariableEnabled": true
    },
    {
      "id": "6a91d7af1e4e008c07f1c35d",
      "name": "Status (Traces)",
      "type": "QUERY_EXPRESSION",
      "expression": "StatusCode",
      "source": "JSON Traces"
    },
    {
      "id": "7ca33140-cdfc-4434-bd29-62782c7aa3b0",
      "name": "Severity",
      "variableName": "Severity",
      "type": "QUERY_EXPRESSION",
      "expression": "SeverityText",
      "source": "Demo Logs",
      "appliesToSourceIds": [
        "Demo Logs",
        "Demo Traces"
      ],
      "isBroadcastEnabled": true,
      "isVariableEnabled": true
    }
  ],
  "containers": []
}

References

  • Linear Issue: Related to HDX-5059
  • Related PRs:

@changeset-bot

changeset-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 24da881

The changes in this PR will be included in the next version bump.

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

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

@vercel

vercel Bot commented Aug 28, 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 28, 2026 6:12pm
hyperdx-storybook Ready Ready Preview Aug 28, 2026 6:12pm

Request Review

@greptile-apps

greptile-apps Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR displays static-list dashboard filters, preserves their authored option order, and exposes selected values to tiles as variables.

  • Combines queried and static filter-option providers behind one hook.
  • Renders all supported dashboard filters while limiting linked-filter controls to queried filters.
  • Adds unit and full-stack coverage for static options, variable propagation, ordering, and URL persistence.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
packages/app/src/DashboardFilters.tsx Renders queried and static filters through the merged values hook, preserves static option order, and keeps linking limited to queried filters.
packages/app/src/hooks/useDashboardFilterValues.tsx Splits filters by type, merges their value maps, and prevents empty queried-filter loading state from affecting static-only dashboards.
packages/app/src/hooks/useStaticDashboardFilterValues.tsx Exposes static options synchronously with stable non-loading and non-error state.
packages/app/src/components/VirtualMultiSelect/VirtualMultiSelect.tsx Adds an opt-out from alphabetical sorting so authored static-list order can be retained.
packages/app/tests/e2e/features/dashboard-static-filters.spec.ts Covers authored option order, tile variable filtering, and URL-backed selection persistence.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  D[Dashboard filter definitions] --> T{Filter type}
  T -->|Query expression| Q[Query available values]
  T -->|Static list| S[Use authored options]
  Q --> M[Merged values by filter ID]
  S --> M
  M --> U[Dashboard filter dropdown]
  U --> V[URL-backed selection]
  V --> C[Chart variable]
  C --> R[Tile query rendering]
Loading

Reviews (2): Last reviewed commit: "feat: Display static value filters" | Re-trigger Greptile

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

E2E Test Results

All tests passed • 326 passed • 1 skipped • 1013s

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

Tests ran across 4 shards in parallel.

View full report →

};

/** Dropdown values for a dashboard's filters. */
export function useDashboardFilterValues({

@pulpdrew pulpdrew Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The intention is that this will be a "router" hook that partitions filters by type, delegates to type-specific hooks that fetch values for the type, and then merges the results.

This should make it more straightforward to add new filter types in the near future.

@pulpdrew
pulpdrew marked this pull request as ready for review August 28, 2026 19:05
@github-actions github-actions Bot added the review/tier-2 Low risk — AI review + quick human skim label Aug 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔵 Tier 2 — Low Risk

Small, isolated change with no API route or data model modifications.

Why this tier:

  • Standard feature/fix — introduces new logic or modifies core functionality

Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns.
SLA: Resolve within 4 business hours.

Stats
  • Production files changed: 4
  • Production lines changed: 149 (+ 265 in test files, excluded from tier calculation)
  • Branch: drew/show-static-filter-values
  • Author: pulpdrew

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

@github-actions

Copy link
Copy Markdown
Contributor

Deep Review

✅ No critical issues found. This is a small, well-tested, cleanly-typed change; the router-hook design matches the reviewer intent raised on the PR, and prior feedback is addressed. The items below are recommendations and nits.

🟡 P2 -- recommended

  • packages/app/src/components/VirtualMultiSelect/VirtualMultiSelect.tsx:106 -- Reusing the free-text-capable VirtualMultiSelect for STATIC_LIST filters lets a user type any value and press Enter to select it, so the authored option list does not actually constrain the value that becomes $variableName.
    • Fix: Add a prop to disable the Enter-to-add-arbitrary-value path and set it for static-list filters so only authored options can be selected.
  • packages/app/src/hooks/useDashboardFilterValues.tsx:72 -- The router forwards erroredFilterIds, filterErrorMessages, and isError only from the queried delegate, and neither delegate declares the shared DashboardFilterValuesResult type, so a future filter type that can error would have its errors silently dropped -- undercutting the "easy to add filter types" goal of this abstraction.
    • Fix: Annotate both delegate hooks with the exported DashboardFilterValuesResult type and merge the error/loading fields uniformly across delegates.
    • maintainability, kieran-typescript
  • packages/app/src/DashboardFilters.tsx:257 -- The link-toggle visibility gate changed from filters.length >= 2 to linkableFiltersCount >= 2 (now excluding static filters), but no unit test exercises this new branch and the e2e uses a single static filter.
    • Fix: Add a DashboardFilters render test asserting the toggle is hidden for two static filters and shown for two queried filters.
🔵 P3 nitpicks (5)
  • packages/app/src/components/VirtualMultiSelect/VirtualMultiSelect.tsx:195 -- Duplicate authored options render as separate rows that share one value and toggle together; nothing de-dupes and the schema permits duplicates.
    • Fix: De-dupe options preserving first-seen order in useStaticDashboardFilterValues, or add a uniqueness refinement to StaticListDashboardFilterSchema.
    • correctness, adversarial
  • packages/app/src/components/VirtualMultiSelect/VirtualMultiSelect.tsx:49 -- With sort=false the memo returns the caller's data array by reference (for static filters this is filter.options), a latent aliasing hazard if that array is ever mutated in place.
    • Fix: Return [...data] in the unsorted branch, matching the copy the sorted branch already makes.
  • packages/app/src/DashboardFilters.tsx:229 -- A persisted static selection that is no longer among the filter's current options (after an API edit) stays selected and keeps driving $variableName.
    • Fix: Intersect a static filter's persisted selection with its current options when hydrating, or visibly surface the orphaned value.
  • packages/app/src/hooks/useStaticDashboardFilterValues.tsx:14 -- The { values, isLoading } entry shape and the stable-empty Map/Set constants are re-declared here despite already existing in sibling filter-value hooks.
    • Fix: Extract and reuse a shared FilterValueEntry type and shared empty constants.
    • kieran-typescript, maintainability
  • packages/app/src/components/VirtualMultiSelect/VirtualMultiSelect.tsx:49 -- The new sort prop has no component-level test; order preservation is covered only by the @full-stack e2e.
    • Fix: Add a unit test asserting sort={false} preserves order and the default sorts alphabetically.
    • testing, correctness, kieran-typescript, project-standards

Agent-native note: This PR introduces no parity gap -- reading static options and selecting values already work over MCP (via the serialization schema and #2951 variable support). When followup work adds a create/edit UI, saveDashboard's MCP filter schema (packages/api/src/mcp/tools/dashboards/schemas.ts, currently restricted to QUERY_EXPRESSION) must be lifted to include STATIC_LIST in the same change to keep authoring at parity.


Reviewers (10): correctness, adversarial, testing, maintainability, project-standards, kieran-typescript, julik-frontend-races, agent-native, learnings-researcher, previous-comments.

Testing gaps:

  • No unit test for an empty static list (options: []) or for duplicate options.
  • No test for a mixed dashboard where a queried filter is still loading while a static filter must stay non-loading.
  • No component-level test for the VirtualMultiSelect sort prop or the linkableFiltersCount link-toggle branch.

@pulpdrew pulpdrew changed the title feat: Display static value filters feat: Display static value list filters Aug 28, 2026
@pulpdrew pulpdrew changed the title feat: Display static value list filters feat: Render static value list filter inputs Aug 28, 2026
@pulpdrew
pulpdrew requested a review from teeohhem August 28, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/tier-2 Low risk — AI review + quick human skim

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant