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:
committed by
Facebook Github Bot
parent
51139500f4
commit
f30ff068a7
@@ -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`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user