Browse Source

feat(new-trace): Re-route to new traceview when landing on eventDetails. (#66907)

In case someone lands in the event details page (maybe from a saved
link), we'll re-route to the traceview with new `eventId` and
`timestamp` query params.

Note: All the big blocks of change comes from placing the Routing
wrapper above the `TraceMetaQuery`, we no longer have to wait for trace
meta query results for the re-route.

Co-authored-by: Abdullah Khan <abdullahkhan@PG9Y57YDXQ.local>
Abdkhan14 1 year ago
parent
commit
f9e153172f

+ 162 - 165
static/app/views/discover/eventDetails/content.tsx

@@ -138,160 +138,155 @@ function EventDetailsContent(props: Props) {
       metaResults?: TraceMetaQueryChildrenProps
     ) => {
       return (
-        <TraceDetailsRouting event={event} metaResults={metaResults}>
-          <TransactionProfileIdProvider
-            projectId={event.projectID}
-            transactionId={event.type === 'transaction' ? event.id : undefined}
-            timestamp={event.dateReceived}
-          >
-            <Layout.Header>
-              <Layout.HeaderContent>
-                <DiscoverBreadcrumb
-                  eventView={eventView}
+        <TransactionProfileIdProvider
+          projectId={event.projectID}
+          transactionId={event.type === 'transaction' ? event.id : undefined}
+          timestamp={event.dateReceived}
+        >
+          <Layout.Header>
+            <Layout.HeaderContent>
+              <DiscoverBreadcrumb
+                eventView={eventView}
+                event={event}
+                organization={organization}
+                location={location}
+                isHomepage={isHomepage}
+              />
+              <EventHeader event={event} />
+            </Layout.HeaderContent>
+            <Layout.HeaderActions>
+              <ButtonBar gap={1}>
+                <Button size="sm" onClick={() => setIsSidebarVisible(prev => !prev)}>
+                  {isSidebarVisible ? 'Hide Details' : 'Show Details'}
+                </Button>
+                <Button
+                  size="sm"
+                  icon={<IconOpen />}
+                  href={eventJsonUrl}
+                  external
+                  onClick={() =>
+                    trackAnalytics('performance_views.event_details.json_button_click', {
+                      organization,
+                    })
+                  }
+                >
+                  {t('JSON')} (<FileSize bytes={event.size} />)
+                </Button>
+                {hasProfilingFeature && event.type === 'transaction' && (
+                  <TransactionToProfileButton event={event} projectSlug={projectId} />
+                )}
+                {transactionSummaryTarget && (
+                  <Feature organization={organization} features="performance-view">
+                    {({hasFeature}) => (
+                      <Button
+                        size="sm"
+                        disabled={!hasFeature}
+                        priority="primary"
+                        to={transactionSummaryTarget}
+                      >
+                        {t('Go to Summary')}
+                      </Button>
+                    )}
+                  </Feature>
+                )}
+              </ButtonBar>
+            </Layout.HeaderActions>
+          </Layout.Header>
+          <Layout.Body>
+            <Layout.Main fullWidth>
+              <EventMetas
+                quickTrace={results ?? null}
+                meta={metaResults?.meta ?? null}
+                event={event}
+                organization={organization}
+                projectId={projectId}
+                location={location}
+                errorDest="discover"
+                transactionDest="discover"
+              />
+            </Layout.Main>
+            <Layout.Main fullWidth={!isSidebarVisible}>
+              <Projects orgId={organization.slug} slugs={[projectId]}>
+                {({projects, initiallyLoaded}) =>
+                  initiallyLoaded ? (
+                    <SpanEntryContext.Provider
+                      value={{
+                        getViewChildTransactionTarget: childTransactionProps => {
+                          const childTransactionLink = eventDetailsRoute({
+                            eventSlug: childTransactionProps.eventSlug,
+                            orgSlug: organization.slug,
+                          });
+
+                          return {
+                            pathname: childTransactionLink,
+                            query: eventView.generateQueryStringObject(),
+                          };
+                        },
+                      }}
+                    >
+                      <QuickTraceContext.Provider value={results}>
+                        {hasProfilingFeature ? (
+                          <ProfilesProvider
+                            orgSlug={organization.slug}
+                            projectSlug={projectId}
+                            profileId={profileId || ''}
+                          >
+                            <ProfileContext.Consumer>
+                              {profiles => (
+                                <ProfileGroupProvider
+                                  type="flamechart"
+                                  input={
+                                    profiles?.type === 'resolved' ? profiles.data : null
+                                  }
+                                  traceID={profileId || ''}
+                                >
+                                  <BorderlessEventEntries
+                                    organization={organization}
+                                    event={event}
+                                    project={projects[0] as Project}
+                                    showTagSummary={false}
+                                  />
+                                </ProfileGroupProvider>
+                              )}
+                            </ProfileContext.Consumer>
+                          </ProfilesProvider>
+                        ) : (
+                          <BorderlessEventEntries
+                            organization={organization}
+                            event={event}
+                            project={projects[0] as Project}
+                            showTagSummary={false}
+                          />
+                        )}
+                      </QuickTraceContext.Provider>
+                    </SpanEntryContext.Provider>
+                  ) : (
+                    <LoadingIndicator />
+                  )
+                }
+              </Projects>
+            </Layout.Main>
+            {isSidebarVisible && (
+              <Layout.Side>
+                <EventVitals event={event} />
+                <EventCustomPerformanceMetrics
                   event={event}
-                  organization={organization}
                   location={location}
+                  organization={organization}
                   isHomepage={isHomepage}
                 />
-                <EventHeader event={event} />
-              </Layout.HeaderContent>
-              <Layout.HeaderActions>
-                <ButtonBar gap={1}>
-                  <Button size="sm" onClick={() => setIsSidebarVisible(prev => !prev)}>
-                    {isSidebarVisible ? 'Hide Details' : 'Show Details'}
-                  </Button>
-                  <Button
-                    size="sm"
-                    icon={<IconOpen />}
-                    href={eventJsonUrl}
-                    external
-                    onClick={() =>
-                      trackAnalytics(
-                        'performance_views.event_details.json_button_click',
-                        {
-                          organization,
-                        }
-                      )
-                    }
-                  >
-                    {t('JSON')} (<FileSize bytes={event.size} />)
-                  </Button>
-                  {hasProfilingFeature && event.type === 'transaction' && (
-                    <TransactionToProfileButton event={event} projectSlug={projectId} />
-                  )}
-                  {transactionSummaryTarget && (
-                    <Feature organization={organization} features="performance-view">
-                      {({hasFeature}) => (
-                        <Button
-                          size="sm"
-                          disabled={!hasFeature}
-                          priority="primary"
-                          to={transactionSummaryTarget}
-                        >
-                          {t('Go to Summary')}
-                        </Button>
-                      )}
-                    </Feature>
-                  )}
-                </ButtonBar>
-              </Layout.HeaderActions>
-            </Layout.Header>
-            <Layout.Body>
-              <Layout.Main fullWidth>
-                <EventMetas
-                  quickTrace={results ?? null}
-                  meta={metaResults?.meta ?? null}
+                {event.groupID && (
+                  <LinkedIssue groupId={event.groupID} eventId={event.eventID} />
+                )}
+                <TagsTable
+                  generateUrl={generateTagUrl}
                   event={event}
-                  organization={organization}
-                  projectId={projectId}
-                  location={location}
-                  errorDest="discover"
-                  transactionDest="discover"
+                  query={eventView.query}
                 />
-              </Layout.Main>
-              <Layout.Main fullWidth={!isSidebarVisible}>
-                <Projects orgId={organization.slug} slugs={[projectId]}>
-                  {({projects, initiallyLoaded}) =>
-                    initiallyLoaded ? (
-                      <SpanEntryContext.Provider
-                        value={{
-                          getViewChildTransactionTarget: childTransactionProps => {
-                            const childTransactionLink = eventDetailsRoute({
-                              eventSlug: childTransactionProps.eventSlug,
-                              orgSlug: organization.slug,
-                            });
-
-                            return {
-                              pathname: childTransactionLink,
-                              query: eventView.generateQueryStringObject(),
-                            };
-                          },
-                        }}
-                      >
-                        <QuickTraceContext.Provider value={results}>
-                          {hasProfilingFeature ? (
-                            <ProfilesProvider
-                              orgSlug={organization.slug}
-                              projectSlug={projectId}
-                              profileId={profileId || ''}
-                            >
-                              <ProfileContext.Consumer>
-                                {profiles => (
-                                  <ProfileGroupProvider
-                                    type="flamechart"
-                                    input={
-                                      profiles?.type === 'resolved' ? profiles.data : null
-                                    }
-                                    traceID={profileId || ''}
-                                  >
-                                    <BorderlessEventEntries
-                                      organization={organization}
-                                      event={event}
-                                      project={projects[0] as Project}
-                                      showTagSummary={false}
-                                    />
-                                  </ProfileGroupProvider>
-                                )}
-                              </ProfileContext.Consumer>
-                            </ProfilesProvider>
-                          ) : (
-                            <BorderlessEventEntries
-                              organization={organization}
-                              event={event}
-                              project={projects[0] as Project}
-                              showTagSummary={false}
-                            />
-                          )}
-                        </QuickTraceContext.Provider>
-                      </SpanEntryContext.Provider>
-                    ) : (
-                      <LoadingIndicator />
-                    )
-                  }
-                </Projects>
-              </Layout.Main>
-              {isSidebarVisible && (
-                <Layout.Side>
-                  <EventVitals event={event} />
-                  <EventCustomPerformanceMetrics
-                    event={event}
-                    location={location}
-                    organization={organization}
-                    isHomepage={isHomepage}
-                  />
-                  {event.groupID && (
-                    <LinkedIssue groupId={event.groupID} eventId={event.eventID} />
-                  )}
-                  <TagsTable
-                    generateUrl={generateTagUrl}
-                    event={event}
-                    query={eventView.query}
-                  />
-                </Layout.Side>
-              )}
-            </Layout.Body>
-          </TransactionProfileIdProvider>
-        </TraceDetailsRouting>
+              </Layout.Side>
+            )}
+          </Layout.Body>
+        </TransactionProfileIdProvider>
       );
     };
 
@@ -302,23 +297,25 @@ function EventDetailsContent(props: Props) {
       const {start, end} = getTraceTimeRangeFromEvent(event);
 
       return (
-        <TraceMetaQuery
-          location={location}
-          orgSlug={organization.slug}
-          traceId={traceId}
-          start={start}
-          end={end}
-        >
-          {metaResults => (
-            <QuickTraceQuery
-              event={event}
-              location={location}
-              orgSlug={organization.slug}
-            >
-              {results => render(results, metaResults)}
-            </QuickTraceQuery>
-          )}
-        </TraceMetaQuery>
+        <TraceDetailsRouting event={event}>
+          <TraceMetaQuery
+            location={location}
+            orgSlug={organization.slug}
+            traceId={traceId}
+            start={start}
+            end={end}
+          >
+            {metaResults => (
+              <QuickTraceQuery
+                event={event}
+                location={location}
+                orgSlug={organization.slug}
+              >
+                {results => render(results, metaResults)}
+              </QuickTraceQuery>
+            )}
+          </TraceMetaQuery>
+        </TraceDetailsRouting>
       );
     }
 

+ 8 - 21
static/app/views/performance/traceDetails/TraceDetailsRouting.tsx

@@ -2,25 +2,21 @@ import {useEffect} from 'react';
 import {browserHistory} from 'react-router';
 import type {LocationDescriptorObject} from 'history';
 
-import {transactionTargetHash} from 'sentry/components/events/interfaces/spans/utils';
-import LoadingIndicator from 'sentry/components/loadingIndicator';
 import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
+import {getEventTimestamp} from 'sentry/components/quickTrace/utils';
 import type {Event} from 'sentry/types';
-import type {TraceMetaQueryChildrenProps} from 'sentry/utils/performance/quickTrace/traceMetaQuery';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
 
-import {DEFAULT_TRACE_ROWS_LIMIT} from './limitExceededMessage';
 import {getTraceDetailsUrl} from './utils';
 
 type Props = {
   children: JSX.Element;
   event: Event;
-  metaResults: TraceMetaQueryChildrenProps | undefined;
 };
 
 function TraceDetailsRouting(props: Props) {
-  const {metaResults, event, children} = props;
+  const {event, children} = props;
   const organization = useOrganization();
   const location = useLocation();
   const datetimeSelection = normalizeDateTimeParams(location.query);
@@ -28,38 +24,29 @@ function TraceDetailsRouting(props: Props) {
   useEffect(() => {
     const traceId = event.contexts?.trace?.trace_id ?? '';
 
-    if (organization.features.includes('performance-trace-details')) {
+    if (organization.features.includes('trace-view-v1')) {
       if (event?.groupID && event?.eventID) {
         const issuesLocation = `/organizations/${organization.slug}/issues/${event.groupID}/events/${event.eventID}`;
         browserHistory.replace({
           pathname: issuesLocation,
         });
-      } else if (
-        metaResults?.meta &&
-        metaResults?.meta.transactions <= DEFAULT_TRACE_ROWS_LIMIT
-      ) {
+      } else {
         const traceDetailsLocation: LocationDescriptorObject = getTraceDetailsUrl(
           organization,
           traceId,
           datetimeSelection,
-          location.query
+          location.query,
+          getEventTimestamp(event),
+          event.eventID
         );
 
         browserHistory.replace({
           pathname: traceDetailsLocation.pathname,
           query: traceDetailsLocation.query,
-          hash: transactionTargetHash(event.eventID) + location.hash,
         });
       }
     }
-  }, [event, metaResults, location, organization, datetimeSelection]);
-
-  if (
-    metaResults?.isLoading &&
-    organization.features.includes('performance-trace-details')
-  ) {
-    return <LoadingIndicator />;
-  }
+  }, [event, location, organization, datetimeSelection]);
 
   return children;
 }

+ 170 - 170
static/app/views/performance/transactionDetails/content.tsx

@@ -131,177 +131,175 @@ function EventDetailsContent(props: Props) {
         end={end}
       >
         {metaResults => (
-          <TraceDetailsRouting event={transaction} metaResults={metaResults}>
-            <QuickTraceQuery
-              event={transaction}
-              location={location}
-              orgSlug={organization.slug}
-            >
-              {results => (
-                <TransactionProfileIdProvider
-                  projectId={transaction.projectID}
-                  transactionId={
-                    transaction.type === 'transaction' ? transaction.id : undefined
-                  }
-                  timestamp={transaction.dateReceived}
-                >
-                  <Layout.Header>
-                    <Layout.HeaderContent>
-                      <Breadcrumb
-                        organization={organization}
-                        location={location}
-                        transaction={{
-                          project: transaction.projectID,
-                          name: transactionName,
-                        }}
-                        eventSlug={eventSlug}
-                      />
-                      <Layout.Title data-test-id="event-header">
-                        <Tooltip showOnlyOnOverflow skipWrapper title={transactionName}>
-                          <EventTitle>{transaction.title}</EventTitle>
-                        </Tooltip>
-                        {originatingUrl && (
-                          <Button
-                            aria-label={t('Go to originating URL')}
-                            size="zero"
-                            icon={<IconOpen />}
-                            href={originatingUrl}
-                            external
-                            translucentBorder
-                            borderless
-                          />
-                        )}
-                      </Layout.Title>
-                    </Layout.HeaderContent>
-                    <Layout.HeaderActions>
-                      <ButtonBar gap={1}>
+          <QuickTraceQuery
+            event={transaction}
+            location={location}
+            orgSlug={organization.slug}
+          >
+            {results => (
+              <TransactionProfileIdProvider
+                projectId={transaction.projectID}
+                transactionId={
+                  transaction.type === 'transaction' ? transaction.id : undefined
+                }
+                timestamp={transaction.dateReceived}
+              >
+                <Layout.Header>
+                  <Layout.HeaderContent>
+                    <Breadcrumb
+                      organization={organization}
+                      location={location}
+                      transaction={{
+                        project: transaction.projectID,
+                        name: transactionName,
+                      }}
+                      eventSlug={eventSlug}
+                    />
+                    <Layout.Title data-test-id="event-header">
+                      <Tooltip showOnlyOnOverflow skipWrapper title={transactionName}>
+                        <EventTitle>{transaction.title}</EventTitle>
+                      </Tooltip>
+                      {originatingUrl && (
+                        <Button
+                          aria-label={t('Go to originating URL')}
+                          size="zero"
+                          icon={<IconOpen />}
+                          href={originatingUrl}
+                          external
+                          translucentBorder
+                          borderless
+                        />
+                      )}
+                    </Layout.Title>
+                  </Layout.HeaderContent>
+                  <Layout.HeaderActions>
+                    <ButtonBar gap={1}>
+                      <Button
+                        size="sm"
+                        onClick={() => setIsSidebarVisible(prev => !prev)}
+                      >
+                        {isSidebarVisible ? 'Hide Details' : 'Show Details'}
+                      </Button>
+                      {results && (
                         <Button
                           size="sm"
-                          onClick={() => setIsSidebarVisible(prev => !prev)}
+                          icon={<IconOpen />}
+                          href={eventJsonUrl}
+                          external
                         >
-                          {isSidebarVisible ? 'Hide Details' : 'Show Details'}
+                          {t('JSON')} (<FileSize bytes={transaction.size} />)
                         </Button>
-                        {results && (
-                          <Button
-                            size="sm"
-                            icon={<IconOpen />}
-                            href={eventJsonUrl}
-                            external
-                          >
-                            {t('JSON')} (<FileSize bytes={transaction.size} />)
-                          </Button>
-                        )}
-                        {hasProfilingFeature && isTransaction(transaction) && (
-                          <TransactionToProfileButton
-                            event={transaction}
-                            projectSlug={projectId}
-                          />
-                        )}
-                      </ButtonBar>
-                    </Layout.HeaderActions>
-                  </Layout.Header>
-                  <Layout.Body>
-                    {results && (
-                      <Layout.Main fullWidth>
-                        <EventMetas
-                          quickTrace={results}
-                          meta={metaResults?.meta ?? null}
+                      )}
+                      {hasProfilingFeature && isTransaction(transaction) && (
+                        <TransactionToProfileButton
                           event={transaction}
-                          organization={organization}
-                          projectId={projectId}
-                          location={location}
-                          errorDest="issue"
-                          transactionDest="performance"
+                          projectSlug={projectId}
                         />
-                      </Layout.Main>
-                    )}
-                    <Layout.Main fullWidth={!isSidebarVisible}>
-                      <Projects orgId={organization.slug} slugs={[projectId]}>
-                        {({projects: _projects}) => (
-                          <SpanEntryContext.Provider
-                            value={{
-                              getViewChildTransactionTarget: childTransactionProps => {
-                                return getTransactionDetailsUrl(
-                                  organization.slug,
-                                  childTransactionProps.eventSlug,
-                                  childTransactionProps.transaction,
-                                  location.query
-                                );
-                              },
-                            }}
-                          >
-                            <QuickTraceContext.Provider value={results}>
-                              {hasProfilingFeature ? (
-                                <ProfilesProvider
-                                  orgSlug={organization.slug}
-                                  projectSlug={projectId}
-                                  profileId={profileId || ''}
-                                >
-                                  <ProfileContext.Consumer>
-                                    {profiles => (
-                                      <ProfileGroupProvider
-                                        type="flamechart"
-                                        input={
-                                          profiles?.type === 'resolved'
-                                            ? profiles.data
-                                            : null
-                                        }
-                                        traceID={profileId || ''}
-                                      >
-                                        <BorderlessEventEntries
-                                          organization={organization}
-                                          event={event}
-                                          project={_projects[0] as Project}
-                                          showTagSummary={false}
-                                        />
-                                      </ProfileGroupProvider>
-                                    )}
-                                  </ProfileContext.Consumer>
-                                </ProfilesProvider>
-                              ) : (
-                                <BorderlessEventEntries
-                                  organization={organization}
-                                  event={event}
-                                  project={_projects[0] as Project}
-                                  showTagSummary={false}
-                                />
-                              )}
-                            </QuickTraceContext.Provider>
-                          </SpanEntryContext.Provider>
-                        )}
-                      </Projects>
+                      )}
+                    </ButtonBar>
+                  </Layout.HeaderActions>
+                </Layout.Header>
+                <Layout.Body>
+                  {results && (
+                    <Layout.Main fullWidth>
+                      <EventMetas
+                        quickTrace={results}
+                        meta={metaResults?.meta ?? null}
+                        event={transaction}
+                        organization={organization}
+                        projectId={projectId}
+                        location={location}
+                        errorDest="issue"
+                        transactionDest="performance"
+                      />
                     </Layout.Main>
-                    {isSidebarVisible && (
-                      <Layout.Side>
-                        {results === undefined && (
-                          <Fragment>
-                            <EventMetadata
-                              event={transaction}
-                              organization={organization}
-                              projectId={projectId}
-                            />
-                            <RootSpanStatus event={transaction} />
-                          </Fragment>
-                        )}
-                        <EventVitals event={transaction} />
-                        <EventCustomPerformanceMetrics
-                          event={transaction}
-                          location={location}
-                          organization={organization}
-                          source={EventDetailPageSource.PERFORMANCE}
-                        />
-                        <TagsTable
-                          event={transaction}
-                          query={query}
-                          generateUrl={generateTagUrl}
-                        />
-                      </Layout.Side>
-                    )}
-                  </Layout.Body>
-                </TransactionProfileIdProvider>
-              )}
-            </QuickTraceQuery>
-          </TraceDetailsRouting>
+                  )}
+                  <Layout.Main fullWidth={!isSidebarVisible}>
+                    <Projects orgId={organization.slug} slugs={[projectId]}>
+                      {({projects: _projects}) => (
+                        <SpanEntryContext.Provider
+                          value={{
+                            getViewChildTransactionTarget: childTransactionProps => {
+                              return getTransactionDetailsUrl(
+                                organization.slug,
+                                childTransactionProps.eventSlug,
+                                childTransactionProps.transaction,
+                                location.query
+                              );
+                            },
+                          }}
+                        >
+                          <QuickTraceContext.Provider value={results}>
+                            {hasProfilingFeature ? (
+                              <ProfilesProvider
+                                orgSlug={organization.slug}
+                                projectSlug={projectId}
+                                profileId={profileId || ''}
+                              >
+                                <ProfileContext.Consumer>
+                                  {profiles => (
+                                    <ProfileGroupProvider
+                                      type="flamechart"
+                                      input={
+                                        profiles?.type === 'resolved'
+                                          ? profiles.data
+                                          : null
+                                      }
+                                      traceID={profileId || ''}
+                                    >
+                                      <BorderlessEventEntries
+                                        organization={organization}
+                                        event={event}
+                                        project={_projects[0] as Project}
+                                        showTagSummary={false}
+                                      />
+                                    </ProfileGroupProvider>
+                                  )}
+                                </ProfileContext.Consumer>
+                              </ProfilesProvider>
+                            ) : (
+                              <BorderlessEventEntries
+                                organization={organization}
+                                event={event}
+                                project={_projects[0] as Project}
+                                showTagSummary={false}
+                              />
+                            )}
+                          </QuickTraceContext.Provider>
+                        </SpanEntryContext.Provider>
+                      )}
+                    </Projects>
+                  </Layout.Main>
+                  {isSidebarVisible && (
+                    <Layout.Side>
+                      {results === undefined && (
+                        <Fragment>
+                          <EventMetadata
+                            event={transaction}
+                            organization={organization}
+                            projectId={projectId}
+                          />
+                          <RootSpanStatus event={transaction} />
+                        </Fragment>
+                      )}
+                      <EventVitals event={transaction} />
+                      <EventCustomPerformanceMetrics
+                        event={transaction}
+                        location={location}
+                        organization={organization}
+                        source={EventDetailPageSource.PERFORMANCE}
+                      />
+                      <TagsTable
+                        event={transaction}
+                        query={query}
+                        generateUrl={generateTagUrl}
+                      />
+                    </Layout.Side>
+                  )}
+                </Layout.Body>
+              </TransactionProfileIdProvider>
+            )}
+          </QuickTraceQuery>
         )}
       </TraceMetaQuery>
     );
@@ -316,12 +314,14 @@ function EventDetailsContent(props: Props) {
     );
 
     return (
-      <Fragment>
-        {isSampleTransaction && (
-          <FinishSetupAlert organization={organization} projectId={projectId} />
-        )}
-        {renderContent(event)}
-      </Fragment>
+      <TraceDetailsRouting event={event}>
+        <Fragment>
+          {isSampleTransaction && (
+            <FinishSetupAlert organization={organization} projectId={projectId} />
+          )}
+          {renderContent(event)}
+        </Fragment>
+      </TraceDetailsRouting>
     );
   }