mirror of
https://github.com/apache/superset.git
synced 2026-04-20 16:44:46 +00:00
fix(explore): Prevent shared controls from checking feature flags outside React render (#21315)
This commit is contained in:
@@ -24,7 +24,11 @@ import {
|
||||
tn,
|
||||
QueryFormColumn,
|
||||
} from '@superset-ui/core';
|
||||
import { ColumnMeta, isColumnMeta } from '@superset-ui/chart-controls';
|
||||
import {
|
||||
ColumnMeta,
|
||||
isColumnMeta,
|
||||
withDndFallback,
|
||||
} from '@superset-ui/chart-controls';
|
||||
import { isEmpty } from 'lodash';
|
||||
import DndSelectLabel from 'src/explore/components/controls/DndColumnSelectControl/DndSelectLabel';
|
||||
import OptionWrapper from 'src/explore/components/controls/DndColumnSelectControl/OptionWrapper';
|
||||
@@ -34,13 +38,14 @@ import { DndItemType } from 'src/explore/components/DndItemType';
|
||||
import { useComponentDidUpdate } from 'src/hooks/useComponentDidUpdate';
|
||||
import ColumnSelectPopoverTrigger from './ColumnSelectPopoverTrigger';
|
||||
import { DndControlProps } from './types';
|
||||
import SelectControl from '../SelectControl';
|
||||
|
||||
export type DndColumnSelectProps = DndControlProps<QueryFormColumn> & {
|
||||
options: Record<string, ColumnMeta>;
|
||||
options: ColumnMeta[];
|
||||
isTemporal?: boolean;
|
||||
};
|
||||
|
||||
export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
const {
|
||||
value,
|
||||
options,
|
||||
@@ -48,16 +53,20 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
onChange,
|
||||
canDelete = true,
|
||||
ghostButtonText,
|
||||
clickEnabledGhostButtonText,
|
||||
name,
|
||||
label,
|
||||
isTemporal,
|
||||
} = props;
|
||||
const [newColumnPopoverVisible, setNewColumnPopoverVisible] = useState(false);
|
||||
|
||||
const optionSelector = useMemo(
|
||||
() => new OptionSelector(options, multi, value),
|
||||
[multi, options, value],
|
||||
);
|
||||
const optionSelector = useMemo(() => {
|
||||
const optionsMap = Object.fromEntries(
|
||||
options.map(option => [option.column_name, option]),
|
||||
);
|
||||
|
||||
return new OptionSelector(optionsMap, multi, value);
|
||||
}, [multi, options, value]);
|
||||
|
||||
// synchronize values in case of dataset changes
|
||||
const handleOptionsChange = useCallback(() => {
|
||||
@@ -126,15 +135,18 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
[onChange, optionSelector],
|
||||
);
|
||||
|
||||
const popoverOptions = useMemo(() => Object.values(options), [options]);
|
||||
const clickEnabled = useMemo(
|
||||
() => isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX),
|
||||
[],
|
||||
);
|
||||
|
||||
const valuesRenderer = useCallback(
|
||||
() =>
|
||||
optionSelector.values.map((column, idx) =>
|
||||
isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX) ? (
|
||||
clickEnabled ? (
|
||||
<ColumnSelectPopoverTrigger
|
||||
key={idx}
|
||||
columns={popoverOptions}
|
||||
columns={options}
|
||||
onColumnEdit={newColumn => {
|
||||
if (isColumnMeta(newColumn)) {
|
||||
optionSelector.replace(idx, newColumn.column_name);
|
||||
@@ -171,13 +183,15 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
),
|
||||
[
|
||||
canDelete,
|
||||
clickEnabled,
|
||||
isTemporal,
|
||||
label,
|
||||
name,
|
||||
onChange,
|
||||
onClickClose,
|
||||
onShiftOptions,
|
||||
optionSelector,
|
||||
popoverOptions,
|
||||
options,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -205,15 +219,24 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
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);
|
||||
const labelGhostButtonText = useMemo(() => {
|
||||
if (clickEnabled) {
|
||||
return (
|
||||
clickEnabledGhostButtonText ??
|
||||
ghostButtonText ??
|
||||
tn(
|
||||
'Drop a column here or click',
|
||||
'Drop columns here or click',
|
||||
multi ? 2 : 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
ghostButtonText ??
|
||||
tn('Drop column here', 'Drop columns here', multi ? 2 : 1)
|
||||
);
|
||||
}, [clickEnabled, clickEnabledGhostButtonText, ghostButtonText, multi]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -223,16 +246,12 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
valuesRenderer={valuesRenderer}
|
||||
accept={DndItemType.Column}
|
||||
displayGhostButton={multi || optionSelector.values.length === 0}
|
||||
ghostButtonText={ghostButtonText || defaultGhostButtonText}
|
||||
onClickGhostButton={
|
||||
isFeatureEnabled(FeatureFlag.ENABLE_DND_WITH_CLICK_UX)
|
||||
? openPopover
|
||||
: undefined
|
||||
}
|
||||
ghostButtonText={labelGhostButtonText}
|
||||
onClickGhostButton={clickEnabled ? openPopover : undefined}
|
||||
{...props}
|
||||
/>
|
||||
<ColumnSelectPopoverTrigger
|
||||
columns={popoverOptions}
|
||||
columns={options}
|
||||
onColumnEdit={addNewColumnWithPopover}
|
||||
isControlledComponent
|
||||
togglePopover={togglePopover}
|
||||
@@ -245,3 +264,10 @@ export function DndColumnSelect(props: DndColumnSelectProps) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const DndColumnSelectWithFallback = withDndFallback(
|
||||
DndColumnSelect,
|
||||
SelectControl,
|
||||
);
|
||||
|
||||
export { DndColumnSelectWithFallback as DndColumnSelect };
|
||||
|
||||
Reference in New Issue
Block a user