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 type {Stack} from '../../utils';
    
  11. import type {SchedulingEvent} from 'react-devtools-timeline/src/types';
    
  12. 
    
  13. import * as React from 'react';
    
  14. import Button from '../Button';
    
  15. import ButtonIcon from '../ButtonIcon';
    
  16. import ViewSourceContext from '../Components/ViewSourceContext';
    
  17. import {useContext} from 'react';
    
  18. import {TimelineContext} from 'react-devtools-timeline/src/TimelineContext';
    
  19. import {
    
  20.   formatTimestamp,
    
  21.   getSchedulingEventLabel,
    
  22. } from 'react-devtools-timeline/src/utils/formatting';
    
  23. import {stackToComponentSources} from 'react-devtools-shared/src/devtools/utils';
    
  24. import {copy} from 'clipboard-js';
    
  25. 
    
  26. import styles from './SidebarEventInfo.css';
    
  27. 
    
  28. export type Props = {};
    
  29. 
    
  30. type SchedulingEventProps = {
    
  31.   eventInfo: SchedulingEvent,
    
  32. };
    
  33. 
    
  34. function SchedulingEventInfo({eventInfo}: SchedulingEventProps) {
    
  35.   const {viewUrlSourceFunction} = useContext(ViewSourceContext);
    
  36.   const {componentName, timestamp} = eventInfo;
    
  37.   const componentStack = eventInfo.componentStack || null;
    
  38. 
    
  39.   const viewSource = (source: ?Stack) => {
    
  40.     if (viewUrlSourceFunction != null && source != null) {
    
  41.       viewUrlSourceFunction(...source);
    
  42.     }
    
  43.   };
    
  44. 
    
  45.   return (
    
  46.     <>
    
  47.       <div className={styles.Toolbar}>
    
  48.         {componentName} {getSchedulingEventLabel(eventInfo)}
    
  49.       </div>
    
  50.       <div className={styles.Content} tabIndex={0}>
    
  51.         <ul className={styles.List}>
    
  52.           <li className={styles.ListItem}>
    
  53.             <label className={styles.Label}>Timestamp</label>:{' '}
    
  54.             <span className={styles.Value}>{formatTimestamp(timestamp)}</span>
    
  55.           </li>
    
  56.           {componentStack && (
    
  57.             <li className={styles.ListItem}>
    
  58.               <div className={styles.Row}>
    
  59.                 <label className={styles.Label}>Rendered by</label>
    
  60.                 <Button
    
  61.                   onClick={() => copy(componentStack)}
    
  62.                   title="Copy component stack to clipboard">
    
  63.                   <ButtonIcon type="copy" />
    
  64.                 </Button>
    
  65.               </div>
    
  66.               <ul className={styles.List}>
    
  67.                 {stackToComponentSources(componentStack).map(
    
  68.                   ([displayName, source], index) => {
    
  69.                     return (
    
  70.                       <li key={index}>
    
  71.                         <Button
    
  72.                           className={
    
  73.                             source
    
  74.                               ? styles.ClickableSource
    
  75.                               : styles.UnclickableSource
    
  76.                           }
    
  77.                           disabled={!source}
    
  78.                           onClick={() => viewSource(source)}>
    
  79.                           {displayName}
    
  80.                         </Button>
    
  81.                       </li>
    
  82.                     );
    
  83.                   },
    
  84.                 )}
    
  85.               </ul>
    
  86.             </li>
    
  87.           )}
    
  88.         </ul>
    
  89.       </div>
    
  90.     </>
    
  91.   );
    
  92. }
    
  93. 
    
  94. export default function SidebarEventInfo(_: Props): React.Node {
    
  95.   const {selectedEvent} = useContext(TimelineContext);
    
  96.   // (TODO) Refactor in next PR so this supports multiple types of events
    
  97.   if (selectedEvent && selectedEvent.schedulingEvent) {
    
  98.     return <SchedulingEventInfo eventInfo={selectedEvent.schedulingEvent} />;
    
  99.   }
    
  100. 
    
  101.   return null;
    
  102. }