import {Fragment, useMemo} from 'react'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {useReplayContext} from 'sentry/components/replays/replayContext'; import {Tooltip} from 'sentry/components/tooltip'; import {t, tn} from 'sentry/locale'; import type {EventTransaction} from 'sentry/types/event'; import type {Organization} from 'sentry/types/organization'; import getDuration from 'sentry/utils/duration/getDuration'; import type { TraceErrorOrIssue, TraceFullDetailed, TraceSplitResults, } from 'sentry/utils/performance/quickTrace/types'; import type {UseApiQueryResult} from 'sentry/utils/queryClient'; import type RequestError from 'sentry/utils/requestError/requestError'; import {useParams} from 'sentry/utils/useParams'; import {SpanTimeRenderer} from 'sentry/views/traces/fieldRenderers'; import {isTraceNode} from '../../../guards'; import type {TraceMetaQueryResults} from '../../../traceApi/useTraceMeta'; import type {TraceTree, TraceTreeNode} from '../../../traceModels/traceTree'; import {type SectionCardKeyValueList, TraceDrawerComponents} from '../../details/styles'; type GeneralInfoProps = { metaResults: TraceMetaQueryResults; node: TraceTreeNode; organization: Organization; rootEventResults: UseApiQueryResult; traces: TraceSplitResults | null; tree: TraceTree; }; export function GeneralInfo(props: GeneralInfoProps) { const params = useParams<{traceSlug?: string}>(); const {replay} = useReplayContext(); const traceNode = props.tree.root.children[0]; const uniqueErrorIssues = useMemo(() => { if (!traceNode) { return []; } const unique: TraceErrorOrIssue[] = []; const seenIssues: Set = new Set(); for (const issue of traceNode.errors) { if (seenIssues.has(issue.issue_id)) { continue; } seenIssues.add(issue.issue_id); unique.push(issue); } return unique; }, [traceNode]); const uniquePerformanceIssues = useMemo(() => { if (!traceNode) { return []; } const unique: TraceErrorOrIssue[] = []; const seenIssues: Set = new Set(); for (const issue of traceNode.performance_issues) { if (seenIssues.has(issue.issue_id)) { continue; } seenIssues.add(issue.issue_id); unique.push(issue); } return unique; }, [traceNode]); const uniqueIssuesCount = uniqueErrorIssues.length + uniquePerformanceIssues.length; const traceSlug = useMemo(() => { return params.traceSlug?.trim() ?? ''; }, [params.traceSlug]); const isLoading = useMemo(() => { return ( props.metaResults.isLoading || (props.rootEventResults.isPending && props.rootEventResults.fetchStatus !== 'idle') ); }, [ props.metaResults.isLoading, props.rootEventResults.isPending, props.rootEventResults.fetchStatus, ]); if (isLoading) { return ( , }, ]} title={t('General')} /> ); } if (!(traceNode && isTraceNode(traceNode))) { throw new Error('Expected a trace node'); } if ( props.traces?.transactions.length === 0 && props.traces.orphan_errors.length === 0 ) { return null; } const browser = props.rootEventResults?.data?.contexts?.browser; const items: SectionCardKeyValueList = []; // Hide trace_id inside replays because a replay could be connected to multiple traces. if (!replay) { items.push({ key: 'trace_id', subject: t('Trace ID'), value: , }); } items.push( { key: 'events', subject: t('Events'), value: props.metaResults.data ? props.metaResults.data.transactions + props.metaResults.data.errors : '\u2014', }, { key: 'issues', subject: t('Issues'), value: ( 0 ? (
{tn('%s error issue', '%s error issues', uniqueErrorIssues.length)}
{tn( '%s performance issue', '%s performance issues', uniquePerformanceIssues.length )}
) : null } showUnderline position="bottom" > {uniqueIssuesCount > 0 ? ( {uniqueIssuesCount} ) : uniqueIssuesCount === 0 ? ( 0 ) : ( '\u2014' )}
), }, { key: 'start_timestamp', subject: t('Start Timestamp'), value: traceNode.space?.[1] ? ( ) : ( '\u2014' ), }, { key: 'total_duration', subject: t('Total Duration'), value: traceNode.space?.[1] ? getDuration(traceNode.space[1] / 1000, 2, true) : '\u2014', }, { key: 'user', subject: t('User'), value: props.rootEventResults?.data?.user?.email ?? props.rootEventResults?.data?.user?.name ?? '\u2014', }, { key: 'browser', subject: t('Browser'), value: browser ? browser.name + ' ' + browser.version : '\u2014', } ); return ( ); }