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
216 lines
6.2 KiB
TypeScript
216 lines
6.2 KiB
TypeScript
/**
|
|
* 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 React, {useState} from 'react';
|
|
import {plugin} from '../../index';
|
|
import {
|
|
Button,
|
|
Input,
|
|
Modal,
|
|
Tooltip,
|
|
Typography,
|
|
Space,
|
|
Switch,
|
|
Badge,
|
|
Dropdown,
|
|
} from 'antd';
|
|
import {
|
|
EyeOutlined,
|
|
PauseCircleOutlined,
|
|
AppstoreOutlined,
|
|
PlayCircleOutlined,
|
|
SearchOutlined,
|
|
} from '@ant-design/icons';
|
|
import {usePlugin, useValue, Layout} from 'flipper-plugin';
|
|
import {FrameworkEventMetadata, FrameworkEventType} from '../../ClientTypes';
|
|
import {
|
|
buildTreeSelectData,
|
|
FrameworkEventsTreeSelect,
|
|
} from '../shared/FrameworkEventsTreeSelect';
|
|
import {TraversalMode} from '../../DesktopTypes';
|
|
|
|
export const TreeControls: React.FC = () => {
|
|
const instance = usePlugin(plugin);
|
|
const searchTerm = useValue(instance.uiState.searchTerm);
|
|
const isPaused = useValue(instance.uiState.isPaused);
|
|
const filterMainThreadMonitoring = useValue(
|
|
instance.uiState.filterMainThreadMonitoring,
|
|
);
|
|
|
|
const frameworkEventMonitoring: Map<FrameworkEventType, boolean> = useValue(
|
|
instance.uiState.frameworkEventMonitoring,
|
|
);
|
|
|
|
const [showFrameworkEventsModal, setShowFrameworkEventsModal] =
|
|
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 (
|
|
<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
|
|
value={searchTerm}
|
|
onChange={(e) => {
|
|
instance.uiActions.onSearchTermUpdated(e.target.value);
|
|
}}
|
|
prefix={<SearchOutlined />}
|
|
placeholder="Search"
|
|
/>
|
|
<Button
|
|
type="default"
|
|
shape="circle"
|
|
onClick={instance.uiActions.onPlayPauseToggled}
|
|
icon={
|
|
<Tooltip
|
|
title={isPaused ? 'Resume live updates' : 'Pause incoming updates'}>
|
|
{isPaused ? <PlayCircleOutlined /> : <PauseCircleOutlined />}
|
|
</Tooltip>
|
|
}></Button>
|
|
{frameworkEventMonitoring.size > 0 && (
|
|
<>
|
|
<Badge
|
|
size="small"
|
|
count={
|
|
[...frameworkEventMonitoring.values()].filter(
|
|
(val) => val === true,
|
|
).length
|
|
}>
|
|
<Button
|
|
type="default"
|
|
shape="circle"
|
|
onClick={() => {
|
|
setShowFrameworkEventsModal(true);
|
|
}}
|
|
icon={
|
|
<Tooltip title="Framework event monitoring">
|
|
<EyeOutlined />
|
|
</Tooltip>
|
|
}></Button>
|
|
</Badge>
|
|
<FrameworkEventsMonitoringModal
|
|
metadata={frameworkEventMetadata}
|
|
filterMainThreadMonitoring={filterMainThreadMonitoring}
|
|
onSetFilterMainThreadMonitoring={
|
|
instance.uiActions.onSetFilterMainThreadMonitoring
|
|
}
|
|
frameworkEventTypes={[...frameworkEventMonitoring.entries()]}
|
|
onSetEventMonitored={
|
|
instance.uiActions.onSetFrameworkEventMonitored
|
|
}
|
|
visible={showFrameworkEventsModal}
|
|
onCancel={() => setShowFrameworkEventsModal(false)}
|
|
/>
|
|
</>
|
|
)}
|
|
</Layout.Horizontal>
|
|
);
|
|
};
|
|
|
|
function FrameworkEventsMonitoringModal({
|
|
visible,
|
|
onCancel,
|
|
onSetEventMonitored,
|
|
onSetFilterMainThreadMonitoring,
|
|
filterMainThreadMonitoring,
|
|
frameworkEventTypes,
|
|
metadata,
|
|
}: {
|
|
metadata: Map<FrameworkEventType, FrameworkEventMetadata>;
|
|
visible: boolean;
|
|
onCancel: () => void;
|
|
onSetEventMonitored: (
|
|
eventType: FrameworkEventType,
|
|
monitored: boolean,
|
|
) => void;
|
|
filterMainThreadMonitoring: boolean;
|
|
onSetFilterMainThreadMonitoring: (toggled: boolean) => void;
|
|
frameworkEventTypes: [FrameworkEventType, boolean][];
|
|
}) {
|
|
const selectedFrameworkEvents = frameworkEventTypes
|
|
.filter(([, selected]) => selected)
|
|
.map(([eventType]) => eventType);
|
|
|
|
const treeData = buildTreeSelectData(
|
|
frameworkEventTypes.map(([type]) => type),
|
|
metadata,
|
|
);
|
|
|
|
return (
|
|
<Modal
|
|
title="Framework event monitoring"
|
|
open={visible}
|
|
footer={null}
|
|
onCancel={onCancel}>
|
|
<Space direction="vertical" size="large">
|
|
<Typography.Text>
|
|
Monitoring an event will cause the relevant node in the visualizer and
|
|
tree to highlight briefly. Additionally counter will show the number
|
|
of matching events in the tree
|
|
</Typography.Text>
|
|
|
|
<FrameworkEventsTreeSelect
|
|
placeholder="Select node types to monitor"
|
|
onSetEventSelected={onSetEventMonitored}
|
|
selected={selectedFrameworkEvents}
|
|
treeData={treeData}
|
|
/>
|
|
|
|
<Layout.Horizontal gap="medium">
|
|
<Switch
|
|
checked={filterMainThreadMonitoring}
|
|
onChange={(event) => {
|
|
onSetFilterMainThreadMonitoring(event);
|
|
}}
|
|
/>
|
|
<Typography.Text>
|
|
Only highlight events that occured on the main thread
|
|
</Typography.Text>
|
|
</Layout.Horizontal>
|
|
</Space>
|
|
</Modal>
|
|
);
|
|
}
|