accessibilityTableCell.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import type {ComponentProps, CSSProperties} from 'react';
  2. import {forwardRef} from 'react';
  3. import classNames from 'classnames';
  4. import {
  5. Cell,
  6. CodeHighlightCell,
  7. Text,
  8. } from 'sentry/components/replays/virtualizedGrid/bodyCell';
  9. import {Tooltip} from 'sentry/components/tooltip';
  10. import {IconFire, IconInfo, IconWarning} from 'sentry/icons';
  11. import type useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers';
  12. import type {HydratedA11yFrame} from 'sentry/utils/replays/hydrateA11yFrame';
  13. import type {Color} from 'sentry/utils/theme';
  14. import useUrlParams from 'sentry/utils/useUrlParams';
  15. import type useSortAccessibility from 'sentry/views/replays/detail/accessibility/useSortAccessibility';
  16. const EMPTY_CELL = '--';
  17. const IMPACT_ICON_MAPPING: Record<keyof HydratedA11yFrame['impact'], Color> = {
  18. minor: <IconInfo size="xs" />,
  19. moderate: <IconInfo size="xs" />,
  20. serious: <IconWarning size="xs" color="yellow400" />,
  21. critical: <IconFire size="xs" color="red400" />,
  22. };
  23. interface Props extends ReturnType<typeof useCrumbHandlers> {
  24. a11yIssue: HydratedA11yFrame;
  25. columnIndex: number;
  26. currentHoverTime: number | undefined;
  27. currentTime: number;
  28. onClickCell: (props: {dataIndex: number; rowIndex: number}) => void;
  29. rowIndex: number;
  30. sortConfig: ReturnType<typeof useSortAccessibility>['sortConfig'];
  31. style: CSSProperties;
  32. }
  33. const AccessibilityTableCell = forwardRef<HTMLDivElement, Props>(
  34. (
  35. {
  36. a11yIssue,
  37. columnIndex,
  38. currentHoverTime,
  39. currentTime,
  40. onClickCell,
  41. onMouseEnter,
  42. onMouseLeave,
  43. rowIndex,
  44. sortConfig,
  45. style,
  46. }: Props,
  47. ref
  48. ) => {
  49. // Rows include the sortable header, the dataIndex does not
  50. const dataIndex = rowIndex - 1;
  51. const {getParamValue} = useUrlParams('a_detail_row', '');
  52. const isSelected = getParamValue() === String(dataIndex);
  53. const hasOccurred = currentTime >= a11yIssue.offsetMs;
  54. const isBeforeHover =
  55. currentHoverTime === undefined || currentHoverTime >= a11yIssue.offsetMs;
  56. const isByTimestamp = sortConfig.by === 'timestampMs';
  57. const isAsc = isByTimestamp ? sortConfig.asc : undefined;
  58. const columnProps = {
  59. className: classNames({
  60. beforeCurrentTime: isByTimestamp
  61. ? isAsc
  62. ? hasOccurred
  63. : !hasOccurred
  64. : undefined,
  65. afterCurrentTime: isByTimestamp
  66. ? isAsc
  67. ? !hasOccurred
  68. : hasOccurred
  69. : undefined,
  70. beforeHoverTime:
  71. isByTimestamp && currentHoverTime !== undefined
  72. ? isAsc
  73. ? isBeforeHover
  74. : !isBeforeHover
  75. : undefined,
  76. afterHoverTime:
  77. isByTimestamp && currentHoverTime !== undefined
  78. ? isAsc
  79. ? !isBeforeHover
  80. : isBeforeHover
  81. : undefined,
  82. }),
  83. hasOccurred: isByTimestamp ? hasOccurred : undefined,
  84. isSelected,
  85. onClick: () => onClickCell({dataIndex, rowIndex}),
  86. onMouseEnter: () => onMouseEnter(a11yIssue),
  87. onMouseLeave: () => onMouseLeave(a11yIssue),
  88. ref,
  89. style,
  90. } as ComponentProps<typeof Cell>;
  91. const renderFns = [
  92. () => (
  93. <Cell {...columnProps}>
  94. <Text>
  95. {a11yIssue.impact ? (
  96. <Tooltip title={a11yIssue.impact ?? EMPTY_CELL}>
  97. {IMPACT_ICON_MAPPING[a11yIssue.impact]}
  98. </Tooltip>
  99. ) : (
  100. EMPTY_CELL
  101. )}
  102. </Text>
  103. </Cell>
  104. ),
  105. () => (
  106. <Cell {...columnProps}>
  107. <Text>{a11yIssue.id ?? EMPTY_CELL}</Text>
  108. </Cell>
  109. ),
  110. () => (
  111. <Cell {...columnProps}>
  112. <CodeHighlightCell language="html" hideCopyButton data-render-inline>
  113. {a11yIssue.element.element ?? EMPTY_CELL}
  114. </CodeHighlightCell>
  115. </Cell>
  116. ),
  117. ];
  118. return renderFns[columnIndex]();
  119. }
  120. );
  121. export default AccessibilityTableCell;