/** * Copyright 2018-present Facebook. * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * @format */ import type {FlipperDevicePlugin, FlipperPlugin} from '../plugin'; import type {PluginDefinition} from '../dispatcher/plugins'; import type Client from '../Client'; import {Component, Fragment} from 'react'; import {connect} from 'react-redux'; import { FlexColumn, Button, Text, ManagedTable, styled, colors, Link, } from 'flipper'; import {remote} from 'electron'; const Container = styled(FlexColumn)({ padding: 10, width: 700, }); const InfoText = styled(Text)({ lineHeight: '130%', marginBottom: 8, }); const Title = styled('div')({ fontWeight: '500', marginBottom: 10, marginTop: 8, }); const Ellipsis = styled(Text)({ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', }); const Row = styled(FlexColumn)({ alignItems: 'flex-end', }); const TableContainer = styled('div')({ borderRadius: 4, overflow: 'hidden', border: `1px solid ${colors.macOSTitleBarButtonBorder}`, marginTop: 10, marginBottom: 10, backgroundColor: colors.white, height: 400, display: 'flex', }); const Lamp = styled('div')(props => ({ width: 10, height: 10, borderRadius: 5, backgroundColor: props.on ? colors.lime : colors.red, border: `1px solid ${colors.blackAlpha30}`, marginTop: 6, flexShrink: 0, })); type Props = {| devicePlugins: Array>, clientPlugins: Array>, gatekeepedPlugins: Array, disabledPlugins: Array, failedPlugins: Array<[PluginDefinition, string]>, clients: Array, selectedDevice: ?string, onHide: () => mixed, |}; const COLUMNS = { lamp: { value: '', }, name: { value: 'Name', }, status: { value: 'Status', }, gk: { value: 'GK', }, clients: { value: 'Supported by', }, source: { value: 'Source', }, }; const COLUMNS_SIZES = { lamp: 20, name: 'flex', status: 110, gk: 120, clients: 90, source: 140, }; class PluginDebugger extends Component { buildRow( name: string, loaded: boolean, status: string, GKname: ?string, GKpassing: ?boolean, pluginPath: ?string, ) { return { key: name.toLowerCase(), columns: { lamp: {value: }, name: {value: {name}}, status: { value: status ? ( {status} ) : null, }, gk: { value: GKname && ( {GKname} ), }, clients: { value: this.getSupportedClients(name), }, source: { value: pluginPath ? ( {pluginPath} ) : ( bundled ), }, }, }; } getSupportedClients(id: string): string { return this.props.clients .reduce((acc: Array, cv: Client) => { if (cv.plugins.includes(id)) { acc.push(cv.query.app); } return acc; }, []) .join(', '); } getRows() { let rows = []; // bundled plugins are loaded from the defaultPlugins directory within // Flipper's package. const externalPluginPath = (p: PluginDefinition) => p.out.startsWith('./defaultPlugins/') ? null : p.entry; this.props.gatekeepedPlugins.forEach(plugin => rows.push( this.buildRow( plugin.name, false, 'GK disabled', plugin.gatekeeper, false, externalPluginPath(plugin), ), ), ); this.props.devicePlugins.forEach(plugin => rows.push( this.buildRow( plugin.id, true, '', // $FlowFixMe: Flow doesn't know this is inherited from FlipperBasePlugin plugin.gatekeeper, true, // $FlowFixMe: Flow doesn't know this is inherited from FlipperBasePlugin externalPluginPath(plugin), ), ), ); this.props.clientPlugins.forEach(plugin => rows.push( this.buildRow( plugin.id, true, '', // $FlowFixMe: Flow doesn't know this is inherited from FlipperBasePlugin plugin.gatekeeper, true, // $FlowFixMe: Flow doesn't know this is inherited from FlipperBasePlugin externalPluginPath(plugin), ), ), ); this.props.disabledPlugins.forEach(plugin => rows.push( this.buildRow( plugin.name, false, 'disabled', null, null, externalPluginPath(plugin), ), ), ); this.props.failedPlugins.forEach(([plugin, status]) => rows.push( this.buildRow( plugin.name, false, status, null, null, externalPluginPath(plugin), ), ), ); return rows.sort((a, b) => (a.key < b.key ? -1 : 1)); } render() { let content = null; if (!this.props.selectedDevice) { content = ( We can't find any device connected to your computer. Is an emulator/simulator currently running on your system, or is there a development device connected via USB? There are some devices/emulators known to have problems connecting to Flipper. Check out the{' '} known incompatibilities . ); } else if ( !this.props.clients.some( (client: Client) => client.query.device_id === this.props.selectedDevice, ) ) { // no clients for selected device content = ( While Flipper was able to connect to your device, it wasn't able to connect to the app you are running on your device. For this reason, app-specific plugins will not show up. {this.props.clients.length > 0 && ( // we have clients, but not for this device Make sure you selected the correct device from the dropdown button in the upper left corner. Only plugins for the selected device are shown in the sidebar. )} To debug why Flipper couldn't establish a connection to the app, check out our documentation about{' '} connection issues . ); } else { content = ( The table lists all plugins known to Flipper. Some of them might be blocked by GKs, others may not show up, because none of the connected apps is supporting it. ); } return ( Plugin Status {content} ); } } // $FlowFixMe export default connect( ({ plugins: { devicePlugins, clientPlugins, gatekeepedPlugins, disabledPlugins, failedPlugins, }, connections: {selectedPlugin, clients, selectedDevice}, }) => ({ devicePlugins: Array.from(devicePlugins.values()), clientPlugins: Array.from(clientPlugins.values()), gatekeepedPlugins, clients, disabledPlugins, failedPlugins, selectedDevice: selectedDevice?.serial, }), )(PluginDebugger);