From b184500d943e77e0f75e8e0454f8fefc183c5b0a Mon Sep 17 00:00:00 2001 From: Luke De Feo Date: Thu, 26 Oct 2023 05:24:30 -0700 Subject: [PATCH] New sidebar design 1/n Summary: Added basic infra basic types Reviewed By: lblasa Differential Revision: D50595985 fbshipit-source-id: 48ebd74bd8ccebdd8a6d69dbda344b8d831dc04f --- .../public/ui-debugger/DesktopTypes.tsx | 2 + .../public/ui-debugger/components/main.tsx | 11 +- .../components/sidebar/Inspector.tsx | 2 +- .../inspector/FrameworkEventsInspector.tsx | 4 +- .../sidebarV2/AttributesInspector.tsx | 329 ++++++++++++++++++ .../components/sidebarV2/SidebarV2.tsx | 82 +++++ .../plugins/public/ui-debugger/package.json | 1 + 7 files changed, 423 insertions(+), 8 deletions(-) create mode 100644 desktop/plugins/public/ui-debugger/components/sidebarV2/AttributesInspector.tsx create mode 100644 desktop/plugins/public/ui-debugger/components/sidebarV2/SidebarV2.tsx diff --git a/desktop/plugins/public/ui-debugger/DesktopTypes.tsx b/desktop/plugins/public/ui-debugger/DesktopTypes.tsx index b79f8a228..2536de954 100644 --- a/desktop/plugins/public/ui-debugger/DesktopTypes.tsx +++ b/desktop/plugins/public/ui-debugger/DesktopTypes.tsx @@ -18,6 +18,7 @@ import { ClientNode, Metadata, SnapshotInfo, + MetadataId, } from './ClientTypes'; import TypedEmitter from 'typed-emitter'; @@ -26,6 +27,7 @@ export type LiveClientState = { nodes: Map; }; +export type MetadataMap = Map; export type Color = string; export type UIState = { diff --git a/desktop/plugins/public/ui-debugger/components/main.tsx b/desktop/plugins/public/ui-debugger/components/main.tsx index fc3ab0f22..2d13722ef 100644 --- a/desktop/plugins/public/ui-debugger/components/main.tsx +++ b/desktop/plugins/public/ui-debugger/components/main.tsx @@ -21,7 +21,6 @@ import {useHotkeys} from 'react-hotkeys-hook'; import {Id, Metadata, MetadataId, ClientNode} from '../ClientTypes'; import {PerfStats} from './PerfStats'; import {Visualization2D} from './visualizer/Visualization2D'; -import {Inspector} from './sidebar/Inspector'; import {TreeControls} from './tree/TreeControls'; import {Button, Spin, Typography} from 'antd'; import {QueryClientProvider} from 'react-query'; @@ -30,6 +29,8 @@ import {StreamInterceptorErrorView} from './StreamInterceptorErrorView'; import {queryClient} from '../utils/reactQuery'; import {FrameworkEventsTable} from './FrameworkEventsTable'; import {Centered} from './shared/Centered'; +import {SidebarV2} from './sidebarV2/SidebarV2'; +import {getNode} from '../utils/map'; export function Component() { const instance = usePlugin(plugin); @@ -38,6 +39,7 @@ export function Component() { const visualiserWidth = useValue(instance.uiState.visualiserWidth); const nodes: Map = useValue(instance.nodes); const metadata: Map = useValue(instance.metadata); + const selectedNodeId = useValue(instance.uiState.selectedNode); const [showPerfStats, setShowPerfStats] = useState(false); @@ -155,11 +157,10 @@ export function Component() { /> - diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx index 9a7a0c620..94c7c7dae 100644 --- a/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx +++ b/desktop/plugins/public/ui-debugger/components/sidebar/Inspector.tsx @@ -126,7 +126,7 @@ export const Inspector: React.FC = ({ frameworkEventMetadata={frameworkEventMetadata} node={selectedNode} events={selectedFrameworkEvents} - showExtra={showExtra} + showBottomPanel={showExtra} /> )} diff --git a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/FrameworkEventsInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/FrameworkEventsInspector.tsx index 36dd25a1a..f904fcfde 100644 --- a/desktop/plugins/public/ui-debugger/components/sidebar/inspector/FrameworkEventsInspector.tsx +++ b/desktop/plugins/public/ui-debugger/components/sidebar/inspector/FrameworkEventsInspector.tsx @@ -42,7 +42,7 @@ import {tracker} from '../../../utils/tracker'; type Props = { node: ClientNode; events: readonly FrameworkEvent[]; - showExtra?: (title: string, element: ReactNode) => void; + showBottomPanel?: (title: string, element: ReactNode) => void; frameworkEventMetadata: Map; onSetViewMode: (viewMode: ViewMode) => void; }; @@ -50,7 +50,7 @@ type Props = { export const FrameworkEventsInspector: React.FC = ({ node, events, - showExtra, + showBottomPanel: showExtra, frameworkEventMetadata, onSetViewMode, }) => { diff --git a/desktop/plugins/public/ui-debugger/components/sidebarV2/AttributesInspector.tsx b/desktop/plugins/public/ui-debugger/components/sidebarV2/AttributesInspector.tsx new file mode 100644 index 000000000..cbde1cfa3 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebarV2/AttributesInspector.tsx @@ -0,0 +1,329 @@ +/** + * 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 {Input, Typography} from 'antd'; +import {Panel, theme, Layout} from 'flipper-plugin'; +import React from 'react'; +import { + ClientNode, + Inspectable, + InspectableObject, + Metadata, +} from '../../ClientTypes'; +import {MetadataMap} from '../../DesktopTypes'; +import {NoData} from '../sidebar/inspector/NoData'; +import {css, cx} from '@emotion/css'; +import {upperFirst} from 'lodash'; + +export function AttributesInspector({ + node, + metadata, +}: { + node: ClientNode; + metadata: MetadataMap; +}) { + const keys = Object.keys(node.attributes); + const sections = keys + .map((key, _) => { + /** + * The node top-level attributes refer to the displayable panels. + * The panel name is obtained by querying the metadata. + * The inspectable contains the actual attributes belonging to each panel. + */ + const metadataId: number = Number(key); + const sectionMetadata = metadata.get(metadataId); + if (sectionMetadata == null) { + return null; + } + const sectionAttributes = node.attributes[ + metadataId + ] as InspectableObject; + + return AttributeSection( + metadata, + sectionMetadata.name, + sectionAttributes, + ); + }) + .filter((section) => section != null); + + if (sections.length === 0) { + return ; + } + return <>{sections}; +} + +function AttributeSection( + metadataMap: MetadataMap, + name: string, + inspectable: InspectableObject, +) { + const children = Object.keys(inspectable.fields) + .map((key) => { + const metadataId: number = Number(key); + const attributeMetadata = metadataMap.get(metadataId); + + if (attributeMetadata == null) { + return null; + } + const attributeValue = inspectable.fields[metadataId]; + + const attributeName = + upperFirst(attributeMetadata?.name) ?? String(metadataId); + return ( + + + {attributeName} + + + + + + + ); + }) + .filter((attr) => attr != null); + + if (children.length > 0) { + return ( + + + {...children} + + + ); + } else { + return null; + } +} + +/** + * disables hover and focsued states + */ +const readOnlyInput = css` + :hover { + border-color: ${theme.disabledColor} !important; + } + :focus { + border-color: ${theme.disabledColor} !important; + + box-shadow: none !important; + } + box-shadow: none !important; + border-color: ${theme.disabledColor} !important; + + padding: 2px 4px 2px 4px; + + min-height: 20px !important; //this is for text area +`; + +function StyledInput({ + value, + color, + mutable, + rightAddon, +}: { + value: any; + color: string; + mutable: boolean; + rightAddon?: string; +}) { + return ( + + ); +} + +function StyledTextArea({ + value, + color, + mutable, +}: { + value: any; + color: string; + mutable: boolean; + rightAddon?: string; +}) { + return ( + + ); +} + +const boolColor = '#C41D7F'; +const stringColor = '#AF5800'; +const enumColor = '#006D75'; +const numberColor = '#003EB3'; + +type NumberGroupValue = {value: number; addonText: string}; + +function NumberGroup({values}: {values: NumberGroupValue[]}) { + return ( + + {values.map(({value, addonText}, idx) => ( + + ))} + + ); +} + +function AttributeValue({ + inspectable, +}: { + attributeMetadata: Metadata; + metadataMap: MetadataMap; + name: string; + inspectable: Inspectable; + level: number; +}) { + switch (inspectable.type) { + case 'boolean': + return ( + + ); + case 'text': + return ( + + ); + case 'number': + return ( + + ); + + case 'enum': + return ( + + ); + case 'size': + return ( + + ); + + case 'coordinate': + return ( + + ); + case 'coordinate3d': + return ( + + ); + case 'space': + return ( + + + + + ); + case 'bounds': + return ( + + + + + ); + } + return null; +} diff --git a/desktop/plugins/public/ui-debugger/components/sidebarV2/SidebarV2.tsx b/desktop/plugins/public/ui-debugger/components/sidebarV2/SidebarV2.tsx new file mode 100644 index 000000000..c65877e82 --- /dev/null +++ b/desktop/plugins/public/ui-debugger/components/sidebarV2/SidebarV2.tsx @@ -0,0 +1,82 @@ +/** + * 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 {ClientNode, MetadataId, Metadata} from '../../ClientTypes'; +import {plugin} from '../../index'; +import React, {ReactNode} from 'react'; +import {Layout, Tab, Tabs, usePlugin, useValue} from 'flipper-plugin'; +import {NoData} from '../sidebar/inspector/NoData'; +import {Tooltip} from 'antd'; +import {AttributesInspector} from './AttributesInspector'; +import {FrameworkEventsInspector} from '../sidebar/inspector/FrameworkEventsInspector'; +import {theme} from 'flipper-plugin'; +// eslint-disable-next-line rulesdir/no-restricted-imports-clone +import {Glyph} from 'flipper'; + +type Props = { + selectedNode?: ClientNode; + metadata: Map; + showBottomPanel: (title: string, element: ReactNode) => void; +}; +export function SidebarV2({selectedNode, metadata, showBottomPanel}: Props) { + const instance = usePlugin(plugin); + + const frameworkEventMetadata = useValue(instance.frameworkEventMetadata); + + if (!selectedNode) { + return ; + } + const selectedFrameworkEvents = selectedNode.id + ? instance.frameworkEvents.getAllRecordsByIndex({nodeId: selectedNode.id}) + : []; + + return ( + + + + + + + + }> + + + {selectedFrameworkEvents?.length > 0 && ( + + + + + + }> + + + )} + + + ); +} diff --git a/desktop/plugins/public/ui-debugger/package.json b/desktop/plugins/public/ui-debugger/package.json index b6e9d8e5c..8326f56f8 100644 --- a/desktop/plugins/public/ui-debugger/package.json +++ b/desktop/plugins/public/ui-debugger/package.json @@ -33,6 +33,7 @@ "peerDependencies": { "@ant-design/icons": "*", "@emotion/styled": "*", + "@emotion/css": "*", "@types/node": "*", "@types/react": "*", "@types/react-dom": "*",