/** * 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, FlexRow, Spacer, } from 'flipper'; import React, {Component} from 'react'; import {setExportStatusComponent, unsetShare} from '../reducers/application'; import {reportPlatformFailures} from '../utils/metrics'; import CancellableExportStatus from './CancellableExportStatus'; import {performance} from 'perf_hooks'; import {Logger} from '../fb-interfaces/Logger'; import {Idler} from '../utils/Idler'; import { exportStoreToFile, EXPORT_FLIPPER_TRACE_EVENT, } from '../utils/exportData'; import PropTypes from 'prop-types'; import ShareSheetErrorList from './ShareSheetErrorList'; 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: () => any; file: string | null | undefined; logger: Logger; }; type State = { errorArray: Array; result: | { success: boolean; error: Error | null | undefined; } | null | undefined; statusUpdate: string | null | undefined; runInBackground: boolean; }; export default class ShareSheetExportFile extends Component { static contextTypes = { store: PropTypes.object.isRequired, }; state: State = { errorArray: [], result: null, statusUpdate: null, runInBackground: false, }; idler = new Idler(); dispatchAndUpdateToolBarStatus(msg: string) { this.context.store.dispatch( setExportStatusComponent( { this.idler.cancel(); this.context.store.dispatch(unsetShare()); }} />, ), ); } async componentDidMount() { const mark = 'shareSheetExportFile'; performance.mark(mark); try { if (!this.props.file) { return; } const {errorArray} = await reportPlatformFailures( exportStoreToFile( this.props.file, this.context.store, this.idler, (msg: string) => { 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 Notification('Sharable Flipper trace created', { 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) { if (!this.state.runInBackground) { this.setState({errorArray: [], result: {success: false, error: err}}); } this.props.logger.trackTimeSince(mark, 'export:file-error'); } } render() { const onHide = () => { this.context.store.dispatch(unsetShare()); this.props.onHide(); this.idler.cancel(); }; if (!this.props.file) { return this.renderNoFileError(onHide); } const {result, statusUpdate} = this.state; if (result) { const {success, error} = result; if (success) { 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. ); } if (error) { return ( Error {(error && error.message) || 'File could not be saved.'} ); } return null; } else { return (
{statusUpdate && statusUpdate.length > 0 ? ( {statusUpdate} ) : ( Exporting Flipper trace... )}
); } } renderNoFileError(onHide: () => void) { return (
No file selected
); } }