profileGroupProvider.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {createContext, useContext, useEffect, useState} from 'react';
  2. import * as Sentry from '@sentry/react';
  3. import {Client} from 'sentry/api';
  4. import {ProfileHeader} from 'sentry/components/profiling/profileHeader';
  5. import {t} from 'sentry/locale';
  6. import {Organization, Project} from 'sentry/types';
  7. import {RequestState} from 'sentry/types/core';
  8. import {importProfile, ProfileGroup} from 'sentry/utils/profiling/profile/importProfile';
  9. import useApi from 'sentry/utils/useApi';
  10. import useOrganization from 'sentry/utils/useOrganization';
  11. import {useParams} from 'sentry/utils/useParams';
  12. function fetchFlamegraphs(
  13. api: Client,
  14. eventId: string,
  15. projectId: Project['id'],
  16. organization: Organization
  17. ): Promise<ProfileGroup> {
  18. return api
  19. .requestPromise(
  20. `/projects/${organization.slug}/${projectId}/profiling/profiles/${eventId}/`,
  21. {
  22. method: 'GET',
  23. includeAllArgs: true,
  24. }
  25. )
  26. .then(([data]) => importProfile(data, eventId));
  27. }
  28. interface FlamegraphViewProps {
  29. children: React.ReactNode;
  30. }
  31. const ProfileGroupContext = createContext<
  32. | [
  33. RequestState<ProfileGroup>,
  34. React.Dispatch<React.SetStateAction<RequestState<ProfileGroup>>>
  35. ]
  36. | null
  37. >(null);
  38. export const useProfileGroup = () => {
  39. const context = useContext(ProfileGroupContext);
  40. if (!context) {
  41. throw new Error('useProfileGroup was called outside of ProfileGroupProvider');
  42. }
  43. return context;
  44. };
  45. function ProfileGroupProvider(props: FlamegraphViewProps): React.ReactElement {
  46. const api = useApi();
  47. const organization = useOrganization();
  48. const params = useParams();
  49. const [profileGroupState, setProfileGroupState] = useState<RequestState<ProfileGroup>>({
  50. type: 'initial',
  51. });
  52. useEffect(() => {
  53. if (!params.eventId || !params.projectId) {
  54. return undefined;
  55. }
  56. setProfileGroupState({type: 'loading'});
  57. fetchFlamegraphs(api, params.eventId, params.projectId, organization)
  58. .then(importedFlamegraphs => {
  59. setProfileGroupState({type: 'resolved', data: importedFlamegraphs});
  60. })
  61. .catch(err => {
  62. const message = err.toString() || t('Error: Unable to load profiles');
  63. setProfileGroupState({type: 'errored', error: message});
  64. Sentry.captureException(err);
  65. });
  66. return () => {
  67. api.clear();
  68. };
  69. }, [params.eventId, params.projectId, api, organization]);
  70. return (
  71. <ProfileGroupContext.Provider value={[profileGroupState, setProfileGroupState]}>
  72. <ProfileHeader />
  73. {props.children}
  74. </ProfileGroupContext.Provider>
  75. );
  76. }
  77. export default ProfileGroupProvider;