index.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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 useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers';
  12. import type {BreadcrumbFrame} from 'sentry/utils/replays/types';
  13. import ConsoleFilters from 'sentry/views/replays/detail/console/consoleFilters';
  14. import ConsoleLogRow from 'sentry/views/replays/detail/console/consoleLogRow';
  15. import useConsoleFilters from 'sentry/views/replays/detail/console/useConsoleFilters';
  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. import useVirtualizedInspector from '../useVirtualizedInspector';
  21. interface Props {
  22. frames: undefined | BreadcrumbFrame[];
  23. startTimestampMs: number;
  24. }
  25. // Ensure this object is created once as it is an input to
  26. // `useVirtualizedList`'s memoization
  27. const cellMeasurer = {
  28. fixedWidth: true,
  29. minHeight: 24,
  30. };
  31. function Console({frames, startTimestampMs}: Props) {
  32. const {onMouseEnter, onMouseLeave, onClickTimestamp} = useCrumbHandlers();
  33. const filterProps = useConsoleFilters({frames: frames || []});
  34. const {expandPathsRef, searchTerm, logLevel, items, setSearchTerm} = filterProps;
  35. const clearSearchTerm = () => setSearchTerm('');
  36. const {currentTime, currentHoverTime} = useReplayContext();
  37. const listRef = useRef<ReactVirtualizedList>(null);
  38. const deps = useMemo(() => [items], [items]);
  39. const {cache, updateList} = useVirtualizedList({
  40. cellMeasurer,
  41. ref: listRef,
  42. deps,
  43. });
  44. const {handleDimensionChange} = useVirtualizedInspector({
  45. cache,
  46. listRef,
  47. expandPathsRef,
  48. });
  49. const renderRow = ({index, key, style, parent}: ListRowProps) => {
  50. const item = items[index];
  51. return (
  52. <CellMeasurer
  53. cache={cache}
  54. columnIndex={0}
  55. // Set key based on filters, otherwise we can have odd expand/collapse state
  56. // with <ObjectInspector> when filtering
  57. key={`${searchTerm}-${logLevel.join(',')}-${key}`}
  58. parent={parent}
  59. rowIndex={index}
  60. >
  61. <ConsoleLogRow
  62. currentHoverTime={currentHoverTime}
  63. currentTime={currentTime}
  64. expandPaths={Array.from(expandPathsRef.current?.get(index) || [])}
  65. frame={item}
  66. onMouseEnter={onMouseEnter}
  67. onMouseLeave={onMouseLeave}
  68. index={index}
  69. onClickTimestamp={onClickTimestamp}
  70. onDimensionChange={handleDimensionChange}
  71. startTimestampMs={startTimestampMs}
  72. style={style}
  73. />
  74. </CellMeasurer>
  75. );
  76. };
  77. return (
  78. <FluidHeight>
  79. <ConsoleFilters frames={frames} {...filterProps} />
  80. <TabItemContainer data-test-id="replay-details-console-tab">
  81. {frames ? (
  82. <AutoSizer onResize={updateList}>
  83. {({width, height}) => (
  84. <ReactVirtualizedList
  85. deferredMeasurementCache={cache}
  86. height={height}
  87. noRowsRenderer={() => (
  88. <NoRowRenderer
  89. unfilteredItems={frames}
  90. clearSearchTerm={clearSearchTerm}
  91. >
  92. {t('No console logs recorded')}
  93. </NoRowRenderer>
  94. )}
  95. overscanRowCount={5}
  96. ref={listRef}
  97. rowCount={items.length}
  98. rowHeight={cache.rowHeight}
  99. rowRenderer={renderRow}
  100. width={width}
  101. />
  102. )}
  103. </AutoSizer>
  104. ) : (
  105. <Placeholder height="100%" />
  106. )}
  107. </TabItemContainer>
  108. </FluidHeight>
  109. );
  110. }
  111. export default memo(Console);