diff --git a/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx b/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx index bed93e91b..acd76291b 100644 --- a/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx +++ b/desktop/app/src/sandy-chrome/appinspect/AppInspect.tsx @@ -26,6 +26,7 @@ import { getActiveDevice, getMetroDevice, } from '../../selectors/connections'; +import * as connections from '../../selectors/connections'; const {Text} = Typography; @@ -46,6 +47,7 @@ export function AppInspect() { const activeDevice = useSelector(getActiveDevice); const isDeviceConnected = useValue(activeDevice?.connected, false); const isAppConnected = useValue(client?.connected, false); + const hasSelectableDevices = useSelector(connections.hasSelectableDevices); return ( @@ -61,6 +63,7 @@ export function AppInspect() { activeDevice, client, isAppConnected, + hasSelectableDevices, )} {isDeviceConnected && isAppConnected && } {isDeviceConnected && activeDevice && ( @@ -96,6 +99,7 @@ function renderStatusMessage( activeDevice: BaseDevice | null, client: Client | null, isAppConnected: boolean, + hasSelectableDevices: boolean, ): React.ReactNode { if (!activeDevice) { return; @@ -142,7 +146,7 @@ function renderStatusMessage( ) - ) : ( + ) : hasSelectableDevices ? ( - ); + ) : null /* no selectable devices */; } diff --git a/desktop/app/src/sandy-chrome/appinspect/AppSelector.tsx b/desktop/app/src/sandy-chrome/appinspect/AppSelector.tsx index 782d3e72d..5bfbb76cf 100644 --- a/desktop/app/src/sandy-chrome/appinspect/AppSelector.tsx +++ b/desktop/app/src/sandy-chrome/appinspect/AppSelector.tsx @@ -18,10 +18,9 @@ import { } from '@ant-design/icons'; import {Glyph, Layout, styled} from '../../ui'; import {DeviceOS, theme, useTrackedCallback, useValue} from 'flipper-plugin'; -import {batch} from 'react-redux'; +import {batch, useSelector} from 'react-redux'; import {useDispatch, useStore} from '../../utils/useStore'; import { - canBeDefaultDevice, getClientsByDevice, selectClient, selectDevice, @@ -32,6 +31,7 @@ import {State} from '../../reducers'; import {brandColors, brandIcons, colors} from '../../ui/components/colors'; import {TroubleshootingGuide} from './fb-stubs/TroubleshootingGuide'; import GK from '../../fb-stubs/GK'; +import {getSelectableDevices} from '../../selectors/connections'; const {Text} = Typography; @@ -50,13 +50,9 @@ function getOsIcon(os?: DeviceOS) { export function AppSelector() { const dispatch = useDispatch(); - const { - devices, - selectedDevice, - clients, - uninitializedClients, - selectedAppId, - } = useStore((state) => state.connections); + const selectableDevices = useSelector(getSelectableDevices); + const {selectedDevice, clients, uninitializedClients, selectedAppId} = + useStore((state) => state.connections); useValue(selectedDevice?.connected, false); // subscribe to future archived state changes const onSelectDevice = useTrackedCallback( @@ -79,7 +75,7 @@ export function AppSelector() { ); const entries = computeEntries( - devices, + selectableDevices, clients, uninitializedClients, onSelectDevice, @@ -193,47 +189,37 @@ const AppIconContainer = styled.div({ }); function computeEntries( - devices: BaseDevice[], + selectableDevices: BaseDevice[], clients: Map, uninitializedClients: State['connections']['uninitializedClients'], onSelectDevice: (device: BaseDevice) => void, onSelectApp: (device: BaseDevice, client: Client) => void, ) { - const entries = devices - .filter( - (device) => - // hide non default devices, unless they have a connected client or plugins - canBeDefaultDevice(device) || - device.hasDevicePlugins || - getClientsByDevice(device, clients).length > 0, - ) - .map((device) => { - const deviceEntry = ( - { - onSelectDevice(device); - }}> - - - ); - const clientEntries = getClientsByDevice(device, clients).map( - (client) => ( - { - onSelectApp(device, client); - }}> - - - - - ), - ); - return [deviceEntry, ...clientEntries]; - }); + const entries = selectableDevices.map((device) => { + const deviceEntry = ( + { + onSelectDevice(device); + }}> + + + ); + const clientEntries = getClientsByDevice(device, clients).map((client) => ( + { + onSelectApp(device, client); + }}> + + + + + )); + return [deviceEntry, ...clientEntries]; + }); if (uninitializedClients.length) { entries.push([ diff --git a/desktop/app/src/selectors/connections.tsx b/desktop/app/src/selectors/connections.tsx index 70b0048c0..9cbb2bfcb 100644 --- a/desktop/app/src/selectors/connections.tsx +++ b/desktop/app/src/selectors/connections.tsx @@ -14,10 +14,12 @@ import { computeActivePluginList, } from '../utils/pluginUtils'; import createSelector from './createSelector'; +import {canBeDefaultDevice, getClientsByDevice} from '../reducers/connections'; const getSelectedPluginId = (state: State) => state.connections.selectedPlugin; const getSelectedDevice = (state: State) => state.connections.selectedDevice; const getDevices = (state: State) => state.connections.devices; +const getClients = (state: State) => state.connections.clients; const getPluginDownloads = (state: State) => state.pluginDownloads; // N.B. no useSelector, It can't memoise on maps :-/ @@ -31,6 +33,25 @@ export const getMetroDevice = createSelector(getDevices, (devices) => { ); }); +export const getSelectableDevices = createSelector( + getDevices, + getClients, + (devices, clients) => { + return devices.filter( + (device) => + // hide non default devices, unless they have a connected client or plugins + canBeDefaultDevice(device) || + device.hasDevicePlugins || + getClientsByDevice(device, clients).length > 0, + ); + }, +); + +export const hasSelectableDevices = createSelector( + getSelectableDevices, + (selectableDevices) => selectableDevices.length > 0, +); + export const getActiveDevice = createSelector( getSelectedDevice, getActiveClient,