diff --git a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js index 0ad5aedd86cb8..c26f2c2faec7a 100644 --- a/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js +++ b/packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js @@ -7,80 +7,73 @@ * @flow */ +import type {SchedulingEvent} from 'react-devtools-timeline/src/types'; + import * as React from 'react'; -import {isStateUpdateEvent} from 'react-devtools-timeline/src/utils/flow'; import Button from '../Button'; import ButtonIcon from '../ButtonIcon'; import ViewSourceContext from '../Components/ViewSourceContext'; -import {useContext, useMemo} from 'react'; -import {ProfilerContext} from './ProfilerContext'; +import {useContext} from 'react'; +import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext'; import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils'; import styles from './SidebarEventInfo.css'; export type Props = {||}; -export default function SidebarEventInfo(_: Props) { - const {profilingData, selectedCommitIndex} = useContext(ProfilerContext); +function SchedulingEventInfo({eventInfo}: {eventInfo: SchedulingEvent}) { const {viewUrlSourceFunction} = useContext(ViewSourceContext); - const {stack} = useMemo(() => { - if ( - selectedCommitIndex == null || - profilingData == null || - profilingData.timelineData.length === 0 - ) { - return {}; - } - const {schedulingEvents} = profilingData.timelineData[0]; + const componentStack = eventInfo.componentStack + ? stackToComponentSources(eventInfo.componentStack) + : null; - const event = schedulingEvents[selectedCommitIndex]; - if (!isStateUpdateEvent(event)) { - return {}; + const viewSource = source => { + if (viewUrlSourceFunction != null && source != null) { + viewUrlSourceFunction(...source); } + }; - let componentStack = null; - if (event.componentStack) { - componentStack = stackToComponentSources(event.componentStack); - } - - return { - stack: componentStack, - }; - }, [profilingData, selectedCommitIndex]); - - let components; - if (stack) { - components = stack.map(([displayName, source], index) => { - const hasSource = source != null; - - const onClick = () => { - if (viewUrlSourceFunction != null && source != null) { - viewUrlSourceFunction(...source); - } - }; + return ( +
+ {componentStack ? ( +
    + {componentStack.map(([displayName, source], index) => { + const hasSource = source != null; - return ( -
  1. - -
  2. - ); - }); - } + return ( +
  3. + +
  4. + ); + })} +
+ ) : null} +
+ ); +} - return ( +export default function SidebarEventInfo(_: Props) { + const {selectedEvent} = useContext(TimelineContext); + // (TODO) Refactor in next PR so this supports multiple types of events + return selectedEvent ? ( <>
Event Component Tree
-
-
    {components}
-
+ {selectedEvent.schedulingEvent ? ( + + ) : null} - ); + ) : null; } diff --git a/packages/react-devtools-timeline/src/CanvasPage.js b/packages/react-devtools-timeline/src/CanvasPage.js index 116d7b28567df..3abc8ea7a3999 100644 --- a/packages/react-devtools-timeline/src/CanvasPage.js +++ b/packages/react-devtools-timeline/src/CanvasPage.js @@ -9,7 +9,7 @@ import type {Point} from './view-base'; import type { - ReactHoverContextInfo, + ReactEventInfo, TimelineData, ReactMeasure, ViewState, @@ -63,7 +63,7 @@ import useContextMenu from 'react-devtools-shared/src/devtools/ContextMenu/useCo import {getBatchRange} from './utils/getBatchRange'; import {MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL} from './view-base/constants'; import {TimelineSearchContext} from './TimelineSearchContext'; -import {ProfilerContext} from 'react-devtools-shared/src/devtools/views/Profiler/ProfilerContext'; +import {TimelineContext} from './TimelineContext'; import styles from './CanvasPage.css'; @@ -132,7 +132,7 @@ const zoomToBatch = ( viewState.updateHorizontalScrollState(scrollState); }; -const EMPTY_CONTEXT_INFO: ReactHoverContextInfo = { +const EMPTY_CONTEXT_INFO: ReactEventInfo = { componentMeasure: null, flamechartStackFrame: null, measure: null, @@ -162,10 +162,7 @@ function AutoSizedCanvas({ const [isContextMenuShown, setIsContextMenuShown] = useState(false); const [mouseLocation, setMouseLocation] = useState(zeroPoint); // DOM coordinates - const [ - hoveredEvent, - setHoveredEvent, - ] = useState(null); + const [hoveredEvent, setHoveredEvent] = useState(null); const resetHoveredEvent = useCallback( () => setHoveredEvent(EMPTY_CONTEXT_INFO), @@ -529,7 +526,7 @@ function AutoSizedCanvas({ ref: canvasRef, }); - const {selectCommitIndex} = useContext(ProfilerContext); + const {selectEvent} = useContext(TimelineContext); useEffect(() => { const {current: userTimingMarksView} = userTimingMarksViewRef; @@ -566,8 +563,11 @@ function AutoSizedCanvas({ }); } }; - schedulingEventsView.onClick = (schedulingEvent, eventIndex) => { - selectCommitIndex(eventIndex); + schedulingEventsView.onClick = schedulingEvent => { + selectEvent({ + ...EMPTY_CONTEXT_INFO, + schedulingEvent, + }); }; } diff --git a/packages/react-devtools-timeline/src/EventTooltip.js b/packages/react-devtools-timeline/src/EventTooltip.js index b084e8821b82c..13c25444213f9 100644 --- a/packages/react-devtools-timeline/src/EventTooltip.js +++ b/packages/react-devtools-timeline/src/EventTooltip.js @@ -13,7 +13,7 @@ import type { NativeEvent, NetworkMeasure, ReactComponentMeasure, - ReactHoverContextInfo, + ReactEventInfo, ReactMeasure, TimelineData, SchedulingEvent, @@ -35,7 +35,7 @@ type Props = {| canvasRef: {|current: HTMLCanvasElement | null|}, data: TimelineData, height: number, - hoveredEvent: ReactHoverContextInfo | null, + hoveredEvent: ReactEventInfo | null, origin: Point, width: number, |}; diff --git a/packages/react-devtools-timeline/src/TimelineContext.js b/packages/react-devtools-timeline/src/TimelineContext.js index f024ec68dccf6..c753fe1c28d6b 100644 --- a/packages/react-devtools-timeline/src/TimelineContext.js +++ b/packages/react-devtools-timeline/src/TimelineContext.js @@ -23,6 +23,7 @@ import type { TimelineData, SearchRegExpStateChangeCallback, ViewState, + ReactEventInfo, } from './types'; import type {RefObject} from 'shared/ReactTypes'; @@ -33,6 +34,8 @@ export type Context = {| searchInputContainerRef: RefObject, setFile: (file: File | null) => void, viewState: ViewState, + selectEvent: ReactEventInfo => void, + selectedEvent: ReactEventInfo, |}; const TimelineContext = createContext(((null: any): Context)); @@ -121,6 +124,8 @@ function TimelineContextController({children}: Props) { return state; }, [file]); + const [selectedEvent, selectEvent] = useState(null); + const value = useMemo( () => ({ file, @@ -129,8 +134,18 @@ function TimelineContextController({children}: Props) { searchInputContainerRef, setFile, viewState, + selectEvent, + selectedEvent, }), - [file, inMemoryTimelineData, isTimelineSupported, setFile, viewState], + [ + file, + inMemoryTimelineData, + isTimelineSupported, + setFile, + viewState, + selectEvent, + selectedEvent, + ], ); return ( diff --git a/packages/react-devtools-timeline/src/types.js b/packages/react-devtools-timeline/src/types.js index b62405b28a16b..0d8766726ff54 100644 --- a/packages/react-devtools-timeline/src/types.js +++ b/packages/react-devtools-timeline/src/types.js @@ -240,7 +240,7 @@ export type TimelineDataExport = {| thrownErrors: ThrownError[], |}; -export type ReactHoverContextInfo = {| +export type ReactEventInfo = {| componentMeasure: ReactComponentMeasure | null, flamechartStackFrame: FlamechartStackFrame | null, measure: ReactMeasure | null,