Browse Source

ref(insights): Dynamically generate module URLs everywhere (#70973)

## tl;dr

Right now: Hardcoded URLs like
`/organization/${slug}/performance/browser/resources/spans/`
With this PR: `${moduleURL}/spans/`

## Context

`useModuleURL` and its more specific siblings like
`useResourcesModuleURL` check some config variables (the current base
URL of Insights, and the current base URL of the relevant module) and
generate the prefix automatically.

This is great because:

1. Easier to change URLs. e.g., if we rename a module (happens pretty
often), the config variable change is the only thing needed
2. Easier to feature-flag URLs. e.g., when we move insights to
`/insights/` I can generate the base URL based on a feature flag

I went through the app and tried to find every single instance of a
hard-coded URL and replaced it with this module URL helper.

## Addendum on `baseURL`

You might be wondering "what about `baseURL`"? I'm getting rid of it. As
of this PR, `baseURL` is no longer respected by anything. The only
modules that respected it were Resources and Queries, and only in one
spot

`baseURL` made sense when a single module had to be routed in _multiple
contexts at the same time_ (e.g., when `/starfish/database` and
`/performance/database` _both_ had to work) but that's no longer true. I
hate `baseURL` because of its spooky action at a distance. You
misconfigure `baseURL` in one spot, and URLs break somewhere far away.
That's no way to live.

I'll delete `RoutingContext` very soon.
George Gritsouk 9 months ago
parent
commit
15c926a27d

+ 6 - 5
static/app/views/aiMonitoring/PipelinesTable.tsx

@@ -25,7 +25,7 @@ import {decodeScalar, decodeSorts} from 'sentry/utils/queryString';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
-import {normalizeUrl} from 'sentry/utils/withDomainRequired';
+import {useAIModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
 import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover';
 import type {SpanMetricsResponse} from 'sentry/views/starfish/types';
@@ -91,6 +91,8 @@ export function isAValidSort(sort: Sort): sort is ValidSort {
 
 export function PipelinesTable() {
   const location = useLocation();
+  const moduleURL = useAIModuleURL();
+
   const organization = useOrganization();
   const cursor = decodeScalar(location.query?.[QueryParameterNames.SPANS_CURSOR]);
   const sortField = decodeScalar(location.query?.[QueryParameterNames.SPANS_SORT]);
@@ -205,7 +207,7 @@ export function PipelinesTable() {
                 sortParameterName: QueryParameterNames.SPANS_SORT,
               }),
             renderBodyCell: (column, row) =>
-              renderBodyCell(column, row, meta, location, organization),
+              renderBodyCell(moduleURL, column, row, meta, location, organization),
           }}
           location={location}
         />
@@ -216,6 +218,7 @@ export function PipelinesTable() {
 }
 
 function renderBodyCell(
+  moduleURL: string,
   column: Column,
   row: Row,
   meta: EventsMetaType | undefined,
@@ -237,9 +240,7 @@ function renderBodyCell(
 
     return (
       <Link
-        to={normalizeUrl(
-          `/organizations/${organization.slug}/ai-monitoring/pipeline-type/${row['span.group']}?${qs.stringify(queryString)}`
-        )}
+        to={`${moduleURL}/pipeline-type/${row['span.group']}?${qs.stringify(queryString)}`}
       >
         {row['span.description']}
       </Link>

+ 3 - 2
static/app/views/aiMonitoring/aiMonitoringDetailsPage.tsx

@@ -14,7 +14,6 @@ import {decodeScalar} from 'sentry/utils/queryString';
 import {MutableSearch} from 'sentry/utils/tokenizeSearch';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
-import {normalizeUrl} from 'sentry/utils/withDomainRequired';
 import {
   NumberOfPipelinesChart,
   PipelineDurationChart,
@@ -25,6 +24,7 @@ import {BASE_URL} from 'sentry/views/aiMonitoring/settings';
 import {MetricReadout} from 'sentry/views/performance/metricReadout';
 import * as ModuleLayout from 'sentry/views/performance/moduleLayout';
 import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
+import {useAIModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover';
 import {
   SpanFunction,
@@ -43,6 +43,7 @@ type Query = {
 };
 
 export function AiMonitoringPage({params}: Props) {
+  const moduleURL = useAIModuleURL();
   const location = useLocation<Query>();
 
   const organization = useOrganization();
@@ -101,7 +102,7 @@ export function AiMonitoringPage({params}: Props) {
                 },
                 {
                   label: spanDescription ?? t('(no name)'),
-                  to: normalizeUrl(`/organizations/${organization.slug}/ai-monitoring`),
+                  to: moduleURL,
                 },
               ]}
             />

+ 8 - 4
static/app/views/performance/browser/resources/resourceSummaryPage/index.tsx

@@ -27,6 +27,10 @@ import RenderBlockingSelector from 'sentry/views/performance/browser/resources/s
 import {ResourceSpanOps} from 'sentry/views/performance/browser/resources/shared/types';
 import {useResourceModuleFilters} from 'sentry/views/performance/browser/resources/utils/useResourceFilters';
 import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
+import {
+  useResourceModuleURL,
+  useWebVitalsModuleURL,
+} from 'sentry/views/performance/utils/useModuleURL';
 import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover';
 import {ModuleName, SpanMetricsField} from 'sentry/views/starfish/types';
 import {SampleList} from 'sentry/views/starfish/views/spanSummaryPage/sampleList';
@@ -42,6 +46,8 @@ const {
 } = SpanMetricsField;
 
 function ResourceSummary() {
+  const resourcesModuleURL = useResourceModuleURL();
+  const webVitalsModuleURL = useWebVitalsModuleURL();
   const organization = useOrganization();
   const {groupId} = useParams();
   const filters = useResourceModuleFilters();
@@ -94,9 +100,7 @@ function ResourceSummary() {
               },
               {
                 label: 'Resources',
-                to: normalizeUrl(
-                  `/organizations/${organization.slug}/performance/browser/resources/`
-                ),
+                to: resourcesModuleURL,
                 preservePageFilters: true,
               },
               {
@@ -145,7 +149,7 @@ function ResourceSummary() {
           <ResourceSummaryCharts groupId={groupId} />
           <ResourceSummaryTable />
           <SampleList
-            transactionRoute="/performance/browser/pageloads/"
+            transactionRoute={webVitalsModuleURL}
             groupId={groupId}
             moduleName={ModuleName.RESOURCE}
             transactionName={transaction as string}

+ 3 - 4
static/app/views/performance/browser/webVitals/components/performanceScoreRingWithTooltips.tsx

@@ -6,7 +6,6 @@ import type {Location} from '@sentry/react/types/types';
 import Link from 'sentry/components/links/link';
 import {t} from 'sentry/locale';
 import {space} from 'sentry/styles/space';
-import type {Organization} from 'sentry/types/organization';
 import type {TableData} from 'sentry/utils/discover/discoverQuery';
 import useMouseTracking from 'sentry/utils/replays/hooks/useMouseTracking';
 import {useLocation} from 'sentry/utils/useLocation';
@@ -17,6 +16,7 @@ import type {
   ProjectScore,
   WebVitals,
 } from 'sentry/views/performance/browser/webVitals/utils/types';
+import {useWebVitalsModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 
 import {ORDER_WITH_INP} from '../performanceScoreChart';
 
@@ -69,14 +69,12 @@ type WebVitalLabelProps = {
   location: Location;
   onHover: (webVital: WebVitals) => void;
   onUnHover: () => void;
-  organization: Organization;
   webVital: WebVitals;
   projectData?: TableData;
   webVitalLabelCoordinates?: WebVitalsLabelCoordinates;
 };
 
 function WebVitalLabel({
-  organization,
   location,
   webVital,
   coordinates,
@@ -86,6 +84,7 @@ function WebVitalLabel({
   inPerformanceWidget,
   projectData,
 }: WebVitalLabelProps) {
+  const moduleURL = useWebVitalsModuleURL();
   const xOffset = webVitalLabelCoordinates?.[webVital]?.x ?? 0;
   const yOffset = webVitalLabelCoordinates?.[webVital]?.y ?? 0;
   const webvitalInfo =
@@ -99,7 +98,7 @@ function WebVitalLabel({
   return (
     <Link
       to={{
-        pathname: `/organizations/${organization.slug}/performance/browser/pageloads/`,
+        pathname: moduleURL,
         query: {
           ...location.query,
           webVital,

+ 4 - 6
static/app/views/performance/browser/webVitals/pageOverview.tsx

@@ -48,6 +48,7 @@ import {
   StyledAlert,
 } from 'sentry/views/performance/browser/webVitals/webVitalsLandingPage';
 import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
+import {useWebVitalsModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 
 import {transactionSummaryRouteWithQuery} from '../../transactionSummary/utils';
 
@@ -76,6 +77,7 @@ function getCurrentTabSelection(selectedTab) {
 }
 
 export function PageOverview() {
+  const moduleURL = useWebVitalsModuleURL();
   const organization = useOrganization();
   const location = useLocation();
   const {projects} = useProjects();
@@ -113,9 +115,7 @@ export function PageOverview() {
 
   if (transaction === undefined) {
     // redirect user to webvitals landing page
-    window.location.href = normalizeUrl(
-      `/organizations/${organization.slug}/performance/browser/pageloads/`
-    );
+    window.location.href = moduleURL;
     return null;
   }
 
@@ -163,9 +163,7 @@ export function PageOverview() {
                 },
                 {
                   label: 'Web Vitals',
-                  to: normalizeUrl(
-                    `/organizations/${organization.slug}/performance/browser/pageloads/`
-                  ),
+                  to: moduleURL,
                   preservePageFilters: true,
                 },
                 ...(transaction ? [{label: 'Page Overview'}] : []),

+ 3 - 3
static/app/views/performance/cache/tables/transactionCell.tsx

@@ -2,7 +2,7 @@ import * as qs from 'query-string';
 
 import Link from 'sentry/components/links/link';
 import {useLocation} from 'sentry/utils/useLocation';
-import {useCacheUrl} from 'sentry/views/performance/cache/utils';
+import {useCacheModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
 
 interface Props {
@@ -12,8 +12,8 @@ interface Props {
 }
 
 export function TransactionCell({project, transaction}: Props) {
+  const moduleURL = useCacheModuleURL();
   const location = useLocation();
-  const cacheUrl = useCacheUrl();
 
   if (!transaction) {
     return NULL_DESCRIPTION;
@@ -27,7 +27,7 @@ export function TransactionCell({project, transaction}: Props) {
 
   return (
     <OverflowEllipsisTextContainer>
-      <Link to={`${cacheUrl}/?${qs.stringify(query)}`}>{transaction}</Link>
+      <Link to={`${moduleURL}/?${qs.stringify(query)}`}>{transaction}</Link>
     </OverflowEllipsisTextContainer>
   );
 }

+ 0 - 8
static/app/views/performance/cache/utils.ts

@@ -1,8 +0,0 @@
-import useOrganization from 'sentry/utils/useOrganization';
-import {normalizeUrl} from 'sentry/utils/withDomainRequired';
-import {CACHE_BASE_URL} from 'sentry/views/performance/cache/settings';
-
-export const useCacheUrl = () => {
-  const {slug} = useOrganization();
-  return normalizeUrl(`/organizations/${slug}${CACHE_BASE_URL}`);
-};

+ 3 - 3
static/app/views/performance/database/databaseSpanSummaryPage.tsx

@@ -26,6 +26,7 @@ import {useSelectedDurationAggregate} from 'sentry/views/performance/database/us
 import {MetricReadout} from 'sentry/views/performance/metricReadout';
 import * as ModuleLayout from 'sentry/views/performance/moduleLayout';
 import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
+import {useDatabaseModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {useSynchronizeCharts} from 'sentry/views/starfish/components/chart';
 import {DatabaseSpanDescription} from 'sentry/views/starfish/components/spanDescription';
 import {getTimeSpentExplanation} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
@@ -47,6 +48,7 @@ type Query = {
 type Props = RouteComponentProps<Query, {groupId: string}>;
 
 export function DatabaseSpanSummaryPage({params}: Props) {
+  const moduleURL = useDatabaseModuleURL();
   const organization = useOrganization();
   const location = useLocation<Query>();
 
@@ -165,9 +167,7 @@ export function DatabaseSpanSummaryPage({params}: Props) {
               },
               {
                 label: 'Queries',
-                to: normalizeUrl(
-                  `/organizations/${organization.slug}/performance/database`
-                ),
+                to: moduleURL,
                 preservePageFilters: true,
               },
               {

+ 6 - 5
static/app/views/performance/database/queryTransactionsTable.tsx

@@ -15,7 +15,7 @@ import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
 import type {Sort} from 'sentry/utils/discover/fields';
 import {useLocation} from 'sentry/utils/useLocation';
 import useOrganization from 'sentry/utils/useOrganization';
-import {normalizeUrl} from 'sentry/utils/withDomainRequired';
+import {useDatabaseModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
 import {OverflowEllipsisTextContainer} from 'sentry/views/starfish/components/textAlign';
 import type {SpanMetricsResponse} from 'sentry/views/starfish/types';
@@ -93,6 +93,7 @@ export function QueryTransactionsTable({
   sort,
   span,
 }: Props) {
+  const moduleURL = useDatabaseModuleURL();
   const location = useLocation();
   const organization = useOrganization();
 
@@ -126,7 +127,7 @@ export function QueryTransactionsTable({
               sortParameterName: QueryParameterNames.TRANSACTIONS_SORT,
             }),
           renderBodyCell: (column, row) =>
-            renderBodyCell(column, row, meta, span, location, organization),
+            renderBodyCell(moduleURL, column, row, meta, span, location, organization),
         }}
         location={location}
       />
@@ -137,6 +138,7 @@ export function QueryTransactionsTable({
 }
 
 function renderBodyCell(
+  moduleURL: string,
   column: Column,
   row: Row,
   meta: EventsMetaType | undefined,
@@ -150,9 +152,8 @@ function renderBodyCell(
         ? `${row['transaction.method']} ${row.transaction}`
         : row.transaction;
 
-    const pathname = normalizeUrl(
-      `/organizations/${organization.slug}/performance/database/spans/span/${encodeURIComponent(span[SpanMetricsField.SPAN_GROUP])}`
-    );
+    const pathname = `${moduleURL}/spans/span/${encodeURIComponent(span[SpanMetricsField.SPAN_GROUP])}`;
+
     const query: {[key: string]: string | undefined} = {
       ...location.query,
       transaction: row.transaction,

+ 3 - 1
static/app/views/performance/http/httpDomainSummaryPage.tsx

@@ -46,6 +46,7 @@ import {
 import {MetricReadout} from 'sentry/views/performance/metricReadout';
 import * as ModuleLayout from 'sentry/views/performance/moduleLayout';
 import {ModulePageProviders} from 'sentry/views/performance/modulePageProviders';
+import {useRequestsModuleURL} from 'sentry/views/performance/utils/useModuleURL';
 import {useSynchronizeCharts} from 'sentry/views/starfish/components/chart';
 import {getTimeSpentExplanation} from 'sentry/views/starfish/components/tableCells/timeSpentCell';
 import {useSpanMetrics} from 'sentry/views/starfish/queries/useDiscover';
@@ -61,6 +62,7 @@ type Query = {
 };
 
 export function HTTPDomainSummaryPage() {
+  const moduleURL = useRequestsModuleURL();
   const location = useLocation<Query>();
   const organization = useOrganization();
   const {projects} = useProjects();
@@ -180,7 +182,7 @@ export function HTTPDomainSummaryPage() {
               },
               {
                 label: MODULE_TITLE,
-                to: normalizeUrl(`/organizations/${organization.slug}/performance/http`),
+                to: moduleURL,
                 preservePageFilters: true,
               },
               {

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