This is an automated email from the ASF dual-hosted git repository.
kgabryje pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 203c311 feat(explore): make dnd controls clickable (#16119)
203c311 is described below
commit 203c311ca30cba616bff5253ca561438da21c03e
Author: Kamil Gabryjelski <[email protected]>
AuthorDate: Tue Aug 17 14:56:39 2021 +0200
feat(explore): make dnd controls clickable (#16119)
* Make ghost buttons clickable
* Popover for column control
* Make column dnd ghost button clickable
* Prefill operator only if column is defined
* Remove data-tests
* lint fix
* Hide new features behind a feature flag
* Change ghost button texts
* Remove caret for non clickable columns
---
.../DndColumnSelectControl/ColumnSelectPopover.tsx | 223 +++++++++++++++++++++
.../ColumnSelectPopoverTrigger.tsx | 99 +++++++++
.../DndColumnSelectControl/DndColumnSelect.tsx | 134 ++++++++++---
.../DndColumnSelectControl/DndFilterSelect.tsx | 18 +-
.../DndColumnSelectControl/DndMetricSelect.tsx | 28 ++-
.../DndColumnSelectControl/DndSelectLabel.tsx | 5 +-
.../controls/DndColumnSelectControl/types.ts | 1 +
superset/config.py | 1 +
8 files changed, 475 insertions(+), 34 deletions(-)
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
new file mode 100644
index 0000000..c58b3d3
--- /dev/null
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -0,0 +1,223 @@
+/**
+ * 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.
+ */
+/* eslint-disable camelcase */
+import React, { useCallback, useMemo, useState } from 'react';
+import Tabs from 'src/components/Tabs';
+import Button from 'src/components/Button';
+import { NativeSelect as Select } from 'src/components/Select';
+import { t, styled } from '@superset-ui/core';
+
+import { Form, FormItem } from 'src/components/Form';
+import { StyledColumnOption } from 'src/explore/components/optionRenderers';
+import { ColumnMeta } from '@superset-ui/chart-controls';
+
+const StyledSelect = styled(Select)`
+ .metric-option {
+ & > svg {
+ min-width: ${({ theme }) => `${theme.gridUnit * 4}px`};
+ }
+ & > .option-label {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+ }
+`;
+
+interface ColumnSelectPopoverProps {
+ columns: ColumnMeta[];
+ editedColumn?: ColumnMeta;
+ onChange: (column: ColumnMeta) => void;
+ onClose: () => void;
+}
+
+const ColumnSelectPopover = ({
+ columns,
+ editedColumn,
+ onChange,
+ onClose,
+}: ColumnSelectPopoverProps) => {
+ const [
+ initialCalculatedColumn,
+ initialSimpleColumn,
+ ] = editedColumn?.expression
+ ? [editedColumn, undefined]
+ : [undefined, editedColumn];
+ const [selectedCalculatedColumn, setSelectedCalculatedColumn] = useState(
+ initialCalculatedColumn,
+ );
+ const [selectedSimpleColumn, setSelectedSimpleColumn] = useState(
+ initialSimpleColumn,
+ );
+
+ const [calculatedColumns, simpleColumns] = useMemo(
+ () =>
+ columns?.reduce(
+ (acc: [ColumnMeta[], ColumnMeta[]], column: ColumnMeta) => {
+ if (column.expression) {
+ acc[0].push(column);
+ } else {
+ acc[1].push(column);
+ }
+ return acc;
+ },
+ [[], []],
+ ),
+ [columns],
+ );
+
+ const onCalculatedColumnChange = useCallback(
+ selectedColumnName => {
+ const selectedColumn = calculatedColumns.find(
+ col => col.column_name === selectedColumnName,
+ );
+ setSelectedCalculatedColumn(selectedColumn);
+ setSelectedSimpleColumn(undefined);
+ },
+ [calculatedColumns],
+ );
+
+ const onSimpleColumnChange = useCallback(
+ selectedColumnName => {
+ const selectedColumn = simpleColumns.find(
+ col => col.column_name === selectedColumnName,
+ );
+ setSelectedCalculatedColumn(undefined);
+ setSelectedSimpleColumn(selectedColumn);
+ },
+ [simpleColumns],
+ );
+
+ const defaultActiveTabKey =
+ initialSimpleColumn || calculatedColumns.length === 0 ? 'simple' : 'saved';
+
+ const onSave = useCallback(() => {
+ const selectedColumn = selectedCalculatedColumn || selectedSimpleColumn;
+ if (!selectedColumn) {
+ return;
+ }
+ onChange(selectedColumn);
+ onClose();
+ }, [onChange, onClose, selectedCalculatedColumn, selectedSimpleColumn]);
+
+ const onResetStateAndClose = useCallback(() => {
+ setSelectedCalculatedColumn(initialCalculatedColumn);
+ setSelectedSimpleColumn(initialSimpleColumn);
+ onClose();
+ }, [initialCalculatedColumn, initialSimpleColumn, onClose]);
+
+ const stateIsValid = selectedCalculatedColumn || selectedSimpleColumn;
+ const hasUnsavedChanges =
+ selectedCalculatedColumn?.column_name !==
+ initialCalculatedColumn?.column_name ||
+ selectedSimpleColumn?.column_name !== initialSimpleColumn?.column_name;
+
+ const filterOption = useCallback(
+ (input, option) =>
+ option?.filterBy.toLowerCase().indexOf(input.toLowerCase()) >= 0,
+ [],
+ );
+
+ const getPopupContainer = useCallback(
+ (triggerNode: any) => triggerNode.parentNode,
+ [],
+ );
+
+ return (
+ <Form layout="vertical" id="metrics-edit-popover">
+ <Tabs
+ id="adhoc-metric-edit-tabs"
+ defaultActiveKey={defaultActiveTabKey}
+ className="adhoc-metric-edit-tabs"
+ allowOverflow
+ >
+ <Tabs.TabPane key="saved" tab={t('Saved')}>
+ <FormItem label={t('Saved expressions')}>
+ <StyledSelect
+ value={selectedCalculatedColumn?.column_name}
+ getPopupContainer={getPopupContainer}
+ onChange={onCalculatedColumnChange}
+ allowClear
+ showSearch
+ autoFocus={!selectedCalculatedColumn}
+ filterOption={filterOption}
+ placeholder={t('%s column(s)', calculatedColumns.length)}
+ >
+ {calculatedColumns.map(calculatedColumn => (
+ <Select.Option
+ value={calculatedColumn.column_name}
+ filterBy={
+ calculatedColumn.verbose_name ||
+ calculatedColumn.column_name
+ }
+ key={calculatedColumn.column_name}
+ >
+ <StyledColumnOption column={calculatedColumn} showType />
+ </Select.Option>
+ ))}
+ </StyledSelect>
+ </FormItem>
+ </Tabs.TabPane>
+ <Tabs.TabPane key="simple" tab={t('Simple')}>
+ <FormItem label={t('Column')}>
+ <Select
+ value={selectedSimpleColumn?.column_name}
+ getPopupContainer={getPopupContainer}
+ onChange={onSimpleColumnChange}
+ allowClear
+ showSearch
+ autoFocus={!selectedSimpleColumn}
+ filterOption={filterOption}
+ placeholder={t('%s column(s)', simpleColumns.length)}
+ >
+ {simpleColumns.map(simpleColumn => (
+ <Select.Option
+ value={simpleColumn.column_name}
+ filterBy={
+ simpleColumn.verbose_name || simpleColumn.column_name
+ }
+ key={simpleColumn.column_name}
+ >
+ <StyledColumnOption column={simpleColumn} showType />
+ </Select.Option>
+ ))}
+ </Select>
+ </FormItem>
+ </Tabs.TabPane>
+ </Tabs>
+ <div>
+ <Button buttonSize="small" onClick={onResetStateAndClose} cta>
+ {t('Close')}
+ </Button>
+ <Button
+ disabled={!stateIsValid}
+ buttonStyle={
+ hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
+ }
+ buttonSize="small"
+ onClick={onSave}
+ cta
+ >
+ {t('Save')}
+ </Button>
+ </div>
+ </Form>
+ );
+};
+
+export default ColumnSelectPopover;
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
new file mode 100644
index 0000000..4caf086
--- /dev/null
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopoverTrigger.tsx
@@ -0,0 +1,99 @@
+/**
+ * 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, { useCallback, useMemo, useState } from 'react';
+import { ColumnMeta } from '@superset-ui/chart-controls';
+import Popover from 'src/components/Popover';
+import { ExplorePopoverContent } from
'src/explore/components/ExploreContentPopover';
+import ColumnSelectPopover from './ColumnSelectPopover';
+
+interface ColumnSelectPopoverTriggerProps {
+ columns: ColumnMeta[];
+ editedColumn?: ColumnMeta;
+ onColumnEdit: (editedColumn: ColumnMeta) => void;
+ isControlledComponent?: boolean;
+ visible?: boolean;
+ togglePopover?: (visible: boolean) => void;
+ closePopover?: () => void;
+ children: React.ReactNode;
+}
+
+const ColumnSelectPopoverTrigger = ({
+ columns,
+ editedColumn,
+ onColumnEdit,
+ isControlledComponent,
+ children,
+ ...props
+}: ColumnSelectPopoverTriggerProps) => {
+ const [popoverVisible, setPopoverVisible] = useState(false);
+
+ const togglePopover = useCallback((visible: boolean) => {
+ setPopoverVisible(visible);
+ }, []);
+
+ const closePopover = useCallback(() => {
+ setPopoverVisible(false);
+ }, []);
+
+ const {
+ visible,
+ handleTogglePopover,
+ handleClosePopover,
+ } = isControlledComponent
+ ? {
+ visible: props.visible,
+ handleTogglePopover: props.togglePopover!,
+ handleClosePopover: props.closePopover!,
+ }
+ : {
+ visible: popoverVisible,
+ handleTogglePopover: togglePopover,
+ handleClosePopover: closePopover,
+ };
+
+ const overlayContent = useMemo(
+ () => (
+ <ExplorePopoverContent>
+ <ColumnSelectPopover
+ editedColumn={editedColumn}
+ columns={columns}
+ onClose={handleClosePopover}
+ onChange={onColumnEdit}
+ />
+ </ExplorePopoverContent>
+ ),
+ [columns, editedColumn, handleClosePopover, onColumnEdit],
+ );
+
+ return (
+ <Popover
+ placement="right"
+ trigger="click"
+ content={overlayContent}
+ defaultVisible={visible}
+ visible={visible}
+ onVisibleChange={handleTogglePopover}
+ destroyTooltipOnHide
+ >
+ {children}
+ </Popover>
+ );
+};
+
+export default ColumnSelectPopoverTrigger;
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
index 788b4e2..69cc644 100644
---
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
@@ -16,8 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-import React, { useCallback, useMemo } from 'react';
-import { tn } from '@superset-ui/core';
+import React, { useCallback, useMemo, useState } from 'react';
+import { FeatureFlag, isFeatureEnabled, tn } from '@superset-ui/core';
import { ColumnMeta } from '@superset-ui/chart-controls';
import { isEmpty } from 'lodash';
import { LabelProps } from
'src/explore/components/controls/DndColumnSelectControl/types';
@@ -27,6 +27,7 @@ import { OptionSelector } from
'src/explore/components/controls/DndColumnSelectC
import { DatasourcePanelDndItem } from
'src/explore/components/DatasourcePanel/types';
import { DndItemType } from 'src/explore/components/DndItemType';
import { useComponentDidUpdate } from 'src/common/hooks/useComponentDidUpdate';
+import ColumnSelectPopoverTrigger from './ColumnSelectPopoverTrigger';
export const DndColumnSelect = (props: LabelProps) => {
const {
@@ -39,6 +40,8 @@ export const DndColumnSelect = (props: LabelProps) => {
name,
label,
} = props;
+ const [newColumnPopoverVisible, setNewColumnPopoverVisible] =
useState(false);
+
const optionSelector = useMemo(
() => new OptionSelector(options, multi, value),
[multi, options, value],
@@ -110,41 +113,120 @@ export const DndColumnSelect = (props: LabelProps) => {
[onChange, optionSelector],
);
+ const popoverOptions = useMemo(
+ () =>
+ Object.values(options).filter(
+ col =>
+ !optionSelector.values
+ .map(val => val.column_name)
+ .includes(col.column_name),
+ ),
+ [optionSelector.values, options],
+ );
+
const valuesRenderer = useCallback(
() =>
- optionSelector.values.map((column, idx) => (
- <OptionWrapper
- key={idx}
- index={idx}
- clickClose={onClickClose}
- onShiftOptions={onShiftOptions}
- type={`${DndItemType.ColumnOption}_${name}_${label}`}
- canDelete={canDelete}
- column={column}
- />
- )),
+ optionSelector.values.map((column, idx) =>
+ isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) ? (
+ <ColumnSelectPopoverTrigger
+ columns={popoverOptions}
+ onColumnEdit={newColumn => {
+ optionSelector.replace(idx, newColumn.column_name);
+ onChange(optionSelector.getValues());
+ }}
+ editedColumn={column}
+ >
+ <OptionWrapper
+ key={idx}
+ index={idx}
+ clickClose={onClickClose}
+ onShiftOptions={onShiftOptions}
+ type={`${DndItemType.ColumnOption}_${name}_${label}`}
+ canDelete={canDelete}
+ column={column}
+ withCaret
+ />
+ </ColumnSelectPopoverTrigger>
+ ) : (
+ <OptionWrapper
+ key={idx}
+ index={idx}
+ clickClose={onClickClose}
+ onShiftOptions={onShiftOptions}
+ type={`${DndItemType.ColumnOption}_${name}_${label}`}
+ canDelete={canDelete}
+ column={column}
+ />
+ ),
+ ),
[
canDelete,
label,
name,
+ onChange,
onClickClose,
onShiftOptions,
- optionSelector.values,
+ optionSelector,
+ popoverOptions,
],
);
+ const addNewColumnWithPopover = useCallback(
+ (newColumn: ColumnMeta) => {
+ optionSelector.add(newColumn.column_name);
+ onChange(optionSelector.getValues());
+ },
+ [onChange, optionSelector],
+ );
+
+ const togglePopover = useCallback((visible: boolean) => {
+ setNewColumnPopoverVisible(visible);
+ }, []);
+
+ const closePopover = useCallback(() => {
+ togglePopover(false);
+ }, [togglePopover]);
+
+ const openPopover = useCallback(() => {
+ togglePopover(true);
+ }, [togglePopover]);
+
+ const defaultGhostButtonText = isFeatureEnabled(
+ FeatureFlag.ENABLE_DND_WITH_CLICK_UX,
+ )
+ ? tn(
+ 'Drop a column here or click',
+ 'Drop columns here or click',
+ multi ? 2 : 1,
+ )
+ : tn('Drop column here', 'Drop columns here', multi ? 2 : 1);
+
return (
- <DndSelectLabel<string | string[], ColumnMeta[]>
- onDrop={onDrop}
- canDrop={canDrop}
- valuesRenderer={valuesRenderer}
- accept={DndItemType.Column}
- displayGhostButton={multi || optionSelector.values.length === 0}
- ghostButtonText={
- ghostButtonText ||
- tn('Drop column here', 'Drop columns here', multi ? 2 : 1)
- }
- {...props}
- />
+ <div>
+ <DndSelectLabel<string | string[], ColumnMeta[]>
+ onDrop={onDrop}
+ canDrop={canDrop}
+ valuesRenderer={valuesRenderer}
+ accept={DndItemType.Column}
+ displayGhostButton={multi || optionSelector.values.length === 0}
+ ghostButtonText={ghostButtonText || defaultGhostButtonText}
+ onClickGhostButton={
+ isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
+ ? openPopover
+ : undefined
+ }
+ {...props}
+ />
+ <ColumnSelectPopoverTrigger
+ columns={popoverOptions}
+ onColumnEdit={addNewColumnWithPopover}
+ isControlledComponent
+ togglePopover={togglePopover}
+ closePopover={closePopover}
+ visible={newColumnPopoverVisible}
+ >
+ <div />
+ </ColumnSelectPopoverTrigger>
+ </div>
);
};
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
index 1e2eba8..97842f5 100644
---
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
@@ -333,6 +333,11 @@ export const DndFilterSelect = (props:
DndFilterSelectProps) => {
],
);
+ const handleClickGhostButton = useCallback(() => {
+ setDroppedItem(null);
+ togglePopover(true);
+ }, [togglePopover]);
+
const adhocFilter = useMemo(() => {
if (droppedItem?.metric_name) {
return new AdhocFilter({
@@ -351,7 +356,7 @@ export const DndFilterSelect = (props:
DndFilterSelectProps) => {
const config: Partial<AdhocFilter> = {
subject: (droppedItem as ColumnMeta)?.column_name,
};
- if (isFeatureEnabled(FeatureFlag.UX_BETA)) {
+ if (config.subject && isFeatureEnabled(FeatureFlag.UX_BETA)) {
config.operator = OPERATOR_ENUM_TO_OPERATOR_TYPE[Operators.IN].operation;
config.operatorId = Operators.IN;
}
@@ -367,6 +372,10 @@ export const DndFilterSelect = (props:
DndFilterSelectProps) => {
[togglePopover],
);
+ const ghostButtonText =
isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
+ ? t('Drop columns/metrics here or click')
+ : t('Drop columns or metrics here');
+
return (
<>
<DndSelectLabel<OptionValueType, OptionValueType[]>
@@ -374,7 +383,12 @@ export const DndFilterSelect = (props:
DndFilterSelectProps) => {
canDrop={canDrop}
valuesRenderer={valuesRenderer}
accept={DND_ACCEPTED_TYPES}
- ghostButtonText={t('Drop columns or metrics here')}
+ ghostButtonText={ghostButtonText}
+ onClickGhostButton={
+ isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
+ ? handleClickGhostButton
+ : undefined
+ }
{...props}
/>
<AdhocFilterPopoverTrigger
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
index f44934a..5967f33 100644
---
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
@@ -312,6 +312,11 @@ export const DndMetricSelect = (props: any) => {
[onNewMetric, togglePopover],
);
+ const handleClickGhostButton = useCallback(() => {
+ setDroppedItem(null);
+ togglePopover(true);
+ }, [togglePopover]);
+
const adhocMetric = useMemo(() => {
if (droppedItem?.type === DndItemType.Column) {
const itemValue = droppedItem?.value as ColumnMeta;
@@ -334,6 +339,18 @@ export const DndMetricSelect = (props: any) => {
return new AdhocMetric({ isNew: true });
}, [droppedItem]);
+ const ghostButtonText =
isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
+ ? tn(
+ 'Drop a column/metric here or click',
+ 'Drop columns/metrics here or click',
+ multi ? 2 : 1,
+ )
+ : tn(
+ 'Drop column or metric here',
+ 'Drop columns or metrics here',
+ multi ? 2 : 1,
+ );
+
return (
<div className="metrics-select">
<DndSelectLabel<OptionValueType, OptionValueType[]>
@@ -341,12 +358,13 @@ export const DndMetricSelect = (props: any) => {
canDrop={canDrop}
valuesRenderer={valuesRenderer}
accept={DND_ACCEPTED_TYPES}
- ghostButtonText={tn(
- 'Drop column or metric here',
- 'Drop columns or metrics here',
- multi ? 2 : 1,
- )}
+ ghostButtonText={ghostButtonText}
displayGhostButton={multi || value.length === 0}
+ onClickGhostButton={
+ isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
+ ? handleClickGhostButton
+ : undefined
+ }
{...props}
/>
<AdhocMetricPopoverTrigger
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
index d5d365f..d3bf95d 100644
---
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
@@ -55,7 +55,10 @@ export default function DndSelectLabel<T, O>({
function renderGhostButton() {
return (
- <AddControlLabel cancelHover>
+ <AddControlLabel
+ cancelHover={!props.onClickGhostButton}
+ onClick={props.onClickGhostButton}
+ >
<Icons.PlusSmall iconColor={theme.colors.grayscale.light1} />
{t(props.ghostButtonText || 'Drop columns here')}
</AddControlLabel>
diff --git
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
index 6a8a687..b77e9d2 100644
---
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
+++
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
@@ -65,6 +65,7 @@ export interface DndColumnSelectProps<
accept: DndItemType | DndItemType[];
ghostButtonText?: string;
displayGhostButton?: boolean;
+ onClickGhostButton?: () => void;
}
export type OptionValueType = Record<string, any>;
diff --git a/superset/config.py b/superset/config.py
index 58d9693..f18fcca 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -388,6 +388,7 @@ DEFAULT_FEATURE_FLAGS: Dict[str, bool] = {
"OMNIBAR": False,
"DASHBOARD_RBAC": False,
"ENABLE_EXPLORE_DRAG_AND_DROP": False,
+ "ENABLE_DND_WITH_CLICK_UX": False,
# Enabling ALERTS_ATTACH_REPORTS, the system sends email and slack message
# with screenshot and link
# Disables ALERTS_ATTACH_REPORTS, the system DOES NOT generate screenshot