deadRageSelectorCards.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. import {ComponentProps, Fragment, ReactNode} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Location} from 'history';
  4. import {LinkButton} from 'sentry/components/button';
  5. import {hydratedSelectorData} from 'sentry/components/replays/utils';
  6. import {IconCursorArrow, IconShow} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import useDeadRageSelectors from 'sentry/utils/replays/hooks/useDeadRageSelectors';
  10. import {useLocation} from 'sentry/utils/useLocation';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  13. import SelectorTable from 'sentry/views/replays/deadRageClick/selectorTable';
  14. function DeadRageSelectorCards() {
  15. const location = useLocation();
  16. return (
  17. <SplitCardContainer>
  18. <DeadClickTable location={location} />
  19. <RageClickTable location={location} />
  20. </SplitCardContainer>
  21. );
  22. }
  23. function DeadClickTable({location}: {location: Location<any>}) {
  24. const {isLoading, isError, data} = useDeadRageSelectors({
  25. per_page: 3,
  26. sort: '-count_dead_clicks',
  27. cursor: undefined,
  28. prefix: 'selector_',
  29. });
  30. return (
  31. <SelectorTable
  32. data={hydratedSelectorData(data, 'count_dead_clicks')}
  33. isError={isError}
  34. isLoading={isLoading}
  35. location={location}
  36. clickCountColumn={{key: 'count_dead_clicks', name: 'dead clicks'}}
  37. clickCountSortable={false}
  38. title={
  39. <Fragment>
  40. <IconContainer>
  41. <IconCursorArrow size="xs" color="yellow300" />
  42. </IconContainer>
  43. {t('Most Dead Clicks')}
  44. </Fragment>
  45. }
  46. headerButtons={
  47. <SearchButton
  48. label={t('Show all')}
  49. sort="-count_dead_clicks"
  50. path="dead-clicks"
  51. />
  52. }
  53. customHandleResize={() => {}}
  54. />
  55. );
  56. }
  57. function RageClickTable({location}: {location: Location<any>}) {
  58. const {isLoading, isError, data} = useDeadRageSelectors({
  59. per_page: 3,
  60. sort: '-count_rage_clicks',
  61. cursor: undefined,
  62. prefix: 'selector_',
  63. });
  64. return (
  65. <SelectorTable
  66. data={hydratedSelectorData(data, 'count_rage_clicks')}
  67. isError={isError}
  68. isLoading={isLoading}
  69. location={location}
  70. clickCountColumn={{key: 'count_rage_clicks', name: 'rage clicks'}}
  71. clickCountSortable={false}
  72. title={
  73. <Fragment>
  74. <IconContainer>
  75. <IconCursorArrow size="xs" color="red300" />
  76. </IconContainer>
  77. {t('Most Rage Clicks')}
  78. </Fragment>
  79. }
  80. headerButtons={
  81. <SearchButton
  82. label={t('Show all')}
  83. sort="-count_rage_clicks"
  84. path="rage-clicks"
  85. />
  86. }
  87. customHandleResize={() => {}}
  88. />
  89. );
  90. }
  91. function SearchButton({
  92. label,
  93. sort,
  94. path,
  95. ...props
  96. }: {
  97. label: ReactNode;
  98. path: string;
  99. sort: string;
  100. } & Omit<ComponentProps<typeof LinkButton>, 'size' | 'to'>) {
  101. const location = useLocation();
  102. const organization = useOrganization();
  103. return (
  104. <LinkButton
  105. {...props}
  106. size="xs"
  107. to={{
  108. pathname: normalizeUrl(`/organizations/${organization.slug}/replays/${path}/`),
  109. query: {
  110. ...location.query,
  111. sort,
  112. query: undefined,
  113. cursor: undefined,
  114. },
  115. }}
  116. icon={<IconShow size="xs" />}
  117. >
  118. {label}
  119. </LinkButton>
  120. );
  121. }
  122. const SplitCardContainer = styled('div')`
  123. display: grid;
  124. grid-template-columns: 1fr 1fr;
  125. grid-template-rows: max-content max-content;
  126. grid-auto-flow: column;
  127. gap: 0 ${space(2)};
  128. align-items: stretch;
  129. padding-top: ${space(1)};
  130. `;
  131. const IconContainer = styled('span')`
  132. margin-right: ${space(1)};
  133. `;
  134. export default DeadRageSelectorCards;