deadRageSelectorCards.tsx 3.8 KB

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