@hyperdx/app@2.29.0
Minor Changes
-
9af8cba: feat: add Browser RUM dashboard template
- New "Browser RUM" template in the dashboards gallery for browser sessions instrumented with the HyperDX Browser SDK (or any OTel browser instrumentation emitting a
rum.sessionIdresource attribute) - Performance Overview section: page-view/session/error KPIs, Core Web Vitals (LCP/INP/CLS) p75, median/p75/p90 page-load percentiles, and long-task health
- Page Views Breakdown section: traffic grouped by URL, browser (parsed from the
http.user_agentthe document-load instrumentation emits), country, and device size (derived fromscreen.xy) - Errors section with tabs for an overview, JS exceptions (by message and by page), and failing API calls
- Five dashboard-level filters: Service, Environment, Service Version, Page URL, and Country
- Top Countries tile and the Country filter populate when the OTel collector's
geoipprocessor is enabled (geo can't be derived in the browser)
- New "Browser RUM" template in the dashboards gallery for browser sessions instrumented with the HyperDX Browser SDK (or any OTel browser instrumentation emitting a
-
5cd7090: Add UI support for configuring an external Prometheus-compatible endpoint on a
connection. Modify Connections model to now have a boolean
isPrometheusEndpointfield and use host for storing the host. -
b6a4b3b: feat: lazy-load dashboard tiles based on viewport visibility
Dashboard tiles now only run their ClickHouse queries once they scroll into the browser viewport, instead of every tile querying on page load. A tile loads the first time it becomes visible and keeps its data afterward. This significantly reduces the number of queries fired when opening dashboards with many tiles.
-
f40cf68: feat(dashboards): add a background trend sparkline to number tiles
Number tiles can now render a faint line or area sparkline behind the value,
derived from a time-bucketed version of the same query, so the value's trend
over the selected range is visible at a glance. This is handy for SLO /
error-budget tiles where the burn over time matters as much as the current
number. The sparkline inherits the tile's color by default and can be
overridden to any palette token. Configure it under Display Settings >
Background chart on a number tile. Available on builder number tiles (raw SQL
number tiles return a single value with no time dimension to bucket). -
17e1eb1: feat: Add an "external link" row-click action for dashboard table tiles
-
c1403a7: Number chart tiles now support a second series with the "As Ratio" toggle (
series[0] / series[1]), matching line and bar charts. Combined with apercentnumber format, this renders a percentage (e.g. success/error rate) as a single big number with the trend sparkline behind it. -
e03971b: refactor(theme): rename chart palette tokens from chart-1..10 to hue-named
(chart-blue, chart-orange, ...) and unify the categorical palette across HyperDX
and ClickStackStored configs from the initial color picker (#2265) keep working.
ChartPaletteTokenSchemastays strict (a plainz.enum, so itsz.input
matchesz.output— wrapping it inz.preprocesswould poison
validateRequest'sreq.bodyinference all the way up to
Dashboard.tiles[i].config.color). Migration of legacychart-1..chart-10
happens at five complementary points so no entry or wire-format path can slip
through, all composing over a single shared walker
(walkRawDashboardTileColorsincommon-utils) so the per-tile traversal
stays in lockstep:- Fetch-time / write-time (React):
normalizeDashboardTileColorsin
packages/app/src/dashboard.tsheals dashboards on read
(useDashboards/fetchLocalDashboards/fetchDashboards) and on write
(useUpdateDashboard/useCreateDashboard). Unresolvable color strings
(stale hexes, hand-edited values, forward-rolled future tokens) are
preserved so the user's chosen value survives a render pass — the strict
server-side schema surfaces a clear error on next save instead of the
normalizer quietly dropping the field. - JSON import:
DBDashboardImportPageruns
normalizeRawDashboardTileColorson the parsed JSON before the strict
DashboardTemplateSchema.safeParse, so templates exported from a
pre-rename deploy import cleanly. - Server-side GET response healing:
getDashboards/getDashboardin
packages/api/src/controllers/dashboard.tsrewrite legacy tile colors on
the way out. Pre-rename Mongo docs are served on the wire as
hue-named tokens so non-React HTTP clients (CI scripts, stale bundle
tabs during a rolling deploy, the external API) can round-trip
GET → PATCH without ever resurrectingchart-Nthrough the strict
schema. - Server-side write shim: the dashboards POST / PATCH routes mount
a request-body preprocessor that rewrites legacy tile colors before
validateRequestrunsChartPaletteTokenSchema. Catches non-React
HTTP callers (stale-bundle tabs during a rolling deploy, CI scripts,
MCP, the upcoming external-API parity work) for a one-release
deprecation window without weakening the schema's input/output equality.
The dashboard provisioner task applies the same shim before parsing
on-disk template files. - Render-time (belt-and-suspenders):
DBNumberChartand
ColorSwatchInputalso callresolveChartPaletteTokenfor tiles
constructed in memory between fetch and save (ChartEditorform
state, unit-test fixtures, hand-rolledTileliterals).
The migration preserves the HyperDX slot ordering from #2265 (slot 1 = brand
green, slot 2 = blue, etc.).ClickStack legacy color caveat: Pre-rename ClickStack used a different slot
ordering than HyperDX (--color-chart-1was brand blue#437eef, not brand
green). The migration map uses HyperDX slot ordering, so any ClickStack
dashboard saved via #2265 withcolor: 'chart-1'will flip from blue to
Observable green after migration. We chose this trade-off deliberately over
branching the legacy map by active theme:LEGACY_CHART_PALETTE_TOKEN_MAPlives
incommon-utils(shared with the API), and migration is one-shot persisted on
next save — theme-branching would couple common-utils to browser DOM state and
still produce wrong results for users whose active theme changed since the
original pick. Affected users can manually re-pick the desired hue via the (now
hue-labeled) color picker.The categorical palette is based on Observable 10, with
chart-blueswapped to
#437eefto match the brand link color
(--click-global-color-text-link-default); all other hues are straight from
Observable 10. The palette resolves identically on both themes — picking
chart-bluealways renders the brand blue. Brand identity for charts moves
entirely into the semantic layer:--color-chart-successand--color-chart-info
resolve to categoricalchart-green(#3ca951) andchart-blue(#437eef) on
both HyperDX and ClickStack, so success fills, info-level logs, and the
matching multi-series slots all read consistently across brands.Internally, JS (
CATEGORICAL_HEX_BY_TOKENinpackages/app/src/utils.ts) is
the source of truth for categorical hues —getColorFromCSSVariableand
getColorFromCSSTokenskipgetComputedStylefor categorical tokens since the
palette is unified across themes. The matching--color-chart-{hue}CSS vars in
_tokens.scssremain as a stylesheet-author affordance (inlinevar()use,
devtools inspection) and a hook for any future per-brand override. Semantic
tokens still resolve throughgetComputedStylebecause they genuinely vary per
theme. - Fetch-time / write-time (React):
-
418567f: feat: trace panel inline split detail
Patch Changes
-
56c5866: fix(search-filters): prevent nested filter dropdowns from disappearing on reopen
-
998ea5d: feat: Add option to fit time chart y-axis lower bound
-
0497ca5: Bump http-proxy-middleware to v4, replacing http-proxy with httpxy
-
20fabc6: feat: add a "Connect your AI assistant" section to Team Settings
A new section on the Team Settings page (Integrations tab, above the API Keys
card) lets a user install the HyperDX MCP server in Claude Code, Cursor,
VS Code + Copilot, Codex CLI, or any MCP-compatible host without hand-rolling
JSON. Per-host snippets carry the user's personal access key so the install
works against the existing/api/mcproute without extra setup. -
8e52cef: feat(dashboard): auto-resize font in number tiles to fit container
Number tiles now automatically scale their font size to fit the available
width, preventing text overflow on narrow tiles and making better use of
space on wide ones. Includes an error boundary so a single broken tile
does not crash the entire dashboard. -
5a1dde4: fix(search): wrap date column values in a type-matching parse/convert expression when building IN/NOT IN filters, so including/excluding a timestamp value no longer fails with "Cannot convert string ... to type DateTime64" or "Type mismatch in IN ... Expected: DateTime. Got: Decimal64". Date column types are now resolved from the query result set, so aliased (
TimestampTime AS time) and computed (toDate(TimestampTime)) DateTime/Date columns are also wrapped correctly when added to filters. -
31b8781: feat(chart-explorer): duplicate a series in the chart builder
Add a Duplicate button to each series row in the chart builder that inserts a
copy of that series directly below it, so building a near-identical variant
(for example avg and p95 of the same column) no longer requires re-entering
every field by hand. "Add Series" still creates a blank series. The copy
starts with an empty alias so it does not collide with the original's alias in
the generated SQL. -
5e19a2b: Show elapsed time and Generated SQL for search timeline view
-
65931e3: feat(search): make active filter pills editable in place
Clicking an active filter pill under the search bar now opens a small menu to copy the value, flip the filter polarity (include vs exclude), or switch to a different value of the same field, without removing and re-adding the filter. The polarity is preserved when changing the value, and the one-click remove on each pill is unchanged. Range and not-applied pills keep their remove-only behavior.
-
7152d2b: feat: Use optimistic updates for favorites
-
497d50b: feat: Allow selecting the column or SQL expression used for event pattern grouping (with shareable URL state)
-
ae39bc4: fix: Correct filter handling for filter keys with special characters
-
bd31ea9: fix: handle boolean values in JSON viewer filter actions
-
052315b: fix: improve contrast of excluded search filter pills
Excluded ("!=") filter pills above the search results used a saturated red background with red text and a red remove button, which made them hard to read in the light theme. They now use a soft red tint with a readable accent, legible in both light and dark themes.
-
7b6db8d: fix(app): format log detail Timestamp in local timezone
The log detail JSON viewer rendered Timestamp and TimestampTime as raw UTC ISO strings while the results table used the shared FormatTime helper.
-
bcec176: fix: allow saving edits to markdown dashboard tiles that have a minimal config shape (no resolved source)
-
8261b46: fix: inline parametric aggregate function arguments instead of passing as query parameters
-
bf6e1f2: feat(charts): the time-chart series limit is now configured per chart in the Display Settings drawer instead of as a workspace-wide team setting (the team "Time Chart Series Limit" setting is removed). It is disabled by default — charts fetch every series and no
__hdx_series_limitCTE is emitted — and is cleared back to disabled by emptying the field. The control only appears for builder line/bar charts; the limit and its Generated SQL preview now come from the chart's own config. When a limit is set, chunked time-chart queries keep a consistent top-N series set: previously each time-window chunk ranked its own top-N, so charts could render more series than the limit and adjacent windows disagreed; the ranking is now pinned to the newest chunk window for every chunk so the union across chunks equals the limit. -
f9fab8e: fix: Prevent table content from overlapping table headers
-
973d120: fix: polish promql experience across the app
-
712ba11: fix: Navigate to the dashboard listing page after deleting a dashboard
-
2130775: fix(row-panel): mergePath now emits string-key subscripts for Map columns,
preventing a crash when expanding rows with numeric-looking attribute keysmergePathconverted numeric path segments to 1-based array subscripts
([N+1]) regardless of whether the parent column was a Map or an Array.
On aMap(String, String)column this produced SQL likeLogAttributes[2],
which ClickHouse rejects withIllegal types of arguments: Map(String, String), UInt8 for function arrayElement. The grid row
"expand" view failed for any row whose attribute path included a
numeric-looking key under a Map column.mergePathnow accepts amapColumnsargument alongsidejsonColumns.
For Map-typed parents, sub-keys always render as string subscripts
(Map['1']) regardless of whether the key looks numeric. The three
callers (useAutoCompleteOptions,DBRowJsonViewervia the row panels,
DBSearchPageFilters) now thread Map-column names from the source
schema. A newuseMapColumnshook mirrorsuseJsonColumns.Fixes HDX-4369.
-
2cecc9f: Dashboard table tiles configured with a row-click action now show a trailing arrow-up-right icon at the right edge of each row, revealed on hover, with a small tooltip that names the destination. Actionable rows get a stronger background highlight on hover to reinforce interactivity before the user sees the arrow fade in. The icon click navigates to the same URL as a row click, with all the standard native browser behaviors (cmd-click new tab, middle-click new tab, right-click context menu).
-
d985895: Fix: Resolved an issue with markdown tiles breaking dashboard imports.
-
750b8af: feat(mcp): add denoise option to clickstack_search tool
Add a
denoiseboolean parameter to the MCPclickstack_searchtool that
automatically filters out high-frequency repetitive event patterns from
search results, mirroring the web app's "Denoise Results" feature.When enabled, the tool samples 10k random events, mines patterns using
the Drain algorithm, identifies noisy patterns (>10% of sample), and
filters them out of result rows. Returns filtered rows plus metadata
listing removed patterns with estimated counts.Extracts shared denoise constants (
DENOISE_SAMPLE_SIZE,
DENOISE_NOISE_THRESHOLD) into@hyperdx/common-utilsso the web app
and MCP server use the same values. -
cd6a17d: feat: auto-fill metric table dropdowns when creating a Metrics source
The 5 metric-table dropdowns (Gauge, Histogram, Sum, Summary, Exponential
Histogram) now auto-populate by matching table names in the selected database
to their metric type via suffix patterns. Prefersotel_metrics_prefixed
names, never overwrites user selections, and shows a green notification on
successful autofill. -
6747cf9: fix(dashboards): keep the auto-detected number format when applying display settings
Opening Display Settings on a number tile that auto-detects its format from the
datasource (for example p95 of a trace Duration column) and clicking Apply no
longer rewrites the format to Number. The drawer now reflects the
datasource-derived format, and Apply persistsnumberFormatonly when the user
explicitly changes it; otherwise it stays unset so render-time auto-detection
keeps driving the format. -
a258fcf: fix(dashboards): match the number-tile background sparkline to the displayed value
The big number on a number tile is a single aggregate (its query drops
groupBy), but the background sparkline kept anygroupBythe tile carried over from a prior Line display type. It then plotted only the first group's trend behind a value that aggregates every group. The sparkline now dropsgroupByas well, so its trend reflects the same single series as the value it sits behind. -
9d71399: fix(z-index): keep sticky header below drawers and drawers above the fullscreen tile modal
Two related z-index regressions:
PageHeaderwas pinned atz-index: 100, but app drawers opt into a
much lower stack viaZIndexContext(contextZIndex + 10, so a
top-level drawer renders atz-index: 10). The sticky header therefore
floated above the drawer overlay. The header now sits atz-index: 2so
drawer overlays reliably cover the page chrome while the header still
wins against normal scrolling content.FullscreenPanelModalused Mantine's default modal z-index (200) and
didn't propagate it throughZIndexContext. Clicking a row in a
fullscreen search tile opened aDBRowSidePaneldrawer atz-index: 10
that was hidden behind the modal. The modal now follows the existing
contextZIndex + 10pattern and wraps its children in a
ZIndexContext.Provider, so child drawers stack on top of it.
-
538a1c4: chore: migrate the custom Dashboard page to shared
PageLayout/PageHeader. Breadcrumbs, the editable dashboard name, dashboard actions (Favorite, Tags, Menu), and the "Created by … Updated …" meta now live in a single page header, while the query toolbar (SQL/Lucene WHERE, time range, granularity, Live, refresh, edit filters, Run) is pinned to the top of the scroll container as a dedicated sticky row — the chrome above scrolls away and only the toolbar follows the user. The "Updated …" meta moves to the right side of the breadcrumbs row instead of sitting as a separate body line.PageHeadergains astickyRowslot that any page can use to declare a single row that should be the only pinned element, with the rest of the header treated as scrolling chrome. Other pages are unaffected — aPageHeaderwithoutstickyRowkeeps the existing fully-sticky behavior. -
5e3e541: fix(search): keep select-alias filters working in Event Patterns
Filtering on a column the source exposes only under an alias (for example a
default select ofServiceName as service) failed in the Event Patterns view
withUnknown expression or table expression identifier 'service'. The
results table works because its own SELECT defines the alias, but Event
Patterns rebuilds the SELECT and did not carry the alias definitions. The
pattern query now receives the same aliasWITHclauses already threaded into
the results, histogram, and heatmap queries, so the filter resolves. -
e492280: feat: add source field suggestions
-
defbe1f: Add Cmd/Ctrl+Enter support for running raw SQL chart queries from the SQL editor.
-
1a64796: Removing relative imports and using path aliases
-
c74744a: fix: fallback to body or implicit column expression when other empty
-
d1d91d7: feat(service-map): server-side filtering, latency percentiles, throughput & focus
The Service Map gains server-side filtering (Lucene/SQL
whereplus a
service-name multi-select with inbound/outbound neighbor expansion), latency
percentiles (p50/p95/p99) and request throughput (req/s) in node and edge
tooltips, a "Focus" action to scope the map to a service and its immediate
dependencies, and node sizing by total throughput (incoming + outgoing).
Percentiles are computed server-side via a single GROUPING SETS query. -
b763ba6: fix: next-runtime-env runtime env var injection fixed for images
-
53e8bd1: fix: Fix height of source select RHS menu
-
5e8af09: Transition the local development server from Webpack to Turbopack to
significantly improve build performance and hot-reloading speed. -
2a68145: feat(source-picker): chip + kebab menu UX
-
f95687b: Fix the database, table, and connection dropdowns being clipped inside the source setup modal. The dropdowns now render in a portal, so the full list is visible and scrollable when configuring or editing a source.
-
48e19e8: Suggest existing section names in the source form's Section field. The field is now an autocomplete fed by the sections already in use, so a new source can reuse an existing section instead of retyping it (which is how a section ends up split into near-duplicates like "Billing" and "billing"). The field stays free-text, so any new section name is still accepted.
-
03f9dd7: feat: add an optional Section field to data sources
Sources can now carry an optional free-text Section label, set from the source
settings form. The value is persisted and returned by GET /api/v2/sources, so
external API consumers can read it. This lays the groundwork for grouping and
searching sources by section in the source selector. -
fdb18f2: Group the data source selector by section and add tag-style search. When sources have a Section assigned, the selector lists them under section headers; search matches on both the source name and its section, so a section name acts as a tag (typing "billing" returns every source in the Billing section, including ones whose name does not contain "billing"). The selector stays flat until at least one source has a section, so deployments that have not adopted sections see no change. The grouped dropdown is also widened and pinned to the picker's left edge so section headers and source names are not cramped.
-
34aa906: Show each source's Section on the Manage Sources list. A sectioned source now displays its section, with a folder icon, in the dimmed metadata row alongside its connection and table, so the list mirrors the grouped selector. Sources without a section are unchanged.
-
6e0880a: feat: Add Known Columns List setting for distributed tables
-
81e524c: feat(charts): cap group-by time charts to a top-N series limit to prevent browser memory exhaustion on high-cardinality group-bys. The cap defaults to 100 (the number of series rendered) and is configurable per team via a new "Time Chart Series Limit" setting; series beyond the cap remain available in the series selector.
-
bc5cd00: feat: emphasize the series nearest the cursor in multi-series time charts. The nearest line is thickened and the others fade back, and its tooltip row is bolded while the rest dim, so a value is easy to trace back to its line.
-
a6e7dcd: chore: Make error states consistent across chart types
-
9bbf680: fix: bug preventing deletion of nested subdocuments like metadataMVs
-
Updated dependencies [9119de5]
-
Updated dependencies [1d44098]
-
Updated dependencies [9f23b7e]
-
Updated dependencies [998ea5d]
-
Updated dependencies [0497ca5]
-
Updated dependencies [ee90738]
-
Updated dependencies [5c46215]
-
Updated dependencies [45954c3]
-
Updated dependencies [5cd7090]
-
Updated dependencies [9a7e392]
-
Updated dependencies [5a1dde4]
-
Updated dependencies [b798f91]
-
Updated dependencies [ae39bc4]
-
Updated dependencies [cdd7ca0]
-
Updated dependencies [d11991b]
-
Updated dependencies [8261b46]
-
Updated dependencies [bf6e1f2]
-
Updated dependencies [973d120]
-
Updated dependencies [677e3f7]
-
Updated dependencies [89949b1]
-
Updated dependencies [747352f]
-
Updated dependencies [8164492]
-
Updated dependencies [a19ba54]
-
Updated dependencies [7e7159a]
-
Updated dependencies [63469fe]
-
Updated dependencies [f34a31f]
-
Updated dependencies [f6bda8c]
-
Updated dependencies [f326ccf]
-
Updated dependencies [750b8af]
-
Updated dependencies [caba7c2]
-
Updated dependencies [f113ea3]
-
Updated dependencies [634101c]
-
Updated dependencies [ba626ef]
-
Updated dependencies [f40cf68]
-
Updated dependencies [f126d5b]
-
Updated dependencies [ebfc2e8]
-
Updated dependencies [bbc2985]
-
Updated dependencies [17e1eb1]
-
Updated dependencies [60a91e4]
-
Updated dependencies [e03971b]
-
Updated dependencies [adac913]
-
Updated dependencies [1a64796]
-
Updated dependencies [c74744a]
-
Updated dependencies [03f9dd7]
-
Updated dependencies [6e0880a]
-
Updated dependencies [fc3ef2d]
-
Updated dependencies [81e524c]
-
Updated dependencies [da3caab]
-
Updated dependencies [55a255a]
-
Updated dependencies [9bbf680]
- @hyperdx/api@2.29.0
- @hyperdx/common-utils@0.21.0