groupReplays.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import Link from 'sentry/components/links/link';
  4. import Pagination from 'sentry/components/pagination';
  5. import {PanelTable} from 'sentry/components/panels';
  6. import {IconArrow} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import {PageContent} from 'sentry/styles/organization';
  9. import {Group, NewQuery} from 'sentry/types';
  10. import DiscoverQuery from 'sentry/utils/discover/discoverQuery';
  11. import EventView from 'sentry/utils/discover/eventView';
  12. import {getQueryParamAsString} from 'sentry/utils/replays/getQueryParamAsString';
  13. import {useLocation} from 'sentry/utils/useLocation';
  14. import useOrganization from 'sentry/utils/useOrganization';
  15. import {useParams} from 'sentry/utils/useParams';
  16. import ReplayTable from 'sentry/views/replays/replayTable';
  17. import {Replay} from 'sentry/views/replays/types';
  18. const DEFAULT_DISCOVER_LIMIT = 50;
  19. type Props = {
  20. group: Group;
  21. };
  22. const GroupReplays = ({group}: Props) => {
  23. const location = useLocation();
  24. const organization = useOrganization();
  25. const params = useParams();
  26. const {project} = group;
  27. const getEventView = () => {
  28. const {groupId} = params;
  29. const eventQueryParams: NewQuery = {
  30. id: '',
  31. name: '',
  32. version: 2,
  33. fields: [
  34. 'replayId',
  35. 'eventID',
  36. 'project',
  37. 'timestamp',
  38. 'url',
  39. 'user.display',
  40. 'user.email',
  41. 'user.id',
  42. 'user.ip_address',
  43. 'user.name',
  44. 'user.username',
  45. ],
  46. projects: [+project.id],
  47. orderby: getQueryParamAsString(query.sort) || '-timestamp',
  48. query: `issue.id:${groupId}`,
  49. };
  50. return EventView.fromNewQueryWithLocation(eventQueryParams, location);
  51. };
  52. const {query} = location;
  53. const {cursor: _cursor, page: _page, ...currentQuery} = query;
  54. const sort: {
  55. field: string;
  56. } = {
  57. field: getQueryParamAsString(query.sort) || '-timestamp',
  58. };
  59. const arrowDirection = sort.field.startsWith('-') ? 'down' : 'up';
  60. const sortArrow = <IconArrow color="gray300" size="xs" direction={arrowDirection} />;
  61. return (
  62. <Fragment>
  63. <StyledPageContent>
  64. <DiscoverQuery
  65. eventView={getEventView()}
  66. location={location}
  67. orgSlug={organization.slug}
  68. limit={DEFAULT_DISCOVER_LIMIT}
  69. >
  70. {data => {
  71. return (
  72. <Fragment>
  73. <StyledPanelTable
  74. isLoading={data.isLoading}
  75. isEmpty={data.tableData?.data.length === 0}
  76. headers={[
  77. t('Session'),
  78. <SortLink
  79. key="timestamp"
  80. role="columnheader"
  81. aria-sort={
  82. !sort.field.endsWith('timestamp')
  83. ? 'none'
  84. : sort.field === '-timestamp'
  85. ? 'descending'
  86. : 'ascending'
  87. }
  88. to={{
  89. pathname: location.pathname,
  90. query: {
  91. ...currentQuery,
  92. sort: sort.field === '-timestamp' ? 'timestamp' : '-timestamp',
  93. },
  94. }}
  95. >
  96. {t('Timestamp')} {sort.field.endsWith('timestamp') && sortArrow}
  97. </SortLink>,
  98. t('Duration'),
  99. t('Errors'),
  100. ]}
  101. >
  102. {data.tableData ? (
  103. <ReplayTable
  104. idKey="replayId"
  105. replayList={data.tableData.data as Replay[]}
  106. />
  107. ) : null}
  108. </StyledPanelTable>
  109. <Pagination pageLinks={data.pageLinks} />
  110. </Fragment>
  111. );
  112. }}
  113. </DiscoverQuery>
  114. </StyledPageContent>
  115. </Fragment>
  116. );
  117. };
  118. const StyledPanelTable = styled(PanelTable)`
  119. grid-template-columns: minmax(0, 1fr) max-content max-content max-content;
  120. `;
  121. const StyledPageContent = styled(PageContent)`
  122. box-shadow: 0px 0px 1px ${p => p.theme.gray200};
  123. background-color: ${p => p.theme.background};
  124. `;
  125. const SortLink = styled(Link)`
  126. color: inherit;
  127. :hover {
  128. color: inherit;
  129. }
  130. svg {
  131. vertical-align: top;
  132. }
  133. `;
  134. export default GroupReplays;