From f30ff068a747b3b521a476c5ee7242a239eebe18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20B=C3=BCchele?= Date: Fri, 15 Mar 2019 11:27:30 -0700 Subject: [PATCH] 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 --- src/MenuBar.js | 21 +------ src/chrome/DevicesButton.js | 116 +++++++++++++++++++++++++----------- src/utils/exportData.js | 17 ++++++ src/utils/icons.js | 8 +++ 4 files changed, 108 insertions(+), 54 deletions(-) diff --git a/src/MenuBar.js b/src/MenuBar.js index 55cbefccb..4a44bdfa9 100644 --- a/src/MenuBar.js +++ b/src/MenuBar.js @@ -8,8 +8,7 @@ import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js'; import { exportStoreToFile, - importFileToStore, - IMPORT_FLIPPER_TRACE_EVENT, + showOpenDialog, EXPORT_FLIPPER_TRACE_EVENT, } from './utils/exportData.js'; import {setActiveSheet, ACTIVE_SHEET_SHARE_DATA} from './reducers/application'; @@ -20,10 +19,7 @@ import {remote} from 'electron'; const {dialog} = remote; import os from 'os'; import path from 'path'; -import { - reportPlatformFailures, - tryCatchReportPlatformFailures, -} from './utils/metrics'; +import {reportPlatformFailures} from './utils/metrics'; export type DefaultKeyboardAction = 'clear' | 'goToBottom' | 'createPaste'; export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help'; @@ -329,18 +325,7 @@ function getTemplate( label: 'Open File...', accelerator: 'CommandOrControl+O', click: function(item: Object, focusedWindow: Object) { - dialog.showOpenDialog( - { - properties: ['openFile'], - }, - (files: Array) => { - if (files !== undefined && files.length > 0) { - tryCatchReportPlatformFailures(() => { - importFileToStore(files[0], store); - }, `${IMPORT_FLIPPER_TRACE_EVENT}:UI`); - } - }, - ); + showOpenDialog(store); }, }, { diff --git a/src/chrome/DevicesButton.js b/src/chrome/DevicesButton.js index 5b4c37bd4..c6a7f9f06 100644 --- a/src/chrome/DevicesButton.js +++ b/src/chrome/DevicesButton.js @@ -6,12 +6,15 @@ */ import {Component, Button, styled} from 'flipper'; +import ArchivedDevice from '../devices/ArchivedDevice.js'; import {connect} from 'react-redux'; import {spawn} from 'child_process'; import {dirname} from 'path'; import {selectDevice, preferDevice} from '../reducers/connections.js'; import {default as which} from 'which'; import {promisify} from 'util'; +import {showOpenDialog} from '../utils/exportData'; +import PropTypes from 'prop-types'; import type BaseDevice from '../devices/BaseDevice.js'; const whichPromise = promisify(which); @@ -29,6 +32,10 @@ const DropdownButton = styled(Button)({ }); class DevicesButton extends Component { + static contextTypes = { + store: PropTypes.object.isRequired, + }; + launchEmulator = (name: string) => { // On Linux, you must run the emulator from the directory it's in because // reasons ... @@ -54,49 +61,77 @@ class DevicesButton extends Component { selectedDevice, selectDevice, } = this.props; - let text = 'No device selected'; + let buttonLabel = 'No device selected'; let icon = 'minus-circle'; - if (selectedDevice) { - text = selectedDevice.title; + if (selectedDevice instanceof ArchivedDevice) { + buttonLabel = `${selectedDevice?.title || 'Unknown device'} (offline)`; + icon = 'box'; + } else if (selectedDevice?.deviceType === 'physical') { + buttonLabel = selectedDevice?.title || 'Unknown device'; icon = 'mobile'; + } else if (selectedDevice?.deviceType === 'emulator') { + buttonLabel = selectedDevice?.title || 'Unknown emulator'; + icon = 'desktop'; } const dropdown = []; - if (devices.length > 0) { - dropdown.push( - { - label: 'Running devices', - enabled: false, - }, - ...devices.map((device: BaseDevice) => { - let label = ''; - switch (device.deviceType) { - case 'emulator': - label = ''; - break; - case 'physical': - label = '📱 '; - break; - case 'archivedEmulator': - label = '📦 '; - break; - case 'archivedPhysical': - label = '📦 '; - break; - default: - label = ''; - } - return { - click: () => selectDevice(device), - checked: device === selectedDevice, - label: `${label}${device.title}`, - type: 'checkbox', - }; - }), - ); + // Physical devices + const connectedDevices = [ + { + label: 'Connected Devices', + enabled: false, + }, + ...devices + .filter(device => device.deviceType === 'physical') + .map((device: BaseDevice) => ({ + click: () => selectDevice(device), + checked: device === selectedDevice, + label: `📱 ${device.title}`, + 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) { const emulators = Array.from(androidEmulators) .filter( @@ -119,9 +154,18 @@ class DevicesButton extends Component { ); } } + if (dropdown.length > 0) { + dropdown.push({type: 'separator'}); + } + dropdown.push({ + label: 'Open File...', + click: () => { + showOpenDialog(this.context.store); + }, + }); return ( - {text} + {buttonLabel} ); } diff --git a/src/utils/exportData.js b/src/utils/exportData.js index a40b55681..02843c3a5 100644 --- a/src/utils/exportData.js +++ b/src/utils/exportData.js @@ -22,6 +22,8 @@ import uuid from 'uuid'; import {remote} from 'electron'; import {serialize, deserialize} from './serialization'; import {readCurrentRevision} from './packageMetadata.js'; +import {tryCatchReportPlatformFailures} from './metrics'; + export const IMPORT_FLIPPER_TRACE_EVENT = 'import-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); }); }; + +export function showOpenDialog(store: Store) { + remote.dialog.showOpenDialog( + { + properties: ['openFile'], + }, + (files: Array) => { + if (files !== undefined && files.length > 0) { + tryCatchReportPlatformFailures(() => { + importFileToStore(files[0], store); + }, `${IMPORT_FLIPPER_TRACE_EVENT}:UI`); + } + }, + ); +} diff --git a/src/utils/icons.js b/src/utils/icons.js index fb0a9097f..380d4111e 100644 --- a/src/utils/icons.js +++ b/src/utils/icons.js @@ -35,6 +35,14 @@ export const precachedIcons: Array = [ name: 'mobile', size: 12, }, + { + name: 'box', + size: 12, + }, + { + name: 'desktop', + size: 12, + }, { name: 'bug', size: 12,