diff --git a/desktop/app/src/RenderHost.tsx b/desktop/app/src/RenderHost.tsx index b985ad531..663edca4a 100644 --- a/desktop/app/src/RenderHost.tsx +++ b/desktop/app/src/RenderHost.tsx @@ -59,6 +59,7 @@ export interface RenderHost { ...args: ChildProcessEvents[Event] ): void; shouldUseDarkColors(): boolean; + restartFlipper(update?: boolean): void; } let renderHostInstance: RenderHost | undefined; @@ -89,5 +90,6 @@ if (process.env.NODE_ENV === 'test') { shouldUseDarkColors() { return false; }, + restartFlipper() {}, }); } diff --git a/desktop/app/src/chrome/PlatformSelectWizard.tsx b/desktop/app/src/chrome/PlatformSelectWizard.tsx index cea992bcc..a128b45ae 100644 --- a/desktop/app/src/chrome/PlatformSelectWizard.tsx +++ b/desktop/app/src/chrome/PlatformSelectWizard.tsx @@ -15,10 +15,10 @@ import {Settings} from '../reducers/settings'; import {flush} from '../utils/persistor'; import ToggledSection from './settings/ToggledSection'; import {isEqual} from 'lodash'; -import restartFlipper from '../utils/restartFlipper'; import {reportUsage} from 'flipper-common'; import {Modal, Button} from 'antd'; import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin'; +import {getRenderHostInstance} from '../RenderHost'; const WIZARD_FINISHED_LOCAL_STORAGE_KEY = 'platformSelectWizardFinished'; @@ -65,7 +65,7 @@ class PlatformSelectWizard extends Component { return flush().then(() => { if (!settingsPristine) { reportUsage('platformwizard:action:changed'); - restartFlipper(true); + getRenderHostInstance().restartFlipper(); } else { reportUsage('platformwizard:action:noop'); } diff --git a/desktop/app/src/chrome/SettingsSheet.tsx b/desktop/app/src/chrome/SettingsSheet.tsx index 1cb835666..e308cbda6 100644 --- a/desktop/app/src/chrome/SettingsSheet.tsx +++ b/desktop/app/src/chrome/SettingsSheet.tsx @@ -23,11 +23,11 @@ import ToggledSection from './settings/ToggledSection'; import {FilePathConfigField, ConfigText} from './settings/configFields'; import KeyboardShortcutInput from './settings/KeyboardShortcutInput'; import {isEqual, isMatch, isEmpty} from 'lodash'; -import restartFlipper from '../utils/restartFlipper'; import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel'; import {reportUsage} from 'flipper-common'; import {Modal, message, Button} from 'antd'; import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin'; +import {getRenderHostInstance} from '../RenderHost'; type OwnProps = { onHide: () => void; @@ -70,7 +70,7 @@ class SettingsSheet extends Component { this.props.updateLauncherSettings(this.state.updatedLauncherSettings); this.props.onHide(); return flush().then(() => { - restartFlipper(true); + getRenderHostInstance().restartFlipper(true); }); }; diff --git a/desktop/app/src/dispatcher/handleOpenPluginDeeplink.tsx b/desktop/app/src/dispatcher/handleOpenPluginDeeplink.tsx index 393627839..27cde6e0a 100644 --- a/desktop/app/src/dispatcher/handleOpenPluginDeeplink.tsx +++ b/desktop/app/src/dispatcher/handleOpenPluginDeeplink.tsx @@ -27,7 +27,6 @@ import {loadPluginsFromMarketplace} from './fb-stubs/pluginMarketplace'; import {loadPlugin, switchPlugin} from '../reducers/pluginManager'; import {startPluginDownload} from '../reducers/pluginDownloads'; import isProduction from '../utils/isProduction'; -import restart from '../utils/restartFlipper'; import BaseDevice from '../devices/BaseDevice'; import Client from '../Client'; import {RocketOutlined} from '@ant-design/icons'; @@ -39,6 +38,7 @@ import { DeeplinkInteractionState, OpenPluginParams, } from '../deeplinkTracking'; +import {getRenderHostInstance} from '../RenderHost'; export function parseOpenPluginParams(query: string): OpenPluginParams { // 'flipper://open-plugin?plugin-id=graphql&client=facebook&devices=android,ios&chrome=1&payload=' @@ -362,7 +362,7 @@ async function verifyPluginStatus( ), okText: 'Restart', onConfirm: async () => { - restart(); + getRenderHostInstance().restartFlipper(); // intentionally forever pending, we're restarting... return new Promise(() => {}); }, diff --git a/desktop/app/src/electron/initializeElectron.tsx b/desktop/app/src/electron/initializeElectron.tsx new file mode 100644 index 000000000..c91dbfdfc --- /dev/null +++ b/desktop/app/src/electron/initializeElectron.tsx @@ -0,0 +1,80 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import path from 'path'; +import { + _NuxManagerContext, + _createNuxManager, + _setGlobalInteractionReporter, + _LoggerContext, +} from 'flipper-plugin'; +// eslint-disable-next-line flipper/no-electron-remote-imports +import {ipcRenderer, remote, SaveDialogReturnValue} from 'electron'; +import {setRenderHostInstance} from '../RenderHost'; +import {clipboard} from 'electron'; +import restart from './restartFlipper'; + +export function initializeElectron() { + setRenderHostInstance({ + processId: remote.process.pid, + readTextFromClipboard() { + return clipboard.readText(); + }, + async showSaveDialog(options) { + return (await remote.dialog.showSaveDialog(options))?.filePath; + }, + async showOpenDialog({filter, defaultPath}) { + const result = await remote.dialog.showOpenDialog({ + defaultPath, + properties: ['openFile'], + filters: filter ? [filter] : undefined, + }); + return result.filePaths?.[0]; + }, + showSelectDirectoryDialog(defaultPath = path.resolve('/')) { + return remote.dialog + .showOpenDialog({ + properties: ['openDirectory'], + defaultPath, + }) + .then((result: SaveDialogReturnValue & {filePaths: string[]}) => { + if (result.filePath) { + return result.filePath.toString(); + } + // Electron typings seem of here, just in case, + // (can be tested with settings dialog) + // handle both situations + if (result.filePaths) { + return result.filePaths[0]; + } + return undefined; + }); + }, + registerShortcut(shortcut, callback) { + remote.globalShortcut.register(shortcut, callback); + }, + hasFocus() { + return remote.getCurrentWindow().isFocused(); + }, + onIpcEvent(event, callback) { + ipcRenderer.on(event, (_ev, ...args: any[]) => { + callback(...(args as any)); + }); + }, + sendIpcEvent(event, ...args: any[]) { + ipcRenderer.send(event, ...args); + }, + shouldUseDarkColors() { + return remote.nativeTheme.shouldUseDarkColors; + }, + restartFlipper() { + restart(); + }, + }); +} diff --git a/desktop/app/src/utils/restartFlipper.tsx b/desktop/app/src/electron/restartFlipper.tsx similarity index 95% rename from desktop/app/src/utils/restartFlipper.tsx rename to desktop/app/src/electron/restartFlipper.tsx index 324efd6f9..f4677531c 100644 --- a/desktop/app/src/utils/restartFlipper.tsx +++ b/desktop/app/src/electron/restartFlipper.tsx @@ -9,7 +9,7 @@ // eslint-disable-next-line flipper/no-electron-remote-imports import {remote} from 'electron'; -import isProduction from './isProduction'; +import isProduction from '../utils/isProduction'; export default function restart(update: boolean = false) { if (isProduction()) { diff --git a/desktop/app/src/init.tsx b/desktop/app/src/init.tsx index c1d017d50..ef843b3f7 100644 --- a/desktop/app/src/init.tsx +++ b/desktop/app/src/init.tsx @@ -49,16 +49,14 @@ import styled from '@emotion/styled'; import {CopyOutlined} from '@ant-design/icons'; import {getVersionString} from './utils/versionString'; import {PersistGate} from 'redux-persist/integration/react'; -// eslint-disable-next-line flipper/no-electron-remote-imports -import {ipcRenderer, remote, SaveDialogReturnValue} from 'electron'; import { setLoggerInstance, setUserSessionManagerInstance, GK as flipperCommonGK, } from 'flipper-common'; import {internGraphPOSTAPIRequest} from './fb-stubs/user'; -import {getRenderHostInstance, setRenderHostInstance} from './RenderHost'; -import {clipboard} from 'electron'; +import {getRenderHostInstance} from './RenderHost'; +import {initializeElectron} from './electron/initializeElectron'; if (process.env.NODE_ENV === 'development' && os.platform() === 'darwin') { // By default Node.JS has its internal certificate storage and doesn't use @@ -189,7 +187,7 @@ function setProcessState(store: Store) { } function init() { - initializeFlipperForElectron(); + initializeElectron(); // TODO: centralise all those initialisations in a single configuration call flipperCommonGK.get = (name) => GK.get(name); const store = getStore(); @@ -259,59 +257,3 @@ const CodeBlock = styled(Input.TextArea)({ ...theme.monospace, color: theme.textColorSecondary, }); - -function initializeFlipperForElectron() { - setRenderHostInstance({ - processId: remote.process.pid, - readTextFromClipboard() { - return clipboard.readText(); - }, - async showSaveDialog(options) { - return (await remote.dialog.showSaveDialog(options))?.filePath; - }, - async showOpenDialog({filter, defaultPath}) { - const result = await remote.dialog.showOpenDialog({ - defaultPath, - properties: ['openFile'], - filters: filter ? [filter] : undefined, - }); - return result.filePaths?.[0]; - }, - showSelectDirectoryDialog(defaultPath = path.resolve('/')) { - return remote.dialog - .showOpenDialog({ - properties: ['openDirectory'], - defaultPath, - }) - .then((result: SaveDialogReturnValue & {filePaths: string[]}) => { - if (result.filePath) { - return result.filePath.toString(); - } - // Electron typings seem of here, just in case, - // (can be tested with settings dialog) - // handle both situations - if (result.filePaths) { - return result.filePaths[0]; - } - return undefined; - }); - }, - registerShortcut(shortcut, callback) { - remote.globalShortcut.register(shortcut, callback); - }, - hasFocus() { - return remote.getCurrentWindow().isFocused(); - }, - onIpcEvent(event, callback) { - ipcRenderer.on(event, (_ev, ...args: any[]) => { - callback(...(args as any)); - }); - }, - sendIpcEvent(event, ...args: any[]) { - ipcRenderer.send(event, ...args); - }, - shouldUseDarkColors() { - return remote.nativeTheme.shouldUseDarkColors; - }, - }); -}