replays.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  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 Button from 'sentry/components/button';
  6. import * as Layout from 'sentry/components/layouts/thirds';
  7. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  8. import PageHeading from 'sentry/components/pageHeading';
  9. import Pagination from 'sentry/components/pagination';
  10. import ReplaysFeatureBadge from 'sentry/components/replays/replaysFeatureBadge';
  11. import {t} from 'sentry/locale';
  12. import {PageContent} from 'sentry/styles/organization';
  13. import EventView from 'sentry/utils/discover/eventView';
  14. import {decodeScalar} from 'sentry/utils/queryString';
  15. import {DEFAULT_SORT, REPLAY_LIST_FIELDS} from 'sentry/utils/replays/fetchReplayList';
  16. import useReplayList from 'sentry/utils/replays/hooks/useReplayList';
  17. import {useReplayOnboardingSidebarPanel} from 'sentry/utils/replays/hooks/useReplayOnboarding';
  18. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  19. import useMedia from 'sentry/utils/useMedia';
  20. import useOrganization from 'sentry/utils/useOrganization';
  21. import ReplaysFilters from 'sentry/views/replays/filters';
  22. import ReplayOnboardingPanel from 'sentry/views/replays/list/replayOnboardingPanel';
  23. import ReplayTable from 'sentry/views/replays/replayTable';
  24. import {ReplayColumns} from 'sentry/views/replays/replayTable/types';
  25. import type {ReplayListLocationQuery} from 'sentry/views/replays/types';
  26. type Props = RouteComponentProps<{orgId: string}, {}, any, ReplayListLocationQuery>;
  27. function Replays({location}: Props) {
  28. const organization = useOrganization();
  29. const theme = useTheme();
  30. const hasRoomForColumns = useMedia(`(min-width: ${theme.breakpoints.small})`);
  31. const eventView = useMemo(() => {
  32. const query = decodeScalar(location.query.query, '');
  33. const conditions = new MutableSearch(query);
  34. return EventView.fromNewQueryWithLocation(
  35. {
  36. id: '',
  37. name: '',
  38. version: 2,
  39. fields: REPLAY_LIST_FIELDS,
  40. projects: [],
  41. query: conditions.formatString(),
  42. orderby: decodeScalar(location.query.sort, DEFAULT_SORT),
  43. },
  44. location
  45. );
  46. }, [location]);
  47. const {replays, pageLinks, isFetching, fetchError} = useReplayList({
  48. eventView,
  49. location,
  50. organization,
  51. });
  52. const {hasSentOneReplay, activateSidebar} = useReplayOnboardingSidebarPanel();
  53. return (
  54. <Fragment>
  55. <Layout.Header>
  56. <StyledLayoutHeaderContent>
  57. <StyledHeading>
  58. {t('Replays')} <ReplaysFeatureBadge space={1} />
  59. </StyledHeading>
  60. </StyledLayoutHeaderContent>
  61. </Layout.Header>
  62. <PageFiltersContainer>
  63. <StyledPageContent>
  64. <ReplaysFilters />
  65. {hasSentOneReplay ? (
  66. <Fragment>
  67. <ReplayTable
  68. fetchError={fetchError}
  69. isFetching={isFetching}
  70. replays={replays}
  71. sort={eventView.sorts[0]}
  72. visibleColumns={[
  73. ReplayColumns.session,
  74. ...(hasRoomForColumns
  75. ? [ReplayColumns.projectId, ReplayColumns.startedAt]
  76. : []),
  77. ReplayColumns.duration,
  78. ReplayColumns.countErrors,
  79. ReplayColumns.activity,
  80. ]}
  81. />
  82. <Pagination
  83. pageLinks={pageLinks}
  84. onCursor={(cursor, path, searchQuery) => {
  85. browserHistory.push({
  86. pathname: path,
  87. query: {...searchQuery, cursor},
  88. });
  89. }}
  90. />
  91. </Fragment>
  92. ) : (
  93. <ReplayOnboardingPanel>
  94. <Button onClick={activateSidebar} priority="primary">
  95. {t('Get Started')}
  96. </Button>
  97. <Button
  98. href="https://docs.sentry.io/platforms/javascript/session-replay/"
  99. external
  100. >
  101. {t('Read Docs')}
  102. </Button>
  103. </ReplayOnboardingPanel>
  104. )}
  105. </StyledPageContent>
  106. </PageFiltersContainer>
  107. </Fragment>
  108. );
  109. }
  110. const StyledLayoutHeaderContent = styled(Layout.HeaderContent)`
  111. display: flex;
  112. justify-content: space-between;
  113. flex-direction: row;
  114. `;
  115. const StyledHeading = styled(PageHeading)`
  116. line-height: 40px;
  117. display: flex;
  118. `;
  119. const StyledPageContent = styled(PageContent)`
  120. box-shadow: 0px 0px 1px ${p => p.theme.gray200};
  121. background-color: ${p => p.theme.background};
  122. `;
  123. export default Replays;