Searchable
Summary: _typescript_ Reviewed By: passy Differential Revision: D16807182 fbshipit-source-id: 68bc8365bc5b0d8075d0a93d5963c824c0d66769
This commit is contained in:
committed by
Facebook Github Bot
parent
c8c90ee413
commit
62a204bdbe
@@ -51,8 +51,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@jest-runner/electron": "^2.0.1",
|
"@jest-runner/electron": "^2.0.1",
|
||||||
|
"@types/deep-equal": "^1.0.1",
|
||||||
"@types/invariant": "^2.2.30",
|
"@types/invariant": "^2.2.30",
|
||||||
"@types/jest": "^24.0.16",
|
"@types/jest": "^24.0.16",
|
||||||
|
"@types/lodash.debounce": "^4.0.6",
|
||||||
"@types/react": "^16.8.24",
|
"@types/react": "^16.8.24",
|
||||||
"@types/react-dom": "^16.8.5",
|
"@types/react-dom": "^16.8.5",
|
||||||
"@types/react-redux": "^7.1.1",
|
"@types/react-redux": "^7.1.1",
|
||||||
|
|||||||
@@ -157,15 +157,15 @@ export {
|
|||||||
SearchBox,
|
SearchBox,
|
||||||
SearchInput,
|
SearchInput,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
|
SearchableProps,
|
||||||
default as Searchable,
|
default as Searchable,
|
||||||
} from './ui/components/searchable/Searchable.js';
|
} from './ui/components/searchable/Searchable.tsx';
|
||||||
export {
|
export {
|
||||||
default as SearchableTable,
|
default as SearchableTable,
|
||||||
} from './ui/components/searchable/SearchableTable.js';
|
} from './ui/components/searchable/SearchableTable.tsx';
|
||||||
export {
|
export {
|
||||||
default as SearchableTable_immutable,
|
default as SearchableTable_immutable,
|
||||||
} from './ui/components/searchable/SearchableTable_immutable.js';
|
} from './ui/components/searchable/SearchableTable_immutable.tsx';
|
||||||
export {SearchableProps} from './ui/components/searchable/Searchable.js';
|
|
||||||
export {
|
export {
|
||||||
ElementID,
|
ElementID,
|
||||||
ElementData,
|
ElementData,
|
||||||
|
|||||||
@@ -5,53 +5,59 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Filter} from 'flipper';
|
import {Filter} from '../filter/types';
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import Text from '../Text.tsx';
|
import Text from '../Text';
|
||||||
import styled from '../../styled/index.js';
|
import styled from 'react-emotion';
|
||||||
import {findDOMNode} from 'react-dom';
|
import {findDOMNode} from 'react-dom';
|
||||||
import {colors} from '../colors.tsx';
|
import {colors} from '../colors';
|
||||||
import electron from 'electron';
|
import electron, {MenuItemConstructorOptions} from 'electron';
|
||||||
|
import React from 'react';
|
||||||
|
import {ColorProperty} from 'csstype';
|
||||||
|
|
||||||
const Token = styled(Text)(props => ({
|
const Token = styled(Text)(
|
||||||
display: 'inline-flex',
|
(props: {focused?: boolean; color?: ColorProperty}) => ({
|
||||||
alignItems: 'center',
|
display: 'inline-flex',
|
||||||
backgroundColor: props.focused
|
alignItems: 'center',
|
||||||
? colors.macOSHighlightActive
|
backgroundColor: props.focused
|
||||||
: props.color || colors.macOSHighlight,
|
? colors.macOSHighlightActive
|
||||||
borderRadius: 4,
|
: props.color || colors.macOSHighlight,
|
||||||
marginRight: 4,
|
borderRadius: 4,
|
||||||
padding: 4,
|
marginRight: 4,
|
||||||
paddingLeft: 6,
|
padding: 4,
|
||||||
height: 21,
|
paddingLeft: 6,
|
||||||
color: props.focused ? 'white' : 'inherit',
|
height: 21,
|
||||||
'&:active': {
|
color: props.focused ? 'white' : 'inherit',
|
||||||
backgroundColor: colors.macOSHighlightActive,
|
'&:active': {
|
||||||
color: colors.white,
|
backgroundColor: colors.macOSHighlightActive,
|
||||||
},
|
color: colors.white,
|
||||||
'&:first-of-type': {
|
},
|
||||||
marginLeft: 3,
|
'&:first-of-type': {
|
||||||
},
|
marginLeft: 3,
|
||||||
}));
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const Key = styled(Text)(props => ({
|
const Key = styled(Text)(
|
||||||
position: 'relative',
|
(props: {type: 'exclude' | 'include' | 'enum'; focused?: boolean}) => ({
|
||||||
fontWeight: 500,
|
position: 'relative',
|
||||||
paddingRight: 12,
|
fontWeight: 500,
|
||||||
textTransform: 'capitalize',
|
paddingRight: 12,
|
||||||
lineHeight: '21px',
|
textTransform: 'capitalize',
|
||||||
'&:after': {
|
lineHeight: '21px',
|
||||||
content: props.type === 'exclude' ? '"≠"' : '"="',
|
'&:after': {
|
||||||
paddingLeft: 5,
|
content: props.type === 'exclude' ? '"≠"' : '"="',
|
||||||
position: 'absolute',
|
paddingLeft: 5,
|
||||||
top: -1,
|
position: 'absolute',
|
||||||
right: 0,
|
top: -1,
|
||||||
fontSize: 14,
|
right: 0,
|
||||||
},
|
fontSize: 14,
|
||||||
'&:active:after': {
|
},
|
||||||
backgroundColor: colors.macOSHighlightActive,
|
'&:active:after': {
|
||||||
},
|
backgroundColor: colors.macOSHighlightActive,
|
||||||
}));
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const Value = styled(Text)({
|
const Value = styled(Text)({
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
@@ -62,7 +68,7 @@ const Value = styled(Text)({
|
|||||||
paddingLeft: 3,
|
paddingLeft: 3,
|
||||||
});
|
});
|
||||||
|
|
||||||
const Chevron = styled('div')(props => ({
|
const Chevron = styled('div')((props: {focused?: boolean}) => ({
|
||||||
border: 0,
|
border: 0,
|
||||||
paddingLeft: 3,
|
paddingLeft: 3,
|
||||||
paddingRight: 1,
|
paddingRight: 1,
|
||||||
@@ -81,23 +87,24 @@ const Chevron = styled('div')(props => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
type Props = {|
|
type Props = {
|
||||||
filter: Filter,
|
filter: Filter;
|
||||||
focused: boolean,
|
focused: boolean;
|
||||||
index: number,
|
index: number;
|
||||||
onFocus: (focusedToken: number) => void,
|
onFocus: (focusedToken: number) => void;
|
||||||
onBlur: () => void,
|
onBlur: () => void;
|
||||||
onDelete: (deletedToken: number) => void,
|
onDelete: (deletedToken: number) => void;
|
||||||
onReplace: (index: number, filter: Filter) => void,
|
onReplace: (index: number, filter: Filter) => void;
|
||||||
|};
|
};
|
||||||
|
|
||||||
export default class FilterToken extends PureComponent<Props> {
|
export default class FilterToken extends PureComponent<Props> {
|
||||||
_ref: ?Element;
|
_ref: Element | undefined;
|
||||||
|
|
||||||
onMouseDown = () => {
|
onMouseDown = () => {
|
||||||
if (
|
if (
|
||||||
this.props.filter.persistent == null ||
|
this.props.filter.type !== 'enum' ||
|
||||||
this.props.filter.persistent === false
|
(this.props.filter.persistent == null ||
|
||||||
|
this.props.filter.persistent === false)
|
||||||
) {
|
) {
|
||||||
this.props.onFocus(this.props.index);
|
this.props.onFocus(this.props.index);
|
||||||
}
|
}
|
||||||
@@ -112,7 +119,7 @@ export default class FilterToken extends PureComponent<Props> {
|
|||||||
...this.props.filter.enum.map(({value, label}) => ({
|
...this.props.filter.enum.map(({value, label}) => ({
|
||||||
label,
|
label,
|
||||||
click: () => this.changeEnum(value),
|
click: () => this.changeEnum(value),
|
||||||
type: 'checkbox',
|
type: 'checkbox' as 'checkbox',
|
||||||
checked: this.props.filter.value.indexOf(value) > -1,
|
checked: this.props.filter.value.indexOf(value) > -1,
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
@@ -144,12 +151,14 @@ export default class FilterToken extends PureComponent<Props> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const menu = electron.remote.Menu.buildFromTemplate(menuTemplate);
|
const menu = electron.remote.Menu.buildFromTemplate(menuTemplate);
|
||||||
const {bottom, left} = this._ref ? this._ref.getBoundingClientRect() : {};
|
const {bottom, left} = this._ref.getBoundingClientRect();
|
||||||
|
|
||||||
menu.popup({
|
menu.popup({
|
||||||
window: electron.remote.getCurrentWindow(),
|
window: electron.remote.getCurrentWindow(),
|
||||||
|
// @ts-ignore: async is private API
|
||||||
async: true,
|
async: true,
|
||||||
x: parseInt(left, 10),
|
x: left,
|
||||||
y: parseInt(bottom, 10) + 8,
|
y: bottom + 8,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -185,7 +194,7 @@ export default class FilterToken extends PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setRef = (ref: React.ElementRef<*>) => {
|
setRef = (ref: React.ReactInstance) => {
|
||||||
const element = findDOMNode(ref);
|
const element = findDOMNode(ref);
|
||||||
if (element instanceof HTMLElement) {
|
if (element instanceof HTMLElement) {
|
||||||
this._ref = element;
|
this._ref = element;
|
||||||
@@ -5,20 +5,21 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Filter} from 'flipper';
|
import {Filter} from '../filter/types';
|
||||||
import type {TableColumns} from '../table/types';
|
import {TableColumns} from '../table/types';
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import Toolbar from '../Toolbar.tsx';
|
import Toolbar from '../Toolbar';
|
||||||
import FlexRow from '../FlexRow.tsx';
|
import FlexRow from '../FlexRow';
|
||||||
import Input from '../Input.tsx';
|
import Input from '../Input';
|
||||||
import {colors} from '../colors.tsx';
|
import {colors} from '../colors';
|
||||||
import Text from '../Text.tsx';
|
import Text from '../Text';
|
||||||
import FlexBox from '../FlexBox.tsx';
|
import FlexBox from '../FlexBox';
|
||||||
import Glyph from '../Glyph.tsx';
|
import Glyph from '../Glyph';
|
||||||
import FilterToken from './FilterToken.js';
|
import FilterToken from './FilterToken';
|
||||||
import styled from '../../styled/index.js';
|
import styled from 'react-emotion';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
import ToggleSwitch from '../ToggleSwitch.tsx';
|
import ToggleSwitch from '../ToggleSwitch';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
const SearchBar = styled(Toolbar)({
|
const SearchBar = styled(Toolbar)({
|
||||||
height: 42,
|
height: 42,
|
||||||
@@ -35,22 +36,24 @@ export const SearchBox = styled(FlexBox)({
|
|||||||
paddingLeft: 4,
|
paddingLeft: 4,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const SearchInput = styled(Input)(props => ({
|
export const SearchInput = styled(Input)(
|
||||||
border: props.focus ? '1px solid black' : 0,
|
(props: {focus?: boolean; regex?: boolean; isValidInput?: boolean}) => ({
|
||||||
...(props.regex ? {fontFamily: 'monospace'} : {}),
|
border: props.focus ? '1px solid black' : 0,
|
||||||
padding: 0,
|
...(props.regex ? {fontFamily: 'monospace'} : {}),
|
||||||
fontSize: '1em',
|
padding: 0,
|
||||||
flexGrow: 1,
|
fontSize: '1em',
|
||||||
height: 'auto',
|
flexGrow: 1,
|
||||||
lineHeight: '100%',
|
height: 'auto',
|
||||||
marginLeft: 2,
|
lineHeight: '100%',
|
||||||
width: '100%',
|
marginLeft: 2,
|
||||||
color: props.regex && !props.isValidInput ? colors.red : colors.black,
|
width: '100%',
|
||||||
'&::-webkit-input-placeholder': {
|
color: props.regex && !props.isValidInput ? colors.red : colors.black,
|
||||||
color: colors.placeholder,
|
'&::-webkit-input-placeholder': {
|
||||||
fontWeight: 300,
|
color: colors.placeholder,
|
||||||
},
|
fontWeight: 300,
|
||||||
}));
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
const Clear = styled(Text)({
|
const Clear = styled(Text)({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
@@ -83,34 +86,34 @@ const Actions = styled(FlexRow)({
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type SearchableProps = {|
|
export type SearchableProps = {
|
||||||
addFilter: (filter: Filter) => void,
|
addFilter: (filter: Filter) => void;
|
||||||
searchTerm: string,
|
searchTerm: string;
|
||||||
filters: Array<Filter>,
|
filters: Array<Filter>;
|
||||||
allowRegexSearch?: boolean,
|
allowRegexSearch?: boolean;
|
||||||
regexEnabled?: boolean,
|
regexEnabled?: boolean;
|
||||||
|};
|
|
||||||
|
|
||||||
type Props = {|
|
|
||||||
placeholder?: string,
|
|
||||||
actions: React.Node,
|
|
||||||
tableKey: string,
|
|
||||||
columns?: TableColumns,
|
|
||||||
onFilterChange: (filters: Array<Filter>) => void,
|
|
||||||
defaultFilters: Array<Filter>,
|
|
||||||
allowRegexSearch: boolean,
|
|
||||||
|};
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
filters: Array<Filter>,
|
|
||||||
focusedToken: number,
|
|
||||||
searchTerm: string,
|
|
||||||
hasFocus: boolean,
|
|
||||||
regexEnabled: boolean,
|
|
||||||
compiledRegex: ?RegExp,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function compileRegex(s: string): ?RegExp {
|
type Props = {
|
||||||
|
placeholder?: string;
|
||||||
|
actions: React.ReactNode;
|
||||||
|
tableKey: string;
|
||||||
|
columns?: TableColumns;
|
||||||
|
onFilterChange: (filters: Array<Filter>) => void;
|
||||||
|
defaultFilters: Array<Filter>;
|
||||||
|
allowRegexSearch: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type State = {
|
||||||
|
filters: Array<Filter>;
|
||||||
|
focusedToken: number;
|
||||||
|
searchTerm: string;
|
||||||
|
hasFocus: boolean;
|
||||||
|
regexEnabled: boolean;
|
||||||
|
compiledRegex: RegExp | null | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
function compileRegex(s: string): RegExp | null {
|
||||||
try {
|
try {
|
||||||
return new RegExp(s);
|
return new RegExp(s);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -135,7 +138,7 @@ const Searchable = (
|
|||||||
compiledRegex: null,
|
compiledRegex: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
_inputRef: ?HTMLInputElement;
|
_inputRef: HTMLInputElement | undefined;
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
window.document.addEventListener('keydown', this.onKeyDown);
|
window.document.addEventListener('keydown', this.onKeyDown);
|
||||||
@@ -223,7 +226,7 @@ const Searchable = (
|
|||||||
window.document.removeEventListener('keydown', this.onKeyDown);
|
window.document.removeEventListener('keydown', this.onKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTableKey = (): ?string => {
|
getTableKey = (): string | null | undefined => {
|
||||||
if (this.props.tableKey) {
|
if (this.props.tableKey) {
|
||||||
return this.props.tableKey;
|
return this.props.tableKey;
|
||||||
} else if (this.props.columns) {
|
} else if (this.props.columns) {
|
||||||
@@ -238,7 +241,7 @@ const Searchable = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onKeyDown = (e: SyntheticKeyboardEvent<>) => {
|
onKeyDown = (e: KeyboardEvent) => {
|
||||||
const ctrlOrCmd = e =>
|
const ctrlOrCmd = e =>
|
||||||
(e.metaKey && process.platform === 'darwin') ||
|
(e.metaKey && process.platform === 'darwin') ||
|
||||||
(e.ctrlKey && process.platform !== 'darwin');
|
(e.ctrlKey && process.platform !== 'darwin');
|
||||||
@@ -252,11 +255,12 @@ const Searchable = (
|
|||||||
this._inputRef.blur();
|
this._inputRef.blur();
|
||||||
this.setState({searchTerm: ''});
|
this.setState({searchTerm: ''});
|
||||||
} else if (e.key === 'Backspace' && this.hasFocus()) {
|
} else if (e.key === 'Backspace' && this.hasFocus()) {
|
||||||
|
const lastFilter = this.state.filters[this.state.filters.length - 1];
|
||||||
if (
|
if (
|
||||||
this.state.focusedToken === -1 &&
|
this.state.focusedToken === -1 &&
|
||||||
this.state.searchTerm === '' &&
|
this.state.searchTerm === '' &&
|
||||||
this._inputRef &&
|
this._inputRef &&
|
||||||
!this.state.filters[this.state.filters.length - 1].persistent
|
(lastFilter.type !== 'enum' || !lastFilter.persistent)
|
||||||
) {
|
) {
|
||||||
this._inputRef.blur();
|
this._inputRef.blur();
|
||||||
this.setState({focusedToken: this.state.filters.length - 1});
|
this.setState({focusedToken: this.state.filters.length - 1});
|
||||||
@@ -274,7 +278,7 @@ const Searchable = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeSearchTerm = (e: SyntheticInputEvent<HTMLInputElement>) => {
|
onChangeSearchTerm = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
searchTerm: e.target.value,
|
searchTerm: e.target.value,
|
||||||
compiledRegex: compileRegex(e.target.value),
|
compiledRegex: compileRegex(e.target.value),
|
||||||
@@ -291,9 +295,9 @@ const Searchable = (
|
|||||||
match.forEach((filter: string) => {
|
match.forEach((filter: string) => {
|
||||||
const separator =
|
const separator =
|
||||||
filter.indexOf(':') > filter.indexOf('=') ? ':' : '=';
|
filter.indexOf(':') > filter.indexOf('=') ? ':' : '=';
|
||||||
let [key, ...value] = filter.split(separator);
|
let [key, ...values] = filter.split(separator);
|
||||||
value = value.join(separator).trim();
|
let value = values.join(separator).trim();
|
||||||
let type = 'include';
|
let type: 'include' | 'exclude' | 'enum' = 'include';
|
||||||
// if value starts with !, it's an exclude filter
|
// if value starts with !, it's an exclude filter
|
||||||
if (value.indexOf('!') === 0) {
|
if (value.indexOf('!') === 0) {
|
||||||
type = 'exclude';
|
type = 'exclude';
|
||||||
@@ -315,7 +319,7 @@ const Searchable = (
|
|||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
setInputRef = (ref: ?HTMLInputElement) => {
|
setInputRef = (ref: HTMLInputElement | undefined) => {
|
||||||
this._inputRef = ref;
|
this._inputRef = ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -326,12 +330,13 @@ const Searchable = (
|
|||||||
if (filterIndex > -1) {
|
if (filterIndex > -1) {
|
||||||
const filters = [...this.state.filters];
|
const filters = [...this.state.filters];
|
||||||
const defaultFilter: Filter = this.props.defaultFilters[filterIndex];
|
const defaultFilter: Filter = this.props.defaultFilters[filterIndex];
|
||||||
|
const filter = filters[filterIndex];
|
||||||
if (
|
if (
|
||||||
defaultFilter != null &&
|
defaultFilter != null &&
|
||||||
defaultFilter.type === 'enum' &&
|
defaultFilter.type === 'enum' &&
|
||||||
filters[filterIndex].type === 'enum'
|
filter.type === 'enum'
|
||||||
) {
|
) {
|
||||||
filters[filterIndex].enum = defaultFilter.enum;
|
filter.enum = defaultFilter.enum;
|
||||||
}
|
}
|
||||||
this.setState({filters});
|
this.setState({filters});
|
||||||
// filter for this key already exists
|
// filter for this key already exists
|
||||||
@@ -339,7 +344,7 @@ const Searchable = (
|
|||||||
}
|
}
|
||||||
// persistent filters are always at the front
|
// persistent filters are always at the front
|
||||||
const filters =
|
const filters =
|
||||||
filter.persistent === true
|
filter.type === 'enum' && filter.persistent === true
|
||||||
? [filter, ...this.state.filters]
|
? [filter, ...this.state.filters]
|
||||||
: this.state.filters.concat(filter);
|
: this.state.filters.concat(filter);
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -397,14 +402,14 @@ const Searchable = (
|
|||||||
clear = () =>
|
clear = () =>
|
||||||
this.setState({
|
this.setState({
|
||||||
filters: this.state.filters.filter(
|
filters: this.state.filters.filter(
|
||||||
f => f.persistent != null && f.persistent === true,
|
f => f.type === 'enum' && f.persistent === true,
|
||||||
),
|
),
|
||||||
searchTerm: '',
|
searchTerm: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
getPersistKey = () => `SEARCHABLE_STORAGE_KEY_${this.getTableKey() || ''}`;
|
getPersistKey = () => `SEARCHABLE_STORAGE_KEY_${this.getTableKey() || ''}`;
|
||||||
|
|
||||||
render(): React.Node {
|
render() {
|
||||||
const {placeholder, actions, ...props} = this.props;
|
const {placeholder, actions, ...props} = this.props;
|
||||||
return [
|
return [
|
||||||
<SearchBar position="top" key="searchbar">
|
<SearchBar position="top" key="searchbar">
|
||||||
@@ -438,7 +443,7 @@ const Searchable = (
|
|||||||
? this.state.compiledRegex !== null
|
? this.state.compiledRegex !== null
|
||||||
: true
|
: true
|
||||||
}
|
}
|
||||||
regex={this.state.regexEnabled && this.state.searchTerm}
|
regex={Boolean(this.state.regexEnabled && this.state.searchTerm)}
|
||||||
/>
|
/>
|
||||||
</SearchBox>
|
</SearchBox>
|
||||||
{this.props.allowRegexSearch ? (
|
{this.props.allowRegexSearch ? (
|
||||||
@@ -5,26 +5,24 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {ManagedTableProps, TableBodyRow, Filter} from 'flipper';
|
import {Filter} from '../filter/types';
|
||||||
import type {SearchableProps} from './Searchable.js';
|
import ManagedTable, {ManagedTableProps} from '../table/ManagedTable.js';
|
||||||
import {PureComponent} from 'react';
|
import {TableBodyRow} from '../table/types.js';
|
||||||
import ManagedTable from '../table/ManagedTable.js';
|
import Searchable, {SearchableProps} from './Searchable';
|
||||||
|
import React, {PureComponent} from 'react';
|
||||||
import textContent from '../../../utils/textContent.tsx';
|
import textContent from '../../../utils/textContent';
|
||||||
import Searchable from './Searchable.js';
|
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
|
|
||||||
type Props = {|
|
type Props = {
|
||||||
...ManagedTableProps,
|
|
||||||
...SearchableProps,
|
|
||||||
/** Reference to the table */
|
/** Reference to the table */
|
||||||
innerRef?: (ref: React.ElementRef<*>) => void,
|
innerRef?: (ref: React.RefObject<any>) => void;
|
||||||
/** Filters that are added to the filterbar by default */
|
/** Filters that are added to the filterbar by default */
|
||||||
defaultFilters: Array<Filter>,
|
defaultFilters: Array<Filter>;
|
||||||
|};
|
} & ManagedTableProps &
|
||||||
|
SearchableProps;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
filterRows: (row: TableBodyRow) => boolean,
|
filterRows: (row: TableBodyRow) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowMatchesFilters = (filters: Array<Filter>, row: TableBodyRow) =>
|
const rowMatchesFilters = (filters: Array<Filter>, row: TableBodyRow) =>
|
||||||
@@ -5,26 +5,26 @@
|
|||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type {ManagedTableProps_immutable, TableBodyRow, Filter} from 'flipper';
|
import {Filter} from '../filter/types';
|
||||||
import type {SearchableProps} from './Searchable.js';
|
import {ManagedTableProps_immutable} from '../table/ManagedTable_immutable.js';
|
||||||
|
import {TableBodyRow} from '../table/types.js';
|
||||||
|
import Searchable, {SearchableProps} from './Searchable';
|
||||||
import {PureComponent} from 'react';
|
import {PureComponent} from 'react';
|
||||||
import ManagedTable_immutable from '../table/ManagedTable_immutable.js';
|
import ManagedTable_immutable from '../table/ManagedTable_immutable.js';
|
||||||
|
import textContent from '../../../utils/textContent';
|
||||||
import textContent from '../../../utils/textContent.tsx';
|
|
||||||
import Searchable from './Searchable.js';
|
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
type Props = {|
|
type Props = {
|
||||||
...ManagedTableProps_immutable,
|
|
||||||
...SearchableProps,
|
|
||||||
/** Reference to the table */
|
/** Reference to the table */
|
||||||
innerRef?: (ref: React.ElementRef<*>) => void,
|
innerRef?: (ref: React.RefObject<any>) => void;
|
||||||
/** Filters that are added to the filterbar by default */
|
/** Filters that are added to the filterbar by default */
|
||||||
defaultFilters: Array<Filter>,
|
defaultFilters: Array<Filter>;
|
||||||
|};
|
} & ManagedTableProps_immutable &
|
||||||
|
SearchableProps;
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
filterRows: (row: TableBodyRow) => boolean,
|
filterRows: (row: TableBodyRow) => boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const rowMatchesFilters = (filters: Array<Filter>, row: TableBodyRow) =>
|
const rowMatchesFilters = (filters: Array<Filter>, row: TableBodyRow) =>
|
||||||
@@ -14,7 +14,7 @@ import type {
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FilterRow from '../filter/FilterRow.tsx';
|
import FilterRow from '../filter/FilterRow.tsx';
|
||||||
import styled from '../../styled/index.js';
|
import styled from 'react-emotion';
|
||||||
import FlexRow from '../FlexRow.tsx';
|
import FlexRow from '../FlexRow.tsx';
|
||||||
import {colors} from '../colors.tsx';
|
import {colors} from '../colors.tsx';
|
||||||
import {normaliseColumnWidth} from './utils.js';
|
import {normaliseColumnWidth} from './utils.js';
|
||||||
|
|||||||
@@ -154,14 +154,14 @@ export {
|
|||||||
SearchInput,
|
SearchInput,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
default as Searchable,
|
default as Searchable,
|
||||||
} from './components/searchable/Searchable.js';
|
} from './components/searchable/Searchable.tsx';
|
||||||
export {
|
export {
|
||||||
default as SearchableTable,
|
default as SearchableTable,
|
||||||
} from './components/searchable/SearchableTable.js';
|
} from './components/searchable/SearchableTable.tsx';
|
||||||
export {
|
export {
|
||||||
default as SearchableTable_immutable,
|
default as SearchableTable_immutable,
|
||||||
} from './components/searchable/SearchableTable_immutable.js';
|
} from './components/searchable/SearchableTable_immutable.tsx';
|
||||||
export type {SearchableProps} from './components/searchable/Searchable.js';
|
export type {SearchableProps} from './components/searchable/Searchable.tsx';
|
||||||
|
|
||||||
//
|
//
|
||||||
export type {
|
export type {
|
||||||
|
|||||||
17
yarn.lock
17
yarn.lock
@@ -1062,6 +1062,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.4.tgz#56eec47706f0fd0b7c694eae2f3172e6b0b769da"
|
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.4.tgz#56eec47706f0fd0b7c694eae2f3172e6b0b769da"
|
||||||
integrity sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==
|
integrity sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==
|
||||||
|
|
||||||
|
"@types/deep-equal@^1.0.1":
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/deep-equal/-/deep-equal-1.0.1.tgz#71cfabb247c22bcc16d536111f50c0ed12476b03"
|
||||||
|
integrity sha512-mMUu4nWHLBlHtxXY17Fg6+ucS/MnndyOWyOe7MmwkoMYxvfQU2ajtRaEvqSUv+aVkMqH/C0NCI8UoVfRNQ10yg==
|
||||||
|
|
||||||
"@types/eslint-visitor-keys@^1.0.0":
|
"@types/eslint-visitor-keys@^1.0.0":
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
|
||||||
@@ -1131,6 +1136,18 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636"
|
||||||
integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
|
integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A==
|
||||||
|
|
||||||
|
"@types/lodash.debounce@^4.0.6":
|
||||||
|
version "4.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.debounce/-/lodash.debounce-4.0.6.tgz#c5a2326cd3efc46566c47e4c0aa248dc0ee57d60"
|
||||||
|
integrity sha512-4WTmnnhCfDvvuLMaF3KV4Qfki93KebocUF45msxhYyjMttZDQYzHkO639ohhk8+oco2cluAFL3t5+Jn4mleylQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash@*":
|
||||||
|
version "4.14.136"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.136.tgz#413e85089046b865d960c9ff1d400e04c31ab60f"
|
||||||
|
integrity sha512-0GJhzBdvsW2RUccNHOBkabI8HZVdOXmXbXhuKlDEd5Vv12P7oAVGfomGp3Ne21o5D/qu1WmthlNKFaoZJJeErA==
|
||||||
|
|
||||||
"@types/minimatch@*":
|
"@types/minimatch@*":
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
|
|||||||
Reference in New Issue
Block a user