import {useMemo} from 'react'; import styled from '@emotion/styled'; import {PlatformIcon} from 'platformicons'; import Link from 'sentry/components/links/link'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {PlatformKey, Project} from 'sentry/types/project'; import {trackAnalytics} from 'sentry/utils/analytics'; import {generateProfileFlamechartRouteWithQuery} from 'sentry/utils/profiling/routes'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; import { isSpanNode, isTransactionNode, } from 'sentry/views/performance/newTraceDetails/guards'; import type { TraceTree, TraceTreeNode, } from 'sentry/views/performance/newTraceDetails/traceModels/traceTree'; export function TraceProfiles({ tree, onScrollToNode, }: { onScrollToNode: (node: TraceTreeNode) => void; tree: TraceTree; }) { const {projects} = useProjects(); const organization = useOrganization(); const projectLookup: Record = useMemo(() => { return projects.reduce>( (acc, project) => { acc[project.slug] = project.platform; return acc; }, {} ); }, [projects]); const profiles = useMemo( () => Array.from(tree.profiled_events.values()), [tree.profiled_events] ); return ( {t('Profiled Transaction')} {t('Profile')} {profiles.map((node, index) => { const link = generateProfileFlamechartRouteWithQuery({ orgSlug: organization.slug, projectSlug: node.metadata.project_slug as string, profileId: node.profiles?.[0].profile_id as string, }); const onClick = () => { trackAnalytics('profiling_views.go_to_flamegraph', { organization, source: 'performance.trace_view', }); }; if (isTransactionNode(node)) { return (
{node.profiles?.[0].profile_id?.substring(0, 8)}
); } if (isSpanNode(node)) { return (
{node.profiles?.[0].profile_id?.substring(0, 8)}
); } return null; })}
); } const ProfilesTable = styled('div')` margin-top: ${space(1)}; display: grid !important; grid-template-columns: 1fr min-content; grid-template-rows: auto; width: 100%; border: 1px solid ${p => p.theme.border}; border-radius: ${p => p.theme.borderRadius}; overflow: hidden; > div { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: ${space(0.5)} ${space(1)}; } img { width: 16px; height: 16px; margin-right: ${space(0.5)}; } `; const ProfilesTableRow = styled('div')` display: grid; grid-column: 1 / -1; grid-template-columns: subgrid; width: 100%; padding: ${space(0.5)}; padding: ${space(0.5)} ${space(2)}; & > div { padding: ${space(0.5)} ${space(1)}; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } &:first-child { background-color: ${p => p.theme.backgroundSecondary}; } &:not(:last-child) { border-bottom: 1px solid ${p => p.theme.border}; } `; const ProfilesTableTitle = styled('div')` color: ${p => p.theme.subText}; font-size: ${p => p.theme.fontSizeMedium}; font-weight: ${p => p.theme.fontWeightBold}; padding: 0 ${space(0.5)}; background-color: ${p => p.theme.backgroundSecondary}; `;