import {Fragment, useCallback, useEffect, useState} from 'react'; import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import {loadDocs} from 'sentry/actionCreators/projects'; import Feature from 'sentry/components/acl/feature'; import {Alert} from 'sentry/components/alert'; import {Button} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import NotFound from 'sentry/components/errors/notFound'; import HookOrDefault from 'sentry/components/hookOrDefault'; import ExternalLink from 'sentry/components/links/externalLink'; import LoadingError from 'sentry/components/loadingError'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {DocumentationWrapper} from 'sentry/components/onboarding/documentationWrapper'; import {Footer} from 'sentry/components/onboarding/footer'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import { performance as performancePlatforms, Platform, PlatformKey, } from 'sentry/data/platformCategories'; import platforms from 'sentry/data/platforms'; import {IconChevron} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import ConfigStore from 'sentry/stores/configStore'; import {space} from 'sentry/styles/space'; import {Organization, Project} from 'sentry/types'; import useApi from 'sentry/utils/useApi'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import {normalizeUrl} from 'sentry/utils/withDomainRequired'; // in this case, the default is rendered inside the hook const SetUpSdkDoc = HookOrDefault({ hookName: 'component:set-up-sdk-doc', }); type Props = RouteComponentProps<{platform: string; projectId: string}, {}>; export function SetUpGeneralSdkDoc({ organization, projectSlug, platform, }: { organization: Organization; platform: Platform; projectSlug: Project['slug']; }) { const api = useApi(); const [loading, setLoading] = useState(true); const [error, setError] = useState(false); const [html, setHtml] = useState(''); const fetchDocs = useCallback(async () => { setLoading(true); try { const {html: reponse} = await loadDocs({ api, orgSlug: organization.slug, projectSlug, platform: platform.key as PlatformKey, }); setHtml(reponse); window.scrollTo(0, 0); } catch (err) { setError(err); } setLoading(false); }, [api, organization.slug, projectSlug, platform.key]); useEffect(() => { fetchDocs(); }, [fetchDocs]); return (
{tct( ` This is a quick getting started guide. For in-depth instructions on integrating Sentry with [platform], view [docLink:our complete documentation].`, { platform: platform.name, docLink: , } )} {loading ? ( ) : error ? ( ) : ( )}
); } export function ProjectInstallPlatform({location, params, route, router}: Props) { const organization = useOrganization(); const isSelfHosted = ConfigStore.get('isSelfHosted'); const {projects, initiallyLoaded} = useProjects({ slugs: [params.projectId], orgId: organization.slug, }); const loadingProjects = !initiallyLoaded; const project = !loadingProjects ? projects.find(proj => proj.slug === params.projectId) : undefined; const heartbeatFooter = !!organization?.features.includes( 'onboarding-heartbeat-footer' ); const currentPlatform = params.platform ?? 'other'; const platformIntegration = platforms.find(p => p.id === currentPlatform); const platform: Platform = { key: currentPlatform as PlatformKey, id: platformIntegration?.id, name: platformIntegration?.name, link: platformIntegration?.link, }; const redirectToNeutralDocs = useCallback(() => { if (!project?.slug) { return; } router.push( normalizeUrl( `/organizations/${organization.slug}/projects/${project.slug}/getting-started/` ) ); }, [organization.slug, project?.slug, router]); useEffect(() => { // redirect if platform is not known. if (!platform.key || platform.key === 'other') { redirectToNeutralDocs(); } }, [platform.key, redirectToNeutralDocs]); if (!platform.id) { return ; } const issueStreamLink = `/organizations/${organization.slug}/issues/`; const performanceOverviewLink = `/organizations/${organization.slug}/performance/`; const gettingStartedLink = `/organizations/${organization.slug}/projects/${params.projectId}/getting-started/`; const showPerformancePrompt = performancePlatforms.includes(platform.id as PlatformKey); const isGettingStarted = window.location.href.indexOf('getting-started') > 0; if (!project) { return null; } return (

{t('Configure %(platform)s SDK', {platform: platform.name})}

{isSelfHosted ? ( ) : ( )} {isGettingStarted && showPerformancePrompt && ( {({hasFeature}) => { if (hasFeature) { return null; } return ( {t( `Your selected platform supports performance, but your organization does not have performance enabled.` )} ); }} )} {isGettingStarted && heartbeatFooter ? (
); } const StyledButtonBar = styled(ButtonBar)` margin-top: ${space(3)}; width: max-content; @media (max-width: ${p => p.theme.breakpoints.small}) { width: auto; grid-row-gap: ${space(1)}; grid-auto-flow: row; } `; const StyledPageHeader = styled('div')` display: flex; justify-content: space-between; margin-bottom: ${space(3)}; h2 { margin: 0; } @media (max-width: ${p => p.theme.breakpoints.small}) { flex-direction: column; align-items: flex-start; h2 { margin-bottom: ${space(2)}; } } `; const StyledAlert = styled(Alert)` margin-top: ${space(2)}; `;