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. import WhatChanged from './WhatChanged';
    
  13. import {ProfilerContext} from './ProfilerContext';
    
  14. import {formatDuration, formatTime} from './utils';
    
  15. import {StoreContext} from '../context';
    
  16. import Button from '../Button';
    
  17. import ButtonIcon from '../ButtonIcon';
    
  18. 
    
  19. import styles from './SidebarSelectedFiberInfo.css';
    
  20. 
    
  21. export type Props = {};
    
  22. 
    
  23. export default function SidebarSelectedFiberInfo(_: Props): 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.   const commitIndices = profilingCache.getFiberCommits({
    
  37.     fiberID: ((selectedFiberID: any): number),
    
  38.     rootID: ((rootID: any): number),
    
  39.   });
    
  40. 
    
  41.   // $FlowFixMe[missing-local-annot]
    
  42.   const handleKeyDown = event => {
    
  43.     switch (event.key) {
    
  44.       case 'ArrowUp':
    
  45.         if (selectedCommitIndex !== null) {
    
  46.           const prevIndex = commitIndices.indexOf(selectedCommitIndex);
    
  47.           const nextIndex =
    
  48.             prevIndex > 0 ? prevIndex - 1 : commitIndices.length - 1;
    
  49.           selectCommitIndex(commitIndices[nextIndex]);
    
  50.         }
    
  51.         event.preventDefault();
    
  52.         break;
    
  53.       case 'ArrowDown':
    
  54.         if (selectedCommitIndex !== null) {
    
  55.           const prevIndex = commitIndices.indexOf(selectedCommitIndex);
    
  56.           const nextIndex =
    
  57.             prevIndex < commitIndices.length - 1 ? prevIndex + 1 : 0;
    
  58.           selectCommitIndex(commitIndices[nextIndex]);
    
  59.         }
    
  60.         event.preventDefault();
    
  61.         break;
    
  62.       default:
    
  63.         break;
    
  64.     }
    
  65.   };
    
  66. 
    
  67.   useEffect(() => {
    
  68.     const selectedElement = selectedListItemRef.current;
    
  69.     if (
    
  70.       selectedElement !== null &&
    
  71.       // $FlowFixMe[method-unbinding]
    
  72.       typeof selectedElement.scrollIntoView === 'function'
    
  73.     ) {
    
  74.       selectedElement.scrollIntoView({block: 'nearest', inline: 'nearest'});
    
  75.     }
    
  76.   }, [selectedCommitIndex]);
    
  77. 
    
  78.   const listItems = [];
    
  79.   let i = 0;
    
  80.   for (i = 0; i < commitIndices.length; i++) {
    
  81.     const commitIndex = commitIndices[i];
    
  82. 
    
  83.     const {duration, timestamp} = profilerStore.getCommitData(
    
  84.       ((rootID: any): number),
    
  85.       commitIndex,
    
  86.     );
    
  87. 
    
  88.     listItems.push(
    
  89.       <button
    
  90.         key={commitIndex}
    
  91.         ref={selectedCommitIndex === commitIndex ? selectedListItemRef : null}
    
  92.         className={
    
  93.           selectedCommitIndex === commitIndex
    
  94.             ? styles.CurrentCommit
    
  95.             : styles.Commit
    
  96.         }
    
  97.         onClick={() => selectCommitIndex(commitIndex)}>
    
  98.         {formatTime(timestamp)}s for {formatDuration(duration)}ms
    
  99.       </button>,
    
  100.     );
    
  101.   }
    
  102. 
    
  103.   return (
    
  104.     <Fragment>
    
  105.       <div className={styles.Toolbar}>
    
  106.         <div className={styles.Component}>
    
  107.           {selectedFiberName || 'Selected component'}
    
  108.         </div>
    
  109. 
    
  110.         <Button
    
  111.           onClick={() => selectFiber(null, null)}
    
  112.           title="Back to commit view">
    
  113.           <ButtonIcon type="close" />
    
  114.         </Button>
    
  115.       </div>
    
  116.       <div className={styles.Content} onKeyDown={handleKeyDown} tabIndex={0}>
    
  117.         <WhatChanged fiberID={((selectedFiberID: any): number)} />
    
  118.         {listItems.length > 0 && (
    
  119.           <Fragment>
    
  120.             <label className={styles.Label}>Rendered at</label>: {listItems}
    
  121.           </Fragment>
    
  122.         )}
    
  123.         {listItems.length === 0 && (
    
  124.           <div>Did not render during this profiling session.</div>
    
  125.         )}
    
  126.       </div>
    
  127.     </Fragment>
    
  128.   );
    
  129. }