From f9de6b12b05f598a4b4e8240a4bb96f094232576 Mon Sep 17 00:00:00 2001 From: Drew Davis Date: Fri, 3 Apr 2026 08:38:14 -0400 Subject: [PATCH 1/3] fix: Hide 'Add Alert' button on SQL Dashboard Tiles --- packages/app/src/DBDashboardPage.tsx | 45 ++++++++++++++-------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/packages/app/src/DBDashboardPage.tsx b/packages/app/src/DBDashboardPage.tsx index ca028befc4..a28f8a276b 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} + > + + + + + + + )} Date: Fri, 3 Apr 2026 08:41:42 -0400 Subject: [PATCH 2/3] fix: Hide Attribute Explorer Group By on Number charts --- .../src/components/DBEditTimeChartForm.tsx | 2 +- .../components/MetricAttributeHelperPanel.tsx | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/app/src/components/DBEditTimeChartForm.tsx b/packages/app/src/components/DBEditTimeChartForm.tsx index 347eeccf4c..1b5ecd2185 100644 --- a/packages/app/src/components/DBEditTimeChartForm.tsx +++ b/packages/app/src/components/DBEditTimeChartForm.tsx @@ -496,7 +496,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 112338f330..07c9c0d860 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 && ( + + )} Date: Fri, 3 Apr 2026 08:59:49 -0400 Subject: [PATCH 3/3] fix: Hide custom/none aggregation for metric sources --- .changeset/short-wombats-develop.md | 5 +++ packages/app/src/components/AggFnSelect.tsx | 7 +++- .../src/components/DBEditTimeChartForm.tsx | 13 +++++-- .../e2e/components/ChartEditorComponent.ts | 33 +++++++++++++++++ .../app/tests/e2e/features/dashboard.spec.ts | 35 +++++++++++++++++++ 5 files changed, 89 insertions(+), 4 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 0000000000..505656e8c8 --- /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/components/AggFnSelect.tsx b/packages/app/src/components/AggFnSelect.tsx index bc234ee7d7..b7a9c97bfe 100644 --- a/packages/app/src/components/AggFnSelect.tsx +++ b/packages/app/src/components/AggFnSelect.tsx @@ -13,10 +13,12 @@ function AggFnSelect({ value, defaultValue, onChange, + hideCustom, }: { value: string; defaultValue: string; onChange: (value: OnChangeValue) => 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 1b5ecd2185..d5c464f520 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 && ( diff --git a/packages/app/tests/e2e/components/ChartEditorComponent.ts b/packages/app/tests/e2e/components/ChartEditorComponent.ts index faf9a1686b..d1b8915ee4 100644 --- a/packages/app/tests/e2e/components/ChartEditorComponent.ts +++ b/packages/app/tests/e2e/components/ChartEditorComponent.ts @@ -18,6 +18,7 @@ export class ChartEditorComponent { private readonly chartTypeInput: Locator; private readonly sourceSelector: Locator; private readonly metricSelector: Locator; + private readonly aggFnSelect: Locator; private readonly addOrRemoveAlertButton: Locator; private readonly webhookSelector: Locator; private readonly runQueryButton: Locator; @@ -29,6 +30,7 @@ export class ChartEditorComponent { this.chartTypeInput = page.getByTestId('chart-type-input'); this.sourceSelector = page.getByTestId('source-selector'); this.metricSelector = page.getByTestId('metric-name-selector'); + this.aggFnSelect = page.getByTestId('agg-fn-select'); this.addOrRemoveAlertButton = page.getByTestId('alert-button'); this.webhookSelector = page.getByTestId('select-webhook'); this.addNewWebhookButton = page.getByTestId('add-new-webhook-button'); @@ -99,6 +101,33 @@ export class ChartEditorComponent { } } + /** + * Select an aggregation function from the dropdown + */ + async selectAggFn(label: string) { + await this.aggFnSelect.click(); + await this.page.getByRole('option', { name: label }).click(); + } + + /** + * Get the currently selected aggregation function value + */ + async getSelectedAggFn(): Promise { + 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 071b0553d9..2872f0e0c1 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', {},