diff --git a/.changeset/few-ravens-teach.md b/.changeset/few-ravens-teach.md new file mode 100644 index 00000000..0af1f812 --- /dev/null +++ b/.changeset/few-ravens-teach.md @@ -0,0 +1,5 @@ +--- +"@hyperdx/app": patch +--- + +fix: Fix query error on ClickHouse Query latency chart diff --git a/packages/app/src/components/DBHeatmapChart.tsx b/packages/app/src/components/DBHeatmapChart.tsx index bad724eb..f548a3b7 100644 --- a/packages/app/src/components/DBHeatmapChart.tsx +++ b/packages/app/src/components/DBHeatmapChart.tsx @@ -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 diff --git a/packages/app/tests/e2e/features/clickhouse-dashboard.spec.ts b/packages/app/tests/e2e/features/clickhouse-dashboard.spec.ts new file mode 100644 index 00000000..ca3a33ec --- /dev/null +++ b/packages/app/tests/e2e/features/clickhouse-dashboard.spec.ts @@ -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(); + }); +}); diff --git a/packages/app/tests/e2e/page-objects/ClickHouseDashboardPage.ts b/packages/app/tests/e2e/page-objects/ClickHouseDashboardPage.ts new file mode 100644 index 00000000..7b2b207f --- /dev/null +++ b/packages/app/tests/e2e/page-objects/ClickHouseDashboardPage.ts @@ -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'); + } +}