diff --git a/static/app/components/events/interfaces/spans/newTraceDetailsSpanDetails.tsx b/static/app/components/events/interfaces/spans/newTraceDetailsSpanDetails.tsx index 6ebf779a1eaa8c..5a7767ef8fdc09 100644 --- a/static/app/components/events/interfaces/spans/newTraceDetailsSpanDetails.tsx +++ b/static/app/components/events/interfaces/spans/newTraceDetailsSpanDetails.tsx @@ -99,8 +99,8 @@ function NewTraceDetailsSpanDetail(props: SpanDetailProps) { const profileId = props.event.contexts.profile?.profile_id || ''; const issues = useMemo(() => { - return [...props.node.errors, ...props.node.occurences]; - }, [props.node.errors, props.node.occurences]); + return [...props.node.errors, ...props.node.occurrences]; + }, [props.node.errors, props.node.occurrences]); const {projects} = useProjects(); const project = projects.find(p => p.id === props.event.projectID); @@ -299,7 +299,7 @@ function NewTraceDetailsSpanDetail(props: SpanDetailProps) { } function renderSpanErrorMessage() { - const hasErrors = props.node.errors.size > 0 || props.node.occurences.size > 0; + const hasErrors = props.node.errors.size > 0 || props.node.occurrences.size > 0; if (!hasErrors || isGapSpan(props.node.value)) { return null; diff --git a/static/app/views/performance/newTraceDetails/issuesTraceWaterfall.tsx b/static/app/views/performance/newTraceDetails/issuesTraceWaterfall.tsx index 20a0c5d5508f93..b6981bfd7c19f0 100644 --- a/static/app/views/performance/newTraceDetails/issuesTraceWaterfall.tsx +++ b/static/app/views/performance/newTraceDetails/issuesTraceWaterfall.tsx @@ -189,15 +189,14 @@ export function IssuesTraceWaterfall(props: IssuesTraceWaterfallProps) { } } - for (const p of n.occurences) { - if (p.event_id === props.event.eventID) { + for (const o of n.occurrences) { + if (o.event_id === props.event.eventID) { return true; } } } - if (isSpanNode(n) || isEAPSpanNode(n)) { - const spanId = 'span_id' in n.value ? n.value.span_id : n.value.event_id; - if (spanId === props.event.eventID) { + if (isSpanNode(n)) { + if (n.value.span_id === props.event.eventID) { return true; } for (const e of n.errors) { @@ -205,8 +204,24 @@ export function IssuesTraceWaterfall(props: IssuesTraceWaterfallProps) { return true; } } - for (const p of n.occurences) { - if (p.event_id === props.event.eventID) { + for (const o of n.occurrences) { + if (o.event_id === props.event.eventID) { + return true; + } + } + } + + if (isEAPSpanNode(n)) { + if (n.value.event_id === props.event.eventID) { + return true; + } + for (const e of n.errors) { + if (e.event_id === props.event.eventID) { + return true; + } + } + for (const o of n.occurrences) { + if (o.event_id === props.event.occurrence?.id) { return true; } } @@ -232,7 +247,7 @@ export function IssuesTraceWaterfall(props: IssuesTraceWaterfallProps) { if ( isTraceErrorNode(props.tree.list[start]!) || node.errors.size > 0 || - node.occurences.size > 0 + node.occurrences.size > 0 ) { preserveNodes.push(props.tree.list[start]!); break; @@ -244,7 +259,7 @@ export function IssuesTraceWaterfall(props: IssuesTraceWaterfallProps) { if ( isTraceErrorNode(props.tree.list[start]!) || node.errors.size > 0 || - node.occurences.size > 0 + node.occurrences.size > 0 ) { preserveNodes.push(props.tree.list[start]!); break; diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/parentAutogroup.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/parentAutogroup.tsx index d8bd90f08b708c..7dae3dd80c652f 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/parentAutogroup.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/parentAutogroup.tsx @@ -22,8 +22,8 @@ export function ParentAutogroupNodeDetails({ }: TraceTreeNodeDetailsProps) { const theme = useTheme(); const issues = useMemo(() => { - return [...node.errors, ...node.occurences]; - }, [node.errors, node.occurences]); + return [...node.errors, ...node.occurrences]; + }, [node.errors, node.occurrences]); const parentTransaction = TraceTree.ParentTransaction(node); diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/siblingAutogroup.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/siblingAutogroup.tsx index 46d1ee98e5dc8e..c30dc943501cdf 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/siblingAutogroup.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/autogroup/siblingAutogroup.tsx @@ -22,8 +22,8 @@ export function SiblingAutogroupNodeDetails({ }: TraceTreeNodeDetailsProps) { const theme = useTheme(); const issues = useMemo(() => { - return [...node.errors, ...node.occurences]; - }, [node.errors, node.occurences]); + return [...node.errors, ...node.occurrences]; + }, [node.errors, node.occurrences]); const parentTransaction = TraceTree.ParentTransaction(node); diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/issues/issues.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/issues/issues.tsx index d134191ebda2bf..f17bc2eb9e83d5 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/issues/issues.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/issues/issues.tsx @@ -309,10 +309,10 @@ export function IssueList({issues, node, organization}: IssueListProps) { }, [node, node.errors.size]); const uniqueOccurences = useMemo(() => { - const unique: TraceTree.TraceOccurence[] = []; + const unique: TraceTree.TraceOccurrence[] = []; const seenIssues: Set = new Set(); - for (const issue of node.occurences) { + for (const issue of node.occurrences) { if (seenIssues.has(issue.issue_id)) { continue; } @@ -323,7 +323,7 @@ export function IssueList({issues, node, organization}: IssueListProps) { return unique; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [node, node.occurences.size]); + }, [node, node.occurrences.size]); const uniqueIssues = useMemo(() => { return [...uniqueOccurences, ...uniqueErrorIssues.sort(sortIssuesByLevel)]; @@ -384,7 +384,7 @@ function IssueListHeader({ }: { errorIssues: TraceTree.TraceErrorIssue[]; node: TraceTreeNode; - occurences: TraceTree.TraceOccurence[]; + occurences: TraceTree.TraceOccurrence[]; }) { const [singular, plural] = useMemo((): [string, string] => { const label = [t('Issue'), t('Issues')] as [string, string]; diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx index 141fbb7382f526..78746b55c9935c 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/span/index.tsx @@ -281,8 +281,8 @@ export function SpanNodeDetails({ const hasNewTraceUi = useHasTraceNewUi(); const {projects} = useProjects(); const issues = useMemo(() => { - return [...node.errors, ...node.occurences]; - }, [node.errors, node.occurences]); + return [...node.errors, ...node.occurrences]; + }, [node.errors, node.occurrences]); const project = projects.find(proj => proj.slug === node.event?.projectSlug); const profileMeta = getProfileMeta(node.event) || ''; diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/index.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/index.tsx index 3b78d0d2d6d418..b57611794759f8 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/index.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/details/transaction/index.tsx @@ -149,8 +149,8 @@ export function TransactionNodeDetails({ }: TraceTreeNodeDetailsProps>) { const {projects} = useProjects(); const issues = useMemo(() => { - return [...node.errors, ...node.occurences]; - }, [node.errors, node.occurences]); + return [...node.errors, ...node.occurrences]; + }, [node.errors, node.occurrences]); const { data: event, isError, diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/generalInfo.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/generalInfo.tsx index 056b6d43e2e3b8..78b1d2de0b545c 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/generalInfo.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/generalInfo.tsx @@ -58,10 +58,10 @@ export function GeneralInfo(props: GeneralInfoProps) { return []; } - const unique: TraceTree.TraceOccurence[] = []; + const unique: TraceTree.TraceOccurrence[] = []; const seenIssues: Set = new Set(); - for (const issue of traceNode.occurences) { + for (const issue of traceNode.occurrences) { if (seenIssues.has(issue.issue_id)) { continue; } diff --git a/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/index.tsx b/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/index.tsx index 5c9ed0e1262a40..4086dc9ced24e3 100644 --- a/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/index.tsx +++ b/static/app/views/performance/newTraceDetails/traceDrawer/tabs/trace/index.tsx @@ -46,10 +46,10 @@ export function TraceDetails(props: TraceDetailsProps) { return []; } - return [...props.node.errors, ...props.node.occurences]; + return [...props.node.errors, ...props.node.occurrences]; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.node, props.node?.errors.size, props.node?.occurences.size]); + }, [props.node, props.node?.errors.size, props.node?.occurrences.size]); if (!props.node) { return null; diff --git a/static/app/views/performance/newTraceDetails/traceGuards.tsx b/static/app/views/performance/newTraceDetails/traceGuards.tsx index 02ef5d3cc311e0..573c6286e7f576 100644 --- a/static/app/views/performance/newTraceDetails/traceGuards.tsx +++ b/static/app/views/performance/newTraceDetails/traceGuards.tsx @@ -209,6 +209,6 @@ export function getPageloadTransactionChildCount( export function isTraceOccurence( issue: TraceTree.TraceIssue -): issue is TraceTree.TraceOccurence { +): issue is TraceTree.TraceOccurrence { return 'issue_id' in issue && issue.event_type !== 'error'; } diff --git a/static/app/views/performance/newTraceDetails/traceHeader/meta.tsx b/static/app/views/performance/newTraceDetails/traceHeader/meta.tsx index cad5c7d25cd4b1..b43e10afb1b1eb 100644 --- a/static/app/views/performance/newTraceDetails/traceHeader/meta.tsx +++ b/static/app/views/performance/newTraceDetails/traceHeader/meta.tsx @@ -101,10 +101,10 @@ export function Meta(props: MetaProps) { return []; } - const unique: TraceTree.TraceOccurence[] = []; + const unique: TraceTree.TraceOccurrence[] = []; const seenIssues: Set = new Set(); - for (const issue of traceNode.occurences) { + for (const issue of traceNode.occurrences) { if (seenIssues.has(issue.issue_id)) { continue; } diff --git a/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.spec.tsx b/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.spec.tsx index 55e9f353fbcfe2..3aff618689440f 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.spec.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.spec.tsx @@ -62,7 +62,8 @@ function mockSpansResponse( function hasErrors(n: TraceTreeNode): boolean { return ( - (isTraceErrorNode(n) || n.errors.size > 0 || n.occurences.size > 0) && !isTraceNode(n) + (isTraceErrorNode(n) || n.errors.size > 0 || n.occurrences.size > 0) && + !isTraceNode(n) ); } diff --git a/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.tsx b/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.tsx index 28203eaef48a44..523c7cbcef2967 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/issuesTraceTree.tsx @@ -1,4 +1,5 @@ import type {Client} from 'sentry/api'; +import type {Event} from 'sentry/types/event'; import type {Organization} from 'sentry/types/organization'; import type {TraceMetaQueryResults} from 'sentry/views/performance/newTraceDetails/traceApi/useTraceMeta'; import { @@ -55,7 +56,7 @@ export class IssuesTraceTree extends TraceTree { static ExpandToEvent( tree: IssuesTraceTree, - eventId: string, + event: Event, options: { api: Client; organization: Organization; @@ -64,21 +65,25 @@ export class IssuesTraceTree extends TraceTree { ): Promise { const node = TraceTree.Find(tree.root, n => { if (isTraceErrorNode(n) || isEAPErrorNode(n)) { - return n.value.event_id === eventId; + return n.value.event_id === event.eventID; } if (isTransactionNode(n) || isEAPSpanNode(n)) { - if (n.value.event_id === eventId) { + if (n.value.event_id === event.eventID) { return true; } for (const e of n.errors) { - if (e.event_id === eventId) { + if (e.event_id === event.eventID) { return true; } } - for (const p of n.occurences) { - if (p.event_id === eventId) { + for (const o of n.occurrences) { + if (isTransactionNode(n)) { + if (o.event_id === event.eventID) { + return true; + } + } else if (o.event_id === event.occurrence?.id) { return true; } } diff --git a/static/app/views/performance/newTraceDetails/traceModels/traceTree.spec.tsx b/static/app/views/performance/newTraceDetails/traceModels/traceTree.spec.tsx index b0eb6e469483b8..fac1b9f311544a 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/traceTree.spec.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/traceTree.spec.tsx @@ -19,6 +19,7 @@ import { assertEAPSpanNode, assertTransactionNode, makeEAPError, + makeEAPOccurrence, makeEAPSpan, makeEAPTrace, makeEventTransaction, @@ -188,6 +189,21 @@ const eapTraceWithErrors = makeEAPTrace([ }), ]); +const eapTraceWithOccurences = makeEAPTrace([ + makeEAPSpan({ + event_id: 'eap-span-1', + is_transaction: true, + occurrences: [], + children: [ + makeEAPSpan({ + event_id: 'eap-span-2', + is_transaction: false, + occurrences: [makeEAPOccurrence({event_id: 'eap-occurence-1'})], + }), + ], + }), +]); + const eapTraceWithOrphanErrors = makeEAPTrace([ makeEAPError({ event_id: 'eap-error-1', @@ -252,7 +268,7 @@ describe('TraceTree', () => { }), traceMetadata ); - expect(tree.root.children[0]!.children[0]!.occurences.size).toBe(1); + expect(tree.root.children[0]!.children[0]!.occurrences.size).toBe(1); }); it('adds transaction profile to node', () => { @@ -584,6 +600,18 @@ describe('TraceTree', () => { expect(eapSpan?.errors.size).toBe(1); }); + it('adds eap occurences to tree nodes', () => { + const tree = TraceTree.FromTrace(eapTraceWithOccurences, traceMetadata); + + expect(tree.root.children[0]!.occurrences.size).toBe(1); + + const eapTransaction = findEAPSpanByEventId(tree, 'eap-span-1'); + const eapSpan = findEAPSpanByEventId(tree, 'eap-span-2'); + + expect(eapTransaction?.occurrences.size).toBe(1); + expect(eapSpan?.occurrences.size).toBe(1); + }); + it('initializes expanded based on is_transaction property', () => { const tree = TraceTree.FromTrace( makeEAPTrace([ diff --git a/static/app/views/performance/newTraceDetails/traceModels/traceTree.tsx b/static/app/views/performance/newTraceDetails/traceModels/traceTree.tsx index 0929c7cc8fc926..6b46e976eb8982 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/traceTree.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/traceTree.tsx @@ -130,7 +130,19 @@ export declare namespace TraceTree { type EAPError = { event_id: string; - event_type: string; + event_type: 'error'; + issue_id: number; + level: Level; + project_id: number; + project_slug: string; + start_timestamp: number; + transaction: string; + description?: string; + }; + + type EAPOccurrence = { + event_id: string; + event_type: 'occurrence'; issue_id: number; level: Level; project_id: number; @@ -147,6 +159,7 @@ export declare namespace TraceTree { errors: EAPError[]; event_id: string; is_transaction: boolean; + occurrences: EAPOccurrence[]; op: string; parent_span_id: string; project_id: number; @@ -176,9 +189,10 @@ export declare namespace TraceTree { type TraceError = TraceErrorType; type TraceErrorIssue = TraceError | EAPError; - type TraceOccurence = TracePerformanceIssueType; + type TracePerformanceIssue = TracePerformanceIssueType; + type TraceOccurrence = TracePerformanceIssue | EAPOccurrence; - type TraceIssue = TraceErrorIssue | TraceOccurence; + type TraceIssue = TraceErrorIssue | TraceOccurrence; type Profile = {profile_id: string} | {profiler_id: string}; type Project = { @@ -428,11 +442,22 @@ export class TraceTree extends TraceTreeEventDispatcher { closestEAPTransaction.errors.add(error); } } - } - if (isTransactionNode(c)) { - for (const performanceIssue of c.value.performance_issues) { - traceNode.occurences.add(performanceIssue); + let occurences: TraceTree.TraceOccurrence[] = []; + if ('performance_issues' in c.value) { + occurences = c.value.performance_issues; + } else if ('occurrences' in c.value) { + occurences = c.value.occurrences as TraceTree.TraceOccurrence[]; + } + + for (const occurence of occurences) { + traceNode.occurrences.add(occurence); + + // Propagate occurences to the closest EAP transaction for visibility in the initially collapsed + // eap-transactions only view, on load + if (closestEAPTransaction) { + closestEAPTransaction.occurrences.add(occurence); + } } } @@ -603,7 +628,7 @@ export class TraceTree extends TraceTreeEventDispatcher { c.value, node )) { - c.occurences.add(performanceIssue); + c.occurrences.add(performanceIssue); } for (const error of getRelatedSpanErrorsFromTransaction(c.value, node)) { c.errors.add(error); @@ -652,8 +677,8 @@ export class TraceTree extends TraceTreeEventDispatcher { baseTraceNode.errors.add(error); } - for (const occurence of additionalTraceNode.occurences) { - baseTraceNode.occurences.add(occurence); + for (const occurence of additionalTraceNode.occurrences) { + baseTraceNode.occurrences.add(occurence); } for (const profile of additionalTraceNode.profiles) { @@ -827,7 +852,7 @@ export class TraceTree extends TraceTreeEventDispatcher { let groupMatchCount = 0; let errors: TraceTree.TraceErrorIssue[] = []; - let occurences: TraceTree.TraceOccurence[] = []; + let occurences: TraceTree.TraceOccurrence[] = []; let start = head.space[0]; let end = head.space[0] + head.space[1]; @@ -844,7 +869,7 @@ export class TraceTree extends TraceTreeEventDispatcher { end = Math.max(end, tail.space[0] + tail.space[1]); errors = errors.concat(Array.from(tail.errors)); - occurences = occurences.concat(Array.from(tail.occurences)); + occurences = occurences.concat(Array.from(tail.occurrences)); groupMatchCount++; tail = tail.children[0]; @@ -894,14 +919,14 @@ export class TraceTree extends TraceTreeEventDispatcher { // Checking the tail node for errors as it is not included in the grouping // while loop, but is hidden when the autogrouped node is collapsed errors = errors.concat(Array.from(tail.errors)); - occurences = occurences.concat(Array.from(tail.occurences)); + occurences = occurences.concat(Array.from(tail.occurrences)); start = Math.min(start, tail.space[0]); end = Math.max(end, tail.space[0] + tail.space[1]); autoGroupedNode.space = [start, end - start]; autoGroupedNode.errors = new Set(errors); - autoGroupedNode.occurences = new Set(occurences); + autoGroupedNode.occurrences = new Set(occurences); for (const c of tail.children) { c.parent = autoGroupedNode; @@ -1032,8 +1057,8 @@ export class TraceTree extends TraceTreeEventDispatcher { autoGroupedNode.errors.add(error); } - for (const occurence of child.occurences) { - autoGroupedNode.occurences.add(occurence); + for (const occurence of child.occurrences) { + autoGroupedNode.occurrences.add(occurence); } } @@ -1336,8 +1361,8 @@ export class TraceTree extends TraceTreeEventDispatcher { return true; } } - for (const p of n.occurences) { - if (p.event_id === eventId) { + for (const o of n.occurrences) { + if (o.event_id === eventId) { return true; } } @@ -1354,17 +1379,12 @@ export class TraceTree extends TraceTreeEventDispatcher { return true; } } - for (const p of n.occurences) { - if (p.event_id === eventId) { + for (const o of n.occurrences) { + if (o.event_id === eventId) { return true; } } } - if (isEAPSpanNode(n)) { - if (n.value.event_id === eventId) { - return true; - } - } if (isTraceErrorNode(n) || isEAPErrorNode(n)) { return n.value.event_id === eventId; } @@ -2292,12 +2312,12 @@ function getRelatedSpanErrorsFromTransaction( function getRelatedPerformanceIssuesFromTransaction( span: TraceTree.Span, node: TraceTreeNode -): TraceTree.TraceOccurence[] { +): TraceTree.TraceOccurrence[] { if (!isTransactionNode(node) || !node.value?.performance_issues?.length) { return []; } - const occurences: TraceTree.TraceOccurence[] = []; + const occurences: TraceTree.TraceOccurrence[] = []; for (const perfIssue of node.value.performance_issues) { for (const s of perfIssue.span) { diff --git a/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.spec.tsx b/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.spec.tsx index e55cdaa472d4ff..eb2fa8ca747ae9 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.spec.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.spec.tsx @@ -39,7 +39,7 @@ describe('TraceTreeNode', () => { }), metadata ); - expect(node.occurences.has(issue)).toBe(true); + expect(node.occurrences.has(issue)).toBe(true); }); it('stores error on node', () => { diff --git a/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.tsx b/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.tsx index 69ed73f32611b4..8496bf6f92c103 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/traceTreeNode.tsx @@ -69,7 +69,7 @@ export class TraceTreeNode // Events associated with the node, these are inferred from the node value. errors = new Set(); - occurences = new Set(); + occurrences = new Set(); profiles: TraceTree.Profile[] = []; space: [number, number] = [0, 0]; @@ -114,7 +114,12 @@ export class TraceTreeNode } if ('performance_issues' in value && Array.isArray(value.performance_issues)) { - value.performance_issues.forEach(issue => this.occurences.add(issue)); + value.performance_issues.forEach(issue => this.occurrences.add(issue)); + } + + // EAP spans can have occurences + if ('occurrences' in value && Array.isArray(value.occurrences)) { + value.occurrences.forEach(occurence => this.occurrences.add(occurence)); } if ('profile_id' in value && typeof value.profile_id === 'string') { @@ -138,7 +143,7 @@ export class TraceTreeNode } get hasErrors(): boolean { - return this.errors.size > 0 || this.occurences.size > 0; + return this.errors.size > 0 || this.occurrences.size > 0; } private _max_severity: keyof Theme['level'] | undefined; diff --git a/static/app/views/performance/newTraceDetails/traceModels/traceTreeTestUtils.tsx b/static/app/views/performance/newTraceDetails/traceModels/traceTreeTestUtils.tsx index b9850476b1a45a..d09135f1b44674 100644 --- a/static/app/views/performance/newTraceDetails/traceModels/traceTreeTestUtils.tsx +++ b/static/app/views/performance/newTraceDetails/traceModels/traceTreeTestUtils.tsx @@ -1,11 +1,7 @@ import {uuid4} from '@sentry/core'; import {EntryType, type Event, type EventTransaction} from 'sentry/types/event'; -import type { - TracePerformanceIssue, - TraceSplitResults, -} from 'sentry/utils/performance/quickTrace/types'; -import type {TraceMetaQueryResults} from 'sentry/views/performance/newTraceDetails/traceApi/useTraceMeta'; +import type {TraceSplitResults} from 'sentry/utils/performance/quickTrace/types'; import { isAutogroupedNode, isEAPSpanNode, @@ -16,6 +12,8 @@ import { isTransactionNode, } from 'sentry/views/performance/newTraceDetails/traceGuards'; +import type {TraceMetaQueryResults} from '../traceApi/useTraceMeta'; + import {ParentAutogroupNode} from './parentAutogroupNode'; import {SiblingAutogroupNode} from './siblingAutogroupNode'; import type {TraceTree} from './traceTree'; @@ -129,6 +127,23 @@ export function makeEAPError( } as TraceTree.EAPError; } +export function makeEAPOccurrence( + overrides: Partial = {} +): TraceTree.EAPOccurrence { + return { + event_id: overrides.event_id ?? uuid4(), + description: 'Test Occurence', + start_timestamp: 0, + project_id: 1, + project_slug: 'project_slug', + transaction: 'occurence.transaction', + event_type: 'occurrence', + issue_id: 1, + level: 'info', + ...overrides, + }; +} + export function makeTraceError( overrides: Partial = {} ): TraceTree.TraceError { @@ -143,8 +158,8 @@ export function makeTraceError( } export function makeTracePerformanceIssue( - overrides: Partial = {} -): TracePerformanceIssue { + overrides: Partial = {} +): TraceTree.TracePerformanceIssue { return { culprit: 'code', end: new Date().toISOString(), @@ -154,7 +169,7 @@ export function makeTracePerformanceIssue( type: 0, issue_short_id: 'issue short id', ...overrides, - } as TracePerformanceIssue; + } as TraceTree.TracePerformanceIssue; } export function makeTraceMetaQueryResults( diff --git a/static/app/views/performance/newTraceDetails/traceRenderers/virtualizedViewManager.tsx b/static/app/views/performance/newTraceDetails/traceRenderers/virtualizedViewManager.tsx index c9ed4017a41565..dad7b7dab4194a 100644 --- a/static/app/views/performance/newTraceDetails/traceRenderers/virtualizedViewManager.tsx +++ b/static/app/views/performance/newTraceDetails/traceRenderers/virtualizedViewManager.tsx @@ -1695,15 +1695,23 @@ function getIconTimestamps( let min_icon_timestamp = span_space[0]; let max_icon_timestamp = span_space[0] + span_space[1]; - if (!node.errors.size && !node.occurences.size) { + if (!node.errors.size && !node.occurrences.size) { return [min_icon_timestamp, max_icon_timestamp]; } - for (const issue of node.occurences) { - // Perf issues render icons at the start timestamp - if (typeof issue.start === 'number') { - min_icon_timestamp = Math.min(min_icon_timestamp, issue.start * 1e3 - icon_width); - max_icon_timestamp = Math.max(max_icon_timestamp, issue.start * 1e3 + icon_width); + for (const occurence of node.occurrences) { + // Occurences render icons at the start timestamp + const start_timestamp = + 'start_timestamp' in occurence ? occurence.start_timestamp : occurence.start; + if (typeof start_timestamp === 'number') { + min_icon_timestamp = Math.min( + min_icon_timestamp, + start_timestamp * 1e3 - icon_width + ); + max_icon_timestamp = Math.max( + max_icon_timestamp, + start_timestamp * 1e3 + icon_width + ); } } diff --git a/static/app/views/performance/newTraceDetails/traceRow/traceAutogroupedRow.tsx b/static/app/views/performance/newTraceDetails/traceRow/traceAutogroupedRow.tsx index 40d1b7b6d43690..7fa05fc932a8f4 100644 --- a/static/app/views/performance/newTraceDetails/traceRow/traceAutogroupedRow.tsx +++ b/static/app/views/performance/newTraceDetails/traceRow/traceAutogroupedRow.tsx @@ -70,7 +70,7 @@ export function TraceAutogroupedRow( virtualized_index={props.virtualized_index} color={makeTraceNodeBarColor(props.theme, props.node)} node_spaces={props.node.autogroupedSegments} - occurences={props.node.occurences} + occurrences={props.node.occurrences} profiles={props.node.profiles} />