@@ -15,32 +15,32 @@ import {useLocation} from 'sentry/utils/useLocation';
15
15
import useOrganization from 'sentry/utils/useOrganization' ;
16
16
import { useTrace } from 'sentry/views/performance/newTraceDetails/traceApi/useTrace' ;
17
17
import { isEmptyTrace } from 'sentry/views/performance/newTraceDetails/traceApi/utils' ;
18
+ import { useFindNextTrace } from 'sentry/views/performance/newTraceDetails/traceLinksNavigation/useFindNextTrace' ;
18
19
import { getTraceDetailsUrl } from 'sentry/views/performance/traceDetails/utils' ;
19
20
20
- // Currently, we only support previous but component can be used for 'next trace' in the future
21
- type ConnectedTraceConnection = 'previous' ; // | 'next';
21
+ export type ConnectedTraceConnection = 'previous' | 'next' ;
22
22
23
23
const LINKED_TRACE_MAX_DURATION = 3600 ; // 1h in seconds
24
24
25
25
function useIsTraceAvailable (
26
- traceLink ?: SpanLink ,
27
- previousTraceTimestamp ?: number
26
+ traceID ?: SpanLink [ 'trace_id' ] ,
27
+ linkedTraceTimestamp ?: number
28
28
) : {
29
29
isAvailable : boolean ;
30
30
isLoading : boolean ;
31
31
} {
32
32
const trace = useTrace ( {
33
- traceSlug : traceLink ?. trace_id ,
34
- timestamp : previousTraceTimestamp ,
33
+ traceSlug : traceID ,
34
+ timestamp : linkedTraceTimestamp ,
35
35
} ) ;
36
36
37
37
const isAvailable = useMemo ( ( ) => {
38
- if ( ! traceLink ) {
38
+ if ( ! traceID ) {
39
39
return false ;
40
40
}
41
41
42
42
return Boolean ( trace . data && ! isEmptyTrace ( trace . data ) ) ;
43
- } , [ traceLink , trace ] ) ;
43
+ } , [ traceID , trace ] ) ;
44
44
45
45
return {
46
46
isAvailable,
@@ -52,37 +52,47 @@ type TraceLinkNavigationButtonProps = {
52
52
currentTraceTimestamps : { end ?: number ; start ?: number } ;
53
53
direction : ConnectedTraceConnection ;
54
54
isLoading ?: boolean ;
55
+ projectID ?: string ;
55
56
traceContext ?: TraceContextType ;
56
57
} ;
57
58
58
59
export function TraceLinkNavigationButton ( {
59
60
direction,
60
61
traceContext,
61
62
isLoading,
63
+ projectID,
62
64
currentTraceTimestamps,
63
65
} : TraceLinkNavigationButtonProps ) {
64
66
const organization = useOrganization ( ) ;
65
67
const location = useLocation ( ) ;
66
68
67
- const traceLink = traceContext ?. links ?. find (
68
- link => link . attributes ?. [ 'sentry.link.type' ] === `${ direction } _trace`
69
- ) ;
70
-
71
69
// We connect traces over a 1h period - As we don't have timestamps of the linked trace, it is calculated based on this timeframe
72
70
const linkedTraceTimestamp =
73
71
direction === 'previous' && currentTraceTimestamps . start
74
- ? currentTraceTimestamps . start - LINKED_TRACE_MAX_DURATION // Earliest start times of previous trace
75
- : // : direction === 'next' && currentTraceTimestamps.end
76
- // ? currentTraceTimestamps.end + LINKED_TRACE_MAX_DURATION
77
- undefined ;
72
+ ? currentTraceTimestamps . start - LINKED_TRACE_MAX_DURATION // Earliest start time of previous trace (- 1h)
73
+ : direction === 'next' && currentTraceTimestamps . end
74
+ ? currentTraceTimestamps . end + LINKED_TRACE_MAX_DURATION // Latest end time of next trace (+ 1h)
75
+ : undefined ;
76
+
77
+ const previousTraceLink = traceContext ?. links ?. find (
78
+ link => link . attributes ?. [ 'sentry.link.type' ] === `${ direction } _trace`
79
+ ) ;
80
+
81
+ const nextTraceData = useFindNextTrace ( {
82
+ direction,
83
+ currentTraceID : traceContext ?. trace_id ,
84
+ linkedTraceStartTimestamp : currentTraceTimestamps . end ,
85
+ linkedTraceEndTimestamp : linkedTraceTimestamp ,
86
+ projectID,
87
+ } ) ;
78
88
79
89
const dateSelection = useMemo (
80
90
( ) => normalizeDateTimeParams ( location . query ) ,
81
91
[ location . query ]
82
92
) ;
83
93
84
94
const { isAvailable : isLinkedTraceAvailable } = useIsTraceAvailable (
85
- traceLink ,
95
+ direction === 'previous' ? previousTraceLink ?. trace_id : nextTraceData ?. trace_id ,
86
96
linkedTraceTimestamp
87
97
) ;
88
98
@@ -92,13 +102,13 @@ export function TraceLinkNavigationButton({
92
102
return null ;
93
103
}
94
104
95
- if ( traceLink && isLinkedTraceAvailable ) {
105
+ if ( previousTraceLink && isLinkedTraceAvailable ) {
96
106
return (
97
107
< TraceLink
98
108
color = "gray500"
99
109
to = { getTraceDetailsUrl ( {
100
- traceSlug : traceLink . trace_id ,
101
- spanId : traceLink . span_id ,
110
+ traceSlug : previousTraceLink . trace_id ,
111
+ spanId : previousTraceLink . span_id ,
102
112
dateSelection,
103
113
timestamp : linkedTraceTimestamp ,
104
114
location,
@@ -111,7 +121,26 @@ export function TraceLinkNavigationButton({
111
121
) ;
112
122
}
113
123
114
- if ( traceLink ?. sampled === false ) {
124
+ if ( nextTraceData ?. trace_id && nextTraceData . span_id && isLinkedTraceAvailable ) {
125
+ return (
126
+ < TraceLink
127
+ color = "gray500"
128
+ to = { getTraceDetailsUrl ( {
129
+ traceSlug : nextTraceData . trace_id ,
130
+ spanId : nextTraceData . span_id ,
131
+ dateSelection,
132
+ timestamp : linkedTraceTimestamp ,
133
+ location,
134
+ organization,
135
+ } ) }
136
+ >
137
+ < TraceLinkText > { t ( 'Go to Next Trace' ) } </ TraceLinkText >
138
+ < IconChevron direction = "right" />
139
+ </ TraceLink >
140
+ ) ;
141
+ }
142
+
143
+ if ( previousTraceLink ?. sampled === false ) {
115
144
return (
116
145
< StyledTooltip
117
146
position = "right"
0 commit comments