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/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}
+ >
+
+
+
+
+
+
+ )}
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 fe930f2f22..93a3354a10 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 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({
- }
- onClick={handleAddToGroupBy}
- >
- Group By
-
+ {onAddToGroupBy && (
+ }
+ onClick={handleAddToGroupBy}
+ >
+ Group By
+
+ )}
{
+ 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',
{},