index.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import {Fragment, useEffect} from 'react';
  2. import {Location} from 'history';
  3. import Feature from 'sentry/components/acl/feature';
  4. import Alert from 'sentry/components/alert';
  5. import * as Layout from 'sentry/components/layouts/thirds';
  6. import LoadingIndicator from 'sentry/components/loadingIndicator';
  7. import {t} from 'sentry/locale';
  8. import {PageContent} from 'sentry/styles/organization';
  9. import type {Organization, Project} from 'sentry/types';
  10. import EventView from 'sentry/utils/discover/eventView';
  11. import {decodeScalar} from 'sentry/utils/queryString';
  12. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  13. import withOrganization from 'sentry/utils/withOrganization';
  14. import withProjects from 'sentry/utils/withProjects';
  15. import type {ReplayListLocationQuery} from 'sentry/views/replays/types';
  16. import PageLayout, {ChildProps} from '../pageLayout';
  17. import Tab from '../tabs';
  18. import ReplaysContent from './content';
  19. import useReplaysFromTransaction from './useReplaysFromTransaction';
  20. type Props = {
  21. location: Location<ReplayListLocationQuery>;
  22. organization: Organization;
  23. projects: Project[];
  24. };
  25. function renderNoAccess() {
  26. return (
  27. <PageContent>
  28. <Alert type="warning">{t("You don't have access to this feature")}</Alert>
  29. </PageContent>
  30. );
  31. }
  32. function TransactionReplays(props: Props) {
  33. const {location, organization, projects} = props;
  34. return (
  35. <Feature
  36. features={['session-replay-ui']}
  37. organization={organization}
  38. renderDisabled={renderNoAccess}
  39. >
  40. <PageLayout
  41. location={location}
  42. organization={organization}
  43. projects={projects}
  44. tab={Tab.Replays}
  45. getDocumentTitle={getDocumentTitle}
  46. generateEventView={generateEventView}
  47. childComponent={ReplaysContentWrapper}
  48. />
  49. </Feature>
  50. );
  51. }
  52. function ReplaysContentWrapper({
  53. eventView: eventsWithReplaysView,
  54. location,
  55. organization,
  56. setError,
  57. }: ChildProps) {
  58. const {eventView, replays, pageLinks, isFetching, fetchError} =
  59. useReplaysFromTransaction({
  60. eventsWithReplaysView,
  61. location,
  62. organization,
  63. });
  64. useEffect(() => {
  65. setError(fetchError?.message);
  66. }, [setError, fetchError]);
  67. if (isFetching || !eventView) {
  68. return (
  69. <Layout.Main fullWidth>
  70. <LoadingIndicator />
  71. </Layout.Main>
  72. );
  73. }
  74. return replays ? (
  75. <ReplaysContent
  76. eventView={eventView}
  77. isFetching={isFetching}
  78. location={location}
  79. organization={organization}
  80. pageLinks={pageLinks}
  81. replays={replays}
  82. />
  83. ) : (
  84. <Fragment>{null}</Fragment>
  85. );
  86. }
  87. function getDocumentTitle(transactionName: string): string {
  88. const hasTransactionName =
  89. typeof transactionName === 'string' && String(transactionName).trim().length > 0;
  90. if (hasTransactionName) {
  91. return [String(transactionName).trim(), t('Replays')].join(' \u2014 ');
  92. }
  93. return [t('Summary'), t('Replays')].join(' \u2014 ');
  94. }
  95. function generateEventView({
  96. location,
  97. transactionName,
  98. }: {
  99. location: Location;
  100. transactionName: string;
  101. }) {
  102. const query = decodeScalar(location.query.query, '');
  103. const conditions = new MutableSearch(query);
  104. conditions.addFilterValues('transaction', [transactionName]);
  105. conditions.addFilterValues('!replayId', ['']);
  106. return EventView.fromNewQueryWithLocation(
  107. {
  108. id: '',
  109. name: `Replay events within a transaction`,
  110. version: 2,
  111. fields: ['replayId', 'count()'],
  112. query: conditions.formatString(),
  113. projects: [],
  114. },
  115. location
  116. );
  117. }
  118. export default withProjects(withOrganization(TransactionReplays));