Move app/src (mostly) to flipper-ui-core/src
Summary: This diff moves all UI code from app/src to app/flipper-ui-core. That is now slightly too much (e.g. node deps are not removed yet), but from here it should be easier to move things out again, as I don't want this diff to be open for too long to avoid too much merge conflicts. * But at least flipper-ui-core is Electron free :) * Killed all cross module imports as well, as they where now even more in the way * Some unit test needed some changes, most not too big (but emotion hashes got renumbered in the snapshots, feel free to ignore that) * Found some files that were actually meaningless (tsconfig in plugins, WatchTools files, that start generating compile errors, removed those Follow up work: * make flipper-ui-core configurable, and wire up flipper-server-core in Electron instead of here * remove node deps (aigoncharov) * figure out correct place to load GKs, plugins, make intern requests etc., and move to the correct module * clean up deps Reviewed By: aigoncharov Differential Revision: D32427722 fbshipit-source-id: 14fe92e1ceb15b9dcf7bece367c8ab92df927a70
This commit is contained in:
committed by
Facebook GitHub Bot
parent
54b7ce9308
commit
7e50c0466a
227
desktop/flipper-ui-core/src/chrome/ShareSheetExportUrl.tsx
Normal file
227
desktop/flipper-ui-core/src/chrome/ShareSheetExportUrl.tsx
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* 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 {FlexColumn, styled, Text, FlexRow, Spacer, Input} from '../ui';
|
||||
import React, {Component} from 'react';
|
||||
import {ReactReduxContext, ReactReduxContextValue} from 'react-redux';
|
||||
import {Logger} from 'flipper-common';
|
||||
import {IdlerImpl} from '../utils/Idler';
|
||||
import {
|
||||
shareFlipperData,
|
||||
DataExportResult,
|
||||
DataExportError,
|
||||
} from '../fb-stubs/user';
|
||||
import {
|
||||
exportStore,
|
||||
EXPORT_FLIPPER_TRACE_EVENT,
|
||||
displayFetchMetadataErrors,
|
||||
} from '../utils/exportData';
|
||||
import ShareSheetErrorList from './ShareSheetErrorList';
|
||||
import {reportPlatformFailures} from 'flipper-common';
|
||||
import {performance} from 'perf_hooks';
|
||||
import ShareSheetPendingDialog from './ShareSheetPendingDialog';
|
||||
import {getLogger} from 'flipper-common';
|
||||
import {resetSupportFormV2State} from '../reducers/supportForm';
|
||||
import {MiddlewareAPI} from '../reducers/index';
|
||||
import {getFlipperLib, Layout} from 'flipper-plugin';
|
||||
import {Button, Modal} from 'antd';
|
||||
|
||||
export const SHARE_FLIPPER_TRACE_EVENT = 'share-flipper-link';
|
||||
|
||||
const Copy = styled(Input)({
|
||||
marginRight: 0,
|
||||
marginBottom: 15,
|
||||
});
|
||||
|
||||
const InfoText = styled(Text)({
|
||||
lineHeight: 1.35,
|
||||
marginBottom: 15,
|
||||
});
|
||||
|
||||
const Title = styled(Text)({
|
||||
marginBottom: 6,
|
||||
});
|
||||
|
||||
const ErrorMessage = styled(Text)({
|
||||
display: 'block',
|
||||
marginTop: 6,
|
||||
wordBreak: 'break-all',
|
||||
whiteSpace: 'pre-line',
|
||||
lineHeight: 1.35,
|
||||
});
|
||||
|
||||
type Props = {
|
||||
onHide: () => any;
|
||||
logger: Logger;
|
||||
};
|
||||
|
||||
type State = {
|
||||
fetchMetaDataErrors: {
|
||||
[plugin: string]: Error;
|
||||
} | null;
|
||||
result: DataExportError | DataExportResult | null;
|
||||
statusUpdate: string | null;
|
||||
};
|
||||
|
||||
export default class ShareSheetExportUrl extends Component<Props, State> {
|
||||
static contextType: React.Context<ReactReduxContextValue> = ReactReduxContext;
|
||||
|
||||
state: State = {
|
||||
fetchMetaDataErrors: null,
|
||||
result: null,
|
||||
statusUpdate: null,
|
||||
};
|
||||
|
||||
get store(): MiddlewareAPI {
|
||||
return this.context.store;
|
||||
}
|
||||
|
||||
idler = new IdlerImpl();
|
||||
|
||||
async componentDidMount() {
|
||||
const mark = 'shareSheetExportUrl';
|
||||
performance.mark(mark);
|
||||
try {
|
||||
const statusUpdate = (msg: string) => {
|
||||
this.setState({statusUpdate: msg});
|
||||
};
|
||||
const {serializedString, fetchMetaDataErrors} =
|
||||
await reportPlatformFailures(
|
||||
exportStore(this.store, false, this.idler, statusUpdate),
|
||||
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_LINK`,
|
||||
);
|
||||
const uploadMarker = `${EXPORT_FLIPPER_TRACE_EVENT}:upload`;
|
||||
performance.mark(uploadMarker);
|
||||
statusUpdate('Uploading Flipper Export...');
|
||||
const result = await reportPlatformFailures(
|
||||
shareFlipperData(serializedString),
|
||||
`${SHARE_FLIPPER_TRACE_EVENT}`,
|
||||
);
|
||||
|
||||
if ((result as DataExportError).error != undefined) {
|
||||
const res = result as DataExportError;
|
||||
const err = new Error(res.error);
|
||||
err.stack = res.stacktrace;
|
||||
throw err;
|
||||
}
|
||||
getLogger().trackTimeSince(uploadMarker, uploadMarker, {
|
||||
plugins: this.store.getState().plugins.selectedPlugins,
|
||||
});
|
||||
const flipperUrl = (result as DataExportResult).flipperUrl;
|
||||
if (flipperUrl) {
|
||||
getFlipperLib().writeTextToClipboard(String(flipperUrl));
|
||||
new Notification('Shareable Flipper Export created', {
|
||||
body: 'URL copied to clipboard',
|
||||
requireInteraction: true,
|
||||
});
|
||||
}
|
||||
this.setState({fetchMetaDataErrors, result});
|
||||
this.store.dispatch(resetSupportFormV2State());
|
||||
this.props.logger.trackTimeSince(mark, 'export:url-success');
|
||||
} catch (e) {
|
||||
const result: DataExportError = {
|
||||
error_class: 'EXPORT_ERROR',
|
||||
error: e,
|
||||
stacktrace: '',
|
||||
};
|
||||
if (e instanceof Error) {
|
||||
result.error = e.message;
|
||||
result.stacktrace = e.stack || '';
|
||||
}
|
||||
// Show the error in UI.
|
||||
this.setState({result});
|
||||
this.props.logger.trackTimeSince(mark, 'export:url-error', result);
|
||||
console.error('Failed to export to flipper trace', e);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
const {result} = this.state;
|
||||
if (!result || !(result as DataExportResult).flipperUrl) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cancelAndHide = () => {
|
||||
this.props.onHide();
|
||||
this.idler.cancel();
|
||||
};
|
||||
|
||||
renderPending(statusUpdate: string | null) {
|
||||
return (
|
||||
<Modal visible onCancel={this.cancelAndHide} footer={null}>
|
||||
<ShareSheetPendingDialog
|
||||
width={500}
|
||||
statusUpdate={statusUpdate}
|
||||
statusMessage="Uploading Flipper Export..."
|
||||
onCancel={this.cancelAndHide}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {result, statusUpdate, fetchMetaDataErrors} = this.state;
|
||||
if (!result) {
|
||||
return this.renderPending(statusUpdate);
|
||||
}
|
||||
|
||||
const {title, errorArray} = displayFetchMetadataErrors(fetchMetaDataErrors);
|
||||
return (
|
||||
<Modal visible onCancel={this.cancelAndHide} footer={null}>
|
||||
<Layout.Container>
|
||||
<>
|
||||
<FlexColumn>
|
||||
{(result as DataExportResult).flipperUrl ? (
|
||||
<>
|
||||
<Title bold>Data Upload Successful</Title>
|
||||
<InfoText>
|
||||
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.
|
||||
</InfoText>
|
||||
<Copy
|
||||
value={(result as DataExportResult).flipperUrl}
|
||||
readOnly
|
||||
/>
|
||||
<InfoText>
|
||||
When sharing your Flipper link, consider that the captured
|
||||
data might contain sensitve information like access tokens
|
||||
used in network requests.
|
||||
</InfoText>
|
||||
<ShareSheetErrorList
|
||||
errors={errorArray}
|
||||
title={title}
|
||||
type={'warning'}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Title bold>
|
||||
{(result as DataExportError).error_class || 'Error'}
|
||||
</Title>
|
||||
<ErrorMessage code>
|
||||
{(result as DataExportError).error ||
|
||||
'The data could not be uploaded'}
|
||||
</ErrorMessage>
|
||||
</>
|
||||
)}
|
||||
</FlexColumn>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button type="primary" onClick={this.cancelAndHide}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</>
|
||||
</Layout.Container>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user