Skip to content

Commit

Permalink
better filter lists and async filter functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
nytai committed Apr 21, 2020
1 parent 557b28a commit 05774b1
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 179 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const mockedProps = {
Header: 'ID',
sortable: true,
},
{
accessor: 'age',
Header: 'Age',
},
{
accessor: 'name',
Header: 'Name',
Expand Down Expand Up @@ -287,6 +291,7 @@ Array [
});

describe('ListView with new UI filters', () => {
const fetchSelectsMock = jest.fn(() => []);
const newFiltersProps = {
...mockedProps,
useNewUIFilters: true,
Expand All @@ -304,6 +309,13 @@ describe('ListView with new UI filters', () => {
input: 'search',
operator: 'ct',
},
{
Header: 'Age',
id: 'age',
input: 'select',
fetchSelects: fetchSelectsMock,
operator: 'eq',
},
],
};

Expand All @@ -320,19 +332,23 @@ describe('ListView with new UI filters', () => {
expect(wrapper.find(ListViewFilters)).toHaveLength(1);
});

it('fetched selects if function is provided', () => {
expect(fetchSelectsMock).toHaveBeenCalled();
});

it('calls fetchData on filter', () => {
act(() => {
wrapper
.find('[data-test="filters-select"]')
.last()
.first()
.props()
.onChange({ value: 'bar' });
});

act(() => {
wrapper
.find('[data-test="filters-search"]')
.last()
.first()
.props()
.onChange({ currentTarget: { value: 'something' } });
});
Expand All @@ -348,42 +364,42 @@ describe('ListView with new UI filters', () => {
});

expect(newFiltersProps.fetchData.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
"filters": Array [
Object {
"id": "id",
"operator": "eq",
"value": "bar",
},
],
"pageIndex": 0,
"pageSize": 1,
"sortBy": Array [],
},
]
`);
Array [
Object {
"filters": Array [
Object {
"id": "id",
"operator": "eq",
"value": "bar",
},
],
"pageIndex": 0,
"pageSize": 1,
"sortBy": Array [],
},
]
`);

expect(newFiltersProps.fetchData.mock.calls[1]).toMatchInlineSnapshot(`
Array [
Object {
"filters": Array [
Object {
"id": "id",
"operator": "eq",
"value": "bar",
},
Object {
"id": "name",
"operator": "ct",
"value": "something",
},
],
"pageIndex": 0,
"pageSize": 1,
"sortBy": Array [],
},
]
`);
Array [
Object {
"filters": Array [
Object {
"id": "id",
"operator": "eq",
"value": "bar",
},
Object {
"id": "name",
"operator": "ct",
"value": "something",
},
],
"pageIndex": 0,
"pageSize": 1,
"sortBy": Array [],
},
]
`);
});
});
93 changes: 58 additions & 35 deletions superset-frontend/src/components/ListView/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import React, { useState } from 'react';
import styled from '@emotion/styled';
import { withTheme } from 'emotion-theming';

import StyledSelect from 'src/components/StyledSelect';
import StyledSelect, { AsyncStyledSelect } from 'src/components/StyledSelect';
import SearchInput from 'src/components/SearchInput';
import { Filter, Filters, FilterValue, InternalFilter } from './types';

Expand All @@ -32,6 +32,7 @@ interface SelectFilterProps extends BaseFilter {
onSelect: (selected: any) => any;
selects: Filter['selects'];
emptyLabel?: string;
fetchSelects?: Filter['fetchSelects'];
}

const FilterContainer = styled.div`
Expand All @@ -51,11 +52,13 @@ function SelectFilter({
emptyLabel = 'None',
initialValue,
onSelect,
fetchSelects,
}: SelectFilterProps) {
const clearFilterSelect = {
label: emptyLabel,
value: CLEAR_SELECT_FILTER_VALUE,
};

const options = React.useMemo(() => [clearFilterSelect, ...selects], [
emptyLabel,
selects,
Expand All @@ -73,17 +76,34 @@ function SelectFilter({
selected.value === CLEAR_SELECT_FILTER_VALUE ? undefined : selected.value,
);
};
const fetchAndFormatSelects = async () => {
if (!fetchSelects) return { options: [clearFilterSelect] };
const selectValues = await fetchSelects();
return { options: [clearFilterSelect, ...selectValues] };
};

return (
<FilterContainer>
<Title>{Header}:</Title>
<StyledSelect
data-test="filters-select"
value={value}
options={options}
onChange={onChange}
clearable={false}
/>
{fetchSelects ? (
<AsyncStyledSelect
data-test="filters-select"
value={value}
onChange={onChange}
loadOptions={fetchAndFormatSelects}
placeholder={initialValue || emptyLabel}
loadingPlaceholder="Loading..."
clearable={false}
/>
) : (
<StyledSelect
data-test="filters-select"
value={value}
options={options}
onChange={onChange}
clearable={false}
/>
)}
</FilterContainer>
);
}
Expand Down Expand Up @@ -134,33 +154,36 @@ function UIFilters({
}: UIFiltersProps) {
return (
<FilterWrapper>
{filters.map(({ Header, input, selects, unfilteredLabel }, index) => {
const initialValue =
internalFilters[index] && internalFilters[index].value;
if (input === 'select') {
return (
<SelectFilter
key={Header}
Header={Header}
selects={selects}
emptyLabel={unfilteredLabel}
initialValue={initialValue}
onSelect={(value: any) => updateFilterValue(index, value)}
/>
);
}
if (input === 'search') {
return (
<SearchFilter
key={Header}
Header={Header}
initialValue={initialValue}
onSubmit={(value: string) => updateFilterValue(index, value)}
/>
);
}
return null;
})}
{filters.map(
({ Header, input, selects, unfilteredLabel, fetchSelects }, index) => {
const initialValue =
internalFilters[index] && internalFilters[index].value;
if (input === 'select') {
return (
<SelectFilter
key={Header}
Header={Header}
selects={selects}
emptyLabel={unfilteredLabel}
initialValue={initialValue}
fetchSelects={fetchSelects}
onSelect={(value: any) => updateFilterValue(index, value)}
/>
);
}
if (input === 'search') {
return (
<SearchFilter
key={Header}
Header={Header}
initialValue={initialValue}
onSubmit={(value: string) => updateFilterValue(index, value)}
/>
);
}
return null;
},
)}
</FilterWrapper>
);
}
Expand Down
2 changes: 2 additions & 0 deletions superset-frontend/src/components/ListView/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export interface Filter {
input?: 'text' | 'textarea' | 'select' | 'checkbox' | 'search';
unfilteredLabel?: string;
selects?: Select[];
onFilterOpen?: () => void;
fetchSelects?: () => Promise<Select[]>;
}

export type Filters = Filter[];
Expand Down
29 changes: 28 additions & 1 deletion superset-frontend/src/components/StyledSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
import styled from '@emotion/styled';
// @ts-ignore
import Select from 'react-select';
import Select, { Async } from 'react-select';

export default styled(Select)`
display: inline;
Expand Down Expand Up @@ -46,3 +46,30 @@ export default styled(Select)`
border-bottom-left-radius: 0;
}
`;

export const AsyncStyledSelect = styled(Async)`
display: inline;
&.is-focused:not(.is-open) > .Select-control {
border: none;
box-shadow: none;
}
.Select-control {
display: inline-table;
border: none;
width: 100px;
&:focus,
&:hover {
border: none;
box-shadow: none;
}
.Select-arrow-zone {
padding-left: 10px;
}
}
.Select-menu-outer {
margin-top: 0;
border-bottom-left-radius: 0;
border-bottom-left-radius: 0;
}
`;
Loading

0 comments on commit 05774b1

Please sign in to comment.