github hyperdxio/hyperdx @hyperdx/app@2.29.0

4 hours ago

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.sessionId resource 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_agent the document-load instrumentation emits), country, and device size (derived from screen.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 geoip processor is enabled (geo can't be derived in the browser)
  • 5cd7090: Add UI support for configuring an external Prometheus-compatible endpoint on a
    connection. Modify Connections model to now have a boolean
    isPrometheusEndpoint field 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 a percent number 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 ClickStack

    Stored configs from the initial color picker (#2265) keep working.
    ChartPaletteTokenSchema stays strict (a plain z.enum, so its z.input
    matches z.output — wrapping it in z.preprocess would poison
    validateRequest's req.body inference all the way up to
    Dashboard.tiles[i].config.color). Migration of legacy chart-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
    (walkRawDashboardTileColors in common-utils) so the per-tile traversal
    stays in lockstep:

    • Fetch-time / write-time (React): normalizeDashboardTileColors in
      packages/app/src/dashboard.ts heals 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: DBDashboardImportPage runs
      normalizeRawDashboardTileColors on the parsed JSON before the strict
      DashboardTemplateSchema.safeParse, so templates exported from a
      pre-rename deploy import cleanly.
    • Server-side GET response healing: getDashboards / getDashboard in
      packages/api/src/controllers/dashboard.ts rewrite 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 resurrecting chart-N through the strict
      schema.
    • Server-side write shim: the dashboards POST / PATCH routes mount
      a request-body preprocessor that rewrites legacy tile colors before
      validateRequest runs ChartPaletteTokenSchema. 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): DBNumberChart and
      ColorSwatchInput also call resolveChartPaletteToken for tiles
      constructed in memory between fetch and save (ChartEditor form
      state, unit-test fixtures, hand-rolled Tile literals).

    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-1 was brand blue #437eef, not brand
    green). The migration map uses HyperDX slot ordering, so any ClickStack
    dashboard saved via #2265 with color: '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_MAP lives
    in common-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-blue swapped to
    #437eef to 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-blue always renders the brand blue. Brand identity for charts moves
    entirely into the semantic layer: --color-chart-success and --color-chart-info
    resolve to categorical chart-green (#3ca951) and chart-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_TOKEN in packages/app/src/utils.ts) is
    the source of truth for categorical hues — getColorFromCSSVariable and
    getColorFromCSSToken skip getComputedStyle for categorical tokens since the
    palette is unified across themes. The matching --color-chart-{hue} CSS vars in
    _tokens.scss remain as a stylesheet-author affordance (inline var() use,
    devtools inspection) and a hook for any future per-brand override. Semantic
    tokens still resolve through getComputedStyle because they genuinely vary per
    theme.

  • 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/mcp route 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_limit CTE 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 keys

    mergePath converted numeric path segments to 1-based array subscripts
    ([N+1]) regardless of whether the parent column was a Map or an Array.
    On a Map(String, String) column this produced SQL like LogAttributes[2],
    which ClickHouse rejects with Illegal 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.

    mergePath now accepts a mapColumns argument alongside jsonColumns.
    For Map-typed parents, sub-keys always render as string subscripts
    (Map['1']) regardless of whether the key looks numeric. The three
    callers (useAutoCompleteOptions, DBRowJsonViewer via the row panels,
    DBSearchPageFilters) now thread Map-column names from the source
    schema. A new useMapColumns hook mirrors useJsonColumns.

    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 denoise boolean parameter to the MCP clickstack_search tool 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-utils so 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. Prefers otel_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 persists numberFormat only 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 any groupBy the 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 drops groupBy as 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:

    • PageHeader was pinned at z-index: 100, but app drawers opt into a
      much lower stack via ZIndexContext (contextZIndex + 10, so a
      top-level drawer renders at z-index: 10). The sticky header therefore
      floated above the drawer overlay. The header now sits at z-index: 2 so
      drawer overlays reliably cover the page chrome while the header still
      wins against normal scrolling content.
    • FullscreenPanelModal used Mantine's default modal z-index (200) and
      didn't propagate it through ZIndexContext. Clicking a row in a
      fullscreen search tile opened a DBRowSidePanel drawer at z-index: 10
      that was hidden behind the modal. The modal now follows the existing
      contextZIndex + 10 pattern 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.

    PageHeader gains a stickyRow slot 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 — a PageHeader without stickyRow keeps 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 of ServiceName as service) failed in the Event Patterns view
    with Unknown 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 alias WITH clauses 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 where plus 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

Don't miss a new hyperdx release

NewReleases is sending notifications on new releases.