implement free-form search on name and description columns

This commit is contained in:
Collin M. Barrett 2019-09-02 11:34:55 -05:00
parent e33e2f16fa
commit f1913fa6e2
3 changed files with 73 additions and 1 deletions

View file

@ -2,7 +2,7 @@ import { Table } from 'antd';
import React from 'react';
import { RouteComponentProps } from 'react-router';
import { useTablePageSizer } from '../../hooks';
import { useSearchColumnFilter, useTablePageSizer } from '../../hooks';
import { Language } from '../../interfaces/Language';
import { License } from '../../interfaces/License';
import { List } from '../../interfaces/List';
@ -28,6 +28,8 @@ interface Props {
export const ListsTable = (props: RouteComponentProps & Props) => {
const { lists, languages, licenses, software, tags, ...routeComponentProps } = props;
const tablePageSize = useTablePageSizer();
const searchNameColumn = useSearchColumnFilter<List>(nameof<List>("name"));
const searchDescriptionColumn = useSearchColumnFilter<List>(nameof<List>("description"));
return (
<Table<List>
dataSource={lists}
@ -56,6 +58,9 @@ export const ListsTable = (props: RouteComponentProps & Props) => {
width={tablePageSize.isNarrowWindow ? undefined : 200}
className={styles.nogrow}
fixed="left"
filterDropdown={searchNameColumn.filterDropdown}
filterIcon={searchNameColumn.filterIcon}
onFilter={searchNameColumn.onFilter}
render={(name: string) =>
<div>{name}</div>} />
{tablePageSize.isNarrowWindow
@ -64,6 +69,9 @@ export const ListsTable = (props: RouteComponentProps & Props) => {
title="Description"
dataIndex={nameof<List>("description")}
className={styles.nogrow}
filterDropdown={searchDescriptionColumn.filterDropdown}
filterIcon={searchDescriptionColumn.filterIcon}
onFilter={searchDescriptionColumn.onFilter}
render={(description: string, list: List) =>
<Description
description={description}

View file

@ -1,6 +1,7 @@
import { useLanguages } from './useLanguages';
import { useLicenses } from './useLicenses';
import { useLists } from './useLists';
import { useSearchColumnFilter } from './useSearchColumnFilter';
import { useSoftware } from './useSoftware';
import { useSyntaxes } from './useSyntaxes';
import { useTablePageSizer } from './useTablePageSizer';
@ -10,6 +11,7 @@ export {
useLanguages,
useLicenses,
useLists,
useSearchColumnFilter,
useSoftware,
useSyntaxes,
useTablePageSizer,

View file

@ -0,0 +1,62 @@
import { Button, Icon, Input } from 'antd';
import { FilterDropdownProps } from 'antd/lib/table';
import React, { useEffect, useState } from 'react';
interface FilterPropsState<T> {
filterDropdown?: React.ReactNode | ((props: FilterDropdownProps) => React.ReactNode);
filterIcon?: React.ReactNode | ((filtered: boolean) => React.ReactNode);
onFilter?: (value: any, record: T) => boolean;
}
export const useSearchColumnFilter = <T extends {}>(dataIndex: string) => {
const [filterProps, setFilterProps] = useState<FilterPropsState<T>>({
filterDropdown: undefined,
filterIcon: undefined,
onFilter: undefined
});
useEffect(() => {
const handleSearch = (confirm?: () => void) => {
confirm && confirm();
};
const handleReset = (clearFilters?: (selectedKeys: string[]) => void) => {
clearFilters && clearFilters([]);
};
setFilterProps({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
placeholder={`Search ${dataIndex}`}
value={selectedKeys && selectedKeys[0]}
onChange={e => setSelectedKeys && setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => handleSearch(confirm)}
style={{ width: 188, marginBottom: 8, display: 'block' }} />
<Button
type="primary"
onClick={() => handleSearch(confirm)}
icon="search"
size="small"
style={{ width: 90, marginRight: 8 }} >
Search
</Button>
<Button
onClick={() => handleReset(clearFilters)}
size="small"
style={{ width: 90 }}>
Reset
</Button>
</div>
),
filterIcon: filtered => (
<Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />
),
onFilter: (value, record) => {
const searchValue = (record as any)[dataIndex];
return searchValue && searchValue
.toString()
.toLowerCase()
.includes(value.toLowerCase())
}
})
}, [dataIndex]);
return filterProps;
};