index.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {memo, useMemo, useRef} from 'react';
  2. import {
  3. AutoSizer,
  4. CellMeasurer,
  5. List as ReactVirtualizedList,
  6. ListRowProps,
  7. } from 'react-virtualized';
  8. import Placeholder from 'sentry/components/placeholder';
  9. import {useReplayContext} from 'sentry/components/replays/replayContext';
  10. import {t} from 'sentry/locale';
  11. import useExtractedCrumbHtml from 'sentry/utils/replays/hooks/useExtractedCrumbHtml';
  12. import type ReplayReader from 'sentry/utils/replays/replayReader';
  13. import DomFilters from 'sentry/views/replays/detail/domMutations/domFilters';
  14. import DomMutationRow from 'sentry/views/replays/detail/domMutations/domMutationRow';
  15. import useDomFilters from 'sentry/views/replays/detail/domMutations/useDomFilters';
  16. import FluidHeight from 'sentry/views/replays/detail/layout/fluidHeight';
  17. import NoRowRenderer from 'sentry/views/replays/detail/noRowRenderer';
  18. import TabItemContainer from 'sentry/views/replays/detail/tabItemContainer';
  19. import useVirtualizedList from 'sentry/views/replays/detail/useVirtualizedList';
  20. type Props = {
  21. replay: null | ReplayReader;
  22. startTimestampMs: number;
  23. };
  24. // Ensure this object is created once as it is an input to
  25. // `useVirtualizedList`'s memoization
  26. const cellMeasurer = {
  27. fixedWidth: true,
  28. minHeight: 82,
  29. };
  30. function DomMutations({replay, startTimestampMs}: Props) {
  31. const {isLoading, actions} = useExtractedCrumbHtml({replay});
  32. const {currentTime, currentHoverTime} = useReplayContext();
  33. const filterProps = useDomFilters({actions: actions || []});
  34. const {items, setSearchTerm} = filterProps;
  35. const clearSearchTerm = () => setSearchTerm('');
  36. const listRef = useRef<ReactVirtualizedList>(null);
  37. const deps = useMemo(() => [items], [items]);
  38. const {cache, updateList} = useVirtualizedList({
  39. cellMeasurer,
  40. ref: listRef,
  41. deps,
  42. });
  43. const renderRow = ({index, key, style, parent}: ListRowProps) => {
  44. const mutation = items[index];
  45. return (
  46. <CellMeasurer
  47. cache={cache}
  48. columnIndex={0}
  49. key={key}
  50. parent={parent}
  51. rowIndex={index}
  52. >
  53. <DomMutationRow
  54. currentTime={currentTime}
  55. currentHoverTime={currentHoverTime}
  56. mutation={mutation}
  57. startTimestampMs={startTimestampMs}
  58. style={style}
  59. />
  60. </CellMeasurer>
  61. );
  62. };
  63. return (
  64. <FluidHeight>
  65. <DomFilters actions={actions} {...filterProps} />
  66. <TabItemContainer>
  67. {isLoading || !actions ? (
  68. <Placeholder height="100%" />
  69. ) : (
  70. <AutoSizer onResize={updateList}>
  71. {({width, height}) => (
  72. <ReactVirtualizedList
  73. deferredMeasurementCache={cache}
  74. height={height}
  75. noRowsRenderer={() => (
  76. <NoRowRenderer
  77. unfilteredItems={actions}
  78. clearSearchTerm={clearSearchTerm}
  79. >
  80. {t('No DOM events recorded')}
  81. </NoRowRenderer>
  82. )}
  83. overscanRowCount={5}
  84. ref={listRef}
  85. rowCount={items.length}
  86. rowHeight={cache.rowHeight}
  87. rowRenderer={renderRow}
  88. width={width}
  89. />
  90. )}
  91. </AutoSizer>
  92. )}
  93. </TabItemContainer>
  94. </FluidHeight>
  95. );
  96. }
  97. export default memo(DomMutations);