Back out "remove all mentions of metro from flipper-ui-core"
Summary: Original commit changeset: edc33c2b989e Original Phabricator Diff: D51200129 Reviewed By: lblasa Differential Revision: D51586736 fbshipit-source-id: e81355f7a0f0533ebc47f4cfc6c40af4865dbad0
This commit is contained in:
committed by
Facebook GitHub Bot
parent
244573abe3
commit
d8f507dba0
@@ -56,6 +56,39 @@ test('doing a double REGISTER_DEVICE fails', () => {
|
|||||||
}).toThrow('still connected');
|
}).toThrow('still connected');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('register, remove, re-register a metro device works correctly', () => {
|
||||||
|
const device1 = new TestDevice(
|
||||||
|
'http://localhost:8081',
|
||||||
|
'emulator',
|
||||||
|
'React Native',
|
||||||
|
'Metro',
|
||||||
|
);
|
||||||
|
let state: State = reducer(undefined, {
|
||||||
|
type: 'REGISTER_DEVICE',
|
||||||
|
payload: device1,
|
||||||
|
});
|
||||||
|
expect(state.devices.length).toBe(1);
|
||||||
|
expect(state.devices[0].displayTitle()).toBe('React Native');
|
||||||
|
|
||||||
|
device1.disconnect();
|
||||||
|
|
||||||
|
expect(state.devices.length).toBe(1);
|
||||||
|
expect(state.devices[0].displayTitle()).toBe('React Native (Offline)');
|
||||||
|
|
||||||
|
state = reducer(state, {
|
||||||
|
type: 'REGISTER_DEVICE',
|
||||||
|
payload: new TestDevice(
|
||||||
|
'http://localhost:8081',
|
||||||
|
'emulator',
|
||||||
|
'React Native',
|
||||||
|
'Metro',
|
||||||
|
),
|
||||||
|
});
|
||||||
|
expect(state.devices.length).toBe(1);
|
||||||
|
expect(state.devices[0].displayTitle()).toBe('React Native');
|
||||||
|
expect(state.devices[0]).not.toBe(device1);
|
||||||
|
});
|
||||||
|
|
||||||
test('selectPlugin sets deepLinkPayload correctly', () => {
|
test('selectPlugin sets deepLinkPayload correctly', () => {
|
||||||
const device1 = new TestDevice(
|
const device1 = new TestDevice(
|
||||||
'http://localhost:8081',
|
'http://localhost:8081',
|
||||||
@@ -200,8 +233,10 @@ describe('selection changes', () => {
|
|||||||
|
|
||||||
let device1: BaseDevice;
|
let device1: BaseDevice;
|
||||||
let device2: BaseDevice;
|
let device2: BaseDevice;
|
||||||
|
let metroDevice: BaseDevice;
|
||||||
let d1app1: Client;
|
let d1app1: Client;
|
||||||
let d1app2: Client;
|
let d1app2: Client;
|
||||||
|
let d2app1: Client;
|
||||||
let d2app2: Client;
|
let d2app2: Client;
|
||||||
let store: Store;
|
let store: Store;
|
||||||
let mockFlipper: MockFlipperResult;
|
let mockFlipper: MockFlipperResult;
|
||||||
@@ -214,8 +249,13 @@ describe('selection changes', () => {
|
|||||||
|
|
||||||
device1 = mockFlipper.device;
|
device1 = mockFlipper.device;
|
||||||
device2 = mockFlipper.createDevice({});
|
device2 = mockFlipper.createDevice({});
|
||||||
|
metroDevice = mockFlipper.createDevice({
|
||||||
|
os: 'Metro',
|
||||||
|
serial: 'http://localhost:8081',
|
||||||
|
});
|
||||||
d1app1 = mockFlipper.client;
|
d1app1 = mockFlipper.client;
|
||||||
d1app2 = await mockFlipper.createClient(device1, 'd1app2');
|
d1app2 = await mockFlipper.createClient(device1, 'd1app2');
|
||||||
|
d2app1 = await mockFlipper.createClient(device2, 'd2app1');
|
||||||
d2app2 = await mockFlipper.createClient(device2, 'd2app2');
|
d2app2 = await mockFlipper.createClient(device2, 'd2app2');
|
||||||
store = mockFlipper.store;
|
store = mockFlipper.store;
|
||||||
});
|
});
|
||||||
@@ -279,6 +319,31 @@ describe('selection changes', () => {
|
|||||||
expect(getActiveDevice(store.getState())).toBe(device1);
|
expect(getActiveDevice(store.getState())).toBe(device1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('select a metro device', async () => {
|
||||||
|
store.dispatch(
|
||||||
|
selectPlugin({
|
||||||
|
selectedPlugin: DevicePlugin1.id,
|
||||||
|
selectedDevice: metroDevice,
|
||||||
|
selectedAppId: d2app1.id, // this app will determine the active device
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const state = store.getState();
|
||||||
|
expect(state.connections).toMatchObject({
|
||||||
|
selectedDevice: metroDevice,
|
||||||
|
selectedPlugin: DevicePlugin1.id,
|
||||||
|
selectedAppId: d2app1.id,
|
||||||
|
userPreferredDevice: metroDevice.title,
|
||||||
|
// other prefs not updated
|
||||||
|
userPreferredPlugin: DevicePlugin1.id,
|
||||||
|
userPreferredApp: d2app1.query.app,
|
||||||
|
});
|
||||||
|
|
||||||
|
// used by plugin list, to keep main device / app selection correct
|
||||||
|
expect(getActiveClient(state)).toBe(d2app1);
|
||||||
|
expect(getActiveDevice(state)).toBe(device2);
|
||||||
|
});
|
||||||
|
|
||||||
test('introducing new client does not select it', async () => {
|
test('introducing new client does not select it', async () => {
|
||||||
await mockFlipper.createClient(device2, 'd2app3');
|
await mockFlipper.createClient(device2, 'd2app3');
|
||||||
expect(store.getState().connections).toMatchObject({
|
expect(store.getState().connections).toMatchObject({
|
||||||
@@ -336,12 +401,12 @@ describe('selection changes', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('select device', () => {
|
test('select device', () => {
|
||||||
store.dispatch(selectDevice(device1));
|
store.dispatch(selectDevice(metroDevice));
|
||||||
expect(store.getState().connections).toMatchObject({
|
expect(store.getState().connections).toMatchObject({
|
||||||
selectedDevice: device1,
|
selectedDevice: metroDevice,
|
||||||
selectedPlugin: TestPlugin1.id,
|
selectedPlugin: TestPlugin1.id,
|
||||||
selectedAppId: null,
|
selectedAppId: null,
|
||||||
userPreferredDevice: device1.title,
|
userPreferredDevice: metroDevice.title,
|
||||||
// other prefs not updated
|
// other prefs not updated
|
||||||
userPreferredPlugin: TestPlugin1.id,
|
userPreferredPlugin: TestPlugin1.id,
|
||||||
userPreferredApp: d1app1.query.app,
|
userPreferredApp: d1app1.query.app,
|
||||||
|
|||||||
@@ -19,13 +19,18 @@ import Client from '../../Client';
|
|||||||
import {BaseDevice} from 'flipper-frontend-core';
|
import {BaseDevice} from 'flipper-frontend-core';
|
||||||
import {ExclamationCircleOutlined, FieldTimeOutlined} from '@ant-design/icons';
|
import {ExclamationCircleOutlined, FieldTimeOutlined} from '@ant-design/icons';
|
||||||
import {useSelector} from 'react-redux';
|
import {useSelector} from 'react-redux';
|
||||||
import {getActiveClient, getActiveDevice} from '../../selectors/connections';
|
import {
|
||||||
|
getActiveClient,
|
||||||
|
getActiveDevice,
|
||||||
|
getMetroDevice,
|
||||||
|
} from '../../selectors/connections';
|
||||||
import * as connections from '../../selectors/connections';
|
import * as connections from '../../selectors/connections';
|
||||||
import {PluginActionsMenu} from '../../chrome/PluginActionsMenu';
|
import {PluginActionsMenu} from '../../chrome/PluginActionsMenu';
|
||||||
|
|
||||||
const {Text} = Typography;
|
const {Text} = Typography;
|
||||||
|
|
||||||
export function AppInspect() {
|
export function AppInspect() {
|
||||||
|
const metroDevice = useSelector(getMetroDevice);
|
||||||
const client = useSelector(getActiveClient);
|
const client = useSelector(getActiveClient);
|
||||||
const activeDevice = useSelector(getActiveDevice);
|
const activeDevice = useSelector(getActiveDevice);
|
||||||
const isDeviceConnected = useValue(activeDevice?.connected, false);
|
const isDeviceConnected = useValue(activeDevice?.connected, false);
|
||||||
@@ -51,7 +56,11 @@ export function AppInspect() {
|
|||||||
</Layout.Container>
|
</Layout.Container>
|
||||||
<Layout.ScrollContainer vertical padv={theme.space.large}>
|
<Layout.ScrollContainer vertical padv={theme.space.large}>
|
||||||
{activeDevice ? (
|
{activeDevice ? (
|
||||||
<PluginList activeDevice={activeDevice} client={client} />
|
<PluginList
|
||||||
|
activeDevice={activeDevice}
|
||||||
|
metroDevice={metroDevice}
|
||||||
|
client={client}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Layout.ScrollContainer>
|
</Layout.ScrollContainer>
|
||||||
</Layout.Top>
|
</Layout.Top>
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ const {Text} = Typography;
|
|||||||
export const PluginList = memo(function PluginList({
|
export const PluginList = memo(function PluginList({
|
||||||
client,
|
client,
|
||||||
activeDevice,
|
activeDevice,
|
||||||
|
metroDevice,
|
||||||
}: {
|
}: {
|
||||||
client: Client | null;
|
client: Client | null;
|
||||||
activeDevice: BaseDevice | null;
|
activeDevice: BaseDevice | null;
|
||||||
|
metroDevice: BaseDevice | null;
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const connections = useStore((state) => state.connections);
|
const connections = useStore((state) => state.connections);
|
||||||
@@ -52,9 +54,11 @@ export const PluginList = memo(function PluginList({
|
|||||||
const pluginLists = useSelector(getPluginLists);
|
const pluginLists = useSelector(getPluginLists);
|
||||||
const downloads = useStore((state) => state.pluginDownloads);
|
const downloads = useStore((state) => state.pluginDownloads);
|
||||||
const isConnected = useValue(activeDevice?.connected, false);
|
const isConnected = useValue(activeDevice?.connected, false);
|
||||||
|
const metroConnected = useValue(metroDevice?.connected, false);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
devicePlugins,
|
devicePlugins,
|
||||||
|
metroPlugins,
|
||||||
enabledPlugins,
|
enabledPlugins,
|
||||||
disabledPlugins,
|
disabledPlugins,
|
||||||
unavailablePlugins,
|
unavailablePlugins,
|
||||||
@@ -92,6 +96,19 @@ export const PluginList = memo(function PluginList({
|
|||||||
},
|
},
|
||||||
[dispatch, activeDevice, connections.selectedAppId],
|
[dispatch, activeDevice, connections.selectedAppId],
|
||||||
);
|
);
|
||||||
|
const handleMetroPluginClick = useCallback(
|
||||||
|
(pluginId) => {
|
||||||
|
dispatch(
|
||||||
|
selectPlugin({
|
||||||
|
selectedPlugin: pluginId,
|
||||||
|
selectedAppId: connections.selectedAppId,
|
||||||
|
deepLinkPayload: null,
|
||||||
|
selectedDevice: metroDevice,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[dispatch, metroDevice, connections.selectedAppId],
|
||||||
|
);
|
||||||
const handleEnablePlugin = useCallback(
|
const handleEnablePlugin = useCallback(
|
||||||
(id: string) => {
|
(id: string) => {
|
||||||
const plugin = (plugins.clientPlugins.get(id) ??
|
const plugin = (plugins.clientPlugins.get(id) ??
|
||||||
@@ -190,15 +207,39 @@ export const PluginList = memo(function PluginList({
|
|||||||
<PluginMenu
|
<PluginMenu
|
||||||
inlineIndent={8}
|
inlineIndent={8}
|
||||||
onClick={() => {}}
|
onClick={() => {}}
|
||||||
defaultOpenKeys={['enabled']}
|
defaultOpenKeys={['enabled', 'metro']}
|
||||||
selectedKeys={
|
selectedKeys={
|
||||||
connections.selectedPlugin ? [connections.selectedPlugin] : []
|
connections.selectedPlugin
|
||||||
|
? [
|
||||||
|
(connections.selectedDevice === metroDevice ? 'metro:' : '') +
|
||||||
|
connections.selectedPlugin,
|
||||||
|
]
|
||||||
|
: []
|
||||||
}
|
}
|
||||||
mode="inline">
|
mode="inline">
|
||||||
<PluginGroup key="enabled" title="Enabled">
|
<PluginGroup key="enabled" title="Enabled">
|
||||||
{allEnabledPlugins}
|
{allEnabledPlugins}
|
||||||
</PluginGroup>
|
</PluginGroup>
|
||||||
|
|
||||||
|
{!isArchived && metroConnected && (
|
||||||
|
<PluginGroup
|
||||||
|
key="metro"
|
||||||
|
title="React Native"
|
||||||
|
hint="The following plugins are exposed by the currently running Metro instance. Note that Metro might currently be connected to a different application or device than selected above.">
|
||||||
|
{metroPlugins.map((plugin) => (
|
||||||
|
<PluginEntry
|
||||||
|
key={'metro:' + plugin.id}
|
||||||
|
plugin={plugin.details}
|
||||||
|
scrollTo={
|
||||||
|
plugin.id === connections.selectedPlugin &&
|
||||||
|
connections.selectedDevice === metroDevice
|
||||||
|
}
|
||||||
|
onClick={handleMetroPluginClick}
|
||||||
|
tooltip={getPluginTooltip(plugin.details)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</PluginGroup>
|
||||||
|
)}
|
||||||
{isConnected && (
|
{isConnected && (
|
||||||
<PluginGroup
|
<PluginGroup
|
||||||
key="disabled"
|
key="disabled"
|
||||||
|
|||||||
@@ -12,9 +12,33 @@ import {
|
|||||||
MockFlipperResult,
|
MockFlipperResult,
|
||||||
} from '../../../__tests__/test-utils/createMockFlipperWithPlugin';
|
} from '../../../__tests__/test-utils/createMockFlipperWithPlugin';
|
||||||
import {FlipperPlugin} from '../../../plugin';
|
import {FlipperPlugin} from '../../../plugin';
|
||||||
|
import {BaseDevice, TestDevice} from 'flipper-frontend-core';
|
||||||
import {_SandyPluginDefinition} from 'flipper-plugin';
|
import {_SandyPluginDefinition} from 'flipper-plugin';
|
||||||
|
import {TestUtils} from 'flipper-plugin';
|
||||||
|
import {selectPlugin} from '../../../reducers/connections';
|
||||||
|
import {
|
||||||
|
addGatekeepedPlugins,
|
||||||
|
registerMarketplacePlugins,
|
||||||
|
registerPlugins,
|
||||||
|
} from '../../../reducers/plugins';
|
||||||
|
import {switchPlugin} from '../../../reducers/pluginManager';
|
||||||
|
|
||||||
import {getActiveDevice} from '../../../selectors/connections';
|
// eslint-disable-next-line
|
||||||
|
import * as LogsPluginModule from '../../../../../plugins/public/logs/index';
|
||||||
|
import {createMockDownloadablePluginDetails} from '../../../utils/testUtils';
|
||||||
|
import {
|
||||||
|
getActiveClient,
|
||||||
|
getActiveDevice,
|
||||||
|
getMetroDevice,
|
||||||
|
getPluginLists,
|
||||||
|
} from '../../../selectors/connections';
|
||||||
|
|
||||||
|
const createMockPluginDetails = TestUtils.createMockPluginDetails;
|
||||||
|
|
||||||
|
const logsPlugin = new _SandyPluginDefinition(
|
||||||
|
createMockPluginDetails({id: 'DeviceLogs'}),
|
||||||
|
LogsPluginModule,
|
||||||
|
);
|
||||||
|
|
||||||
class TestPlugin extends FlipperPlugin<any, any, any> {}
|
class TestPlugin extends FlipperPlugin<any, any, any> {}
|
||||||
|
|
||||||
@@ -39,3 +63,221 @@ describe('basic getActiveDevice', () => {
|
|||||||
expect(getActiveDevice(store.getState())).toBe(device);
|
expect(getActiveDevice(store.getState())).toBe(device);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('basic getActiveDevice with metro present', () => {
|
||||||
|
let flipper: MockFlipperResult;
|
||||||
|
let metro: BaseDevice;
|
||||||
|
let testDevice: BaseDevice;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
flipper = await createMockFlipperWithPlugin(logsPlugin);
|
||||||
|
flipper.device.supportsPlugin = (p) => {
|
||||||
|
return p.id !== 'unsupportedDevicePlugin';
|
||||||
|
};
|
||||||
|
testDevice = flipper.device;
|
||||||
|
// flipper.store.dispatch(registerPlugins([LogsPlugin]))
|
||||||
|
flipper.store.dispatch({
|
||||||
|
type: 'REGISTER_DEVICE',
|
||||||
|
payload: new TestDevice(
|
||||||
|
'http://localhost:8081',
|
||||||
|
'physical',
|
||||||
|
'metro',
|
||||||
|
'Metro',
|
||||||
|
),
|
||||||
|
});
|
||||||
|
metro = getMetroDevice(flipper.store.getState())!;
|
||||||
|
metro.supportsPlugin = (p) => {
|
||||||
|
return p.id !== 'unsupportedDevicePlugin';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
test('findMetroDevice', () => {
|
||||||
|
expect(metro.os).toBe('Metro');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('correct base selection state', () => {
|
||||||
|
const state = flipper.store.getState();
|
||||||
|
const {connections} = state;
|
||||||
|
expect(connections).toMatchObject({
|
||||||
|
devices: [testDevice, metro],
|
||||||
|
selectedDevice: testDevice,
|
||||||
|
selectedPlugin: 'DeviceLogs',
|
||||||
|
userPreferredDevice: 'MockAndroidDevice',
|
||||||
|
userPreferredPlugin: 'DeviceLogs',
|
||||||
|
userPreferredApp: 'TestApp',
|
||||||
|
});
|
||||||
|
expect(getActiveClient(state)).toBe(flipper.client);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('selecting Metro Logs works but keeps normal device preferred', () => {
|
||||||
|
expect(getActiveClient(flipper.store.getState())).toBe(flipper.client);
|
||||||
|
flipper.store.dispatch(
|
||||||
|
selectPlugin({
|
||||||
|
selectedPlugin: logsPlugin.id,
|
||||||
|
selectedAppId: flipper.client.id,
|
||||||
|
selectedDevice: metro,
|
||||||
|
deepLinkPayload: null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(flipper.store.getState().connections).toMatchObject({
|
||||||
|
devices: [testDevice, metro],
|
||||||
|
selectedAppId: 'TestApp#Android#MockAndroidDevice#serial',
|
||||||
|
selectedDevice: metro,
|
||||||
|
selectedPlugin: 'DeviceLogs',
|
||||||
|
userPreferredDevice: 'MockAndroidDevice', // Not metro!
|
||||||
|
userPreferredPlugin: 'DeviceLogs',
|
||||||
|
userPreferredApp: 'TestApp',
|
||||||
|
});
|
||||||
|
const state = flipper.store.getState();
|
||||||
|
// find best device is still metro
|
||||||
|
expect(getActiveDevice(state)).toBe(testDevice);
|
||||||
|
// find best client still returns app
|
||||||
|
expect(getActiveClient(state)).toBe(flipper.client);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('computePluginLists', () => {
|
||||||
|
const state = flipper.store.getState();
|
||||||
|
expect(getPluginLists(state)).toEqual({
|
||||||
|
downloadablePlugins: [],
|
||||||
|
devicePlugins: [logsPlugin],
|
||||||
|
metroPlugins: [logsPlugin],
|
||||||
|
enabledPlugins: [],
|
||||||
|
disabledPlugins: [],
|
||||||
|
unavailablePlugins: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('computePluginLists with problematic plugins', () => {
|
||||||
|
const noopPlugin = {
|
||||||
|
plugin() {},
|
||||||
|
Component() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const unsupportedDevicePlugin = new _SandyPluginDefinition(
|
||||||
|
createMockPluginDetails({
|
||||||
|
id: 'unsupportedDevicePlugin',
|
||||||
|
title: 'Unsupported Device Plugin',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
devicePlugin() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
supportsDevice() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
Component() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const unsupportedPlugin = new _SandyPluginDefinition(
|
||||||
|
createMockPluginDetails({
|
||||||
|
id: 'unsupportedPlugin',
|
||||||
|
title: 'Unsupported Plugin',
|
||||||
|
}),
|
||||||
|
noopPlugin,
|
||||||
|
);
|
||||||
|
|
||||||
|
const gateKeepedPlugin = createMockPluginDetails({
|
||||||
|
id: 'gateKeepedPlugin',
|
||||||
|
title: 'Gatekeeped Plugin',
|
||||||
|
gatekeeper: 'not for you',
|
||||||
|
});
|
||||||
|
|
||||||
|
const plugin1 = new _SandyPluginDefinition(
|
||||||
|
createMockPluginDetails({
|
||||||
|
id: 'plugin1',
|
||||||
|
title: 'Plugin 1',
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
plugin() {},
|
||||||
|
Component() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const plugin2 = new _SandyPluginDefinition(
|
||||||
|
createMockPluginDetails({
|
||||||
|
id: 'plugin2',
|
||||||
|
title: 'Plugin 2',
|
||||||
|
}),
|
||||||
|
noopPlugin,
|
||||||
|
);
|
||||||
|
|
||||||
|
const supportedDownloadablePlugin = createMockDownloadablePluginDetails({
|
||||||
|
id: 'supportedUninstalledPlugin',
|
||||||
|
title: 'Supported Uninstalled Plugin',
|
||||||
|
});
|
||||||
|
|
||||||
|
const unsupportedDownloadablePlugin = createMockDownloadablePluginDetails({
|
||||||
|
id: 'unsupportedUninstalledPlugin',
|
||||||
|
title: 'Unsupported Uninstalled Plugin',
|
||||||
|
});
|
||||||
|
|
||||||
|
flipper.store.dispatch(
|
||||||
|
registerPlugins([
|
||||||
|
unsupportedDevicePlugin,
|
||||||
|
unsupportedPlugin,
|
||||||
|
plugin1,
|
||||||
|
plugin2,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
flipper.store.dispatch(addGatekeepedPlugins([gateKeepedPlugin]));
|
||||||
|
flipper.store.dispatch(
|
||||||
|
registerMarketplacePlugins([
|
||||||
|
supportedDownloadablePlugin,
|
||||||
|
unsupportedDownloadablePlugin,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// ok, this is a little hackish
|
||||||
|
flipper.client.plugins = new Set([
|
||||||
|
'plugin1',
|
||||||
|
'plugin2',
|
||||||
|
'supportedUninstalledPlugin',
|
||||||
|
]);
|
||||||
|
|
||||||
|
let state = flipper.store.getState();
|
||||||
|
const pluginLists = getPluginLists(state);
|
||||||
|
expect(pluginLists).toEqual({
|
||||||
|
devicePlugins: [logsPlugin],
|
||||||
|
metroPlugins: [logsPlugin],
|
||||||
|
enabledPlugins: [],
|
||||||
|
disabledPlugins: [plugin1, plugin2],
|
||||||
|
unavailablePlugins: [
|
||||||
|
[
|
||||||
|
gateKeepedPlugin,
|
||||||
|
"Plugin 'Gatekeeped Plugin' is only available to members of gatekeeper 'not for you'",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
unsupportedDevicePlugin.details,
|
||||||
|
"Device plugin 'Unsupported Device Plugin' is not supported by the selected device 'MockAndroidDevice' (Android)",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
unsupportedPlugin.details,
|
||||||
|
"Plugin 'Unsupported Plugin' is not supported by the selected application 'TestApp' (Android)",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
unsupportedDownloadablePlugin,
|
||||||
|
"Plugin 'Unsupported Uninstalled Plugin' is not supported by the selected application 'TestApp' (Android) and not installed in Flipper",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
downloadablePlugins: [supportedDownloadablePlugin],
|
||||||
|
});
|
||||||
|
|
||||||
|
flipper.store.dispatch(
|
||||||
|
switchPlugin({
|
||||||
|
plugin: plugin2,
|
||||||
|
selectedApp: flipper.client.query.app,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
state = flipper.store.getState();
|
||||||
|
expect(getPluginLists(state)).toMatchObject({
|
||||||
|
enabledPlugins: [plugin2],
|
||||||
|
disabledPlugins: [plugin1],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ const getPluginDownloads = (state: State) => state.pluginDownloads;
|
|||||||
export const getActiveClient = (state: State) =>
|
export const getActiveClient = (state: State) =>
|
||||||
state.connections.clients.get(state.connections.selectedAppId!) ?? null;
|
state.connections.clients.get(state.connections.selectedAppId!) ?? null;
|
||||||
|
|
||||||
|
export const getMetroDevice = createSelector(getDevices, (devices) => {
|
||||||
|
return (
|
||||||
|
devices.find((device) => device.os === 'Metro' && !device.isArchived) ??
|
||||||
|
null
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export const getSelectableDevices = createSelector(
|
export const getSelectableDevices = createSelector(
|
||||||
getDevices,
|
getDevices,
|
||||||
getClients,
|
getClients,
|
||||||
@@ -48,7 +55,12 @@ export const hasSelectableDevices = createSelector(
|
|||||||
export const getActiveDevice = createSelector(
|
export const getActiveDevice = createSelector(
|
||||||
getSelectedDevice,
|
getSelectedDevice,
|
||||||
getActiveClient,
|
getActiveClient,
|
||||||
(selectedDevice, client) => {
|
getMetroDevice,
|
||||||
|
(selectedDevice, client, metroDevice) => {
|
||||||
|
// if not Metro device, use the selected device as metro device
|
||||||
|
if (selectedDevice !== metroDevice) {
|
||||||
|
return selectedDevice;
|
||||||
|
}
|
||||||
// if there is an active app, use device owning the app
|
// if there is an active app, use device owning the app
|
||||||
if (client) {
|
if (client) {
|
||||||
// TODO: Will be fixed later in the stack
|
// TODO: Will be fixed later in the stack
|
||||||
@@ -90,6 +102,7 @@ export const getPluginLists = createSelector(
|
|||||||
failedPlugins,
|
failedPlugins,
|
||||||
}),
|
}),
|
||||||
getActiveDevice,
|
getActiveDevice,
|
||||||
|
getMetroDevice,
|
||||||
getActiveClient,
|
getActiveClient,
|
||||||
computePluginLists,
|
computePluginLists,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {getAppVersion} from './info';
|
|||||||
|
|
||||||
export type PluginLists = {
|
export type PluginLists = {
|
||||||
devicePlugins: PluginDefinition[];
|
devicePlugins: PluginDefinition[];
|
||||||
|
metroPlugins: PluginDefinition[];
|
||||||
enabledPlugins: PluginDefinition[];
|
enabledPlugins: PluginDefinition[];
|
||||||
disabledPlugins: PluginDefinition[];
|
disabledPlugins: PluginDefinition[];
|
||||||
unavailablePlugins: [plugin: PluginDetails, reason: string][];
|
unavailablePlugins: [plugin: PluginDetails, reason: string][];
|
||||||
@@ -169,9 +170,11 @@ export function computePluginLists(
|
|||||||
| 'clientPlugins'
|
| 'clientPlugins'
|
||||||
>,
|
>,
|
||||||
device: BaseDevice | null,
|
device: BaseDevice | null,
|
||||||
|
metroDevice: BaseDevice | null,
|
||||||
client: Client | null,
|
client: Client | null,
|
||||||
): {
|
): {
|
||||||
devicePlugins: PluginDefinition[];
|
devicePlugins: PluginDefinition[];
|
||||||
|
metroPlugins: PluginDefinition[];
|
||||||
enabledPlugins: PluginDefinition[];
|
enabledPlugins: PluginDefinition[];
|
||||||
disabledPlugins: PluginDefinition[];
|
disabledPlugins: PluginDefinition[];
|
||||||
unavailablePlugins: [plugin: PluginDetails, reason: string][];
|
unavailablePlugins: [plugin: PluginDetails, reason: string][];
|
||||||
@@ -186,19 +189,26 @@ export function computePluginLists(
|
|||||||
const devicePlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
|
const devicePlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
|
||||||
.filter((p) => device?.supportsPlugin(p))
|
.filter((p) => device?.supportsPlugin(p))
|
||||||
.filter((p) => enabledDevicePluginsState.has(p.id));
|
.filter((p) => enabledDevicePluginsState.has(p.id));
|
||||||
|
const metroPlugins: PluginDefinition[] = [...plugins.devicePlugins.values()]
|
||||||
|
.filter((p) => metroDevice?.supportsPlugin(p))
|
||||||
|
.filter((p) => enabledDevicePluginsState.has(p.id));
|
||||||
const enabledPlugins: PluginDefinition[] = [];
|
const enabledPlugins: PluginDefinition[] = [];
|
||||||
const disabledPlugins: PluginDefinition[] = [
|
const disabledPlugins: PluginDefinition[] = [
|
||||||
...plugins.devicePlugins.values(),
|
...plugins.devicePlugins.values(),
|
||||||
]
|
]
|
||||||
.filter((p) => device?.supportsPlugin(p.details))
|
.filter(
|
||||||
|
(p) =>
|
||||||
|
device?.supportsPlugin(p.details) ||
|
||||||
|
metroDevice?.supportsPlugin(p.details),
|
||||||
|
)
|
||||||
.filter((p) => !enabledDevicePluginsState.has(p.id));
|
.filter((p) => !enabledDevicePluginsState.has(p.id));
|
||||||
const unavailablePlugins: [plugin: PluginDetails, reason: string][] = [];
|
const unavailablePlugins: [plugin: PluginDetails, reason: string][] = [];
|
||||||
const downloadablePlugins: DownloadablePluginDetails[] = [];
|
const downloadablePlugins: DownloadablePluginDetails[] = [];
|
||||||
|
|
||||||
if (device) {
|
if (device) {
|
||||||
// find all device plugins that aren't part of the current device
|
// find all device plugins that aren't part of the current device / metro
|
||||||
for (const p of plugins.devicePlugins.values()) {
|
for (const p of plugins.devicePlugins.values()) {
|
||||||
if (!device.supportsPlugin(p)) {
|
if (!device.supportsPlugin(p) && !metroDevice?.supportsPlugin(p)) {
|
||||||
unavailablePlugins.push([
|
unavailablePlugins.push([
|
||||||
p.details,
|
p.details,
|
||||||
`Device plugin '${getPluginTitle(
|
`Device plugin '${getPluginTitle(
|
||||||
@@ -212,7 +222,10 @@ export function computePluginLists(
|
|||||||
for (const plugin of uninstalledMarketplacePlugins.filter(
|
for (const plugin of uninstalledMarketplacePlugins.filter(
|
||||||
(d) => d.pluginType === 'device',
|
(d) => d.pluginType === 'device',
|
||||||
)) {
|
)) {
|
||||||
if (device.supportsPlugin(plugin)) {
|
if (
|
||||||
|
device.supportsPlugin(plugin) ||
|
||||||
|
metroDevice?.supportsPlugin(plugin)
|
||||||
|
) {
|
||||||
downloadablePlugins.push(plugin);
|
downloadablePlugins.push(plugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,6 +327,7 @@ export function computePluginLists(
|
|||||||
enabledPlugins.sort(sortPluginsByName);
|
enabledPlugins.sort(sortPluginsByName);
|
||||||
devicePlugins.sort(sortPluginsByName);
|
devicePlugins.sort(sortPluginsByName);
|
||||||
disabledPlugins.sort(sortPluginsByName);
|
disabledPlugins.sort(sortPluginsByName);
|
||||||
|
metroPlugins.sort(sortPluginsByName);
|
||||||
unavailablePlugins.sort(([a], [b]) => {
|
unavailablePlugins.sort(([a], [b]) => {
|
||||||
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
|
return getPluginTitle(a) > getPluginTitle(b) ? 1 : -1;
|
||||||
});
|
});
|
||||||
@@ -323,6 +337,7 @@ export function computePluginLists(
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
devicePlugins,
|
devicePlugins,
|
||||||
|
metroPlugins,
|
||||||
enabledPlugins,
|
enabledPlugins,
|
||||||
disabledPlugins,
|
disabledPlugins,
|
||||||
unavailablePlugins,
|
unavailablePlugins,
|
||||||
@@ -356,6 +371,7 @@ function getFavoritePlugins(
|
|||||||
export function computeActivePluginList({
|
export function computeActivePluginList({
|
||||||
enabledPlugins,
|
enabledPlugins,
|
||||||
devicePlugins,
|
devicePlugins,
|
||||||
|
metroPlugins,
|
||||||
disabledPlugins,
|
disabledPlugins,
|
||||||
downloadablePlugins,
|
downloadablePlugins,
|
||||||
unavailablePlugins,
|
unavailablePlugins,
|
||||||
@@ -375,6 +391,13 @@ export function computeActivePluginList({
|
|||||||
definition: plugin,
|
definition: plugin,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
for (const plugin of metroPlugins) {
|
||||||
|
pluginList[plugin.id] = {
|
||||||
|
status: 'enabled',
|
||||||
|
details: plugin.details,
|
||||||
|
definition: plugin,
|
||||||
|
};
|
||||||
|
}
|
||||||
for (const plugin of disabledPlugins) {
|
for (const plugin of disabledPlugins) {
|
||||||
pluginList[plugin.id] = {
|
pluginList[plugin.id] = {
|
||||||
status: 'disabled',
|
status: 'disabled',
|
||||||
|
|||||||
Reference in New Issue
Block a user