fix: Fix query error on ClickHouse Query latency chart (#1978)

## Summary

This PR fixes the heatmap Query Latency chart on the ClickHouse page, by casting the value expression to Float64 so that it matches the type of other `greatest()` args.

### Screenshots or video

Before

<img width="2301" height="341" alt="Screenshot 2026-03-24 at 10 29 44 AM" src="https://github.com/user-attachments/assets/4c3c2562-e2c8-4bc8-8739-adb7768d7cf6" />
<img width="1945" height="304" alt="Screenshot 2026-03-24 at 10 29 35 AM" src="https://github.com/user-attachments/assets/5d8d3dd0-bf56-4af8-bfe9-7672723c255b" />

After

<img width="2290" height="367" alt="Screenshot 2026-03-24 at 10 33 29 AM" src="https://github.com/user-attachments/assets/af034dbd-d983-416b-9b47-927db818bd02" />
<img width="2296" height="299" alt="Screenshot 2026-03-24 at 10 33 38 AM" src="https://github.com/user-attachments/assets/e5910d8d-e799-444d-b38d-8fa574beae87" />


### How to test locally or on Vercel

This can be validated in the preview environment

### References



- Linear Issue: Closes HDX-3794
- Related PRs:
This commit is contained in:
Drew Davis 2026-03-24 10:42:28 -04:00 committed by GitHub
parent 45755260d0
commit cdc29d5a88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 73 additions and 2 deletions

View file

@ -0,0 +1,5 @@
---
"@hyperdx/app": patch
---
fix: Fix query error on ClickHouse Query latency chart

View file

@ -454,11 +454,11 @@ function HeatmapContainer({
// For linear scale: bucket by raw value (original behavior)
const bucketExprAgg =
scaleType === 'log'
? `widthBucket(log(greatest(value_calc, ${effectiveMin})), log(${effectiveMin}), log(${max}), ${nBuckets})`
? `widthBucket(log(greatest(toFloat64(value_calc), ${effectiveMin})), log(${effectiveMin}), log(${max}), ${nBuckets})`
: `widthBucket(value_calc, ${effectiveMin}, ${max}, ${nBuckets})`;
const bucketExprDirect =
scaleType === 'log'
? `widthBucket(log(greatest(${valueExpression}, ${effectiveMin})), log(${effectiveMin}), log(${max}), ${nBuckets})`
? `widthBucket(log(greatest(toFloat64(${valueExpression}), ${effectiveMin})), log(${effectiveMin}), log(${max}), ${nBuckets})`
: `widthBucket(${valueExpression}, ${effectiveMin}, ${max}, ${nBuckets})`;
const bucketConfig: BuilderChartConfigWithDateRange = isAggregateExpression

View file

@ -0,0 +1,21 @@
import { ClickHouseDashboardPage } from '../page-objects/ClickHouseDashboardPage';
import { expect, test } from '../utils/base-test';
test.describe('ClickHouse Dashboard', { tag: ['@full-stack'] }, () => {
let clickhousePage: ClickHouseDashboardPage;
test.beforeEach(async ({ page }) => {
clickhousePage = new ClickHouseDashboardPage(page);
});
test('should load heatmap chart without error', async () => {
await clickhousePage.goto();
await clickhousePage.waitForPageLoad();
// Select the local connection
await clickhousePage.selectConnection('local');
// Assert the heatmap rendered without error
await expect(await clickhousePage.queryLatencyChart).toBeVisible();
});
});

View file

@ -0,0 +1,45 @@
/**
* ClickHouseDashboardPage - Page object for the /clickhouse dashboard page
* Encapsulates interactions with the ClickHouse system dashboard
*/
import { Locator, Page } from '@playwright/test';
export class ClickHouseDashboardPage {
readonly page: Page;
private readonly _pageContainer: Locator;
private readonly _queryLatencyChart: Locator;
private readonly _connectionSelect: Locator;
constructor(page: Page) {
this.page = page;
this._pageContainer = page.getByTestId('clickhouse-dashboard-page');
// Scope heatmap locators to the chart container with the "Query Latency" title
this._queryLatencyChart = this._pageContainer
.locator('div')
.filter({ hasText: 'Query Latency' })
.first();
this._connectionSelect = page.getByPlaceholder('Connection');
}
async goto() {
await this.page.goto('/clickhouse');
}
async selectConnection(connectionName: string) {
await this._connectionSelect.click();
const option = this.page.getByRole('option', { name: connectionName });
await option.click();
}
async waitForPageLoad() {
await this._pageContainer.waitFor({ state: 'visible' });
}
get container(): Locator {
return this._pageContainer;
}
get queryLatencyChart(): Locator {
return this._queryLatencyChart.locator('.uplot');
}
}