Dashboard loading indicators and live tail ranges
Demo by @brandon-pereira
Both changes here are open source contributions: the loading indicators are from @Harshul1484, and the live tail changes are from @krishs01. Both came out of issues raised against the repo over the last few weeks.
Previously, it wasn’t always clear what was happening when you refreshed a dashboard. Some tiles disappeared behind a spinner, while others kept showing the previous data with no indication that a query was running. On a slow connection or a large query, you couldn’t tell whether you were looking at the latest results. Line and stacked bar time charts already pulsed during a refetch, but number, bar, pie and table tiles only checked
isLoading, which stays false while react-query is showing placeholder data.
Those tiles now keep the previous data on screen and pulse until the refetch finishes. This landed across a few small PRs, starting with number, bar and pie tiles, then tables, heatmaps, and the list-bar and histogram charts on the Services dashboard. Tables needed an additional fix because useOffsetPaginatedQuery only kept previous rows in live mode, so the whole tile disappeared during a refresh. Search and event pattern tiles, along with the Pods, Nodes and Namespaces tables on the Kubernetes dashboard, still have the old behaviour. The PRs for those are open.
For live tail, the time picker previously greyed out every preset above one hour without explaining why. The switch controlling those presets was also labelled “Relative Time”, even though the rest of the app calls it live tail.
The 3h and 6h presets are now available, and the switch is labelled Live tail ranges. Presets that are still disabled show a “Not available for Live Tail” tooltip on hover. Ranges of 12h and above remain disabled because each refresh re-queries the full time window. With a default refresh interval of 10 seconds, that would mean scanning 12 to 24 hours of data every 10 seconds.
Related PRs: #3211 Pulse number, bar and pie tiles while a dashboard refreshes, #3212 Keep table tile rows on screen while a dashboard refreshes, #3221 Keep heatmap tiles on screen while a dashboard refreshes, #3229 Pulse the list-bar and histogram charts while they refresh, #3224 Keep search and pattern tiles on screen while a dashboard refreshes (open), #3228 Keep Kubernetes dashboard tables on screen while the page refreshes (open), #3219 Enable live tail for 3h and 6h, rename switch, add disabled tooltip
Issue templates and the Needs Feedback flow
Demo by @brandon-pereira
This one is a change to the repository rather than the product. Previously, people could open an issue in the HyperDX repo with a free-form body. New issues now start from either a bug report or a feature request template, with blank issues disabled. We can add more templates as we need them.
The bug report template asks for debug info up front. The app already has a Help → Copy debug info action that copies the frontend and backend versions, deployment mode, browser and session ID, with API keys and query parameters stripped out. Pasting that into the issue should save a round of questions. For collector and CLI issues, that field is marked
N/A.
New issues also get the Needs Feedback label automatically. This means the issue is still under discussion and isn’t ready for a PR. Once we’ve agreed on the scope, a maintainer changes the label to Accepting PR, and it’s ready for someone to pick up.
That flow is documented in CONTRIBUTING.md. It’s a convention for now, with nothing enforcing it on the PR side. The aim is to avoid people spending time on fixes before we’ve agreed on the issue and the approach. We’ll likely refine this as we see how it works.
Related PRs: #3239 Add debug-info ask and Needs Feedback issue flow
Multiple PromQL expressions on one chart
Demo by @pulpdrew
Previously, PromQL was only supported in time series charts, with one expression per tile. You can now add multiple PromQL expressions to the same time series chart, each with its own alias. In the demo, we’re using that to plot p50, p95 and p99 latency together.
The query preview below the editor now shows the generated PromQL for every expression, with variables substituted. Previously, it only showed the first expression. This lets you check what each query resolves to before saving.
The first PR in the list is the refactor that made this possible. It extracts the PromQL editor and the series controls in the chart builder into shared components, so we can reuse them for each expression.
Related PRs: #3145 Extract PromQL functions, PromqlExpressionEditor, and ChartSeriesControls, #3146 Plot several PromQL expressions on one chart
PromQL number, pie and table charts
Demo by @pulpdrew
The audio in this clip is poor, sorry about that. The description below covers everything that was shown.
PromQL now works with number, pie, bar and table charts as well as time series. The biggest change is to number charts. Previously, every PromQL query was a range query, evaluated at each step across the selected time range. The chart then displayed the first result by time and series name. You can now choose between an instant query, evaluated once at the end of the range, and a range query. This mirrors how Grafana stat tiles work.
For a range query, you also choose a reducer: last, min, max, avg, sum or count. This runs client-side and reduces the samples for each series to a single value. If there’s still more than one value, either from multiple series or unreduced samples, the chart shows a warning explaining that a number tile displays a single value and the expression needs to aggregate.
Number charts also support sparklines for range queries, using the same results fetched for the number. Those queries now follow the dashboard’s time range and granularity, just like time series queries, which lets the number and sparkline share the results.
Pie and bar charts have the same instant and range options with a reducer, and support the legend template. Reducers also work with instant queries that return multiple samples per series. For example,
up[5m] returns a matrix, which is reduced across time to an instant vector before being displayed as slices or bars. The same reduction applies to number charts.
Tables show the raw query results. Each sample becomes a row, with a column for each label. __name__ and Timestamp appear as the leading columns when present. For range queries, that means a row for every sample at every step, with the timestamp included. Number formatting is supported across all of these chart types.
Related PRs: #3169 Support instant and range-based PromQL number tiles, #3178 Support sparkline on PromQL number charts, #3238 Support PromQL table charts, #3253 Support PromQL pie and bar charts
Dashboard variables in markdown tiles
Demo by @pulpdrew
Dashboard variables previously worked in queries but not in markdown tiles. You can now reference them in markdown, including inside links. Changing a value in the variable picker updates both the text and the link target. In the demo, we’re using this to pass the selected value through to another page.
Values use the new
markdown format by default, which escapes markdown characters. Markdown tiles also block scripts and raw HTML. If you need an unescaped value, for example inside a code block, you can use another format such as ${var:csv}.
Invalid variable references are flagged in the editor, and the MCP dashboard validation and prompts have been updated to match.
Related PRs: #3246 Substitute variables in markdown tiles
PromQL macros
Demo by @pulpdrew
PromQL now supports three Grafana-compatible macros based on the dashboard’s time range and granularity.
$__interval gives you the chart or dashboard granularity, and $__range gives you the length of the chart’s date range in seconds. $__rate_interval is max(4 × 15s, $__interval), giving rate calculations a window that covers several scrape intervals. For now, this assumes a scrape interval of 15 seconds.
The macros are substituted alongside variables, so you can see their resolved values in the generated PromQL preview. They’re also suggested in the editor’s autocomplete. Under the hood, this reuses most of the existing SQL macro machinery.
Related PRs: #3244 Support PromQL macros
Selecting rows on the search page
Demo by @pulpdrew
This is a small feature from a user request. You can now select individual rows in search results using a checkbox, or shift-click to select a range. Once you’ve selected some rows, you get Download CSV, Copy CSV and Copy JSON actions, plus an option to clear the selection. These include all the columns currently shown in the table, so you can get a handful of rows out of ClickStack without exporting the whole result set.
The checkboxes appear on hover, which is a follow-up from @MikeShi42. They’re hidden by default and fade in when you hover over a row. They also appear on keyboard focus, so you don’t tab to an invisible control. Once any row is selected, all checkboxes stay visible so you can see where to shift-click. On touch devices, they’re always visible.
The checkbox column keeps its width as you hover, so the table doesn’t move around. It’s also been narrowed from 24px to 18px, and the checkbox has a tooltip explaining how to select a range with shift-click.
Related PRs: #3140 Support search row multi-select download and copy, #3164 Reveal search row-selection checkboxes on hover
Materialized and alias columns in the row details panel
Demo by @pulpdrew
This is an open source contribution from @BilalAtique, following an issue asking for computed columns in the row details panel. The panel fetches each row with
SELECT *, which excludes MATERIALIZED and ALIAS columns unless asterisk_include_materialized_columns and asterisk_include_alias_columns are enabled. That meant materialized columns you’d added to your logs table, along with the standard otel_logs *AttributeItems aliases, didn’t appear.
There’s now a Show materialized and alias columns option in the gear menu in the Column Values view. It’s off by default and saved in local storage alongside the other panel preferences. Turning it on adds both settings to row queries that use *. Sources with a Known Columns List are unchanged.
Row lookups now also apply the source’s own query settings, which take precedence over the toggle. If both settings are enabled on the source, the columns appear even with the option off. If the source has asterisk_include_alias_columns = 0, alias columns stay hidden even with the option on.
There are a couple of things to be aware of. The row query will fail if the connection’s user can’t change these settings, for example with readonly = 1 or a settings profile that marks them as CONST. It will also fail if an alias can’t be evaluated for that row. The panel shows the ClickHouse error and a Hide materialized and alias columns action to turn the option back off.
The __hdx_materialized_* columns are also fetched, but remain hidden in the viewer. A toggle for those isn’t included in this change.
Related PRs: #3234 Apply source query settings to the row side panel’s row lookup, #3231 Add an option to show MATERIALIZED and ALIAS columns in the row details panel
Map attribute columns labelled by their key
Demo by @pulpdrew
Another open source contribution, this time from @DevShoaib78. Previously, adding a map attribute such as
host.arch as a column from the filters sidebar or row side panel gave it ClickHouse’s derived name in the results table e.g. arrayElement(ResourceAttributes, 'host.arch').
Both actions now use the same logic on the search page, adding the expression to the SELECT with an alias: ResourceAttributes['host.arch'] AS "host.arch". The column header then reads host.arch. You can see and edit the alias in the SELECT input. SQL you write by hand is never rewritten, so existing saved searches, alerts and dashboards are unchanged.
The alias is skipped where it could change the query’s meaning. That includes keys that match a table column, because ClickHouse resolves aliases before columns in WHERE and ORDER BY, and names already used in the SELECT, such as the same key from two different maps. It’s also skipped if the key contains " or \.
The side panel, filters sidebar and nested filter groups now recognise an expression with or without its alias when checking whether a column is already shown. That stops them offering to add a column that’s already in the table.
Related PRs: #3163 Label Map attribute columns by their key instead of arrayElement(…)