From 442d1b233439835500d2520b59e015293e08b465 Mon Sep 17 00:00:00 2001 From: jagerts <94642410+jagerts@users.noreply.github.com> Date: Mon, 23 May 2022 23:42:44 +0300 Subject: [PATCH] [Chore]: Technical: add types for filters (#1809) * add types for filters Signed-off-by: e.zhgulev * add changes due to code review Signed-off-by: Evgeny Zhgulev * fix typescript exception Signed-off-by: Evgeny Zhgulev * add factory return type Signed-off-by: Evgeny Zhgulev * fix linting failure Signed-off-by: Evgeny Zhgulev * add changes due to code review Signed-off-by: Evgeny Zhgulev * add changes due to code review Signed-off-by: Evgeny Zhgulev Co-authored-by: e.zhgulev --- src/actions/actions.ts | 2 + src/actions/vis-state-actions.ts | 6 +- src/components/bottom-widget.tsx | 2 +- .../floating-time-display.tsx | 6 +- .../animation-control/playback-controls.tsx | 4 +- src/components/common/field-selector.tsx | 4 +- src/components/common/range-slider.tsx | 2 +- .../common/time-range-slider-time-title.tsx | 2 +- src/components/common/time-range-slider.tsx | 44 ++++++----- .../filters/{components.js => components.ts} | 0 .../filter-panels/filter-panel-types.d.ts | 28 ------- ....js => filter-panel-with-field-select.tsx} | 48 +++++------- ...panel.js => multi-select-filter-panel.tsx} | 30 +++----- ...w-filter-panel.js => new-filter-panel.tsx} | 31 ++++---- ...lter-panel.js => polygon-filter-panel.tsx} | 42 ++++------ ...filter-panel.js => range-filter-panel.tsx} | 30 +++----- ...anel.js => single-select-filter-panel.tsx} | 30 +++----- ...r-panel.js => time-range-filter-panel.tsx} | 21 +++-- src/components/filters/filter-panels/types.ts | 39 ++++++++++ src/components/filters/{index.js => index.ts} | 0 ...lect-filter.js => multi-select-filter.tsx} | 3 +- src/components/filters/polygon-filter.d.ts | 13 ---- .../{polygon-filter.js => polygon-filter.tsx} | 75 +++++++++--------- .../{range-filter.js => range-filter.tsx} | 7 +- ...ect-filter.js => single-select-filter.tsx} | 3 +- ...-range-filter.js => time-range-filter.tsx} | 14 +++- .../{time-widget.js => time-widget.tsx} | 28 +++++-- src/components/filters/types.ts | 76 +++++++++++++++++++ .../side-panel/common/dataset-tag.tsx | 18 ++--- .../side-panel/common/dataset-title.tsx | 14 ++-- .../common/source-data-selector.tsx | 14 +++- src/components/side-panel/common/types.ts | 34 ++++----- .../filter-panel/filter-panel-header.tsx | 18 +++-- .../side-panel/filter-panel/filter-panel.tsx | 5 +- src/reducers/vis-state-updaters.ts | 1 + 35 files changed, 375 insertions(+), 319 deletions(-) rename src/components/filters/{components.js => components.ts} (100%) delete mode 100644 src/components/filters/filter-panels/filter-panel-types.d.ts rename src/components/filters/filter-panels/{filter-panel-with-field-select.js => filter-panel-with-field-select.tsx} (76%) rename src/components/filters/filter-panels/{multi-select-filter-panel.js => multi-select-filter-panel.tsx} (77%) rename src/components/filters/filter-panels/{new-filter-panel.js => new-filter-panel.tsx} (80%) rename src/components/filters/filter-panels/{polygon-filter-panel.js => polygon-filter-panel.tsx} (75%) rename src/components/filters/filter-panels/{range-filter-panel.js => range-filter-panel.tsx} (77%) rename src/components/filters/filter-panels/{single-select-filter-panel.js => single-select-filter-panel.tsx} (77%) rename src/components/filters/filter-panels/{time-range-filter-panel.js => time-range-filter-panel.tsx} (84%) create mode 100644 src/components/filters/filter-panels/types.ts rename src/components/filters/{index.js => index.ts} (100%) rename src/components/filters/{multi-select-filter.js => multi-select-filter.tsx} (92%) delete mode 100644 src/components/filters/polygon-filter.d.ts rename src/components/filters/{polygon-filter.js => polygon-filter.tsx} (53%) rename src/components/filters/{range-filter.js => range-filter.tsx} (89%) rename src/components/filters/{single-select-filter.js => single-select-filter.tsx} (93%) rename src/components/filters/{time-range-filter.js => time-range-filter.tsx} (85%) rename src/components/filters/{time-widget.js => time-widget.tsx} (89%) create mode 100644 src/components/filters/types.ts diff --git a/src/actions/actions.ts b/src/actions/actions.ts index fa326bc9cc..ab60817288 100644 --- a/src/actions/actions.ts +++ b/src/actions/actions.ts @@ -71,6 +71,8 @@ export type AddDataToMapPayload = { info?: Partial; }; +export type ActionHandler any> = (...args: Parameters) => void; + /** * Add data to kepler.gl reducer, prepare map with preset configuration if config is passed. * Kepler.gl provides a handy set of utils to parse data from different formats to the `data` object required in dataset. You rarely need to manually format the data obejct. diff --git a/src/actions/vis-state-actions.ts b/src/actions/vis-state-actions.ts index aad1904d18..398693db70 100644 --- a/src/actions/vis-state-actions.ts +++ b/src/actions/vis-state-actions.ts @@ -240,7 +240,7 @@ export function setFilter( idx: number, prop: string, value: any, - valueIndex: number + valueIndex?: number ): Merge { return { type: ActionTypes.SET_FILTER, @@ -309,7 +309,7 @@ export function setFilterAnimationWindow({ } export type AddFilterUpdaterAction = { - dataId: string; + dataId?: string | null; }; /** * Add a new filter @@ -319,7 +319,7 @@ export type AddFilterUpdaterAction = { * @public */ export function addFilter( - dataId: string + dataId: string | null ): Merge { return { type: ActionTypes.ADD_FILTER, diff --git a/src/components/bottom-widget.tsx b/src/components/bottom-widget.tsx index fc1531b8f8..ead329ca9a 100644 --- a/src/components/bottom-widget.tsx +++ b/src/components/bottom-widget.tsx @@ -245,7 +245,7 @@ export default function BottomWidgetFactory( ( interface FloatingTimeDisplayProps { currentTime: number | number[]; - defaultTimeFormat?: string; - timeFormat?: string; - timezone?: string; + defaultTimeFormat?: string | null; + timeFormat?: string | null; + timezone?: string | null; } export default function FloatingTimeDisplayFactory() { diff --git a/src/components/common/animation-control/playback-controls.tsx b/src/components/common/animation-control/playback-controls.tsx index b6342559c7..3cf7ae2384 100644 --- a/src/components/common/animation-control/playback-controls.tsx +++ b/src/components/common/animation-control/playback-controls.tsx @@ -157,9 +157,9 @@ interface PlaybackControls { speed: number; animationWindow?: string; setFilterAnimationWindow?: (id: string) => void; - updateAnimationSpeed; + updateAnimationSpeed?: (val: number) => void; pauseAnimation?: () => void; - resetAnimation: () => void; + resetAnimation?: () => void; startAnimation: () => void; playbackIcons?: typeof DEFAULT_ICONS; animationItems?: {[key: string]: AnimationItem}; diff --git a/src/components/common/field-selector.tsx b/src/components/common/field-selector.tsx index c5459abf83..a43874433a 100644 --- a/src/components/common/field-selector.tsx +++ b/src/components/common/field-selector.tsx @@ -27,6 +27,7 @@ import {classList} from './item-selector/dropdown-list'; import {toArray} from 'utils/utils'; import {notNullorUndefined} from 'utils/data-utils'; import FieldTokenFactory from '../common/field-token'; +import {Field} from 'utils/table-utils/kepler-table'; const defaultDisplayOption = d => d.displayName || d.name; const defaultValueOption = d => d.name; @@ -73,7 +74,8 @@ type FieldType = name?: string; fieldIdx?: number; type?: number; - }; + } + | Field; interface FieldSelectorFactoryProps { fields?: FieldType[]; diff --git a/src/components/common/range-slider.tsx b/src/components/common/range-slider.tsx index 286b2bcd33..8ecc0c2ebd 100644 --- a/src/components/common/range-slider.tsx +++ b/src/components/common/range-slider.tsx @@ -73,7 +73,7 @@ interface RangeSliderProps { step?: number; sliderHandleWidth?: number; xAxis?: ElementType; - timezone?: string; + timezone?: string | null; timeFormat?: string; playbackControlWidth?: number; lineChart?: LineChart; diff --git a/src/components/common/time-range-slider-time-title.tsx b/src/components/common/time-range-slider-time-title.tsx index 6c407c6034..097dcebb31 100644 --- a/src/components/common/time-range-slider-time-title.tsx +++ b/src/components/common/time-range-slider-time-title.tsx @@ -64,7 +64,7 @@ const TimeValue = ({value}) => ( interface TimeTitleProps { value: number[]; isEnlarged?: boolean; - timezone?: string; + timezone?: string | null; timeFormat: string; } diff --git a/src/components/common/time-range-slider.tsx b/src/components/common/time-range-slider.tsx index fa439897cf..c283372e9d 100644 --- a/src/components/common/time-range-slider.tsx +++ b/src/components/common/time-range-slider.tsx @@ -19,7 +19,6 @@ // THE SOFTWARE. import React, {useMemo} from 'react'; -import PropTypes from 'prop-types'; import throttle from 'lodash.throttle'; import styled from 'styled-components'; @@ -27,6 +26,7 @@ import RangeSliderFactory from 'components/common/range-slider'; import TimeSliderMarkerFactory from 'components/common/time-slider-marker'; import PlaybackControlsFactory from 'components/common/animation-control/playback-controls'; import TimeRangeSliderTimeTitleFactory from 'components/common/time-range-slider-time-title'; +import {HistogramBin, LineChart} from 'reducers'; const animationControlWidth = 176; @@ -34,6 +34,28 @@ interface StyledSliderContainerProps { isEnlarged?: boolean; } +type TimeRangeSliderProps = { + domain?: [number, number]; + value: [number, number]; + isEnlarged?: boolean; + hideTimeTitle?: boolean; + isAnimating: boolean; + timeFormat: string; + timezone?: string | null; + histogram?: HistogramBin[]; + plotType?: string; + lineChart?: LineChart; + step: number; + isAnimatable?: boolean; + speed: number; + animationWindow: string; + resetAnimation?: () => void; + toggleAnimation: () => void; + updateAnimationSpeed?: (val: number) => void; + setFilterAnimationWindow?: (id: string) => void; + onChange: (v: number[]) => void; +}; + const StyledSliderContainer = styled.div` align-items: flex-end; display: flex; @@ -63,7 +85,7 @@ export default function TimeRangeSliderFactory( TimeSliderMarker: ReturnType, TimeRangeSliderTimeTitle: ReturnType ) { - const TimeRangeSlider = props => { + const TimeRangeSlider: React.FC = props => { const { domain, value, @@ -145,23 +167,5 @@ export default function TimeRangeSliderFactory( ); }; - TimeRangeSlider.propTypes = { - onChange: PropTypes.func.isRequired, - domain: PropTypes.arrayOf(PropTypes.number), - value: PropTypes.arrayOf(PropTypes.number).isRequired, - step: PropTypes.number.isRequired, - plotType: PropTypes.string, - histogram: PropTypes.arrayOf(PropTypes.any), - lineChart: PropTypes.object, - toggleAnimation: PropTypes.func.isRequired, - exportAnimation: PropTypes.func, - isAnimatable: PropTypes.bool, - isEnlarged: PropTypes.bool, - speed: PropTypes.number, - timeFormat: PropTypes.string, - timezone: PropTypes.string, - hideTimeTitle: PropTypes.bool - }; - return React.memo(TimeRangeSlider); } diff --git a/src/components/filters/components.js b/src/components/filters/components.ts similarity index 100% rename from src/components/filters/components.js rename to src/components/filters/components.ts diff --git a/src/components/filters/filter-panels/filter-panel-types.d.ts b/src/components/filters/filter-panels/filter-panel-types.d.ts deleted file mode 100644 index af2e48ae65..0000000000 --- a/src/components/filters/filter-panels/filter-panel-types.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {FunctionComponent, ComponentType} from 'react'; -import {Filter, Dataset, Field} from 'reducers'; -import {Layer} from 'layers'; - -interface PanelAction { - id: string, - tooltip: string, - onClick: () => void, - iconComponent: ComponentType, - active: boolean -} - -export type FilterPanelProps = { - idx: number, - layers: ReadonlyArray, - datasets: ReadonlyArray, - allAvailableFields: ReadonlyArray, - filter: Filter, - panelActions: ReadonlyArray, - isAnyFilterAnimating: boolean, - enlargeFilter: () => void, - setFilter: (idx: number, field: string, value: any) => void, - removeFilter: () => void, - toggleAnimation: () => void, - toggleFilterFeature: () => void -}; - -export type FilterPanelComponent = FunctionComponent; diff --git a/src/components/filters/filter-panels/filter-panel-with-field-select.js b/src/components/filters/filter-panels/filter-panel-with-field-select.tsx similarity index 76% rename from src/components/filters/filter-panels/filter-panel-with-field-select.js rename to src/components/filters/filter-panels/filter-panel-with-field-select.tsx index b40de8a37a..513998d267 100644 --- a/src/components/filters/filter-panels/filter-panel-with-field-select.js +++ b/src/components/filters/filter-panels/filter-panel-with-field-select.tsx @@ -25,6 +25,8 @@ import PanelHeaderActionFactory from 'components/side-panel/panel-header-action' import SourceDataSelectorFactory from 'components/side-panel/common/source-data-selector'; import FieldSelectorFactory from '../../common/field-selector'; import {getSupportedFilterFields} from './new-filter-panel'; +import {FilterPanelWithFieldSelectComponent} from './types'; +import KeplerTable from 'utils/table-utils/kepler-table'; FieldPanelWithFieldSelectFactory.deps = [ FilterPanelHeaderFactory, @@ -34,16 +36,15 @@ FieldPanelWithFieldSelectFactory.deps = [ ]; function FieldPanelWithFieldSelectFactory( - FilterPanelHeader, - SourceDataSelector, - FieldSelector, - PanelHeaderAction + FilterPanelHeader: ReturnType, + SourceDataSelector: ReturnType, + FieldSelector: ReturnType, + PanelHeaderAction: ReturnType ) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const FilterPanelWithFieldSelect = React.memo( + const FilterPanelWithFieldSelect: FilterPanelWithFieldSelectComponent = React.memo( ({ - allAvailableFields, children, + allAvailableFields, datasets, filter, idx, @@ -62,24 +63,18 @@ function FieldPanelWithFieldSelectFactory( ]); const fieldValue = useMemo( - () => ((Array.isArray(filter.name) ? filter.name[0] : filter.name)), + () => (Array.isArray(filter.name) ? filter.name[0] : filter.name), [filter.name] ); - const dataset = datasets[filter.dataId[0]]; + const dataset: KeplerTable = datasets[filter.dataId[0]]; const supportedFields = useMemo( () => getSupportedFilterFields(dataset.supportedFilterTypes, allAvailableFields), [dataset.supportedFilterTypes, allAvailableFields] ); return ( <> - + - {panelActions && - panelActions.map(panelAction => ( - - ))} + {panelActions?.map(panelAction => ( + + ))} {Object.keys(datasets).length > 1 && ( diff --git a/src/components/filters/filter-panels/multi-select-filter-panel.js b/src/components/filters/filter-panels/multi-select-filter-panel.tsx similarity index 77% rename from src/components/filters/filter-panels/multi-select-filter-panel.js rename to src/components/filters/filter-panels/multi-select-filter-panel.tsx index 2849fcf3e3..be443938c6 100644 --- a/src/components/filters/filter-panels/multi-select-filter-panel.js +++ b/src/components/filters/filter-panels/multi-select-filter-panel.tsx @@ -20,24 +20,18 @@ import React, {useCallback} from 'react'; import MultiSelectFilterFactory from 'components/filters/multi-select-filter'; +import {MultiSelectFilter} from 'reducers'; import FieldPanelWithFieldSelectFactory from 'components/filters/filter-panels/filter-panel-with-field-select'; +import {FilterPanelComponent} from './types'; MultiSelectFilterPanelFactory.deps = [FieldPanelWithFieldSelectFactory, MultiSelectFilterFactory]; -function MultiSelectFilterPanelFactory(FieldPanelWithFieldSelect, MultiSelectFilter) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const MultiSelectFilterPanel = React.memo( - ({ - idx, - datasets, - allAvailableFields, - filter, - isAnyFilterAnimating, - enlargeFilter, - setFilter, - removeFilter, - toggleAnimation - }) => { +function MultiSelectFilterPanelFactory( + FieldPanelWithFieldSelect: ReturnType, + MultiSelectFilter: ReturnType +) { + const MultiSelectFilterPanel: FilterPanelComponent = React.memo( + ({idx, datasets, allAvailableFields, filter, setFilter, removeFilter}) => { const onSetFilter = useCallback(value => setFilter(idx, 'value', value), [idx, setFilter]); return ( @@ -52,13 +46,7 @@ function MultiSelectFilterPanelFactory(FieldPanelWithFieldSelect, MultiSelectFil > {filter.type && !filter.enlarged && (
- +
)} diff --git a/src/components/filters/filter-panels/new-filter-panel.js b/src/components/filters/filter-panels/new-filter-panel.tsx similarity index 80% rename from src/components/filters/filter-panels/new-filter-panel.js rename to src/components/filters/filter-panels/new-filter-panel.tsx index 61bca8ca0a..7f44a0c9c2 100644 --- a/src/components/filters/filter-panels/new-filter-panel.js +++ b/src/components/filters/filter-panels/new-filter-panel.tsx @@ -23,6 +23,9 @@ import {StyledFilterContent} from 'components/common/styled-components'; import FilterPanelHeaderFactory from 'components/side-panel/filter-panel/filter-panel-header'; import SourceDataSelectorFactory from 'components/side-panel/common/source-data-selector'; import FieldSelectorFactory from '../../common/field-selector'; +import {FilterBase} from 'reducers'; +import {FilterPanelComponent} from './types'; +import KeplerTable, {Field} from 'utils/table-utils/kepler-table'; NewFilterPanelFactory.deps = [ FilterPanelHeaderFactory, @@ -30,16 +33,22 @@ NewFilterPanelFactory.deps = [ FieldSelectorFactory ]; -export function getSupportedFilterFields(supportedFilterTypes, fields) { +export function getSupportedFilterFields( + supportedFilterTypes: KeplerTable['supportedFilterTypes'], + fields: Field[] +) { return supportedFilterTypes ? fields.filter(field => supportedFilterTypes.includes(field.type)) : fields; } -function NewFilterPanelFactory(FilterPanelHeader, SourceDataSelector, FieldSelector) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const NewFilterPanel = React.memo( - ({idx, filter, datasets, allAvailableFields, setFilter, removeFilter, enlargeFilter}) => { +function NewFilterPanelFactory( + FilterPanelHeader: ReturnType, + SourceDataSelector: ReturnType, + FieldSelector: ReturnType +) { + const NewFilterPanel: FilterPanelComponent = React.memo( + ({idx, filter, datasets, allAvailableFields, setFilter, removeFilter}) => { const onFieldSelector = useCallback(field => setFilter(idx, 'name', field.name), [ idx, setFilter @@ -50,7 +59,7 @@ function NewFilterPanelFactory(FilterPanelHeader, SourceDataSelector, FieldSelec setFilter ]); - const dataset = datasets[filter.dataId[0]]; + const dataset: KeplerTable = datasets[filter.dataId[0]]; const supportedFields = useMemo( () => getSupportedFilterFields(dataset.supportedFilterTypes, allAvailableFields), [dataset.supportedFilterTypes, allAvailableFields] @@ -58,15 +67,7 @@ function NewFilterPanelFactory(FilterPanelHeader, SourceDataSelector, FieldSelec return ( <> - + { - const filterDatasets = useMemo(() => filter.dataId.map(d => datasets[d]), [filter, datasets]); +function PolygonFilterPanelFactory( + FilterPanelHeader: ReturnType, + PolygonFilter: ReturnType, + PanelHeaderAction: ReturnType +) { + const PolygonFilterPanel: PolygonFilterPanelComponent = React.memo( + ({idx, datasets, layers, filter, removeFilter, setFilter, toggleFilterFeature}) => { + const filterDatasets: KeplerTable[] = useMemo(() => filter.dataId.map(d => datasets[d]), [ + filter, + datasets + ]); const onSetLayers = useCallback(value => setFilter(idx, 'layerId', value), [setFilter, idx]); @@ -57,13 +56,7 @@ function PolygonFilterPanelFactory(FilterPanelHeader, PolygonFilter, PanelHeader return (
- + Geo - {featureType}
- +
diff --git a/src/components/filters/filter-panels/range-filter-panel.js b/src/components/filters/filter-panels/range-filter-panel.tsx similarity index 77% rename from src/components/filters/filter-panels/range-filter-panel.js rename to src/components/filters/filter-panels/range-filter-panel.tsx index 845e3d8603..efc981eadd 100644 --- a/src/components/filters/filter-panels/range-filter-panel.js +++ b/src/components/filters/filter-panels/range-filter-panel.tsx @@ -20,24 +20,18 @@ import React, {useCallback} from 'react'; import RangeFilterFactory from 'components/filters/range-filter'; +import {RangeFilter} from 'reducers'; import FieldPanelWithFieldSelectFactory from 'components/filters/filter-panels/filter-panel-with-field-select'; +import {FilterPanelComponent} from './types'; RangeFilterPanelFactory.deps = [FieldPanelWithFieldSelectFactory, RangeFilterFactory]; -function RangeFilterPanelFactory(FieldPanelWithFieldSelect, RangeFilter) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const RangeFilterPanel = React.memo( - ({ - idx, - datasets, - allAvailableFields, - filter, - isAnyFilterAnimating, - enlargeFilter, - removeFilter, - setFilter, - toggleAnimation - }) => { +function RangeFilterPanelFactory( + FieldPanelWithFieldSelect: ReturnType, + RangeFilter: ReturnType +) { + const RangeFilterPanel: FilterPanelComponent = React.memo( + ({idx, datasets, allAvailableFields, filter, removeFilter, setFilter}) => { const onSetFilter = useCallback(value => setFilter(idx, 'value', value), [idx, setFilter]); return ( @@ -52,13 +46,7 @@ function RangeFilterPanelFactory(FieldPanelWithFieldSelect, RangeFilter) { > {filter.type && !filter.enlarged && (
- +
)} diff --git a/src/components/filters/filter-panels/single-select-filter-panel.js b/src/components/filters/filter-panels/single-select-filter-panel.tsx similarity index 77% rename from src/components/filters/filter-panels/single-select-filter-panel.js rename to src/components/filters/filter-panels/single-select-filter-panel.tsx index b364dc2cf4..3e3d4c9446 100644 --- a/src/components/filters/filter-panels/single-select-filter-panel.js +++ b/src/components/filters/filter-panels/single-select-filter-panel.tsx @@ -20,24 +20,18 @@ import React, {useCallback} from 'react'; import SingleSelectFilterFactory from 'components/filters/single-select-filter'; +import {SelectFilter} from 'reducers'; import FieldPanelWithFieldSelectFactory from 'components/filters/filter-panels/filter-panel-with-field-select'; +import {FilterPanelComponent} from './types'; SingleSelectFilterPanelFactory.deps = [FieldPanelWithFieldSelectFactory, SingleSelectFilterFactory]; -function SingleSelectFilterPanelFactory(FieldPanelWithFieldSelect, SingleSelectFilter) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const SingleSelectFilterPanel = React.memo( - ({ - idx, - datasets, - allAvailableFields, - filter, - isAnyFilterAnimating, - enlargeFilter, - setFilter, - removeFilter, - toggleAnimation - }) => { +function SingleSelectFilterPanelFactory( + FieldPanelWithFieldSelect: ReturnType, + SingleSelectFilter: ReturnType +) { + const SingleSelectFilterPanel: FilterPanelComponent = React.memo( + ({idx, datasets, allAvailableFields, filter, setFilter, removeFilter}) => { const onSetFilter = useCallback(value => setFilter(idx, 'value', value), [idx, setFilter]); return ( @@ -52,13 +46,7 @@ function SingleSelectFilterPanelFactory(FieldPanelWithFieldSelect, SingleSelectF > {filter.type && !filter.enlarged && (
- +
)} diff --git a/src/components/filters/filter-panels/time-range-filter-panel.js b/src/components/filters/filter-panels/time-range-filter-panel.tsx similarity index 84% rename from src/components/filters/filter-panels/time-range-filter-panel.js rename to src/components/filters/filter-panels/time-range-filter-panel.tsx index a4e53739e1..245454a451 100644 --- a/src/components/filters/filter-panels/time-range-filter-panel.js +++ b/src/components/filters/filter-panels/time-range-filter-panel.tsx @@ -21,24 +21,21 @@ import React, {useCallback, useMemo} from 'react'; import TimeRangeFilterFactory from 'components/filters/time-range-filter'; import {Clock} from 'components/common/icons'; -import SourceDataSelectorFactory from 'components/side-panel/common/source-data-selector'; import FieldPanelWithFieldSelectFactory from 'components/filters/filter-panels/filter-panel-with-field-select'; +import {TimeRangeFilterPanelComponent} from './types'; -TimeRangeFilterPanelFactory.deps = [ - FieldPanelWithFieldSelectFactory, - TimeRangeFilterFactory, - SourceDataSelectorFactory -]; +TimeRangeFilterPanelFactory.deps = [FieldPanelWithFieldSelectFactory, TimeRangeFilterFactory]; -function TimeRangeFilterPanelFactory(FieldPanelWithFieldSelect, TimeRangeFilter) { - /** @type {import('./filter-panel-types').FilterPanelComponent} */ - const TimeRangeFilterPanel = React.memo( +function TimeRangeFilterPanelFactory( + FieldPanelWithFieldSelect: ReturnType, + TimeRangeFilter: ReturnType +) { + const TimeRangeFilterPanel: TimeRangeFilterPanelComponent = React.memo( ({ idx, datasets, allAvailableFields, filter, - isAnyFilterAnimating, enlargeFilter, setFilter, removeFilter, @@ -74,10 +71,10 @@ function TimeRangeFilterPanelFactory(FieldPanelWithFieldSelect, TimeRangeFilter)
)} diff --git a/src/components/filters/filter-panels/types.ts b/src/components/filters/filter-panels/types.ts new file mode 100644 index 0000000000..d79377168c --- /dev/null +++ b/src/components/filters/filter-panels/types.ts @@ -0,0 +1,39 @@ +import {FunctionComponent, ComponentType} from 'react'; +import {Datasets, Filter, PolygonFilter, TimeRangeFilter} from 'reducers'; +import {Layer} from 'layers'; +import {Field} from 'utils/table-utils/kepler-table'; + +interface PanelAction { + id: string; + tooltip: string; + onClick: () => void; + iconComponent: ComponentType; + active: boolean; +} + +export interface FilterPanelProps { + idx: number; + datasets: Datasets; + allAvailableFields: Field[]; + filter: F; + removeFilter: () => void; + setFilter: (idx: number, field: string, value: any) => void; +} +export interface PolygonFilterPanelProps extends FilterPanelProps { + layers: ReadonlyArray; + toggleFilterFeature: () => void; +} +export interface TimeRangeFilterPanelProps extends FilterPanelProps { + enlargeFilter: () => void; + toggleAnimation: () => void; +} +export interface FilterPanelWithFieldSelectProps extends FilterPanelProps { + panelActions?: ReadonlyArray; +} + +export type FilterPanelComponent = FunctionComponent>; +export type PolygonFilterPanelComponent = FunctionComponent; +export type TimeRangeFilterPanelComponent = FunctionComponent; +export type FilterPanelWithFieldSelectComponent = FunctionComponent< + FilterPanelWithFieldSelectProps +>; diff --git a/src/components/filters/index.js b/src/components/filters/index.ts similarity index 100% rename from src/components/filters/index.js rename to src/components/filters/index.ts diff --git a/src/components/filters/multi-select-filter.js b/src/components/filters/multi-select-filter.tsx similarity index 92% rename from src/components/filters/multi-select-filter.js rename to src/components/filters/multi-select-filter.tsx index c8eb77f0ae..5186546113 100644 --- a/src/components/filters/multi-select-filter.js +++ b/src/components/filters/multi-select-filter.tsx @@ -22,9 +22,10 @@ import React from 'react'; import ItemSelector from '../common/item-selector/item-selector'; import {PanelLabel} from '../common/styled-components'; import {FormattedMessage} from 'localization'; +import {MultiSelectFilterProps} from './types'; export default function MultiSelectFilterFactory() { - const MultiSelectFilter = ({filter, setFilter}) => ( + const MultiSelectFilter: React.FC = ({filter, setFilter}) => (
diff --git a/src/components/filters/polygon-filter.d.ts b/src/components/filters/polygon-filter.d.ts deleted file mode 100644 index 11cc095e36..0000000000 --- a/src/components/filters/polygon-filter.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {FunctionComponent} from 'react'; -import {Filter} from 'reducers'; -import {Layer} from 'layers'; - -export type PolygonFilterProps = { - filter: Filter, - layers: ReadonlyArray, - setLayers: (ids: ReadonlyArray) => void -}; - -export const PolygonFilter: FunctionComponent; - -export default function PolygonFilterFactory(): PolygonFilter; diff --git a/src/components/filters/polygon-filter.js b/src/components/filters/polygon-filter.tsx similarity index 53% rename from src/components/filters/polygon-filter.js rename to src/components/filters/polygon-filter.tsx index cb8ab20da3..81296d67d7 100644 --- a/src/components/filters/polygon-filter.js +++ b/src/components/filters/polygon-filter.tsx @@ -20,50 +20,53 @@ import React, {useMemo, useCallback} from 'react'; import ItemSelector from 'components/common/item-selector/item-selector'; -import {StyledFilterPanel} from './components'; +import {Layer} from 'layers'; import {LAYER_TYPES} from 'layers/types'; +import {PolygonFilterProps} from './types'; +import {StyledFilterPanel} from './components'; -const layerFilter = layer => layer.type === LAYER_TYPES.point; -const isAlreadySelected = (selectedLayers, layerId) => +const layerFilter = (layer: Layer) => layer.type === LAYER_TYPES.point; +const isAlreadySelected = (selectedLayers: Layer[], layerId: string) => selectedLayers.findIndex(l => l.id === layerId) === -1; function PolygonFilterFactory() { - /** @type {typeof import('./polygon-filter').PolygonFilter} */ - const PolygonFilter = React.memo(({filter, layers, setLayers}) => { - const setNewLayers = useCallback( - newLayers => { - return setLayers(newLayers.map(l => l.id)); - }, - [setLayers] - ); + const PolygonFilter: React.FC = React.memo( + ({filter, layers, setLayers}) => { + const setNewLayers = useCallback( + newLayers => { + return setLayers(newLayers.map((l: Layer) => l.id)); + }, + [setLayers] + ); - const selectedLayers = useMemo(() => layers.filter(l => filter.layerId?.includes(l.id)), [ - filter, - layers - ]); + const selectedLayers = useMemo(() => layers.filter(l => filter.layerId?.includes(l.id)), [ + filter, + layers + ]); - const availableLayers = useMemo(() => { - // remove already added layers and filter out non point layers - return layers.filter( - layer => layerFilter(layer) && isAlreadySelected(selectedLayers, layer.id) - ); - }, [layers, selectedLayers]); + const availableLayers = useMemo(() => { + // remove already added layers and filter out non point layers + return layers.filter( + layer => layerFilter(layer) && isAlreadySelected(selectedLayers, layer.id) + ); + }, [layers, selectedLayers]); - return ( -
- Layers: - l.id} - displayOption={l => l.config.label} - /> -
- ); - }); + return ( +
+ Layers: + l.id} + displayOption={(l: Layer) => l.config.label} + /> +
+ ); + } + ); PolygonFilter.displayName = 'PolygonFilter'; diff --git a/src/components/filters/range-filter.js b/src/components/filters/range-filter.tsx similarity index 89% rename from src/components/filters/range-filter.js rename to src/components/filters/range-filter.tsx index 03eeac2fb8..69d6a96269 100644 --- a/src/components/filters/range-filter.js +++ b/src/components/filters/range-filter.tsx @@ -20,11 +20,12 @@ import React from 'react'; import RangeSliderFactory from 'components/common/range-slider'; +import {RangeFilterProps} from './types'; RangeFilterFactory.deps = [RangeSliderFactory]; -export default function RangeFilterFactory(RangeSlider) { - const RangeFilter = ({filter, setFilter}) => ( +export default function RangeFilterFactory(RangeSlider: ReturnType) { + const RangeFilter: React.FC = ({filter, setFilter}) => (
diff --git a/src/components/filters/single-select-filter.js b/src/components/filters/single-select-filter.tsx similarity index 93% rename from src/components/filters/single-select-filter.js rename to src/components/filters/single-select-filter.tsx index a6edd4478f..966227ab7d 100644 --- a/src/components/filters/single-select-filter.js +++ b/src/components/filters/single-select-filter.tsx @@ -22,9 +22,10 @@ import React from 'react'; import ItemSelector from '../common/item-selector/item-selector'; import {PanelLabel, SidePanelSection} from '../common/styled-components'; import {FormattedMessage} from 'localization'; +import {SingleSelectFilterProps} from './types'; export default function SingleSelectFilterFactory() { - const SingleSelectFilter = ({filter, setFilter}) => ( + const SingleSelectFilter: React.FC = ({filter, setFilter}) => ( diff --git a/src/components/filters/time-range-filter.js b/src/components/filters/time-range-filter.tsx similarity index 85% rename from src/components/filters/time-range-filter.js rename to src/components/filters/time-range-filter.tsx index d2c4719e50..999324b9cb 100644 --- a/src/components/filters/time-range-filter.js +++ b/src/components/filters/time-range-filter.tsx @@ -21,11 +21,13 @@ import React from 'react'; import TimeRangeSliderFactory from 'components/common/time-range-slider'; import {DEFAULT_TIME_FORMAT} from 'constants/default-settings'; +import {TimeRangeFilter} from 'reducers'; +import {TimeRangeFilterProps} from './types'; /* * TimeRangeFilter -> TimeRangeSlider -> RangeSlider */ -export function timeRangeSliderFieldsSelector(filter) { +export function timeRangeSliderFieldsSelector(filter: TimeRangeFilter) { const hasUserFormat = typeof filter.timeFormat === 'string'; const timeFormat = (hasUserFormat ? filter.timeFormat : filter.defaultTimeFormat) || DEFAULT_TIME_FORMAT; @@ -51,8 +53,14 @@ export function timeRangeSliderFieldsSelector(filter) { TimeRangeFilterFactory.deps = [TimeRangeSliderFactory]; -function TimeRangeFilterFactory(TimeRangeSlider) { - const TimeRangeFilter = ({filter, setFilter, isAnimatable, toggleAnimation, hideTimeTitle}) => ( +function TimeRangeFilterFactory(TimeRangeSlider: ReturnType) { + const TimeRangeFilter: React.FC = ({ + filter, + setFilter, + isAnimatable, + toggleAnimation, + hideTimeTitle + }) => ( ` display: flex; justify-content: space-between; width: 100%; @@ -103,12 +105,19 @@ const StyledTitle = styled(CenterFlexbox)` `; TimeWidgetTopFactory.deps = [FieldSelectorFactory]; -export function TimeWidgetTopFactory(FieldSelector) { - const TimeWidgetTop = ({filter, readOnly, datasets, setFilterPlot, index, onClose}) => { +export function TimeWidgetTopFactory(FieldSelector: ReturnType) { + const TimeWidgetTop: React.FC = ({ + filter, + readOnly, + datasets, + setFilterPlot, + index, + onClose + }) => { const yAxisFields = useMemo( () => ((datasets[filter.dataId[0]] || {}).fields || []).filter( - f => f.type === 'integer' || f.type === 'real' + (f: Field) => f.type === 'integer' || f.type === 'real' ), [datasets, filter.dataId] ); @@ -132,7 +141,6 @@ export function TimeWidgetTopFactory(FieldSelector) { , + FloatingTimeDisplay: ReturnType, + TimeWidgetTop: ReturnType +) { + const TimeWidget: React.FC = ({ datasets, filter, index, @@ -170,7 +182,7 @@ function TimeWidgetFactory(TimeRangeSlider, FloatingTimeDisplay, TimeWidgetTop) enlargeFilter, setFilterPlot, setFilterAnimationWindow - }) => { + }: TimeWidgetProps) => { const _updateAnimationSpeed = useCallback(speed => updateAnimationSpeed(index, speed), [ updateAnimationSpeed, index diff --git a/src/components/filters/types.ts b/src/components/filters/types.ts new file mode 100644 index 0000000000..94b654e3ed --- /dev/null +++ b/src/components/filters/types.ts @@ -0,0 +1,76 @@ +import { + Datasets, + Filter, + MultiSelectFilter, + RangeFilter, + SelectFilter, + TimeRangeFilter +} from 'reducers'; +import {Layer} from 'layers'; +import { + ActionHandler, + enlargeFilter, + setFilterAnimationTime, + setFilterAnimationWindow, + setFilterPlot, + toggleFilterAnimation, + updateFilterAnimationSpeed +} from 'actions'; + +export type PolygonFilterProps = { + filter: Filter; + layers: ReadonlyArray; + setLayers: (ids: ReadonlyArray) => void; +}; + +export type TopSectionWrapperProps = { + hoverColor?: string; +}; + +export type RangeFilterProps = { + filter: RangeFilter; + setFilter: (v: number[]) => void; +}; + +export type TimeRangeFilterProps = { + filter: TimeRangeFilter; + isAnimatable: boolean; + hideTimeTitle: boolean; + setFilter: (v: number[]) => void; + toggleAnimation: () => void; +}; + +export type SingleSelectFilterProps = { + filter: SelectFilter; + setFilter: (v: string | number | boolean | object | null) => void; +}; + +export type MultiSelectFilterProps = { + filter: MultiSelectFilter; + setFilter: (v: ReadonlyArray | null) => void; +}; + +export type TimeWidgetTopProps = { + filter: Filter; + readOnly: boolean; + datasets: Datasets; + setFilterPlot: ActionHandler; + index: number; + onClose: () => void; +}; + +export type TimeWidgetProps = { + datasets: Datasets; + filter: TimeRangeFilter; + index: number; + readOnly: boolean; + showTimeDisplay: boolean; + isAnimatable: boolean; + resetAnimation: () => void; + setFilterAnimationTime: ActionHandler; + updateAnimationSpeed: ActionHandler; + toggleAnimation: ActionHandler; + enlargeFilter: ActionHandler; + setFilterPlot: ActionHandler; + setFilterAnimationWindow: ActionHandler; +}; diff --git a/src/components/side-panel/common/dataset-tag.tsx b/src/components/side-panel/common/dataset-tag.tsx index 530588e76d..45a1040f83 100644 --- a/src/components/side-panel/common/dataset-tag.tsx +++ b/src/components/side-panel/common/dataset-tag.tsx @@ -18,15 +18,13 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import React, {MouseEvent} from 'react'; +import React from 'react'; import {FormattedMessage} from 'localization'; import styled from 'styled-components'; import {DatasetSquare, Tooltip} from 'components'; -import {DatasetTagWrapperProps, DatasetTagProps, UpdateTableColorTypes} from './types'; +import {DatasetTagProps, UpdateTableColorTypes} from './types'; -function nop(_) {} - -const DatasetTagWrapper = styled.div` +const DatasetTagWrapper = styled.div` display: flex; color: ${props => props.theme.textColor}; font-size: 11px; @@ -49,15 +47,11 @@ const DatasetColorPicker = styled.div` display: flex; `; -const UpdateTableColor = ({updateTableColor = nop, children, id}: UpdateTableColorTypes) => ( +const UpdateTableColor = ({children, id}: UpdateTableColorTypes) => ( { - e.stopPropagation(); - updateTableColor(id); - }} > {children} @@ -65,8 +59,8 @@ const UpdateTableColor = ({updateTableColor = nop, children, id}: UpdateTableCol export default function DatasetTagFactory() { const DatasetTag = ({onClick, onClickSquare, dataset, updateTableColor, id}: DatasetTagProps) => ( - - + + ` color: ${props => props.theme.textColor}; display: flex; @@ -69,13 +67,13 @@ const DataTagAction = styled.div` opacity: 0; `; -const ShowDataTable = ({id, showDatasetTable = nop}: ShowDataTableProps) => ( +const ShowDataTable = ({id, showDatasetTable}: ShowDataTableProps) => ( { e.stopPropagation(); - showDatasetTable(id); + showDatasetTable?.(id); }} /> @@ -86,7 +84,7 @@ const ShowDataTable = ({id, showDatasetTable = nop}: ShowDataTableProps) => ( ); -const RemoveDataset = ({datasetKey, removeDataset = nop}: RemoveDatasetProps) => ( +const RemoveDataset = ({datasetKey, removeDataset}: RemoveDatasetProps) => ( height="16px" onClick={e => { e.stopPropagation(); - removeDataset(datasetKey); + removeDataset?.(datasetKey); }} /> @@ -111,7 +109,7 @@ DatasetTitleFactory.deps = [DatasetTagFactory]; export default function DatasetTitleFactory( DatasetTag: ReturnType -): React.ComponentClass { +): React.ComponentType { class DatasetTitle extends PureComponent { state = { displayColorPicker: false @@ -162,7 +160,7 @@ export default function DatasetTitleFactory( }) => - updateTableColor?.(dataset.id, [color.rgb.r, color.rgb.g, color.rgb.b]) + updateTableColor(dataset.id, [color.rgb.r, color.rgb.g, color.rgb.b]) } onSwatchClose={this._handleClosePicker} /> diff --git a/src/components/side-panel/common/source-data-selector.tsx b/src/components/side-panel/common/source-data-selector.tsx index e149a444f3..bf3a873c25 100644 --- a/src/components/side-panel/common/source-data-selector.tsx +++ b/src/components/side-panel/common/source-data-selector.tsx @@ -33,7 +33,7 @@ SourceDataSelectorFactory.deps = [DatasetTagFactory]; export default function SourceDataSelectorFactory( DatasetTag: ReturnType -): React.ComponentClass { +): React.ComponentType { const DatasetItem = ({value}: DatasetItemProps) => ; class SourceDataSelector extends Component { @@ -42,6 +42,7 @@ export default function SourceDataSelectorFactory( }; /* selectors */ + dataIdSelector = (props: SourceDataSelectorProps) => props.dataId; datasetsSelector = (props: SourceDataSelectorProps) => props.datasets; dsOptionsSelector = createSelector(this.datasetsSelector, datasets => Object.values(datasets).map(ds => ({ @@ -50,10 +51,17 @@ export default function SourceDataSelectorFactory( color: ds.color })) ); + dsSelectedItemsSelector = createSelector( + this.dataIdSelector, + this.datasetsSelector, + (dataId, datasets) => + dataId ? ((Array.isArray(dataId) && dataId) || [dataId]).map(id => datasets[id]) : [] + ); render() { - const {dataId, disabled, onSelect, defaultValue, inputTheme} = this.props; + const {disabled, onSelect, defaultValue, inputTheme} = this.props; const dsOptions = this.dsOptionsSelector(this.props); + const selectedItems = this.dsSelectedItemsSelector(this.props); return ( @@ -62,7 +70,7 @@ export default function SourceDataSelectorFactory( void; -}; - -export type DatasetTagWrapperProps = { - updateTableColor?: (d: string, c?: RGBColor) => void; }; export type DatasetTagProps = { id?: string; dataset: KeplerTable; - updateTableColor?: (d: string, c?: RGBColor) => void; + updateTableColor?: ActionHandler; onClick?: (e: MouseEvent) => void; onClickSquare?: (e: MouseEvent) => void; }; export type ShowDataTableProps = { id: string; - showDatasetTable: Function; + showDatasetTable?: ActionHandler; }; export type RemoveDatasetProps = { datasetKey: string; - removeDataset?: (d: string) => void; + removeDataset?: ActionHandler; }; export type StyledDatasetTitleProps = { @@ -40,20 +38,20 @@ export type StyledDatasetTitleProps = { export type DatasetTitleProps = { dataset: KeplerTable; - showDatasetTable: Function; showDeleteDataset: boolean; onTitleClick?: () => void; - updateTableColor?: (d: string, c?: RGBColor) => void; - removeDataset?: (d: string) => void; + showDatasetTable?: ActionHandler; + updateTableColor: ActionHandler; + removeDataset?: ActionHandler; }; export type SourceDataCatalogProps = { datasets: Datasets; - showDatasetTable: Function; - showDeleteDataset: boolean; + showDeleteDataset?: boolean; onTitleClick?: () => void; - updateTableColor?: (d: string, c?: RGBColor) => void; - removeDataset?: (d: string) => void; + showDatasetTable?: ActionHandler; + updateTableColor: ActionHandler; + removeDataset?: ActionHandler; }; export type DatasetItemProps = { @@ -61,10 +59,10 @@ export type DatasetItemProps = { }; export type SourceDataSelectorProps = { - dataId: string; + dataId: string | string[]; datasets: Datasets; disabled: boolean; - defaultValue: string; + defaultValue?: string; inputTheme: string; onSelect: (items: ReadonlyArray | null) => void; }; diff --git a/src/components/side-panel/filter-panel/filter-panel-header.tsx b/src/components/side-panel/filter-panel/filter-panel-header.tsx index 0689ebf08d..557586e83d 100644 --- a/src/components/side-panel/filter-panel/filter-panel-header.tsx +++ b/src/components/side-panel/filter-panel/filter-panel-header.tsx @@ -24,10 +24,12 @@ import PanelHeaderActionFactory from 'components/side-panel/panel-header-action' import {Trash} from 'components/common/icons'; import {createLinearGradient} from 'utils/color-utils'; import {StyledPanelHeader} from 'components/common/styled-components'; -import {FilterPanelProps} from 'components/filters/filter-panels/filter-panel-types'; +import {Filter, RGBColor} from 'reducers'; import KeplerTable from 'utils/table-utils/kepler-table'; -export const StyledFilterHeader = styled(StyledPanelHeader)` +export const StyledFilterHeader = styled(StyledPanelHeader)<{ + labelRCGColorValues: RGBColor[]; +}>` cursor: pointer; padding: 10px 12px; @@ -47,15 +49,19 @@ const StyledChildrenContainer = styled.div` flex: 2; `; -interface FilterPanelHeaderProps extends FilterPanelProps { +type FilterPanelHeaderProps = { children: React.ReactNode; - enlarged?: boolean; + datasets: KeplerTable[]; + filter: Filter; + removeFilter: () => void; actionIcons?: Record; -} +}; FilterPanelHeaderFactory.deps = [PanelHeaderActionFactory]; -function FilterPanelHeaderFactory(PanelHeaderAction: ReturnType) { +function FilterPanelHeaderFactory( + PanelHeaderAction: ReturnType +): React.ComponentType { const defaultActionIcons = { delete: Trash }; diff --git a/src/components/side-panel/filter-panel/filter-panel.tsx b/src/components/side-panel/filter-panel/filter-panel.tsx index 013d2de76e..5eba60f601 100644 --- a/src/components/side-panel/filter-panel/filter-panel.tsx +++ b/src/components/side-panel/filter-panel/filter-panel.tsx @@ -30,10 +30,9 @@ import SingleSelectFilterPanelFactory from 'components/filters/filter-panels/sin import MultiSelectFilterPanelFactory from 'components/filters/filter-panels/multi-select-filter-panel'; import RangeFilterPanelFactory from 'components/filters/filter-panels/range-filter-panel'; import PolygonFilterPanelFactory from 'components/filters/filter-panels/polygon-filter-panel'; - import {Filter} from 'reducers/vis-state-updaters'; import {Field} from 'utils/table-utils/kepler-table'; -import {FilterPanelProps} from 'components/filters/filter-panels/filter-panel-types'; +import {FilterPanelProps} from 'components/filters/filter-panels/types'; const StyledFilterPanel = styled.div` margin-bottom: 12px; @@ -60,7 +59,7 @@ function FilterPanelFactory( MultiSelectFilterPanel: ReturnType, RangeFilterPanel: ReturnType, PolygonFilterPanel: ReturnType -) { +): React.ComponentType { const FilterPanelComponents = { default: NewFilterPanel, [FILTER_TYPES.timeRange]: TimeRangeFilterPanel, diff --git a/src/reducers/vis-state-updaters.ts b/src/reducers/vis-state-updaters.ts index 6292957b0e..88636536a3 100644 --- a/src/reducers/vis-state-updaters.ts +++ b/src/reducers/vis-state-updaters.ts @@ -214,6 +214,7 @@ export type TimeRangeFilter = FilterBase & plotType: { [key: string]: any; }; + animationWindow: string; }; export type PolygonFilter = FilterBase & {