feat: Implement drag and drop columns for filters (#13340)

* Implement DnD feature for filters

* minor refactor

* Fix types

* Fix undefined error

* Refactor

* Fix ts errors

* Fix conflicting dnd types

* Bump superset-ui packages

* Change DndItemType case to PascalCase

* Remove redundant null check

* Fix

* Fix csrf mock api call
This commit is contained in:
Kamil Gabryjelski
2021-03-07 10:54:08 +01:00
committed by GitHub
parent 3970d7316b
commit 7b370e6f17
23 changed files with 1069 additions and 540 deletions

View File

@@ -0,0 +1,83 @@
/**
* 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, { useState } from 'react';
import { ColumnMeta, ColumnOption } from '@superset-ui/chart-controls';
import { isEmpty } from 'lodash';
import { LabelProps } from './types';
import DndSelectLabel from './DndSelectLabel';
import OptionWrapper from './components/OptionWrapper';
import { OptionSelector } from './utils';
import { DatasourcePanelDndItem } from '../../DatasourcePanel/types';
import { DndItemType } from '../../DndItemType';
export const DndColumnSelect = (props: LabelProps) => {
const { value, options } = props;
const optionSelector = new OptionSelector(options, value);
const [values, setValues] = useState<ColumnMeta[]>(optionSelector.values);
const onDrop = (item: DatasourcePanelDndItem) => {
const column = item.value as ColumnMeta;
if (!optionSelector.isArray && !isEmpty(optionSelector.values)) {
optionSelector.replace(0, column.column_name);
} else {
optionSelector.add(column.column_name);
}
setValues(optionSelector.values);
props.onChange(optionSelector.getValues());
};
const canDrop = (item: DatasourcePanelDndItem) =>
!optionSelector.has((item.value as ColumnMeta).column_name);
const onClickClose = (index: number) => {
optionSelector.del(index);
setValues(optionSelector.values);
props.onChange(optionSelector.getValues());
};
const onShiftOptions = (dragIndex: number, hoverIndex: number) => {
optionSelector.swap(dragIndex, hoverIndex);
setValues(optionSelector.values);
props.onChange(optionSelector.getValues());
};
const valuesRenderer = () =>
values.map((column, idx) => (
<OptionWrapper
key={idx}
index={idx}
clickClose={onClickClose}
onShiftOptions={onShiftOptions}
type={DndItemType.ColumnOption}
>
<ColumnOption column={column} showType />
</OptionWrapper>
));
return (
<DndSelectLabel<string | string[], ColumnMeta[]>
values={values}
onDrop={onDrop}
canDrop={canDrop}
valuesRenderer={valuesRenderer}
accept={DndItemType.Column}
{...props}
/>
);
};