Add ui-debugger modes

Summary:
## This diff: Add debugger mode infrastructure

We want to enable infrastructure allowing adding modes in the future without branching client and plugin code

This infra allows for the client to send a message informing flipper about the supported modes (following diffs)

Currently broadcasting mode change event over to the client

Reviewed By: lblasa

Differential Revision: D49385860

fbshipit-source-id: 2db6f65064d1ff7e1f57b2da93c3ed195400fb7f
This commit is contained in:
Sash Zats
2023-09-20 11:37:12 -07:00
committed by Facebook GitHub Bot
parent c3ad4f7180
commit 1c3720fd5c
6 changed files with 104 additions and 4 deletions

View File

@@ -7,6 +7,8 @@
* @format * @format
*/ */
import {TraversalMode} from './DesktopTypes';
export type Events = { export type Events = {
init: InitEvent; init: InitEvent;
subtreeUpdate: SubtreeUpdateEvent; subtreeUpdate: SubtreeUpdateEvent;
@@ -14,6 +16,11 @@ export type Events = {
perfStats: PerfStatsEvent; perfStats: PerfStatsEvent;
performanceStats: PerformanceStatsEvent; performanceStats: PerformanceStatsEvent;
metadataUpdate: UpdateMetadataEvent; metadataUpdate: UpdateMetadataEvent;
setTraversalMode: SetTraversalModeEvent;
};
export type SetTraversalModeEvent = {
mode: TraversalMode;
}; };
export type FrameScanEvent = { export type FrameScanEvent = {
@@ -69,6 +76,8 @@ export type FrameworkEvent = {
export type InitEvent = { export type InitEvent = {
rootId: Id; rootId: Id;
frameworkEventMetadata?: FrameworkEventMetadata[]; frameworkEventMetadata?: FrameworkEventMetadata[];
supportedTraversalModes?: TraversalMode[];
currentTraversalMode?: TraversalMode;
}; };
/** /**
@@ -110,6 +119,10 @@ export type UpdateMetadataEvent = {
attributeMetadata: Record<MetadataId, Metadata>; attributeMetadata: Record<MetadataId, Metadata>;
}; };
export type UpdateAvailableTraversalModeEvent = {
modes: TraversalMode[];
};
export type ClientNode = { export type ClientNode = {
id: Id; id: Id;
parent?: Id; parent?: Id;

View File

@@ -42,6 +42,9 @@ export type UIState = {
visualiserWidth: Atom<number>; visualiserWidth: Atom<number>;
frameworkEventMonitoring: Atom<Map<FrameworkEventType, boolean>>; frameworkEventMonitoring: Atom<Map<FrameworkEventType, boolean>>;
filterMainThreadMonitoring: Atom<boolean>; filterMainThreadMonitoring: Atom<boolean>;
supportedTraversalModes: Atom<TraversalMode[]>;
currentTraversalMode: Atom<TraversalMode>;
}; };
//enumerates the keys of input type and casts each to ReadOnlyAtom, this is so we only expose read only atoms to the UI //enumerates the keys of input type and casts each to ReadOnlyAtom, this is so we only expose read only atoms to the UI
@@ -66,6 +69,8 @@ export type NestedNode = {
activeChildIdx?: number; activeChildIdx?: number;
}; };
export type TraversalMode = 'view-hierarchy' | 'accessibility-hierarchy';
export type ViewMode = export type ViewMode =
| {mode: 'default'} | {mode: 'default'}
| {mode: 'frameworkEventsTable'; nodeId: Id; isTree: boolean}; | {mode: 'frameworkEventsTable'; nodeId: Id; isTree: boolean};
@@ -106,6 +111,7 @@ export type UIActions = {
onCollapseAllNonAncestors: (nodeId: Id) => void; onCollapseAllNonAncestors: (nodeId: Id) => void;
onCollapseAllRecursively: (nodeId: Id) => void; onCollapseAllRecursively: (nodeId: Id) => void;
ensureAncestorsExpanded: (nodeId: Id) => void; ensureAncestorsExpanded: (nodeId: Id) => void;
setCurrentTraversalMode: (mode: TraversalMode) => void;
}; };
export type SelectionSource = export type SelectionSource =

View File

@@ -18,10 +18,12 @@ import {
Space, Space,
Switch, Switch,
Badge, Badge,
Dropdown,
} from 'antd'; } from 'antd';
import { import {
EyeOutlined, EyeOutlined,
PauseCircleOutlined, PauseCircleOutlined,
AppstoreOutlined,
PlayCircleOutlined, PlayCircleOutlined,
SearchOutlined, SearchOutlined,
} from '@ant-design/icons'; } from '@ant-design/icons';
@@ -31,6 +33,7 @@ import {
buildTreeSelectData, buildTreeSelectData,
FrameworkEventsTreeSelect, FrameworkEventsTreeSelect,
} from '../shared/FrameworkEventsTreeSelect'; } from '../shared/FrameworkEventsTreeSelect';
import {TraversalMode} from '../../DesktopTypes';
export const TreeControls: React.FC = () => { export const TreeControls: React.FC = () => {
const instance = usePlugin(plugin); const instance = usePlugin(plugin);
@@ -44,13 +47,50 @@ export const TreeControls: React.FC = () => {
instance.uiState.frameworkEventMonitoring, instance.uiState.frameworkEventMonitoring,
); );
const frameworkEventMetadata = useValue(instance.frameworkEventMetadata);
const [showFrameworkEventsModal, setShowFrameworkEventsModal] = const [showFrameworkEventsModal, setShowFrameworkEventsModal] =
useState(false); useState(false);
const frameworkEventMetadata = useValue(instance.frameworkEventMetadata);
const currentTraversalMode = useValue(instance.uiState.currentTraversalMode);
const supportedTraversalModes = useValue(
instance.uiState.supportedTraversalModes,
);
const labelForMode = (mode: TraversalMode) => {
switch (mode) {
case 'view-hierarchy':
return 'UI Hierarchy';
case 'accessibility-hierarchy':
return 'Accessibility Hierarchy';
}
};
const menus = supportedTraversalModes.map((mode) => ({
key: mode,
label: labelForMode(mode),
}));
return ( return (
<Layout.Horizontal gap="medium" pad="medium"> <Layout.Horizontal gap="medium" pad="medium">
{supportedTraversalModes.length > 1 ? (
<Dropdown
menu={{
selectable: true,
selectedKeys: [currentTraversalMode],
items: menus,
onSelect: async (event) => {
const mode = event.selectedKeys[0] as TraversalMode;
instance.uiActions.setCurrentTraversalMode(mode); // update UI
await instance.onTraversalModeChange(mode); // update mobile client
},
}}>
<Tooltip title="Debugger Mode">
<Button shape="circle">
<AppstoreOutlined />
</Button>
</Tooltip>
</Dropdown>
) : null}
<Input <Input
value={searchTerm} value={searchTerm}
onChange={(e) => { onChange={(e) => {

View File

@@ -23,6 +23,7 @@ import {
import { import {
UIState, UIState,
NodeSelection, NodeSelection,
TraversalMode,
StreamState, StreamState,
ReadOnlyUIState, ReadOnlyUIState,
LiveClientState, LiveClientState,
@@ -38,7 +39,15 @@ import {uiActions} from './plugin/uiActions';
import {first} from 'lodash'; import {first} from 'lodash';
import {getNode} from './utils/map'; import {getNode} from './utils/map';
export function plugin(client: PluginClient<Events>) { type TraversalModeChangeEvent = {
mode: TraversalMode;
};
export type Methods = {
onTraversalModeChange(params: TraversalModeChangeEvent): Promise<void>;
};
export function plugin(client: PluginClient<Events, Methods>) {
const rootId = createState<Id | undefined>(undefined); const rootId = createState<Id | undefined>(undefined);
const metadata = createState<Map<MetadataId, Metadata>>(new Map()); const metadata = createState<Map<MetadataId, Metadata>>(new Map());
@@ -87,6 +96,22 @@ export function plugin(client: PluginClient<Events>) {
draft.set(frameworkEventMeta.type, false); draft.set(frameworkEventMeta.type, false);
}); });
}); });
if (
event.supportedTraversalModes &&
event.supportedTraversalModes.length > 1
) {
uiState.supportedTraversalModes.set(event.supportedTraversalModes);
}
if (
event.currentTraversalMode &&
uiState.supportedTraversalModes.get().includes(event.currentTraversalMode)
) {
uiState.currentTraversalMode.set(event.currentTraversalMode);
console.log(
`[ui-debugger] Unsupported debugger mode ${event.currentTraversalMode}.`,
);
}
frameworkEventMetadata.update((draft) => { frameworkEventMetadata.update((draft) => {
event.frameworkEventMetadata?.forEach((frameworkEventMeta) => { event.frameworkEventMetadata?.forEach((frameworkEventMeta) => {
draft.set(frameworkEventMeta.type, frameworkEventMeta); draft.set(frameworkEventMeta.type, frameworkEventMeta);
@@ -256,6 +281,9 @@ export function plugin(client: PluginClient<Events>) {
}); });
client.onMessage('frameScan', processFrame); client.onMessage('frameScan', processFrame);
const onTraversalModeChange = async (mode: TraversalMode) =>
client.send('onTraversalModeChange', {mode});
return { return {
rootId, rootId,
uiState: uiState as ReadOnlyUIState, uiState: uiState as ReadOnlyUIState,
@@ -268,6 +296,7 @@ export function plugin(client: PluginClient<Events>) {
metadata, metadata,
perfEvents, perfEvents,
os: client.device.os, os: client.device.os,
onTraversalModeChange,
}; };
} }
@@ -308,5 +337,9 @@ function createUIState(): UIState {
focusedNode: createState<Id | undefined>(undefined), focusedNode: createState<Id | undefined>(undefined),
expandedNodes: createState<Set<Id>>(new Set()), expandedNodes: createState<Set<Id>>(new Set()),
wireFrameMode: createState<WireFrameMode>('All'), wireFrameMode: createState<WireFrameMode>('All'),
// view-hierarchy is the default state so we start with it until we fetch supported modes from the client
supportedTraversalModes: createState<TraversalMode[]>(['view-hierarchy']),
currentTraversalMode: createState<TraversalMode>('view-hierarchy'),
}; };
} }

View File

@@ -11,6 +11,7 @@ import {Atom} from 'flipper-plugin';
import {debounce} from 'lodash'; import {debounce} from 'lodash';
import {ClientNode, FrameworkEventType, Id, SnapshotInfo} from '../ClientTypes'; import {ClientNode, FrameworkEventType, Id, SnapshotInfo} from '../ClientTypes';
import { import {
TraversalMode,
LiveClientState, LiveClientState,
SelectionSource, SelectionSource,
UIActions, UIActions,
@@ -189,6 +190,11 @@ export function uiActions(
searchTermUpdatedDebounced(searchTerm); searchTermUpdatedDebounced(searchTerm);
}; };
const setCurrentTraversalMode = (mode: TraversalMode) => {
tracker.track('traversal-mode-updated', {mode});
uiState.currentTraversalMode.set(mode);
};
return { return {
onExpandNode, onExpandNode,
onCollapseNode, onCollapseNode,
@@ -207,5 +213,6 @@ export function uiActions(
onExpandAllRecursively, onExpandAllRecursively,
onCollapseAllRecursively, onCollapseAllRecursively,
ensureAncestorsExpanded, ensureAncestorsExpanded,
setCurrentTraversalMode,
}; };
} }

View File

@@ -10,7 +10,7 @@
import {getFlipperLib} from 'flipper-plugin'; import {getFlipperLib} from 'flipper-plugin';
import {FrameworkEventType, Tag} from '../ClientTypes'; import {FrameworkEventType, Tag} from '../ClientTypes';
import {SelectionSource} from '../DesktopTypes'; import {TraversalMode, SelectionSource} from '../DesktopTypes';
const UI_DEBUGGER_IDENTIFIER = 'ui-debugger'; const UI_DEBUGGER_IDENTIFIER = 'ui-debugger';
@@ -67,6 +67,7 @@ type TrackerEvents = {
'context-menu-expand-recursive': {}; 'context-menu-expand-recursive': {};
'context-menu-collapse-recursive': {}; 'context-menu-collapse-recursive': {};
'context-menu-collapse-non-ancestors': {}; 'context-menu-collapse-non-ancestors': {};
'traversal-mode-updated': {mode: TraversalMode};
}; };
export interface Tracker { export interface Tracker {