Skip to content

Commit af6a412

Browse files
committed
Resign sidebar
1 parent 1974d08 commit af6a412

File tree

4 files changed

+112
-80
lines changed

4 files changed

+112
-80
lines changed

packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.css

+23-26
Original file line numberDiff line numberDiff line change
@@ -20,51 +20,48 @@
2020
}
2121

2222
.ListItem {
23-
margin: 0;
23+
flex: 1 1;
24+
margin: 0 0 0.5rem;
2425
}
2526

2627
.Label {
27-
display: flex;
28-
justify-content: space-between;
29-
28+
overflow: hidden;
29+
text-overflow: ellipsis;
3030
font-weight: bold;
31-
}
32-
33-
[data-source="true"]:hover .Label > .Button {
34-
background-color: var(--color-background-hover);
31+
flex: 1 1;
3532
}
3633

3734
.Value {
3835
font-family: var(--font-family-monospace);
3936
font-size: var(--font-size-monospace-normal);
4037
}
4138

42-
.NothingSelected {
43-
display: flex;
39+
.Row {
40+
display: flex;
41+
flex-direction: row;
4442
align-items: center;
45-
justify-content: center;
46-
height: 100%;
47-
color: var(--color-dim);
48-
}
43+
border-top: 1px solid var(--color-border);
44+
}
4945

50-
.Button {
51-
display: flex;
52-
flex: 1;
53-
54-
max-width: 95%;
46+
.UnclickableSource,
47+
.ClickableSource {
48+
width: 100%;
5549
overflow: hidden;
5650
text-overflow: ellipsis;
51+
font-family: var(--font-family-sans);
52+
font-size: var(--font-size-sans-normal);
5753
}
5854

59-
[data-source="true"] .Button {
60-
cursor: pointer;
55+
.UnclickableSource {
56+
color: var(--color-dim);
6157
}
6258

63-
64-
.Button > span {
65-
display: block;
66-
text-align: left;
59+
.ClickableSource {
60+
color: var(--color-text);
61+
cursor: pointer;
6762
}
6863

69-
.Source {
64+
.ClickableSource:focus,
65+
.ClickableSource:hover {
66+
background-color: var(--color-background-hover);
7067
}

packages/react-devtools-shared/src/devtools/views/Profiler/SidebarEventInfo.js

+68-40
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,25 @@ import ButtonIcon from '../ButtonIcon';
1515
import ViewSourceContext from '../Components/ViewSourceContext';
1616
import {useContext} from 'react';
1717
import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext';
18+
import {
19+
formatTimestamp,
20+
getSchedulingEventLabel,
21+
} from 'react-devtools-timeline/src/utils/formatting';
1822
import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils';
23+
import {copy} from 'clipboard-js';
1924

2025
import styles from './SidebarEventInfo.css';
2126

2227
export type Props = {||};
2328

24-
function SchedulingEventInfo({eventInfo}: {eventInfo: SchedulingEvent}) {
25-
const {viewUrlSourceFunction} = useContext(ViewSourceContext);
29+
type SchedulingEventProps = {|
30+
eventInfo: SchedulingEvent,
31+
|};
2632

27-
const componentStack = eventInfo.componentStack
28-
? stackToComponentSources(eventInfo.componentStack)
29-
: null;
33+
function SchedulingEventInfo({eventInfo}: SchedulingEventProps) {
34+
const {viewUrlSourceFunction} = useContext(ViewSourceContext);
35+
const {componentName, timestamp} = eventInfo;
36+
const componentStack = eventInfo.componentStack || null;
3037

3138
const viewSource = source => {
3239
if (viewUrlSourceFunction != null && source != null) {
@@ -35,45 +42,66 @@ function SchedulingEventInfo({eventInfo}: {eventInfo: SchedulingEvent}) {
3542
};
3643

3744
return (
38-
<div className={styles.Content} tabIndex={0}>
39-
{componentStack ? (
40-
<ol className={styles.List}>
41-
{componentStack.map(([displayName, source], index) => {
42-
const hasSource = source != null;
43-
44-
return (
45-
<li
46-
key={index}
47-
className={styles.ListItem}
48-
data-source={hasSource}>
49-
<label className={styles.Label}>
50-
<Button
51-
className={styles.Button}
52-
onClick={() => viewSource(source)}>
53-
{displayName}
54-
</Button>
55-
{hasSource && (
56-
<ButtonIcon className={styles.Source} type="view-source" />
57-
)}
58-
</label>
59-
</li>
60-
);
61-
})}
62-
</ol>
63-
) : null}
64-
</div>
45+
<>
46+
<div className={styles.Toolbar}>
47+
{componentName} {getSchedulingEventLabel(eventInfo)}
48+
</div>
49+
<div className={styles.Content} tabIndex={0}>
50+
<ul className={styles.List}>
51+
<li className={styles.ListItem}>
52+
<label className={styles.Label}>Timestamp</label>:{' '}
53+
<span className={styles.Value}>{formatTimestamp(timestamp)}</span>
54+
</li>
55+
{componentStack && (
56+
<li className={styles.ListItem}>
57+
<div className={styles.Row}>
58+
<label className={styles.Label}>Rendered by</label>
59+
<Button
60+
onClick={() => copy(componentStack)}
61+
title="Copy component stack to clipboard">
62+
<ButtonIcon type="copy" />
63+
</Button>
64+
</div>
65+
<ul className={styles.List}>
66+
{stackToComponentSources(componentStack).map(
67+
([displayName, source], index) => {
68+
return (
69+
<li key={index}>
70+
<Button
71+
className={
72+
source
73+
? styles.ClickableSource
74+
: styles.UnclickableSource
75+
}
76+
disabled={!source}
77+
onClick={() => viewSource(source)}>
78+
{displayName}
79+
</Button>
80+
</li>
81+
);
82+
},
83+
)}
84+
</ul>
85+
</li>
86+
)}
87+
</ul>
88+
</div>
89+
</>
6590
);
6691
}
6792

6893
export default function SidebarEventInfo(_: Props) {
6994
const {selectedEvent} = useContext(TimelineContext);
7095
// (TODO) Refactor in next PR so this supports multiple types of events
71-
return selectedEvent ? (
72-
<>
73-
<div className={styles.Toolbar}>Event Component Tree</div>
74-
{selectedEvent.schedulingEvent ? (
75-
<SchedulingEventInfo eventInfo={selectedEvent.schedulingEvent} />
76-
) : null}
77-
</>
78-
) : null;
96+
if (selectedEvent) {
97+
return (
98+
<>
99+
{selectedEvent.schedulingEvent ? (
100+
<SchedulingEventInfo eventInfo={selectedEvent.schedulingEvent} />
101+
) : null}
102+
</>
103+
);
104+
}
105+
106+
return null;
79107
}

packages/react-devtools-timeline/src/EventTooltip.js

+6-14
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ import type {
2424
} from './types';
2525

2626
import * as React from 'react';
27-
import {formatDuration, formatTimestamp, trimString} from './utils/formatting';
27+
import {
28+
formatDuration,
29+
formatTimestamp,
30+
trimString,
31+
getSchedulingEventLabel,
32+
} from './utils/formatting';
2833
import {getBatchRange} from './utils/getBatchRange';
2934
import useSmartTooltip from './utils/useSmartTooltip';
3035
import styles from './EventTooltip.css';
@@ -40,19 +45,6 @@ type Props = {|
4045
width: number,
4146
|};
4247

43-
function getSchedulingEventLabel(event: SchedulingEvent): string | null {
44-
switch (event.type) {
45-
case 'schedule-render':
46-
return 'render scheduled';
47-
case 'schedule-state-update':
48-
return 'state update scheduled';
49-
case 'schedule-force-update':
50-
return 'force update scheduled';
51-
default:
52-
return null;
53-
}
54-
}
55-
5648
function getReactMeasureLabel(type): string | null {
5749
switch (type) {
5850
case 'commit':

packages/react-devtools-timeline/src/utils/formatting.js

+15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
* @flow
88
*/
99

10+
import type {SchedulingEvent} from '../types';
11+
1012
import prettyMilliseconds from 'pretty-ms';
1113

1214
export function formatTimestamp(ms: number) {
@@ -28,3 +30,16 @@ export function trimString(string: string, length: number): string {
2830
}
2931
return string;
3032
}
33+
34+
export function getSchedulingEventLabel(event: SchedulingEvent): string | null {
35+
switch (event.type) {
36+
case 'schedule-render':
37+
return 'render scheduled';
38+
case 'schedule-state-update':
39+
return 'state update scheduled';
40+
case 'schedule-force-update':
41+
return 'force update scheduled';
42+
default:
43+
return null;
44+
}
45+
}

0 commit comments

Comments
 (0)