diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
new file mode 100644
index 0000000000000..e7ff7cd9a7565
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.test.tsx
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom/extend-expect';
+import { Provider } from 'react-redux';
+import configureMockStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import { supersetTheme, ThemeProvider } from '@superset-ui/core';
+import ColumnSelectPopover from 'src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover';
+
+const middlewares = [thunk];
+const mockStore = configureMockStore(middlewares);
+
+describe('ColumnSelectPopover - onTabChange function', () => {
+ it('updates adhocColumn when switching to sqlExpression tab with custom label', () => {
+ const mockColumns = [{ column_name: 'year' }];
+ const mockOnClose = jest.fn();
+ const mockOnChange = jest.fn();
+ const mockGetCurrentTab = jest.fn();
+ const mockSetDatasetModal = jest.fn();
+ const mockSetLabel = jest.fn();
+
+ const store = mockStore({ explore: { datasource: { type: 'table' } } });
+
+ const { container, getByText } = render(
+
+
+
+
+ ,
+ );
+
+ const sqlExpressionTab = container.querySelector(
+ '#adhoc-metric-edit-tabs-tab-sqlExpression',
+ );
+ expect(sqlExpressionTab).not.toBeNull();
+ fireEvent.click(sqlExpressionTab!);
+ expect(mockGetCurrentTab).toHaveBeenCalledWith('sqlExpression');
+
+ const saveButton = getByText('Save');
+ fireEvent.click(saveButton);
+ expect(mockOnChange).toHaveBeenCalledWith({
+ label: 'Custom Label',
+ sqlExpression: 'year',
+ expressionType: 'SQL',
+ });
+ });
+});
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index 4806e5394a3ae..96abf36484c0f 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -68,6 +68,7 @@ interface ColumnSelectPopoverProps {
editedColumn?: ColumnMeta | AdhocColumn;
onChange: (column: ColumnMeta | AdhocColumn) => void;
onClose: () => void;
+ hasCustomLabel: boolean;
setLabel: (title: string) => void;
getCurrentTab: (tab: string) => void;
label: string;
@@ -93,13 +94,14 @@ const getInitialColumnValues = (
const ColumnSelectPopover = ({
columns,
editedColumn,
+ getCurrentTab,
+ hasCustomLabel,
+ isTemporal,
+ label,
onChange,
onClose,
setDatasetModal,
setLabel,
- getCurrentTab,
- label,
- isTemporal,
}: ColumnSelectPopoverProps) => {
const datasourceType = useSelector(
state => state.explore.datasource.type,
@@ -117,6 +119,7 @@ const ColumnSelectPopover = ({
const [selectedSimpleColumn, setSelectedSimpleColumn] = useState<
ColumnMeta | undefined
>(initialSimpleColumn);
+ const [selectedTab, setSelectedTab] = useState(null);
const [resizeButton, width, height] = useResizeButton(
POPOVER_INITIAL_WIDTH,
@@ -188,7 +191,34 @@ const ColumnSelectPopover = ({
useEffect(() => {
getCurrentTab(defaultActiveTabKey);
- }, [defaultActiveTabKey, getCurrentTab]);
+ setSelectedTab(defaultActiveTabKey);
+ }, [defaultActiveTabKey, getCurrentTab, setSelectedTab]);
+
+ useEffect(() => {
+ /* if the adhoc column is not set (because it was never edited) but the
+ * tab is selected and the label has changed, then we need to set the
+ * adhoc column manually */
+ if (
+ adhocColumn === undefined &&
+ selectedTab === 'sqlExpression' &&
+ hasCustomLabel
+ ) {
+ const sqlExpression =
+ selectedSimpleColumn?.column_name ||
+ selectedCalculatedColumn?.expression ||
+ '';
+ setAdhocColumn({ label, sqlExpression, expressionType: 'SQL' });
+ }
+ }, [
+ adhocColumn,
+ defaultActiveTabKey,
+ hasCustomLabel,
+ getCurrentTab,
+ label,
+ selectedCalculatedColumn,
+ selectedSimpleColumn,
+ selectedTab,
+ ]);
const onSave = useCallback(() => {
if (adhocColumn && adhocColumn.label !== label) {
@@ -225,6 +255,7 @@ const ColumnSelectPopover = ({
const onTabChange = useCallback(
tab => {
getCurrentTab(tab);
+ setSelectedTab(tab);
// @ts-ignore
sqlEditorRef.current?.editor.focus();
},
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
index 4340317f04d11..341d91e616cc8 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
@@ -103,6 +103,7 @@ const ColumnSelectPopoverTrigger = ({
setDatasetModal={setDatasetModal}
onClose={handleClosePopover}
onChange={onColumnEdit}
+ hasCustomLabel={hasCustomLabel}
label={popoverLabel}
setLabel={setPopoverLabel}
getCurrentTab={getCurrentTab}
@@ -114,6 +115,7 @@ const ColumnSelectPopoverTrigger = ({
columns,
editedColumn,
getCurrentTab,
+ hasCustomLabel,
handleClosePopover,
isTemporal,
onColumnEdit,
@@ -121,10 +123,13 @@ const ColumnSelectPopoverTrigger = ({
],
);
- const onLabelChange = useCallback((e: any) => {
- setPopoverLabel(e.target.value);
- setHasCustomLabel(true);
- }, []);
+ const onLabelChange = useCallback(
+ (e: any) => {
+ setPopoverLabel(e.target.value);
+ setHasCustomLabel(true);
+ },
+ [setPopoverLabel, setHasCustomLabel],
+ );
const popoverTitle = useMemo(
() => (