platformIntegrationSetup.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import {Fragment, useEffect, useState} from 'react';
  2. import styled from '@emotion/styled';
  3. import {Button} from 'sentry/components/button';
  4. import ButtonBar from 'sentry/components/buttonBar';
  5. import LoadingError from 'sentry/components/loadingError';
  6. import LoadingIndicator from 'sentry/components/loadingIndicator';
  7. import {t} from 'sentry/locale';
  8. import {space} from 'sentry/styles/space';
  9. import type {IntegrationProvider} from 'sentry/types/integrations';
  10. import type {PlatformIntegration, Project} from 'sentry/types/project';
  11. import {trackAnalytics} from 'sentry/utils/analytics';
  12. import {useApiQuery} from 'sentry/utils/queryClient';
  13. import normalizeUrl from 'sentry/utils/url/normalizeUrl';
  14. import {useNavigate} from 'sentry/utils/useNavigate';
  15. import useOrganization from 'sentry/utils/useOrganization';
  16. import AddInstallationInstructions from 'sentry/views/onboarding/components/integrations/addInstallationInstructions';
  17. import PostInstallCodeSnippet from 'sentry/views/onboarding/components/integrations/postInstallCodeSnippet';
  18. import {PlatformDocHeader} from 'sentry/views/projectInstall/platformDocHeader';
  19. import {AddIntegrationButton} from 'sentry/views/settings/organizationIntegrations/addIntegrationButton';
  20. import FirstEventFooter from './components/firstEventFooter';
  21. interface PlatformIntegrationSetupProps {
  22. integrationSlug: string;
  23. loading: boolean;
  24. onClickManualSetup: () => void;
  25. platform: PlatformIntegration | undefined;
  26. project: Project | undefined;
  27. }
  28. export function PlatformIntegrationSetup({
  29. project,
  30. platform,
  31. onClickManualSetup,
  32. integrationSlug,
  33. loading,
  34. }: PlatformIntegrationSetupProps) {
  35. const organization = useOrganization();
  36. const [installed, setInstalled] = useState(false);
  37. const navigate = useNavigate();
  38. const {
  39. data: integrations,
  40. isPending,
  41. isError,
  42. refetch,
  43. } = useApiQuery<{providers: IntegrationProvider[]}>(
  44. [
  45. `/organizations/${organization.slug}/config/integrations/?provider_key=${integrationSlug}`,
  46. ],
  47. {
  48. enabled: !!integrationSlug,
  49. staleTime: 0,
  50. }
  51. );
  52. useEffect(() => {
  53. window.scrollTo(0, 0);
  54. // redirect if platform is not known.
  55. if ((!platform || platform.id === 'other') && !!project?.slug) {
  56. navigate(
  57. normalizeUrl(
  58. `/organizations/${organization.slug}/projects/${project.slug}/getting-started/`
  59. )
  60. );
  61. }
  62. }, [platform, organization.slug, navigate, project?.slug]);
  63. const isLoading = isPending || loading;
  64. if (isLoading) {
  65. return <LoadingIndicator />;
  66. }
  67. if (isError) {
  68. return <LoadingError onRetry={refetch} />;
  69. }
  70. const provider = integrations?.providers.length ? integrations.providers[0] : null;
  71. if (!provider || !platform || !project) {
  72. return null;
  73. }
  74. return (
  75. <OuterWrapper>
  76. <InnerWrapper>
  77. <PlatformDocHeader
  78. platform={{
  79. key: platform.id,
  80. id: platform.id,
  81. name: platform.name,
  82. link: platform.link,
  83. }}
  84. projectSlug={project.slug}
  85. title={t('Automatically instrument %s', platform.name)}
  86. />
  87. {!installed ? (
  88. <Fragment>
  89. <AddInstallationInstructions />
  90. <StyledButtonBar gap={1}>
  91. <AddIntegrationButton
  92. provider={provider}
  93. onAddIntegration={() => setInstalled(true)}
  94. organization={organization}
  95. priority="primary"
  96. size="sm"
  97. analyticsParams={{view: 'project_creation', already_installed: false}}
  98. modalParams={{projectId: project.id}}
  99. aria-label={t('Add integration')}
  100. />
  101. <Button
  102. size="sm"
  103. onClick={() => {
  104. onClickManualSetup();
  105. trackAnalytics('integrations.switch_manual_sdk_setup', {
  106. integration_type: 'first_party',
  107. integration: integrationSlug,
  108. view: 'project_creation',
  109. organization,
  110. });
  111. }}
  112. >
  113. {t('Manual Setup')}
  114. </Button>
  115. </StyledButtonBar>
  116. </Fragment>
  117. ) : (
  118. <Fragment>
  119. <PostInstallCodeSnippet provider={provider} />
  120. <FirstEventFooter
  121. project={project}
  122. organization={organization}
  123. docsLink={
  124. // TODO: make dynamic when adding more integrations
  125. 'https://docs.sentry.io/product/integrations/cloud-monitoring/aws-lambda/'
  126. }
  127. docsOnClick={() =>
  128. trackAnalytics('growth.onboarding_view_full_docs', {organization})
  129. }
  130. />
  131. </Fragment>
  132. )}
  133. </InnerWrapper>
  134. </OuterWrapper>
  135. );
  136. }
  137. const StyledButtonBar = styled(ButtonBar)`
  138. margin-top: ${space(3)};
  139. width: max-content;
  140. @media (max-width: ${p => p.theme.breakpoints.small}) {
  141. width: auto;
  142. grid-row-gap: ${space(1)};
  143. grid-auto-flow: row;
  144. }
  145. `;
  146. const InnerWrapper = styled('div')`
  147. max-width: 850px;
  148. `;
  149. const OuterWrapper = styled('div')`
  150. display: flex;
  151. flex-direction: column;
  152. align-items: center;
  153. margin-top: 50px;
  154. `;