Add framework event node level event filtering

Summary: Lets you filter a nodes events by thread or type

Reviewed By: lblasa

Differential Revision: D48346955

fbshipit-source-id: 455d65ad21c54c5ad26782ac6a446f7ae15a4356
This commit is contained in:
Luke De Feo
2023-08-21 04:24:16 -07:00
committed by Facebook GitHub Bot
parent 3cd6079c24
commit f5bc03c263
3 changed files with 94 additions and 26 deletions

View File

@@ -45,6 +45,9 @@ export class TimelineDataDescription extends Component<Props, State> {
render(): ReactNode { render(): ReactNode {
const moments = Object.values(this.props.timeline.time); const moments = Object.values(this.props.timeline.time);
if (moments == null || moments.length === 0) {
return null;
}
const firstMoment = moments[0].moment; const firstMoment = moments[0].moment;
const points = moments.map((value) => ({ const points = moments.map((value) => ({
label: value.display, label: value.display,

View File

@@ -16,7 +16,9 @@ export function FrameworkEventsTreeSelect({
onSetEventSelected, onSetEventSelected,
selected, selected,
placeholder, placeholder,
width,
}: { }: {
width?: number;
placeholder: string; placeholder: string;
selected: string[]; selected: string[];
treeData: TreeSelectNode[]; treeData: TreeSelectNode[];
@@ -33,7 +35,7 @@ export function FrameworkEventsTreeSelect({
placeholder={placeholder} placeholder={placeholder}
virtual={false} //for scrollbar virtual={false} //for scrollbar
style={{ style={{
width: '100%', width: width ?? '100%',
}} }}
treeData={treeData} treeData={treeData}
treeDefaultExpandAll treeDefaultExpandAll

View File

@@ -10,14 +10,20 @@
import { import {
DataInspector, DataInspector,
Layout, Layout,
produce,
theme, theme,
TimelineDataDescription, TimelineDataDescription,
} from 'flipper-plugin'; } from 'flipper-plugin';
import {FrameworkEvent, ClientNode} from '../../../ClientTypes'; import {FrameworkEvent, ClientNode} from '../../../ClientTypes';
import React, {ReactNode} from 'react'; import React, {ReactNode, useState} from 'react';
import {StackTraceInspector} from './StackTraceInspector'; import {StackTraceInspector} from './StackTraceInspector';
import {Descriptions, Tag} from 'antd'; import {Collapse, Descriptions, Select, Tag} from 'antd';
import {frameworkEventSeparator} from '../../shared/FrameworkEventsTreeSelect'; import {frameworkEventSeparator} from '../../shared/FrameworkEventsTreeSelect';
import {
buildTreeSelectData,
FrameworkEventsTreeSelect,
} from '../../shared/FrameworkEventsTreeSelect';
import {uniqBy} from 'lodash';
type Props = { type Props = {
node: ClientNode; node: ClientNode;
@@ -29,20 +35,76 @@ export const FrameworkEventsInspector: React.FC<Props> = ({
events, events,
showExtra, showExtra,
}) => { }) => {
const allThreads = uniqBy(events, 'thread').map((event) => event.thread);
const [filteredThreads, setFilteredThreads] = useState<Set<string>>(
new Set(),
);
const allEventTypes = uniqBy(events, 'type').map((event) => event.type);
const [filteredEventTypes, setFilteredEventTypes] = useState<Set<string>>(
new Set(),
);
const filteredEvents = events
.filter(
(event) =>
filteredEventTypes.size === 0 || filteredEventTypes.has(event.type),
)
.filter(
(event) =>
filteredThreads.size === 0 || filteredThreads.has(event.thread!),
);
return ( return (
<Layout.Container gap="small" padv="small">
<Collapse>
<Collapse.Panel header="Filter events" key="1">
<Layout.Container gap="tiny">
<FrameworkEventsTreeSelect
placeholder="Select events types to filter by"
treeData={buildTreeSelectData(allEventTypes)}
width={250}
onSetEventSelected={(eventType, selected) => {
setFilteredEventTypes((cur) =>
produce(cur, (draft) => {
if (selected) {
draft.add(eventType);
} else {
draft.delete(eventType);
}
}),
);
}}
selected={[...filteredEventTypes]}
/>
<Select
mode="multiple"
style={{width: '250px'}}
placeholder="Select threads to filter by"
defaultValue={[] as string[]}
options={allThreads.map((thread) => ({
value: thread,
label: thread,
}))}
onChange={(value) => setFilteredThreads(new Set(value))}
/>
</Layout.Container>
</Collapse.Panel>
</Collapse>
<TimelineDataDescription <TimelineDataDescription
key={node.id} key={node.id}
canSetCurrent={false} canSetCurrent={false}
onClick={(current) => { onClick={(current) => {
const idx = parseInt(current, 10); const idx = parseInt(current, 10);
const event = events[idx]; const event = filteredEvents[idx];
showExtra?.( showExtra?.(
'Event details', 'Event details',
<EventDetails event={event} node={node} />, <EventDetails event={event} node={node} />,
); );
}} }}
timeline={{ timeline={{
time: events.map((event, idx) => { time: filteredEvents.map((event, idx) => {
return { return {
moment: event.timestamp, moment: event.timestamp,
display: `${eventTypeToName(event.type)}`, display: `${eventTypeToName(event.type)}`,
@@ -53,6 +115,7 @@ export const FrameworkEventsInspector: React.FC<Props> = ({
current: 'initialNone', current: 'initialNone',
}} }}
/> />
</Layout.Container>
); );
}; };