import {Fragment} from 'react';
import type {Location} from 'history';
import IdBadge from 'sentry/components/idBadge';
import * as Layout from 'sentry/components/layouts/thirds';
import type {Organization} from 'sentry/types/organization';
import type {Project} from 'sentry/types/project';
import type {SpanSlug} from 'sentry/utils/performance/suspectSpans/types';
import useRouteAnalyticsEventNames from 'sentry/utils/routeAnalytics/useRouteAnalyticsEventNames';
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
import {useLocation} from 'sentry/utils/useLocation';
import {useParams} from 'sentry/utils/useParams';
import {useSpanMetrics} from 'sentry/views/insights/common/queries/useDiscover';
import {AiHeader} from 'sentry/views/insights/pages/ai/aiPageHeader';
import {BackendHeader} from 'sentry/views/insights/pages/backend/backendPageHeader';
import {FrontendHeader} from 'sentry/views/insights/pages/frontend/frontendPageHeader';
import {MobileHeader} from 'sentry/views/insights/pages/mobile/mobilePageHeader';
import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters';
import type {
SpanMetricsQueryFilters,
SpanMetricsResponse,
} from 'sentry/views/insights/types';
import Breadcrumb, {getTabCrumbs} from 'sentry/views/performance/breadcrumb';
import {SpanSummaryReferrer} from 'sentry/views/performance/transactionSummary/transactionSpans/spanSummary/referrers';
import SpanSummaryCharts from 'sentry/views/performance/transactionSummary/transactionSpans/spanSummary/spanSummaryCharts';
import SpanSummaryTable from 'sentry/views/performance/transactionSummary/transactionSpans/spanSummary/spanSummaryTable';
import {getSelectedProjectPlatforms} from 'sentry/views/performance/utils';
import Tab from '../../tabs';
import SpanSummaryControls from './spanSummaryControls';
import SpanSummaryHeader from './spanSummaryHeader';
type Props = {
organization: Organization;
project: Project | undefined;
spanSlug: SpanSlug;
transactionName: string;
};
export default function SpanSummary(props: Props) {
const {organization, project, transactionName, spanSlug} = props;
const location = useLocation();
const {isInDomainView, view} = useDomainViewFilters();
// customize the route analytics event we send
useRouteAnalyticsEventNames(
'performance_views.span_summary.view',
'Performance Views: Span Summary page viewed'
);
useRouteAnalyticsParams({
project_platforms: project ? getSelectedProjectPlatforms(location, [project]) : '',
});
const domainViewHeaderProps = {
headerTitle: (
{project && (
)}
{transactionName}
),
breadcrumbs: getTabCrumbs({
organization,
location,
transaction: {name: transactionName, project: project?.id ?? ''},
tab: Tab.SPANS,
spanSlug,
view,
}),
hideDefaultTabs: true,
};
return (
{!isInDomainView && (
{project && (
)}
{transactionName}
)}
{isInDomainView && view === 'frontend' && (
)}
{isInDomainView && view === 'backend' && (
)}
{isInDomainView && view === 'mobile' && }
{isInDomainView && view === 'ai' && }
);
}
type ContentProps = {
location: Location;
organization: Organization;
project: Project | undefined;
transactionName: string;
};
function SpanSummaryContent(props: ContentProps) {
const {transactionName, project} = props;
const {spanSlug: spanParam} = useParams();
const [spanOp, groupId] = spanParam.split(':');
const filters: SpanMetricsQueryFilters = {
'span.group': groupId,
'span.op': spanOp,
transaction: transactionName,
};
const {data: spanHeaderData} = useSpanMetrics(
{
search: MutableSearch.fromQueryObject(filters),
fields: ['span.description', 'sum(span.duration)', 'count()'],
sorts: [{field: 'sum(span.duration)', kind: 'desc'}],
},
SpanSummaryReferrer.SPAN_SUMMARY_HEADER_DATA
);
// Average span duration must be queried for separately, since it could get broken up into multiple groups if used in the first query
const {data: avgDurationData} = useSpanMetrics(
{
search: MutableSearch.fromQueryObject(filters),
fields: ['avg(span.duration)'],
},
SpanSummaryReferrer.SPAN_SUMMARY_HEADER_DATA
);
const parsedData = parseSpanHeaderData(spanHeaderData);
return (
);
}
function parseSpanHeaderData(data: Partial[]) {
if (!data || data.length === 0) {
return undefined;
}
if (data.length === 1) {
return {
description: data[0]?.['span.description'],
timeSpent: data[0]?.['sum(span.duration)'],
spanCount: data[0]?.['count()'],
};
}
const cumulativeData = {
description: undefined,
timeSpent: 0,
spanCount: 0,
};
data.forEach(datum => {
cumulativeData.timeSpent += datum['sum(span.self_time)'] ?? 0;
cumulativeData.spanCount += datum['count()'] ?? 0;
});
return cumulativeData;
}