diff --git a/desktop/app/src/chrome/CancellableExportStatus.tsx b/desktop/app/src/chrome/CancellableExportStatus.tsx deleted file mode 100644 index 2c6bf0b93..000000000 --- a/desktop/app/src/chrome/CancellableExportStatus.tsx +++ /dev/null @@ -1,39 +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 - */ - -import {FlexRow, Button} from '../ui/index'; -import {styled, LoadingIndicator, Text} from '../ui'; -import React, {Component} from 'react'; -import {colors} from '../ui/components/colors'; - -const Wrapper = styled(FlexRow)({ - color: colors.light50, - alignItems: 'center', - marginLeft: 10, -}); - -type Props = { - msg: string; - onCancel: () => void; -}; - -export default class CancellableExportStatus extends Component { - render() { - const {msg, onCancel} = this.props; - return ( - - -   - {msg} -   - - - ); - } -} diff --git a/desktop/app/src/chrome/ExportDataPluginSheet.tsx b/desktop/app/src/chrome/ExportDataPluginSheet.tsx index 94e9ba550..d87bf22de 100644 --- a/desktop/app/src/chrome/ExportDataPluginSheet.tsx +++ b/desktop/app/src/chrome/ExportDataPluginSheet.tsx @@ -9,42 +9,22 @@ import {connect} from 'react-redux'; import React, {Component} from 'react'; -import {ShareType} from '../reducers/application'; import {State as Store} from '../reducers'; -import {ActiveSheet} from '../reducers/application'; -import {selectedPlugins as actionForSelectedPlugins} from '../reducers/plugins'; -import { - ACTIVE_SHEET_SHARE_DATA, - setActiveSheet as getActiveSheetAction, - setExportDataToFileActiveSheet as getExportDataToFileActiveSheetAction, -} from '../reducers/application'; import ListView from './ListView'; -import {Dispatch, Action} from 'redux'; -import {unsetShare} from '../reducers/application'; import {FlexColumn, styled} from '../ui'; import {getExportablePlugins} from '../selectors/connections'; type OwnProps = { onHide: () => void; + selectedPlugins: Array; + setSelectedPlugins: (plugins: string[]) => void; }; type StateFromProps = { - share: ShareType | null; - selectedPlugins: Array; availablePluginsToExport: Array<{id: string; label: string}>; }; -type DispatchFromProps = { - setSelectedPlugins: (payload: Array) => void; - setActiveSheet: (payload: ActiveSheet) => void; - setExportDataToFileActiveSheet: (payload: { - file: string; - closeOnFinish: boolean; - }) => void; - unsetShare: () => void; -}; - -type Props = OwnProps & StateFromProps & DispatchFromProps; +type Props = OwnProps & StateFromProps; const Container = styled(FlexColumn)({ maxHeight: 700, @@ -53,78 +33,27 @@ const Container = styled(FlexColumn)({ class ExportDataPluginSheet extends Component { render() { - const {onHide} = this.props; - const onHideWithUnsettingShare = () => { - this.props.unsetShare(); - onHide(); - }; return ( { - const {share} = this.props; - if (!share) { - console.error( - 'applications.share is undefined, whereas it was expected to be defined', - ); - } else { - switch (share.type) { - case 'link': - this.props.setActiveSheet(ACTIVE_SHEET_SHARE_DATA); - break; - case 'file': { - const file = share.file; - if (file) { - this.props.setExportDataToFileActiveSheet({ - file, - closeOnFinish: true, - }); - } else { - console.error('share.file is undefined'); - } - } - } - } - }} onChange={(selectedArray) => { this.props.setSelectedPlugins(selectedArray); }} elements={this.props.availablePluginsToExport} selectedElements={new Set(this.props.selectedPlugins)} - onHide={onHideWithUnsettingShare} + onHide={() => {}} /> ); } } -export default connect( - (state) => { - const availablePluginsToExport = getExportablePlugins(state); - return { - share: state.application.share, - selectedPlugins: state.plugins.selectedPlugins, - availablePluginsToExport, - }; - }, - (dispatch: Dispatch>) => ({ - setSelectedPlugins: (plugins: Array) => { - dispatch(actionForSelectedPlugins(plugins)); - }, - setActiveSheet: (payload: ActiveSheet) => { - dispatch(getActiveSheetAction(payload)); - }, - setExportDataToFileActiveSheet: (payload: { - file: string; - closeOnFinish: boolean; - }) => { - dispatch(getExportDataToFileActiveSheetAction(payload)); - }, - unsetShare: () => { - dispatch(unsetShare()); - }, - }), -)(ExportDataPluginSheet); +export default connect((state) => { + const availablePluginsToExport = getExportablePlugins(state); + return { + availablePluginsToExport, + }; +})(ExportDataPluginSheet); diff --git a/desktop/app/src/chrome/SettingsSheet.tsx b/desktop/app/src/chrome/SettingsSheet.tsx index 9987624c4..a9efe593e 100644 --- a/desktop/app/src/chrome/SettingsSheet.tsx +++ b/desktop/app/src/chrome/SettingsSheet.tsx @@ -7,7 +7,6 @@ * @format */ -import {Button, FlexColumn} from '../ui'; import React, {Component, useContext} from 'react'; import {Radio} from 'antd'; import {updateSettings, Action} from '../reducers/settings'; @@ -27,13 +26,13 @@ import {isEqual, isMatch, isEmpty} from 'lodash'; import restartFlipper from '../utils/restartFlipper'; import LauncherSettingsPanel from '../fb-stubs/LauncherSettingsPanel'; import {reportUsage} from '../utils/metrics'; -import {Modal, message} from 'antd'; +import {Modal, message, Button} from 'antd'; import {Layout, withTrackingScope, _NuxManagerContext} from 'flipper-plugin'; type OwnProps = { onHide: () => void; platform: NodeJS.Platform; - noModal?: boolean; + noModal?: boolean; // used for testing }; type StateFromProps = { @@ -246,7 +245,7 @@ class SettingsSheet extends Component { })); }} /> - + Theme Selection { Light Use System Setting - + { const footer = ( <> - + @@ -388,7 +381,7 @@ function ResetTooltips() { function ResetLocalState() { return ( - - - )} - + + + Data Exported Successfully + + When sharing your Flipper data, consider that the captured data + might contain sensitive information like access tokens used in + network requests. + + + + + + + + ); } renderError(result: {kind: 'error'; error: Error}) { return ( - - {({store}) => ( - - Error - - {result.error.message || 'File could not be saved.'} - - - - - - - )} - + + Error + + {result.error.message || 'File could not be saved.'} + + + + + + ); } renderPending(statusUpdate: string | null) { return ( - - {({store}) => ( - this.cancelAndHide(store)} - onRunInBackground={() => { - this.setState({runInBackground: true}); - if (statusUpdate) { - this.dispatchAndUpdateToolBarStatus(statusUpdate); - } - this.props.onHide(); - }} - /> - )} - + this.cancelAndHide()} + /> ); } - cancelAndHide(store: MiddlewareAPI) { - store.dispatch(unsetShare()); + cancelAndHide = () => { this.props.onHide(); this.idler.cancel(); - } + }; - render() { + renderStatus() { const {result, statusUpdate} = this.state; switch (result.kind) { case 'success': @@ -252,4 +200,12 @@ export default class ShareSheetExportFile extends Component { return this.renderPending(statusUpdate); } } + + render() { + return ( + + {this.renderStatus()} + + ); + } } diff --git a/desktop/app/src/chrome/ShareSheetExportUrl.tsx b/desktop/app/src/chrome/ShareSheetExportUrl.tsx index 2934f7150..c464ca8c4 100644 --- a/desktop/app/src/chrome/ShareSheetExportUrl.tsx +++ b/desktop/app/src/chrome/ShareSheetExportUrl.tsx @@ -7,14 +7,9 @@ * @format */ -import {FlexColumn, Button, styled, Text, FlexRow, Spacer, Input} from '../ui'; +import {FlexColumn, styled, Text, FlexRow, Spacer, Input} from '../ui'; import React, {Component} from 'react'; import {ReactReduxContext} from 'react-redux'; -import { - setExportStatusComponent, - unsetShare, - setExportURL, -} from '../reducers/application'; import {Logger} from '../fb-interfaces/Logger'; import {IdlerImpl} from '../utils/Idler'; import { @@ -29,21 +24,16 @@ import { } from '../utils/exportData'; import ShareSheetErrorList from './ShareSheetErrorList'; import {reportPlatformFailures} from '../utils/metrics'; -import CancellableExportStatus from './CancellableExportStatus'; import {performance} from 'perf_hooks'; import ShareSheetPendingDialog from './ShareSheetPendingDialog'; import {getInstance as getLogger} from '../fb-stubs/Logger'; import {resetSupportFormV2State} from '../reducers/supportForm'; import {MiddlewareAPI} from '../reducers/index'; -import {getFlipperLib} from 'flipper-plugin'; +import {getFlipperLib, Layout} from 'flipper-plugin'; +import {Button, Modal} from 'antd'; export const SHARE_FLIPPER_TRACE_EVENT = 'share-flipper-link'; -const Container = styled(FlexColumn)({ - padding: 20, - width: 500, -}); - const Copy = styled(Input)({ marginRight: 0, marginBottom: 15, @@ -69,11 +59,9 @@ const ErrorMessage = styled(Text)({ type Props = { onHide: () => any; logger: Logger; - closeOnFinish: boolean; }; type State = { - runInBackground: boolean; fetchMetaDataErrors: { [plugin: string]: Error; } | null; @@ -88,7 +76,6 @@ export default class ShareSheetExportUrl extends Component { fetchMetaDataErrors: null, result: null, statusUpdate: null, - runInBackground: false, }; get store(): MiddlewareAPI { @@ -97,30 +84,12 @@ export default class ShareSheetExportUrl extends Component { idler = new IdlerImpl(); - dispatchAndUpdateToolBarStatus(msg: string) { - this.store.dispatch( - setExportStatusComponent( - { - this.idler.cancel(); - this.store.dispatch(unsetShare()); - }} - />, - ), - ); - } - async componentDidMount() { const mark = 'shareSheetExportUrl'; performance.mark(mark); try { const statusUpdate = (msg: string) => { - if (this.state.runInBackground) { - this.dispatchAndUpdateToolBarStatus(msg); - } else { - this.setState({statusUpdate: msg}); - } + this.setState({statusUpdate: msg}); }; const {serializedString, fetchMetaDataErrors} = await reportPlatformFailures( @@ -146,17 +115,13 @@ export default class ShareSheetExportUrl extends Component { }); const flipperUrl = (result as DataExportResult).flipperUrl; if (flipperUrl) { - this.store.dispatch(setExportURL(flipperUrl)); - if (this.state.runInBackground) { - getFlipperLib().writeTextToClipboard(String(flipperUrl)); - new Notification('Shareable Flipper Export created', { - body: 'URL copied to clipboard', - requireInteraction: true, - }); - } + getFlipperLib().writeTextToClipboard(String(flipperUrl)); + new Notification('Shareable Flipper Export created', { + body: 'URL copied to clipboard', + requireInteraction: true, + }); } this.setState({fetchMetaDataErrors, result}); - this.store.dispatch(unsetShare()); this.store.dispatch(resetSupportFormV2State()); this.props.logger.trackTimeSince(mark, 'export:url-success'); } catch (e) { @@ -165,62 +130,39 @@ export default class ShareSheetExportUrl extends Component { error: e, stacktrace: '', }; - if (!this.state.runInBackground) { - if (e instanceof Error) { - result.error = e.message; - result.stacktrace = e.stack || ''; - } - // Show the error in UI. - this.setState({result}); + if (e instanceof Error) { + result.error = e.message; + result.stacktrace = e.stack || ''; } - this.store.dispatch(unsetShare()); + // Show the error in UI. + this.setState({result}); this.props.logger.trackTimeSince(mark, 'export:url-error', result); - throw e; + console.error('Failed to export to flipper trace', e); } } - sheetHidden: boolean = false; - - hideSheet = () => { - this.sheetHidden = true; - this.props.onHide(); - this.idler.cancel(); - }; - componentDidUpdate() { const {result} = this.state; if (!result || !(result as DataExportResult).flipperUrl) { return; } - if (!this.sheetHidden && this.props.closeOnFinish) { - this.hideSheet(); - } } - cancelAndHide = (store: MiddlewareAPI) => () => { - store.dispatch(unsetShare()); - this.hideSheet(); + cancelAndHide = () => { + this.props.onHide(); + this.idler.cancel(); }; renderPending(statusUpdate: string | null) { return ( - - {({store}) => ( - { - this.setState({runInBackground: true}); - if (statusUpdate) { - this.dispatchAndUpdateToolBarStatus(statusUpdate); - } - this.props.onHide(); - }} - /> - )} - + + + ); } @@ -232,56 +174,54 @@ export default class ShareSheetExportUrl extends Component { const {title, errorArray} = displayFetchMetadataErrors(fetchMetaDataErrors); return ( - - {({store}) => ( - - <> - - {(result as DataExportResult).flipperUrl ? ( - <> - Data Upload Successful - - Flipper's data was successfully uploaded. This URL can be - used to share with other Flipper users. Opening it will - import the data from your export. - - - - When sharing your Flipper link, consider that the captured - data might contain sensitve information like access tokens - used in network requests. - - - - ) : ( - <> - - {(result as DataExportError).error_class || 'Error'} - - - {(result as DataExportError).error || - 'The data could not be uploaded'} - - - )} - - - - - - - - )} - + + + <> + + {(result as DataExportResult).flipperUrl ? ( + <> + Data Upload Successful + + Flipper's data was successfully uploaded. This URL can be + used to share with other Flipper users. Opening it will + import the data from your export. + + + + When sharing your Flipper link, consider that the captured + data might contain sensitve information like access tokens + used in network requests. + + + + ) : ( + <> + + {(result as DataExportError).error_class || 'Error'} + + + {(result as DataExportError).error || + 'The data could not be uploaded'} + + + )} + + + + + + + + ); } } diff --git a/desktop/app/src/chrome/ShareSheetPendingDialog.tsx b/desktop/app/src/chrome/ShareSheetPendingDialog.tsx index 6284a4c9a..f807a9b95 100644 --- a/desktop/app/src/chrome/ShareSheetPendingDialog.tsx +++ b/desktop/app/src/chrome/ShareSheetPendingDialog.tsx @@ -7,76 +7,38 @@ * @format */ -import { - FlexColumn, - styled, - Button, - colors, - Spacer, - FlexRow, - Text, - LoadingIndicator, -} from '../ui'; +import {Button, Typography} from 'antd'; +import {Layout, Spinner} from 'flipper-plugin'; import React from 'react'; -const Container = styled(FlexColumn)({ - padding: 20, -}); - -const Center = styled(FlexColumn)({ - alignItems: 'center', - paddingTop: 50, - paddingBottom: 50, -}); - -const Uploading = styled(Text)({ - marginTop: 15, -}); +const {Text} = Typography; export default function (props: { statusMessage: string; statusUpdate: string | null; hideNavButtons?: boolean; onCancel?: () => void; - onRunInBackground?: () => void; width?: number; }) { return ( - -
- - {props.statusUpdate && props.statusUpdate.length > 0 ? ( - - {props.statusUpdate} - - ) : ( - - {props.statusMessage} - - )} -
- {!props.hideNavButtons && props.onCancel && props.onRunInBackground && ( - - + + + {props.statusUpdate && props.statusUpdate.length > 0 ? ( + {props.statusUpdate} + ) : ( + {props.statusMessage} + )} + {!props.hideNavButtons && props.onCancel && ( + +
- - + )} - + ); } diff --git a/desktop/app/src/chrome/Sheet.tsx b/desktop/app/src/chrome/Sheet.tsx deleted file mode 100644 index 99ac2cbe9..000000000 --- a/desktop/app/src/chrome/Sheet.tsx +++ /dev/null @@ -1,53 +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 - */ - -import React, {Component} from 'react'; - -import {setActiveSheet} from '../reducers/application'; -import {connect} from 'react-redux'; - -import {State as Store} from '../reducers'; - -import {ActiveSheet} from '../reducers/application'; -import {Modal} from 'antd'; - -type OwnProps = { - children: (onHide: () => any) => any; -}; - -type StateFromProps = { - activeSheet: ActiveSheet; -}; - -type DispatchFromProps = { - onHideSheet: () => void; -}; - -type Props = OwnProps & StateFromProps & DispatchFromProps; -class Sheet extends Component { - render() { - return ( - - {this.props.children(this.props.onHideSheet)} - - ); - } -} - -export default connect( - ({application: {activeSheet}}) => ({ - activeSheet, - }), - { - onHideSheet: () => setActiveSheet(null), - }, -)(Sheet); diff --git a/desktop/app/src/chrome/SheetRenderer.tsx b/desktop/app/src/chrome/SheetRenderer.tsx deleted file mode 100644 index 5108735e7..000000000 --- a/desktop/app/src/chrome/SheetRenderer.tsx +++ /dev/null @@ -1,62 +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 - */ - -import React, {useCallback} from 'react'; -import ShareSheetExportUrl from './ShareSheetExportUrl'; -import ExportDataPluginSheet from './ExportDataPluginSheet'; -import ShareSheetExportFile from './ShareSheetExportFile'; -import Sheet from './Sheet'; -import { - ACTIVE_SHEET_SHARE_DATA, - ACTIVE_SHEET_SHARE_DATA_IN_FILE, - ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT, -} from '../reducers/application'; -import {Logger} from '../fb-interfaces/Logger'; -import {useStore} from '../utils/useStore'; - -export function SheetRenderer({logger}: {logger: Logger}) { - const activeSheet = useStore((state) => state.application.activeSheet); - // MWE: share being grabbed (and stored) here isn't ideal, clean up in the future? - const share = useStore((state) => state.application.share); - - const renderSheet = useCallback( - (onHide: () => any) => { - switch (activeSheet) { - case ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT: - return ; - case ACTIVE_SHEET_SHARE_DATA: - return ( - - ); - case ACTIVE_SHEET_SHARE_DATA_IN_FILE: - return share && share.type === 'file' ? ( - - ) : ( - (() => { - console.error('No file provided when calling share sheet.'); - return null; - })() - ); - default: - return null; - } - }, - [activeSheet, logger, share], - ); - - return {renderSheet}; -} diff --git a/desktop/app/src/chrome/__tests__/ShareSheetPendingDialog.node.tsx b/desktop/app/src/chrome/__tests__/ShareSheetPendingDialog.node.tsx index 22e1b1739..ff79c0620 100644 --- a/desktop/app/src/chrome/__tests__/ShareSheetPendingDialog.node.tsx +++ b/desktop/app/src/chrome/__tests__/ShareSheetPendingDialog.node.tsx @@ -20,7 +20,6 @@ test('ShareSheetPendingDialog is rendered with status update', () => { {}} - onRunInBackground={() => {}} statusMessage="wubba lubba dub dub" statusUpdate="Update" /> @@ -35,7 +34,6 @@ test('ShareSheetPendingDialog is rendered without status update', () => { {}} - onRunInBackground={() => {}} statusMessage="wubba lubba dub dub" statusUpdate={null} /> diff --git a/desktop/app/src/chrome/__tests__/__snapshots__/ShareSheetPendingDialog.node.tsx.snap b/desktop/app/src/chrome/__tests__/__snapshots__/ShareSheetPendingDialog.node.tsx.snap index 02559628a..8b0b7b9d4 100644 --- a/desktop/app/src/chrome/__tests__/__snapshots__/ShareSheetPendingDialog.node.tsx.snap +++ b/desktop/app/src/chrome/__tests__/__snapshots__/ShareSheetPendingDialog.node.tsx.snap @@ -2,35 +2,60 @@ exports[`ShareSheetPendingDialog is rendered with status update 1`] = `
-
- Update +
-
-
+ + Update + + +
+
-
`; exports[`ShareSheetPendingDialog is rendered without status update 1`] = `
-
- wubba lubba dub dub +
-
-
+ + wubba lubba dub dub + + +
+
-
`; diff --git a/desktop/app/src/chrome/plugin-manager/PluginDebugger.tsx b/desktop/app/src/chrome/plugin-manager/PluginDebugger.tsx index afbecec8a..3b539661e 100644 --- a/desktop/app/src/chrome/plugin-manager/PluginDebugger.tsx +++ b/desktop/app/src/chrome/plugin-manager/PluginDebugger.tsx @@ -8,9 +8,10 @@ */ import {PluginDetails} from 'flipper-plugin-lib'; +import {Layout} from 'flipper-plugin'; import Client from '../../Client'; import {TableBodyRow} from '../../ui/components/table/types'; -import React, {Component, Fragment} from 'react'; +import React, {Component} from 'react'; import {connect} from 'react-redux'; import {Text, ManagedTable, styled, colors} from '../../ui'; import StatusIndicator from '../../ui/components/StatusIndicator'; @@ -211,7 +212,7 @@ class PluginDebugger extends Component { render() { return ( - + The table lists all plugins known to Flipper. { columnSizes={COLUMNS_SIZES} /> - + ); } } diff --git a/desktop/app/src/reducers/application.tsx b/desktop/app/src/reducers/application.tsx index b19070277..618c9f5fb 100644 --- a/desktop/app/src/reducers/application.tsx +++ b/desktop/app/src/reducers/application.tsx @@ -11,33 +11,7 @@ // eslint-disable-next-line flipper/no-electron-remote-imports import {remote} from 'electron'; import {v1 as uuidv1} from 'uuid'; -import {ReactElement} from 'react'; -import CancellableExportStatus from '../chrome/CancellableExportStatus'; import {Actions} from './'; -export const ACTIVE_SHEET_PLUGINS: 'PLUGINS' = 'PLUGINS'; -export const ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT: 'SELECT_PLUGINS_TO_EXPORT' = - 'SELECT_PLUGINS_TO_EXPORT'; -export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA'; -export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN'; -export const ACTIVE_SHEET_SETTINGS: 'SETTINGS' = 'SETTINGS'; -export const ACTIVE_SHEET_DOCTOR: 'DOCTOR' = 'DOCTOR'; -export const ACTIVE_SHEET_SHARE_DATA_IN_FILE: 'SHARE_DATA_IN_FILE' = - 'SHARE_DATA_IN_FILE'; -export const SET_EXPORT_STATUS_MESSAGE: 'SET_EXPORT_STATUS_MESSAGE' = - 'SET_EXPORT_STATUS_MESSAGE'; -export const UNSET_SHARE: 'UNSET_SHARE' = 'UNSET_SHARE'; -export const ACTIVE_SHEET_CHANGELOG = 'ACTIVE_SHEET_CHANGELOG'; -export const ACTIVE_SHEET_CHANGELOG_RECENT_ONLY = - 'ACTIVE_SHEET_CHANGELOG_RECENT_ONLY'; - -/** - * @deprecated this is a weird mechanism, and using imperative dialogs will be simpler - */ -export type ActiveSheet = - | typeof ACTIVE_SHEET_SHARE_DATA - | typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE - | typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT - | null; export type LauncherMsg = { message: string; @@ -73,7 +47,6 @@ export type State = { rightSidebarVisible: boolean; rightSidebarAvailable: boolean; windowIsFocused: boolean; - activeSheet: ActiveSheet; share: ShareType | null; sessionId: string | null; serverPorts: ServerPorts; @@ -96,18 +69,6 @@ export type Action = type: 'windowIsFocused'; payload: {isFocused: boolean; time: number}; } - | { - type: 'SET_ACTIVE_SHEET'; - payload: ActiveSheet; - } - | { - type: typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE; - payload: {file: string; closeOnFinish: boolean}; - } - | { - type: typeof ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT; - payload: ShareType; - } | { type: 'SET_SERVER_PORTS'; payload: { @@ -129,17 +90,6 @@ export type Action = message: string; }; } - | { - type: 'UNSET_SHARE'; - } - | { - type: 'SET_EXPORT_STATUS_MESSAGE'; - payload: React.ReactNode; - } - | { - type: 'SET_EXPORT_URL'; - payload: string; - } | { type: 'ADD_STATUS_MSG'; payload: {msg: string; sender: string}; @@ -213,27 +163,6 @@ export default function reducer( ...state, windowIsFocused: action.payload.isFocused, }; - } else if (action.type === 'SET_ACTIVE_SHEET') { - return { - ...state, - activeSheet: action.payload, - }; - } else if (action.type === ACTIVE_SHEET_SHARE_DATA_IN_FILE) { - return { - ...state, - activeSheet: ACTIVE_SHEET_SHARE_DATA_IN_FILE, - share: { - type: 'file', - file: action.payload.file, - closeOnFinish: action.payload.closeOnFinish, - }, - }; - } else if (action.type === ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT) { - return { - ...state, - activeSheet: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT, - share: action.payload, - }; } else if (action.type === 'SET_SERVER_PORTS') { return { ...state, @@ -249,23 +178,6 @@ export default function reducer( ...state, launcherMsg: action.payload, }; - } else if (action.type === 'SET_EXPORT_STATUS_MESSAGE') { - if (state.share) { - const {share} = state; - return { - ...state, - share: {...share, statusComponent: action.payload}, - }; - } - return state; - } else if (action.type === 'UNSET_SHARE') { - return {...state, share: null}; - } else if (action.type === 'SET_EXPORT_URL') { - const share = state.share; - if (share && share.type === 'link') { - return {...state, share: {...share, url: action.payload}}; - } - return state; } else if (action.type === 'ADD_STATUS_MSG') { const {sender, msg} = action.payload; const statusMsg = statusMessage(sender, msg); @@ -298,37 +210,6 @@ export const toggleAction = ( payload, }); -export const unsetShare = (): Action => ({ - type: UNSET_SHARE, -}); - -export const setExportStatusComponent = ( - payload: ReactElement, -): Action => ({ - type: SET_EXPORT_STATUS_MESSAGE, - payload, -}); - -export const setSelectPluginsToExportActiveSheet = ( - payload: ShareType, -): Action => ({ - type: ACTIVE_SHEET_SELECT_PLUGINS_TO_EXPORT, - payload, -}); - -export const setExportDataToFileActiveSheet = (payload: { - file: string; - closeOnFinish: boolean; -}): Action => ({ - type: ACTIVE_SHEET_SHARE_DATA_IN_FILE, - payload: payload, -}); - -export const setActiveSheet = (payload: ActiveSheet): Action => ({ - type: 'SET_ACTIVE_SHEET', - payload, -}); - export const toggleLeftSidebarVisible = (payload?: boolean): Action => ({ type: 'leftSidebarVisible', payload, @@ -344,11 +225,6 @@ export const toggleRightSidebarAvailable = (payload?: boolean): Action => ({ payload, }); -export const setExportURL = (result: string): Action => ({ - type: 'SET_EXPORT_URL', - payload: result, -}); - export const addStatusMessage = (payload: StatusMessageType): Action => ({ type: 'ADD_STATUS_MSG', payload, diff --git a/desktop/app/src/sandy-chrome/SandyApp.tsx b/desktop/app/src/sandy-chrome/SandyApp.tsx index fb04f703e..17c6a6c5a 100644 --- a/desktop/app/src/sandy-chrome/SandyApp.tsx +++ b/desktop/app/src/sandy-chrome/SandyApp.tsx @@ -30,7 +30,6 @@ import {AppInspect} from './appinspect/AppInspect'; import PluginContainer from '../PluginContainer'; import {ContentContainer} from './ContentContainer'; import {Notification} from './notification/Notification'; -import {SheetRenderer} from '../chrome/SheetRenderer'; import ChangelogSheet, {hasNewChangesToShow} from '../chrome/ChangelogSheet'; import {getVersionString} from '../utils/versionString'; import config from '../fb-stubs/config'; @@ -179,7 +178,6 @@ export function SandyApp() { {outOfContentsContainer} - <_PortalsManager /> ); diff --git a/desktop/app/src/utils/exportData.tsx b/desktop/app/src/utils/exportData.tsx index b6264647e..ac49bf566 100644 --- a/desktop/app/src/utils/exportData.tsx +++ b/desktop/app/src/utils/exportData.tsx @@ -7,13 +7,14 @@ * @format */ +import * as React from 'react'; import os from 'os'; import path from 'path'; import electron from 'electron'; -import {getInstance as getLogger} from '../fb-stubs/Logger'; +import {getInstance, getInstance as getLogger} from '../fb-stubs/Logger'; import {Store, MiddlewareAPI} from '../reducers'; import {DeviceExport} from '../devices/BaseDevice'; -import {State as PluginsState} from '../reducers/plugins'; +import {selectedPlugins, State as PluginsState} from '../reducers/plugins'; import {PluginNotification} from '../reducers/notifications'; import Client, {ClientExport} from '../Client'; import {getAppVersion} from './info'; @@ -33,14 +34,16 @@ import { resetSupportFormV2State, SupportFormRequestDetailsState, } from '../reducers/supportForm'; -import {setSelectPluginsToExportActiveSheet} from '../reducers/application'; import {deconstructClientId} from '../utils/clientUtils'; import {performance} from 'perf_hooks'; import {processMessageQueue} from './messageQueue'; import {getPluginTitle} from './pluginUtils'; import {capture} from './screenshot'; import {uploadFlipperMedia} from '../fb-stubs/user'; -import {ClientQuery, Idler} from 'flipper-plugin'; +import {ClientQuery, Dialog, Idler} from 'flipper-plugin'; +import ShareSheetExportUrl from '../chrome/ShareSheetExportUrl'; +import ShareSheetExportFile from '../chrome/ShareSheetExportFile'; +import ExportDataPluginSheet from '../chrome/ExportDataPluginSheet'; export const IMPORT_FLIPPER_TRACE_EVENT = 'import-flipper-trace'; export const EXPORT_FLIPPER_TRACE_EVENT = 'export-flipper-trace'; @@ -612,36 +615,54 @@ export function showOpenDialog(store: Store) { }); } -export function startFileExport(dispatch: Store['dispatch']) { - electron.remote.dialog - .showSaveDialog( - // @ts-ignore This appears to work but isn't allowed by the types - null, - { - title: 'FlipperExport', - defaultPath: path.join(os.homedir(), 'FlipperExport.flipper'), - }, - ) - .then(async (result: electron.SaveDialogReturnValue) => { - const file = result.filePath; - if (!file) { - return; - } - dispatch( - setSelectPluginsToExportActiveSheet({ - type: 'file', - file: file, - closeOnFinish: false, - }), - ); - }); +export async function startFileExport(dispatch: Store['dispatch']) { + const result = await electron.remote.dialog.showSaveDialog( + // @ts-ignore This appears to work but isn't allowed by the types + null, + { + title: 'FlipperExport', + defaultPath: path.join(os.homedir(), 'FlipperExport.flipper'), + }, + ); + const file = result.filePath; + if (!file) { + return; + } + const plugins = await selectPlugins(); + if (plugins === false) { + return; // cancelled + } + // TODO: no need to put this in the store, + // need to be cleaned up later in combination with SupportForm + dispatch(selectedPlugins(plugins)); + Dialog.showModal((onHide) => ( + + )); } -export function startLinkExport(dispatch: Store['dispatch']) { - dispatch( - setSelectPluginsToExportActiveSheet({ - type: 'link', - closeOnFinish: false, - }), - ); +export async function startLinkExport(dispatch: Store['dispatch']) { + const plugins = await selectPlugins(); + if (plugins === false) { + return; // cancelled + } + // TODO: no need to put this in the store, + // need to be cleaned up later in combination with SupportForm + dispatch(selectedPlugins(plugins)); + Dialog.showModal((onHide) => ( + + )); +} + +async function selectPlugins() { + return await Dialog.select({ + title: 'Select plugins to export', + defaultValue: [], + renderer: (value, onChange, onCancel) => ( + + ), + }); } diff --git a/desktop/flipper-plugin/src/ui/Dialog.tsx b/desktop/flipper-plugin/src/ui/Dialog.tsx index 5120074c1..d2d13004a 100644 --- a/desktop/flipper-plugin/src/ui/Dialog.tsx +++ b/desktop/flipper-plugin/src/ui/Dialog.tsx @@ -237,6 +237,27 @@ export const Dialog = { }); }, + select({ + defaultValue, + renderer, + ...rest + }: { + defaultValue: T; + renderer: ( + value: T, + onChange: (newValue: T) => void, + onCancel: () => void, + ) => React.ReactElement; + } & BaseDialogOptions): DialogResult { + const handle = Dialog.show({ + ...rest, + defaultValue, + children: (currentValue, setValue): React.ReactElement => + renderer(currentValue, setValue, () => handle.close()), + }); + return handle; + }, + loading({ title, message,