mirror of
https://github.com/apache/superset.git
synced 2026-04-20 00:24:38 +00:00
feat(explore): Drag and drop UX improvements (#13598)
* Create a metric immediately when saved metric is dropped * Display borders around control boxes when metric or column is dragged * Fix imports * Display ghost button * Rename placeholder to ghostButton
This commit is contained in:
committed by
GitHub
parent
6b30f55cfd
commit
ae66f5fa78
@@ -72,7 +72,6 @@ export const DndColumnSelect = (props: LabelProps) => {
|
||||
|
||||
return (
|
||||
<DndSelectLabel<string | string[], ColumnMeta[]>
|
||||
values={values}
|
||||
onDrop={onDrop}
|
||||
canDrop={canDrop}
|
||||
valuesRenderer={valuesRenderer}
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { logging, SupersetClient, t } from '@superset-ui/core';
|
||||
import { ColumnMeta, Metric } from '@superset-ui/chart-controls';
|
||||
import { logging, SupersetClient, t, Metric } from '@superset-ui/core';
|
||||
import { ColumnMeta } from '@superset-ui/chart-controls';
|
||||
import { Tooltip } from 'src/common/components/Tooltip';
|
||||
import { OPERATORS } from 'src/explore/constants';
|
||||
import { OptionSortType } from 'src/explore/types';
|
||||
@@ -300,7 +300,6 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => {
|
||||
return (
|
||||
<>
|
||||
<DndSelectLabel<OptionValueType, OptionValueType[]>
|
||||
values={values}
|
||||
onDrop={(item: DatasourcePanelDndItem) => {
|
||||
setDroppedItem(item.value);
|
||||
togglePopover(true);
|
||||
@@ -313,7 +312,7 @@ export const DndFilterSelect = (props: DndFilterSelectProps) => {
|
||||
DndItemType.MetricOption,
|
||||
DndItemType.AdhocMetricOption,
|
||||
]}
|
||||
placeholderText={t('Drop columns or metrics')}
|
||||
ghostButtonText={t('Drop columns or metrics')}
|
||||
{...props}
|
||||
/>
|
||||
<AdhocFilterPopoverTrigger
|
||||
|
||||
@@ -241,41 +241,35 @@ export const DndMetricSelect = (props: any) => {
|
||||
togglePopover(false);
|
||||
};
|
||||
|
||||
const { savedMetric, adhocMetric } = useMemo(() => {
|
||||
if (droppedItem?.type === 'column') {
|
||||
const handleDrop = (item: DatasourcePanelDndItem) => {
|
||||
if (item.type === DndItemType.Metric) {
|
||||
onNewMetric(item.value as Metric);
|
||||
}
|
||||
if (item.type === DndItemType.Column) {
|
||||
setDroppedItem(item);
|
||||
togglePopover(true);
|
||||
}
|
||||
};
|
||||
|
||||
const adhocMetric = useMemo(() => {
|
||||
if (droppedItem?.type === DndItemType.Column) {
|
||||
const itemValue = droppedItem?.value as ColumnMeta;
|
||||
return {
|
||||
savedMetric: {} as savedMetricType,
|
||||
adhocMetric: new AdhocMetric({
|
||||
column: { column_name: itemValue?.column_name },
|
||||
}),
|
||||
};
|
||||
return new AdhocMetric({
|
||||
column: { column_name: itemValue?.column_name },
|
||||
});
|
||||
}
|
||||
if (droppedItem?.type === 'metric') {
|
||||
const itemValue = droppedItem?.value as savedMetricType;
|
||||
return {
|
||||
savedMetric: itemValue,
|
||||
adhocMetric: new AdhocMetric({ isNew: true }),
|
||||
};
|
||||
}
|
||||
return {
|
||||
savedMetric: {} as savedMetricType,
|
||||
adhocMetric: new AdhocMetric({ isNew: true }),
|
||||
};
|
||||
return new AdhocMetric({ isNew: true });
|
||||
}, [droppedItem?.type, droppedItem?.value]);
|
||||
|
||||
return (
|
||||
<div className="metrics-select">
|
||||
<DndSelectLabel<OptionValueType, OptionValueType[]>
|
||||
values={value}
|
||||
onDrop={(item: DatasourcePanelDndItem) => {
|
||||
setDroppedItem(item);
|
||||
togglePopover(true);
|
||||
}}
|
||||
onDrop={handleDrop}
|
||||
canDrop={canDrop}
|
||||
valuesRenderer={valuesRenderer}
|
||||
accept={[DndItemType.Column, DndItemType.Metric]}
|
||||
placeholderText={t('Drop columns or metrics')}
|
||||
ghostButtonText={t('Drop columns or metrics')}
|
||||
displayGhostButton={multi || value.length === 0}
|
||||
{...props}
|
||||
/>
|
||||
<AdhocMetricPopoverTrigger
|
||||
@@ -286,7 +280,7 @@ export const DndMetricSelect = (props: any) => {
|
||||
props.savedMetrics,
|
||||
props.value,
|
||||
)}
|
||||
savedMetric={savedMetric}
|
||||
savedMetric={{} as savedMetricType}
|
||||
datasourceType={props.datasourceType}
|
||||
isControlledComponent
|
||||
visible={newMetricPopoverVisible}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import { useDrop } from 'react-dnd';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { t, useTheme } from '@superset-ui/core';
|
||||
import ControlHeader from 'src/explore/components/ControlHeader';
|
||||
import {
|
||||
@@ -30,9 +29,10 @@ import { DatasourcePanelDndItem } from 'src/explore/components/DatasourcePanel/t
|
||||
import Icon from 'src/components/Icon';
|
||||
import { DndColumnSelectProps } from './types';
|
||||
|
||||
export default function DndSelectLabel<T, O>(
|
||||
props: DndColumnSelectProps<T, O>,
|
||||
) {
|
||||
export default function DndSelectLabel<T, O>({
|
||||
displayGhostButton = true,
|
||||
...props
|
||||
}: DndColumnSelectProps<T, O>) {
|
||||
const theme = useTheme();
|
||||
|
||||
const [{ isOver, canDrop }, datasourcePanelDrop] = useDrop({
|
||||
@@ -51,11 +51,11 @@ export default function DndSelectLabel<T, O>(
|
||||
}),
|
||||
});
|
||||
|
||||
function renderPlaceHolder() {
|
||||
function renderGhostButton() {
|
||||
return (
|
||||
<AddControlLabel cancelHover>
|
||||
<Icon name="plus-small" color={theme.colors.grayscale.light1} />
|
||||
{t(props.placeholderText || 'Drop columns')}
|
||||
{t(props.ghostButtonText || 'Drop columns')}
|
||||
</AddControlLabel>
|
||||
);
|
||||
}
|
||||
@@ -66,7 +66,8 @@ export default function DndSelectLabel<T, O>(
|
||||
<ControlHeader {...props} />
|
||||
</HeaderContainer>
|
||||
<DndLabelsContainer canDrop={canDrop} isOver={isOver}>
|
||||
{isEmpty(props.values) ? renderPlaceHolder() : props.valuesRenderer()}
|
||||
{props.valuesRenderer()}
|
||||
{displayGhostButton && renderGhostButton()}
|
||||
</DndLabelsContainer>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
* under the License.
|
||||
*/
|
||||
import { ReactNode } from 'react';
|
||||
import { ColumnMeta, Metric } from '@superset-ui/chart-controls';
|
||||
import { Metric } from '@superset-ui/core';
|
||||
import { ColumnMeta } from '@superset-ui/chart-controls';
|
||||
import { DatasourcePanelDndItem } from '../../DatasourcePanel/types';
|
||||
import { DndItemType } from '../../DndItemType';
|
||||
|
||||
@@ -45,12 +46,12 @@ export interface DndColumnSelectProps<
|
||||
T = string[] | string,
|
||||
O = string[] | string
|
||||
> extends LabelProps<T> {
|
||||
values?: O;
|
||||
onDrop: (item: DatasourcePanelDndItem) => void;
|
||||
canDrop: (item: DatasourcePanelDndItem) => boolean;
|
||||
valuesRenderer: () => ReactNode;
|
||||
accept: DndItemType | DndItemType[];
|
||||
placeholderText?: string;
|
||||
ghostButtonText?: string;
|
||||
displayGhostButton?: boolean;
|
||||
}
|
||||
|
||||
export type OptionValueType = Record<string, any>;
|
||||
|
||||
Reference in New Issue
Block a user