Cleaning up sheet abstraction to use Ant/flipper-plugin dialogs instead
Summary: This diff cleans up order remaining dialogs, the ones involved in exporting to file or url. Includes some legacy component cleanup boyscouting, but not too much. This removes a lot of code where state of the wizard was stored globally, and makes it locally instead. Other code that was removed involves interaction with the old UI, which allowed import / export to be running in the background as well. (which is no longer needed since we optimised the process) Reviewed By: timur-valiev Differential Revision: D30192000 fbshipit-source-id: 13be883c5bf217a3d58b610b78516359e9bd0ebc
This commit is contained in:
committed by
Facebook GitHub Bot
parent
9e5575cf69
commit
d56375970d
@@ -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<Props> {
|
||||
render() {
|
||||
const {msg, onCancel} = this.props;
|
||||
return (
|
||||
<Wrapper>
|
||||
<LoadingIndicator size={16} />
|
||||
|
||||
<Text>{msg}</Text>
|
||||
|
||||
<Button onClick={onCancel}> Cancel </Button>
|
||||
</Wrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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<string>;
|
||||
setSelectedPlugins: (plugins: string[]) => void;
|
||||
};
|
||||
|
||||
type StateFromProps = {
|
||||
share: ShareType | null;
|
||||
selectedPlugins: Array<string>;
|
||||
availablePluginsToExport: Array<{id: string; label: string}>;
|
||||
};
|
||||
|
||||
type DispatchFromProps = {
|
||||
setSelectedPlugins: (payload: Array<string>) => 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<Props, {}> {
|
||||
render() {
|
||||
const {onHide} = this.props;
|
||||
const onHideWithUnsettingShare = () => {
|
||||
this.props.unsetShare();
|
||||
onHide();
|
||||
};
|
||||
return (
|
||||
<Container>
|
||||
<ListView
|
||||
type="multiple"
|
||||
title="Select the plugins for which you want to export the data"
|
||||
leftPadding={8}
|
||||
onSubmit={() => {
|
||||
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={() => {}}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
(state) => {
|
||||
const availablePluginsToExport = getExportablePlugins(state);
|
||||
return {
|
||||
share: state.application.share,
|
||||
selectedPlugins: state.plugins.selectedPlugins,
|
||||
availablePluginsToExport,
|
||||
};
|
||||
},
|
||||
(dispatch: Dispatch<Action<any>>) => ({
|
||||
setSelectedPlugins: (plugins: Array<string>) => {
|
||||
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<StateFromProps, {}, OwnProps, Store>((state) => {
|
||||
const availablePluginsToExport = getExportablePlugins(state);
|
||||
return {
|
||||
availablePluginsToExport,
|
||||
};
|
||||
})(ExportDataPluginSheet);
|
||||
|
||||
@@ -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<Props, State> {
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
<FlexColumn style={{paddingLeft: 15, paddingBottom: 10}}>
|
||||
<Layout.Container style={{paddingLeft: 15, paddingBottom: 10}}>
|
||||
Theme Selection
|
||||
<Radio.Group
|
||||
value={darkMode}
|
||||
@@ -262,7 +261,7 @@ class SettingsSheet extends Component<Props, State> {
|
||||
<Radio.Button value="light">Light</Radio.Button>
|
||||
<Radio.Button value="system">Use System Setting</Radio.Button>
|
||||
</Radio.Group>
|
||||
</FlexColumn>
|
||||
</Layout.Container>
|
||||
<ToggledSection
|
||||
label="React Native keyboard shortcuts"
|
||||
toggled={reactNative.shortcuts.enabled}
|
||||
@@ -330,21 +329,15 @@ class SettingsSheet extends Component<Props, State> {
|
||||
|
||||
const footer = (
|
||||
<>
|
||||
<Button compact padded onClick={this.props.onHide}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={this.props.onHide}>Cancel</Button>
|
||||
<Button
|
||||
disabled={settingsPristine || forcedRestart}
|
||||
compact
|
||||
padded
|
||||
onClick={this.applyChangesWithoutRestart}>
|
||||
Apply
|
||||
</Button>
|
||||
<Button
|
||||
disabled={settingsPristine}
|
||||
type="primary"
|
||||
compact
|
||||
padded
|
||||
onClick={this.applyChanges}>
|
||||
Apply and Restart
|
||||
</Button>
|
||||
@@ -388,7 +381,7 @@ function ResetTooltips() {
|
||||
function ResetLocalState() {
|
||||
return (
|
||||
<Button
|
||||
type="danger"
|
||||
danger
|
||||
onClick={() => {
|
||||
window.localStorage.clear();
|
||||
message.success('Local storage state cleared');
|
||||
|
||||
@@ -9,9 +9,7 @@
|
||||
|
||||
import {FlexColumn, Button, styled, Text, FlexRow, Spacer} from '../ui';
|
||||
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 {IdlerImpl} from '../utils/Idler';
|
||||
@@ -24,6 +22,7 @@ import ShareSheetErrorList from './ShareSheetErrorList';
|
||||
import ShareSheetPendingDialog from './ShareSheetPendingDialog';
|
||||
import {ReactReduxContext} from 'react-redux';
|
||||
import {MiddlewareAPI} from '../reducers/index';
|
||||
import {Modal} from 'antd';
|
||||
|
||||
const Container = styled(FlexColumn)({
|
||||
padding: 20,
|
||||
@@ -69,39 +68,23 @@ type State = {
|
||||
kind: 'pending';
|
||||
};
|
||||
statusUpdate: string | null;
|
||||
runInBackground: boolean;
|
||||
};
|
||||
|
||||
export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
static contextType = ReactReduxContext;
|
||||
|
||||
get store(): MiddlewareAPI {
|
||||
return this.context.store;
|
||||
}
|
||||
|
||||
state: State = {
|
||||
fetchMetaDataErrors: null,
|
||||
result: {kind: 'pending'},
|
||||
statusUpdate: null,
|
||||
runInBackground: false,
|
||||
};
|
||||
|
||||
idler = new IdlerImpl();
|
||||
|
||||
dispatchAndUpdateToolBarStatus(msg: string) {
|
||||
this.store.dispatch(
|
||||
setExportStatusComponent(
|
||||
<CancellableExportStatus
|
||||
msg={msg}
|
||||
onCancel={() => {
|
||||
this.idler.cancel();
|
||||
this.store.dispatch(unsetShare());
|
||||
}}
|
||||
/>,
|
||||
),
|
||||
);
|
||||
get store(): MiddlewareAPI {
|
||||
return this.context.store;
|
||||
}
|
||||
|
||||
idler = new IdlerImpl();
|
||||
|
||||
async componentDidMount() {
|
||||
const mark = 'shareSheetExportFile';
|
||||
performance.mark(mark);
|
||||
@@ -116,28 +99,17 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
false,
|
||||
this.idler,
|
||||
(msg: string) => {
|
||||
if (this.state.runInBackground) {
|
||||
this.dispatchAndUpdateToolBarStatus(msg);
|
||||
} else {
|
||||
this.setState({statusUpdate: msg});
|
||||
}
|
||||
this.setState({statusUpdate: msg});
|
||||
},
|
||||
),
|
||||
`${EXPORT_FLIPPER_TRACE_EVENT}:UI_FILE`,
|
||||
);
|
||||
if (this.state.runInBackground) {
|
||||
new Notification('Shareable Flipper Export created', {
|
||||
body: `Saved to ${this.props.file}`,
|
||||
requireInteraction: true,
|
||||
});
|
||||
}
|
||||
this.setState({
|
||||
fetchMetaDataErrors,
|
||||
result: fetchMetaDataErrors
|
||||
? {error: JSON.stringify(fetchMetaDataErrors) as any, kind: 'error'}
|
||||
: {kind: 'success'},
|
||||
});
|
||||
this.store.dispatch(unsetShare());
|
||||
this.props.logger.trackTimeSince(mark, 'export:file-success');
|
||||
} catch (err) {
|
||||
const result: {
|
||||
@@ -147,14 +119,10 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
kind: 'error',
|
||||
error: err,
|
||||
};
|
||||
if (!this.state.runInBackground) {
|
||||
// Show the error in UI.
|
||||
this.setState({result});
|
||||
} else {
|
||||
this.store.dispatch(unsetShare());
|
||||
}
|
||||
// Show the error in UI.
|
||||
this.setState({result});
|
||||
this.props.logger.trackTimeSince(mark, 'export:file-error', result);
|
||||
throw err;
|
||||
console.error('Failed to export to file: ', err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,84 +132,64 @@ export default class ShareSheetExportFile extends Component<Props, State> {
|
||||
);
|
||||
|
||||
return (
|
||||
<ReactReduxContext.Consumer>
|
||||
{({store}) => (
|
||||
<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>
|
||||
<ShareSheetErrorList
|
||||
errors={errorArray}
|
||||
title={title}
|
||||
type={'warning'}
|
||||
/>
|
||||
</FlexColumn>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button compact padded onClick={() => this.cancelAndHide(store)}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Container>
|
||||
)}
|
||||
</ReactReduxContext.Consumer>
|
||||
<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>
|
||||
<ShareSheetErrorList
|
||||
errors={errorArray}
|
||||
title={title}
|
||||
type={'warning'}
|
||||
/>
|
||||
</FlexColumn>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button compact padded onClick={() => this.cancelAndHide()}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
renderError(result: {kind: 'error'; error: Error}) {
|
||||
return (
|
||||
<ReactReduxContext.Consumer>
|
||||
{({store}) => (
|
||||
<Container>
|
||||
<Title bold>Error</Title>
|
||||
<ErrorMessage code>
|
||||
{result.error.message || 'File could not be saved.'}
|
||||
</ErrorMessage>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button compact padded onClick={() => this.cancelAndHide(store)}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Container>
|
||||
)}
|
||||
</ReactReduxContext.Consumer>
|
||||
<Container>
|
||||
<Title bold>Error</Title>
|
||||
<ErrorMessage code>
|
||||
{result.error.message || 'File could not be saved.'}
|
||||
</ErrorMessage>
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Button compact padded onClick={() => this.cancelAndHide()}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
renderPending(statusUpdate: string | null) {
|
||||
return (
|
||||
<ReactReduxContext.Consumer>
|
||||
{({store}) => (
|
||||
<ShareSheetPendingDialog
|
||||
width={500}
|
||||
statusUpdate={statusUpdate}
|
||||
statusMessage="Creating Flipper Export..."
|
||||
onCancel={() => this.cancelAndHide(store)}
|
||||
onRunInBackground={() => {
|
||||
this.setState({runInBackground: true});
|
||||
if (statusUpdate) {
|
||||
this.dispatchAndUpdateToolBarStatus(statusUpdate);
|
||||
}
|
||||
this.props.onHide();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ReactReduxContext.Consumer>
|
||||
<ShareSheetPendingDialog
|
||||
width={500}
|
||||
statusUpdate={statusUpdate}
|
||||
statusMessage="Creating Flipper Export..."
|
||||
onCancel={() => 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<Props, State> {
|
||||
return this.renderPending(statusUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Modal visible onCancel={this.cancelAndHide} footer={null}>
|
||||
{this.renderStatus()}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Props, State> {
|
||||
fetchMetaDataErrors: null,
|
||||
result: null,
|
||||
statusUpdate: null,
|
||||
runInBackground: false,
|
||||
};
|
||||
|
||||
get store(): MiddlewareAPI {
|
||||
@@ -97,30 +84,12 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
|
||||
|
||||
idler = new IdlerImpl();
|
||||
|
||||
dispatchAndUpdateToolBarStatus(msg: string) {
|
||||
this.store.dispatch(
|
||||
setExportStatusComponent(
|
||||
<CancellableExportStatus
|
||||
msg={msg}
|
||||
onCancel={() => {
|
||||
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<Props, State> {
|
||||
});
|
||||
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<Props, State> {
|
||||
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 (
|
||||
<ReactReduxContext.Consumer>
|
||||
{({store}) => (
|
||||
<ShareSheetPendingDialog
|
||||
width={500}
|
||||
statusUpdate={statusUpdate}
|
||||
statusMessage="Uploading Flipper Export..."
|
||||
onCancel={this.cancelAndHide(store)}
|
||||
onRunInBackground={() => {
|
||||
this.setState({runInBackground: true});
|
||||
if (statusUpdate) {
|
||||
this.dispatchAndUpdateToolBarStatus(statusUpdate);
|
||||
}
|
||||
this.props.onHide();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ReactReduxContext.Consumer>
|
||||
<Modal visible onCancel={this.cancelAndHide} footer={null}>
|
||||
<ShareSheetPendingDialog
|
||||
width={500}
|
||||
statusUpdate={statusUpdate}
|
||||
statusMessage="Uploading Flipper Export..."
|
||||
onCancel={this.cancelAndHide}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -232,56 +174,54 @@ export default class ShareSheetExportUrl extends Component<Props, State> {
|
||||
|
||||
const {title, errorArray} = displayFetchMetadataErrors(fetchMetaDataErrors);
|
||||
return (
|
||||
<ReactReduxContext.Consumer>
|
||||
{({store}) => (
|
||||
<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 compact padded onClick={this.cancelAndHide(store)}>
|
||||
Close
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</>
|
||||
</Container>
|
||||
)}
|
||||
</ReactReduxContext.Consumer>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<Container style={{width: props.width}}>
|
||||
<Center>
|
||||
<LoadingIndicator size={30} />
|
||||
{props.statusUpdate && props.statusUpdate.length > 0 ? (
|
||||
<Uploading bold color={colors.macOSTitleBarIcon}>
|
||||
{props.statusUpdate}
|
||||
</Uploading>
|
||||
) : (
|
||||
<Uploading bold color={colors.macOSTitleBarIcon}>
|
||||
{props.statusMessage}
|
||||
</Uploading>
|
||||
)}
|
||||
</Center>
|
||||
{!props.hideNavButtons && props.onCancel && props.onRunInBackground && (
|
||||
<FlexRow>
|
||||
<Spacer />
|
||||
<Layout.Container style={{width: props.width, textAlign: 'center'}}>
|
||||
<Spinner size={30} />
|
||||
{props.statusUpdate && props.statusUpdate.length > 0 ? (
|
||||
<Text strong>{props.statusUpdate}</Text>
|
||||
) : (
|
||||
<Text strong>{props.statusMessage}</Text>
|
||||
)}
|
||||
{!props.hideNavButtons && props.onCancel && (
|
||||
<Layout.Right>
|
||||
<div />
|
||||
<Button
|
||||
compact
|
||||
padded
|
||||
onClick={() => {
|
||||
props.onCancel && props.onCancel();
|
||||
}}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
compact
|
||||
padded
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
props.onRunInBackground && props.onRunInBackground();
|
||||
}}>
|
||||
Run In Background
|
||||
</Button>
|
||||
</FlexRow>
|
||||
</Layout.Right>
|
||||
)}
|
||||
</Container>
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<Props, {}> {
|
||||
render() {
|
||||
return (
|
||||
<Modal
|
||||
visible={!!this.props.activeSheet}
|
||||
footer={null}
|
||||
onCancel={this.props.onHideSheet}>
|
||||
{this.props.children(this.props.onHideSheet)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect<StateFromProps, DispatchFromProps, OwnProps, Store>(
|
||||
({application: {activeSheet}}) => ({
|
||||
activeSheet,
|
||||
}),
|
||||
{
|
||||
onHideSheet: () => setActiveSheet(null),
|
||||
},
|
||||
)(Sheet);
|
||||
@@ -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 <ExportDataPluginSheet onHide={onHide} />;
|
||||
case ACTIVE_SHEET_SHARE_DATA:
|
||||
return (
|
||||
<ShareSheetExportUrl
|
||||
onHide={onHide}
|
||||
logger={logger}
|
||||
closeOnFinish={share != null && share.closeOnFinish}
|
||||
/>
|
||||
);
|
||||
case ACTIVE_SHEET_SHARE_DATA_IN_FILE:
|
||||
return share && share.type === 'file' ? (
|
||||
<ShareSheetExportFile
|
||||
onHide={onHide}
|
||||
file={share.file}
|
||||
logger={logger}
|
||||
/>
|
||||
) : (
|
||||
(() => {
|
||||
console.error('No file provided when calling share sheet.');
|
||||
return null;
|
||||
})()
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
[activeSheet, logger, share],
|
||||
);
|
||||
|
||||
return <Sheet>{renderSheet}</Sheet>;
|
||||
}
|
||||
@@ -20,7 +20,6 @@ test('ShareSheetPendingDialog is rendered with status update', () => {
|
||||
<Provider store={mockStore}>
|
||||
<ShareSheetPendingDialog
|
||||
onCancel={() => {}}
|
||||
onRunInBackground={() => {}}
|
||||
statusMessage="wubba lubba dub dub"
|
||||
statusUpdate="Update"
|
||||
/>
|
||||
@@ -35,7 +34,6 @@ test('ShareSheetPendingDialog is rendered without status update', () => {
|
||||
<Provider store={mockStore}>
|
||||
<ShareSheetPendingDialog
|
||||
onCancel={() => {}}
|
||||
onRunInBackground={() => {}}
|
||||
statusMessage="wubba lubba dub dub"
|
||||
statusUpdate={null}
|
||||
/>
|
||||
|
||||
@@ -2,35 +2,60 @@
|
||||
|
||||
exports[`ShareSheetPendingDialog is rendered with status update 1`] = `
|
||||
<div
|
||||
className="css-1lvu114-View-FlexBox-FlexColumn"
|
||||
className="css-gzchr8-Container e1hsqii15"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
"width": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="css-1tg2qwm-View-FlexBox-FlexColumn"
|
||||
className="ant-spin ant-spin-spinning"
|
||||
>
|
||||
<div
|
||||
className="css-hs91vy-LoadingIndicator eq9prj20"
|
||||
size={30}
|
||||
/>
|
||||
<span
|
||||
className="css-137ad86-Text"
|
||||
color="#6f6f6f"
|
||||
aria-label="loading"
|
||||
className="anticon anticon-loading anticon-spin ant-spin-dot"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"fontSize": 30,
|
||||
}
|
||||
}
|
||||
>
|
||||
Update
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="css-wospjg-View-FlexBox-FlexRow epz0qe20"
|
||||
<span
|
||||
className="ant-typography"
|
||||
style={
|
||||
Object {
|
||||
"WebkitLineClamp": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="css-t4wmtk-View-FlexBox-Spacer e13mj6h80"
|
||||
/>
|
||||
<strong>
|
||||
Update
|
||||
</strong>
|
||||
</span>
|
||||
<div
|
||||
className="css-1knrt0j-SandySplitContainer e1hsqii10"
|
||||
>
|
||||
<div />
|
||||
<button
|
||||
className="ant-btn ant-btn-default"
|
||||
className="ant-btn"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
@@ -38,50 +63,66 @@ exports[`ShareSheetPendingDialog is rendered with status update 1`] = `
|
||||
Cancel
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="ant-btn ant-btn-primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Run In Background
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`ShareSheetPendingDialog is rendered without status update 1`] = `
|
||||
<div
|
||||
className="css-1lvu114-View-FlexBox-FlexColumn"
|
||||
className="css-gzchr8-Container e1hsqii15"
|
||||
style={
|
||||
Object {
|
||||
"textAlign": "center",
|
||||
"width": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="css-1tg2qwm-View-FlexBox-FlexColumn"
|
||||
className="ant-spin ant-spin-spinning"
|
||||
>
|
||||
<div
|
||||
className="css-hs91vy-LoadingIndicator eq9prj20"
|
||||
size={30}
|
||||
/>
|
||||
<span
|
||||
className="css-137ad86-Text"
|
||||
color="#6f6f6f"
|
||||
aria-label="loading"
|
||||
className="anticon anticon-loading anticon-spin ant-spin-dot"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"fontSize": 30,
|
||||
}
|
||||
}
|
||||
>
|
||||
wubba lubba dub dub
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="css-wospjg-View-FlexBox-FlexRow epz0qe20"
|
||||
<span
|
||||
className="ant-typography"
|
||||
style={
|
||||
Object {
|
||||
"WebkitLineClamp": undefined,
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="css-t4wmtk-View-FlexBox-Spacer e13mj6h80"
|
||||
/>
|
||||
<strong>
|
||||
wubba lubba dub dub
|
||||
</strong>
|
||||
</span>
|
||||
<div
|
||||
className="css-1knrt0j-SandySplitContainer e1hsqii10"
|
||||
>
|
||||
<div />
|
||||
<button
|
||||
className="ant-btn ant-btn-default"
|
||||
className="ant-btn"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
@@ -89,15 +130,6 @@ exports[`ShareSheetPendingDialog is rendered without status update 1`] = `
|
||||
Cancel
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
className="ant-btn ant-btn-primary"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
Run In Background
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -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<Props> {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Fragment>
|
||||
<Layout.Container pad>
|
||||
<InfoText>The table lists all plugins known to Flipper.</InfoText>
|
||||
<TableContainer>
|
||||
<ManagedTable
|
||||
@@ -221,7 +222,7 @@ class PluginDebugger extends Component<Props> {
|
||||
columnSizes={COLUMNS_SIZES}
|
||||
/>
|
||||
</TableContainer>
|
||||
</Fragment>
|
||||
</Layout.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<typeof CancellableExportStatus>,
|
||||
): 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,
|
||||
|
||||
@@ -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}
|
||||
</MainContainer>
|
||||
</Layout.Left>
|
||||
<SheetRenderer logger={logger} />
|
||||
<_PortalsManager />
|
||||
</Layout.Container>
|
||||
);
|
||||
|
||||
@@ -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) => (
|
||||
<ShareSheetExportFile onHide={onHide} file={file} logger={getInstance()} />
|
||||
));
|
||||
}
|
||||
|
||||
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) => (
|
||||
<ShareSheetExportUrl onHide={onHide} logger={getInstance()} />
|
||||
));
|
||||
}
|
||||
|
||||
async function selectPlugins() {
|
||||
return await Dialog.select<string[]>({
|
||||
title: 'Select plugins to export',
|
||||
defaultValue: [],
|
||||
renderer: (value, onChange, onCancel) => (
|
||||
<ExportDataPluginSheet
|
||||
onHide={onCancel}
|
||||
selectedPlugins={value}
|
||||
setSelectedPlugins={onChange}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -237,6 +237,27 @@ export const Dialog = {
|
||||
});
|
||||
},
|
||||
|
||||
select<T>({
|
||||
defaultValue,
|
||||
renderer,
|
||||
...rest
|
||||
}: {
|
||||
defaultValue: T;
|
||||
renderer: (
|
||||
value: T,
|
||||
onChange: (newValue: T) => void,
|
||||
onCancel: () => void,
|
||||
) => React.ReactElement;
|
||||
} & BaseDialogOptions): DialogResult<false | T> {
|
||||
const handle = Dialog.show<T>({
|
||||
...rest,
|
||||
defaultValue,
|
||||
children: (currentValue, setValue): React.ReactElement =>
|
||||
renderer(currentValue, setValue, () => handle.close()),
|
||||
});
|
||||
return handle;
|
||||
},
|
||||
|
||||
loading({
|
||||
title,
|
||||
message,
|
||||
|
||||
Reference in New Issue
Block a user