Browse Source

feat(new-trace): Adding direct-routing to trace view from transaction summary and span details (#68696)

Last of directly routing to trace view from performance, covers:
- transaction summary
- transaction summary > span details
- Aggregate span samples

---------

Co-authored-by: Abdullah Khan <abdullahkhan@PG9Y57YDXQ.local>
Abdkhan14 11 months ago
parent
commit
74b54e4253

+ 2 - 2
static/app/components/discover/transactionsList.spec.tsx

@@ -72,10 +72,10 @@ describe('TransactionsList', function () {
         },
       ];
       generateLink = {
-        transaction: (org, row, query) => ({
+        transaction: (org, row) => ({
           pathname: `/${org.slug}`,
           query: {
-            ...query,
+            ...location.query,
             transaction: row.transaction,
             count: row.count,
             'count()': row['count()'],

+ 2 - 2
static/app/components/discover/transactionsList.tsx

@@ -1,7 +1,7 @@
 import {Component, Fragment, useContext, useEffect} from 'react';
 import {browserHistory} from 'react-router';
 import styled from '@emotion/styled';
-import type {Location, LocationDescriptor, Query} from 'history';
+import type {Location, LocationDescriptor} from 'history';
 
 import GuideAnchor from 'sentry/components/assistant/guideAnchor';
 import {Button} from 'sentry/components/button';
@@ -100,7 +100,7 @@ type Props = {
     (
       organization: Organization,
       tableRow: TableDataRow,
-      query: Query
+      location: Location
     ) => LocationDescriptor
   >;
   generatePerformanceTransactionEventsView?: () => EventView;

+ 3 - 3
static/app/components/discover/transactionsTable.tsx

@@ -1,6 +1,6 @@
 import {Fragment, PureComponent} from 'react';
 import styled from '@emotion/styled';
-import type {Location, LocationDescriptor, Query} from 'history';
+import type {Location, LocationDescriptor} from 'history';
 
 import SortLink from 'sentry/components/gridEditable/sortLink';
 import Link from 'sentry/components/links/link';
@@ -39,7 +39,7 @@ type Props = {
     (
       organization: Organization,
       tableRow: TableDataRow,
-      query: Query
+      location: Location
     ) => LocationDescriptor
   >;
   handleCellAction?: (
@@ -143,7 +143,7 @@ class TransactionsTable extends PureComponent<Props> {
       const fieldRenderer = getFieldRenderer(field, tableMeta, useAggregateAlias);
       let rendered = fieldRenderer(row, {organization, location});
 
-      const target = generateLink?.[field]?.(organization, row, location.query);
+      const target = generateLink?.[field]?.(organization, row, location);
 
       if (target && !objectIsEmpty(target)) {
         if (fields[index] === 'replayId') {

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

@@ -1,10 +1,13 @@
 import styled from '@emotion/styled';
+import type {Location} from 'history';
 
 import Link from 'sentry/components/links/link';
 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 {
   QuickTraceEvent,
@@ -27,20 +30,32 @@ type Props = {
   trace: Readonly<ParsedTraceType>;
 };
 
-function renderSpanSamples(span: AggregateSpanType, project: Project | undefined) {
+function renderSpanSamples(
+  aggSpan: AggregateSpanType,
+  project: Project | undefined,
+  location: Location,
+  organization: Organization
+) {
   if (!project) {
     return null;
   }
 
-  return span.samples?.map(([transactionId, spanId], index) => (
+  return aggSpan.samples?.map(({transaction, span, trace, timestamp}, index) => (
     <Link
-      key={`${transactionId}-${spanId}`}
-      to={`/performance/${project.slug}:${transactionId}#span-${spanId}`}
-    >{`${spanId}${index < span.samples.length - 1 ? ', ' : ''}`}</Link>
+      key={`${transaction}-${span}`}
+      to={generateLinkToEventInTraceView({
+        organization,
+        eventSlug: `${project.slug}:${transaction}`,
+        dataRow: {id: transaction, trace, timestamp},
+        location,
+        eventView: EventView.fromLocation(location),
+        spanId: span,
+      })}
+    >{`${span}${index < aggSpan.samples.length - 1 ? ', ' : ''}`}</Link>
   ));
 }
 
-function AggregateSpanDetail({span}: Props) {
+function AggregateSpanDetail({span, organization}: Props) {
   const location = useLocation();
   const {projects} = useProjects();
 
@@ -62,7 +77,9 @@ function AggregateSpanDetail({span}: Props) {
           <tbody>
             <Row title={t('Avg Duration')}>{getDuration(avgDuration)}</Row>
             <Row title={t('Frequency')}>{frequency && formatPercentage(frequency)}</Row>
-            <Row title={t('Span Samples')}>{renderSpanSamples(span, project)}</Row>
+            <Row title={t('Span Samples')}>
+              {renderSpanSamples(span, project, location, organization)}
+            </Row>
           </tbody>
         </table>
       </SpanDetails>

+ 6 - 1
static/app/components/events/interfaces/spans/types.tsx

@@ -66,7 +66,12 @@ export type RawSpanType = {
 export type AggregateSpanType = RawSpanType & {
   count: number;
   frequency: number;
-  samples: Array<[string, string]>;
+  samples: Array<{
+    span: string;
+    timestamp: number;
+    trace: string;
+    transaction: string;
+  }>;
   total: number;
   type: 'aggregate';
 };

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

@@ -22,7 +22,8 @@ export function useSpanWaterfallModelFromTransaction(
       'avg(absolute_offset)': start_timestamp,
       'count()': count,
       'avg(duration)': duration,
-      samples,
+      sample_spans,
+      trace,
       ...rest
     } = span;
     return {
@@ -33,11 +34,11 @@ export function useSpanWaterfallModelFromTransaction(
       exclusive_time,
       timestamp: (start_timestamp + duration) / 1000,
       start_timestamp: start_timestamp / 1000,
-      trace_id: '1', // not actually trace_id just a placeholder
+      trace,
       count,
       total,
       duration,
-      samples,
+      samples: sample_spans,
       frequency: count / total,
       type: 'aggregate',
     };

+ 3 - 1
static/app/utils/discover/urls.tsx

@@ -48,6 +48,7 @@ export function generateLinkToEventInTraceView({
   location,
   spanId,
   eventSlug,
+  transactionName,
   type = 'performance',
 }: {
   dataRow: TableDataRow;
@@ -57,6 +58,7 @@ export function generateLinkToEventInTraceView({
   organization: Organization;
   isHomepage?: boolean;
   spanId?: string;
+  transactionName?: string;
   type?: 'performance' | 'discover';
 }) {
   const dateSelection = eventView.normalizeDateSelection(location);
@@ -78,7 +80,7 @@ export function generateLinkToEventInTraceView({
     return getTransactionDetailsUrl(
       organization.slug,
       eventSlug,
-      undefined,
+      transactionName,
       location.query,
       spanId
     );

+ 1 - 0
static/app/utils/performance/suspectSpans/types.tsx

@@ -3,6 +3,7 @@ export type ExampleSpan = {
   finishTimestamp: number;
   id: string;
   startTimestamp: number;
+  trace: string;
 };
 
 export type ExampleTransaction = {

+ 17 - 5
static/app/views/performance/transactionSummary/transactionEvents/eventsTable.tsx

@@ -18,8 +18,7 @@ import type {IssueAttachment, Organization} from 'sentry/types';
 import {trackAnalytics} from 'sentry/utils/analytics';
 import type {TableData, TableDataRow} from 'sentry/utils/discover/discoverQuery';
 import DiscoverQuery from 'sentry/utils/discover/discoverQuery';
-import type EventView from 'sentry/utils/discover/eventView';
-import {isFieldSortable} from 'sentry/utils/discover/eventView';
+import EventView, {isFieldSortable} from 'sentry/utils/discover/eventView';
 import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
 import {
   fieldAlignment,
@@ -27,6 +26,10 @@ import {
   isSpanOperationBreakdownField,
   SPAN_OP_RELATIVE_BREAKDOWN_FIELD,
 } from 'sentry/utils/discover/fields';
+import {
+  generateEventSlug,
+  generateLinkToEventInTraceView,
+} from 'sentry/utils/discover/urls';
 import ViewReplayLink from 'sentry/utils/discover/viewReplayLink';
 import parseLinkHeader from 'sentry/utils/parseLinkHeader';
 import {VisuallyCompleteWithData} from 'sentry/utils/performanceForSentry';
@@ -38,7 +41,6 @@ import {
   generateProfileLink,
   generateReplayLink,
   generateTraceLink,
-  generateTransactionLink,
   normalizeSearchConditions,
 } from '../utils';
 
@@ -164,8 +166,18 @@ class EventsTable extends Component<Props, State> {
       if (isIssue && !isRegressionIssue && field === 'id') {
         target.pathname = `/organizations/${organization.slug}/issues/${issueId}/events/${dataRow.id}/`;
       } else {
-        const generateLink = field === 'id' ? generateTransactionLink : generateTraceLink;
-        target = generateLink(transactionName)(organization, dataRow, location.query);
+        if (field === 'id') {
+          target = generateLinkToEventInTraceView({
+            eventSlug: generateEventSlug(dataRow),
+            dataRow: dataRow,
+            eventView: EventView.fromLocation(location),
+            location,
+            organization,
+            transactionName: transactionName,
+          });
+        } else {
+          target = generateTraceLink(transactionName)(organization, dataRow, location);
+        }
       }
 
       return (

+ 2 - 2
static/app/views/performance/transactionSummary/transactionOverview/content.tsx

@@ -57,7 +57,7 @@ import {
   generateProfileLink,
   generateReplayLink,
   generateTraceLink,
-  generateTransactionLink,
+  generateTransactionIdLink,
   normalizeSearchConditions,
   SidebarSpacer,
   TransactionFilterOptions,
@@ -391,7 +391,7 @@ function SummaryContent({
             titles={transactionsListTitles}
             handleDropdownChange={handleTransactionsListSortChange}
             generateLink={{
-              id: generateTransactionLink(transactionName),
+              id: generateTransactionIdLink(transactionName),
               trace: generateTraceLink(eventView.normalizeDateSelection(location)),
               replayId: generateReplayLink(routes),
               'profile.id': generateProfileLink(),

Some files were not shown because too many files changed in this diff