replaysErroneousDeadRageCards.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import {useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Location} from 'history';
  4. import {space} from 'sentry/styles/space';
  5. import type {Organization} from 'sentry/types';
  6. import EventView from 'sentry/utils/discover/eventView';
  7. import useReplayList from 'sentry/utils/replays/hooks/useReplayList';
  8. import {useHaveSelectedProjectsSentAnyReplayEvents} from 'sentry/utils/replays/hooks/useReplayOnboarding';
  9. import {useLocation} from 'sentry/utils/useLocation';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import ReplayTable from 'sentry/views/replays/replayTable';
  12. import {ReplayColumn} from 'sentry/views/replays/replayTable/types';
  13. import {ReplayListLocationQuery} from 'sentry/views/replays/types';
  14. function ReplaysErroneousDeadRageCards() {
  15. const organization = useOrganization();
  16. const location = useLocation<ReplayListLocationQuery>();
  17. const newLocation = useMemo(() => {
  18. return {
  19. pathname: '',
  20. search: '',
  21. hash: '',
  22. state: '',
  23. action: 'PUSH' as const,
  24. key: '',
  25. query: {
  26. project: location.query.project,
  27. environment: location.query.environment,
  28. start: location.query.start,
  29. statsPeriod: location.query.statsPeriod,
  30. utc: location.query.utc,
  31. end: location.query.end,
  32. },
  33. };
  34. }, [
  35. location.query.project,
  36. location.query.environment,
  37. location.query.start,
  38. location.query.statsPeriod,
  39. location.query.utc,
  40. location.query.end,
  41. ]);
  42. const eventViewErrors = useMemo(() => {
  43. return EventView.fromNewQueryWithLocation(
  44. {
  45. id: '',
  46. name: '',
  47. version: 2,
  48. fields: [
  49. 'activity',
  50. 'duration',
  51. 'count_errors',
  52. 'id',
  53. 'project_id',
  54. 'user',
  55. 'finished_at',
  56. 'is_archived',
  57. 'started_at',
  58. ],
  59. projects: [],
  60. query: 'count_errors:>0',
  61. orderby: '-count_errors',
  62. },
  63. newLocation
  64. );
  65. }, [newLocation]);
  66. const eventViewDeadRage = useMemo(() => {
  67. return EventView.fromNewQueryWithLocation(
  68. {
  69. id: '',
  70. name: '',
  71. version: 2,
  72. fields: [
  73. 'activity',
  74. 'duration',
  75. 'count_dead_clicks',
  76. 'count_rage_clicks',
  77. 'id',
  78. 'project_id',
  79. 'user',
  80. 'finished_at',
  81. 'is_archived',
  82. 'started_at',
  83. ],
  84. projects: [],
  85. query: 'count_rage_clicks:>0',
  86. orderby: '-count_rage_clicks',
  87. },
  88. newLocation
  89. );
  90. }, [newLocation]);
  91. const hasSessionReplay = organization.features.includes('session-replay');
  92. const hasDeadRageCards = organization.features.includes('replay-error-click-cards');
  93. const {hasSentOneReplay, fetching} = useHaveSelectedProjectsSentAnyReplayEvents();
  94. const deadRageCols = [
  95. ReplayColumn.MOST_RAGE_CLICKS,
  96. ReplayColumn.COUNT_DEAD_CLICKS,
  97. ReplayColumn.COUNT_RAGE_CLICKS,
  98. ];
  99. const errorCols = [
  100. ReplayColumn.MOST_ERRONEOUS_REPLAYS,
  101. ReplayColumn.DURATION,
  102. ReplayColumn.COUNT_ERRORS,
  103. ReplayColumn.ACTIVITY,
  104. ];
  105. return hasSessionReplay && !fetching && hasSentOneReplay ? (
  106. hasDeadRageCards ? (
  107. <SplitCardContainer>
  108. <CardTable
  109. eventView={eventViewErrors}
  110. location={newLocation}
  111. organization={organization}
  112. visibleColumns={errorCols}
  113. />
  114. <CardTable
  115. eventView={eventViewDeadRage}
  116. location={newLocation}
  117. organization={organization}
  118. visibleColumns={deadRageCols}
  119. />
  120. </SplitCardContainer>
  121. ) : null
  122. ) : null;
  123. }
  124. function CardTable({
  125. eventView,
  126. location,
  127. organization,
  128. visibleColumns,
  129. }: {
  130. eventView: EventView;
  131. location: Location;
  132. organization: Organization;
  133. visibleColumns: ReplayColumn[];
  134. }) {
  135. const {replays, isFetching, fetchError} = useReplayList({
  136. eventView,
  137. location,
  138. organization,
  139. perPage: 3,
  140. });
  141. const gridRows = new Array(replays ? (replays.length > 0 ? 3 : 1) : 1)
  142. .fill(' ')
  143. .map(_ => '1fr')
  144. .join(' ');
  145. return (
  146. <ReplayTable
  147. fetchError={fetchError}
  148. isFetching={isFetching}
  149. replays={replays}
  150. sort={undefined}
  151. visibleColumns={visibleColumns}
  152. saveLocation
  153. gridRows={'auto ' + gridRows}
  154. />
  155. );
  156. }
  157. const SplitCardContainer = styled('div')`
  158. display: grid;
  159. grid-template-columns: 1fr 1fr;
  160. gap: ${space(2)};
  161. align-items: stretch;
  162. `;
  163. export default ReplaysErroneousDeadRageCards;