From b4e1498eb3992c06ea0f249c7b6b98004ff8b4c1 Mon Sep 17 00:00:00 2001 From: Drew Davis Date: Fri, 3 Apr 2026 11:44:54 -0400 Subject: [PATCH] fix: Fix minor bugs in chart editor (#2050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary This PR makes a few minor improvements to dashboard tiles and the chart editor ### Hide the "Add Alert" button on dashboard tiles based on raw SQL These tiles don't yet support alerts Screenshot 2026-04-03 at 8 37 36 AM Screenshot 2026-04-03 at 8 37 42 AM Closes HDX-3910 ### Hide the "Group By" button on the Attribute explorer for Number Charts Number charts don't support Group By Screenshot 2026-04-03 at 8 41 10 AM Screenshot 2026-04-03 at 8 41 00 AM Screenshot 2026-04-03 at 8 41 02 AM Screenshot 2026-04-03 at 8 40 56 AM Closes HDX-3871 ### Disable the "Custom" Aggregation for Metric queries These were already broken because there was no input available for the user to provide the custom aggregation. Custom aggregations don't make much sense for metric sources, since the queries we build for metrics would be very difficult for users to build custom aggregations on. We also now have SQL-based charts if users want to do custom aggregations on metric sources. Screenshot 2026-04-03 at 9 03 40 AM Closes HDX-3799 ### How to test locally or on Vercel These can be tested in the preview environment (except for the alert button, that must be tested locally) --- .changeset/short-wombats-develop.md | 5 +++ packages/app/src/DBDashboardPage.tsx | 45 ++++++++++--------- packages/app/src/components/AggFnSelect.tsx | 7 ++- .../src/components/DBEditTimeChartForm.tsx | 15 +++++-- .../components/MetricAttributeHelperPanel.tsx | 24 +++++----- .../e2e/components/ChartEditorComponent.ts | 33 ++++++++++++++ .../app/tests/e2e/features/dashboard.spec.ts | 35 +++++++++++++++ 7 files changed, 126 insertions(+), 38 deletions(-) create mode 100644 .changeset/short-wombats-develop.md diff --git a/.changeset/short-wombats-develop.md b/.changeset/short-wombats-develop.md new file mode 100644 index 00000000..505656e8 --- /dev/null +++ b/.changeset/short-wombats-develop.md @@ -0,0 +1,5 @@ +--- +"@hyperdx/app": patch +--- + +fix: Fix minor bugs in chart editor diff --git a/packages/app/src/DBDashboardPage.tsx b/packages/app/src/DBDashboardPage.tsx index ca028bef..a28f8a27 100644 --- a/packages/app/src/DBDashboardPage.tsx +++ b/packages/app/src/DBDashboardPage.tsx @@ -367,27 +367,28 @@ const Tile = forwardRef( > {(chart.config.displayType === DisplayType.Line || chart.config.displayType === DisplayType.StackedBar || - chart.config.displayType === DisplayType.Number) && ( - +} - mr={4} - > - - - - - - - )} + chart.config.displayType === DisplayType.Number) && + !isRawSqlSavedChartConfig(chart.config) && ( + +} + mr={4} + > + + + + + + + )} void; + hideCustom?: boolean; }) { const _onChange = useCallback( (value: string | null) => { @@ -42,7 +44,7 @@ function AggFnSelect({ value={value} defaultValue={defaultValue} onChange={_onChange} - data={AGG_FNS} + data={hideCustom ? AGG_FNS.filter(fn => fn.value !== 'none') : AGG_FNS} data-testid="agg-fn-select" /> ); @@ -52,11 +54,13 @@ export function AggFnSelectControlled({ aggFnName, quantileLevelName, defaultValue, + hideCustom, ...props }: { defaultValue: string; aggFnName: string; quantileLevelName: string; + hideCustom?: boolean; } & Omit, 'name'>) { const { field: { onChange: onAggFnChange, value: aggFnValue }, @@ -96,6 +100,7 @@ export function AggFnSelectControlled({ value={value} defaultValue={defaultValue} onChange={onChange} + hideCustom={hideCustom} /> ); } diff --git a/packages/app/src/components/DBEditTimeChartForm.tsx b/packages/app/src/components/DBEditTimeChartForm.tsx index fe930f2f..93a3354a 100644 --- a/packages/app/src/components/DBEditTimeChartForm.tsx +++ b/packages/app/src/components/DBEditTimeChartForm.tsx @@ -220,11 +220,17 @@ function ChartSeriesEditorComponent({ const metricType = useWatch({ control, name: `${namePrefix}metricType` }); // Initialize metricType to 'gauge' when switching to a metric source + // and reset 'custom' aggFn to 'count' since custom is not supported for metrics useEffect(() => { - if (tableSource?.kind === SourceKind.Metric && !metricType) { - setValue(`${namePrefix}metricType`, MetricsDataType.Gauge); + if (tableSource?.kind === SourceKind.Metric) { + if (!metricType) { + setValue(`${namePrefix}metricType`, MetricsDataType.Gauge); + } + if (aggFn === 'none') { + setValue(`${namePrefix}aggFn`, 'count'); + } } - }, [tableSource?.kind, metricType, namePrefix, setValue]); + }, [tableSource?.kind, metricType, aggFn, namePrefix, setValue]); const tableName = tableSource?.kind === SourceKind.Metric @@ -363,6 +369,7 @@ function ChartSeriesEditorComponent({ quantileLevelName={`${namePrefix}level`} defaultValue={AGG_FNS[0]?.value ?? 'avg'} control={control} + hideCustom={tableSource?.kind === SourceKind.Metric} /> {tableSource?.kind === SourceKind.Metric && metricType && ( @@ -496,7 +503,7 @@ function ChartSeriesEditorComponent({ language={aggConditionLanguage === 'sql' ? 'sql' : 'lucene'} metricMetadata={metricMetadata} onAddToWhere={handleAddToWhere} - onAddToGroupBy={handleAddToGroupBy} + onAddToGroupBy={showGroupBy ? handleAddToGroupBy : undefined} /> )} diff --git a/packages/app/src/components/MetricAttributeHelperPanel.tsx b/packages/app/src/components/MetricAttributeHelperPanel.tsx index 112338f3..07c9c0d8 100644 --- a/packages/app/src/components/MetricAttributeHelperPanel.tsx +++ b/packages/app/src/components/MetricAttributeHelperPanel.tsx @@ -42,7 +42,7 @@ interface MetricAttributeHelperPanelProps { language: 'sql' | 'lucene'; metricMetadata?: MetricMetadata | null; onAddToWhere: (clause: string) => void; - onAddToGroupBy: (clause: string) => void; + onAddToGroupBy?: (clause: string) => void; } const CATEGORY_LABELS: Record = { @@ -170,7 +170,7 @@ interface AttributeValueListProps { language: 'sql' | 'lucene'; onAddToWhere: (clause: string) => void; onBack: () => void; - onAddToGroupBy: (clause: string) => void; + onAddToGroupBy?: (clause: string) => void; } function AttributeValueList({ @@ -217,7 +217,7 @@ function AttributeValueList({ attribute.name, 'sql', ); - onAddToGroupBy(clause); + onAddToGroupBy?.(clause); }, [attribute, onAddToGroupBy]); return ( @@ -234,14 +234,16 @@ function AttributeValueList({ - + {onAddToGroupBy && ( + + )} { + return this.aggFnSelect.inputValue(); + } + + /** + * Check if an aggregation function option is available in the dropdown + */ + async isAggFnOptionAvailable(label: string): Promise { + await this.aggFnSelect.click(); + const option = this.page.getByRole('option', { name: label }); + const visible = await option.isVisible().catch(() => false); + // Close the dropdown + await this.page.keyboard.press('Escape'); + return visible; + } + async clickAddAlert() { await this.addOrRemoveAlertButton.click(); this.addNewWebhookButton.waitFor({ @@ -250,6 +279,10 @@ export class ChartEditorComponent { return this.metricSelector; } + get aggFn() { + return this.aggFnSelect; + } + get alertButton() { return this.addOrRemoveAlertButton; } diff --git a/packages/app/tests/e2e/features/dashboard.spec.ts b/packages/app/tests/e2e/features/dashboard.spec.ts index 071b0553..2872f0e0 100644 --- a/packages/app/tests/e2e/features/dashboard.spec.ts +++ b/packages/app/tests/e2e/features/dashboard.spec.ts @@ -786,6 +786,41 @@ test.describe('Dashboard', { tag: ['@dashboard'] }, () => { }); }); + test( + 'should deselect and hide the Custom aggregation function when switching to a metric source', + { tag: '@full-stack' }, + async () => { + await test.step('Navigate to dashboard and open new tile editor', async () => { + await dashboardPage.openNewTileEditor(); + }); + + await test.step('Select the "Custom" aggregation function', async () => { + await dashboardPage.chartEditor.selectAggFn('Custom'); + const selectedAggFn = + await dashboardPage.chartEditor.getSelectedAggFn(); + expect(selectedAggFn).toBe('Custom'); + }); + + await test.step('Switch the source to a metric source', async () => { + await dashboardPage.chartEditor.selectSource( + DEFAULT_METRICS_SOURCE_NAME, + ); + }); + + await test.step('Verify the aggregation function was automatically changed away from "Custom"', async () => { + const selectedAggFn = + await dashboardPage.chartEditor.getSelectedAggFn(); + expect(selectedAggFn).toBe('Count of Events'); + }); + + await test.step('Verify the "Custom" option is NOT available in the aggregation dropdown', async () => { + const isCustomAvailable = + await dashboardPage.chartEditor.isAggFnOptionAvailable('Custom'); + expect(isCustomAvailable).toBe(false); + }); + }, + ); + test( 'should clear saved query when WHERE input is cleared and saved', {},