Files
flipper/desktop/plugins/public/ui-debugger/components/tree/ContextMenu.tsx
Luke De Feo ce1fdfdf19 Added context menu items for collapsing and expanding nodes
Summary:
Added 3 context menu items:
- expand recursive
- collapse recursive

These are self explanatory.

I also collapse non ancestors. This collapses everything except your direct ancestor path to the root. Quite useful to refocus the tree on a node

Changelog: UIDebugger - added  context menu items for exanding and collapsing the tree.

Reviewed By: aigoncharov

Differential Revision: D47949840

fbshipit-source-id: 6eebba182fe2092fbf5f0db0ec5ff728c3900424
2023-08-01 10:32:29 -07:00

199 lines
5.3 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 {FrameworkEvent, Id, ClientNode} from '../../ClientTypes';
import {OnSelectNode, ViewMode} from '../../DesktopTypes';
import React, {ReactNode} from 'react';
import {DataSource, getFlipperLib} from 'flipper-plugin';
import {Dropdown, Menu} from 'antd';
import {UIDebuggerMenuItem} from '../util/UIDebuggerMenuItem';
import {tracker} from '../../utils/tracker';
import {
BigGrepContextMenuItems,
IDEContextMenuItems,
} from '../fb-stubs/IDEContextMenu';
import {
CopyOutlined,
FullscreenExitOutlined,
FullscreenOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
NodeExpandOutlined,
SnippetsOutlined,
TableOutlined,
} from '@ant-design/icons';
export const ContextMenu: React.FC<{
frameworkEvents: DataSource<FrameworkEvent>;
nodes: Map<Id, ClientNode>;
hoveredNodeId?: Id;
focusedNodeId?: Id;
onFocusNode: (id?: Id) => void;
onContextMenuOpen: (open: boolean) => void;
onSetViewMode: (viewMode: ViewMode) => void;
onExpandRecursively: (id: Id) => void;
onCollapseRecursively: (id: Id) => void;
onCollapseNonAncestors: (id: Id) => void;
onSelectNode: OnSelectNode;
}> = ({
nodes,
frameworkEvents,
hoveredNodeId,
children,
focusedNodeId,
onFocusNode,
onContextMenuOpen,
onSetViewMode,
onExpandRecursively,
onCollapseRecursively,
onCollapseNonAncestors,
onSelectNode,
}) => {
const copyItems: ReactNode[] = [];
const hoveredNode = nodes.get(hoveredNodeId ?? Number.MAX_SAFE_INTEGER);
let treeCollapseItems: ReactNode[] = [];
if (hoveredNode) {
treeCollapseItems = [
<UIDebuggerMenuItem
key="expand-recursive"
text="Expand recursively"
icon={<MenuUnfoldOutlined />}
onClick={() => {
onExpandRecursively(hoveredNode.id);
onSelectNode(hoveredNode.id, 'context-menu');
tracker.track('context-menu-expand-recursive', {});
}}
/>,
<UIDebuggerMenuItem
key="collapse-recursive"
text="Collapse recurisvely"
icon={<MenuFoldOutlined />}
onClick={() => {
onCollapseRecursively(hoveredNode.id);
onSelectNode(hoveredNode.id, 'context-menu');
tracker.track('context-menu-collapse-recursive', {});
}}
/>,
<UIDebuggerMenuItem
key="collapse-non-ancestors"
text="Collapse non ancestors"
icon={<NodeExpandOutlined />}
onClick={() => {
onCollapseNonAncestors(hoveredNode.id);
onSelectNode(hoveredNode.id, 'context-menu');
tracker.track('context-menu-collapse-non-ancestors', {});
}}
/>,
<Menu.Divider key="expand-divider" />,
];
copyItems.push(
<UIDebuggerMenuItem
key="Copy Element name"
text="Copy Element name"
icon={<CopyOutlined />}
onClick={() => {
tracker.track('context-menu-name-copied', {name: hoveredNode.name});
getFlipperLib().writeTextToClipboard(hoveredNode.name);
}}
/>,
);
copyItems.push(
Object.entries(hoveredNode.inlineAttributes).map(([key, value]) => (
<UIDebuggerMenuItem
key={key}
text={`Copy ${key}`}
icon={<SnippetsOutlined />}
onClick={() => {
tracker.track('context-menu-copied', {
name: hoveredNode.name,
key,
value,
});
getFlipperLib().writeTextToClipboard(value);
}}
/>
)),
);
copyItems.push(
<BigGrepContextMenuItems key="big-grep" node={hoveredNode} />,
);
}
const focus = hoveredNode != null &&
focusedNodeId !== hoveredNodeId &&
hoveredNode.bounds.height !== 0 &&
hoveredNode.bounds.width !== 0 && (
<UIDebuggerMenuItem
key="focus"
text={`Focus element`}
icon={<FullscreenExitOutlined />}
onClick={() => {
onFocusNode(hoveredNodeId);
}}
/>
);
const removeFocus = focusedNodeId && (
<UIDebuggerMenuItem
key="remove-focus"
text="Remove focus"
icon={<FullscreenOutlined />}
onClick={() => {
onFocusNode(undefined);
}}
/>
);
const matchingFrameworkEvents =
(hoveredNode &&
frameworkEvents.getAllRecordsByIndex({nodeId: hoveredNode.id})) ??
[];
const frameworkEventsTable = matchingFrameworkEvents.length > 0 && (
<UIDebuggerMenuItem
text="Explore events"
onClick={() => {
onSetViewMode({
mode: 'frameworkEventsTable',
treeRootId: hoveredNode?.id ?? '',
});
}}
icon={<TableOutlined />}
/>
);
return (
<Dropdown
onVisibleChange={(visible) => {
onContextMenuOpen(visible);
}}
overlay={() => (
<Menu>
{treeCollapseItems}
{focus}
{removeFocus}
{frameworkEventsTable}
{(focus || removeFocus || frameworkEventsTable) && (
<Menu.Divider key="divider-focus" />
)}
{copyItems}
{hoveredNode && <IDEContextMenuItems key="ide" node={hoveredNode} />}
</Menu>
)}
trigger={['contextMenu']}>
{children}
</Dropdown>
);
};