fix: adds pagination/infinite scroll to owners select in DashboardList and ChartList (#10035)

This commit is contained in:
ʈᵃᵢ 2020-06-17 16:27:21 -07:00 committed by GitHub
parent be6b9b8fec
commit c914af0bc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 14 deletions

View File

@ -7630,6 +7630,11 @@
"resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-0.1.5.tgz",
"integrity": "sha512-Fx6atDc7JM1r0WkPCDhNetVZNp+DO21q/HGlomAKBG+k8vb1B8fg8Yige4oCf1P9OWTZWm5tM5i3jlXhrSbNOg=="
},
"@seznam/compose-react-refs": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@seznam/compose-react-refs/-/compose-react-refs-1.0.4.tgz",
"integrity": "sha512-TwrojUAFVSd+HPAdnul0o65X8mIam+dJOxcWI6LhHAUIpVRk2cJp2dyWXWl6sJvZTY9ODSJpOibt7JKSNUjVfQ=="
},
"@sinonjs/commons": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz",
@ -27381,6 +27386,11 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.3.tgz",
"integrity": "sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA=="
},
"react-is-mounted-hook": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/react-is-mounted-hook/-/react-is-mounted-hook-1.0.3.tgz",
"integrity": "sha512-YCCYcTVYMPfTi6WhWIwM9EYBcpHoivjjkE90O5ScsE9wXSbeXGZvLDMGt4mdSNcWshhc8JD0AzgBmsleCSdSFA=="
},
"react-json-tree": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/react-json-tree/-/react-json-tree-0.11.2.tgz",
@ -27737,6 +27747,32 @@
}
}
},
"react-select-async-paginate": {
"version": "0.4.0-alpha.1",
"resolved": "https://registry.npmjs.org/react-select-async-paginate/-/react-select-async-paginate-0.4.0-alpha.1.tgz",
"integrity": "sha512-086CF1dP69m9jwlGne+YLA0lk6jz21510hwKWmOBClr0zeYceMerXUcxXZvwr0wwroDo444ub1clkcblP88OQg==",
"requires": {
"@babel/runtime": "^7.9.6",
"@seznam/compose-react-refs": "^1.0.4",
"react-is-mounted-hook": "^1.0.3",
"sleep-promise": "^8.0.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.10.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.2.tgz",
"integrity": "sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"regenerator-runtime": {
"version": "0.13.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
}
}
},
"react-select-fast-filter-options": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/react-select-fast-filter-options/-/react-select-fast-filter-options-0.2.3.tgz",
@ -29368,6 +29404,11 @@
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
"dev": true
},
"sleep-promise": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/sleep-promise/-/sleep-promise-8.0.1.tgz",
"integrity": "sha1-jXlaJ+ojlT32tSuRCB5eImZZk8U="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",

View File

@ -159,6 +159,7 @@
"react-router-dom": "^5.1.2",
"react-search-input": "^0.11.3",
"react-select": "^3.1.0",
"react-select-async-paginate": "^0.4.0-alpha.1",
"react-select-fast-filter-options": "^0.2.1",
"react-sortable-hoc": "^1.11.0",
"react-split": "^2.0.4",

View File

@ -329,6 +329,7 @@ describe('ListView with new UI filters', () => {
id: 'age',
input: 'select',
fetchSelects: fetchSelectsMock,
paginate: true,
operator: 'eq',
},
],
@ -347,10 +348,6 @@ 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

View File

@ -22,10 +22,11 @@ import { withTheme } from 'emotion-theming';
import {
Select,
AsyncSelect,
PaginatedSelect,
PartialThemeConfig,
PartialStylesConfig,
} from 'src/components/Select';
import SearchInput from 'src/components/SearchInput';
import {
Filter,
@ -45,6 +46,7 @@ interface SelectFilterProps extends BaseFilter {
selects: Filter['selects'];
emptyLabel?: string;
fetchSelects?: Filter['fetchSelects'];
paginate?: boolean;
}
const FilterContainer = styled.div`
@ -90,6 +92,7 @@ function SelectFilter({
initialValue,
onSelect,
fetchSelects,
paginate = false,
}: SelectFilterProps) {
const clearFilterSelect = {
label: emptyLabel,
@ -106,36 +109,52 @@ function SelectFilter({
);
setSelectedOption(selected);
};
const fetchAndFormatSelects = async (inputValue: string) => {
const fetchAndFormatSelects = async (
inputValue: string,
loadedOptions: SelectOption[],
{ page }: { page: number },
) => {
// only include clear filter when filter value does not exist
let result = inputValue ? [] : [clearFilterSelect];
let result = inputValue || page > 0 ? [] : [clearFilterSelect];
let hasMore = paginate;
if (fetchSelects) {
const selectValues = await fetchSelects(inputValue);
const selectValues = await fetchSelects(inputValue, page);
// update matching option at initial load
const matchingOption = result.find(x => x.value === initialValue);
if (matchingOption) {
setSelectedOption(matchingOption);
}
if (!selectValues.length) {
hasMore = false;
}
result = [...result, ...selectValues];
}
return result;
return {
options: result,
hasMore,
additional: {
page: page + 1,
},
};
};
return (
<FilterContainer>
<FilterTitle>{Header}</FilterTitle>
{fetchSelects ? (
<AsyncSelect
<PaginatedSelect
data-test="filters-select"
themeConfig={filterSelectTheme}
stylesConfig={filterSelectStyles}
value={selectedOption}
onChange={onChange}
loadOptions={fetchAndFormatSelects}
defaultOptions
placeholder={emptyLabel}
loadingMessage={() => 'Loading...'}
clearable={false}
additional={{
page: 0,
}}
/>
) : (
<Select
@ -200,7 +219,15 @@ function UIFilters({
<FilterWrapper>
{filters.map(
(
{ Header, id, input, selects, unfilteredLabel, fetchSelects },
{
Header,
id,
input,
selects,
unfilteredLabel,
fetchSelects,
paginate,
},
index,
) => {
const initialValue =
@ -215,6 +242,7 @@ function UIFilters({
emptyLabel={unfilteredLabel}
initialValue={initialValue}
fetchSelects={fetchSelects}
paginate={paginate}
onSelect={(value: any) => updateFilterValue(index, value)}
/>
);

View File

@ -41,8 +41,8 @@ interface Props {
initialSort?: SortColumn[];
filters?: Filters;
bulkActions?: Array<{
key?: string;
name: React.ReactNode;
key: string;
name: React.ReactNode | string;
onSelect: (rows: any[]) => any;
}>;
useNewUIFilters?: boolean;

View File

@ -42,6 +42,7 @@ export interface Filter {
pageIndex?: number,
pageSize?: number,
) => Promise<SelectOption[]>;
paginate?: boolean;
}
export type Filters = Filter[];

View File

@ -30,6 +30,7 @@ import BasicSelect, {
import Async from 'react-select/async';
import Creatable from 'react-select/creatable';
import AsyncCreatable from 'react-select/async-creatable';
import { withAsyncPaginate } from 'react-select-async-paginate';
import { SelectComponents } from 'react-select/src/components';
import {
@ -286,4 +287,7 @@ export const Select = styled(WindowedSelect);
export const AsyncSelect = styled(WindowedAsyncSelect);
export const CreatableSelect = styled(WindowedCreatableSelect);
export const AsyncCreatableSelect = styled(WindowedAsyncCreatableSelect);
// Wrap with async pagination (infinite scroll). Cannot use windowed since options are appended dynamically which causes focus jumping
// @ts-ignore
export const PaginatedSelect = withAsyncPaginate(styled(BasicSelect));
export default Select;

View File

@ -434,6 +434,7 @@ class ChartList extends React.PureComponent<Props, State> {
operator: 'rel_m_m',
unfilteredLabel: 'All',
fetchSelects: this.fetchOwners,
paginate: true,
},
{
Header: 'Viz Type',
@ -452,6 +453,7 @@ class ChartList extends React.PureComponent<Props, State> {
operator: 'eq',
unfilteredLabel: 'All',
fetchSelects: this.fetchDatasets,
paginate: false,
},
{
Header: 'Search',

View File

@ -437,6 +437,7 @@ class DashboardList extends React.PureComponent<Props, State> {
operator: 'rel_m_m',
unfilteredLabel: 'All',
fetchSelects: this.fetchOwners,
paginate: true,
},
{
Header: 'Published',