mirror of
https://github.com/apache/superset.git
synced 2024-09-12 08:39:45 -04:00
feat(native-filters): Disable Apply button if filter required (#15222)
* fix:fix get permission function * fix: fix select first value by clear all * lint: fix lint * feat: disable select on missed value * fix: refactor ff * feat: connect nulls for line chart * lint: fix lint * docs: fix message * fix: fix CR comments * fix: fix Collapsed items * fix: fix Collapsed items
This commit is contained in:
parent
1269cc2f88
commit
388eb01f06
@ -43,6 +43,7 @@ import { ClientErrorObject } from 'src/utils/getClientErrorObject';
|
|||||||
import { FilterProps } from './types';
|
import { FilterProps } from './types';
|
||||||
import { getFormData } from '../../utils';
|
import { getFormData } from '../../utils';
|
||||||
import { useCascadingFilters } from './state';
|
import { useCascadingFilters } from './state';
|
||||||
|
import { checkIsMissingRequiredValue } from '../utils';
|
||||||
|
|
||||||
const FilterItem = styled.div`
|
const FilterItem = styled.div`
|
||||||
min-height: ${({ theme }) => theme.gridUnit * 11}px;
|
min-height: ${({ theme }) => theme.gridUnit * 11}px;
|
||||||
@ -181,6 +182,11 @@ const FilterValue: React.FC<FilterProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isMissingRequiredValue = checkIsMissingRequiredValue(
|
||||||
|
filter,
|
||||||
|
filter.dataMask?.filterState,
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FilterItem data-test="form-item-value">
|
<FilterItem data-test="form-item-value">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@ -194,7 +200,11 @@ const FilterValue: React.FC<FilterProps> = ({
|
|||||||
queriesData={hasDataSource ? state : [{ data: [{}] }]}
|
queriesData={hasDataSource ? state : [{ data: [{}] }]}
|
||||||
chartType={filterType}
|
chartType={filterType}
|
||||||
behaviors={[Behavior.NATIVE_FILTER]}
|
behaviors={[Behavior.NATIVE_FILTER]}
|
||||||
filterState={filter.dataMask?.filterState}
|
filterState={{
|
||||||
|
...filter.dataMask?.filterState,
|
||||||
|
validateMessage: isMissingRequiredValue && t('Value is required'),
|
||||||
|
validateStatus: isMissingRequiredValue && 'error',
|
||||||
|
}}
|
||||||
ownState={filter.dataMask?.ownState}
|
ownState={filter.dataMask?.ownState}
|
||||||
enableNoResults={metadata?.enableNoResults}
|
enableNoResults={metadata?.enableNoResults}
|
||||||
isRefreshing={isRefreshing}
|
isRefreshing={isRefreshing}
|
||||||
|
@ -29,12 +29,11 @@ import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
|||||||
import { updateDataMask } from 'src/dataMask/actions';
|
import { updateDataMask } from 'src/dataMask/actions';
|
||||||
import { DataMaskStateWithId, DataMaskWithId } from 'src/dataMask/types';
|
import { DataMaskStateWithId, DataMaskWithId } from 'src/dataMask/types';
|
||||||
import { useImmer } from 'use-immer';
|
import { useImmer } from 'use-immer';
|
||||||
import { areObjectsEqual } from 'src/reduxUtils';
|
|
||||||
import { testWithId } from 'src/utils/testUtils';
|
import { testWithId } from 'src/utils/testUtils';
|
||||||
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
import { Filter } from 'src/dashboard/components/nativeFilters/types';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import { getInitialDataMask } from 'src/dataMask/reducer';
|
import { getInitialDataMask } from 'src/dataMask/reducer';
|
||||||
import { getOnlyExtraFormData, TabIds } from './utils';
|
import { checkIsApplyDisabled, TabIds } from './utils';
|
||||||
import FilterSets from './FilterSets';
|
import FilterSets from './FilterSets';
|
||||||
import {
|
import {
|
||||||
useNativeFiltersDataMask,
|
useNativeFiltersDataMask,
|
||||||
@ -214,16 +213,11 @@ const FilterBar: React.FC<FiltersBarProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useFilterUpdates(dataMaskSelected, setDataMaskSelected);
|
useFilterUpdates(dataMaskSelected, setDataMaskSelected);
|
||||||
|
const isApplyDisabled = checkIsApplyDisabled(
|
||||||
const dataSelectedValues = Object.values(dataMaskSelected);
|
dataMaskSelected,
|
||||||
const dataAppliedValues = Object.values(dataMaskApplied);
|
dataMaskApplied,
|
||||||
const isApplyDisabled =
|
filterValues,
|
||||||
areObjectsEqual(
|
);
|
||||||
getOnlyExtraFormData(dataMaskSelected),
|
|
||||||
getOnlyExtraFormData(dataMaskApplied),
|
|
||||||
{ ignoreUndefined: true },
|
|
||||||
) || dataSelectedValues.length !== dataAppliedValues.length;
|
|
||||||
|
|
||||||
const isInitialized = useInitialization();
|
const isInitialized = useInitialization();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DataMaskStateWithId } from 'src/dataMask/types';
|
import { DataMaskStateWithId } from 'src/dataMask/types';
|
||||||
|
import { areObjectsEqual } from 'src/reduxUtils';
|
||||||
|
import { FilterState } from '@superset-ui/core';
|
||||||
import { Filter } from '../types';
|
import { Filter } from '../types';
|
||||||
|
|
||||||
export enum TabIds {
|
export enum TabIds {
|
||||||
@ -46,3 +48,39 @@ export const getOnlyExtraFormData = (data: DataMaskStateWithId) =>
|
|||||||
(prev, next) => ({ ...prev, [next.id]: next.extraFormData }),
|
(prev, next) => ({ ...prev, [next.id]: next.extraFormData }),
|
||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const checkIsMissingRequiredValue = (
|
||||||
|
filter: Filter,
|
||||||
|
filterState?: FilterState,
|
||||||
|
) => {
|
||||||
|
const value = filterState?.value;
|
||||||
|
// TODO: this property should be unhardcoded
|
||||||
|
return (
|
||||||
|
filter.controlValues.enableEmptyFilter &&
|
||||||
|
(value === null || value === undefined)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const checkIsApplyDisabled = (
|
||||||
|
dataMaskSelected: DataMaskStateWithId,
|
||||||
|
dataMaskApplied: DataMaskStateWithId,
|
||||||
|
filters: Filter[],
|
||||||
|
) => {
|
||||||
|
const dataSelectedValues = Object.values(dataMaskSelected);
|
||||||
|
const dataAppliedValues = Object.values(dataMaskApplied);
|
||||||
|
|
||||||
|
return (
|
||||||
|
areObjectsEqual(
|
||||||
|
getOnlyExtraFormData(dataMaskSelected),
|
||||||
|
getOnlyExtraFormData(dataMaskApplied),
|
||||||
|
{ ignoreUndefined: true },
|
||||||
|
) ||
|
||||||
|
dataSelectedValues.length !== dataAppliedValues.length ||
|
||||||
|
filters.some(filter =>
|
||||||
|
checkIsMissingRequiredValue(
|
||||||
|
filter,
|
||||||
|
dataMaskSelected?.[filter?.id]?.filterState,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -16,11 +16,12 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { ReactNode, useState } from 'react';
|
import React, { ReactNode, useEffect, useState } from 'react';
|
||||||
import { styled } from '@superset-ui/core';
|
import { styled } from '@superset-ui/core';
|
||||||
import { Checkbox } from 'src/common/components';
|
import { Checkbox } from 'src/common/components';
|
||||||
|
|
||||||
interface CollapsibleControlProps {
|
interface CollapsibleControlProps {
|
||||||
|
initialValue?: boolean;
|
||||||
checked?: boolean;
|
checked?: boolean;
|
||||||
title: string;
|
title: string;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -45,8 +46,23 @@ const StyledContainer = styled.div<{ checked: boolean }>`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const CollapsibleControl = (props: CollapsibleControlProps) => {
|
const CollapsibleControl = (props: CollapsibleControlProps) => {
|
||||||
const { checked = false, title, children, onChange } = props;
|
const {
|
||||||
const [isChecked, setIsChecked] = useState(checked);
|
checked,
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
onChange = () => {},
|
||||||
|
initialValue = false,
|
||||||
|
} = props;
|
||||||
|
const [isChecked, setIsChecked] = useState(initialValue);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// if external `checked` changed to `undefined`, it means that we work now in uncontrolled mode with local state
|
||||||
|
// and we need ignore external value
|
||||||
|
if (checked !== undefined) {
|
||||||
|
setIsChecked(checked);
|
||||||
|
}
|
||||||
|
}, [checked]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer checked={isChecked}>
|
<StyledContainer checked={isChecked}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -54,10 +70,12 @@ const CollapsibleControl = (props: CollapsibleControlProps) => {
|
|||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
const value = e.target.checked;
|
const value = e.target.checked;
|
||||||
setIsChecked(value);
|
// external `checked` value has more priority then local state
|
||||||
if (onChange) {
|
if (checked === undefined) {
|
||||||
onChange(value);
|
// uncontrolled mode
|
||||||
|
setIsChecked(value);
|
||||||
}
|
}
|
||||||
|
onChange(value);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
|
@ -69,7 +69,7 @@ import {
|
|||||||
setNativeFilterFieldValues,
|
setNativeFilterFieldValues,
|
||||||
useForceUpdate,
|
useForceUpdate,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { useBackendFormUpdate } from './state';
|
import { useBackendFormUpdate, useDefaultValue } from './state';
|
||||||
import { getFormData } from '../../utils';
|
import { getFormData } from '../../utils';
|
||||||
import { Filter } from '../../types';
|
import { Filter } from '../../types';
|
||||||
import getControlItemsMap from './getControlItemsMap';
|
import getControlItemsMap from './getControlItemsMap';
|
||||||
@ -280,14 +280,13 @@ const FiltersConfigForm = (
|
|||||||
const [activeFilterPanelKey, setActiveFilterPanelKey] = useState<
|
const [activeFilterPanelKey, setActiveFilterPanelKey] = useState<
|
||||||
string | string[]
|
string | string[]
|
||||||
>(FilterPanels.basic.key);
|
>(FilterPanels.basic.key);
|
||||||
const [hasDefaultValue, setHasDefaultValue] = useState(
|
|
||||||
!!filterToEdit?.defaultDataMask?.filterState?.value,
|
|
||||||
);
|
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
const [datasetDetails, setDatasetDetails] = useState<Record<string, any>>();
|
const [datasetDetails, setDatasetDetails] = useState<Record<string, any>>();
|
||||||
const defaultFormFilter = useMemo(() => {}, []);
|
const defaultFormFilter = useMemo(() => {}, []);
|
||||||
const formFilter =
|
const formFilter =
|
||||||
form.getFieldValue('filters')?.[filterId] || defaultFormFilter;
|
form.getFieldValue('filters')?.[filterId] || defaultFormFilter;
|
||||||
|
|
||||||
const nativeFilterItems = getChartMetadataRegistry().items;
|
const nativeFilterItems = getChartMetadataRegistry().items;
|
||||||
const nativeFilterVizTypes = Object.entries(nativeFilterItems)
|
const nativeFilterVizTypes = Object.entries(nativeFilterItems)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -431,6 +430,11 @@ const FiltersConfigForm = (
|
|||||||
...formFilter,
|
...formFilter,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [hasDefaultValue, setHasDefaultValue] = useDefaultValue(
|
||||||
|
formFilter,
|
||||||
|
filterToEdit,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (hasDataset && hasFilledDataset && hasDefaultValue && isDataDirty) {
|
if (hasDataset && hasFilledDataset && hasDefaultValue && isDataDirty) {
|
||||||
refreshHandler();
|
refreshHandler();
|
||||||
@ -672,6 +676,7 @@ const FiltersConfigForm = (
|
|||||||
/>
|
/>
|
||||||
<CollapsibleControl
|
<CollapsibleControl
|
||||||
title={t('Filter has default value')}
|
title={t('Filter has default value')}
|
||||||
|
initialValue={hasDefaultValue}
|
||||||
checked={hasDefaultValue}
|
checked={hasDefaultValue}
|
||||||
onChange={value => setHasDefaultValue(value)}
|
onChange={value => setHasDefaultValue(value)}
|
||||||
>
|
>
|
||||||
@ -680,18 +685,17 @@ const FiltersConfigForm = (
|
|||||||
initialValue={filterToEdit?.defaultDataMask}
|
initialValue={filterToEdit?.defaultDataMask}
|
||||||
data-test="default-input"
|
data-test="default-input"
|
||||||
label={<StyledLabel>{t('Default Value')}</StyledLabel>}
|
label={<StyledLabel>{t('Default Value')}</StyledLabel>}
|
||||||
required
|
required={formFilter?.controlValues?.enableEmptyFilter}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
validator: (rule, value) => {
|
validator: (rule, value) => {
|
||||||
const hasValue = !!value?.filterState?.value;
|
const hasValue = !!value?.filterState?.value;
|
||||||
if (
|
if (
|
||||||
hasValue ||
|
hasValue ||
|
||||||
// TODO: do more generic
|
// TODO: do more generic
|
||||||
formFilter.controlValues?.defaultToFirstItem
|
formFilter.controlValues?.defaultToFirstItem ||
|
||||||
|
// Not marked as required
|
||||||
|
!formFilter.controlValues?.enableEmptyFilter
|
||||||
) {
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@ -760,7 +764,7 @@ const FiltersConfigForm = (
|
|||||||
{isCascadingFilter && (
|
{isCascadingFilter && (
|
||||||
<CollapsibleControl
|
<CollapsibleControl
|
||||||
title={t('Filter is hierarchical')}
|
title={t('Filter is hierarchical')}
|
||||||
checked={hasParentFilter}
|
initialValue={hasParentFilter}
|
||||||
onChange={checked => {
|
onChange={checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
// execute after render
|
// execute after render
|
||||||
@ -801,7 +805,7 @@ const FiltersConfigForm = (
|
|||||||
{hasDataset && hasAdditionalFilters && (
|
{hasDataset && hasAdditionalFilters && (
|
||||||
<CollapsibleControl
|
<CollapsibleControl
|
||||||
title={t('Pre-filter available values')}
|
title={t('Pre-filter available values')}
|
||||||
checked={hasPreFilter}
|
initialValue={hasPreFilter}
|
||||||
onChange={checked => {
|
onChange={checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
validatePreFilter();
|
validatePreFilter();
|
||||||
@ -902,7 +906,7 @@ const FiltersConfigForm = (
|
|||||||
<CollapsibleControl
|
<CollapsibleControl
|
||||||
title={t('Sort filter values')}
|
title={t('Sort filter values')}
|
||||||
onChange={checked => onSortChanged(checked || undefined)}
|
onChange={checked => onSortChanged(checked || undefined)}
|
||||||
checked={hasSorting}
|
initialValue={hasSorting}
|
||||||
>
|
>
|
||||||
<StyledFormItem
|
<StyledFormItem
|
||||||
name={[
|
name={[
|
||||||
|
@ -16,10 +16,11 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { useEffect } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import { FormInstance } from 'antd/lib/form';
|
import { FormInstance } from 'antd/lib/form';
|
||||||
import { NativeFiltersForm } from '../types';
|
import { NativeFiltersForm, NativeFiltersFormItem } from '../types';
|
||||||
import { setNativeFilterFieldValues, useForceUpdate } from './utils';
|
import { setNativeFilterFieldValues, useForceUpdate } from './utils';
|
||||||
|
import { Filter } from '../../types';
|
||||||
|
|
||||||
// When some fields in form changed we need re-fetch data for Filter defaultValue
|
// When some fields in form changed we need re-fetch data for Filter defaultValue
|
||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
@ -46,3 +47,29 @@ export const useBackendFormUpdate = (
|
|||||||
filterId,
|
filterId,
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useDefaultValue = (
|
||||||
|
formFilter?: NativeFiltersFormItem,
|
||||||
|
filterToEdit?: Filter,
|
||||||
|
) => {
|
||||||
|
const [hasDefaultValue, setHasPartialDefaultValue] = useState(
|
||||||
|
!!filterToEdit?.defaultDataMask?.filterState?.value ||
|
||||||
|
formFilter?.controlValues?.enableEmptyFilter,
|
||||||
|
);
|
||||||
|
const setHasDefaultValue = useCallback(
|
||||||
|
(value?) => {
|
||||||
|
setHasPartialDefaultValue(
|
||||||
|
value || formFilter?.controlValues?.enableEmptyFilter
|
||||||
|
? true
|
||||||
|
: undefined,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[formFilter?.controlValues?.enableEmptyFilter],
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setHasDefaultValue();
|
||||||
|
}, [setHasDefaultValue]);
|
||||||
|
|
||||||
|
return [hasDefaultValue, setHasDefaultValue];
|
||||||
|
};
|
||||||
|
@ -26,9 +26,11 @@ import {
|
|||||||
GenericDataType,
|
GenericDataType,
|
||||||
JsonObject,
|
JsonObject,
|
||||||
smartDateDetailedFormatter,
|
smartDateDetailedFormatter,
|
||||||
|
styled,
|
||||||
t,
|
t,
|
||||||
tn,
|
tn,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
|
import { FormItem } from 'src/components/Form';
|
||||||
import React, {
|
import React, {
|
||||||
RefObject,
|
RefObject,
|
||||||
ReactElement,
|
ReactElement,
|
||||||
@ -80,6 +82,10 @@ function reducer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Error = styled.div`
|
||||||
|
color: ${({ theme }) => theme.colors.error.base};
|
||||||
|
`;
|
||||||
|
|
||||||
export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
||||||
const {
|
const {
|
||||||
coltypeMap,
|
coltypeMap,
|
||||||
@ -273,52 +279,57 @@ export default function PluginFilterSelect(props: PluginFilterSelectProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Styles height={height} width={width}>
|
<Styles height={height} width={width}>
|
||||||
<StyledSelect
|
<FormItem
|
||||||
allowClear={!enableEmptyFilter}
|
validateStatus={filterState.validateStatus}
|
||||||
// @ts-ignore
|
extra={<Error>{filterState.validateMessage}</Error>}
|
||||||
value={filterState.value || []}
|
|
||||||
disabled={isDisabled}
|
|
||||||
showSearch={showSearch}
|
|
||||||
mode={multiSelect ? 'multiple' : undefined}
|
|
||||||
placeholder={placeholderText}
|
|
||||||
onSearch={searchWrapper}
|
|
||||||
onSelect={clearSuggestionSearch}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
onDropdownVisibleChange={setIsDropdownVisible}
|
|
||||||
dropdownRender={(
|
|
||||||
originNode: ReactElement & { ref?: RefObject<HTMLElement> },
|
|
||||||
) => {
|
|
||||||
if (isDropdownVisible && !wasDropdownVisible) {
|
|
||||||
originNode.ref?.current?.scrollTo({ top: 0 });
|
|
||||||
}
|
|
||||||
return originNode;
|
|
||||||
}}
|
|
||||||
onFocus={setFocusedFilter}
|
|
||||||
// @ts-ignore
|
|
||||||
onChange={handleChange}
|
|
||||||
ref={inputRef}
|
|
||||||
loading={isRefreshing}
|
|
||||||
maxTagCount={5}
|
|
||||||
menuItemSelectedIcon={<Icon iconSize="m" />}
|
|
||||||
>
|
>
|
||||||
{sortedData.map(row => {
|
<StyledSelect
|
||||||
const [value] = groupby.map(col => row[col]);
|
allowClear={!enableEmptyFilter}
|
||||||
return (
|
// @ts-ignore
|
||||||
// @ts-ignore
|
value={filterState.value || []}
|
||||||
<Option key={`${value}`} value={value}>
|
disabled={isDisabled}
|
||||||
{labelFormatter(value, datatype)}
|
showSearch={showSearch}
|
||||||
</Option>
|
mode={multiSelect ? 'multiple' : undefined}
|
||||||
);
|
placeholder={placeholderText}
|
||||||
})}
|
onSearch={searchWrapper}
|
||||||
{currentSuggestionSearch &&
|
onSelect={clearSuggestionSearch}
|
||||||
!ensureIsArray(filterState.value).some(
|
onBlur={handleBlur}
|
||||||
suggestion => suggestion === currentSuggestionSearch,
|
onDropdownVisibleChange={setIsDropdownVisible}
|
||||||
) && (
|
dropdownRender={(
|
||||||
<Option value={currentSuggestionSearch}>
|
originNode: ReactElement & { ref?: RefObject<HTMLElement> },
|
||||||
{`${t('Create "%s"', currentSuggestionSearch)}`}
|
) => {
|
||||||
</Option>
|
if (isDropdownVisible && !wasDropdownVisible) {
|
||||||
)}
|
originNode.ref?.current?.scrollTo({ top: 0 });
|
||||||
</StyledSelect>
|
}
|
||||||
|
return originNode;
|
||||||
|
}}
|
||||||
|
onFocus={setFocusedFilter}
|
||||||
|
// @ts-ignore
|
||||||
|
onChange={handleChange}
|
||||||
|
ref={inputRef}
|
||||||
|
loading={isRefreshing}
|
||||||
|
maxTagCount={5}
|
||||||
|
menuItemSelectedIcon={<Icon iconSize="m" />}
|
||||||
|
>
|
||||||
|
{sortedData.map(row => {
|
||||||
|
const [value] = groupby.map(col => row[col]);
|
||||||
|
return (
|
||||||
|
// @ts-ignore
|
||||||
|
<Option key={`${value}`} value={value}>
|
||||||
|
{labelFormatter(value, datatype)}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
{currentSuggestionSearch &&
|
||||||
|
!ensureIsArray(filterState.value).some(
|
||||||
|
suggestion => suggestion === currentSuggestionSearch,
|
||||||
|
) && (
|
||||||
|
<Option value={currentSuggestionSearch}>
|
||||||
|
{`${t('Create "%s"', currentSuggestionSearch)}`}
|
||||||
|
</Option>
|
||||||
|
)}
|
||||||
|
</StyledSelect>
|
||||||
|
</FormItem>
|
||||||
</Styles>
|
</Styles>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user