profileHeader.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import {useCallback, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import * as Layout from 'sentry/components/layouts/thirds';
  5. import {
  6. ProfilingBreadcrumbs,
  7. ProfilingBreadcrumbsProps,
  8. } from 'sentry/components/profiling/profilingBreadcrumbs';
  9. import {t} from 'sentry/locale';
  10. import {space} from 'sentry/styles/space';
  11. import {Event} from 'sentry/types';
  12. import {trackAnalytics} from 'sentry/utils/analytics';
  13. import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
  14. import {isSchema, isSentrySampledProfile} from 'sentry/utils/profiling/guards/profile';
  15. import {useLocation} from 'sentry/utils/useLocation';
  16. import useOrganization from 'sentry/utils/useOrganization';
  17. import {useProfiles} from 'sentry/views/profiling/profilesProvider';
  18. function getTransactionName(input: Profiling.ProfileInput): string {
  19. if (isSchema(input)) {
  20. return input.metadata.transactionName;
  21. }
  22. if (isSentrySampledProfile(input)) {
  23. return input.transaction.name || t('Unknown Transaction');
  24. }
  25. return t('Unknown Transaction');
  26. }
  27. interface ProfileHeaderProps {
  28. eventId: string;
  29. projectId: string;
  30. transaction: Event | null;
  31. }
  32. function ProfileHeader({transaction, projectId, eventId}: ProfileHeaderProps) {
  33. const location = useLocation();
  34. const organization = useOrganization();
  35. const profiles = useProfiles();
  36. const transactionName =
  37. profiles.type === 'resolved' ? getTransactionName(profiles.data) : '';
  38. const profileId = eventId ?? '';
  39. const projectSlug = projectId ?? '';
  40. const transactionTarget = transaction?.id
  41. ? getTransactionDetailsUrl(organization.slug, `${projectSlug}:${transaction.id}`)
  42. : null;
  43. const handleGoToTransaction = useCallback(() => {
  44. trackAnalytics('profiling_views.go_to_transaction', {
  45. organization,
  46. source: 'transaction_details',
  47. });
  48. }, [organization]);
  49. const breadcrumbTrails: ProfilingBreadcrumbsProps['trails'] = useMemo(() => {
  50. return [
  51. {type: 'landing', payload: {query: location.query}},
  52. {
  53. type: 'profile summary',
  54. payload: {
  55. projectSlug,
  56. transaction: transactionName,
  57. query: location.query,
  58. },
  59. },
  60. {
  61. type: 'flamechart',
  62. payload: {
  63. transaction: transactionName,
  64. profileId,
  65. projectSlug,
  66. query: location.query,
  67. },
  68. },
  69. ];
  70. }, [location, projectSlug, transactionName, profileId]);
  71. return (
  72. <SmallerLayoutHeader>
  73. <SmallerHeaderContent>
  74. <SmallerProfilingBreadcrumbsWrapper>
  75. <ProfilingBreadcrumbs organization={organization} trails={breadcrumbTrails} />
  76. </SmallerProfilingBreadcrumbsWrapper>
  77. </SmallerHeaderContent>
  78. <Layout.HeaderActions>
  79. {transactionTarget && (
  80. <Button size="sm" onClick={handleGoToTransaction} to={transactionTarget}>
  81. {t('Go to Transaction')}
  82. </Button>
  83. )}
  84. </Layout.HeaderActions>
  85. </SmallerLayoutHeader>
  86. );
  87. }
  88. const SmallerHeaderContent = styled(Layout.HeaderContent)`
  89. margin-bottom: ${space(1.5)};
  90. `;
  91. const SmallerProfilingBreadcrumbsWrapper = styled('div')`
  92. nav {
  93. padding-bottom: ${space(1)};
  94. }
  95. `;
  96. const SmallerLayoutHeader = styled(Layout.Header)`
  97. padding: ${space(1)} ${space(2)} ${space(0)} ${space(2)} !important;
  98. `;
  99. export {ProfileHeader};