Skip to content

Commit

Permalink
[DevTools] Resign Timeline Profiler Sidebar (#24816)
Browse files Browse the repository at this point in the history
This PR:
* Redesigned the sidebar to resemble the flamegraph profiler sidebar and added title and timestamp to the sidebar
* Added ability to copy the component stack (for places where you're unable to link to source)

https://user-images.githubusercontent.com/2735514/176564897-5301d6d4-429a-4ea3-86cd-74427cff4ce6.mov
  • Loading branch information
lunaruan authored Jun 30, 2022
1 parent 1974d08 commit 4e1fcfa
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 80 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
padding: 0;
border-radius: 0.25rem;
flex: 0 0 auto;
cursor: pointer;
}
.ButtonContent {
display: inline-flex;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,51 +20,47 @@
}

.ListItem {
margin: 0;
flex: 1 1;
margin: 0 0 0.5rem;
}

.Label {
display: flex;
justify-content: space-between;

overflow: hidden;
text-overflow: ellipsis;
font-weight: bold;
}

[data-source="true"]:hover .Label > .Button {
background-color: var(--color-background-hover);
flex: 1 1;
}

.Value {
font-family: var(--font-family-monospace);
font-size: var(--font-size-monospace-normal);
}

.NothingSelected {
display: flex;
.Row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
height: 100%;
color: var(--color-dim);
}

.Button {
display: flex;
flex: 1;
border-top: 1px solid var(--color-border);
}

max-width: 95%;
.UnclickableSource,
.ClickableSource {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
font-family: var(--font-family-sans);
font-size: var(--font-size-sans-normal);
}

[data-source="true"] .Button {
cursor: pointer;
.UnclickableSource {
color: var(--color-dim);
}


.Button > span {
display: block;
text-align: left;
.ClickableSource {
color: var(--color-text);
}

.Source {
.ClickableSource:focus,
.ClickableSource:hover {
background-color: var(--color-background-hover);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,25 @@ import ButtonIcon from '../ButtonIcon';
import ViewSourceContext from '../Components/ViewSourceContext';
import {useContext} from 'react';
import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext';
import {
formatTimestamp,
getSchedulingEventLabel,
} from 'react-devtools-timeline/src/utils/formatting';
import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils';
import {copy} from 'clipboard-js';

import styles from './SidebarEventInfo.css';

export type Props = {||};

function SchedulingEventInfo({eventInfo}: {eventInfo: SchedulingEvent}) {
const {viewUrlSourceFunction} = useContext(ViewSourceContext);
type SchedulingEventProps = {|
eventInfo: SchedulingEvent,
|};

const componentStack = eventInfo.componentStack
? stackToComponentSources(eventInfo.componentStack)
: null;
function SchedulingEventInfo({eventInfo}: SchedulingEventProps) {
const {viewUrlSourceFunction} = useContext(ViewSourceContext);
const {componentName, timestamp} = eventInfo;
const componentStack = eventInfo.componentStack || null;

const viewSource = source => {
if (viewUrlSourceFunction != null && source != null) {
Expand All @@ -35,45 +42,60 @@ function SchedulingEventInfo({eventInfo}: {eventInfo: SchedulingEvent}) {
};

return (
<div className={styles.Content} tabIndex={0}>
{componentStack ? (
<ol className={styles.List}>
{componentStack.map(([displayName, source], index) => {
const hasSource = source != null;

return (
<li
key={index}
className={styles.ListItem}
data-source={hasSource}>
<label className={styles.Label}>
<Button
className={styles.Button}
onClick={() => viewSource(source)}>
{displayName}
</Button>
{hasSource && (
<ButtonIcon className={styles.Source} type="view-source" />
)}
</label>
</li>
);
})}
</ol>
) : null}
</div>
<>
<div className={styles.Toolbar}>
{componentName} {getSchedulingEventLabel(eventInfo)}
</div>
<div className={styles.Content} tabIndex={0}>
<ul className={styles.List}>
<li className={styles.ListItem}>
<label className={styles.Label}>Timestamp</label>:{' '}
<span className={styles.Value}>{formatTimestamp(timestamp)}</span>
</li>
{componentStack && (
<li className={styles.ListItem}>
<div className={styles.Row}>
<label className={styles.Label}>Rendered by</label>
<Button
onClick={() => copy(componentStack)}
title="Copy component stack to clipboard">
<ButtonIcon type="copy" />
</Button>
</div>
<ul className={styles.List}>
{stackToComponentSources(componentStack).map(
([displayName, source], index) => {
return (
<li key={index}>
<Button
className={
source
? styles.ClickableSource
: styles.UnclickableSource
}
disabled={!source}
onClick={() => viewSource(source)}>
{displayName}
</Button>
</li>
);
},
)}
</ul>
</li>
)}
</ul>
</div>
</>
);
}

export default function SidebarEventInfo(_: Props) {
const {selectedEvent} = useContext(TimelineContext);
// (TODO) Refactor in next PR so this supports multiple types of events
return selectedEvent ? (
<>
<div className={styles.Toolbar}>Event Component Tree</div>
{selectedEvent.schedulingEvent ? (
<SchedulingEventInfo eventInfo={selectedEvent.schedulingEvent} />
) : null}
</>
) : null;
if (selectedEvent && selectedEvent.schedulingEvent) {
return <SchedulingEventInfo eventInfo={selectedEvent.schedulingEvent} />;
}

return null;
}
20 changes: 6 additions & 14 deletions packages/react-devtools-timeline/src/EventTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ import type {
} from './types';

import * as React from 'react';
import {formatDuration, formatTimestamp, trimString} from './utils/formatting';
import {
formatDuration,
formatTimestamp,
trimString,
getSchedulingEventLabel,
} from './utils/formatting';
import {getBatchRange} from './utils/getBatchRange';
import useSmartTooltip from './utils/useSmartTooltip';
import styles from './EventTooltip.css';
Expand All @@ -40,19 +45,6 @@ type Props = {|
width: number,
|};

function getSchedulingEventLabel(event: SchedulingEvent): string | null {
switch (event.type) {
case 'schedule-render':
return 'render scheduled';
case 'schedule-state-update':
return 'state update scheduled';
case 'schedule-force-update':
return 'force update scheduled';
default:
return null;
}
}

function getReactMeasureLabel(type): string | null {
switch (type) {
case 'commit':
Expand Down
15 changes: 15 additions & 0 deletions packages/react-devtools-timeline/src/utils/formatting.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* @flow
*/

import type {SchedulingEvent} from '../types';

import prettyMilliseconds from 'pretty-ms';

export function formatTimestamp(ms: number) {
Expand All @@ -28,3 +30,16 @@ export function trimString(string: string, length: number): string {
}
return string;
}

export function getSchedulingEventLabel(event: SchedulingEvent): string | null {
switch (event.type) {
case 'schedule-render':
return 'render scheduled';
case 'schedule-state-update':
return 'state update scheduled';
case 'schedule-force-update':
return 'force update scheduled';
default:
return null;
}
}

0 comments on commit 4e1fcfa

Please sign in to comment.