import {type ReactNode, useMemo} from 'react'; import {ClassNames} from '@emotion/react'; import styled from '@emotion/styled'; import {Button, LinkButton} from 'sentry/components/button'; import {Hovercard} from 'sentry/components/hovercard'; import {platformsWithNestedInstrumentationGuides} from 'sentry/data/platformCategories'; import {IconOpen, IconQuestion} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {EventTransaction} from 'sentry/types/event'; import type {Project} from 'sentry/types/project'; import type {UseApiQueryResult} from 'sentry/utils/queryClient'; import type RequestError from 'sentry/utils/requestError/requestError'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import {traceAnalytics} from 'sentry/views/performance/newTraceDetails/traceAnalytics'; function Resource({ title, subtitle, link, }: { link: string; subtitle: ReactNode; title: string; }) { const organization = useOrganization(); return ( } borderless external href={link} onClick={() => { traceAnalytics.trackTraceConfigurationsDocsClicked(organization, title); }} > {title} {subtitle} ); } type ParsedPlatform = { platformName: string; framework?: string; }; function parsePlatform(platform: string): ParsedPlatform { // Except react-native, all other project platforms have the following two structures: // 1. "{language}-{framework}", e.g. "javascript-nextjs" // 2. "{language}", e.g. "python" const [platformName, framework] = platform === 'react-native' ? ['react-native', undefined] : platform.split('-'); return {platformName, framework}; } export function getCustomInstrumentationLink(project: Project | undefined): string { // Default to JavaScript guide if project or platform is not available if (!project || !project.platform) { return `https://docs.sentry.io/platforms/javascript/tracing/instrumentation/custom-instrumentation/`; } const {platformName, framework} = parsePlatform(project.platform); return platformsWithNestedInstrumentationGuides.includes(project.platform) && framework ? `https://docs.sentry.io/platforms/${platformName}/guides/${framework}/tracing/instrumentation/custom-instrumentation/` : `https://docs.sentry.io/platforms/${platformName}/tracing/instrumentation/custom-instrumentation/`; } function getDistributedTracingLink(project: Project | undefined): string { // Default to JavaScript guide if project or platform is not available if (!project || !project.platform) { return `https://docs.sentry.io/platforms/javascript/tracing/trace-propagation/`; } const {platformName, framework} = parsePlatform(project.platform); return framework ? `https://docs.sentry.io/platforms/${platformName}/guides/${framework}/tracing/trace-propagation/` : `https://docs.sentry.io/platforms/${platformName}/tracing/trace-propagation/`; } type ResourceButtonsProps = { customInstrumentationLink: string; distributedTracingLink: string; }; function ResourceButtons({ customInstrumentationLink, distributedTracingLink, }: ResourceButtonsProps) { return ( ); } type TraceConfigurationsProps = { rootEventResults: UseApiQueryResult; }; export default function TraceConfigurations({ rootEventResults, }: TraceConfigurationsProps) { const {projects} = useProjects(); const traceProject = useMemo(() => { return rootEventResults.data ? projects.find(p => p.id === rootEventResults.data.projectID) : undefined; }, [projects, rootEventResults.data]); const customInstrumentationLink = useMemo( () => getCustomInstrumentationLink(traceProject), [traceProject] ); const distributedTracingLink = useMemo( () => getDistributedTracingLink(traceProject), [traceProject] ); return ( {({css}) => ( } bodyClassName={css` padding: ${space(1)}; `} position="top-end" > )} ); } const ButtonContainer = styled('div')` display: flex; flex-direction: column; gap: ${space(1)}; align-items: flex-start; `; const ButtonContent = styled('div')` display: flex; flex-direction: column; text-align: left; white-space: pre-line; gap: ${space(0.25)}; `; const ButtonTitle = styled('div')` font-weight: ${p => p.theme.fontWeightNormal}; `; const ButtonSubtitle = styled('div')` color: ${p => p.theme.gray300}; font-weight: ${p => p.theme.fontWeightNormal}; font-size: ${p => p.theme.fontSizeSmall}; `; const StyledLinkButton = styled(LinkButton)` padding: ${space(1)}; height: auto; `;