/** * Copyright 2018-present Facebook. * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * @format */ import {Filter} from '../filter/types'; import ManagedTable, {ManagedTableProps} from '../table/ManagedTable'; import {TableBodyRow} from '../table/types'; import Searchable, {SearchableProps} from './Searchable'; import React, {PureComponent} from 'react'; import textContent from '../../../utils/textContent'; import deepEqual from 'deep-equal'; type Props = { /** Reference to the table */ innerRef?: (ref: React.RefObject) => void; /** Filters that are added to the filterbar by default */ defaultFilters: Array; } & ManagedTableProps & SearchableProps; type State = { filterRows: (row: TableBodyRow) => boolean; }; const rowMatchesFilters = (filters: Array, row: TableBodyRow) => filters .map((filter: Filter) => { if (filter.type === 'enum' && row.type != null) { return filter.value.length === 0 || filter.value.indexOf(row.type) > -1; } else if (filter.type === 'include') { return ( textContent(row.columns[filter.key].value).toLowerCase() === filter.value.toLowerCase() ); } else if (filter.type === 'exclude') { return ( textContent(row.columns[filter.key].value).toLowerCase() !== filter.value.toLowerCase() ); } else { return true; } }) .every(x => x === true); function rowMatchesRegex(values: Array, regex: string): boolean { try { const re = new RegExp(regex); return values.some(x => re.test(x)); } catch (e) { return false; } } function rowMatchesSearchTerm( searchTerm: string, isRegex: boolean, row: TableBodyRow, ): boolean { if (searchTerm == null || searchTerm.length === 0) { return true; } const rowValues = Object.keys(row.columns).map(key => textContent(row.columns[key].value), ); if (isRegex) { return rowMatchesRegex(rowValues, searchTerm); } return rowValues.some(x => x.toLowerCase().includes(searchTerm.toLowerCase()), ); } const filterRowsFactory = ( filters: Array, searchTerm: string, regexSearch: boolean, ) => (row: TableBodyRow): boolean => rowMatchesFilters(filters, row) && rowMatchesSearchTerm(searchTerm, regexSearch, row); class SearchableManagedTable extends PureComponent { static defaultProps = { defaultFilters: [], }; state = { filterRows: filterRowsFactory( this.props.filters, this.props.searchTerm, this.props.regexEnabled || false, ), }; componentDidMount() { this.props.defaultFilters.map(this.props.addFilter); } componentWillReceiveProps(nextProps: Props) { if ( nextProps.searchTerm !== this.props.searchTerm || nextProps.regexEnabled != this.props.regexEnabled || !deepEqual(this.props.filters, nextProps.filters) ) { this.setState({ filterRows: filterRowsFactory( nextProps.filters, nextProps.searchTerm, nextProps.regexEnabled || false, ), }); } } render() { const { addFilter, searchTerm: _searchTerm, filters: _filters, innerRef, rows, ...props } = this.props; return ( ); } } /** * Table with filter and searchbar, supports all properties a ManagedTable * and Searchable supports. */ export default Searchable(SearchableManagedTable);