replays.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import {Fragment, useMemo} from 'react';
  2. import {browserHistory, RouteComponentProps} from 'react-router';
  3. import {useTheme} from '@emotion/react';
  4. import styled from '@emotion/styled';
  5. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  6. import PageHeading from 'sentry/components/pageHeading';
  7. import Pagination from 'sentry/components/pagination';
  8. import ReplaysFeatureBadge from 'sentry/components/replays/replaysFeatureBadge';
  9. import {t} from 'sentry/locale';
  10. import {PageContent, PageHeader} from 'sentry/styles/organization';
  11. import space from 'sentry/styles/space';
  12. import EventView from 'sentry/utils/discover/eventView';
  13. import {decodeScalar} from 'sentry/utils/queryString';
  14. import {DEFAULT_SORT, REPLAY_LIST_FIELDS} from 'sentry/utils/replays/fetchReplayList';
  15. import useReplayList from 'sentry/utils/replays/hooks/useReplayList';
  16. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  17. import useMedia from 'sentry/utils/useMedia';
  18. import useOrganization from 'sentry/utils/useOrganization';
  19. import ReplaysFilters from 'sentry/views/replays/filters';
  20. import ReplayTable from 'sentry/views/replays/replayTable';
  21. import type {ReplayListLocationQuery} from 'sentry/views/replays/types';
  22. type Props = RouteComponentProps<{orgId: string}, {}, any, ReplayListLocationQuery>;
  23. function Replays({location}: Props) {
  24. const organization = useOrganization();
  25. const theme = useTheme();
  26. const minWidthIsSmall = useMedia(`(min-width: ${theme.breakpoints.small})`);
  27. const eventView = useMemo(() => {
  28. const query = decodeScalar(location.query.query, '');
  29. const conditions = new MutableSearch(query);
  30. return EventView.fromNewQueryWithLocation(
  31. {
  32. id: '',
  33. name: '',
  34. version: 2,
  35. fields: REPLAY_LIST_FIELDS,
  36. projects: [],
  37. query: conditions.formatString(),
  38. orderby: decodeScalar(location.query.sort, DEFAULT_SORT),
  39. },
  40. location
  41. );
  42. }, [location]);
  43. const {pathname, query} = location;
  44. const {replays, pageLinks, isFetching, fetchError} = useReplayList({
  45. organization,
  46. eventView,
  47. });
  48. return (
  49. <Fragment>
  50. <StyledPageHeader>
  51. <HeaderTitle>
  52. <div>
  53. {t('Replays')} <ReplaysFeatureBadge />
  54. </div>
  55. </HeaderTitle>
  56. </StyledPageHeader>
  57. <PageFiltersContainer>
  58. <StyledPageContent>
  59. <ReplaysFilters
  60. query={query.query || ''}
  61. organization={organization}
  62. handleSearchQuery={searchQuery => {
  63. browserHistory.push({
  64. pathname,
  65. query: {
  66. ...query,
  67. cursor: undefined,
  68. query: searchQuery.trim(),
  69. },
  70. });
  71. }}
  72. />
  73. <ReplayTable
  74. isFetching={isFetching}
  75. fetchError={fetchError}
  76. replays={replays}
  77. showProjectColumn={minWidthIsSmall}
  78. sort={eventView.sorts[0]}
  79. />
  80. <Pagination
  81. pageLinks={pageLinks}
  82. onCursor={(cursor, path, searchQuery) => {
  83. browserHistory.push({
  84. pathname: path,
  85. query: {...searchQuery, cursor},
  86. });
  87. }}
  88. />
  89. </StyledPageContent>
  90. </PageFiltersContainer>
  91. </Fragment>
  92. );
  93. }
  94. const StyledPageHeader = styled(PageHeader)`
  95. background-color: ${p => p.theme.surface100};
  96. min-width: max-content;
  97. margin: ${space(3)} ${space(0)} ${space(4)} ${space(4)};
  98. `;
  99. const StyledPageContent = styled(PageContent)`
  100. box-shadow: 0px 0px 1px ${p => p.theme.gray200};
  101. background-color: ${p => p.theme.background};
  102. `;
  103. const HeaderTitle = styled(PageHeading)`
  104. display: flex;
  105. align-items: center;
  106. justify-content: space-between;
  107. flex: 1;
  108. `;
  109. export default Replays;