/** * 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, {ReactNode, useEffect, useRef, useState} from 'react'; import {plugin} from '../index'; import { DetailSidebar, Layout, usePlugin, useValue, _Sidebar as ResizablePanel, theme, } from 'flipper-plugin'; import {useHotkeys} from 'react-hotkeys-hook'; import {Id, Metadata, MetadataId, UINode} from '../types'; import {PerfStats} from './PerfStats'; import {Visualization2D} from './Visualization2D'; import {Inspector} from './sidebar/Inspector'; import {Controls} from './Controls'; import {Button, Spin} from 'antd'; import {QueryClientProvider} from 'react-query'; import {Tree2} from './Tree'; import {StreamInterceptorErrorView} from './StreamInterceptorErrorView'; export function Component() { const instance = usePlugin(plugin); const rootId = useValue(instance.rootId); const streamState = useValue(instance.uiState.streamState); const visualiserWidth = useValue(instance.uiState.visualiserWidth); const nodes: Map = useValue(instance.nodes); const metadata: Map = useValue(instance.metadata); const [showPerfStats, setShowPerfStats] = useState(false); useHotkeys('ctrl+i', () => setShowPerfStats((show) => !show)); const [bottomPanelComponent, setBottomPanelComponent] = useState< ReactNode | undefined >(); const openBottomPanelWithContent = (component: ReactNode) => { setBottomPanelComponent(component); }; const dismissBottomPanel = () => { setBottomPanelComponent(undefined); }; if (showPerfStats) return ( ); if (streamState.state === 'FatalError') { return ( Reset } /> ); } if (streamState.state === 'StreamInterceptorRetryableError') { return ( Retry } /> ); } if (rootId == null || streamState.state === 'RetryingAfterError') { return ( ); } else { return ( <> { instance.uiActions.setVisualiserWidth(width); }} gutter> {bottomPanelComponent} ); } } export function Centered(props: {children: React.ReactNode}) { return ( {props.children} ); } type BottomPanelProps = { dismiss: () => void; children: React.ReactNode; }; export function BottomPanel({dismiss, children}: BottomPanelProps) { const bottomPanelRef = useRef(null); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( bottomPanelRef.current && !bottomPanelRef.current.contains(event.target) ) { dismiss(); } }; // Add event listener when the component is mounted. document.addEventListener('mousedown', handleClickOutside); // Remove event listener when component is unmounted. return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [bottomPanelRef, dismiss]); if (!children) { return <>; } return (
{children}
); }