Search full request details

Summary: Simple implementation of searching through request/response body on "network" tab

Reviewed By: passy

Differential Revision: D18268026

fbshipit-source-id: 39386d2d6ec50b47c3ca3dec976821282b51636f
This commit is contained in:
Anton Nikolaev
2019-11-01 06:53:42 -07:00
committed by Facebook Github Bot
parent 691a4ee135
commit faaf8c4f32
5 changed files with 55 additions and 6 deletions

View File

@@ -283,8 +283,11 @@ ${request.headers
) )
.join('\n')}`; .join('\n')}`;
if (request.data) { const requestData = request.data ? decodeBody(request) : null;
copyText += `\n\n${decodeBody(request)}`; const responseData = response && response.data ? decodeBody(response) : null;
if (requestData) {
copyText += `\n\n${requestData}`;
} }
if (response) { if (response) {
@@ -300,8 +303,8 @@ ${response.headers
.join('\n')}`; .join('\n')}`;
} }
if (response) { if (responseData) {
copyText += `\n\n${decodeBody(response)}`; copyText += `\n\n${responseData}`;
} }
return { return {
@@ -346,6 +349,8 @@ ${response.headers
sortKey: request.timestamp, sortKey: request.timestamp,
copyText, copyText,
highlightOnHover: true, highlightOnHover: true,
requestBody: requestData,
responseBody: responseData,
}; };
} }
@@ -471,6 +476,7 @@ class NetworkTable extends PureComponent<NetworkTableProps, NetworkTableState> {
highlightedRows={this.props.highlightedRows} highlightedRows={this.props.highlightedRows}
rowLineHeight={26} rowLineHeight={26}
allowRegexSearch={true} allowRegexSearch={true}
allowBodySearch={true}
zebra={false} zebra={false}
actions={<Button onClick={this.props.clear}>Clear Table</Button>} actions={<Button onClick={this.props.clear}>Clear Table</Button>}
/> />

View File

@@ -56,6 +56,7 @@ type Props = {
toggled?: boolean; toggled?: boolean;
className?: string; className?: string;
label?: string; label?: string;
tooltip?: string;
}; };
/** /**
@@ -71,7 +72,7 @@ type Props = {
export default class ToggleButton extends React.Component<Props> { export default class ToggleButton extends React.Component<Props> {
render() { render() {
return ( return (
<Container onClick={this.props.onClick}> <Container onClick={this.props.onClick} title={this.props.tooltip}>
<StyledButton <StyledButton
className={this.props.className} className={this.props.className}
toggled={this.props.toggled || false} toggled={this.props.toggled || false}

View File

@@ -93,7 +93,9 @@ export type SearchableProps = {
searchTerm: string; searchTerm: string;
filters: Array<Filter>; filters: Array<Filter>;
allowRegexSearch?: boolean; allowRegexSearch?: boolean;
allowBodySearch?: boolean;
regexEnabled?: boolean; regexEnabled?: boolean;
bodySearchEnabled?: boolean;
}; };
type Props = { type Props = {
@@ -104,6 +106,7 @@ type Props = {
onFilterChange: (filters: Array<Filter>) => void; onFilterChange: (filters: Array<Filter>) => void;
defaultFilters: Array<Filter>; defaultFilters: Array<Filter>;
allowRegexSearch: boolean; allowRegexSearch: boolean;
allowBodySearch: boolean;
}; };
type State = { type State = {
@@ -112,6 +115,7 @@ type State = {
searchTerm: string; searchTerm: string;
hasFocus: boolean; hasFocus: boolean;
regexEnabled: boolean; regexEnabled: boolean;
bodySearchEnabled: boolean;
compiledRegex: RegExp | null | undefined; compiledRegex: RegExp | null | undefined;
}; };
@@ -137,6 +141,7 @@ const Searchable = (
searchTerm: '', searchTerm: '',
hasFocus: false, hasFocus: false,
regexEnabled: false, regexEnabled: false,
bodySearchEnabled: false,
compiledRegex: null, compiledRegex: null,
}; };
@@ -149,6 +154,7 @@ const Searchable = (
| { | {
filters: Array<Filter>; filters: Array<Filter>;
regexEnabled?: boolean; regexEnabled?: boolean;
bodySearchEnabled?: boolean;
searchTerm?: string; searchTerm?: string;
} }
| undefined; | undefined;
@@ -192,6 +198,8 @@ const Searchable = (
searchTerm: searchTerm, searchTerm: searchTerm,
filters: savedState.filters || this.state.filters, filters: savedState.filters || this.state.filters,
regexEnabled: savedState.regexEnabled || this.state.regexEnabled, regexEnabled: savedState.regexEnabled || this.state.regexEnabled,
bodySearchEnabled:
savedState.bodySearchEnabled || this.state.bodySearchEnabled,
compiledRegex: compileRegex(searchTerm), compiledRegex: compileRegex(searchTerm),
}); });
} }
@@ -202,6 +210,7 @@ const Searchable = (
this.getTableKey() && this.getTableKey() &&
(prevState.searchTerm !== this.state.searchTerm || (prevState.searchTerm !== this.state.searchTerm ||
prevState.regexEnabled != this.state.regexEnabled || prevState.regexEnabled != this.state.regexEnabled ||
prevState.bodySearchEnabled != this.state.bodySearchEnabled ||
prevState.filters !== this.state.filters) prevState.filters !== this.state.filters)
) { ) {
window.localStorage.setItem( window.localStorage.setItem(
@@ -210,6 +219,7 @@ const Searchable = (
searchTerm: this.state.searchTerm, searchTerm: this.state.searchTerm,
filters: this.state.filters, filters: this.state.filters,
regexEnabled: this.state.regexEnabled, regexEnabled: this.state.regexEnabled,
bodySearchEnabled: this.state.bodySearchEnabled,
}), }),
); );
if (this.props.onFilterChange != null) { if (this.props.onFilterChange != null) {
@@ -406,6 +416,12 @@ const Searchable = (
}); });
}; };
onBodySearchToggled = () => {
this.setState({
bodySearchEnabled: !this.state.bodySearchEnabled,
});
};
hasFocus = (): boolean => { hasFocus = (): boolean => {
return this.state.focusedToken !== -1 || this.state.hasFocus; return this.state.focusedToken !== -1 || this.state.hasFocus;
}; };
@@ -464,6 +480,16 @@ const Searchable = (
label={'Regex'} label={'Regex'}
/> />
) : null} ) : null}
{this.props.allowBodySearch ? (
<ToggleButton
toggled={this.state.bodySearchEnabled}
onClick={this.onBodySearchToggled}
label={'Body'}
tooltip={
'Search request and response bodies (warning: this can be quite slow)'
}
/>
) : null}
{(this.state.searchTerm || this.state.filters.length > 0) && ( {(this.state.searchTerm || this.state.filters.length > 0) && (
<Clear onClick={this.clear}>&times;</Clear> <Clear onClick={this.clear}>&times;</Clear>
)} )}
@@ -475,6 +501,7 @@ const Searchable = (
addFilter={this.addFilter} addFilter={this.addFilter}
searchTerm={this.state.searchTerm} searchTerm={this.state.searchTerm}
regexEnabled={this.state.regexEnabled} regexEnabled={this.state.regexEnabled}
bodySearchEnabled={this.state.bodySearchEnabled}
filters={this.state.filters} filters={this.state.filters}
/>, />,
]; ];

View File

@@ -60,6 +60,7 @@ function rowMatchesRegex(values: Array<string>, regex: string): boolean {
function rowMatchesSearchTerm( function rowMatchesSearchTerm(
searchTerm: string, searchTerm: string,
isRegex: boolean, isRegex: boolean,
isBodySearchEnabled: boolean,
row: TableBodyRow, row: TableBodyRow,
): boolean { ): boolean {
if (searchTerm == null || searchTerm.length === 0) { if (searchTerm == null || searchTerm.length === 0) {
@@ -68,6 +69,14 @@ function rowMatchesSearchTerm(
const rowValues = Object.keys(row.columns).map(key => const rowValues = Object.keys(row.columns).map(key =>
textContent(row.columns[key].value), textContent(row.columns[key].value),
); );
if (isBodySearchEnabled) {
if (row.requestBody) {
rowValues.push(row.requestBody);
}
if (row.responseBody) {
rowValues.push(row.responseBody);
}
}
if (isRegex) { if (isRegex) {
return rowMatchesRegex(rowValues, searchTerm); return rowMatchesRegex(rowValues, searchTerm);
} }
@@ -80,9 +89,10 @@ const filterRowsFactory = (
filters: Array<Filter>, filters: Array<Filter>,
searchTerm: string, searchTerm: string,
regexSearch: boolean, regexSearch: boolean,
bodySearch: boolean,
) => (row: TableBodyRow): boolean => ) => (row: TableBodyRow): boolean =>
rowMatchesFilters(filters, row) && rowMatchesFilters(filters, row) &&
rowMatchesSearchTerm(searchTerm, regexSearch, row); rowMatchesSearchTerm(searchTerm, regexSearch, bodySearch, row);
class SearchableManagedTable extends PureComponent<Props, State> { class SearchableManagedTable extends PureComponent<Props, State> {
static defaultProps = { static defaultProps = {
@@ -94,6 +104,7 @@ class SearchableManagedTable extends PureComponent<Props, State> {
this.props.filters, this.props.filters,
this.props.searchTerm, this.props.searchTerm,
this.props.regexEnabled || false, this.props.regexEnabled || false,
this.props.bodySearchEnabled || false,
), ),
}; };
@@ -105,6 +116,7 @@ class SearchableManagedTable extends PureComponent<Props, State> {
if ( if (
nextProps.searchTerm !== this.props.searchTerm || nextProps.searchTerm !== this.props.searchTerm ||
nextProps.regexEnabled != this.props.regexEnabled || nextProps.regexEnabled != this.props.regexEnabled ||
nextProps.bodySearchEnabled != this.props.bodySearchEnabled ||
!deepEqual(this.props.filters, nextProps.filters) !deepEqual(this.props.filters, nextProps.filters)
) { ) {
this.setState({ this.setState({
@@ -112,6 +124,7 @@ class SearchableManagedTable extends PureComponent<Props, State> {
nextProps.filters, nextProps.filters,
nextProps.searchTerm, nextProps.searchTerm,
nextProps.regexEnabled || false, nextProps.regexEnabled || false,
nextProps.bodySearchEnabled || false,
), ),
}); });
} }

View File

@@ -55,6 +55,8 @@ export type TableBodyRow = {
highlightedBackgroundColor?: BackgroundColorProperty | undefined; highlightedBackgroundColor?: BackgroundColorProperty | undefined;
onDoubleClick?: (e: React.MouseEvent) => void; onDoubleClick?: (e: React.MouseEvent) => void;
copyText?: string; copyText?: string;
requestBody?: string | null | undefined;
responseBody?: string | null | undefined;
highlightOnHover?: boolean; highlightOnHover?: boolean;
columns: { columns: {
[key: string]: TableBodyColumn; [key: string]: TableBodyColumn;