/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import type {ViewState} from './types'; import * as React from 'react'; import { Suspense, useContext, useDeferredValue, useLayoutEffect, useRef, useState, } from 'react'; import {SettingsContext} from 'react-devtools-shared/src/devtools/views/Settings/SettingsContext'; import {ProfilerContext} from 'react-devtools-shared/src/devtools/views/Profiler/ProfilerContext'; import NoProfilingData from 'react-devtools-shared/src/devtools/views/Profiler/NoProfilingData'; import RecordingInProgress from 'react-devtools-shared/src/devtools/views/Profiler/RecordingInProgress'; import {updateColorsToMatchTheme} from './content-views/constants'; import {TimelineContext} from './TimelineContext'; import CanvasPage from './CanvasPage'; import {importFile} from './timelineCache'; import TimelineSearchInput from './TimelineSearchInput'; import TimelineNotSupported from './TimelineNotSupported'; import {TimelineSearchContextController} from './TimelineSearchContext'; import styles from './Timeline.css'; export function Timeline(_: {}): React.Node { const {file, inMemoryTimelineData, isTimelineSupported, setFile, viewState} = useContext(TimelineContext); const {didRecordCommits, isProfiling} = useContext(ProfilerContext); const ref = useRef(null); // HACK: Canvas rendering uses an imperative API, // but DevTools colors are stored in CSS variables (see root.css and SettingsContext). // When the theme changes, we need to trigger update the imperative colors and re-draw the Canvas. const {theme} = useContext(SettingsContext); // HACK: SettingsContext also uses a useLayoutEffect to update styles; // make sure the theme context in SettingsContext updates before this code. const deferredTheme = useDeferredValue(theme); // HACK: Schedule a re-render of the Canvas once colors have been updated. // The easiest way to guarangee this happens is to recreate the inner Canvas component. const [key, setKey] = useState(theme); useLayoutEffect(() => { const pollForTheme = () => { if (updateColorsToMatchTheme(((ref.current: any): HTMLDivElement))) { clearInterval(intervalID); setKey(deferredTheme); } }; const intervalID = setInterval(pollForTheme, 50); return () => { clearInterval(intervalID); }; }, [deferredTheme]); let content = null; if (isProfiling) { content = ; } else if (inMemoryTimelineData && inMemoryTimelineData.length > 0) { // TODO (timeline) Support multiple renderers. const timelineData = inMemoryTimelineData[0]; content = ( ); } else if (file) { content = ( }> ); } else if (didRecordCommits) { content = ; } else if (isTimelineSupported) { content = ; } else { content = ; } return (
{content}
); } const ProcessingData = () => (
Processing data...
This should only take a minute.
); // $FlowFixMe[missing-local-annot] const CouldNotLoadProfile = ({error, onFileSelect}) => (
Could not load profile
{error.message && (
{error.message}
)}
Try importing another Chrome performance profile.
); const NoTimelineData = () => (
This current profile does not contain timeline data.
); const FileLoader = ({ file, onFileSelect, viewState, }: { file: File | null, onFileSelect: (file: File) => void, viewState: ViewState, }) => { if (file === null) { return null; } const dataOrError = importFile(file); if (dataOrError instanceof Error) { return ( ); } return ( ); };