diff --git a/src/plugins/reactdevtools/index.tsx b/src/plugins/reactdevtools/index.tsx index ad0a0f4f6..cebd089b9 100644 --- a/src/plugins/reactdevtools/index.tsx +++ b/src/plugins/reactdevtools/index.tsx @@ -7,9 +7,8 @@ * @format */ -import ReactDOM from 'react-dom'; import ReactDevToolsStandalone from 'react-devtools-core/standalone'; -import {FlipperPlugin, AndroidDevice, styled} from 'flipper'; +import {FlipperPlugin, AndroidDevice, styled, View, Toolbar} from 'flipper'; import React from 'react'; import getPort from 'get-port'; import address from 'address'; @@ -19,6 +18,7 @@ const Container = styled.div({ flex: '1 1 0%', justifyContent: 'center', alignItems: 'stretch', + height: '100%', }); const DEV_TOOLS_NODE_ID = 'reactdevtools-out-of-react-node'; @@ -43,7 +43,7 @@ function findDevToolsNode(): HTMLElement | null { } function attachDevTools(target: Element | Text, devToolsNode: HTMLElement) { - target.insertBefore(devToolsNode, target.childNodes[0]); + target.appendChild(devToolsNode); devToolsNode.style.display = 'flex'; } @@ -52,27 +52,89 @@ function detachDevTools(devToolsNode: HTMLElement) { document.body && document.body.appendChild(devToolsNode); } -export default class extends FlipperPlugin<{}, any, {}> { +const CONNECTED = 'DevTools connected'; + +export default class extends FlipperPlugin< + { + status: string; + }, + any, + {} +> { + pollHandle?: NodeJS.Timeout; + containerRef: React.RefObject = React.createRef(); + triedToAutoConnect = false; + + state = { + status: 'initializing', + }; + componentDidMount() { let devToolsNode = findDevToolsNode(); if (!devToolsNode) { devToolsNode = createDevToolsNode(); this.initializeDevTools(devToolsNode); + } else { + this.setStatus( + 'DevTools have been initialized, waiting for connection...', + ); + if (devToolsNode.innerHTML) { + this.setStatus(CONNECTED); + } else { + this.startPollForConnection(); + } } - const currentComponentNode = ReactDOM.findDOMNode(this); - currentComponentNode && attachDevTools(currentComponentNode, devToolsNode); + attachDevTools(this.containerRef?.current!, devToolsNode); + this.startPollForConnection(); } componentWillUnmount() { + if (this.pollHandle) { + clearTimeout(this.pollHandle); + } const devToolsNode = findDevToolsNode(); devToolsNode && detachDevTools(devToolsNode); } + setStatus(status: string) { + console.log(`[ReactDevtoolsPlugin] ${status}`); + if (status.startsWith('The server is listening on')) { + this.setState({status: status + ' Waiting for connection...'}); + } else { + this.setState({status}); + } + } + + startPollForConnection() { + this.pollHandle = setTimeout(() => { + if (findDevToolsNode()?.innerHTML) { + this.setStatus(CONNECTED); + } else { + if (!this.triedToAutoConnect) { + this.triedToAutoConnect = true; + this.setStatus( + "The DevTools didn't connect yet. Please open the DevMenu or Reload to connect", + ); + // TODO: send reload command + } + this.startPollForConnection(); + } + }, 3000); + } + async initializeDevTools(devToolsNode: HTMLElement) { + this.setStatus('Waiting for port 8097'); const port = await getPort({port: 8097}); // default port for dev tools - ReactDevToolsStandalone.setContentDOMNode(devToolsNode).startServer(port); + this.setStatus('Starting DevTools server on ' + port); + ReactDevToolsStandalone.setContentDOMNode(devToolsNode) + .setStatusListener(status => { + this.setStatus(status); + }) + .startServer(port); + this.setStatus('Waiting for device'); const device = await this.getDevice(); + if (device) { const host = device.deviceType === 'physical' @@ -80,16 +142,25 @@ export default class extends FlipperPlugin<{}, any, {}> { : device instanceof AndroidDevice ? '10.0.2.2' // Host IP for Android emulator host system : 'localhost'; + this.setStatus(`Updating config to ${host}:${port}`); this.client.call('config', {port, host}); if (['quest', 'go', 'pacific'].includes(device.title.toLowerCase())) { const device = await this.getDevice(); + this.setStatus(`Setting up reverse port mapping: ${port}:${port}`); (device as AndroidDevice).reverse([port, port]); } } } render() { - return ; + return ( + + {this.state.status !== CONNECTED ? ( + {this.state.status} + ) : null} + + + ); } } diff --git a/src/plugins/reactdevtools/react-devtools-core.d.tsx b/src/plugins/reactdevtools/react-devtools-core.d.tsx index f5be99f0c..755fdae9f 100644 --- a/src/plugins/reactdevtools/react-devtools-core.d.tsx +++ b/src/plugins/reactdevtools/react-devtools-core.d.tsx @@ -9,8 +9,9 @@ declare module 'react-devtools-core/standalone' { interface DevTools { - setContentDOMNode(node: HTMLElement): DevTools; - startServer(port: number): DevTools; + setContentDOMNode(node: HTMLElement): this; + startServer(port: number): this; + setStatusListener(listener: (message: string) => void): this; } const DevTools: DevTools; export default DevTools;