react/packages/react-devtools-shared/src/devtools/views/Profiler/ProfilingImportExportButton...

129 lines
3.8 KiB
JavaScript
Raw Normal View History

2019-08-28 01:54:01 +08:00
/**
* 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.
*
* @flow
*/
2019-04-01 08:02:30 +08:00
2019-08-14 08:58:03 +08:00
import React, {Fragment, useContext, useCallback, useRef} from 'react';
import {ProfilerContext} from './ProfilerContext';
import {ModalDialogContext} from '../ModalDialog';
2019-04-01 08:02:30 +08:00
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
2019-08-14 08:58:03 +08:00
import {StoreContext} from '../context';
import {
prepareProfilingDataExport,
prepareProfilingDataFrontendFromExport,
} from './utils';
2019-08-14 08:58:03 +08:00
import {downloadFile} from '../utils';
2019-04-01 08:02:30 +08:00
import styles from './ProfilingImportExportButtons.css';
2019-08-14 08:58:03 +08:00
import type {ProfilingDataExport} from './types';
2019-04-01 08:02:30 +08:00
export default function ProfilingImportExportButtons() {
2019-08-14 08:58:03 +08:00
const {isProfiling, profilingData, rootID} = useContext(ProfilerContext);
2019-04-01 08:02:30 +08:00
const store = useContext(StoreContext);
2019-08-14 08:58:03 +08:00
const {profilerStore} = store;
2019-04-01 08:02:30 +08:00
const inputRef = useRef<HTMLInputElement | null>(null);
const downloadRef = useRef<HTMLAnchorElement | null>(null);
2019-04-01 08:02:30 +08:00
2019-08-14 08:58:03 +08:00
const {dispatch: modalDialogDispatch} = useContext(ModalDialogContext);
const downloadData = useCallback(() => {
if (rootID === null) {
return;
}
2019-04-01 08:02:30 +08:00
if (profilingData !== null && downloadRef.current !== null) {
const profilingDataExport = prepareProfilingDataExport(profilingData);
const date = new Date();
const dateString = date
.toLocaleDateString(undefined, {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})
.replace(/\//g, '-');
const timeString = date
.toLocaleTimeString(undefined, {
hour12: false,
})
.replace(/:/g, '-');
downloadFile(
downloadRef.current,
`profiling-data.${dateString}.${timeString}.json`,
JSON.stringify(profilingDataExport, null, 2),
);
}
}, [rootID, profilingData]);
2019-04-01 08:02:30 +08:00
const uploadData = useCallback(() => {
if (inputRef.current !== null) {
inputRef.current.click();
}
}, []);
const handleFiles = useCallback(() => {
const input = inputRef.current;
if (input !== null && input.files.length > 0) {
const fileReader = new FileReader();
fileReader.addEventListener('load', () => {
try {
const raw = ((fileReader.result: any): string);
const profilingDataExport = ((JSON.parse(
raw,
): any): ProfilingDataExport);
profilerStore.profilingData = prepareProfilingDataFrontendFromExport(
profilingDataExport,
);
} catch (error) {
modalDialogDispatch({
type: 'SHOW',
title: 'Import failed',
content: (
<Fragment>
<div>The profiling data you selected cannot be imported.</div>
{error !== null && (
<div className={styles.ErrorMessage}>{error.message}</div>
)}
</Fragment>
),
});
}
});
// TODO (profiling) Handle fileReader errors.
fileReader.readAsText(input.files[0]);
}
}, [modalDialogDispatch, profilerStore]);
2019-04-01 08:02:30 +08:00
return (
<Fragment>
<div className={styles.VRule} />
<input
ref={inputRef}
className={styles.Input}
type="file"
onChange={handleFiles}
tabIndex={-1}
2019-04-01 08:02:30 +08:00
/>
<a ref={downloadRef} className={styles.Input} />
2019-04-01 08:02:30 +08:00
<Button
disabled={isProfiling}
onClick={uploadData}
2019-08-14 08:58:03 +08:00
title="Load profile...">
2019-04-01 08:02:30 +08:00
<ButtonIcon type="import" />
</Button>
<Button
2019-05-23 23:36:34 +08:00
disabled={isProfiling || !profilerStore.didRecordCommits}
onClick={downloadData}
2019-08-14 08:58:03 +08:00
title="Save profile...">
<ButtonIcon type="export" />
</Button>
2019-04-01 08:02:30 +08:00
</Fragment>
);
}