Repository: getsentry/sentry
Pull request: feat(trace): Update trace details to include performance issues
- This updates the trace details to include performance issues
- Also fix an issue where the transaction wasn't turning red if its only issue was a performance one
- CLoses: https://github.com/getsentry/sentry/issues/45778

![image](https://user-images.githubusercontent.com/4205004/231217615-ad4bc677-4c82-46d2-8f26-09c675373531.png)


Problem statement:
Update the Event Breakdown to include Performance Issues
The Event Breakdown at the top of the trace view, currently shows the count of errors & transactions. It should also show the count of performance issues.

Check with design, there was a discussion here about having a list of all the performance issues on the page as well.

Hints from issue discussion:

Commit message: fix: typing

Patch to review:
diff --git a/static/app/utils/performance/quickTrace/types.tsx b/static/app/utils/performance/quickTrace/types.tsx
index 5f46f092112f5d..1139724624a02f 100644
--- a/static/app/utils/performance/quickTrace/types.tsx
+++ b/static/app/utils/performance/quickTrace/types.tsx
@@ -118,6 +118,7 @@ export type QuickTraceQueryChildrenProps = BaseTraceChildrenProps &
 
 export type TraceMeta = {
   errors: number;
+  performance_issues: number;
   projects: number;
   transactions: number;
 };
diff --git a/static/app/views/performance/traceDetails/content.spec.tsx b/static/app/views/performance/traceDetails/content.spec.tsx
index da01e4f8043c5a..0eeaf521983d29 100644
--- a/static/app/views/performance/traceDetails/content.spec.tsx
+++ b/static/app/views/performance/traceDetails/content.spec.tsx
@@ -39,7 +39,7 @@ describe('TraceDetailsContent', () => {
     it('should render a list of errors when a trace contains only error events', async () => {
       const initialData = initializeData();
       const eventView = EventView.fromSavedQuery(DEFAULT_EVENT_VIEW);
-      const meta = {errors: 2, projects: 1, transactions: 0};
+      const meta = {errors: 2, projects: 1, transactions: 0, performance_issues: 1};
 
       render(
         <TraceDetailsContent
@@ -81,7 +81,7 @@ describe('TraceDetailsContent', () => {
 
       const initialData = initializeData();
       const eventView = EventView.fromSavedQuery(DEFAULT_EVENT_VIEW);
-      const meta = {errors: 2, projects: 1, transactions: 0};
+      const meta = {errors: 2, projects: 1, transactions: 0, performance_issues: 0};
 
       render(
         <TraceDetailsContent
diff --git a/static/app/views/performance/traceDetails/content.tsx b/static/app/views/performance/traceDetails/content.tsx
index 45cff672bbd267..35b43f84d45838 100644
--- a/static/app/views/performance/traceDetails/content.tsx
+++ b/static/app/views/performance/traceDetails/content.tsx
@@ -176,13 +176,16 @@ class TraceDetailsContent extends Component<Props, State> {
 
   renderTraceHeader(traceInfo: TraceInfo) {
     const {meta} = this.props;
+    const errors = meta?.errors ?? traceInfo.errors.size;
+    const performanceIssues =
+      meta?.performance_issues ?? traceInfo.performanceIssues.size;
     return (
       <TraceDetailHeader>
         <GuideAnchor target="trace_view_guide_breakdown">
           <MetaData
             headingText={t('Event Breakdown')}
             tooltipText={t(
-              'The number of transactions and errors there are in this trace.'
+              'The number of transactions and issues there are in this trace.'
             )}
             bodyText={tct('[transactions]  |  [errors]', {
               transactions: tn(
@@ -190,7 +193,7 @@ class TraceDetailsContent extends Component<Props, State> {
                 '%s Transactions',
                 meta?.transactions ?? traceInfo.transactions.size
               ),
-              errors: tn('%s Error', '%s Errors', meta?.errors ?? traceInfo.errors.size),
+              errors: tn('%s Issues', '%s Issues', errors + performanceIssues),
             })}
             subtext={tn(
               'Across %s project',
diff --git a/static/app/views/performance/traceDetails/transactionBar.tsx b/static/app/views/performance/traceDetails/transactionBar.tsx
index 958b2ca408fb92..b130ad0c0a02da 100644
--- a/static/app/views/performance/traceDetails/transactionBar.tsx
+++ b/static/app/views/performance/traceDetails/transactionBar.tsx
@@ -294,7 +294,7 @@ class TransactionBar extends Component<Props, State> {
       this.props;
     const left = this.getCurrentOffset();
     const errored = isTraceFullDetailed(transaction)
-      ? transaction.errors.length > 0
+      ? transaction.errors.length + transaction.performance_issues.length > 0
       : false;
 
     const content = isTraceFullDetailed(transaction) ? (
diff --git a/static/app/views/performance/traceDetails/types.tsx b/static/app/views/performance/traceDetails/types.tsx
index 4e1f57505a4e0e..b00642ca1bb275 100644
--- a/static/app/views/performance/traceDetails/types.tsx
+++ b/static/app/views/performance/traceDetails/types.tsx
@@ -13,6 +13,10 @@ export type TraceInfo = {
    * The maximum generation in the trace.
    */
   maxGeneration: number;
+  /**
+   * The performance Issues on the trace
+   */
+  performanceIssues: Set<string>;
   /**
    * The projects in the trace
    */
diff --git a/static/app/views/performance/traceDetails/utils.tsx b/static/app/views/performance/traceDetails/utils.tsx
index 149305fe266cba..ec2f1f5d7cf24f 100644
--- a/static/app/views/performance/traceDetails/utils.tsx
+++ b/static/app/views/performance/traceDetails/utils.tsx
@@ -30,6 +30,9 @@ function traceVisitor() {
     for (const error of event.errors ?? []) {
       accumulator.errors.add(error.event_id);
     }
+    for (const performanceIssue of event.performance_issues ?? []) {
+      accumulator.errors.add(performanceIssue.event_id);
+    }
 
     accumulator.transactions.add(event.event_id);
     accumulator.projects.add(event.project_slug);
@@ -50,6 +53,7 @@ export function getTraceInfo(traces: TraceFullDetailed[]) {
   const initial = {
     projects: new Set<string>(),
     errors: new Set<string>(),
+    performanceIssues: new Set<string>(),
     transactions: new Set<string>(),
     startTimestamp: Number.MAX_SAFE_INTEGER,
     endTimestamp: 0,


Code review comments:
diff_hunk: @@ -176,21 +176,24 @@ class TraceDetailsContent extends Component<Props, State> {
 
   renderTraceHeader(traceInfo: TraceInfo) {
     const {meta} = this.props;
+    const errors = meta?.errors ?? traceInfo.errors.size;
+    const performanceIssues =
+      meta?.performance_issues ?? traceInfo.performanceIssues.size;
     return (
       <TraceDetailHeader>
         <GuideAnchor target="trace_view_guide_breakdown">
           <MetaData
             headingText={t('Event Breakdown')}
             tooltipText={t(
-              'The number of transactions and errors there are in this trace.'
+              'The number of transactions and issues there are in this trace.'
             )}
             bodyText={tct('[transactions]  |  [errors]', {
               transactions: tn(
                 '%s Transaction',
                 '%s Transactions',
                 meta?.transactions ?? traceInfo.transactions.size
               ),
-              errors: tn('%s Error', '%s Errors', meta?.errors ?? traceInfo.errors.size),
+              errors: tn('%s Issues', '%s Issues', errors + performanceIssues),
path: static/app/views/performance/traceDetails/content.tsx
text: @user1:
```suggestion
              errors: tn('%s Issue', '%s Issues', errors + performanceIssues),
```