@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
33import type { LocationDescriptor } from 'history' ;
44
55import { LinkButton } from 'sentry/components/button' ;
6+ import ExternalLink from 'sentry/components/links/externalLink' ;
67import Link from 'sentry/components/links/link' ;
78import { generateTraceTarget } from 'sentry/components/quickTrace/utils' ;
89import { IconOpen } from 'sentry/icons' ;
@@ -11,6 +12,7 @@ import type {Event} from 'sentry/types/event';
1112import { type Group , IssueCategory } from 'sentry/types/group' ;
1213import type { Organization } from 'sentry/types/organization' ;
1314import { defined } from 'sentry/utils' ;
15+ import { trackAnalytics } from 'sentry/utils/analytics' ;
1416import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams' ;
1517import { useLocation } from 'sentry/utils/useLocation' ;
1618import useOrganization from 'sentry/utils/useOrganization' ;
@@ -58,9 +60,15 @@ interface EventTraceViewInnerProps {
5860 event : Event ;
5961 organization : Organization ;
6062 traceId : string ;
63+ traceTarget : LocationDescriptor ;
6164}
6265
63- function EventTraceViewInner ( { event, organization, traceId} : EventTraceViewInnerProps ) {
66+ function EventTraceViewInner ( {
67+ event,
68+ organization,
69+ traceId,
70+ traceTarget,
71+ } : EventTraceViewInnerProps ) {
6472 const timestamp = new Date ( event . dateReceived ) . getTime ( ) / 1e3 ;
6573
6674 const trace = useTrace ( {
@@ -108,7 +116,14 @@ function EventTraceViewInner({event, organization, traceId}: EventTraceViewInner
108116 replay = { null }
109117 event = { event }
110118 />
111- < IssuesTraceOverlay event = { event } />
119+ < IssuesTraceOverlayContainer
120+ href = { getHrefFromTraceTarget ( traceTarget ) }
121+ onClick = { ( ) => {
122+ trackAnalytics ( 'issue_details.view_full_trace_waterfall_clicked' , {
123+ organization,
124+ } ) ;
125+ } }
126+ />
112127 </ IssuesTraceContainer >
113128 </ TraceStateProvider >
114129 ) ;
@@ -129,39 +144,6 @@ function getHrefFromTraceTarget(traceTarget: LocationDescriptor) {
129144 return `${ traceTarget . pathname } ?${ searchParams . toString ( ) } ` ;
130145}
131146
132- function IssuesTraceOverlay ( { event} : { event : Event } ) {
133- const location = useLocation ( ) ;
134- const organization = useOrganization ( ) ;
135-
136- const traceTarget = generateTraceTarget (
137- event ,
138- organization ,
139- {
140- ...location ,
141- query : {
142- ...location . query ,
143- groupId : event . groupID ,
144- } ,
145- } ,
146- TraceViewSources . ISSUE_DETAILS
147- ) ;
148-
149- return (
150- < IssuesTraceOverlayContainer >
151- < LinkButton
152- size = "sm"
153- icon = { < IconOpen /> }
154- href = { getHrefFromTraceTarget ( traceTarget ) }
155- external
156- analyticsEventName = "Issue Details: View Full Trace"
157- analyticsEventKey = "issue_details.view_full_trace"
158- >
159- { t ( 'View Full Trace' ) }
160- </ LinkButton >
161- </ IssuesTraceOverlayContainer >
162- ) ;
163- }
164-
165147function OneOtherIssueEvent ( { event} : { event : Event } ) {
166148 const location = useLocation ( ) ;
167149 const organization = useOrganization ( ) ;
@@ -200,52 +182,69 @@ const IssuesTraceContainer = styled('div')`
200182 position: relative;
201183` ;
202184
203- const IssuesTraceOverlayContainer = styled ( 'div' ) `
185+ const IssuesTraceOverlayContainer = styled ( ExternalLink ) `
204186 position: absolute;
205187 inset: 0;
206188 z-index: 10;
207-
208- a {
209- display: none;
210- position: absolute;
211- top: 50%;
212- left: 50%;
213- transform: translate(-50%, -50%);
214- }
215-
216- &:hover {
217- background-color: rgba(128, 128, 128, 0.4);
218-
219- a {
220- display: block;
221- }
222- }
223189` ;
224190
225- interface EventTraceViewProps extends Omit < EventTraceViewInnerProps , 'traceId' > {
191+ interface EventTraceViewProps {
192+ event : Event ;
226193 group : Group ;
194+ organization : Organization ;
227195}
228196
229197export function EventTraceView ( { group, event, organization} : EventTraceViewProps ) {
230198 const traceId = event . contexts . trace ?. trace_id ;
199+ const location = useLocation ( ) ;
200+
231201 if ( ! traceId ) {
232202 return null ;
233203 }
234204
205+ const traceTarget = generateTraceTarget (
206+ event ,
207+ organization ,
208+ {
209+ ...location ,
210+ query : {
211+ ...location . query ,
212+ groupId : event . groupID ,
213+ } ,
214+ } ,
215+ TraceViewSources . ISSUE_DETAILS
216+ ) ;
217+
235218 const hasProfilingFeature = organization . features . includes ( 'profiling' ) ;
236219 const hasTracePreviewFeature =
237220 hasProfilingFeature &&
238221 // Only display this for error or default events since performance events are handled elsewhere
239222 group . issueCategory !== IssueCategory . PERFORMANCE ;
240223
241224 return (
242- < InterimSection type = { SectionKey . TRACE } title = { t ( 'Trace' ) } >
225+ < InterimSection
226+ type = { SectionKey . TRACE }
227+ title = { t ( 'Trace Preview' ) }
228+ actions = {
229+ < LinkButton
230+ size = "xs"
231+ icon = { < IconOpen /> }
232+ href = { getHrefFromTraceTarget ( traceTarget ) }
233+ external
234+ analyticsEventName = "Issue Details: View Full Trace Action Button Clicked"
235+ analyticsEventKey = "issue_details.view_full_trace_action_button_clicked"
236+ >
237+ { t ( 'View Full Trace' ) }
238+ </ LinkButton >
239+ }
240+ >
243241 < OneOtherIssueEvent event = { event } />
244242 { hasTracePreviewFeature && (
245243 < EventTraceViewInner
246244 event = { event }
247245 organization = { organization }
248246 traceId = { traceId }
247+ traceTarget = { traceTarget }
249248 />
250249 ) }
251250 </ InterimSection >
0 commit comments