Просмотр исходного кода

feat(new-trace): Adding direct-routing to traceview from outside performance. (#68988)

Co-authored-by: Abdullah Khan <abdullahkhan@PG9Y57YDXQ.local>
Co-authored-by: getsantry[bot] <66042841+getsantry[bot]@users.noreply.github.com>
Abdkhan14 10 месяцев назад
Родитель
Сommit
845b66be02

+ 13 - 12
static/app/components/events/eventStatisticalDetector/eventComparison/eventDisplay.tsx

@@ -26,9 +26,8 @@ import {defined} from 'sentry/utils';
 import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
 import EventView from 'sentry/utils/discover/eventView';
 import {DiscoverDatasets} from 'sentry/utils/discover/types';
-import {generateEventSlug} from 'sentry/utils/discover/urls';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import {getShortEventId} from 'sentry/utils/events';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
 import {useApiQuery} from 'sentry/utils/queryClient';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
@@ -143,6 +142,7 @@ function EventDisplay({
   durationBaseline,
 }: EventDisplayProps) {
   const organization = useOrganization();
+  const location = useLocation();
   const [selectedEventId, setSelectedEventId] = useState<string>('');
 
   const {data, isLoading, isError} = useFetchSampleEvents({
@@ -190,6 +190,15 @@ function EventDisplay({
   }
 
   const waterfallModel = new WaterfallModel(eventData);
+  const traceSlug = eventData.contexts?.trace?.trace_id ?? '';
+  const fullEventTarget = generateLinkToEventInTraceView({
+    eventId: eventData.id,
+    projectSlug: project.slug,
+    traceSlug,
+    timestamp: eventData.endTimestamp,
+    location,
+    organization,
+  });
   return (
     <EventDisplayContainer>
       <div>
@@ -219,10 +228,7 @@ function EventDisplay({
             <LinkButton
               title={t('Full Event Details')}
               size={BUTTON_SIZE}
-              to={getTransactionDetailsUrl(
-                organization.slug,
-                generateEventSlug({project: project.slug, id: eventData.id})
-              )}
+              to={fullEventTarget}
               aria-label={t('Full Event Details')}
               icon={<IconOpen />}
             />
@@ -253,12 +259,7 @@ function EventDisplay({
           </div>
         </StyledControlBar>
         <ComparisonContentWrapper>
-          <Link
-            to={getTransactionDetailsUrl(
-              organization.slug,
-              generateEventSlug({project: project.slug, id: selectedEventId})
-            )}
-          >
+          <Link to={fullEventTarget}>
             <MinimapContainer>
               <MinimapPositioningContainer>
                 <ActualMinimap

+ 2 - 2
static/app/components/events/interfaces/breadcrumbs/breadcrumb/data/default.spec.tsx

@@ -54,7 +54,7 @@ describe('Breadcrumb Data Default', function () {
           },
         }}
         event={EventFixture()}
-        orgSlug="org-slug"
+        organization={organization}
         searchTerm=""
         breadcrumb={{
           type: BreadcrumbType.DEBUG,
@@ -98,7 +98,7 @@ describe('Breadcrumb Data Default', function () {
           },
         }}
         event={EventFixture()}
-        orgSlug="org-slug"
+        organization={organization}
         searchTerm=""
         breadcrumb={{
           type: BreadcrumbType.DEBUG,

+ 15 - 11
static/app/components/events/interfaces/breadcrumbs/breadcrumb/data/default.tsx

@@ -9,15 +9,15 @@ import type {
 import type {Event} from 'sentry/types/event';
 import type {Organization} from 'sentry/types/organization';
 import {defined} from 'sentry/utils';
-import {generateEventSlug} from 'sentry/utils/discover/urls';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
+import {useLocation} from 'sentry/utils/useLocation';
 import useProjects from 'sentry/utils/useProjects';
 
 import Summary from './summary';
 
 type Props = {
   breadcrumb: BreadcrumbTypeDefault | BreadcrumbTypeNavigation;
-  orgSlug: Organization['slug'];
+  organization: Organization;
   searchTerm: string;
   event?: Event;
   meta?: Record<any, any>;
@@ -28,7 +28,7 @@ export function Default({
   meta,
   breadcrumb,
   event,
-  orgSlug,
+  organization,
   searchTerm,
   transactionEvents,
 }: Props) {
@@ -43,7 +43,7 @@ export function Default({
           <FormatMessage
             searchTerm={searchTerm}
             event={event}
-            orgSlug={orgSlug}
+            organization={organization}
             breadcrumb={breadcrumb}
             message={message}
             transactionEvents={transactionEvents}
@@ -64,16 +64,17 @@ function FormatMessage({
   event,
   message,
   breadcrumb,
-  orgSlug,
+  organization,
   transactionEvents,
 }: {
   breadcrumb: BreadcrumbTypeDefault | BreadcrumbTypeNavigation;
   message: string;
-  orgSlug: Organization['slug'];
+  organization: Organization;
   searchTerm: string;
   event?: Event;
   transactionEvents?: BreadcrumbTransactionEvent[];
 }) {
+  const location = useLocation();
   const content = <Highlight text={searchTerm}>{message}</Highlight>;
 
   const isSentryTransaction =
@@ -95,12 +96,15 @@ function FormatMessage({
       return content;
     }
     const projectSlug = maybeProject.slug;
-    const eventSlug = generateEventSlug({project: projectSlug, id: message});
-
     const description = transactionData ? (
       <Link
-        to={getTransactionDetailsUrl(orgSlug, eventSlug, undefined, {
-          referrer: 'breadcrumbs',
+        to={generateLinkToEventInTraceView({
+          eventId: message,
+          timestamp: event?.endTimestamp ?? '',
+          traceSlug: event?.contexts?.trace?.trace_id ?? '',
+          projectSlug,
+          organization,
+          location: {...location, query: {...location.query, referrer: 'breadcrumbs'}},
         })}
       >
         <Highlight text={searchTerm}>{transactionData.title}</Highlight>

+ 1 - 3
static/app/components/events/interfaces/breadcrumbs/breadcrumb/data/index.tsx

@@ -29,8 +29,6 @@ export function Data({
   meta,
   transactionEvents,
 }: Props) {
-  const orgSlug = organization.slug;
-
   if (breadcrumb.type === BreadcrumbType.HTTP) {
     return <Http breadcrumb={breadcrumb} searchTerm={searchTerm} meta={meta} />;
   }
@@ -53,7 +51,7 @@ export function Data({
   return (
     <Default
       event={event}
-      orgSlug={orgSlug}
+      organization={organization}
       breadcrumb={breadcrumb}
       searchTerm={searchTerm}
       meta={meta}

+ 1 - 0
static/app/components/events/interfaces/breadcrumbs/breadcrumbs.spec.tsx

@@ -197,6 +197,7 @@ describe('Breadcrumbs', () => {
     });
 
     it('should render Sentry Transactions crumb', async function () {
+      props.organization.features = ['performance-view'];
       props.data.values = [
         {
           message: '12345678123456781234567812345678',

+ 64 - 36
static/app/components/events/interfaces/performance/spanEvidenceKeyValueList.tsx

@@ -1,6 +1,7 @@
 import type {ReactNode} from 'react';
 import {Fragment, useMemo} from 'react';
 import styled from '@emotion/styled';
+import type {Location} from 'history';
 import kebabCase from 'lodash/kebabCase';
 import mapValues from 'lodash/mapValues';
 
@@ -19,6 +20,7 @@ import type {
   EventTransaction,
   KeyValueListData,
   KeyValueListDataItem,
+  Organization,
 } from 'sentry/types';
 import {
   EntryType,
@@ -28,10 +30,10 @@ import {
   isTransactionBased,
 } from 'sentry/types';
 import {formatBytesBase2} from 'sentry/utils';
-import {generateEventSlug} from 'sentry/utils/discover/urls';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import toRoundedPercent from 'sentry/utils/number/toRoundedPercent';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
 import {safeURL} from 'sentry/utils/url/safeURL';
+import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils';
 import {getPerformanceDuration} from 'sentry/views/performance/utils/getPerformanceDuration';
@@ -54,8 +56,9 @@ type Span = (RawSpanType | TraceContextSpanProxy) & {
 type SpanEvidenceKeyValueListProps = {
   causeSpans: Span[];
   event: EventTransaction;
+  location: Location;
   offendingSpans: Span[];
-  orgSlug: string;
+  organization: Organization;
   parentSpan: Span | null;
   issueType?: IssueType;
   projectSlug?: string;
@@ -67,14 +70,15 @@ function ConsecutiveDBQueriesSpanEvidence({
   event,
   causeSpans,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           causeSpans
             ? makeRow(t('Starting Span'), getSpanEvidenceValue(causeSpans[0]))
             : null,
@@ -95,14 +99,15 @@ function ConsecutiveDBQueriesSpanEvidence({
 function ConsecutiveHTTPSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           makeRow(
             'Offending Spans',
             offendingSpans.map(span => span.description)
@@ -116,14 +121,15 @@ function ConsecutiveHTTPSpanEvidence({
 function LargeHTTPPayloadSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           makeRow(t('Large HTTP Payload Span'), getSpanEvidenceValue(offendingSpans[0])),
           makeRow(
             t('Payload Size'),
@@ -139,14 +145,15 @@ function LargeHTTPPayloadSpanEvidence({
 function HTTPOverheadSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
 
           makeRow(t('Max Queue Time'), getHTTPOverheadMaxTime(offendingSpans)),
         ].filter(Boolean) as KeyValueListData
@@ -160,8 +167,9 @@ function NPlusOneDBQueriesSpanEvidence({
   causeSpans,
   parentSpan,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   const dbSpans = offendingSpans.filter(span => (span.op || '').startsWith('db'));
   const repeatingSpanRows = dbSpans
@@ -177,7 +185,7 @@ function NPlusOneDBQueriesSpanEvidence({
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           parentSpan ? makeRow(t('Parent Span'), getSpanEvidenceValue(parentSpan)) : null,
           causeSpans.length > 0
             ? makeRow(t('Preceding Span'), getSpanEvidenceValue(causeSpans[0]))
@@ -192,8 +200,9 @@ function NPlusOneDBQueriesSpanEvidence({
 function NPlusOneAPICallsSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   const requestEntry = event?.entries?.find(isRequestEntry);
   const baseURL = requestEntry?.data?.url;
@@ -205,7 +214,7 @@ function NPlusOneAPICallsSpanEvidence({
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           commonPathPrefix
             ? makeRow(
                 t('Repeating Spans (%s)', offendingSpans.length),
@@ -230,7 +239,10 @@ function NPlusOneAPICallsSpanEvidence({
   );
 }
 
-function MainThreadFunctionEvidence({event, orgSlug}: SpanEvidenceKeyValueListProps) {
+function MainThreadFunctionEvidence({
+  event,
+  organization,
+}: SpanEvidenceKeyValueListProps) {
   const data = useMemo(() => {
     const dataRows: KeyValueListDataItem[] = [];
 
@@ -239,7 +251,7 @@ function MainThreadFunctionEvidence({event, orgSlug}: SpanEvidenceKeyValueListPr
 
     if (evidenceData.transactionName) {
       const transactionSummaryLocation = transactionSummaryRouteWithQuery({
-        orgSlug,
+        orgSlug: organization.slug,
         projectID: event.projectID,
         transaction: evidenceData.transactionName,
         query: {},
@@ -263,7 +275,7 @@ function MainThreadFunctionEvidence({event, orgSlug}: SpanEvidenceKeyValueListPr
     );
 
     return dataRows;
-  }, [event, orgSlug]);
+  }, [event, organization]);
 
   return <PresortedKeyValueList data={data} />;
 }
@@ -307,7 +319,8 @@ export function SpanEvidenceKeyValueList({
   event: EventTransaction;
   projectSlug?: string;
 }) {
-  const {slug: orgSlug} = useOrganization();
+  const organization = useOrganization();
+  const location = useLocation();
   const spanInfo = getSpanInfoFromTransactionEvent(event);
 
   const typeId = event.occurrence?.type;
@@ -320,9 +333,10 @@ export function SpanEvidenceKeyValueList({
       <DefaultSpanEvidence
         event={event}
         offendingSpans={[]}
+        location={location}
         causeSpans={[]}
         parentSpan={null}
-        orgSlug={orgSlug}
+        organization={organization}
         projectSlug={projectSlug}
       />
     );
@@ -335,7 +349,8 @@ export function SpanEvidenceKeyValueList({
       <Component
         event={event}
         issueType={issueType}
-        orgSlug={orgSlug}
+        organization={organization}
+        location={location}
         projectSlug={projectSlug}
         {...spanInfo}
       />
@@ -354,13 +369,14 @@ const isRequestEntry = (entry: Entry): entry is EntryRequest => {
 function SlowDBQueryEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={[
-        makeTransactionNameRow(event, orgSlug, projectSlug),
+        makeTransactionNameRow(event, organization, location, projectSlug),
         makeRow(t('Slow DB Query'), getSpanEvidenceValue(offendingSpans[0])),
         makeRow(
           t('Duration Impact'),
@@ -374,15 +390,16 @@ function SlowDBQueryEvidence({
 function RenderBlockingAssetSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   const offendingSpan = offendingSpans[0]; // For render-blocking assets, there is only one offender
 
   return (
     <PresortedKeyValueList
       data={[
-        makeTransactionNameRow(event, orgSlug, projectSlug),
+        makeTransactionNameRow(event, organization, location, projectSlug),
         makeRow(t('Slow Resource Span'), getSpanEvidenceValue(offendingSpan)),
         makeRow(
           t('FCP Delay'),
@@ -397,13 +414,14 @@ function RenderBlockingAssetSpanEvidence({
 function UncompressedAssetSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={[
-        makeTransactionNameRow(event, orgSlug, projectSlug),
+        makeTransactionNameRow(event, organization, location, projectSlug),
         makeRow(t('Slow Resource Span'), getSpanEvidenceValue(offendingSpans[0])),
         makeRow(
           t('Asset Size'),
@@ -422,14 +440,15 @@ function UncompressedAssetSpanEvidence({
 function DefaultSpanEvidence({
   event,
   offendingSpans,
-  orgSlug,
+  organization,
   projectSlug,
+  location,
 }: SpanEvidenceKeyValueListProps) {
   return (
     <PresortedKeyValueList
       data={
         [
-          makeTransactionNameRow(event, orgSlug, projectSlug),
+          makeTransactionNameRow(event, organization, location, projectSlug),
           offendingSpans.length > 0
             ? makeRow(t('Offending Span'), getSpanEvidenceValue(offendingSpans[0]))
             : null,
@@ -443,20 +462,29 @@ function PresortedKeyValueList({data}: {data: KeyValueListData}) {
   return <KeyValueList shouldSort={false} data={data} />;
 }
 
-const makeTransactionNameRow = (event: Event, orgSlug: string, projectSlug?: string) => {
+const makeTransactionNameRow = (
+  event: Event,
+  organization: Organization,
+  location: Location,
+  projectSlug?: string
+) => {
   const transactionSummaryLocation = transactionSummaryRouteWithQuery({
-    orgSlug,
+    orgSlug: organization.slug,
     projectID: event.projectID,
     transaction: event.title,
     query: {},
   });
 
-  const eventSlug = generateEventSlug({
-    id: event.eventID,
-    project: projectSlug,
-  });
+  const traceSlug = event.contexts?.trace?.trace_id ?? '';
 
-  const eventDetailsLocation = getTransactionDetailsUrl(orgSlug, eventSlug);
+  const eventDetailsLocation = generateLinkToEventInTraceView({
+    traceSlug,
+    projectSlug: projectSlug ?? '',
+    eventId: event.eventID,
+    timestamp: event.endTimestamp ?? '',
+    location,
+    organization,
+  });
 
   const actionButton = projectSlug ? (
     <Button size="xs" to={eventDetailsLocation}>

+ 4 - 4
static/app/components/events/interfaces/spans/aggregateSpanDetail.tsx

@@ -6,7 +6,6 @@ import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import type {Organization, Project} from 'sentry/types';
 import type {AggregateEventTransaction} from 'sentry/types/event';
-import EventView from 'sentry/utils/discover/eventView';
 import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import {formatPercentage, getDuration} from 'sentry/utils/formatters';
 import type {
@@ -45,10 +44,11 @@ function renderSpanSamples(
       key={`${transaction}-${span}`}
       to={generateLinkToEventInTraceView({
         organization,
-        eventSlug: `${project.slug}:${transaction}`,
-        dataRow: {id: transaction, trace, timestamp},
+        traceSlug: trace,
+        projectSlug: project.slug,
+        eventId: transaction,
+        timestamp,
         location,
-        eventView: EventView.fromLocation(location),
         spanId: span,
       })}
     >{`${span}${index < aggSpan.samples.length - 1 ? ', ' : ''}`}</Link>

+ 12 - 11
static/app/components/events/profileEventEvidence.tsx

@@ -4,17 +4,19 @@ import KeyValueList from 'sentry/components/events/interfaces/keyValueList';
 import {IconProfiling} from 'sentry/icons';
 import {t} from 'sentry/locale';
 import type {Event} from 'sentry/types';
-import {generateEventSlug} from 'sentry/utils/discover/urls';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import {generateProfileFlamechartRouteWithHighlightFrame} from 'sentry/utils/profiling/routes';
+import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 
 type ProfileEvidenceProps = {event: Event; projectSlug: string};
 
 export function ProfileEventEvidence({event, projectSlug}: ProfileEvidenceProps) {
   const organization = useOrganization();
+  const location = useLocation();
   const evidenceData = event.occurrence?.evidenceData ?? {};
   const evidenceDisplay = event.occurrence?.evidenceDisplay ?? [];
+  const traceSlug = event.contexts?.trace?.trace_id ?? '';
 
   const keyValueListData = [
     ...(evidenceData.transactionId && evidenceData.transactionName
@@ -26,15 +28,14 @@ export function ProfileEventEvidence({event, projectSlug}: ProfileEvidenceProps)
             actionButton: (
               <Button
                 size="xs"
-                to={getTransactionDetailsUrl(
-                  organization.slug,
-                  generateEventSlug({
-                    id: evidenceData.transactionId,
-                    project: projectSlug,
-                  }),
-                  undefined,
-                  {referrer: 'issue'}
-                )}
+                to={generateLinkToEventInTraceView({
+                  traceSlug,
+                  timestamp: evidenceData.timestamp,
+                  eventId: evidenceData.transactionId,
+                  projectSlug,
+                  location: {...location, query: {...location.query, referrer: 'issue'}},
+                  organization,
+                })}
               >
                 {t('View Transaction')}
               </Button>

+ 17 - 8
static/app/components/metrics/metricSamplesTable.tsx

@@ -25,6 +25,7 @@ import type {DateString, MRI, PageFilters, ParsedMRI} from 'sentry/types';
 import {defined} from 'sentry/utils';
 import {trackAnalytics} from 'sentry/utils/analytics';
 import {Container, FieldDateTime, NumberContainer} from 'sentry/utils/discover/styles';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import {getShortEventId} from 'sentry/utils/events';
 import {formatMetricUsingUnit} from 'sentry/utils/metrics/formatters';
 import {parseMRI} from 'sentry/utils/metrics/mri';
@@ -36,7 +37,6 @@ import {
   type Summary,
   useMetricsSamples,
 } from 'sentry/utils/metrics/useMetricsSamples';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
 import {generateProfileFlamechartRoute} from 'sentry/utils/profiling/routes';
 import Projects from 'sentry/utils/projects';
 import {decodeScalar} from 'sentry/utils/queryString';
@@ -421,6 +421,8 @@ function renderBodyCell(op?: string, unit?: string) {
         <SpanDescription
           description={dataRow['span.description']}
           project={dataRow.project}
+          trace={dataRow.trace}
+          timestamp={dataRow.timestamp}
           selfTime={dataRow['span.self_time']}
           duration={dataRow['span.duration']}
           spanId={dataRow.id}
@@ -491,6 +493,8 @@ function SpanDescription({
   spanId,
   transaction,
   transactionId,
+  trace,
+  timestamp,
   selfTimeColor = '#694D99',
   durationColor = 'gray100',
 }: {
@@ -499,6 +503,8 @@ function SpanDescription({
   project: string;
   selfTime: number;
   spanId: string;
+  timestamp: DateString;
+  trace: string;
   transaction: string;
   transactionId: string | null;
   durationColor?: string;
@@ -508,13 +514,16 @@ function SpanDescription({
   const organization = useOrganization();
   const {projects} = useProjects({slugs: [project]});
   const transactionDetailsTarget = defined(transactionId)
-    ? getTransactionDetailsUrl(
-        organization.slug,
-        `${project}:${transactionId}`,
-        undefined,
-        undefined,
-        spanId
-      )
+    ? generateLinkToEventInTraceView({
+        eventId: transactionId,
+        projectSlug: project,
+        traceSlug: trace,
+        timestamp: timestamp?.toString() ?? '',
+        location,
+        organization,
+        spanId,
+        transactionName: transaction,
+      })
     : undefined;
 
   const colorStops = useMemo(() => {

+ 24 - 7
static/app/components/profiling/flamegraph/flamegraphDrawer/profileDetails.tsx

@@ -14,12 +14,13 @@ import {space} from 'sentry/styles/space';
 import type {Organization, Project} from 'sentry/types';
 import type {EventTransaction} from 'sentry/types/event';
 import {DeviceContextKey} from 'sentry/types/event';
+import {generateLinkToEventInTraceView} from 'sentry/utils/discover/urls';
 import {formatVersion} from 'sentry/utils/formatters';
-import {getTransactionDetailsUrl} from 'sentry/utils/performance/urls';
 import type {FlamegraphPreferences} from 'sentry/utils/profiling/flamegraph/flamegraphStateProvider/reducers/flamegraphPreferences';
 import {useFlamegraphPreferences} from 'sentry/utils/profiling/flamegraph/hooks/useFlamegraphPreferences';
 import type {ProfileGroup} from 'sentry/utils/profiling/profile/importProfile';
 import {makeFormatter} from 'sentry/utils/profiling/units/units';
+import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 import useProjects from 'sentry/utils/useProjects';
 import type {UseResizableDrawerOptions} from 'sentry/utils/useResizableDrawer';
@@ -256,12 +257,22 @@ function TransactionEventDetails({
   project: Project | undefined;
   transaction: EventTransaction;
 }) {
+  const location = useLocation();
   const transactionDetails = useMemo(() => {
     const profileMetadata = profileGroup.metadata;
 
+    const traceSlug = transaction.contexts?.trace?.trace_id ?? '';
     const transactionTarget =
       transaction.id && project && organization
-        ? getTransactionDetailsUrl(organization.slug, `${project.slug}:${transaction.id}`)
+        ? generateLinkToEventInTraceView({
+            eventId: transaction.id,
+            traceSlug,
+            timestamp: transaction.endTimestamp,
+            projectSlug: project.slug,
+            location,
+            organization,
+            transactionName: transaction.title,
+          })
         : null;
 
     const details: {
@@ -323,7 +334,7 @@ function TransactionEventDetails({
     ];
 
     return details;
-  }, [organization, project, profileGroup, transaction]);
+  }, [organization, project, profileGroup, transaction, location]);
 
   return (
     <DetailsContainer>
@@ -364,6 +375,8 @@ function ProfileEventDetails({
   project: Project | undefined;
   transaction: EventTransaction | null;
 }) {
+  const location = useLocation();
+  const traceSlug = transaction?.contexts?.trace?.trace_id ?? '';
   return (
     <DetailsContainer>
       {Object.entries(PROFILE_DETAILS_KEY).map(([label, key]) => {
@@ -387,10 +400,14 @@ function ProfileEventDetails({
         if (key === 'transactionName') {
           const transactionTarget =
             project?.slug && transaction?.id && organization
-              ? getTransactionDetailsUrl(
-                  organization.slug,
-                  `${project.slug}:${transaction.id}`
-                )
+              ? generateLinkToEventInTraceView({
+                  traceSlug,
+                  projectSlug: project.slug,
+                  eventId: transaction.id,
+                  timestamp: transaction.endTimestamp,
+                  location,
+                  organization,
+                })
               : null;
           if (transactionTarget) {
             return (

Некоторые файлы не были показаны из-за большого количества измененных файлов