diff --git a/static/app/routes.tsx b/static/app/routes.tsx
index 43c5bc172e41bd..14a5b77d7fddb2 100644
--- a/static/app/routes.tsx
+++ b/static/app/routes.tsx
@@ -2141,7 +2141,6 @@ function buildRoutes(): RouteObject[] {
{
path: 'vitaldetail/',
component: make(() => import('sentry/views/performance/vitalDetail')),
- deprecatedRouteProps: true,
},
traceView,
...insightsRedirectObjects,
diff --git a/static/app/views/performance/vitalDetail/index.spec.tsx b/static/app/views/performance/vitalDetail/index.spec.tsx
index 4ae581ca5b3da3..279fdebc3328b5 100644
--- a/static/app/views/performance/vitalDetail/index.spec.tsx
+++ b/static/app/views/performance/vitalDetail/index.spec.tsx
@@ -13,45 +13,25 @@ import {textWithMarkupMatcher} from 'sentry-test/utils';
import ProjectsStore from 'sentry/stores/projectsStore';
import TeamStore from 'sentry/stores/teamStore';
-import type {InjectedRouter} from 'sentry/types/legacyReactRouter';
import {WebVital} from 'sentry/utils/fields';
import {Browser} from 'sentry/utils/performance/vitals/constants';
import {DEFAULT_STATS_PERIOD} from 'sentry/views/performance/data';
import VitalDetail from 'sentry/views/performance/vitalDetail';
import {vitalSupportedBrowsers} from 'sentry/views/performance/vitalDetail/utils';
+const mockNavigate = jest.fn();
+jest.mock('sentry/utils/useNavigate', () => ({
+ useNavigate: () => mockNavigate,
+}));
+
const organization = OrganizationFixture({
features: ['discover-basic', 'performance-view'],
});
-const {
- organization: org,
- project,
- router,
-} = initializeOrg({
+const {organization: org, project} = initializeOrg({
organization,
- router: {
- location: {
- query: {
- project: '1',
- },
- },
- },
});
-function TestComponent(props: {router?: InjectedRouter} = {}) {
- return (
-
- );
-}
-
const testSupportedBrowserRendering = (webVital: WebVital) => {
Object.values(Browser).forEach(browser => {
const browserElement = screen.getByText(browser);
@@ -224,10 +204,16 @@ describe('Performance > VitalDetail', () => {
});
it('renders basic UI elements', async () => {
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ project: '1',
+ },
+ },
+ },
});
// It shows a search bar
@@ -252,25 +238,34 @@ describe('Performance > VitalDetail', () => {
});
it('triggers a navigation on search', async () => {
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ project: '1',
+ },
+ },
+ },
});
- // Fill out the search box, and submit it.
+ // Clear any navigation calls from initialization
+ mockNavigate.mockClear();
+
+ // Fill out the search box, and submit it
await userEvent.click(
await screen.findByPlaceholderText('Search for events, users, tags, and more')
);
await userEvent.paste('user.email:uhoh*');
- // Check the navigation.
+ // Check the navigation
await waitFor(() => {
- expect(router.push).toHaveBeenCalledTimes(1);
+ expect(mockNavigate).toHaveBeenCalledTimes(1);
});
- expect(router.push).toHaveBeenCalledWith({
- pathname: undefined,
+ expect(mockNavigate).toHaveBeenCalledWith({
+ pathname: '/performance/vitaldetail/',
query: {
project: '1',
statsPeriod: '14d',
@@ -280,20 +275,16 @@ describe('Performance > VitalDetail', () => {
});
it('applies conditions when linking to transaction summary', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- query: 'sometag:value',
+ render(, {
+ organization: org,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ query: 'sometag:value',
+ },
},
},
- };
-
- render(, {
- router: newRouter,
- organization: org,
- deprecatedRouterMocks: true,
});
expect(
@@ -304,7 +295,7 @@ describe('Performance > VitalDetail', () => {
await screen.findByLabelText('See transaction summary of the transaction something')
);
- expect(newRouter.push).toHaveBeenCalledWith({
+ expect(mockNavigate).toHaveBeenCalledWith({
pathname: `/organizations/${organization.slug}/insights/summary/`,
query: {
transaction: 'something',
@@ -325,30 +316,29 @@ describe('Performance > VitalDetail', () => {
});
it('check CLS', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- query: 'anothertag:value',
- vitalName: 'measurements.cls',
+ render(, {
+ organization: org,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ query: 'anothertag:value',
+ vitalName: 'measurements.cls',
+ },
},
},
- };
-
- render(, {
- router: newRouter,
- organization: org,
- deprecatedRouterMocks: true,
});
expect(await screen.findByText('Cumulative Layout Shift')).toBeInTheDocument();
+ // Check cells are not in ms
+ expect(screen.getByText('0.215').closest('td')).toBeInTheDocument();
+
await userEvent.click(
await screen.findByLabelText('See transaction summary of the transaction something')
);
- expect(newRouter.push).toHaveBeenCalledWith({
+ expect(mockNavigate).toHaveBeenCalledWith({
pathname: `/organizations/${organization.slug}/insights/summary/`,
query: {
transaction: 'something',
@@ -366,29 +356,25 @@ describe('Performance > VitalDetail', () => {
trendColumn: undefined,
},
});
-
- // Check cells are not in ms
- expect(screen.getByText('0.215').closest('td')).toBeInTheDocument();
});
it('can switch vitals with dropdown menu', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- project: 1,
- query: 'tag:value',
+ render(, {
+ organization: org,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ project: '1',
+ query: 'tag:value',
+ },
},
},
- };
-
- render(, {
- router: newRouter,
- organization: org,
- deprecatedRouterMocks: true,
});
+ // Clear any navigation calls from initialization
+ mockNavigate.mockClear();
+
const button = screen.getByRole('button', {name: /web vitals: lcp/i});
expect(button).toBeInTheDocument();
await userEvent.click(button);
@@ -397,11 +383,11 @@ describe('Performance > VitalDetail', () => {
expect(menuItem).toBeInTheDocument();
await userEvent.click(menuItem);
- expect(newRouter.push).toHaveBeenCalledTimes(1);
- expect(newRouter.push).toHaveBeenCalledWith({
- pathname: undefined,
+ expect(mockNavigate).toHaveBeenCalledTimes(1);
+ expect(mockNavigate).toHaveBeenCalledWith({
+ pathname: '/performance/vitaldetail/',
query: {
- project: 1,
+ project: '1',
query: 'tag:value',
vitalName: 'measurements.fcp',
},
@@ -409,10 +395,13 @@ describe('Performance > VitalDetail', () => {
});
it('renders LCP vital correctly', async () => {
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ },
+ },
});
expect(await screen.findByText('Largest Contentful Paint')).toBeInTheDocument();
@@ -425,10 +414,13 @@ describe('Performance > VitalDetail', () => {
});
it('correctly renders which browsers support LCP', async () => {
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ },
+ },
});
expect(await screen.findAllByText(/Largest Contentful Paint/)).toHaveLength(2);
@@ -436,20 +428,16 @@ describe('Performance > VitalDetail', () => {
});
it('correctly renders which browsers support CLS', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- vitalName: 'measurements.cls',
+ render(, {
+ organization: org,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ vitalName: 'measurements.cls',
+ },
},
},
- };
-
- render(, {
- router,
- organization: org,
- deprecatedRouterMocks: true,
});
expect(await screen.findAllByText(/Cumulative Layout Shift/)).toHaveLength(2);
@@ -457,25 +445,21 @@ describe('Performance > VitalDetail', () => {
});
it('correctly renders which browsers support FCP', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- vitalName: 'measurements.fcp',
- },
- },
- };
-
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: [],
});
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ vitalName: 'measurements.fcp',
+ },
+ },
+ },
});
expect(await screen.findAllByText(/First Contentful Paint/)).toHaveLength(2);
@@ -483,25 +467,21 @@ describe('Performance > VitalDetail', () => {
});
it('correctly renders which browsers support FID', async () => {
- const newRouter = {
- ...router,
- location: {
- ...router.location,
- query: {
- vitalName: 'measurements.fid',
- },
- },
- };
-
MockApiClient.addMockResponse({
url: `/organizations/${organization.slug}/events/`,
body: [],
});
- render(, {
- router,
+ render(, {
organization: org,
- deprecatedRouterMocks: true,
+ initialRouterConfig: {
+ location: {
+ pathname: '/performance/vitaldetail/',
+ query: {
+ vitalName: 'measurements.fid',
+ },
+ },
+ },
});
expect(await screen.findAllByText(/First Input Delay/)).toHaveLength(2);
diff --git a/static/app/views/performance/vitalDetail/index.tsx b/static/app/views/performance/vitalDetail/index.tsx
index a22add6eca791a..736f688ab8f8b5 100644
--- a/static/app/views/performance/vitalDetail/index.tsx
+++ b/static/app/views/performance/vitalDetail/index.tsx
@@ -7,9 +7,6 @@ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/co
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
import {t} from 'sentry/locale';
import type {PageFilters} from 'sentry/types/core';
-import type {RouteComponentProps} from 'sentry/types/legacyReactRouter';
-import type {Organization} from 'sentry/types/organization';
-import type {Project} from 'sentry/types/project';
import {WebVital} from 'sentry/utils/fields';
import {PerformanceEventViewProvider} from 'sentry/utils/performance/contexts/performanceEventViewContext';
import {decodeScalar} from 'sentry/utils/queryString';
@@ -17,10 +14,11 @@ import useRouteAnalyticsEventNames from 'sentry/utils/routeAnalytics/useRouteAna
import useRouteAnalyticsParams from 'sentry/utils/routeAnalytics/useRouteAnalyticsParams';
import normalizeUrl from 'sentry/utils/url/normalizeUrl';
import useApi from 'sentry/utils/useApi';
+import {useLocation} from 'sentry/utils/useLocation';
import {useNavigate} from 'sentry/utils/useNavigate';
-import withOrganization from 'sentry/utils/withOrganization';
-import withPageFilters from 'sentry/utils/withPageFilters';
-import withProjects from 'sentry/utils/withProjects';
+import useOrganization from 'sentry/utils/useOrganization';
+import usePageFilters from 'sentry/utils/usePageFilters';
+import useProjects from 'sentry/utils/useProjects';
import {generatePerformanceVitalDetailView} from 'sentry/views/performance/data';
import {
addRoutePerformanceContext,
@@ -31,16 +29,13 @@ import {
import VitalDetailContent from './vitalDetailContent';
-type Props = RouteComponentProps & {
- loadingProjects: boolean;
- organization: Organization;
- projects: Project[];
- selection: PageFilters;
-};
-
-function VitalDetail({organization, selection, location, projects, router}: Props) {
+export default function VitalDetail() {
const api = useApi();
const navigate = useNavigate();
+ const location = useLocation();
+ const organization = useOrganization();
+ const {selection} = usePageFilters();
+ const {projects} = useProjects();
useRouteAnalyticsEventNames(
'performance_views.vital_detail.view',
@@ -105,7 +100,6 @@ function VitalDetail({organization, selection, location, projects, router}: Prop
location={location}
organization={organization}
eventView={eventView}
- router={router}
vitalName={vitalName || WebVital.LCP}
api={api}
/>
@@ -115,5 +109,3 @@ function VitalDetail({organization, selection, location, projects, router}: Prop
);
}
-
-export default withPageFilters(withProjects(withOrganization(VitalDetail)));
diff --git a/static/app/views/performance/vitalDetail/vitalDetailContent.tsx b/static/app/views/performance/vitalDetail/vitalDetailContent.tsx
index 7c286c912ead47..a49206da3dda21 100644
--- a/static/app/views/performance/vitalDetail/vitalDetailContent.tsx
+++ b/static/app/views/performance/vitalDetail/vitalDetailContent.tsx
@@ -24,11 +24,8 @@ import {TransactionSearchQueryBuilder} from 'sentry/components/performance/trans
import {IconCheckmark, IconClose} from 'sentry/icons';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
-import type {InjectedRouter} from 'sentry/types/legacyReactRouter';
import type {Organization} from 'sentry/types/organization';
-import type {Project} from 'sentry/types/project';
import {trackAnalytics} from 'sentry/utils/analytics';
-import {browserHistory} from 'sentry/utils/browserHistory';
import {getUtcToLocalDateObject} from 'sentry/utils/dates';
import type EventView from 'sentry/utils/discover/eventView';
import {WebVital} from 'sentry/utils/fields';
@@ -36,7 +33,8 @@ import {Browser} from 'sentry/utils/performance/vitals/constants';
import {decodeScalar} from 'sentry/utils/queryString';
import Teams from 'sentry/utils/teams';
import {MutableSearch} from 'sentry/utils/tokenizeSearch';
-import withProjects from 'sentry/utils/withProjects';
+import {useNavigate} from 'sentry/utils/useNavigate';
+import useProjects from 'sentry/utils/useProjects';
import {deprecateTransactionAlerts} from 'sentry/views/insights/common/utils/hasEAPAlerts';
import Breadcrumb from 'sentry/views/performance/breadcrumb';
import {getTransactionSearchQuery} from 'sentry/views/performance/utils';
@@ -59,8 +57,6 @@ type Props = {
eventView: EventView;
location: Location;
organization: Organization;
- projects: Project[];
- router: InjectedRouter;
vitalName: WebVital;
};
@@ -71,8 +67,10 @@ function getSummaryConditions(query: string) {
return parsed.formatString();
}
-function VitalDetailContent(props: Props) {
+export default function VitalDetailContent(props: Props) {
const theme = useTheme();
+ const navigate = useNavigate();
+ const {projects} = useProjects();
function handleSearch(query: string) {
const {location} = props;
@@ -84,14 +82,14 @@ function VitalDetailContent(props: Props) {
// do not propagate pagination when making a new search
const searchQueryParams = omit(queryParams, 'cursor');
- browserHistory.push({
+ navigate({
pathname: location.pathname,
query: searchQueryParams,
});
}
function renderCreateAlertButton() {
- const {eventView, organization, projects, vitalName} = props;
+ const {eventView, organization, vitalName} = props;
return (
p.theme.fontSize.md};
margin-bottom: ${space(3)};