Skip to content

Commit

Permalink
feat: Add single select and inverse selection to numeric range (#16722)…
Browse files Browse the repository at this point in the history
… (#17372)

* feat: add single select and inverse selection to numeric range (#16722)

* Ignore invalid eslint errors regarding conditionally called hooks.

* Add license header to new file.

* Flipped the numerical range values for the minimum slider so that the highlighted range value accurately reflects the applied filter.

* Resolved linting errors

* Remove unnecessary important flag from css
  • Loading branch information
mhoustonataegis authored Dec 1, 2021
1 parent f949c8e commit 54b56fe
Show file tree
Hide file tree
Showing 9 changed files with 332 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
/* eslint-disable react-hooks/rules-of-hooks */
import {
ColumnMeta,
InfoTooltipWithTrigger,
Expand All @@ -35,7 +36,7 @@ import {
t,
} from '@superset-ui/core';
import { FormInstance } from 'antd/lib/form';
import { isEmpty, isEqual } from 'lodash';
import { isEqual } from 'lodash';
import React, {
forwardRef,
useCallback,
Expand Down Expand Up @@ -73,6 +74,7 @@ import {
Filter,
NativeFilterType,
} from 'src/dashboard/components/nativeFilters/types';
import { SingleValueType } from 'src/filters/components/Range/SingleValueType';
import { getFormData } from 'src/dashboard/components/nativeFilters/utils';
import {
CASCADING_FILTERS,
Expand Down Expand Up @@ -543,6 +545,15 @@ const FiltersConfigForm = (
!!filterToEdit?.adhoc_filters?.length ||
!!filterToEdit?.time_range;

const hasEnableSingleValue =
formFilter?.controlValues?.enableSingleValue !== undefined ||
filterToEdit?.controlValues?.enableSingleValue !== undefined;

let enableSingleValue = filterToEdit?.controlValues?.enableSingleValue;
if (formFilter?.controlValues?.enableSingleMaxValue !== undefined) {
({ enableSingleValue } = formFilter.controlValues);
}

const hasSorting =
typeof formFilter?.controlValues?.sortAscending === 'boolean' ||
typeof filterToEdit?.controlValues?.sortAscending === 'boolean';
Expand All @@ -568,6 +579,17 @@ const FiltersConfigForm = (
forceUpdate();
};

const onEnableSingleValueChanged = (value: SingleValueType | undefined) => {
const previous = form.getFieldValue('filters')?.[filterId].controlValues;
setNativeFilterFieldValues(form, filterId, {
controlValues: {
...previous,
enableSingleValue: value,
},
});
forceUpdate();
};

const validatePreFilter = () =>
setTimeout(
() =>
Expand Down Expand Up @@ -669,12 +691,13 @@ const FiltersConfigForm = (
]);

useEffect(() => {
// Run only once when the control items are available
if (isActive && !isEmpty(controlItems)) {
// Run only once
if (isActive) {
const hasCheckedAdvancedControl =
hasParentFilter ||
hasPreFilter ||
hasSorting ||
hasEnableSingleValue ||
Object.keys(controlItems)
.filter(key => !BASIC_CONTROL_ITEMS.includes(key))
.some(key => controlItems[key].checked);
Expand Down Expand Up @@ -1137,7 +1160,7 @@ const FiltersConfigForm = (
</CollapsibleControl>
</CleanFormItem>
)}
{formFilter?.filterType !== 'filter_range' && (
{formFilter?.filterType !== 'filter_range' ? (
<CleanFormItem name={['filters', filterId, 'sortFilter']}>
<CollapsibleControl
initialValue={hasSorting}
Expand Down Expand Up @@ -1204,6 +1227,48 @@ const FiltersConfigForm = (
)}
</CollapsibleControl>
</CleanFormItem>
) : (
<CleanFormItem name={['filters', filterId, 'rangeFilter']}>
<CollapsibleControl
initialValue={hasEnableSingleValue}
title={t('Single Value')}
onChange={checked => {
onEnableSingleValueChanged(
checked ? SingleValueType.Exact : undefined,
);
formChanged();
}}
>
<StyledRowFormItem
name={[
'filters',
filterId,
'controlValues',
'enableSingleValue',
]}
initialValue={enableSingleValue}
label={
<StyledLabel>{t('Single value type')}</StyledLabel>
}
>
<Radio.Group
onChange={value =>
onEnableSingleValueChanged(value.target.value)
}
>
<Radio value={SingleValueType.Minimum}>
{t('Minimum')}
</Radio>
<Radio value={SingleValueType.Exact}>
{t('Exact')}
</Radio>
<Radio value={SingleValueType.Maximum}>
{t('Maximum')}
</Radio>
</Radio.Group>
</StyledRowFormItem>
</CollapsibleControl>
</CleanFormItem>
)}
</Collapse.Panel>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,16 @@ test('Should render null empty when "getControlItems" return []', () => {
expect(container.children).toHaveLength(0);
});

test('Should render null empty when "getControlItems" return enableSingleValue', () => {
const props = createProps();
(getControlItems as jest.Mock).mockReturnValue([
{ name: 'enableSingleValue', config: { renderTrigger: true } },
]);
const controlItemsMap = getControlItemsMap(props);
const { container } = renderControlItems(controlItemsMap);
expect(container.children).toHaveLength(0);
});

test('Should render null empty when "controlItems" are falsy', () => {
const props = createProps();
const controlItems = [null, false, {}, { config: { renderTrigger: false } }];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ export default function getControlItemsMap({
.filter(
(controlItem: CustomControlItem) =>
controlItem?.config?.renderTrigger &&
controlItem.name !== 'sortAscending',
controlItem.name !== 'sortAscending' &&
controlItem.name !== 'enableSingleValue',
)
.forEach(controlItem => {
const initialValue =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { AppSection, GenericDataType } from '@superset-ui/core';
import React from 'react';
import { render } from 'spec/helpers/testing-library';
import RangeFilterPlugin from './RangeFilterPlugin';
import { SingleValueType } from './SingleValueType';
import transformProps from './transformProps';

const rangeProps = {
Expand Down Expand Up @@ -118,4 +119,61 @@ describe('RangeFilterPlugin', () => {
},
});
});

it('should call setDataMask with correct greater than filter', () => {
getWrapper({ enableSingleValue: SingleValueType.Minimum });
expect(setDataMask).toHaveBeenCalledWith({
extraFormData: {
filters: [
{
col: 'SP_POP_TOTL',
op: '>=',
val: 70,
},
],
},
filterState: {
label: 'x ≥ 70',
value: [70, 100],
},
});
});

it('should call setDataMask with correct less than filter', () => {
getWrapper({ enableSingleValue: SingleValueType.Maximum });
expect(setDataMask).toHaveBeenCalledWith({
extraFormData: {
filters: [
{
col: 'SP_POP_TOTL',
op: '<=',
val: 70,
},
],
},
filterState: {
label: 'x ≤ 70',
value: [10, 70],
},
});
});

it('should call setDataMask with correct exact filter', () => {
getWrapper({ enableSingleValue: SingleValueType.Exact });
expect(setDataMask).toHaveBeenCalledWith({
extraFormData: {
filters: [
{
col: 'SP_POP_TOTL',
op: '==',
val: 10,
},
],
},
filterState: {
label: 'x = 10',
value: [10, 10],
},
});
});
});
Loading

0 comments on commit 54b56fe

Please sign in to comment.