Share sheet for the file export
Summary: This diff shows an export sheet when one exports the Flipper data in a file. It also shows if any error happens. Look at the video in test case. Reviewed By: danielbuechele Differential Revision: D14624194 fbshipit-source-id: dea0179a83e626e49593e5dde1d5ff128048db02
This commit is contained in:
committed by
Facebook Github Bot
parent
2dacea8541
commit
45999a5292
12
src/App.js
12
src/App.js
@@ -15,6 +15,7 @@ import BugReporterDialog from './chrome/BugReporterDialog.js';
|
|||||||
import ErrorBar from './chrome/ErrorBar.js';
|
import ErrorBar from './chrome/ErrorBar.js';
|
||||||
import ShareSheet from './chrome/ShareSheet.js';
|
import ShareSheet from './chrome/ShareSheet.js';
|
||||||
import SignInSheet from './chrome/SignInSheet.js';
|
import SignInSheet from './chrome/SignInSheet.js';
|
||||||
|
import ShareSheetExportFile from './chrome/ShareSheetExportFile.js';
|
||||||
import PluginContainer from './PluginContainer.js';
|
import PluginContainer from './PluginContainer.js';
|
||||||
import Sheet from './chrome/Sheet.js';
|
import Sheet from './chrome/Sheet.js';
|
||||||
import {ipcRenderer, remote} from 'electron';
|
import {ipcRenderer, remote} from 'electron';
|
||||||
@@ -24,6 +25,7 @@ import {
|
|||||||
ACTIVE_SHEET_PLUGIN_DEBUGGER,
|
ACTIVE_SHEET_PLUGIN_DEBUGGER,
|
||||||
ACTIVE_SHEET_SHARE_DATA,
|
ACTIVE_SHEET_SHARE_DATA,
|
||||||
ACTIVE_SHEET_SIGN_IN,
|
ACTIVE_SHEET_SIGN_IN,
|
||||||
|
ACTIVE_SHEET_SHARE_DATA_IN_FILE,
|
||||||
} from './reducers/application.js';
|
} from './reducers/application.js';
|
||||||
|
|
||||||
import type {Logger} from './fb-interfaces/Logger.js';
|
import type {Logger} from './fb-interfaces/Logger.js';
|
||||||
@@ -44,6 +46,7 @@ type Props = {|
|
|||||||
selectedDevice: ?BaseDevice,
|
selectedDevice: ?BaseDevice,
|
||||||
error: ?string,
|
error: ?string,
|
||||||
activeSheet: ActiveSheet,
|
activeSheet: ActiveSheet,
|
||||||
|
exportFile: ?string,
|
||||||
|};
|
|};
|
||||||
|
|
||||||
export class App extends React.Component<Props> {
|
export class App extends React.Component<Props> {
|
||||||
@@ -76,6 +79,12 @@ export class App extends React.Component<Props> {
|
|||||||
return <ShareSheet onHide={onHide} />;
|
return <ShareSheet onHide={onHide} />;
|
||||||
} else if (this.props.activeSheet === ACTIVE_SHEET_SIGN_IN) {
|
} else if (this.props.activeSheet === ACTIVE_SHEET_SIGN_IN) {
|
||||||
return <SignInSheet onHide={onHide} />;
|
return <SignInSheet onHide={onHide} />;
|
||||||
|
} else if (this.props.activeSheet === ACTIVE_SHEET_SHARE_DATA_IN_FILE) {
|
||||||
|
const {exportFile} = this.props;
|
||||||
|
if (!exportFile) {
|
||||||
|
throw new Error('Tried to export data without passing the file path');
|
||||||
|
}
|
||||||
|
return <ShareSheetExportFile onHide={onHide} file={exportFile} />;
|
||||||
} else {
|
} else {
|
||||||
// contents are added via React.Portal
|
// contents are added via React.Portal
|
||||||
return null;
|
return null;
|
||||||
@@ -103,12 +112,13 @@ export class App extends React.Component<Props> {
|
|||||||
|
|
||||||
export default connect<Props, OwnProps, _, _, _, _>(
|
export default connect<Props, OwnProps, _, _, _, _>(
|
||||||
({
|
({
|
||||||
application: {leftSidebarVisible, activeSheet},
|
application: {leftSidebarVisible, activeSheet, exportFile},
|
||||||
connections: {selectedDevice, error},
|
connections: {selectedDevice, error},
|
||||||
}) => ({
|
}) => ({
|
||||||
leftSidebarVisible,
|
leftSidebarVisible,
|
||||||
selectedDevice,
|
selectedDevice,
|
||||||
activeSheet,
|
activeSheet,
|
||||||
|
exportFile,
|
||||||
error,
|
error,
|
||||||
}),
|
}),
|
||||||
)(App);
|
)(App);
|
||||||
|
|||||||
@@ -6,22 +6,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js';
|
import type {FlipperPlugin, FlipperDevicePlugin} from './plugin.js';
|
||||||
|
import {showOpenDialog} from './utils/exportData.js';
|
||||||
import {
|
import {
|
||||||
exportStoreToFile,
|
setExportDataToFileActiveSheet,
|
||||||
showOpenDialog,
|
setActiveSheet,
|
||||||
EXPORT_FLIPPER_TRACE_EVENT,
|
ACTIVE_SHEET_SHARE_DATA,
|
||||||
} from './utils/exportData.js';
|
} from './reducers/application';
|
||||||
import {setActiveSheet, ACTIVE_SHEET_SHARE_DATA} from './reducers/application';
|
|
||||||
import type {Store} from './reducers/';
|
import type {Store} from './reducers/';
|
||||||
import electron from 'electron';
|
import electron from 'electron';
|
||||||
import {ENABLE_SHAREABLE_LINK} from 'flipper';
|
import {ENABLE_SHAREABLE_LINK} from 'flipper';
|
||||||
import {remote} from 'electron';
|
|
||||||
const {dialog} = remote;
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
import {reportPlatformFailures} 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';
|
||||||
|
const {dialog} = electron.remote;
|
||||||
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
type MenuItem = {|
|
type MenuItem = {|
|
||||||
label?: string,
|
label?: string,
|
||||||
@@ -199,11 +197,11 @@ function getTemplate(
|
|||||||
title: 'FlipperExport',
|
title: 'FlipperExport',
|
||||||
defaultPath: path.join(os.homedir(), 'FlipperExport.flipper'),
|
defaultPath: path.join(os.homedir(), 'FlipperExport.flipper'),
|
||||||
},
|
},
|
||||||
file => {
|
async file => {
|
||||||
reportPlatformFailures(
|
if (!file) {
|
||||||
exportStoreToFile(file, store),
|
return;
|
||||||
`${EXPORT_FLIPPER_TRACE_EVENT}:UI`,
|
}
|
||||||
);
|
store.dispatch(setExportDataToFileActiveSheet(file));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ test('Empty app state matches snapshot', () => {
|
|||||||
selectedDevice={null}
|
selectedDevice={null}
|
||||||
error={null}
|
error={null}
|
||||||
activeSheet={null}
|
activeSheet={null}
|
||||||
|
exportFile={null}
|
||||||
/>
|
/>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
);
|
);
|
||||||
|
|||||||
143
src/chrome/ShareSheetExportFile.js
Normal file
143
src/chrome/ShareSheetExportFile.js
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018-present Facebook.
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
* @format
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
FlexColumn,
|
||||||
|
Button,
|
||||||
|
styled,
|
||||||
|
colors,
|
||||||
|
Text,
|
||||||
|
LoadingIndicator,
|
||||||
|
Component,
|
||||||
|
FlexRow,
|
||||||
|
Spacer,
|
||||||
|
} from 'flipper';
|
||||||
|
import {reportPlatformFailures} from '../utils/metrics';
|
||||||
|
import {
|
||||||
|
exportStoreToFile,
|
||||||
|
EXPORT_FLIPPER_TRACE_EVENT,
|
||||||
|
} from '../utils/exportData.js';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
const Container = styled(FlexColumn)({
|
||||||
|
padding: 20,
|
||||||
|
width: 500,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Center = styled(FlexColumn)({
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingTop: 50,
|
||||||
|
paddingBottom: 50,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Uploading = styled(Text)({
|
||||||
|
marginTop: 15,
|
||||||
|
});
|
||||||
|
|
||||||
|
const ErrorMessage = styled(Text)({
|
||||||
|
display: 'block',
|
||||||
|
marginTop: 6,
|
||||||
|
wordBreak: 'break-all',
|
||||||
|
whiteSpace: 'pre-line',
|
||||||
|
lineHeight: 1.35,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Title = styled(Text)({
|
||||||
|
marginBottom: 6,
|
||||||
|
});
|
||||||
|
|
||||||
|
const InfoText = styled(Text)({
|
||||||
|
lineHeight: 1.35,
|
||||||
|
marginBottom: 15,
|
||||||
|
});
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
onHide: () => mixed,
|
||||||
|
file: string,
|
||||||
|
};
|
||||||
|
type State = {
|
||||||
|
result: ?{
|
||||||
|
success: boolean,
|
||||||
|
error: ?Error,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class ShareSheetExportFile extends Component<Props, State> {
|
||||||
|
static contextTypes = {
|
||||||
|
store: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
result: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
async componentDidMount() {
|
||||||
|
try {
|
||||||
|
await reportPlatformFailures(
|
||||||
|
exportStoreToFile(this.props.file, this.context.store),
|
||||||
|
`${EXPORT_FLIPPER_TRACE_EVENT}:UI`,
|
||||||
|
);
|
||||||
|
this.setState({result: {success: true, error: null}});
|
||||||
|
} catch (err) {
|
||||||
|
this.setState({result: {success: false, error: err}});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {result} = this.state;
|
||||||
|
if (result) {
|
||||||
|
const {success, error} = result;
|
||||||
|
if (success) {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<FlexColumn>
|
||||||
|
<Title bold>Data Exported Successfully</Title>
|
||||||
|
<InfoText>
|
||||||
|
When sharing your Flipper data, consider that the captured data
|
||||||
|
might contain sensitive information like access tokens used in
|
||||||
|
network requests.
|
||||||
|
</InfoText>
|
||||||
|
</FlexColumn>
|
||||||
|
<FlexRow>
|
||||||
|
<Spacer />
|
||||||
|
<Button compact padded onClick={this.props.onHide}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</FlexRow>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Title bold>Error</Title>
|
||||||
|
<ErrorMessage code>
|
||||||
|
{error?.message || 'File could not be saved.'}
|
||||||
|
</ErrorMessage>
|
||||||
|
<FlexRow>
|
||||||
|
<Spacer />
|
||||||
|
<Button compact padded onClick={this.props.onHide}>
|
||||||
|
Close
|
||||||
|
</Button>
|
||||||
|
</FlexRow>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Container>
|
||||||
|
<Center>
|
||||||
|
<LoadingIndicator size={30} />
|
||||||
|
<Uploading bold color={colors.macOSTitleBarIcon}>
|
||||||
|
Exporting Flipper trace...
|
||||||
|
</Uploading>
|
||||||
|
</Center>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,8 @@ export const ACTIVE_SHEET_PLUGIN_DEBUGGER: 'PLUGIN_DEBUGGER' =
|
|||||||
'PLUGIN_DEBUGGER';
|
'PLUGIN_DEBUGGER';
|
||||||
export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA';
|
export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA';
|
||||||
export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN';
|
export const ACTIVE_SHEET_SIGN_IN: 'SIGN_IN' = 'SIGN_IN';
|
||||||
|
export const ACTIVE_SHEET_SHARE_DATA_IN_FILE: 'SHARE_DATA_IN_FILE' =
|
||||||
|
'SHARE_DATA_IN_FILE';
|
||||||
|
|
||||||
export type ActiveSheet =
|
export type ActiveSheet =
|
||||||
| typeof ACTIVE_SHEET_PLUGIN_SHEET
|
| typeof ACTIVE_SHEET_PLUGIN_SHEET
|
||||||
@@ -21,6 +23,7 @@ export type ActiveSheet =
|
|||||||
| typeof ACTIVE_SHEET_PLUGIN_DEBUGGER
|
| typeof ACTIVE_SHEET_PLUGIN_DEBUGGER
|
||||||
| typeof ACTIVE_SHEET_SHARE_DATA
|
| typeof ACTIVE_SHEET_SHARE_DATA
|
||||||
| typeof ACTIVE_SHEET_SIGN_IN
|
| typeof ACTIVE_SHEET_SIGN_IN
|
||||||
|
| typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE
|
||||||
| null;
|
| null;
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
@@ -29,6 +32,7 @@ export type State = {
|
|||||||
rightSidebarAvailable: boolean,
|
rightSidebarAvailable: boolean,
|
||||||
windowIsFocused: boolean,
|
windowIsFocused: boolean,
|
||||||
activeSheet: ActiveSheet,
|
activeSheet: ActiveSheet,
|
||||||
|
exportFile: ?string,
|
||||||
sessionId: ?string,
|
sessionId: ?string,
|
||||||
serverPorts: {
|
serverPorts: {
|
||||||
insecure: number,
|
insecure: number,
|
||||||
@@ -53,6 +57,10 @@ export type Action =
|
|||||||
type: 'SET_ACTIVE_SHEET',
|
type: 'SET_ACTIVE_SHEET',
|
||||||
payload: ActiveSheet,
|
payload: ActiveSheet,
|
||||||
}
|
}
|
||||||
|
| {
|
||||||
|
type: typeof ACTIVE_SHEET_SHARE_DATA_IN_FILE,
|
||||||
|
payload: {file: string},
|
||||||
|
}
|
||||||
| {
|
| {
|
||||||
type: 'SET_SERVER_PORTS',
|
type: 'SET_SERVER_PORTS',
|
||||||
payload: {
|
payload: {
|
||||||
@@ -67,6 +75,7 @@ const initialState: () => State = () => ({
|
|||||||
rightSidebarAvailable: false,
|
rightSidebarAvailable: false,
|
||||||
windowIsFocused: remote.getCurrentWindow().isFocused(),
|
windowIsFocused: remote.getCurrentWindow().isFocused(),
|
||||||
activeSheet: null,
|
activeSheet: null,
|
||||||
|
exportFile: null,
|
||||||
sessionId: uuidv1(),
|
sessionId: uuidv1(),
|
||||||
serverPorts: {
|
serverPorts: {
|
||||||
insecure: 8089,
|
insecure: 8089,
|
||||||
@@ -103,6 +112,12 @@ export default function reducer(state: State, action: Action): State {
|
|||||||
...state,
|
...state,
|
||||||
activeSheet: action.payload,
|
activeSheet: action.payload,
|
||||||
};
|
};
|
||||||
|
} else if (action.type === ACTIVE_SHEET_SHARE_DATA_IN_FILE) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeSheet: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
|
||||||
|
exportFile: action.payload.file,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
if (action.type === 'SET_SERVER_PORTS') {
|
if (action.type === 'SET_SERVER_PORTS') {
|
||||||
return {
|
return {
|
||||||
@@ -122,6 +137,11 @@ export const toggleAction = (
|
|||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setExportDataToFileActiveSheet = (file: string): Action => ({
|
||||||
|
type: ACTIVE_SHEET_SHARE_DATA_IN_FILE,
|
||||||
|
payload: {file},
|
||||||
|
});
|
||||||
|
|
||||||
export const setActiveSheet = (payload: ActiveSheet): Action => ({
|
export const setActiveSheet = (payload: ActiveSheet): Action => ({
|
||||||
type: 'SET_ACTIVE_SHEET',
|
type: 'SET_ACTIVE_SHEET',
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
Reference in New Issue
Block a user