deadRageSelectorCards.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import {ComponentProps, 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 {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={t('Most Dead Clicks')}
  39. headerButtons={
  40. <SearchButton
  41. label={t('Show all')}
  42. sort="-count_dead_clicks"
  43. path="dead-clicks"
  44. />
  45. }
  46. customHandleResize={() => {}}
  47. />
  48. );
  49. }
  50. function RageClickTable({location}: {location: Location<any>}) {
  51. const {isLoading, isError, data} = useDeadRageSelectors({
  52. per_page: 3,
  53. sort: '-count_rage_clicks',
  54. cursor: undefined,
  55. prefix: 'selector_',
  56. });
  57. return (
  58. <SelectorTable
  59. data={hydratedSelectorData(data, 'count_rage_clicks')}
  60. isError={isError}
  61. isLoading={isLoading}
  62. location={location}
  63. clickCountColumn={{key: 'count_rage_clicks', name: 'rage clicks'}}
  64. clickCountSortable={false}
  65. title={t('Most Rage Clicks')}
  66. headerButtons={
  67. <SearchButton
  68. label={t('Show all')}
  69. sort="-count_rage_clicks"
  70. path="rage-clicks"
  71. />
  72. }
  73. customHandleResize={() => {}}
  74. />
  75. );
  76. }
  77. function SearchButton({
  78. label,
  79. sort,
  80. path,
  81. ...props
  82. }: {
  83. label: ReactNode;
  84. path: string;
  85. sort: string;
  86. } & Omit<ComponentProps<typeof LinkButton>, 'size' | 'to'>) {
  87. const location = useLocation();
  88. const organization = useOrganization();
  89. return (
  90. <LinkButton
  91. {...props}
  92. size="sm"
  93. to={{
  94. pathname: normalizeUrl(`/organizations/${organization.slug}/replays/${path}/`),
  95. query: {
  96. ...location.query,
  97. sort,
  98. query: undefined,
  99. cursor: undefined,
  100. },
  101. }}
  102. icon={<IconShow size="xs" />}
  103. >
  104. {label}
  105. </LinkButton>
  106. );
  107. }
  108. const SplitCardContainer = styled('div')`
  109. display: grid;
  110. grid-template-columns: 1fr 1fr;
  111. grid-template-rows: max-content max-content;
  112. grid-auto-flow: column;
  113. gap: 0 ${space(2)};
  114. align-items: stretch;
  115. padding-top: ${space(1)};
  116. `;
  117. export default DeadRageSelectorCards;