sortableHeader.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import styled from '@emotion/styled';
  2. import Link from 'sentry/components/links/link';
  3. import QuestionTooltip from 'sentry/components/questionTooltip';
  4. import {IconArrow} from 'sentry/icons';
  5. import space from 'sentry/styles/space';
  6. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  7. import type {Sort} from 'sentry/utils/discover/fields';
  8. import {useLocation} from 'sentry/utils/useLocation';
  9. import useOrganization from 'sentry/utils/useOrganization';
  10. import type {ReplayListLocationQuery} from 'sentry/views/replays/types';
  11. type NotSortable = {
  12. label: string;
  13. tooltip?: string;
  14. };
  15. type Sortable = {
  16. fieldName: string;
  17. label: string;
  18. sort: undefined | Sort;
  19. tooltip?: string;
  20. };
  21. type Props = NotSortable | Sortable;
  22. function SortableHeader(props: Props) {
  23. const location = useLocation<ReplayListLocationQuery>();
  24. const organization = useOrganization();
  25. if (!('sort' in props) || !props.sort) {
  26. const {label, tooltip} = props;
  27. return (
  28. <Header>
  29. {label}
  30. {tooltip ? (
  31. <StyledQuestionTooltip size="xs" position="top" title={tooltip} />
  32. ) : null}
  33. </Header>
  34. );
  35. }
  36. const {fieldName, label, sort, tooltip} = props;
  37. const arrowDirection = sort?.kind === 'asc' ? 'up' : 'down';
  38. const sortArrow = <IconArrow color="gray300" size="xs" direction={arrowDirection} />;
  39. return (
  40. <Header>
  41. <SortLink
  42. role="columnheader"
  43. aria-sort={
  44. sort?.field.endsWith(fieldName)
  45. ? sort?.kind === 'asc'
  46. ? 'ascending'
  47. : 'descending'
  48. : 'none'
  49. }
  50. onClick={() => {
  51. const column = sort?.field.endsWith(fieldName)
  52. ? sort?.kind === 'desc'
  53. ? fieldName
  54. : '-' + fieldName
  55. : '-' + fieldName;
  56. trackAdvancedAnalyticsEvent('replay.list-sorted', {
  57. organization,
  58. column,
  59. });
  60. }}
  61. to={{
  62. pathname: location.pathname,
  63. query: {
  64. ...location.query,
  65. sort: sort?.field.endsWith(fieldName)
  66. ? sort?.kind === 'desc'
  67. ? fieldName
  68. : '-' + fieldName
  69. : '-' + fieldName,
  70. },
  71. }}
  72. >
  73. {label} {sort?.field === fieldName && sortArrow}
  74. </SortLink>
  75. {tooltip ? (
  76. <StyledQuestionTooltip size="xs" position="top" title={tooltip} />
  77. ) : null}
  78. </Header>
  79. );
  80. }
  81. const Header = styled('div')`
  82. display: grid;
  83. grid-template-columns: repeat(2, max-content);
  84. align-items: center;
  85. `;
  86. const SortLink = styled(Link)`
  87. color: inherit;
  88. :hover {
  89. color: inherit;
  90. }
  91. svg {
  92. vertical-align: top;
  93. }
  94. `;
  95. const StyledQuestionTooltip = styled(QuestionTooltip)`
  96. margin-left: ${space(0.5)};
  97. `;
  98. export default SortableHeader;