Skip to content

feat: Add saved query support to dashboards#1584

Merged
kodiakhq[bot] merged 4 commits intomainfrom
tom/dashboard-filter-saves
Feb 25, 2026
Merged

feat: Add saved query support to dashboards#1584
kodiakhq[bot] merged 4 commits intomainfrom
tom/dashboard-filter-saves

Conversation

@teeohhem
Copy link
Copy Markdown
Contributor

@teeohhem teeohhem commented Jan 9, 2026

Fixes: HDX-1717

On the dashboard page, this PR adds:

  • An option in the ... dropdown to Save/update/delete default query/filters that will save the WHERE input filter, along with any filters applied to the dashboard via the custom filter functionality + ties it to the dashboard object itself. Future reloads of this dashboard will restore saved values.
CleanShot.2026-02-23.at.17.05.46.mp4
CleanShot.2026-02-23.at.17.09.41.mp4

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Jan 9, 2026

⚠️ No Changeset found

Latest commit: 41ea2c1

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 no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

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
Copy link
Copy Markdown

vercel Bot commented Jan 9, 2026

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

Project Deployment Actions Updated (UTC)
hyperdx-v2-oss-app Ready Ready Preview, Comment Feb 25, 2026 11:31pm

Request Review

@claude
Copy link
Copy Markdown

claude Bot commented Jan 9, 2026

PR Review: Add saved query support to dashboards

Overall Implementation: The feature is well-implemented with comprehensive E2E tests.

Issues Found:

  • Race condition in initialization (DBDashboardPage.tsx:729-745) → The useRef<string>(undefined) should be useRef<string | undefined>(undefined) to properly type-check against dashboard.id. Currently TypeScript may not catch issues where dashboard.id could be compared against the wrong type.

  • ⚠️ Missing dependency optimization (DBDashboardPage.tsx:746-757) → The useEffect depends on router.query which changes on every render. Consider using router.query.where and router.query.filters specifically, or use useMemo to stabilize the dependency.

  • ⚠️ Potential data loss pattern (packages/api/src/routers/api/dashboards.ts:84) → The change from _.isNil to _.isUndefined is correct for allowing null to clear fields, but ensure all callers understand this new behavior. Document this in code comments.

  • 🔍 Minor: Missing null check (DBDashboardPage.tsx:759-791) → handleSaveQuery accesses rawFilterQueries?.length correctly, but should also check if it is an empty array before setting to null: rawFilterQueries?.length > 0 ? rawFilterQueries : null

Recommendations:

  1. Add inline comment at line 84 explaining the _.isUndefined change for future maintainers
  2. Consider extracting the saved query restoration logic into a custom hook for better testability
  3. E2E tests are excellent - consider adding unit tests for the handleSaveQuery callback logic

Status: Approve with minor suggestions for follow-up.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jan 9, 2026

PR Review

  • ⚠️ _.isNil_.isUndefined in PATCH endpoint (packages/api/src/routers/api/dashboards.ts): This change allows null to pass through for all fields, not just the new saved query fields. If a client sends { name: null }, it could corrupt required fields. Consider explicitly whitelisting nullable fields or only applying the isUndefined behavior to the new savedQuery/savedFilterValues fields.

  • ⚠️ TypeScript type error: useRef<string>(undefined)string does not include undefined. Should be useRef<string | undefined>(undefined).

  • ⚠️ Potential stale state in handleSaveQuery: onSubmit() triggers async URL state updates (nuqs), but rawFilterQueries is read immediately after from URL state. The saved filter values will reflect the pre-submit URL state. For the where field this is fine (reads from form state via getValues()), but if a user updates filters and immediately clicks save without applying, the saved filter values may be stale.

  • ℹ️ No schema validation on new fields in PATCH handler: savedQuery, savedQueryLanguage, and savedFilterValues are accepted from req.body without Zod validation — consistent with the existing endpoint pattern, but worth addressing if the endpoint is ever hardened.


Generated by Claude Code

@elizabetdev
Copy link
Copy Markdown
Contributor

Hey @teeohhem,

I’d like to suggest moving the Save query and filters action into the global Dashboard ... menu.

Right now we have a mixed interaction model: the dashboard layout (tiles) autosaves, but query and filter inputs require a manual save via the floppy disk icon. This can be confusing.

Two main UX issues with the current placement:

  • Ambiguity: Seeing a save button near the inputs makes users question whether other changes (like moving tiles) were saved.
  • Mental model: Because the icon sits next to the query bar, it implies only the text input is saved, even though it also saves the filters below.

Moving this into the Dashboard ... menu would better separate:

  • Daily usage (running queries, adjusting filters)
  • Configuration (setting default views)

The menu could be state-based.

State 1: No defaults saved:

[ Menu]
----------------------------------
⬇️  Export Dashboard
⬆️  Import New Dashboard
----------------------------------
💾  Save Query & Filters as Default
----------------------------------
🗑️  Delete Dashboard              (danger text)

State 2: Defaults are active

[ Menu ]
----------------------------------
⬇️  Export Dashboard
⬆️  Import New Dashboard
----------------------------------
💾  Update Default Query & Filters
✖️  Remove Default Query & Filters (danger text)
----------------------------------
🗑️  Delete Dashboard              (danger text)

This is only a suggestion. Let me know what you think.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 23, 2026

PR Review: feat: Add saved query support to dashboards

  • WARNING: _.omitBy change is too broad in dashboards.ts: changing from _.isNil to _.isUndefined allows null for ALL dashboard fields (e.g., tiles, tags) via PATCH, not just the new saved query fields. A client sending {tiles: null} would pass through to updateDashboard. Consider scoping null-passthrough to only the new fields, or verify updateDashboard handles null gracefully for all existing fields.

  • WARNING: No backend validation on new savedQuery, savedQueryLanguage, savedFilterValues fields in the PATCH endpoint. savedFilterValues is stored as a generic mongoose.Schema.Types.Array without validation — add Zod/Express validation to match the frontend FilterSchema type.

  • WARNING: Potential race condition in handleSaveQuery: onSubmit() triggers async URL state updates via nuqs, but rawFilterQueries is read from URL state in the same render cycle. Saved filter values may reflect stale URL state. Consider reading from in-memory filter state instead.

  • INFO: useRef<string>(undefined) has a type mismatch — undefined is not assignable to string. Use useRef<string | undefined>(undefined) or useRef<string | null>(null).

Overall design is solid — the URL-params-override-saved-query logic and the initializedDashboard ref guard are good patterns. E2E test coverage is thorough.

@fleon fleon marked this pull request as ready for review February 23, 2026 16:11
@fleon fleon force-pushed the tom/dashboard-filter-saves branch from 854c906 to 7ff15d3 Compare February 23, 2026 16:13
@fleon fleon requested a review from elizabetdev February 23, 2026 16:18
@fleon
Copy link
Copy Markdown
Contributor

fleon commented Feb 23, 2026

@elizabetdev Thanks for your suggestions. I've updated the PR based on that. Attached videos demonstrating how create/update/delete states work in the kebab dropdown.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 23, 2026

PR Review: feat: Add saved query support to dashboards

Overall: Clean implementation. The API change is safe — Zod validates against DashboardSchema.partial(), so only the new nullable fields accept null; existing fields like tiles are not nullable and will reject null values.

Issues

  • ⚠️ TypeScript error in useRef initializationuseRef<string>(undefined) is invalid; undefined is not assignable to string. Fix: useRef<string | undefined>(undefined).

  • ⚠️ Misleading comment in handleSaveQuery → Comment says getValues() reads values "just submitted to URL" — it actually reads React Hook Form in-memory state (not URL state). Works correctly, but may mislead future maintainers.

  • ℹ️ savedFilterValues uses untyped Mongoose array{ type: mongoose.Schema.Types.Array } has no element-level type enforcement in MongoDB. Acceptable since Zod validates on ingress, but worth noting for future server-side usage.

No critical bugs or security issues found.

@fleon fleon force-pushed the tom/dashboard-filter-saves branch from 7ff15d3 to e4f9521 Compare February 25, 2026 13:35
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 25, 2026

E2E Test Results

All tests passed • 72 passed • 4 skipped • 852s

Status Count
✅ Passed 72
❌ Failed 0
⚠️ Flaky 2
⏭️ Skipped 4

Tests ran across 4 shards in parallel.

View full report →

@elizabetdev
Copy link
Copy Markdown
Contributor

@fleon @teeohhem

Looking good! One thing I noticed: when switching dashboards, the query in the SQL/Lucene bar sticks around, which feels a bit confusing.

Maybe we should clear it when changing dashboards and only keep it for dashboards with saved queries? What do you think?

@fleon
Copy link
Copy Markdown
Contributor

fleon commented Feb 25, 2026

@elizabetdev Good idea. Just implemented that.

@github-actions
Copy link
Copy Markdown
Contributor

PR Review

  • ⚠️ API _.isNil_.isUndefined change in dashboards.ts now allows null to pass through for any field in req.body, not just the new saved fields. If there's no Zod validation on the PATCH route body, a client could send { tiles: null } to wipe all tiles → Restrict which fields can be set to null, or add explicit schema validation on the PATCH endpoint body.

  • ⚠️ No server-side size limits on savedQuery (string) or savedFilterValues (array) → Add max length/count validation in the Zod schema or Mongoose model.

  • ⚠️ Stale filter capture in handleSaveQuery: onSubmit() triggers async URL updates, but rawFilterQueries is a closure over the current render's URL state — saving happens before the new query is reflected in URL state. The WHERE value is correctly read from form state via getValues(), but filter values may lag by one render → Read filter values from form/state directly rather than relying on rawFilterQueries after calling onSubmit().

  • ✅ The sessionStorage-based dashboard switching logic, Zod schema additions, and test coverage all look well-structured.


Generated by Claude Code

Copy link
Copy Markdown
Contributor

@elizabetdev elizabetdev left a comment

Choose a reason for hiding this comment

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

LGTM! 🎉

@kodiakhq kodiakhq Bot merged commit 733d612 into main Feb 25, 2026
13 of 14 checks passed
@kodiakhq kodiakhq Bot deleted the tom/dashboard-filter-saves branch February 25, 2026 23:31
kodiakhq Bot pushed a commit that referenced this pull request Mar 4, 2026
In #1584 we added saved default query/filter values support to dashboards. This PR extends that support to the external API.

Fixes HDX-3519
knudtty pushed a commit that referenced this pull request Apr 16, 2026
Fixes: HDX-1717

On the dashboard page, this PR adds:
* An option in the ... dropdown to Save/update/delete default query/filters that will save the WHERE input filter, along with any filters applied to the dashboard via the custom filter functionality + ties it to the dashboard object itself. Future reloads of this dashboard will restore saved values.



https://github.com/user-attachments/assets/5f7c18f7-a695-4d19-b338-6de852a4af6b



https://github.com/user-attachments/assets/ea7653c8-f862-450f-916c-46edfcbfbf35




Co-authored-by: Himanshu Kapoor <2203925+fleon@users.noreply.github.com>
knudtty pushed a commit that referenced this pull request Apr 16, 2026
In #1584 we added saved default query/filter values support to dashboards. This PR extends that support to the external API.

Fixes HDX-3519
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants