Extract framework event tree select
Summary: we will reuse this Reviewed By: lblasa Differential Revision: D48318965 fbshipit-source-id: a5d04481a02e18a2d709f79524aa7449a5b87844
This commit is contained in:
committed by
Facebook GitHub Bot
parent
d5814ea17c
commit
7b6aff245a
@@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
* 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 {TreeSelect} from 'antd';
|
||||||
|
import {FrameworkEventType} from '../../ClientTypes';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export function FrameworkEventsTreeSelect({
|
||||||
|
treeData,
|
||||||
|
onSetEventSelected,
|
||||||
|
selected,
|
||||||
|
placeholder,
|
||||||
|
}: {
|
||||||
|
placeholder: string;
|
||||||
|
selected: string[];
|
||||||
|
treeData: TreeSelectNode[];
|
||||||
|
onSetEventSelected: (
|
||||||
|
eventType: FrameworkEventType,
|
||||||
|
selected: boolean,
|
||||||
|
) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<TreeSelect
|
||||||
|
treeCheckable
|
||||||
|
showSearch={false}
|
||||||
|
showCheckedStrategy={TreeSelect.SHOW_PARENT}
|
||||||
|
placeholder={placeholder}
|
||||||
|
virtual={false} //for scrollbar
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
treeData={treeData}
|
||||||
|
treeDefaultExpandAll
|
||||||
|
value={selected}
|
||||||
|
onSelect={(_: any, node: any) => {
|
||||||
|
for (const leaf of getAllLeaves(node)) {
|
||||||
|
onSetEventSelected(leaf, true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDeselect={(_: any, node: any) => {
|
||||||
|
for (const leaf of getAllLeaves(node)) {
|
||||||
|
onSetEventSelected(leaf, false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type TreeSelectNode = {
|
||||||
|
title: string;
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
children: TreeSelectNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In tree select you can select a parent which implicitly selects all children, we find them all here as the real state
|
||||||
|
* is in terms of the leaf nodes
|
||||||
|
*/
|
||||||
|
function getAllLeaves(treeSelectNode: TreeSelectNode) {
|
||||||
|
const result: string[] = [];
|
||||||
|
function getAllLeavesRec(node: TreeSelectNode) {
|
||||||
|
if (node.children.length > 0) {
|
||||||
|
for (const child of node.children) {
|
||||||
|
getAllLeavesRec(child);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.push(node.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getAllLeavesRec(treeSelectNode);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* transformed flat event type data structure into tree
|
||||||
|
*/
|
||||||
|
export function buildTreeSelectData(eventTypes: string[]): TreeSelectNode[] {
|
||||||
|
const root: TreeSelectNode = buildTreeSelectNode('root', 'root');
|
||||||
|
|
||||||
|
eventTypes.forEach((eventType) => {
|
||||||
|
const eventSubtypes = eventType.split(':');
|
||||||
|
let currentNode = root;
|
||||||
|
|
||||||
|
// Find the parent node for the current id
|
||||||
|
for (let i = 0; i < eventSubtypes.length - 1; i++) {
|
||||||
|
let foundChild = false;
|
||||||
|
for (const child of currentNode.children) {
|
||||||
|
if (child.title === eventSubtypes[i]) {
|
||||||
|
currentNode = child;
|
||||||
|
foundChild = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundChild) {
|
||||||
|
const newNode: TreeSelectNode = buildTreeSelectNode(
|
||||||
|
eventSubtypes[i],
|
||||||
|
eventSubtypes.slice(0, i + 1).join(':'),
|
||||||
|
);
|
||||||
|
|
||||||
|
currentNode.children.push(newNode);
|
||||||
|
currentNode = newNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the current id as a child of the parent node
|
||||||
|
currentNode.children.push(
|
||||||
|
buildTreeSelectNode(
|
||||||
|
eventSubtypes[eventSubtypes.length - 1],
|
||||||
|
eventSubtypes.slice(0, eventSubtypes.length).join(':'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return root.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTreeSelectNode(title: string, fullValue: string): TreeSelectNode {
|
||||||
|
return {
|
||||||
|
title: title,
|
||||||
|
key: fullValue,
|
||||||
|
value: fullValue,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,16 +9,7 @@
|
|||||||
|
|
||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {plugin} from '../../index';
|
import {plugin} from '../../index';
|
||||||
import {
|
import {Button, Input, Modal, Tooltip, Typography, Space, Switch} from 'antd';
|
||||||
Button,
|
|
||||||
Input,
|
|
||||||
Modal,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
TreeSelect,
|
|
||||||
Space,
|
|
||||||
Switch,
|
|
||||||
} from 'antd';
|
|
||||||
import {
|
import {
|
||||||
EyeOutlined,
|
EyeOutlined,
|
||||||
PauseCircleOutlined,
|
PauseCircleOutlined,
|
||||||
@@ -27,6 +18,10 @@ import {
|
|||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {usePlugin, useValue, Layout} from 'flipper-plugin';
|
import {usePlugin, useValue, Layout} from 'flipper-plugin';
|
||||||
import {FrameworkEventType} from '../../ClientTypes';
|
import {FrameworkEventType} from '../../ClientTypes';
|
||||||
|
import {
|
||||||
|
buildTreeSelectData,
|
||||||
|
FrameworkEventsTreeSelect,
|
||||||
|
} from '../shared/FrameworkEventsTreeSelect';
|
||||||
|
|
||||||
export const TreeControls: React.FC = () => {
|
export const TreeControls: React.FC = () => {
|
||||||
const instance = usePlugin(plugin);
|
const instance = usePlugin(plugin);
|
||||||
@@ -133,28 +128,11 @@ function FrameworkEventsMonitoringModal({
|
|||||||
of matching events in the tree
|
of matching events in the tree
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
|
|
||||||
<TreeSelect
|
<FrameworkEventsTreeSelect
|
||||||
treeCheckable
|
|
||||||
showSearch={false}
|
|
||||||
showCheckedStrategy={TreeSelect.SHOW_PARENT}
|
|
||||||
placeholder="Select node types to monitor"
|
placeholder="Select node types to monitor"
|
||||||
virtual={false} //for scrollbar
|
onSetEventSelected={onSetEventMonitored}
|
||||||
style={{
|
selected={selectedFrameworkEvents}
|
||||||
width: '100%',
|
|
||||||
}}
|
|
||||||
treeData={treeData}
|
treeData={treeData}
|
||||||
treeDefaultExpandAll
|
|
||||||
value={selectedFrameworkEvents}
|
|
||||||
onSelect={(_: any, node: any) => {
|
|
||||||
for (const leaf of getAllLeaves(node)) {
|
|
||||||
onSetEventMonitored(leaf, true);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onDeselect={(_: any, node: any) => {
|
|
||||||
for (const leaf of getAllLeaves(node)) {
|
|
||||||
onSetEventMonitored(leaf, false);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Layout.Horizontal gap="medium">
|
<Layout.Horizontal gap="medium">
|
||||||
@@ -172,80 +150,3 @@ function FrameworkEventsMonitoringModal({
|
|||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type TreeSelectNode = {
|
|
||||||
title: string;
|
|
||||||
key: string;
|
|
||||||
value: string;
|
|
||||||
children: TreeSelectNode[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In tree select you can select a parent which implicitly selects all children, we find them all here as the real state
|
|
||||||
* is in terms of the leaf nodes
|
|
||||||
*/
|
|
||||||
function getAllLeaves(treeSelectNode: TreeSelectNode) {
|
|
||||||
const result: string[] = [];
|
|
||||||
function getAllLeavesRec(node: TreeSelectNode) {
|
|
||||||
if (node.children.length > 0) {
|
|
||||||
for (const child of node.children) {
|
|
||||||
getAllLeavesRec(child);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.push(node.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getAllLeavesRec(treeSelectNode);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* transformed flat event type data structure into tree
|
|
||||||
*/
|
|
||||||
function buildTreeSelectData(eventTypes: string[]): TreeSelectNode[] {
|
|
||||||
const root: TreeSelectNode = buildTreeSelectNode('root', 'root');
|
|
||||||
|
|
||||||
eventTypes.forEach((eventType) => {
|
|
||||||
const eventSubtypes = eventType.split(':');
|
|
||||||
let currentNode = root;
|
|
||||||
|
|
||||||
// Find the parent node for the current id
|
|
||||||
for (let i = 0; i < eventSubtypes.length - 1; i++) {
|
|
||||||
let foundChild = false;
|
|
||||||
for (const child of currentNode.children) {
|
|
||||||
if (child.title === eventSubtypes[i]) {
|
|
||||||
currentNode = child;
|
|
||||||
foundChild = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!foundChild) {
|
|
||||||
const newNode: TreeSelectNode = buildTreeSelectNode(
|
|
||||||
eventSubtypes[i],
|
|
||||||
eventSubtypes.slice(0, i + 1).join(':'),
|
|
||||||
);
|
|
||||||
|
|
||||||
currentNode.children.push(newNode);
|
|
||||||
currentNode = newNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add the current id as a child of the parent node
|
|
||||||
currentNode.children.push(
|
|
||||||
buildTreeSelectNode(
|
|
||||||
eventSubtypes[eventSubtypes.length - 1],
|
|
||||||
eventSubtypes.slice(0, eventSubtypes.length).join(':'),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return root.children;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildTreeSelectNode(title: string, fullValue: string): TreeSelectNode {
|
|
||||||
return {
|
|
||||||
title: title,
|
|
||||||
key: fullValue,
|
|
||||||
value: fullValue,
|
|
||||||
children: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user