index.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {RouteComponentProps} from 'react-router';
  2. import styled from '@emotion/styled';
  3. import Feature from 'sentry/components/acl/feature';
  4. import NoProjectMessage from 'sentry/components/noProjectMessage';
  5. import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container';
  6. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  7. import {t} from 'sentry/locale';
  8. import {PageContent} from 'sentry/styles/organization';
  9. import {defined} from 'sentry/utils';
  10. import {decodeScalar} from 'sentry/utils/queryString';
  11. import useOrganization from 'sentry/utils/useOrganization';
  12. import useProjects from 'sentry/utils/useProjects';
  13. import {getTransactionName} from '../../../utils';
  14. import {NoAccess, redirectToPerformanceHomepage} from '../../pageLayout';
  15. import {generateSpansEventView, parseSpanSlug} from '../utils';
  16. import SpanDetailsContent from './content';
  17. type Props = Pick<RouteComponentProps<{spanSlug: string}, {}>, 'location' | 'params'>;
  18. export default function SpanDetails(props: Props) {
  19. const {location, params} = props;
  20. const transactionName = getTransactionName(location);
  21. const spanSlug = parseSpanSlug(params.spanSlug);
  22. const organization = useOrganization();
  23. const {projects} = useProjects();
  24. const projectId = decodeScalar(location.query.project);
  25. if (!defined(projectId) || !defined(transactionName) || !defined(spanSlug)) {
  26. redirectToPerformanceHomepage(organization, location);
  27. return null;
  28. }
  29. const project = projects.find(p => p.id === projectId);
  30. const eventView = generateSpansEventView({
  31. location,
  32. transactionName,
  33. });
  34. return (
  35. <SentryDocumentTitle
  36. title={getDocumentTitle(transactionName)}
  37. orgSlug={organization.slug}
  38. projectSlug={project?.slug}
  39. >
  40. <Feature
  41. features={['performance-view', 'performance-suspect-spans-view']}
  42. organization={organization}
  43. renderDisabled={NoAccess}
  44. >
  45. <PageFiltersContainer
  46. shouldForceProject={defined(project)}
  47. forceProject={project}
  48. specificProjectSlugs={defined(project) ? [project.slug] : []}
  49. >
  50. <StyledPageContent>
  51. <NoProjectMessage organization={organization}>
  52. <SpanDetailsContent
  53. location={location}
  54. organization={organization}
  55. eventView={eventView}
  56. project={project}
  57. transactionName={transactionName}
  58. spanSlug={spanSlug}
  59. />
  60. </NoProjectMessage>
  61. </StyledPageContent>
  62. </PageFiltersContainer>
  63. </Feature>
  64. </SentryDocumentTitle>
  65. );
  66. }
  67. function getDocumentTitle(transactionName: string): string {
  68. const hasTransactionName =
  69. typeof transactionName === 'string' && String(transactionName).trim().length > 0;
  70. if (hasTransactionName) {
  71. return [String(transactionName).trim(), t('Performance')].join(' - ');
  72. }
  73. return [t('Summary'), t('Performance')].join(' - ');
  74. }
  75. const StyledPageContent = styled(PageContent)`
  76. padding: 0;
  77. `;