From 4df0ad4d355f1fc2228c06a3a72c8c2bca102324 Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Fri, 21 Jul 2023 07:17:31 -0700 Subject: [PATCH] Add Framework event table Summary: Very basic framework events table, quite useful for debugging will add more to this soon Reviewed By: lblasa Differential Revision: D47520035 fbshipit-source-id: 10f4572dd4ed3529324f03a969773c7e91fde030 --- .../components/FrameworkEventsTable.tsx | 71 +++++++++++++++ .../public/ui-debugger/components/Tree.tsx | 33 ++++++- .../public/ui-debugger/components/main.tsx | 90 ++++++++++--------- desktop/plugins/public/ui-debugger/index.tsx | 8 ++ desktop/plugins/public/ui-debugger/types.tsx | 7 ++ 5 files changed, 166 insertions(+), 43 deletions(-) create mode 100644 desktop/plugins/public/ui-debugger/components/FrameworkEventsTable.tsx diff --git a/desktop/plugins/public/ui-debugger/components/FrameworkEventsTable.tsx b/desktop/plugins/public/ui-debugger/components/FrameworkEventsTable.tsx new file mode 100644 index 000000000..93d74aae5 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/FrameworkEventsTable.tsx @@ -0,0 +1,71 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {PartitionOutlined} from '@ant-design/icons'; +import { + DataTable, + DataTableColumn, + DataTableManager, + Layout, + usePlugin, +} from 'flipper-plugin'; +import React, {useEffect, useRef} from 'react'; +import {FrameworkEvent, Id} from '../types'; +import {plugin} from '../index'; +import {Button, Tooltip} from 'antd'; + +export function FrameworkEventsTable({rootTreeId}: {rootTreeId?: Id}) { + const instance = usePlugin(plugin); + + const managerRef = useRef | null>(null); + + useEffect(() => { + if (rootTreeId != null) { + managerRef.current?.resetFilters(); + managerRef.current?.addColumnFilter('nodeId', rootTreeId as string); + } + }, [rootTreeId]); + + return ( + + + dataSource={instance.frameworkEvents} + tableManagerRef={managerRef} + columns={columns} + extraActions={ + + + + } + /> + + ); +} + +const columns: DataTableColumn[] = [ + { + key: 'timestamp', + onRender: (row: FrameworkEvent) => { + return new Date(row.timestamp).toLocaleTimeString(); + }, + }, + { + key: 'nodeId', + }, + { + key: 'type', + }, + { + key: 'thread', + }, +]; diff --git a/desktop/plugins/public/ui-debugger/components/Tree.tsx b/desktop/plugins/public/ui-debugger/components/Tree.tsx index 484f16b07..3153d7512 100644 --- a/desktop/plugins/public/ui-debugger/components/Tree.tsx +++ b/desktop/plugins/public/ui-debugger/components/Tree.tsx @@ -13,6 +13,7 @@ import { Id, OnSelectNode, UINode, + ViewMode, } from '../types'; import React, { ReactNode, @@ -52,6 +53,7 @@ import { FullscreenExitOutlined, FullscreenOutlined, SnippetsOutlined, + TableOutlined, } from '@ant-design/icons'; const {Text} = Typography; @@ -216,9 +218,11 @@ export function Tree2({nodes, rootId}: {nodes: Map; rootId: Id}) { text={searchTerm} highlightColor={theme.searchHighlightBackground.yellow}>
; nodes: Map; hoveredNodeId?: Id; focusedNodeId?: Id; onFocusNode: (id?: Id) => void; onContextMenuOpen: (open: boolean) => void; + onSetViewMode: (viewMode: ViewMode) => void; }> = ({ nodes, + frameworkEvents, hoveredNodeId, children, focusedNodeId, onFocusNode, onContextMenuOpen, + onSetViewMode, }) => { const copyItems: ReactNode[] = []; const hoveredNode = nodes.get(hoveredNodeId ?? Number.MAX_SAFE_INTEGER); @@ -579,6 +587,25 @@ const ContextMenu: React.FC<{ }} /> ); + + const matchingFrameworkEvents = + (hoveredNode && + frameworkEvents.getAllRecordsByIndex({nodeId: hoveredNode.id})) ?? + []; + + const frameworkEventsTable = matchingFrameworkEvents.length > 0 && ( + { + onSetViewMode({ + mode: 'frameworkEventsTable', + treeRootId: hoveredNode?.id ?? '', + }); + }} + icon={} + /> + ); + return ( { @@ -588,8 +615,12 @@ const ContextMenu: React.FC<{ {focus} {removeFocus} - {(focus || removeFocus) && } + {frameworkEventsTable} + {(focus || removeFocus || frameworkEventsTable) && ( + + )} {copyItems} + {hoveredNode && } )} diff --git a/desktop/plugins/public/ui-debugger/components/main.tsx b/desktop/plugins/public/ui-debugger/components/main.tsx index 01c76fbd3..4d9851eb4 100644 --- a/desktop/plugins/public/ui-debugger/components/main.tsx +++ b/desktop/plugins/public/ui-debugger/components/main.tsx @@ -28,6 +28,7 @@ import {QueryClientProvider} from 'react-query'; import {Tree2} from './Tree'; import {StreamInterceptorErrorView} from './StreamInterceptorErrorView'; import {queryClient} from '../reactQuery'; +import {FrameworkEventsTable} from './FrameworkEventsTable'; export function Component() { const instance = usePlugin(plugin); @@ -41,6 +42,7 @@ export function Component() { useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show)); + const viewMode = useValue(instance.uiState.viewMode); const [bottomPanelComponent, setBottomPanelComponent] = useState< ReactNode | undefined >(); @@ -96,49 +98,53 @@ export function Component() { ); - } else { - return ( - - - - <> - - - - - { - instance.uiActions.setVisualiserWidth(width); - }} - gutter> - - - - - - - - - {bottomPanelComponent} - - - - - ); } + + if (viewMode.mode === 'frameworkEventsTable') { + return ; + } + + return ( + + + + <> + + + + + { + instance.uiActions.setVisualiserWidth(width); + }} + gutter> + + + + + + + + + {bottomPanelComponent} + + + + + ); } export function Centered(props: {children: React.ReactNode}) { diff --git a/desktop/plugins/public/ui-debugger/index.tsx b/desktop/plugins/public/ui-debugger/index.tsx index 7e4a95631..db3d78ee6 100644 --- a/desktop/plugins/public/ui-debugger/index.tsx +++ b/desktop/plugins/public/ui-debugger/index.tsx @@ -31,6 +31,7 @@ import { UIActions, UINode, UIState, + ViewMode, } from './types'; import {Draft} from 'immer'; import {tracker} from './tracker'; @@ -202,6 +203,8 @@ export function plugin(client: PluginClient) { const uiState: UIState = { isConnected: createState(false), + viewMode: createState({mode: 'default'}), + //used to disabled hover effects which cause rerenders and mess up the existing context menu isContextMenuOpen: createState(false), @@ -461,6 +464,10 @@ function uiActions(uiState: UIState, nodes: Atom>): UIActions { uiState.filterMainThreadMonitoring.set(toggled); }; + const onSetViewMode = (viewMode: ViewMode) => { + uiState.viewMode.set(viewMode); + }; + return { onExpandNode, onCollapseNode, @@ -470,6 +477,7 @@ function uiActions(uiState: UIState, nodes: Atom>): UIActions { onFocusNode, setVisualiserWidth, onSetFilterMainThreadMonitoring, + onSetViewMode, }; } diff --git a/desktop/plugins/public/ui-debugger/types.tsx b/desktop/plugins/public/ui-debugger/types.tsx index f1a7e4da5..faf9d2800 100644 --- a/desktop/plugins/public/ui-debugger/types.tsx +++ b/desktop/plugins/public/ui-debugger/types.tsx @@ -10,6 +10,7 @@ import {Atom} from 'flipper-plugin'; export type UIState = { + viewMode: Atom; isConnected: Atom; isPaused: Atom; streamState: Atom; @@ -25,6 +26,10 @@ export type UIState = { filterMainThreadMonitoring: Atom; }; +export type ViewMode = + | {mode: 'default'} + | {mode: 'frameworkEventsTable'; treeRootId: Id}; + export type NodeSelection = { id: Id; source: SelectionSource; @@ -44,7 +49,9 @@ export type UIActions = { onCollapseNode: (node: Id) => void; setVisualiserWidth: (width: number) => void; onSetFilterMainThreadMonitoring: (toggled: boolean) => void; + onSetViewMode: (viewMode: ViewMode) => void; }; + export type SelectionSource = 'visualiser' | 'tree' | 'keyboard'; export type StreamState =