transactionToProfileButton.tsx 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import {useEffect, useState} from 'react';
  2. import * as Sentry from '@sentry/react';
  3. import {Client} from 'sentry/api';
  4. import Button from 'sentry/components/button';
  5. import {t} from 'sentry/locale';
  6. import {RequestState} from 'sentry/types/core';
  7. import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
  8. import {generateProfileFlamechartRoute} from 'sentry/utils/profiling/routes';
  9. import useApi from 'sentry/utils/useApi';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. interface Props {
  12. orgId: string;
  13. projectId: string;
  14. transactionId: string;
  15. }
  16. function TransactionToProfileButton({transactionId, orgId, projectId}: Props) {
  17. const api = useApi();
  18. const organization = useOrganization();
  19. const [profileIdState, setProfileIdState] = useState<RequestState<string>>({
  20. type: 'initial',
  21. });
  22. useEffect(() => {
  23. fetchProfileId(api, transactionId, orgId, projectId)
  24. .then((profileId: ProfileId) => {
  25. setProfileIdState({type: 'resolved', data: profileId.profile_id});
  26. })
  27. .catch(err => {
  28. // If there isn't a matching profile, we get a 404. No need to raise an error
  29. // in this case, but we should otherwise.
  30. if (err.status !== 404) {
  31. Sentry.captureException(err);
  32. }
  33. });
  34. }, [api, transactionId, orgId, projectId]);
  35. if (profileIdState.type !== 'resolved') {
  36. return null;
  37. }
  38. function handleGoToProfile() {
  39. trackAdvancedAnalyticsEvent('profiling_views.go_to_flamegraph', {
  40. organization,
  41. source: 'transaction_details',
  42. });
  43. }
  44. const target = generateProfileFlamechartRoute({
  45. orgSlug: orgId,
  46. projectSlug: projectId,
  47. profileId: profileIdState.data,
  48. });
  49. return (
  50. <Button onClick={handleGoToProfile} to={target}>
  51. {t('Go to Profile')}
  52. </Button>
  53. );
  54. }
  55. type ProfileId = {
  56. profile_id: string;
  57. };
  58. function fetchProfileId(
  59. api: Client,
  60. transactionId: string,
  61. orgId: string,
  62. projectId: string
  63. ): Promise<ProfileId> {
  64. return api.requestPromise(
  65. `/projects/${orgId}/${projectId}/profiling/transactions/${transactionId}/`,
  66. {
  67. method: 'GET',
  68. }
  69. );
  70. }
  71. export {TransactionToProfileButton};