index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import {memo, useRef} from 'react';
  2. import {
  3. AutoSizer,
  4. CellMeasurer,
  5. List as ReactVirtualizedList,
  6. ListRowProps,
  7. } from 'react-virtualized';
  8. import styled from '@emotion/styled';
  9. import Placeholder from 'sentry/components/placeholder';
  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 useVirtualizedList from 'sentry/views/replays/detail/useVirtualizedList';
  19. type Props = {
  20. replay: null | ReplayReader;
  21. startTimestampMs: number;
  22. };
  23. function DomMutations({replay, startTimestampMs}: Props) {
  24. const {isLoading, actions} = useExtractedCrumbHtml({replay});
  25. const filterProps = useDomFilters({actions: actions || []});
  26. const {items, setSearchTerm} = filterProps;
  27. const clearSearchTerm = () => setSearchTerm('');
  28. const listRef = useRef<ReactVirtualizedList>(null);
  29. const {cache} = useVirtualizedList({
  30. cellMeasurer: {
  31. fixedWidth: true,
  32. minHeight: 82,
  33. },
  34. ref: listRef,
  35. deps: [items],
  36. });
  37. const renderRow = ({index, key, style, parent}: ListRowProps) => {
  38. const mutation = items[index];
  39. return (
  40. <CellMeasurer
  41. cache={cache}
  42. columnIndex={0}
  43. key={key}
  44. parent={parent}
  45. rowIndex={index}
  46. >
  47. <DomMutationRow
  48. mutation={mutation}
  49. mutations={items}
  50. startTimestampMs={startTimestampMs}
  51. style={style}
  52. />
  53. </CellMeasurer>
  54. );
  55. };
  56. return (
  57. <MutationContainer>
  58. <DomFilters actions={actions} {...filterProps} />
  59. <MutationItemContainer>
  60. {isLoading || !actions ? (
  61. <Placeholder height="100%" />
  62. ) : (
  63. <AutoSizer>
  64. {({width, height}) => (
  65. <ReactVirtualizedList
  66. deferredMeasurementCache={cache}
  67. height={height}
  68. noRowsRenderer={() => (
  69. <NoRowRenderer
  70. unfilteredItems={actions}
  71. clearSearchTerm={clearSearchTerm}
  72. >
  73. {t('No DOM events recorded')}
  74. </NoRowRenderer>
  75. )}
  76. overscanRowCount={5}
  77. ref={listRef}
  78. rowCount={items.length}
  79. rowHeight={cache.rowHeight}
  80. rowRenderer={renderRow}
  81. width={width}
  82. />
  83. )}
  84. </AutoSizer>
  85. )}
  86. </MutationItemContainer>
  87. </MutationContainer>
  88. );
  89. }
  90. const MutationContainer = styled(FluidHeight)`
  91. height: 100%;
  92. `;
  93. const MutationItemContainer = styled('div')`
  94. position: relative;
  95. height: 100%;
  96. overflow: hidden;
  97. border: 1px solid ${p => p.theme.border};
  98. border-radius: ${p => p.theme.borderRadius};
  99. `;
  100. export default memo(DomMutations);