Show offline devices in dropdown

Summary:
This diff aims to make the selected device a little clearer, the button now shows different icons depending on the selected devices: physical, emulators and archived devices.

The dropdown now is grouped in these sections, depending on their availability:
- Connected Devices
- Running Emulators
- Imported Devices
- Launch Android emulators
- Open File...

"Open File..." allows to import a file the same way as File -> Open File...

Reviewed By: jknoxville

Differential Revision: D14460789

fbshipit-source-id: 8d6edff0d90d5e02e4ef5976af5680ab8eaf77b4
This commit is contained in:
Daniel Büchele
2019-03-15 11:27:30 -07:00
committed by Facebook Github Bot
parent 51139500f4
commit f30ff068a7
4 changed files with 108 additions and 54 deletions

View File

@@ -8,8 +8,7 @@
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js'; import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js';
import { import {
exportStoreToFile, exportStoreToFile,
importFileToStore, showOpenDialog,
IMPORT_FLIPPER_TRACE_EVENT,
EXPORT_FLIPPER_TRACE_EVENT, EXPORT_FLIPPER_TRACE_EVENT,
} from './utils/exportData.js'; } from './utils/exportData.js';
import {setActiveSheet, ACTIVE_SHEET_SHARE_DATA} from './reducers/application'; import {setActiveSheet, ACTIVE_SHEET_SHARE_DATA} from './reducers/application';
@@ -20,10 +19,7 @@ import {remote} from 'electron';
const {dialog} = remote; const {dialog} = remote;
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import { import {reportPlatformFailures} from './utils/metrics';
reportPlatformFailures,
tryCatchReportPlatformFailures,
} from './utils/metrics';
export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste'; export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste';
export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help'; export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help';
@@ -329,18 +325,7 @@ function getTemplate(
label: 'Open File...', label: 'Open File...',
accelerator: 'CommandOrControl+O', accelerator: 'CommandOrControl+O',
click: function(item: Object, focusedWindow: Object) { click: function(item: Object, focusedWindow: Object) {
dialog.showOpenDialog( showOpenDialog(store);
{
properties: ['openFile'],
},
(files: Array<string>) => {
if (files !== undefined && files.length > 0) {
tryCatchReportPlatformFailures(() => {
importFileToStore(files[0], store);
}, `${IMPORT_FLIPPER_TRACE_EVENT}:UI`);
}
},
);
}, },
}, },
{ {

View File

@@ -6,12 +6,15 @@
*/ */
import {Component, Button, styled} from 'flipper'; import {Component, Button, styled} from 'flipper';
import ArchivedDevice from '../devices/ArchivedDevice.js';
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {spawn} from 'child_process'; import {spawn} from 'child_process';
import {dirname} from 'path'; import {dirname} from 'path';
import {selectDevice, preferDevice} from '../reducers/connections.js'; import {selectDevice, preferDevice} from '../reducers/connections.js';
import {default as which} from 'which'; import {default as which} from 'which';
import {promisify} from 'util'; import {promisify} from 'util';
import {showOpenDialog} from '../utils/exportData';
import PropTypes from 'prop-types';
import type BaseDevice from '../devices/BaseDevice.js'; import type BaseDevice from '../devices/BaseDevice.js';
const whichPromise = promisify(which); const whichPromise = promisify(which);
@@ -29,6 +32,10 @@ const DropdownButton = styled(Button)({
}); });
class DevicesButton extends Component<Props> { class DevicesButton extends Component<Props> {
static contextTypes = {
store: PropTypes.object.isRequired,
};
launchEmulator = (name: string) => { launchEmulator = (name: string) => {
// On Linux, you must run the emulator from the directory it's in because // On Linux, you must run the emulator from the directory it's in because
// reasons ... // reasons ...
@@ -54,49 +61,77 @@ class DevicesButton extends Component<Props> {
selectedDevice, selectedDevice,
selectDevice, selectDevice,
} = this.props; } = this.props;
let text = 'No device selected'; let buttonLabel = 'No device selected';
let icon = 'minus-circle'; let icon = 'minus-circle';
if (selectedDevice) { if (selectedDevice instanceof ArchivedDevice) {
text = selectedDevice.title; buttonLabel = `${selectedDevice?.title || 'Unknown device'} (offline)`;
icon = 'box';
} else if (selectedDevice?.deviceType === 'physical') {
buttonLabel = selectedDevice?.title || 'Unknown device';
icon = 'mobile'; icon = 'mobile';
} else if (selectedDevice?.deviceType === 'emulator') {
buttonLabel = selectedDevice?.title || 'Unknown emulator';
icon = 'desktop';
} }
const dropdown = []; const dropdown = [];
if (devices.length > 0) { // Physical devices
dropdown.push( const connectedDevices = [
{ {
label: 'Running devices', label: 'Connected Devices',
enabled: false, enabled: false,
}, },
...devices.map((device: BaseDevice) => { ...devices
let label = ''; .filter(device => device.deviceType === 'physical')
switch (device.deviceType) { .map((device: BaseDevice) => ({
case 'emulator':
label = '';
break;
case 'physical':
label = '📱 ';
break;
case 'archivedEmulator':
label = '📦 ';
break;
case 'archivedPhysical':
label = '📦 ';
break;
default:
label = '';
}
return {
click: () => selectDevice(device), click: () => selectDevice(device),
checked: device === selectedDevice, checked: device === selectedDevice,
label: `${label}${device.title}`, label: `📱 ${device.title}`,
type: 'checkbox', type: 'checkbox',
}; })),
}), ];
); if (connectedDevices.length > 1) {
dropdown.push(...connectedDevices);
} }
// Emulators
const runningEmulators = [
{
label: 'Running Emulators',
enabled: false,
},
...devices
.filter(device => device.deviceType === 'emulator')
.map((device: BaseDevice) => ({
click: () => selectDevice(device),
checked: device === selectedDevice,
label: device.title,
type: 'checkbox',
})),
];
if (runningEmulators.length > 1) {
dropdown.push(...runningEmulators);
}
// Archived
const importedFiles = [
{
label: 'Imported Devices',
enabled: false,
},
...devices
.filter(device => device instanceof ArchivedDevice)
.map((device: BaseDevice) => ({
click: () => selectDevice(device),
checked: device === selectedDevice,
label: `📦 ${device.title} (offline)`,
type: 'checkbox',
})),
];
if (importedFiles.length > 1) {
dropdown.push(...importedFiles);
}
// Launch Android emulators
if (androidEmulators.length > 0) { if (androidEmulators.length > 0) {
const emulators = Array.from(androidEmulators) const emulators = Array.from(androidEmulators)
.filter( .filter(
@@ -119,9 +154,18 @@ class DevicesButton extends Component<Props> {
); );
} }
} }
if (dropdown.length > 0) {
dropdown.push({type: 'separator'});
}
dropdown.push({
label: 'Open File...',
click: () => {
showOpenDialog(this.context.store);
},
});
return ( return (
<DropdownButton compact={true} icon={icon} dropdown={dropdown}> <DropdownButton compact={true} icon={icon} dropdown={dropdown}>
{text} {buttonLabel}
</DropdownButton> </DropdownButton>
); );
} }

View File

@@ -22,6 +22,8 @@ import uuid from 'uuid';
import {remote} from 'electron'; import {remote} from 'electron';
import {serialize, deserialize} from './serialization'; import {serialize, deserialize} from './serialization';
import {readCurrentRevision} from './packageMetadata.js'; import {readCurrentRevision} from './packageMetadata.js';
import {tryCatchReportPlatformFailures} from './metrics';
export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace'; export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace';
export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace'; export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace';
@@ -337,3 +339,18 @@ export const importFileToStore = (file: string, store: Store) => {
importDataToStore(data, store); importDataToStore(data, store);
}); });
}; };
export function showOpenDialog(store: Store) {
remote.dialog.showOpenDialog(
{
properties: ['openFile'],
},
(files: Array<string>) => {
if (files !== undefined && files.length > 0) {
tryCatchReportPlatformFailures(() => {
importFileToStore(files[0], store);
}, `${IMPORT_FLIPPER_TRACE_EVENT}:UI`);
}
},
);
}

View File

@@ -35,6 +35,14 @@ export const precachedIcons: Array<string> = [
name: 'mobile', name: 'mobile',
size: 12, size: 12,
}, },
{
name: 'box',
size: 12,
},
{
name: 'desktop',
size: 12,
},
{ {
name: 'bug', name: 'bug',
size: 12, size: 12,