Browse Source

feat(perf): Trends and vitals widget links should navigate to transaction summary (#44162)

- Trends landing page widget currently redirects users to the trends
page. This might not be the most useful action for users since they've
already clicked on a specific transaction so they might want to see the
Transaction Summary page. Now, all trends widget transaction links
navigate to the transaction summary page with `tpm` and `duration`
filters pre-populated for consistency with the old flow.
- Vitals widget links would take users to the Vital Details page view
that was filtered only for that specific transaction. This is also a
superfluous step. Now transaction links navigate to the transaction
summary with display set to vitals view.
- Moved `getProjectID` function to the `performance` utils since I saw
it duplicated in a different spots in the code.

Fixes PERF-1946, PERF-1947

---------

Co-authored-by: Scott Cooper <scttcper@gmail.com>
Dameli Ushbayeva 2 years ago
parent
commit
87da975d25

+ 2 - 17
static/app/views/alerts/rules/metric/details/relatedTransactions.tsx

@@ -13,32 +13,17 @@ import DiscoverQuery, {
   TableData,
   TableDataRow,
 } from 'sentry/utils/discover/discoverQuery';
-import EventView, {EventData} from 'sentry/utils/discover/eventView';
+import EventView from 'sentry/utils/discover/eventView';
 import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
 import {fieldAlignment} from 'sentry/utils/discover/fields';
 import type {MetricRule} from 'sentry/views/alerts/rules/metric/types';
 import {getMetricRuleDiscoverQuery} from 'sentry/views/alerts/utils/getMetricRuleDiscoverUrl';
 import type {TableColumn} from 'sentry/views/discover/table/types';
 import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils';
+import {getProjectID} from 'sentry/views/performance/utils';
 
 import type {TimePeriodType} from './constants';
 
-function getProjectID(eventData: EventData, projects: Project[]): string | undefined {
-  const projectSlug = (eventData?.project as string) || undefined;
-
-  if (typeof projectSlug === undefined) {
-    return undefined;
-  }
-
-  const project = projects.find(currentProject => currentProject.slug === projectSlug);
-
-  if (!project) {
-    return undefined;
-  }
-
-  return project.id;
-}
-
 type TableProps = {
   eventView: EventView;
   location: Location;

+ 25 - 1
static/app/views/performance/landing/widgets/widgets/trendsWidget.tsx

@@ -9,8 +9,13 @@ import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import useProjects from 'sentry/utils/useProjects';
 import withProjects from 'sentry/utils/withProjects';
+import {
+  DisplayModes,
+  transactionSummaryRouteWithQuery,
+} from 'sentry/views/performance/transactionSummary/utils';
 import {CompareDurations} from 'sentry/views/performance/trends/changedTransactions';
 import {
+  getProjectID,
   getSelectedProjectPlatforms,
   handleTrendsClick,
   trendsTargetRoute,
@@ -130,9 +135,28 @@ export function TrendsWidget(props: PerformanceWidgetProps) {
           statsPeriod: eventView.statsPeriod || DEFAULT_STATS_PERIOD,
         },
       });
+
+      const transactionTarget = transactionSummaryRouteWithQuery({
+        orgSlug: props.organization.slug,
+        projectID: getProjectID(listItem, projects),
+        transaction: listItem.transaction,
+        query: trendsTarget.query,
+        additionalQuery: {
+          display: DisplayModes.TREND,
+          trendFunction: trendFunctionField,
+          statsPeriod: eventView.statsPeriod || DEFAULT_STATS_PERIOD,
+        },
+      });
+
+      const target = organization.features.includes(
+        'performance-metrics-backed-transaction-summary'
+      )
+        ? transactionTarget
+        : trendsTarget;
+
       return (
         <Fragment>
-          <GrowLink to={trendsTarget}>
+          <GrowLink to={target}>
             <Truncate value={listItem.transaction} maxLength={40} />
           </GrowLink>
           <RightAlignedCell>

+ 20 - 4
static/app/views/performance/landing/widgets/widgets/vitalWidget.tsx

@@ -22,6 +22,10 @@ import {decodeList} from 'sentry/utils/queryString';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import withApi from 'sentry/utils/withApi';
+import {
+  DisplayModes,
+  transactionSummaryRouteWithQuery,
+} from 'sentry/views/performance/transactionSummary/utils';
 import {
   createUnnamedTransactionsDiscoverTarget,
   UNPARAMETERIZED_TRANSACTION,
@@ -247,10 +251,15 @@ export function VitalWidget(props: PerformanceWidgetProps) {
       _eventView.query = initialConditions.formatString();
 
       const isUnparameterizedRow = transaction === UNPARAMETERIZED_TRANSACTION;
-      const target = isUnparameterizedRow
-        ? createUnnamedTransactionsDiscoverTarget({
-            organization,
-            location,
+      const transactionTarget = organization.features.includes(
+        'performance-metrics-backed-transaction-summary'
+      )
+        ? transactionSummaryRouteWithQuery({
+            orgSlug: props.organization.slug,
+            projectID: listItem['project.id'],
+            transaction: listItem.transaction,
+            query: _eventView.generateQueryStringObject(),
+            display: DisplayModes.VITALS,
           })
         : vitalDetailRouteWithQuery({
             orgSlug: organization.slug,
@@ -259,6 +268,13 @@ export function VitalWidget(props: PerformanceWidgetProps) {
             projectID: decodeList(location.query.project),
           });
 
+      const target = isUnparameterizedRow
+        ? createUnnamedTransactionsDiscoverTarget({
+            organization,
+            location,
+          })
+        : transactionTarget;
+
       const data = {
         [settingToVital[props.chartSetting]]: getVitalDataForListItem(
           listItem,

+ 2 - 24
static/app/views/performance/table.tsx

@@ -23,11 +23,7 @@ import DiscoverQuery, {
   TableData,
   TableDataRow,
 } from 'sentry/utils/discover/discoverQuery';
-import EventView, {
-  EventData,
-  isFieldSortable,
-  MetaType,
-} from 'sentry/utils/discover/eventView';
+import EventView, {isFieldSortable, MetaType} from 'sentry/utils/discover/eventView';
 import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
 import {fieldAlignment, getAggregateAlias} from 'sentry/utils/discover/fields';
 import {MEPConsumer} from 'sentry/utils/performance/contexts/metricsEnhancedSetting';
@@ -46,29 +42,11 @@ import {
 import {COLUMN_TITLES} from './data';
 import {
   createUnnamedTransactionsDiscoverTarget,
+  getProjectID,
   getSelectedProjectPlatforms,
   UNPARAMETERIZED_TRANSACTION,
 } from './utils';
 
-export function getProjectID(
-  eventData: EventData,
-  projects: Project[]
-): string | undefined {
-  const projectSlug = (eventData?.project as string) || undefined;
-
-  if (typeof projectSlug === undefined) {
-    return undefined;
-  }
-
-  const project = projects.find(currentProject => currentProject.slug === projectSlug);
-
-  if (!project) {
-    return undefined;
-  }
-
-  return project.id;
-}
-
 type Props = {
   eventView: EventView;
   location: Location;

+ 2 - 21
static/app/views/performance/transactionSummary/transactionEvents/eventsTable.tsx

@@ -16,14 +16,14 @@ import QuestionTooltip from 'sentry/components/questionTooltip';
 import ReplayIdCountProvider from 'sentry/components/replays/replayIdCountProvider';
 import {Tooltip} from 'sentry/components/tooltip';
 import {t, tct} from 'sentry/locale';
-import {IssueAttachment, Organization, Project} from 'sentry/types';
+import {IssueAttachment, Organization} from 'sentry/types';
 import {defined} from 'sentry/utils';
 import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
 import DiscoverQuery, {
   TableData,
   TableDataRow,
 } from 'sentry/utils/discover/discoverQuery';
-import EventView, {EventData, isFieldSortable} from 'sentry/utils/discover/eventView';
+import EventView, {isFieldSortable} from 'sentry/utils/discover/eventView';
 import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
 import {
   fieldAlignment,
@@ -46,25 +46,6 @@ import {
 
 import OperationSort, {TitleProps} from './operationSort';
 
-export function getProjectID(
-  eventData: EventData,
-  projects: Project[]
-): string | undefined {
-  const projectSlug = (eventData?.project as string) || undefined;
-
-  if (typeof projectSlug === undefined) {
-    return undefined;
-  }
-
-  const project = projects.find(currentProject => currentProject.slug === projectSlug);
-
-  if (!project) {
-    return undefined;
-  }
-
-  return project.id;
-}
-
 function OperationTitle({onClick}: TitleProps) {
   return (
     <div onClick={onClick}>

+ 14 - 1
static/app/views/performance/utils.tsx

@@ -14,7 +14,7 @@ import {
 } from 'sentry/types';
 import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
 import {statsPeriodToDays} from 'sentry/utils/dates';
-import EventView from 'sentry/utils/discover/eventView';
+import EventView, {EventData} from 'sentry/utils/discover/eventView';
 import {TRACING_FIELDS} from 'sentry/utils/discover/fields';
 import {getDuration} from 'sentry/utils/formatters';
 import getCurrentSentryReactTransaction from 'sentry/utils/getCurrentSentryReactTransaction';
@@ -344,3 +344,16 @@ export function getSelectedProjectPlatforms(location: Location, projects: Projec
   const selectedProjectPlatforms = getSelectedProjectPlatformsArray(location, projects);
   return selectedProjectPlatforms.join(', ');
 }
+
+export function getProjectID(
+  eventData: EventData,
+  projects: Project[]
+): string | undefined {
+  const projectSlug = (eventData?.project as string) || undefined;
+
+  if (typeof projectSlug === undefined) {
+    return undefined;
+  }
+
+  return projects.find(currentProject => currentProject.slug === projectSlug)?.id;
+}

+ 1 - 21
static/app/views/performance/vitalDetail/table.tsx

@@ -16,7 +16,6 @@ import {t} from 'sentry/locale';
 import {Organization, Project} from 'sentry/types';
 import {trackAnalyticsEvent} from 'sentry/utils/analytics';
 import EventView, {
-  EventData,
   EventsMetaType,
   isFieldSortable,
 } from 'sentry/utils/discover/eventView';
@@ -37,7 +36,7 @@ import {
   transactionSummaryRouteWithQuery,
 } from 'sentry/views/performance/transactionSummary/utils';
 
-import {getSelectedProjectPlatforms} from '../utils';
+import {getProjectID, getSelectedProjectPlatforms} from '../utils';
 
 import {
   getVitalDetailTableMehStatusFunction,
@@ -62,25 +61,6 @@ const getTableColumnTitle = (index: number, vitalName: WebVital) => {
   return titles[index];
 };
 
-export function getProjectID(
-  eventData: EventData,
-  projects: Project[]
-): string | undefined {
-  const projectSlug = (eventData?.project as string) || undefined;
-
-  if (typeof projectSlug === undefined) {
-    return undefined;
-  }
-
-  const project = projects.find(currentProject => currentProject.slug === projectSlug);
-
-  if (!project) {
-    return undefined;
-  }
-
-  return project.id;
-}
-
 type Props = {
   eventView: EventView;
   location: Location;