main
js 160 lines 4.56 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11 import {Fragment, useContext, useEffect, useRef} from 'react';
12
13 import WhatChanged from './WhatChanged';
14 import {ProfilerContext} from './ProfilerContext';
15 import {formatDuration, formatTime} from './utils';
16 import {StoreContext} from '../context';
17 import Button from '../Button';
18 import ButtonIcon from '../ButtonIcon';
19 import InspectedElementBadges from '../Components/InspectedElementBadges';
20
21 import styles from './SidebarSelectedFiberInfo.css';
22
23 export default function SidebarSelectedFiberInfo(): React.Node {
24 const {profilerStore} = useContext(StoreContext);
25 const {
26 rootID,
27 selectCommitIndex,
28 selectedCommitIndex,
29 selectedFiberID,
30 selectedFiberName,
31 selectFiber,
32 } = useContext(ProfilerContext);
33 const {profilingCache} = profilerStore;
34 const selectedListItemRef = useRef<HTMLElement | null>(null);
35
36 useEffect(() => {
37 const selectedElement = selectedListItemRef.current;
38 if (
39 selectedElement !== null &&
40 // $FlowFixMe[method-unbinding]
41 typeof selectedElement.scrollIntoView === 'function'
42 ) {
43 selectedElement.scrollIntoView({block: 'nearest', inline: 'nearest'});
44 }
45 }, [selectedCommitIndex]);
46
47 if (
48 selectedFiberID === null ||
49 rootID === null ||
50 selectedCommitIndex === null
51 ) {
52 return null;
53 }
54
55 const commitIndices = profilingCache.getFiberCommits({
56 fiberID: selectedFiberID,
57 rootID: rootID,
58 });
59
60 const {nodes} = profilingCache.getCommitTree({
61 rootID,
62 commitIndex: selectedCommitIndex,
63 });
64 const node = nodes.get(selectedFiberID);
65
66 // $FlowFixMe[missing-local-annot]
67 const handleKeyDown = event => {
68 switch (event.key) {
69 case 'ArrowUp':
70 // $FlowFixMe[invalid-compare]
71 if (selectedCommitIndex !== null) {
72 const prevIndex = commitIndices.indexOf(selectedCommitIndex);
73 const nextIndex =
74 prevIndex > 0 ? prevIndex - 1 : commitIndices.length - 1;
75 selectCommitIndex(commitIndices[nextIndex]);
76 }
77 event.preventDefault();
78 break;
79 case 'ArrowDown':
80 // $FlowFixMe[invalid-compare]
81 if (selectedCommitIndex !== null) {
82 const prevIndex = commitIndices.indexOf(selectedCommitIndex);
83 const nextIndex =
84 prevIndex < commitIndices.length - 1 ? prevIndex + 1 : 0;
85 selectCommitIndex(commitIndices[nextIndex]);
86 }
87 event.preventDefault();
88 break;
89 default:
90 break;
91 }
92 };
93
94 const listItems = [];
95 let i = 0;
96 for (i = 0; i < commitIndices.length; i++) {
97 const commitIndex = commitIndices[i];
98
99 const {duration, timestamp} = profilerStore.getCommitData(
100 rootID as any as number,
101 commitIndex,
102 );
103
104 listItems.push(
105 <button
106 key={commitIndex}
107 ref={selectedCommitIndex === commitIndex ? selectedListItemRef : null}
108 className={
109 selectedCommitIndex === commitIndex
110 ? styles.CurrentCommit
111 : styles.Commit
112 }
113 onClick={() => selectCommitIndex(commitIndex)}>
114 {formatTime(timestamp)}s for {formatDuration(duration)}ms
115 </button>,
116 );
117 }
118
119 return (
120 <Fragment>
121 <div className={styles.Toolbar}>
122 <div className={styles.Component}>
123 {selectedFiberName || 'Selected component'}
124 </div>
125
126 <Button
127 onClick={() => selectFiber(null, null)}
128 title="Back to commit view">
129 <ButtonIcon type="close" />
130 </Button>
131 </div>
132 <div className={styles.Content}>
133 <div className={styles.RenderInfo}>
134 <div className={styles.RenderInfoContent}>
135 {node != null && (
136 <InspectedElementBadges
137 hocDisplayNames={node.hocDisplayNames}
138 compiledWithForget={node.compiledWithForget}
139 />
140 )}
141 <WhatChanged fiberID={selectedFiberID as any as number} />
142 </div>
143 </div>
144 <div className={styles.CommitList} onKeyDown={handleKeyDown}>
145 {listItems.length > 0 && (
146 <div>
147 <label className={styles.Label}>Rendered at: </label>
148 {listItems}
149 </div>
150 )}
151 {listItems.length === 0 && (
152 <div>
153 Did not render on the client during this profiling session.
154 </div>
155 )}
156 </div>
157 </div>
158 </Fragment>
159 );
160 }