diff --git a/RESOURCES/FEATURE_FLAGS.md b/RESOURCES/FEATURE_FLAGS.md
index b668845a88..5df7c0de71 100644
--- a/RESOURCES/FEATURE_FLAGS.md
+++ b/RESOURCES/FEATURE_FLAGS.md
@@ -73,8 +73,6 @@ These features flags are **safe for production**. They have been tested and will
- DRUID_JOINS
- EMBEDDABLE_CHARTS
- EMBEDDED_SUPERSET
-- ENABLE_DND_WITH_CLICK_UX
-- ENABLE_EXPLORE_DRAG_AND_DROP
- ENABLE_TEMPLATE_PROCESSING
- ESCAPE_MARKDOWN_HTML
- LISTVIEWS_DEFAULT_CARD_VIEW
@@ -95,6 +93,7 @@ These features flags currently default to True and **will be removed in a future
- DASHBOARD_NATIVE_FILTERS
- DASHBOARD_NATIVE_FILTERS_SET
- DISABLE_DATASET_SOURCE_EDIT
+- ENABLE_EXPLORE_DRAG_AND_DROP
- ENABLE_EXPLORE_JSON_CSRF_PROTECTION
- GENERIC_CHART_AXES
- REMOVE_SLICE_LEVEL_LABEL_COLORS
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
index 840c5c3611..c915e8a89d 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
@@ -244,8 +244,7 @@ export const dndGranularitySqlaControl: typeof dndSeriesControl = {
default: (c: Control) => c.default,
clearable: false,
canDelete: false,
- ghostButtonText: t('Drop temporal column here'),
- clickEnabledGhostButtonText: t('Drop a temporal column here or click'),
+ ghostButtonText: t('Drop a temporal column here or click'),
optionRenderer: (c: ColumnMeta) => ,
valueRenderer: (c: ColumnMeta) => ,
valueKey: 'column_name',
diff --git a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
index fbb1efd340..2cf67b080c 100644
--- a/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
+++ b/superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
@@ -40,7 +40,6 @@ export enum FeatureFlag {
EMBEDDABLE_CHARTS = 'EMBEDDABLE_CHARTS',
EMBEDDED_SUPERSET = 'EMBEDDED_SUPERSET',
ENABLE_ADVANCED_DATA_TYPES = 'ENABLE_ADVANCED_DATA_TYPES',
- ENABLE_DND_WITH_CLICK_UX = 'ENABLE_DND_WITH_CLICK_UX',
ENABLE_EXPLORE_DRAG_AND_DROP = 'ENABLE_EXPLORE_DRAG_AND_DROP',
ENABLE_JAVASCRIPT_CONTROLS = 'ENABLE_JAVASCRIPT_CONTROLS',
ENABLE_TEMPLATE_PROCESSING = 'ENABLE_TEMPLATE_PROCESSING',
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx
index 5cf5c59fd9..8eb068c022 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.test.tsx
@@ -45,7 +45,9 @@ test('renders with default props', async () => {
useDnd: true,
useRedux: true,
});
- expect(await screen.findByText('Drop columns here')).toBeInTheDocument();
+ expect(
+ await screen.findByText('Drop columns here or click'),
+ ).toBeInTheDocument();
});
test('renders with value', async () => {
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
index 071fdbd424..673861458d 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelect.tsx
@@ -19,8 +19,6 @@
import React, { useCallback, useMemo, useState } from 'react';
import {
AdhocColumn,
- FeatureFlag,
- isFeatureEnabled,
tn,
QueryFormColumn,
t,
@@ -54,7 +52,6 @@ function DndColumnSelect(props: DndColumnSelectProps) {
onChange,
canDelete = true,
ghostButtonText,
- clickEnabledGhostButtonText,
name,
label,
isTemporal,
@@ -108,11 +105,6 @@ function DndColumnSelect(props: DndColumnSelectProps) {
[onChange, optionSelector],
);
- const clickEnabled = useMemo(
- () => isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX),
- [],
- );
-
const valuesRenderer = useCallback(
() =>
optionSelector.values.map((column, idx) => {
@@ -120,7 +112,7 @@ function DndColumnSelect(props: DndColumnSelectProps) {
isAdhocColumn(column) && column.datasourceWarning
? t('This column might be incompatible with current dataset')
: undefined;
- return clickEnabled ? (
+ return (
- ) : (
-
);
}),
[
canDelete,
- clickEnabled,
isTemporal,
label,
name,
@@ -198,24 +178,16 @@ function DndColumnSelect(props: DndColumnSelectProps) {
togglePopover(true);
}, [togglePopover]);
- const labelGhostButtonText = useMemo(() => {
- if (clickEnabled) {
- return (
- clickEnabledGhostButtonText ??
- ghostButtonText ??
- tn(
- 'Drop a column here or click',
- 'Drop columns here or click',
- multi ? 2 : 1,
- )
- );
- }
-
- return (
+ const labelGhostButtonText = useMemo(
+ () =>
ghostButtonText ??
- tn('Drop column here', 'Drop columns here', multi ? 2 : 1)
- );
- }, [clickEnabled, clickEnabledGhostButtonText, ghostButtonText, multi]);
+ tn(
+ 'Drop a column here or click',
+ 'Drop columns here or click',
+ multi ? 2 : 1,
+ ),
+ [ghostButtonText, multi],
+ );
return (
@@ -226,7 +198,7 @@ function DndColumnSelect(props: DndColumnSelectProps) {
accept={DndItemType.Column}
displayGhostButton={multi || optionSelector.values.length === 0}
ghostButtonText={labelGhostButtonText}
- onClickGhostButton={clickEnabled ? openPopover : undefined}
+ onClickGhostButton={openPopover}
{...props}
/>
{
render(setup(), { useDnd: true });
expect(
- await screen.findByText('Drop columns or metrics here'),
+ await screen.findByText('Drop columns/metrics here or click'),
).toBeInTheDocument();
});
@@ -122,7 +122,7 @@ test('renders options with saved metric', async () => {
},
);
expect(
- await screen.findByText('Drop columns or metrics here'),
+ await screen.findByText('Drop columns/metrics here or click'),
).toBeInTheDocument();
});
@@ -143,7 +143,7 @@ test('renders options with column', async () => {
},
);
expect(
- await screen.findByText('Drop columns or metrics here'),
+ await screen.findByText('Drop columns/metrics here or click'),
).toBeInTheDocument();
});
@@ -165,6 +165,6 @@ test('renders options with adhoc metric', async () => {
},
);
expect(
- await screen.findByText('Drop columns or metrics here'),
+ await screen.findByText('Drop columns/metrics here or click'),
).toBeInTheDocument();
});
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
index da9410fcf2..387f484904 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndFilterSelect.tsx
@@ -18,9 +18,7 @@
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
- FeatureFlag,
hasGenericChartAxes,
- isFeatureEnabled,
logging,
Metric,
QueryFormData,
@@ -397,10 +395,6 @@ const DndFilterSelect = (props: DndFilterSelectProps) => {
[controlName, togglePopover],
);
- const ghostButtonText = isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
- ? t('Drop columns/metrics here or click')
- : t('Drop columns or metrics here');
-
return (
<>
{
canDrop={canDrop}
valuesRenderer={valuesRenderer}
accept={DND_ACCEPTED_TYPES}
- ghostButtonText={ghostButtonText}
- onClickGhostButton={
- isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
- ? handleClickGhostButton
- : undefined
- }
+ ghostButtonText={t('Drop columns/metrics here or click')}
+ onClickGhostButton={handleClickGhostButton}
{...props}
/>
{
test('renders with default props', () => {
render(, { useDnd: true });
- expect(screen.getByText('Drop column or metric here')).toBeInTheDocument();
+ expect(
+ screen.getByText('Drop a column/metric here or click'),
+ ).toBeInTheDocument();
});
test('renders with default props and multi = true', () => {
render(, { useDnd: true });
- expect(screen.getByText('Drop columns or metrics here')).toBeInTheDocument();
+ expect(
+ screen.getByText('Drop columns/metrics here or click'),
+ ).toBeInTheDocument();
});
test('render selected metrics correctly', () => {
@@ -159,7 +163,7 @@ test('remove selected custom metric when metric gets removed from dataset for si
expect(screen.getByText('Metric B')).toBeVisible();
expect(
- screen.queryByText('Drop column or metric here'),
+ screen.queryByText('Drop a column/metric here or click'),
).not.toBeInTheDocument();
const newPropsWithRemovedMetric = {
@@ -182,7 +186,7 @@ test('remove selected custom metric when metric gets removed from dataset for si
);
expect(screen.queryByText('Metric B')).not.toBeInTheDocument();
- expect(screen.getByText('Drop column or metric here')).toBeVisible();
+ expect(screen.getByText('Drop a column/metric here or click')).toBeVisible();
});
test('remove selected adhoc metric when column gets removed from dataset', async () => {
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
index 30904a07ec..afa0a32f0c 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndMetricSelect.tsx
@@ -20,10 +20,8 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
ensureIsArray,
- FeatureFlag,
GenericDataType,
isAdhocMetricSimple,
- isFeatureEnabled,
isSavedMetric,
Metric,
QueryFormMetric,
@@ -329,17 +327,11 @@ const DndMetricSelect = (props: any) => {
return new AdhocMetric({});
}, [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,
- );
+ const ghostButtonText = tn(
+ 'Drop a column/metric here or click',
+ 'Drop columns/metrics here or click',
+ multi ? 2 : 1,
+ );
return (
@@ -350,11 +342,7 @@ const DndMetricSelect = (props: any) => {
accept={DND_ACCEPTED_TYPES}
ghostButtonText={ghostButtonText}
displayGhostButton={multi || value.length === 0}
- onClickGhostButton={
- isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
- ? handleClickGhostButton
- : undefined
- }
+ onClickGhostButton={handleClickGhostButton}
{...props}
/>
false,
valuesRenderer: () => ,
+ ghostButtonText: 'Drop columns here or click',
+ onClickGhostButton: jest.fn(),
};
-test('renders with default props', async () => {
+test('renders with default props', () => {
render(, { useDnd: true });
- expect(await screen.findByText('Drop columns here')).toBeInTheDocument();
+ expect(screen.getByText('Drop columns here or click')).toBeInTheDocument();
});
-test('renders ghost button when empty', async () => {
+test('renders ghost button when empty', () => {
const ghostButtonText = 'Ghost button text';
render(
,
{ useDnd: true },
);
- expect(await screen.findByText(ghostButtonText)).toBeInTheDocument();
+ expect(screen.getByText(ghostButtonText)).toBeInTheDocument();
});
-test('renders values', async () => {
+test('renders values', () => {
const values = 'Values';
const valuesRenderer = () => {values};
render(, {
useDnd: true,
});
- expect(await screen.findByText(values)).toBeInTheDocument();
+ expect(screen.getByText(values)).toBeInTheDocument();
+});
+
+test('Handles ghost button click', () => {
+ render(, { useDnd: true });
+ userEvent.click(screen.getByText('Drop columns here or click'));
+ expect(defaultProps.onClickGhostButton).toHaveBeenCalled();
});
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
index 467a440a4c..397d6f54e0 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndSelectLabel.tsx
@@ -35,14 +35,14 @@ import { DndItemType } from '../../DndItemType';
export type DndSelectLabelProps = {
name: string;
accept: DndItemType | DndItemType[];
- ghostButtonText?: string;
+ ghostButtonText: string;
onDrop: (item: DatasourcePanelDndItem) => void;
canDrop: (item: DatasourcePanelDndItem) => boolean;
canDropValue?: (value: DndItemValue) => boolean;
onDropValue?: (value: DndItemValue) => void;
valuesRenderer: () => ReactNode;
displayGhostButton?: boolean;
- onClickGhostButton?: () => void;
+ onClickGhostButton: () => void;
};
export default function DndSelectLabel({
@@ -80,7 +80,7 @@ export default function DndSelectLabel({
onClick={props.onClickGhostButton}
>
- {t(props.ghostButtonText || 'Drop columns here')}
+ {t(props.ghostButtonText)}
);
}
diff --git a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
index f1658b5ae3..9f445a607d 100644
--- a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
+++ b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/types.ts
@@ -47,7 +47,6 @@ export type DndControlProps =
multi?: boolean;
canDelete?: boolean;
ghostButtonText?: string;
- clickEnabledGhostButtonText?: string;
onChange: (value: ValueType | ValueType[] | null | undefined) => void;
};
diff --git a/superset/config.py b/superset/config.py
index 267ad64391..ea602338d3 100644
--- a/superset/config.py
+++ b/superset/config.py
@@ -458,9 +458,8 @@ DEFAULT_FEATURE_FLAGS: Dict[str, bool] = {
# Enables Alerts and reports new implementation
"ALERT_REPORTS": False,
"DASHBOARD_RBAC": False,
- "ENABLE_EXPLORE_DRAG_AND_DROP": True,
+ "ENABLE_EXPLORE_DRAG_AND_DROP": True, # deprecated
"ENABLE_ADVANCED_DATA_TYPES": False,
- "ENABLE_DND_WITH_CLICK_UX": True,
# 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