diff --git a/desktop/app/src/MenuBar.tsx b/desktop/app/src/MenuBar.tsx deleted file mode 100644 index 38f0a7c40..000000000 --- a/desktop/app/src/MenuBar.tsx +++ /dev/null @@ -1,460 +0,0 @@ -/** - * 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 - */ - -// Deliberate use of remote in this context. -/* eslint-disable no-restricted-properties */ - -import {FlipperPlugin, FlipperDevicePlugin, PluginDefinition} from './plugin'; -import { - showOpenDialog, - startFileExport, - startLinkExport, -} from './utils/exportData'; -import {setStaticView} from './reducers/connections'; -import {Store} from './reducers/'; -import electron, {MenuItemConstructorOptions} from 'electron'; -import constants from './fb-stubs/constants'; -import {Logger} from 'flipper-common'; -import { - _buildInMenuEntries, - _wrapInteractionHandler, - getFlipperLib, - Dialog, -} from 'flipper-plugin'; -import {StyleGuide} from './sandy-chrome/StyleGuide'; -import {showEmulatorLauncher} from './sandy-chrome/appinspect/LaunchEmulator'; -import {webFrame} from 'electron'; -import {openDeeplinkDialog} from './deeplink'; -import React from 'react'; -import ChangelogSheet from './chrome/ChangelogSheet'; -import PluginManager from './chrome/plugin-manager/PluginManager'; -import SettingsSheet from './chrome/SettingsSheet'; -import reloadFlipper from './utils/reloadFlipper'; - -export type DefaultKeyboardAction = keyof typeof _buildInMenuEntries; -export type TopLevelMenu = 'Edit' | 'View' | 'Window' | 'Help'; - -export type KeyboardAction = { - action: string; - label: string; - accelerator?: string; -}; - -export type KeyboardActions = Array; - -const menuItems: Map = new Map(); - -let pluginActionHandler: ((action: string) => void) | null; -function actionHandler(action: string) { - if (pluginActionHandler) { - pluginActionHandler(action); - } else { - console.warn(`Unhandled keyboard action "${action}".`); - } -} - -export function setupMenuBar( - plugins: PluginDefinition[], - store: Store, - logger: Logger, -) { - const template = getTemplate( - electron.remote.app, - electron.remote.shell, - store, - logger, - ); - - // create actual menu instance - const applicationMenu = electron.remote.Menu.buildFromTemplate(template); - - // update menubar - electron.remote.Menu.setApplicationMenu(applicationMenu); -} - -export function activateMenuItems( - activePlugin: - | FlipperPlugin - | FlipperDevicePlugin, -) { - // disable all keyboard actions - for (const item of menuItems) { - item[1].enabled = false; - } - - // set plugin action handler - if (activePlugin.onKeyboardAction) { - pluginActionHandler = activePlugin.onKeyboardAction; - } - - // enable keyboard actions for the current plugin - if (activePlugin.constructor.keyboardActions != null) { - (activePlugin.constructor.keyboardActions || []).forEach( - (keyboardAction) => { - const action = - typeof keyboardAction === 'string' - ? keyboardAction - : keyboardAction.action; - const item = menuItems.get(action); - if (item != null) { - item.enabled = true; - } - }, - ); - } - - // set the application menu again to make sure it updates - electron.remote.Menu?.setApplicationMenu( - electron.remote.Menu.getApplicationMenu(), - ); -} - -function trackMenuItems(menu: string, items: MenuItemConstructorOptions[]) { - items.forEach((item) => { - if (item.label && item.click) { - item.click = _wrapInteractionHandler( - item.click, - 'MenuItem', - 'onClick', - 'flipper:menu:' + menu, - item.label, - ); - } - }); -} - -function getTemplate( - app: electron.App, - shell: electron.Shell, - store: Store, - logger: Logger, -): Array { - const exportSubmenu = [ - { - label: 'File...', - accelerator: 'CommandOrControl+E', - click: () => startFileExport(store.dispatch), - }, - ]; - if (constants.ENABLE_SHAREABLE_LINK) { - exportSubmenu.push({ - label: 'Shareable Link', - accelerator: 'CommandOrControl+Shift+E', - click: () => startLinkExport(store.dispatch), - }); - } - trackMenuItems('export', exportSubmenu); - - const fileSubmenu: MenuItemConstructorOptions[] = [ - { - label: 'Launch Emulator...', - click() { - showEmulatorLauncher(store); - }, - }, - { - label: 'Preferences', - accelerator: 'Cmd+,', - click: () => { - Dialog.showModal((onHide) => ( - - )); - }, - }, - { - label: 'Import Flipper File...', - accelerator: 'CommandOrControl+O', - click: function () { - showOpenDialog(store); - }, - }, - { - label: 'Export', - submenu: exportSubmenu, - }, - ]; - trackMenuItems('file', fileSubmenu); - - const supportRequestSubmenu = [ - { - label: 'Create...', - click: function () { - // Dispatch an action to open the export screen of Support Request form - store.dispatch( - setStaticView(require('./fb-stubs/SupportRequestFormV2').default), - ); - }, - }, - ]; - trackMenuItems('support', supportRequestSubmenu); - - fileSubmenu.push({ - label: 'Support Requests', - submenu: supportRequestSubmenu, - }); - - const viewMenu: MenuItemConstructorOptions[] = [ - { - label: 'Reload', - accelerator: 'CmdOrCtrl+R', - click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { - logger.track('usage', 'reload'); - reloadFlipper(); - }, - }, - { - label: 'Toggle Full Screen', - accelerator: (function () { - if (process.platform === 'darwin') { - return 'Ctrl+Command+F'; - } else { - return 'F11'; - } - })(), - click: function (_, focusedWindow: electron.BrowserWindow | undefined) { - if (focusedWindow) { - focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); - } - }, - }, - { - label: 'Actual Size', - accelerator: (function () { - return 'CmdOrCtrl+0'; - })(), - click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { - webFrame.setZoomFactor(1); - }, - }, - { - label: 'Zoom In', - accelerator: (function () { - return 'CmdOrCtrl+='; - })(), - click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { - webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.25); - }, - }, - { - label: 'Zoom Out', - accelerator: (function () { - return 'CmdOrCtrl+-'; - })(), - click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { - webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.25); - }, - }, - { - label: 'Manage Plugins...', - click: function () { - Dialog.showModal((onHide) => ); - }, - }, - { - type: 'separator', - }, - { - label: 'Flipper style guide', - click() { - store.dispatch(setStaticView(StyleGuide)); - }, - }, - { - label: 'Toggle Developer Tools', - accelerator: (function () { - if (process.platform === 'darwin') { - return 'Alt+Command+I'; - } else { - return 'Ctrl+Shift+I'; - } - })(), - click: function (_, focusedWindow: electron.BrowserWindow | undefined) { - if (focusedWindow) { - // @ts-ignore: https://github.com/electron/electron/issues/7832 - focusedWindow.toggleDevTools(); - } - }, - }, - { - label: 'Trigger deeplink...', - click() { - openDeeplinkDialog(store); - }, - }, - { - type: 'separator', - }, - ]; - trackMenuItems('view', viewMenu); - - const helpMenu: MenuItemConstructorOptions[] = [ - { - label: 'Getting started', - click: function () { - getFlipperLib().openLink( - 'https://fbflipper.com/docs/getting-started/index', - ); - }, - }, - { - label: 'Create plugins', - click: function () { - getFlipperLib().openLink('https://fbflipper.com/docs/tutorial/intro'); - }, - }, - { - label: 'Report problems', - click: function () { - getFlipperLib().openLink(constants.FEEDBACK_GROUP_LINK); - }, - }, - { - label: 'Changelog', - click() { - Dialog.showModal((onHide) => ); - }, - }, - ]; - trackMenuItems('help', helpMenu); - - const template: MenuItemConstructorOptions[] = [ - { - label: 'File', - submenu: fileSubmenu, - }, - { - label: 'Edit', - submenu: [ - { - label: 'Undo', - accelerator: 'CmdOrCtrl+Z', - role: 'undo', - }, - { - label: 'Redo', - accelerator: 'Shift+CmdOrCtrl+Z', - role: 'redo', - }, - { - type: 'separator', - }, - { - label: 'Cut', - accelerator: 'CmdOrCtrl+X', - role: 'cut', - }, - { - label: 'Copy', - accelerator: 'CmdOrCtrl+C', - role: 'copy', - }, - { - label: 'Paste', - accelerator: 'CmdOrCtrl+V', - role: 'paste', - }, - { - label: 'Select All', - accelerator: 'CmdOrCtrl+A', - role: 'selectAll', - }, - ], - }, - { - label: 'View', - submenu: viewMenu, - }, - { - label: 'Window', - role: 'window', - submenu: [ - { - label: 'Minimize', - accelerator: 'CmdOrCtrl+M', - role: 'minimize', - }, - { - label: 'Close', - accelerator: 'CmdOrCtrl+W', - role: 'close', - }, - ], - }, - { - label: 'Help', - role: 'help', - submenu: helpMenu, - }, - ]; - trackMenuItems('support', supportRequestSubmenu); - - if (process.platform === 'darwin') { - const name = app.name; - template.unshift({ - label: name, - submenu: [ - { - label: 'About ' + name, - role: 'about', - }, - { - type: 'separator', - }, - { - label: 'Services', - role: 'services', - submenu: [], - }, - { - type: 'separator', - }, - { - label: 'Hide ' + name, - accelerator: 'Command+H', - role: 'hide', - }, - { - label: 'Hide Others', - accelerator: 'Command+Shift+H', - role: 'hideOthers', - }, - { - label: 'Show All', - role: 'unhide', - }, - { - type: 'separator', - }, - { - label: 'Quit', - accelerator: 'Command+Q', - click: function () { - app.quit(); - }, - }, - ], - }); - const windowMenu = template.find(function (m) { - return m.role === 'window'; - }); - if (windowMenu) { - (windowMenu.submenu as MenuItemConstructorOptions[]).push( - { - type: 'separator', - }, - { - label: 'Bring All to Front', - role: 'front', - }, - ); - } - } - - return template; -} diff --git a/desktop/app/src/PluginContainer.tsx b/desktop/app/src/PluginContainer.tsx index e7b258453..8b68a4b05 100644 --- a/desktop/app/src/PluginContainer.tsx +++ b/desktop/app/src/PluginContainer.tsx @@ -29,7 +29,6 @@ import React, {PureComponent} from 'react'; import {connect, ReactReduxContext, ReactReduxContextValue} from 'react-redux'; import {selectPlugin} from './reducers/connections'; import {State as Store, MiddlewareAPI} from './reducers/index'; -import {activateMenuItems} from './MenuBar'; import {Message} from './reducers/pluginMessageQueue'; import {IdlerImpl} from './utils/Idler'; import {processMessageQueue} from './utils/messageQueue'; @@ -130,26 +129,6 @@ class PluginContainer extends PureComponent { | null | undefined; - refChanged = ( - ref: - | FlipperPlugin - | FlipperDevicePlugin - | null - | undefined, - ) => { - // N.B. for Sandy plugins this lifecycle is managed by PluginRenderer - if (this.plugin) { - this.plugin._teardown(); - this.plugin = null; - } - if (ref && this.props.target) { - activateMenuItems(ref); - ref._init(); - this.props.logger.trackTimeSince(`activePlugin-${ref.constructor.id}`); - this.plugin = ref; - } - }; - idler?: IdlerImpl; pluginBeingProcessed: string | null = null; diff --git a/desktop/app/src/chrome/PluginActionsMenu.tsx b/desktop/app/src/chrome/PluginActionsMenu.tsx index 739ea5a26..eb84d74a7 100644 --- a/desktop/app/src/chrome/PluginActionsMenu.tsx +++ b/desktop/app/src/chrome/PluginActionsMenu.tsx @@ -7,11 +7,12 @@ * @format */ -import Icon from '@ant-design/icons'; +import Icon, {MacCommandOutlined} from '@ant-design/icons'; import {css} from '@emotion/css'; -import {Button, Menu, MenuItemProps} from 'antd'; +import {Button, Menu, MenuItemProps, Row, Tooltip} from 'antd'; import { NormalizedMenuEntry, + NUX, TrackingScope, useTrackedCallback, } from 'flipper-plugin'; @@ -108,7 +109,14 @@ function PluginActionMenuItem({ return ( - {label} + + {label} + {accelerator ? ( + + + + ) : null} + ); } @@ -122,23 +130,25 @@ export function PluginActionsMenu() { return ( - - } - title="Plugin actions" - type="ghost" - /> - } - className={submenu}> - {menuEntries.map((entry) => ( - - ))} - - + + + } + title="Plugin actions" + type="ghost" + /> + } + className={submenu}> + {menuEntries.map((entry) => ( + + ))} + + + ); } diff --git a/desktop/app/src/dispatcher/plugins.tsx b/desktop/app/src/dispatcher/plugins.tsx index 32932397a..771f1509b 100644 --- a/desktop/app/src/dispatcher/plugins.tsx +++ b/desktop/app/src/dispatcher/plugins.tsx @@ -26,12 +26,10 @@ import { } from '../reducers/plugins'; import GK from '../fb-stubs/GK'; import {FlipperBasePlugin} from '../plugin'; -import {setupMenuBar} from '../MenuBar'; import fs from 'fs-extra'; import path from 'path'; import {default as config} from '../utils/processConfig'; import {notNull} from '../utils/typeUtils'; -import {sideEffect} from '../utils/sideEffect'; import { ActivatablePluginDetails, BundledPluginDetails, @@ -57,7 +55,7 @@ import {getStaticPath} from '../utils/pathUtils'; import {createSandyPluginWrapper} from '../utils/createSandyPluginWrapper'; let defaultPluginsIndex: any = null; -export default async (store: Store, logger: Logger) => { +export default async (store: Store, _logger: Logger) => { // expose Flipper and exact globally for dynamically loaded plugins const globalObject: any = typeof window === 'undefined' ? global : window; @@ -125,19 +123,6 @@ export default async (store: Store, logger: Logger) => { store.dispatch(addFailedPlugins(failedPlugins)); store.dispatch(registerPlugins(initialPlugins)); store.dispatch(pluginsInitialized()); - - sideEffect( - store, - {name: 'setupMenuBar', throttleMs: 1000, fireImmediately: true}, - (state) => state.plugins, - (plugins, store) => { - setupMenuBar( - [...plugins.devicePlugins.values(), ...plugins.clientPlugins.values()], - store, - logger, - ); - }, - ); }; function reportVersion(pluginDetails: ActivatablePluginDetails) { diff --git a/desktop/app/src/electron/initializeElectron.tsx b/desktop/app/src/electron/initializeElectron.tsx index d7ac07bc5..0040a88bf 100644 --- a/desktop/app/src/electron/initializeElectron.tsx +++ b/desktop/app/src/electron/initializeElectron.tsx @@ -25,6 +25,7 @@ import { import {getRenderHostInstance, setRenderHostInstance} from '../RenderHost'; import isProduction from '../utils/isProduction'; import fs from 'fs'; +import {setupMenuBar} from './setupMenuBar'; export function initializeElectron() { const app = remote.app; @@ -100,6 +101,8 @@ export function initializeElectron() { desktopPath: app.getPath('desktop'), }, }); + + setupMenuBar(); } function getStaticDir() { diff --git a/desktop/app/src/electron/setupMenuBar.tsx b/desktop/app/src/electron/setupMenuBar.tsx new file mode 100644 index 000000000..fc3d466f4 --- /dev/null +++ b/desktop/app/src/electron/setupMenuBar.tsx @@ -0,0 +1,236 @@ +/** + * 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 + */ + +// Deliberate use of remote in this context. +/* eslint-disable no-restricted-properties */ + +import electron, {MenuItemConstructorOptions} from 'electron'; +import {getLogger} from 'flipper-common'; +import {_buildInMenuEntries, _wrapInteractionHandler} from 'flipper-plugin'; +import {webFrame} from 'electron'; +import reloadFlipper from '../utils/reloadFlipper'; + +export function setupMenuBar() { + const template = getTemplate(electron.remote.app); + // create actual menu instance + const applicationMenu = electron.remote.Menu.buildFromTemplate(template); + // update menubar + electron.remote.Menu.setApplicationMenu(applicationMenu); +} + +function trackMenuItems(menu: string, items: MenuItemConstructorOptions[]) { + items.forEach((item) => { + if (item.label && item.click) { + item.click = _wrapInteractionHandler( + item.click, + 'MenuItem', + 'onClick', + 'flipper:menu:' + menu, + item.label, + ); + } + }); +} + +function getTemplate(app: electron.App): Array { + const viewMenu: MenuItemConstructorOptions[] = [ + { + label: 'Reload', + accelerator: 'CmdOrCtrl+R', + click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { + getLogger().track('usage', 'reload'); + reloadFlipper(); + }, + }, + { + label: 'Toggle Full Screen', + accelerator: (function () { + if (process.platform === 'darwin') { + return 'Ctrl+Command+F'; + } else { + return 'F11'; + } + })(), + click: function (_, focusedWindow: electron.BrowserWindow | undefined) { + if (focusedWindow) { + focusedWindow.setFullScreen(!focusedWindow.isFullScreen()); + } + }, + }, + { + label: 'Actual Size', + accelerator: (function () { + return 'CmdOrCtrl+0'; + })(), + click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { + webFrame.setZoomFactor(1); + }, + }, + { + label: 'Zoom In', + accelerator: (function () { + return 'CmdOrCtrl+='; + })(), + click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { + webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.25); + }, + }, + { + label: 'Zoom Out', + accelerator: (function () { + return 'CmdOrCtrl+-'; + })(), + click: function (_, _focusedWindow: electron.BrowserWindow | undefined) { + webFrame.setZoomFactor(webFrame.getZoomFactor() - 0.25); + }, + }, + { + label: 'Toggle Developer Tools', + accelerator: (function () { + if (process.platform === 'darwin') { + return 'Alt+Command+I'; + } else { + return 'Ctrl+Shift+I'; + } + })(), + click: function (_, focusedWindow: electron.BrowserWindow | undefined) { + if (focusedWindow) { + // @ts-ignore: https://github.com/electron/electron/issues/7832 + focusedWindow.toggleDevTools(); + } + }, + }, + ]; + trackMenuItems('view', viewMenu); + + const template: MenuItemConstructorOptions[] = [ + { + label: 'Edit', + submenu: [ + { + label: 'Undo', + accelerator: 'CmdOrCtrl+Z', + role: 'undo', + }, + { + label: 'Redo', + accelerator: 'Shift+CmdOrCtrl+Z', + role: 'redo', + }, + { + type: 'separator', + }, + { + label: 'Cut', + accelerator: 'CmdOrCtrl+X', + role: 'cut', + }, + { + label: 'Copy', + accelerator: 'CmdOrCtrl+C', + role: 'copy', + }, + { + label: 'Paste', + accelerator: 'CmdOrCtrl+V', + role: 'paste', + }, + { + label: 'Select All', + accelerator: 'CmdOrCtrl+A', + role: 'selectAll', + }, + ], + }, + { + label: 'View', + submenu: viewMenu, + }, + { + label: 'Window', + role: 'window', + submenu: [ + { + label: 'Minimize', + accelerator: 'CmdOrCtrl+M', + role: 'minimize', + }, + { + label: 'Close', + accelerator: 'CmdOrCtrl+W', + role: 'close', + }, + ], + }, + ]; + + if (process.platform === 'darwin') { + const name = app.name; + template.unshift({ + label: name, + submenu: [ + { + label: 'About ' + name, + role: 'about', + }, + { + type: 'separator', + }, + { + label: 'Services', + role: 'services', + submenu: [], + }, + { + type: 'separator', + }, + { + label: 'Hide ' + name, + accelerator: 'Command+H', + role: 'hide', + }, + { + label: 'Hide Others', + accelerator: 'Command+Shift+H', + role: 'hideOthers', + }, + { + label: 'Show All', + role: 'unhide', + }, + { + type: 'separator', + }, + { + label: 'Quit', + accelerator: 'Command+Q', + click: function () { + app.quit(); + }, + }, + ], + }); + const windowMenu = template.find(function (m) { + return m.role === 'window'; + }); + if (windowMenu) { + (windowMenu.submenu as MenuItemConstructorOptions[]).push( + { + type: 'separator', + }, + { + label: 'Bring All to Front', + role: 'front', + }, + ); + } + } + + return template; +} diff --git a/desktop/app/src/index.tsx b/desktop/app/src/index.tsx index 1cdae50b1..c4971b8d5 100644 --- a/desktop/app/src/index.tsx +++ b/desktop/app/src/index.tsx @@ -24,7 +24,7 @@ export { getUser, } from './fb-stubs/user'; export {FlipperPlugin, FlipperDevicePlugin, BaseAction} from './plugin'; -export {PluginClient, Props} from './plugin'; +export {PluginClient, Props, KeyboardActions} from './plugin'; export {default as Client} from './Client'; export {reportUsage} from 'flipper-common'; export {default as promiseTimeout} from './utils/promiseTimeout'; @@ -119,7 +119,6 @@ export { export {ElementFramework} from './ui/components/elements-inspector/ElementFramework'; export {InspectorSidebar} from './ui/components/elements-inspector/sidebar'; export {default as FileSelector} from './ui/components/FileSelector'; -export {KeyboardActions} from './MenuBar'; export {getFlipperMediaCDN, appendAccessTokenToUrl} from './fb-stubs/user'; export {Rect} from './utils/geometry'; export {Logger} from 'flipper-common'; diff --git a/desktop/app/src/plugin.tsx b/desktop/app/src/plugin.tsx index 6721432bd..298025fa7 100644 --- a/desktop/app/src/plugin.tsx +++ b/desktop/app/src/plugin.tsx @@ -7,7 +7,6 @@ * @format */ -import {KeyboardActions} from './MenuBar'; import {Logger} from 'flipper-common'; import Client from './Client'; import {Component} from 'react'; @@ -23,8 +22,19 @@ import { _SandyPluginDefinition, _makeShallowSerializable, _deserializeShallowObject, + _buildInMenuEntries, } from 'flipper-plugin'; +export type DefaultKeyboardAction = keyof typeof _buildInMenuEntries; + +export type KeyboardAction = { + action: string; + label: string; + accelerator?: string; +}; + +export type KeyboardActions = Array; + type Parameters = {[key: string]: any}; export type PluginDefinition = _SandyPluginDefinition; diff --git a/desktop/app/src/sandy-chrome/LeftRail.tsx b/desktop/app/src/sandy-chrome/LeftRail.tsx index 109586c22..76f4f6f11 100644 --- a/desktop/app/src/sandy-chrome/LeftRail.tsx +++ b/desktop/app/src/sandy-chrome/LeftRail.tsx @@ -31,6 +31,7 @@ import { withTrackingScope, Dialog, useTrackedCallback, + NUX, } from 'flipper-plugin'; import SetupDoctorScreen, {checkHasNewProblem} from './SetupDoctorScreen'; import SettingsSheet from '../chrome/SettingsSheet'; @@ -43,7 +44,7 @@ import config from '../fb-stubs/config'; import styled from '@emotion/styled'; import {showEmulatorLauncher} from './appinspect/LaunchEmulator'; import SupportRequestFormV2 from '../fb-stubs/SupportRequestFormV2'; -import {setStaticView, StaticView} from '../reducers/connections'; +import {setStaticView} from '../reducers/connections'; import {getLogger} from 'flipper-common'; import {SandyRatingButton} from '../chrome/RatingButton'; import {filterNotifications} from './notification/notificationUtils'; @@ -207,6 +208,11 @@ const submenu = css` display: none; } `; + +const MenuDividerPadded = styled(Menu.Divider)({ + marginBottom: '8px !important', +}); + function ExtrasMenu() { const store = useStore(); @@ -235,60 +241,64 @@ function ExtrasMenu() { return ( <> - - } small />} - className={submenu}> - {canOpenDialog() ? ( - - Import Flipper file - - ) : null} - {canFileExport() ? ( - - Export Flipper file - - ) : null} - {constants.ENABLE_SHAREABLE_LINK ? ( - - Export shareable link - - ) : null} - openDeeplinkDialog(store)}> - Trigger deeplink - - {config.isFBBuild ? ( - <> - - { - getLogger().track('usage', 'support-form-source', { - source: 'sidebar', - group: undefined, - }); - store.dispatch(setStaticView(SupportRequestFormV2)); - }}> - Feedback + + + } small />} + className={submenu}> + {canOpenDialog() ? ( + + Import Flipper file - - ) : null} - - setShowSettings(true)}> - Settings - - - setWelcomeVisible(true)}> - Help - - - + ) : null} + {canFileExport() ? ( + + Export Flipper file + + ) : null} + {constants.ENABLE_SHAREABLE_LINK ? ( + + Export shareable link + + ) : null} + openDeeplinkDialog(store)}> + Trigger deeplink + + {config.isFBBuild ? ( + <> + + { + getLogger().track('usage', 'support-form-source', { + source: 'sidebar', + group: undefined, + }); + store.dispatch(setStaticView(SupportRequestFormV2)); + }}> + Feedback + + + ) : null} + + setShowSettings(true)}> + Settings + + + setWelcomeVisible(true)}> + Help + + + + {showSettings && ( )} diff --git a/desktop/app/src/sandy-chrome/WelcomeScreen.tsx b/desktop/app/src/sandy-chrome/WelcomeScreen.tsx index 8089b10b8..592807b82 100644 --- a/desktop/app/src/sandy-chrome/WelcomeScreen.tsx +++ b/desktop/app/src/sandy-chrome/WelcomeScreen.tsx @@ -17,7 +17,14 @@ import { BugOutlined, HistoryOutlined, } from '@ant-design/icons'; -import {Dialog, Layout, theme, Tracked, TrackingScope} from 'flipper-plugin'; +import { + Dialog, + Layout, + NUX, + theme, + Tracked, + TrackingScope, +} from 'flipper-plugin'; const {Text, Title} = Typography; @@ -180,14 +187,18 @@ function WelcomeScreenContent() { {isProduction() ? `Version ${getAppVersion()}` : 'Development Mode'} -