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
This commit is contained in:
Kamil Gabryjelski
2021-08-17 14:56:39 +02:00
committed by GitHub
parent 5e75baf0cc
commit 203c311ca3
8 changed files with 475 additions and 34 deletions

View File

@@ -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>
);
};