Migrate framework events backing data structure to datasource
Summary: This will allow us to build a nice table easily. Reviewed By: lblasa Differential Revision: D47520029 fbshipit-source-id: 3cdd776533b66688329171eb29b892e0b9153540
This commit is contained in:
committed by
Facebook GitHub Bot
parent
16480a95f3
commit
7812dae764
@@ -17,14 +17,12 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
import React, {useMemo} from 'react';
|
import React, {useMemo} from 'react';
|
||||||
import {
|
import {
|
||||||
Atom,
|
|
||||||
DataInspector,
|
DataInspector,
|
||||||
DataSource,
|
DataSource,
|
||||||
DataTable,
|
DataTable,
|
||||||
DataTableColumn,
|
DataTableColumn,
|
||||||
DetailSidebar,
|
DetailSidebar,
|
||||||
Layout,
|
Layout,
|
||||||
useValue,
|
|
||||||
} from 'flipper-plugin';
|
} from 'flipper-plugin';
|
||||||
|
|
||||||
export function PerfStats(props: {
|
export function PerfStats(props: {
|
||||||
@@ -32,15 +30,13 @@ export function PerfStats(props: {
|
|||||||
nodes: Map<Id, UINode>;
|
nodes: Map<Id, UINode>;
|
||||||
rootId?: Id;
|
rootId?: Id;
|
||||||
events: DataSource<DynamicPerformanceStatsEvent, number>;
|
events: DataSource<DynamicPerformanceStatsEvent, number>;
|
||||||
frameworkEvents: Atom<Map<Id, FrameworkEvent[]>>;
|
frameworkEvents: DataSource<FrameworkEvent>;
|
||||||
}) {
|
}) {
|
||||||
const uiStateValues = Object.entries(props.uiState).map(([key, value]) => [
|
const uiStateValues = Object.entries(props.uiState).map(([key, value]) => [
|
||||||
key,
|
key,
|
||||||
value.get(),
|
value.get(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const frameworkEventsValue = useValue(props.frameworkEvents);
|
|
||||||
|
|
||||||
const allColumns = useMemo(() => {
|
const allColumns = useMemo(() => {
|
||||||
if (props.events.size > 0) {
|
if (props.events.size > 0) {
|
||||||
const row = props.events.get(0);
|
const row = props.events.get(0);
|
||||||
@@ -65,7 +61,6 @@ export function PerfStats(props: {
|
|||||||
return columns;
|
return columns;
|
||||||
}, [props.events]);
|
}, [props.events]);
|
||||||
|
|
||||||
const newLocal = [...frameworkEventsValue.entries()];
|
|
||||||
return (
|
return (
|
||||||
<Layout.Container grow>
|
<Layout.Container grow>
|
||||||
<DataTable<PerformanceStatsEvent>
|
<DataTable<PerformanceStatsEvent>
|
||||||
@@ -79,11 +74,7 @@ export function PerfStats(props: {
|
|||||||
rootId: props.rootId,
|
rootId: props.rootId,
|
||||||
nodesCount: props.nodes.size,
|
nodesCount: props.nodes.size,
|
||||||
rootNode: props.nodes.get(props.rootId ?? 'noroot'),
|
rootNode: props.nodes.get(props.rootId ?? 'noroot'),
|
||||||
frameworkEvents: newLocal,
|
frameworkEventsSize: props.frameworkEvents.size,
|
||||||
frameworkEventsSize: newLocal.reduce(
|
|
||||||
(acc, value) => acc + value[1].length,
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
}}></DataInspector>
|
}}></DataInspector>
|
||||||
</DetailSidebar>
|
</DetailSidebar>
|
||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import {
|
import {
|
||||||
|
DataSource,
|
||||||
getFlipperLib,
|
getFlipperLib,
|
||||||
HighlightManager,
|
HighlightManager,
|
||||||
HighlightProvider,
|
HighlightProvider,
|
||||||
@@ -69,6 +70,7 @@ export type TreeNode = UINode & {
|
|||||||
idx: number;
|
idx: number;
|
||||||
isExpanded: boolean;
|
isExpanded: boolean;
|
||||||
indentGuide: NodeIndentGuide | null;
|
indentGuide: NodeIndentGuide | null;
|
||||||
|
frameworkEvents: number | null;
|
||||||
};
|
};
|
||||||
export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
||||||
const instance = usePlugin(plugin);
|
const instance = usePlugin(plugin);
|
||||||
@@ -79,7 +81,6 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
const isContextMenuOpen = useValue(instance.uiState.isContextMenuOpen);
|
const isContextMenuOpen = useValue(instance.uiState.isContextMenuOpen);
|
||||||
const hoveredNode = head(useValue(instance.uiState.hoveredNodes));
|
const hoveredNode = head(useValue(instance.uiState.hoveredNodes));
|
||||||
|
|
||||||
const frameworkEvents = useValue(instance.frameworkEvents);
|
|
||||||
const filterMainThreadMonitoring = useValue(
|
const filterMainThreadMonitoring = useValue(
|
||||||
instance.uiState.filterMainThreadMonitoring,
|
instance.uiState.filterMainThreadMonitoring,
|
||||||
);
|
);
|
||||||
@@ -94,6 +95,9 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
focusedNode || rootId,
|
focusedNode || rootId,
|
||||||
expandedNodes,
|
expandedNodes,
|
||||||
selectedNode?.id,
|
selectedNode?.id,
|
||||||
|
instance.frameworkEvents,
|
||||||
|
frameworkEventsMonitoring,
|
||||||
|
filterMainThreadMonitoring,
|
||||||
);
|
);
|
||||||
|
|
||||||
const refs: React.RefObject<HTMLLIElement>[] = treeNodes.map(() =>
|
const refs: React.RefObject<HTMLLIElement>[] = treeNodes.map(() =>
|
||||||
@@ -101,7 +105,16 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {treeNodes, refs};
|
return {treeNodes, refs};
|
||||||
}, [expandedNodes, focusedNode, nodes, rootId, selectedNode]);
|
}, [
|
||||||
|
expandedNodes,
|
||||||
|
filterMainThreadMonitoring,
|
||||||
|
focusedNode,
|
||||||
|
frameworkEventsMonitoring,
|
||||||
|
instance.frameworkEvents,
|
||||||
|
nodes,
|
||||||
|
rootId,
|
||||||
|
selectedNode?.id,
|
||||||
|
]);
|
||||||
|
|
||||||
const isUsingKBToScrollUtill = useRef<MillisSinceEpoch>(0);
|
const isUsingKBToScrollUtill = useRef<MillisSinceEpoch>(0);
|
||||||
|
|
||||||
@@ -240,9 +253,6 @@ export function Tree2({nodes, rootId}: {nodes: Map<Id, UINode>; rootId: Id}) {
|
|||||||
innerRef={refs[virtualRow.index]}
|
innerRef={refs[virtualRow.index]}
|
||||||
key={virtualRow.index}
|
key={virtualRow.index}
|
||||||
treeNode={treeNodes[virtualRow.index]}
|
treeNode={treeNodes[virtualRow.index]}
|
||||||
frameworkEvents={frameworkEvents}
|
|
||||||
frameworkEventsMonitoring={frameworkEventsMonitoring}
|
|
||||||
filterMainThreadMonitoring={filterMainThreadMonitoring}
|
|
||||||
highlightedNodes={highlightedNodes}
|
highlightedNodes={highlightedNodes}
|
||||||
selectedNode={selectedNode?.id}
|
selectedNode={selectedNode?.id}
|
||||||
hoveredNode={hoveredNode}
|
hoveredNode={hoveredNode}
|
||||||
@@ -292,9 +302,6 @@ function TreeItemContainer({
|
|||||||
transform,
|
transform,
|
||||||
innerRef,
|
innerRef,
|
||||||
treeNode,
|
treeNode,
|
||||||
frameworkEvents,
|
|
||||||
frameworkEventsMonitoring,
|
|
||||||
filterMainThreadMonitoring,
|
|
||||||
highlightedNodes,
|
highlightedNodes,
|
||||||
selectedNode,
|
selectedNode,
|
||||||
hoveredNode,
|
hoveredNode,
|
||||||
@@ -308,10 +315,7 @@ function TreeItemContainer({
|
|||||||
transform: string;
|
transform: string;
|
||||||
innerRef: Ref<any>;
|
innerRef: Ref<any>;
|
||||||
treeNode: TreeNode;
|
treeNode: TreeNode;
|
||||||
frameworkEvents: Map<Id, FrameworkEvent[]>;
|
|
||||||
highlightedNodes: Set<Id>;
|
highlightedNodes: Set<Id>;
|
||||||
frameworkEventsMonitoring: Map<FrameworkEventType, boolean>;
|
|
||||||
filterMainThreadMonitoring: boolean;
|
|
||||||
selectedNode?: Id;
|
selectedNode?: Id;
|
||||||
hoveredNode?: Id;
|
hoveredNode?: Id;
|
||||||
isUsingKBToScroll: RefObject<MillisSinceEpoch>;
|
isUsingKBToScroll: RefObject<MillisSinceEpoch>;
|
||||||
@@ -321,15 +325,6 @@ function TreeItemContainer({
|
|||||||
onCollapseNode: (node: Id) => void;
|
onCollapseNode: (node: Id) => void;
|
||||||
onHoverNode: (node: Id) => void;
|
onHoverNode: (node: Id) => void;
|
||||||
}) {
|
}) {
|
||||||
let events = frameworkEvents.get(treeNode.id);
|
|
||||||
if (events) {
|
|
||||||
events = events
|
|
||||||
.filter((e) => frameworkEventsMonitoring.get(e.type))
|
|
||||||
.filter(
|
|
||||||
(e) => filterMainThreadMonitoring === false || e.thread === 'main',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={innerRef}
|
ref={innerRef}
|
||||||
@@ -375,9 +370,9 @@ function TreeItemContainer({
|
|||||||
{nodeIcon(treeNode)}
|
{nodeIcon(treeNode)}
|
||||||
|
|
||||||
<TreeItemRowContent treeNode={treeNode} />
|
<TreeItemRowContent treeNode={treeNode} />
|
||||||
{events && (
|
{treeNode.frameworkEvents && (
|
||||||
<Badge
|
<Badge
|
||||||
count={events.length}
|
count={treeNode.frameworkEvents}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: theme.primaryColor,
|
backgroundColor: theme.primaryColor,
|
||||||
marginLeft: theme.space.small,
|
marginLeft: theme.space.small,
|
||||||
@@ -616,6 +611,9 @@ function toTreeNodes(
|
|||||||
rootId: Id,
|
rootId: Id,
|
||||||
expandedNodes: Set<Id>,
|
expandedNodes: Set<Id>,
|
||||||
selectedNode: Id | undefined,
|
selectedNode: Id | undefined,
|
||||||
|
frameworkEvents: DataSource<FrameworkEvent>,
|
||||||
|
frameworkEventsMonitoring: Map<FrameworkEventType, boolean>,
|
||||||
|
filterMainThreadMonitoring: boolean,
|
||||||
): TreeNode[] {
|
): TreeNode[] {
|
||||||
const root = nodes.get(rootId);
|
const root = nodes.get(rootId);
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
@@ -643,11 +641,21 @@ function toTreeNodes(
|
|||||||
const isExpanded = expandedNodes.has(node.id);
|
const isExpanded = expandedNodes.has(node.id);
|
||||||
const isSelected = node.id === selectedNode;
|
const isSelected = node.id === selectedNode;
|
||||||
|
|
||||||
|
let events = frameworkEvents.getAllRecordsByIndex({nodeId: node.id});
|
||||||
|
if (events) {
|
||||||
|
events = events
|
||||||
|
.filter((e) => frameworkEventsMonitoring.get(e.type))
|
||||||
|
.filter(
|
||||||
|
(e) => filterMainThreadMonitoring === false || e.thread === 'main',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
treeNodes.push({
|
treeNodes.push({
|
||||||
...node,
|
...node,
|
||||||
idx: i,
|
idx: i,
|
||||||
depth,
|
depth,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
|
frameworkEvents: events.length > 0 ? events.length : null,
|
||||||
indentGuide: stackItem.isChildOfSelectedNode
|
indentGuide: stackItem.isChildOfSelectedNode
|
||||||
? {
|
? {
|
||||||
depth: stackItem.selectedNodeDepth,
|
depth: stackItem.selectedNodeDepth,
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ export const Inspector: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const instance = usePlugin(plugin);
|
const instance = usePlugin(plugin);
|
||||||
const selectedNodeId = useValue(instance.uiState.selectedNode)?.id;
|
const selectedNodeId = useValue(instance.uiState.selectedNode)?.id;
|
||||||
const frameworkEvents = useValue(instance.frameworkEvents);
|
|
||||||
|
|
||||||
const selectedNode = selectedNodeId ? nodes.get(selectedNodeId) : undefined;
|
const selectedNode = selectedNodeId ? nodes.get(selectedNodeId) : undefined;
|
||||||
if (!selectedNode) {
|
if (!selectedNode) {
|
||||||
@@ -50,8 +49,8 @@ export const Inspector: React.FC<Props> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selectedFrameworkEvents = selectedNodeId
|
const selectedFrameworkEvents = selectedNodeId
|
||||||
? frameworkEvents?.get(selectedNodeId)
|
? instance.frameworkEvents.getAllRecordsByIndex({nodeId: selectedNodeId})
|
||||||
: undefined;
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout.Container gap pad>
|
<Layout.Container gap pad>
|
||||||
@@ -108,7 +107,7 @@ export const Inspector: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
{selectedFrameworkEvents && (
|
{selectedFrameworkEvents?.length > 0 && (
|
||||||
<Tab
|
<Tab
|
||||||
key={'events'}
|
key={'events'}
|
||||||
tab={
|
tab={
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {StackTraceInspector} from './StackTraceInspector';
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
node: UINode;
|
node: UINode;
|
||||||
events: FrameworkEvent[];
|
events: readonly FrameworkEvent[];
|
||||||
showExtra?: (element: ReactNode) => void;
|
showExtra?: (element: ReactNode) => void;
|
||||||
};
|
};
|
||||||
export const FrameworkEventsInspector: React.FC<Props> = ({
|
export const FrameworkEventsInspector: React.FC<Props> = ({
|
||||||
@@ -41,7 +41,7 @@ export const FrameworkEventsInspector: React.FC<Props> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hasStacktrace = (event: FrameworkEvent) => {
|
const hasStacktrace = (event: FrameworkEvent) => {
|
||||||
return event.attribution?.type === 'stacktrace';
|
return event?.attribution?.type === 'stacktrace';
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export function plugin(client: PluginClient<Events>) {
|
|||||||
clearCallBack: async () => {
|
clearCallBack: async () => {
|
||||||
uiState.streamState.set({state: 'Ok'});
|
uiState.streamState.set({state: 'Ok'});
|
||||||
nodesAtom.set(new Map());
|
nodesAtom.set(new Map());
|
||||||
frameworkEvents.set(new Map());
|
frameworkEvents.clear();
|
||||||
snapshot.set(null);
|
snapshot.set(null);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -191,7 +191,10 @@ export function plugin(client: PluginClient<Events>) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const nodesAtom = createState<Map<Id, UINode>>(new Map());
|
const nodesAtom = createState<Map<Id, UINode>>(new Map());
|
||||||
const frameworkEvents = createState<Map<Id, FrameworkEvent[]>>(new Map());
|
const frameworkEvents = createDataSource<FrameworkEvent>([], {
|
||||||
|
indices: [['nodeId']],
|
||||||
|
limit: 10000,
|
||||||
|
});
|
||||||
|
|
||||||
const highlightedNodes = createState(new Set<Id>());
|
const highlightedNodes = createState(new Set<Id>());
|
||||||
const snapshot = createState<SnapshotInfo | null>(null);
|
const snapshot = createState<SnapshotInfo | null>(null);
|
||||||
@@ -279,18 +282,9 @@ export function plugin(client: PluginClient<Events>) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function applyFrameworkEvents(frameScan: FrameScanEvent) {
|
function applyFrameworkEvents(frameScan: FrameScanEvent) {
|
||||||
frameworkEvents.update((draft) => {
|
for (const frameworkEvent of frameScan.frameworkEvents ?? []) {
|
||||||
if (frameScan?.frameworkEvents) {
|
frameworkEvents.append(frameworkEvent);
|
||||||
frameScan.frameworkEvents.forEach((frameworkEvent) => {
|
|
||||||
const frameworkEventsForNode = draft.get(frameworkEvent.nodeId);
|
|
||||||
if (frameworkEventsForNode) {
|
|
||||||
frameworkEventsForNode.push(frameworkEvent);
|
|
||||||
} else {
|
|
||||||
draft.set(frameworkEvent.nodeId, [frameworkEvent]);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (uiState.isPaused.get() === true) {
|
if (uiState.isPaused.get() === true) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -110,6 +110,7 @@ type UpstreamEvent = {type: 'upstreamEvent'; eventId: Id};
|
|||||||
type FrameworkEventAttribution = Stacktrace | Reason | UpstreamEvent;
|
type FrameworkEventAttribution = Stacktrace | Reason | UpstreamEvent;
|
||||||
|
|
||||||
export type FrameworkEvent = {
|
export type FrameworkEvent = {
|
||||||
|
id: number;
|
||||||
nodeId: Id;
|
nodeId: Id;
|
||||||
type: FrameworkEventType;
|
type: FrameworkEventType;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user