You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(dashboards): address deep review on #2383 + e2e shard 2 fix
E2E shard 2 was failing on three pre-existing dashboard tests because
`visibleFilters` in DashboardFilters.tsx was a new array reference every
render, churning useDashboardFilterValues' useQueries and leaving the
chip dropdown disabled while the values query never settled. Memoize
the array so a stable reference flows into the hook.
Deep review fixes:
- P0/P1: MCP hyperdx_save_dashboard inputSchema now exposes
savedFilterValues, paired with a usage example in the filters param
description so constant: true filters can actually lock to a value
via MCP. The body schema already accepts it; only the tool input
shape was missing.
- P2: DashboardFiltersModal snapshots initialDefaultValues via state
keyed on filter.id, so a background savedFilterValues refetch no
longer wipes in-progress edits in the default-value picker.
- P2: Schema-level coherence checks moved to common-utils via two
reusable refinements applied at the external API boundary:
refineDashboardFilterCoherence rejects readonly/hidden render modes
without constant: true; refineDashboardFiltersConstantSiblings
rejects two filter definitions sharing an expression that disagree
on constant. Internal callers (MCP, future migrations) get the
same protection through the shared schemas.
- P2: openapi.json + JSDoc no longer declare default: false /
default: "editable" on the new constant / renderMode property
schemas. The Zod schema is .optional() with no .default() so
generated SDKs would otherwise surface a default the wire format
never produces; the implied default now lives in the description
text instead.
- P2: page-level merge logic for "Save default" / URL hydration /
savedFilterValues upsert is extracted into dashboardFilterUtils
(normalizeExpression, buildConstantExpressionSet,
stripConstantsFromUrl, mergeConstantFiltersForSave,
upsertSavedDefault, removeSavedDefaultForExpression). The matrix
including bracket-notation expressions is covered by a new unit
test. useDashboardFilters and DBDashboardPage call the helpers.
- P2: bracket-notation constant filter is now covered in the
hook unit tests (SpanAttributes['k8s.pod.name'] resolves through
filterValues, blocks setFilterValue, and survives via
getFilterQueriesForSource).
P3 polish:
- handleRemoveFilter now strips the matching savedFilterValues entry
alongside the filter delete so deleting + recreating a filter on the
same expression doesn't silently re-lock to an orphaned value.
- applyFilterVisibility('editable') returns {} so the spread on save
no longer leaves constant: undefined / renderMode: undefined keys
in memory.
- defaultsChanged uses set equality so reordering the same values
doesn't fire a spurious save write.
- NEVER_USED_RANGE hoisted to module scope.
- FilterVisibility uses z.infer<typeof DashboardFilterRenderMode>
instead of a hand-rolled string union.
- as DashboardFilter cast dropped on filtersForQuery.
- usePresetDashboardFilters.handleSaveFilter widened to accept the
optional defaultValues arg so a future supportsConstantFilters=true
flip on presets doesn't silently drop the second arg.
- parseQuery import uses the @/searchFilters alias for consistency
with sibling files.
- dashboard?.filters dropped from the URL hydration effect's deps
(the initializedDashboard.current === dashboard.id guard already
prevents re-runs).
- HDX-4404 API round-trip test uses toEqual instead of toMatchObject
so unexpected extra fields fail the assertion.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: packages/api/openapi.json
+2-4Lines changed: 2 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -2362,8 +2362,7 @@
2362
2362
},
2363
2363
"constant": {
2364
2364
"type": "boolean",
2365
-
"description": "When true, the value from the dashboard's savedFilterValues matched\nby this filter's expression is applied automatically on every tile\nthis filter scopes, and viewers cannot change it. Use this to lock\na dashboard template to a single scope (clone the dashboard, save a\ndifferent default per copy). Pairs with renderMode to control how\nthe locked filter shows in the filter bar.\n",
2366
-
"default": false,
2365
+
"description": "When true, the value from the dashboard's savedFilterValues matched\nby this filter's expression is applied automatically on every tile\nthis filter scopes, and viewers cannot change it. Use this to lock\na dashboard template to a single scope (clone the dashboard, save a\ndifferent default per copy). Pairs with renderMode to control how\nthe locked filter shows in the filter bar. Omit (or send false)\nfor an ordinary editable filter (the implicit default behavior).\n",
2367
2366
"example": true
2368
2367
},
2369
2368
"renderMode": {
@@ -2373,8 +2372,7 @@
2373
2372
"readonly",
2374
2373
"hidden"
2375
2374
],
2376
-
"description": "Controls how this filter renders in the dashboard filter bar.\n\"editable\" (default) shows a normal dropdown the viewer can change.\n\"readonly\" shows a disabled chip with a lock icon; the viewer\nsees the locked value but cannot edit it. \"hidden\" omits the chip\nentirely; the locked value still scopes every matching tile.\n",
2377
-
"default": "editable",
2375
+
"description": "Controls how this filter renders in the dashboard filter bar.\nOmit for the implicit \"editable\" behavior (normal dropdown the\nviewer can change). \"readonly\" shows a disabled chip with a lock\nicon; the viewer sees the locked value but cannot edit it.\n\"hidden\" omits the chip entirely; the locked value still scopes\nevery matching tile. \"readonly\" and \"hidden\" require constant: true.\n",
0 commit comments