Run export flipper trace in background
Summary: Adds the capability to run the export in the background along with the display of the status in the title bar. Reviewed By: danielbuechele Differential Revision: D16567026 fbshipit-source-id: 3955243cd7f094a7ee33eef3511804ff6e6476be
This commit is contained in:
committed by
Facebook Github Bot
parent
84b64b75dc
commit
8c9eb30060
37
src/chrome/CancellableExportStatus.js
Normal file
37
src/chrome/CancellableExportStatus.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 {FlexRow, Button} from '../ui/index';
|
||||
import {styled, LoadingIndicator, Text} from 'flipper';
|
||||
import {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 => void,
|
||||
};
|
||||
|
||||
export default class CancellableExportStatus extends Component<Props> {
|
||||
render() {
|
||||
const {msg, onCancel} = this.props;
|
||||
return (
|
||||
<Wrapper>
|
||||
<LoadingIndicator size={16} />
|
||||
|
||||
<Text>{msg}</Text>
|
||||
|
||||
<Button onClick={onCancel}> Cancel </Button>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
Spacer,
|
||||
Input,
|
||||
} from 'flipper';
|
||||
import {setExportStatusComponent, unsetShare} from '../reducers/application';
|
||||
import type {Logger} from '../fb-interfaces/Logger.js';
|
||||
import {Idler} from '../utils/Idler';
|
||||
import {shareFlipperData} from '../fb-stubs/user';
|
||||
@@ -25,6 +26,7 @@ import PropTypes from 'prop-types';
|
||||
import {clipboard} from 'electron';
|
||||
import ShareSheetErrorList from './ShareSheetErrorList.js';
|
||||
import {reportPlatformFailures} from '../utils/metrics';
|
||||
import CancellableExportStatus from './CancellableExportStatus';
|
||||
// $FlowFixMe: Missing type defs for node built-in.
|
||||
import {performance} from 'perf_hooks';
|
||||
export const SHARE_FLIPPER_TRACE_EVENT = 'share-flipper-link';
|
||||
@@ -71,6 +73,7 @@ type Props = {
|
||||
logger: Logger,
|
||||
};
|
||||
type State = {
|
||||
runInBackground: boolean,
|
||||
errorArray: Array<Error>,
|
||||
result:
|
||||
| ?{
|
||||
@@ -92,21 +95,42 @@ export default class ShareSheet extends Component<Props, State> {
|
||||
errorArray: [],
|
||||
result: null,
|
||||
statusUpdate: null,
|
||||
runInBackground: false,
|
||||
};
|
||||
|
||||
idler = new Idler();
|
||||
|
||||
dispatchAndUpdateToolBarStatus(msg: string) {
|
||||
this.context.store.dispatch(
|
||||
setExportStatusComponent(
|
||||
<CancellableExportStatus
|
||||
msg={msg}
|
||||
onCancel={() => {
|
||||
this.idler.cancel();
|
||||
this.context.store.dispatch(unsetShare());
|
||||
}}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const mark = 'shareSheetExportUrl';
|
||||
performance.mark(mark);
|
||||
try {
|
||||
const {serializedString, errorArray} = await reportPlatformFailures(
|
||||
exportStore(this.context.store, this.idler, (msg: string) => {
|
||||
this.setState({statusUpdate: msg});
|
||||
if (this.state.runInBackground) {
|
||||
this.dispatchAndUpdateToolBarStatus(msg);
|
||||
} else {
|
||||
this.setState({statusUpdate: msg});
|
||||
}
|
||||
}),
|
||||
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_LINK`,
|
||||
);
|
||||
|
||||
this.context.store.dispatch(unsetShare());
|
||||
|
||||
const result = await reportPlatformFailures(
|
||||
shareFlipperData(serializedString),
|
||||
`${SHARE_FLIPPER_TRACE_EVENT}`,
|
||||
@@ -151,6 +175,19 @@ export default class ShareSheet extends Component<Props, State> {
|
||||
</Center>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button
|
||||
compact
|
||||
padded
|
||||
onClick={() => {
|
||||
this.setState({runInBackground: true});
|
||||
const {statusUpdate} = this.state;
|
||||
if (statusUpdate) {
|
||||
this.dispatchAndUpdateToolBarStatus(statusUpdate);
|
||||
}
|
||||
this.props.onHide();
|
||||
}}>
|
||||
Run In Background
|
||||
</Button>
|
||||
<Button compact padded onClick={onHide}>
|
||||
Close
|
||||
</Button>
|
||||
|
||||
@@ -15,7 +15,9 @@ import {
|
||||
FlexRow,
|
||||
Spacer,
|
||||
} from 'flipper';
|
||||
import {setExportStatusComponent, unsetShare} from '../reducers/application';
|
||||
import {reportPlatformFailures} from '../utils/metrics';
|
||||
import CancellableExportStatus from './CancellableExportStatus';
|
||||
// $FlowFixMe: Missing type defs for node built-in.
|
||||
import {performance} from 'perf_hooks';
|
||||
import type {Logger} from '../fb-interfaces/Logger.js';
|
||||
@@ -72,6 +74,7 @@ type State = {
|
||||
error: ?Error,
|
||||
},
|
||||
statusUpdate: ?string,
|
||||
runInBackground: boolean,
|
||||
};
|
||||
|
||||
export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
@@ -83,10 +86,25 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
errorArray: [],
|
||||
result: null,
|
||||
statusUpdate: null,
|
||||
runInBackground: false,
|
||||
};
|
||||
|
||||
idler = new Idler();
|
||||
|
||||
dispatchAndUpdateToolBarStatus(msg: string) {
|
||||
this.context.store.dispatch(
|
||||
setExportStatusComponent(
|
||||
<CancellableExportStatus
|
||||
msg={msg}
|
||||
onCancel={() => {
|
||||
this.idler.cancel();
|
||||
this.context.store.dispatch(unsetShare());
|
||||
}}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const mark = 'shareSheetExportFile';
|
||||
performance.mark(mark);
|
||||
@@ -102,11 +120,24 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
this.context.store,
|
||||
this.idler,
|
||||
(msg: string) => {
|
||||
this.setState({statusUpdate: msg});
|
||||
if (this.state.runInBackground) {
|
||||
this.dispatchAndUpdateToolBarStatus(msg);
|
||||
} else {
|
||||
this.setState({statusUpdate: msg});
|
||||
}
|
||||
},
|
||||
),
|
||||
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_FILE`,
|
||||
);
|
||||
this.context.store.dispatch(unsetShare());
|
||||
if (this.state.runInBackground) {
|
||||
new window.Notification('Sharable Flipper trace created', {
|
||||
//$FlowFixMe: Already checked that props.file exists
|
||||
body: `Flipper trace exported to the ${this.props.file}`,
|
||||
requireInteraction: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setState({errorArray, result: {success: true, error: null}});
|
||||
this.props.logger.trackTimeSince(mark, 'export:file-success');
|
||||
} catch (err) {
|
||||
@@ -182,6 +213,19 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
</Center>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button
|
||||
compact
|
||||
padded
|
||||
onClick={() => {
|
||||
this.setState({runInBackground: true});
|
||||
const {statusUpdate} = this.state;
|
||||
if (statusUpdate) {
|
||||
this.dispatchAndUpdateToolBarStatus(statusUpdate);
|
||||
}
|
||||
this.props.onHide();
|
||||
}}>
|
||||
Run In Background
|
||||
</Button>
|
||||
<Button compact padded onClick={onHide}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {ActiveSheet, LauncherMsg} from '../reducers/application.js';
|
||||
import {ActiveSheet, LauncherMsg, ShareType} from '../reducers/application.js';
|
||||
|
||||
import {
|
||||
colors,
|
||||
@@ -75,6 +75,7 @@ type StateFromProps = {
|
||||
downloadingImportData: boolean,
|
||||
launcherMsg: LauncherMsg,
|
||||
flipperRating: number | null,
|
||||
share: ShareType | null | undefined,
|
||||
};
|
||||
|
||||
const VersionText = styled(Text)({
|
||||
@@ -115,20 +116,36 @@ const Importing = styled(FlexRow)({
|
||||
marginLeft: 10,
|
||||
});
|
||||
|
||||
function statusMessageComponent(
|
||||
downloadingImportData: boolean,
|
||||
statusComponent?: React.ReactElement<any> | undefined,
|
||||
) {
|
||||
if (downloadingImportData) {
|
||||
return (
|
||||
<Importing>
|
||||
<LoadingIndicator size={16} />
|
||||
Importing data...
|
||||
</Importing>
|
||||
);
|
||||
}
|
||||
if (statusComponent) {
|
||||
return statusComponent;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
type Props = OwnProps & DispatchFromProps & StateFromProps;
|
||||
class TitleBar extends React.Component<Props> {
|
||||
class TitleBar extends React.Component<Props, StateFromProps> {
|
||||
render() {
|
||||
const {share} = this.props;
|
||||
return (
|
||||
<AppTitleBar focused={this.props.windowIsFocused} className="toolbar">
|
||||
<DevicesButton />
|
||||
<ScreenCaptureButtons />
|
||||
{this.props.downloadingImportData && (
|
||||
<Importing>
|
||||
<LoadingIndicator size={16} />
|
||||
Importing data...
|
||||
</Importing>
|
||||
{statusMessageComponent(
|
||||
this.props.downloadingImportData,
|
||||
share != null ? share.statusComponent : undefined,
|
||||
)}
|
||||
|
||||
<Spacer />
|
||||
{config.showFlipperRating ? (
|
||||
<RatingButton
|
||||
@@ -187,6 +204,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
downloadingImportData,
|
||||
launcherMsg,
|
||||
flipperRating,
|
||||
share,
|
||||
},
|
||||
}) => ({
|
||||
windowIsFocused,
|
||||
@@ -196,6 +214,7 @@ export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
downloadingImportData,
|
||||
launcherMsg,
|
||||
flipperRating,
|
||||
share,
|
||||
}),
|
||||
{
|
||||
setActiveSheet,
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
|
||||
import {remote} from 'electron';
|
||||
import uuidv1 from 'uuid/v1';
|
||||
|
||||
import {type Element as ReactElement} from 'react';
|
||||
import CancellableExportStatus from '../chrome/CancellableExportStatus';
|
||||
export const ACTIVE_SHEET_PLUGIN_SHEET: 'PLUGIN_SHEET' = 'PLUGIN_SHEET';
|
||||
export const ACTIVE_SHEET_BUG_REPORTER: 'BUG_REPORTER' = 'BUG_REPORTER';
|
||||
export const ACTIVE_SHEET_PLUGIN_DEBUGGER: 'PLUGIN_DEBUGGER' =
|
||||
@@ -18,6 +19,9 @@ export const ACTIVE_SHEET_SHARE_DATA: 'SHARE_DATA' = 'SHARE_DATA';
|
||||
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 const SET_EXPORT_STATUS_MESSAGE: 'SET_EXPORT_STATUS_MESSAGE' =
|
||||
'SET_EXPORT_STATUS_MESSAGE';
|
||||
export const UNSET_SHARE: 'UNSET_SHARE' = 'UNSET_SHARE';
|
||||
|
||||
export type ActiveSheet =
|
||||
| typeof ACTIVE_SHEET_PLUGIN_SHEET
|
||||
@@ -38,12 +42,12 @@ export type ServerPorts = {
|
||||
secure: number,
|
||||
};
|
||||
|
||||
export type ShareType =
|
||||
| {
|
||||
type: 'file',
|
||||
file: string,
|
||||
}
|
||||
| {type: 'link'};
|
||||
type SubShareType = {type: 'file', file: string} | {type: 'link'};
|
||||
|
||||
export type ShareType = {
|
||||
statusComponent?: ReactElement<typeof CancellableExportStatus>,
|
||||
...SubShareType,
|
||||
};
|
||||
|
||||
export type State = {
|
||||
leftSidebarVisible: boolean,
|
||||
@@ -102,6 +106,13 @@ export type Action =
|
||||
payload: {
|
||||
rating: number,
|
||||
},
|
||||
}
|
||||
| {
|
||||
type: typeof UNSET_SHARE,
|
||||
}
|
||||
| {
|
||||
type: typeof SET_EXPORT_STATUS_MESSAGE,
|
||||
payload: ReactElement<typeof CancellableExportStatus>,
|
||||
};
|
||||
|
||||
const initialState: () => State = () => ({
|
||||
@@ -179,6 +190,18 @@ export default function reducer(state: State, action: Action): State {
|
||||
...state,
|
||||
flipperRating: action.payload.rating,
|
||||
};
|
||||
} else if (action.type === 'SET_EXPORT_STATUS_MESSAGE') {
|
||||
if (state.share) {
|
||||
const {share} = state;
|
||||
return {
|
||||
...state,
|
||||
//$FlowFixMe: T48110490, its not able to understand for which case it needs to apply the changes
|
||||
share: {...share, statusComponent: action.payload},
|
||||
};
|
||||
}
|
||||
return state;
|
||||
} else if (action.type === 'UNSET_SHARE') {
|
||||
return {...state, share: null};
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
@@ -192,6 +215,17 @@ export const toggleAction = (
|
||||
payload,
|
||||
});
|
||||
|
||||
export const unsetShare = (): Action => ({
|
||||
type: UNSET_SHARE,
|
||||
});
|
||||
|
||||
export const setExportStatusComponent = (
|
||||
payload: ReactElement<typeof CancellableExportStatus>,
|
||||
): Action => ({
|
||||
type: SET_EXPORT_STATUS_MESSAGE,
|
||||
payload,
|
||||
});
|
||||
|
||||
export const setSelectPluginsToExportActiveSheet = (
|
||||
payload: ShareType,
|
||||
): Action => ({
|
||||
|
||||
Reference in New Issue
Block a user