Browse Source

feat(issues): Add additional details to trace timeline menu (#64438)

Scott Cooper 1 year ago
parent
commit
22e005d93c

+ 3 - 0
static/app/views/issueDetails/traceTimeline/traceLink.spec.tsx

@@ -32,6 +32,7 @@ describe('TraceLink', () => {
         title: 'Slow DB Query',
         id: 'abc',
         issue: 'SENTRY-ABC1',
+        transaction: '/api/slow/',
       },
     ],
     meta: {fields: {}, units: {}},
@@ -46,6 +47,8 @@ describe('TraceLink', () => {
         title: 'AttributeError: Something Failed',
         id: event.id,
         issue: 'SENTRY-2EYS',
+        transaction: 'important.task',
+        'event.type': 'error',
       },
     ],
     meta: {fields: {}, units: {}},

+ 4 - 0
static/app/views/issueDetails/traceTimeline/traceTimeline.spec.tsx

@@ -32,6 +32,7 @@ describe('TraceTimeline', () => {
         title: 'Slow DB Query',
         id: 'abc',
         issue: 'SENTRY-ABC1',
+        transaction: '/api/slow/',
       },
     ],
     meta: {fields: {}, units: {}},
@@ -46,6 +47,9 @@ describe('TraceTimeline', () => {
         title: 'AttributeError: Something Failed',
         id: event.id,
         issue: 'SENTRY-2EYS',
+        transaction: 'important.task',
+        'event.type': 'error',
+        'stack.function': ['important.task', 'task.run'],
       },
     ],
     meta: {fields: {}, units: {}},

+ 0 - 2
static/app/views/issueDetails/traceTimeline/traceTimelineEvents.tsx

@@ -148,8 +148,6 @@ function NodeGroup({
       title={<TraceTimelineTooltip event={event} timelineEvents={colEvents} />}
       overlayStyle={{
         padding: `0 !important`,
-        maxWidth: '250px !important',
-        width: '250px',
       }}
       offset={10}
       position="bottom"

+ 40 - 16
static/app/views/issueDetails/traceTimeline/traceTimelineTooltip.tsx

@@ -3,7 +3,7 @@ import styled from '@emotion/styled';
 import ProjectBadge from 'sentry/components/idBadge/projectBadge';
 import Link from 'sentry/components/links/link';
 import {generateTraceTarget} from 'sentry/components/quickTrace/utils';
-import {t} from 'sentry/locale';
+import {t, tn} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
 import type {Event} from 'sentry/types';
 import useOrganization from 'sentry/utils/useOrganization';
@@ -11,10 +11,12 @@ import useProjects from 'sentry/utils/useProjects';
 
 import type {TimelineEvent} from './useTraceTimelineEvents';
 
-export function TraceTimelineTooltip({
-  event,
-  timelineEvents,
-}: {event: Event; timelineEvents: TimelineEvent[]}) {
+interface TraceTimelineTooltipProps {
+  event: Event;
+  timelineEvents: TimelineEvent[];
+}
+
+export function TraceTimelineTooltip({event, timelineEvents}: TraceTimelineTooltipProps) {
   const organization = useOrganization();
   const {projects} = useProjects({
     slugs: [
@@ -27,13 +29,16 @@ export function TraceTimelineTooltip({
     return <YouAreHere>{t('You are here')}</YouAreHere>;
   }
 
+  const filteredTimelineEvents = timelineEvents.filter(
+    timelineEvent => timelineEvent.id !== event.id
+  );
+  const displayYouAreHere = filteredTimelineEvents.length !== timelineEvents.length;
   return (
     <UnstyledUnorderedList>
+      {displayYouAreHere && <YouAreHereItem>{t('You are here')}</YouAreHereItem>}
       <EventItemsWrapper>
-        {timelineEvents.slice(0, 3).map(timelineEvent => {
-          const titleSplit = timelineEvent.title.split(':');
+        {filteredTimelineEvents.slice(0, 3).map(timelineEvent => {
           const project = projects.find(p => p.slug === timelineEvent.project);
-
           return (
             <EventItem
               key={timelineEvent.id}
@@ -43,17 +48,27 @@ export function TraceTimelineTooltip({
                 {project && <ProjectBadge project={project} avatarSize={18} hideName />}
               </div>
               <EventTitleWrapper>
-                <EventTitle>{titleSplit[0]}</EventTitle>
-                <EventDescription>{titleSplit.slice(1).join('')}</EventDescription>
+                <EventTitle>{timelineEvent.title}</EventTitle>
+                <EventDescription>
+                  {timelineEvent.transaction
+                    ? timelineEvent.transaction
+                    : 'stack.function' in timelineEvent
+                      ? timelineEvent['stack.function'].at(-1)
+                      : null}
+                </EventDescription>
               </EventTitleWrapper>
             </EventItem>
           );
         })}
       </EventItemsWrapper>
-      {timelineEvents.length > 3 && (
+      {filteredTimelineEvents.length > 3 && (
         <TraceItem>
           <Link to={generateTraceTarget(event, organization)}>
-            {t('View trace for %s more', timelineEvents.length - 3)}
+            {tn(
+              'View %s more event',
+              'View %s more events',
+              filteredTimelineEvents.length - 3
+            )}
           </Link>
         </TraceItem>
       )}
@@ -65,6 +80,7 @@ const UnstyledUnorderedList = styled('div')`
   display: flex;
   flex-direction: column;
   text-align: left;
+  width: 220px;
 `;
 
 const EventItemsWrapper = styled('div')`
@@ -74,9 +90,16 @@ const EventItemsWrapper = styled('div')`
 `;
 
 const YouAreHere = styled('div')`
-  padding: ${space(1)};
-  font-weight: bold;
+  padding: ${space(1)} ${space(2)};
+  text-align: center;
+  font-size: ${p => p.theme.fontSizeMedium};
+`;
+
+const YouAreHereItem = styled('div')`
+  padding: ${space(1)} ${space(2)};
   text-align: center;
+  border-bottom: 1px solid ${p => p.theme.innerBorder};
+  font-size: ${p => p.theme.fontSizeMedium};
 `;
 
 const EventItem = styled(Link)`
@@ -85,9 +108,9 @@ const EventItem = styled(Link)`
   color: ${p => p.theme.textColor};
   gap: ${space(1)};
   width: 100%;
-  padding: ${space(1)};
+  padding: ${space(1)} ${space(1)} ${space(0.5)} ${space(1)};
   border-radius: ${p => p.theme.borderRadius};
-  min-height: 44px;
+  font-size: ${p => p.theme.fontSizeSmall};
 
   &:hover {
     background-color: ${p => p.theme.surface200};
@@ -108,6 +131,7 @@ const EventTitle = styled('div')`
 
 const EventDescription = styled('div')`
   ${p => p.theme.overflowEllipsis};
+  direction: rtl;
 `;
 
 const TraceItem = styled('div')`

+ 21 - 3
static/app/views/issueDetails/traceTimeline/useTraceTimelineEvents.tsx

@@ -6,7 +6,7 @@ import {getTraceTimeRangeFromEvent} from 'sentry/utils/performance/quickTrace/ut
 import {useApiQuery} from 'sentry/utils/queryClient';
 import useOrganization from 'sentry/utils/useOrganization';
 
-export interface TimelineEvent {
+interface BaseEvent {
   id: string;
   issue: string;
   'issue.id': number;
@@ -14,8 +14,17 @@ export interface TimelineEvent {
   'project.name': string;
   timestamp: string;
   title: string;
+  transaction: string;
 }
 
+interface TimelineDiscoverEvent extends BaseEvent {}
+interface TimelineIssuePlatformEvent extends BaseEvent {
+  'event.type': string;
+  'stack.function': string[];
+}
+
+export type TimelineEvent = TimelineDiscoverEvent | TimelineIssuePlatformEvent;
+
 export interface TraceEventResponse {
   data: TimelineEvent[];
   meta: unknown;
@@ -45,7 +54,7 @@ export function useTraceTimelineEvents(
         query: {
           // Get performance issues
           dataset: DiscoverDatasets.ISSUE_PLATFORM,
-          field: ['title', 'project', 'timestamp', 'issue.id', 'issue'],
+          field: ['title', 'project', 'timestamp', 'issue.id', 'issue', 'transaction'],
           per_page: 100,
           query: `trace:${traceId}`,
           referrer: 'api.issues.issue_events',
@@ -71,7 +80,16 @@ export function useTraceTimelineEvents(
         query: {
           // Other events
           dataset: DiscoverDatasets.DISCOVER,
-          field: ['title', 'project', 'timestamp', 'issue.id', 'issue'],
+          field: [
+            'title',
+            'project',
+            'timestamp',
+            'issue.id',
+            'issue',
+            'transaction',
+            'event.type',
+            'stack.function',
+          ],
           per_page: 100,
           query: `trace:${traceId}`,
           referrer: 'api.issues.issue_events',