Hide app selector if no devices are available
Summary: As reported in https://fb.workplace.com/groups/748354712423318/permalink/773382183253904/, special case no devices being present and suggest to launch an emulator. Also extends `useStore()` hook to accept no arguments, in which case it works as Redux's own `useStore` hook, except that it is strongly typed. Reviewed By: passy Differential Revision: D25803497 fbshipit-source-id: d448ac41e0ba7b713ee883caeb27736a2901975c
This commit is contained in:
committed by
Facebook GitHub Bot
parent
dbf194b952
commit
30ea098a63
@@ -47,7 +47,6 @@ import {logout, USER_NOT_SIGNEDIN, USER_UNAUTHORIZED} from '../reducers/user';
|
|||||||
import config from '../fb-stubs/config';
|
import config from '../fb-stubs/config';
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import {showEmulatorLauncher} from './appinspect/LaunchEmulator';
|
import {showEmulatorLauncher} from './appinspect/LaunchEmulator';
|
||||||
import {useStore as useReduxStore} from 'react-redux';
|
|
||||||
import SupportRequestFormV2 from '../fb-stubs/SupportRequestFormV2';
|
import SupportRequestFormV2 from '../fb-stubs/SupportRequestFormV2';
|
||||||
import {setStaticView} from '../reducers/connections';
|
import {setStaticView} from '../reducers/connections';
|
||||||
import {getInstance} from '../fb-stubs/Logger';
|
import {getInstance} from '../fb-stubs/Logger';
|
||||||
@@ -252,7 +251,7 @@ function DebugLogsButton({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function LaunchEmulatorButton() {
|
function LaunchEmulatorButton() {
|
||||||
const store = useReduxStore();
|
const store = useStore();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LeftRailButton
|
<LeftRailButton
|
||||||
|
|||||||
@@ -8,12 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Button, Dropdown, Menu, Radio, Typography} from 'antd';
|
import {Alert, Button, Dropdown, Menu, Radio, Typography} from 'antd';
|
||||||
import {
|
import {
|
||||||
AppleOutlined,
|
AppleOutlined,
|
||||||
AndroidOutlined,
|
AndroidOutlined,
|
||||||
WindowsOutlined,
|
WindowsOutlined,
|
||||||
CaretDownOutlined,
|
CaretDownOutlined,
|
||||||
|
RocketOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {Glyph, Layout, styled} from '../../ui';
|
import {Glyph, Layout, styled} from '../../ui';
|
||||||
import {theme, useTrackedCallback} from 'flipper-plugin';
|
import {theme, useTrackedCallback} from 'flipper-plugin';
|
||||||
@@ -30,8 +31,9 @@ import {getColorByApp} from '../../chrome/mainsidebar/sidebarUtils';
|
|||||||
import Client from '../../Client';
|
import Client from '../../Client';
|
||||||
import {State} from '../../reducers';
|
import {State} from '../../reducers';
|
||||||
import {brandIcons} from '../../ui/components/colors';
|
import {brandIcons} from '../../ui/components/colors';
|
||||||
|
import {showEmulatorLauncher} from './LaunchEmulator';
|
||||||
|
|
||||||
const {Text} = Typography;
|
const {Text, Link, Title} = Typography;
|
||||||
|
|
||||||
function getOsIcon(os?: OS) {
|
function getOsIcon(os?: OS) {
|
||||||
switch (os) {
|
switch (os) {
|
||||||
@@ -86,7 +88,7 @@ export function AppSelector() {
|
|||||||
);
|
);
|
||||||
const client = clients.find((client) => client.id === selectedApp);
|
const client = clients.find((client) => client.id === selectedApp);
|
||||||
|
|
||||||
return (
|
return entries.length ? (
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
value={selectedApp}
|
value={selectedApp}
|
||||||
size="small"
|
size="small"
|
||||||
@@ -96,9 +98,7 @@ export function AppSelector() {
|
|||||||
}}>
|
}}>
|
||||||
<Dropdown
|
<Dropdown
|
||||||
overlay={
|
overlay={
|
||||||
<Menu selectedKeys={selectedApp ? [selectedApp] : []}>
|
<Menu selectedKeys={selectedApp ? [selectedApp] : []}>{entries}</Menu>
|
||||||
{entries.flat()}
|
|
||||||
</Menu>
|
|
||||||
}>
|
}>
|
||||||
<AppInspectButton title="Select the device / app to inspect">
|
<AppInspectButton title="Select the device / app to inspect">
|
||||||
<Layout.Horizontal gap center>
|
<Layout.Horizontal gap center>
|
||||||
@@ -114,6 +114,8 @@ export function AppSelector() {
|
|||||||
</AppInspectButton>
|
</AppInspectButton>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
|
) : (
|
||||||
|
<NoDevices />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,5 +218,36 @@ function computeEntries(
|
|||||||
)),
|
)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
return entries;
|
return entries.flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
function NoDevices() {
|
||||||
|
const store = useStore();
|
||||||
|
|
||||||
|
const onLaunchEmulator = useTrackedCallback(
|
||||||
|
'select-emulator',
|
||||||
|
() => {
|
||||||
|
showEmulatorLauncher(store);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
type="info"
|
||||||
|
message={
|
||||||
|
<>
|
||||||
|
<Title level={4}>No devices found</Title>
|
||||||
|
<Text>
|
||||||
|
Start a fresh emulator <RocketOutlined onClick={onLaunchEmulator} />{' '}
|
||||||
|
or check the{' '}
|
||||||
|
<Link href="https://fbflipper.com/docs/troubleshooting">
|
||||||
|
troubleshooting guide
|
||||||
|
</Link>
|
||||||
|
.
|
||||||
|
</Text>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
useStore as useReduxStore,
|
||||||
useSelector,
|
useSelector,
|
||||||
shallowEqual,
|
shallowEqual,
|
||||||
useDispatch as useDispatchBase,
|
useDispatch as useDispatchBase,
|
||||||
} from 'react-redux';
|
} from 'react-redux';
|
||||||
import {Dispatch as ReduxDispatch} from 'redux';
|
import {Dispatch as ReduxDispatch} from 'redux';
|
||||||
import {State, Actions} from '../reducers/index';
|
import {State, Actions, Store} from '../reducers/index';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strongly typed wrapper or Redux's useSelector.
|
* Strongly typed wrapper or Redux's useSelector.
|
||||||
@@ -22,9 +23,14 @@ import {State, Actions} from '../reducers/index';
|
|||||||
*/
|
*/
|
||||||
export function useStore<Selected>(
|
export function useStore<Selected>(
|
||||||
selector: (state: State) => Selected,
|
selector: (state: State) => Selected,
|
||||||
equalityFn: (left: Selected, right: Selected) => boolean = shallowEqual,
|
equalityFn?: (left: Selected, right: Selected) => boolean,
|
||||||
): Selected {
|
): Selected;
|
||||||
return useSelector(selector, equalityFn);
|
export function useStore(): Store;
|
||||||
|
export function useStore(selector?: any, equalityFn?: any) {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
if (arguments.length === 0) return useReduxStore();
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
return useSelector(selector, equalityFn ?? shallowEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Dispatch = ReduxDispatch<Actions>;
|
export type Dispatch = ReduxDispatch<Actions>;
|
||||||
|
|||||||
Reference in New Issue
Block a user