From 41cf44caff1fce224766aa12d682fbe18089470c Mon Sep 17 00:00:00 2001 From: Shashank Jarmale Date: Tue, 18 Nov 2025 16:12:20 -0800 Subject: [PATCH 1/2] First pass at removing `deprecatedRouteProps` from Discover views --- static/app/router/routes.tsx | 4 - static/app/views/discover/eventDetails.tsx | 9 +- static/app/views/discover/homepage.tsx | 35 +------ static/app/views/discover/results.tsx | 113 +++++++++++++++------ 4 files changed, 92 insertions(+), 69 deletions(-) diff --git a/static/app/router/routes.tsx b/static/app/router/routes.tsx index 757f4e320448c0..fe5efcb1718087 100644 --- a/static/app/router/routes.tsx +++ b/static/app/router/routes.tsx @@ -1780,7 +1780,6 @@ function buildRoutes(): RouteObject[] { { path: 'homepage/', component: make(() => import('sentry/views/discover/homepage')), - deprecatedRouteProps: true, }, traceView, { @@ -1790,12 +1789,10 @@ function buildRoutes(): RouteObject[] { { path: 'results/', component: make(() => import('sentry/views/discover/results')), - deprecatedRouteProps: true, }, { path: ':eventSlug/', component: make(() => import('sentry/views/discover/eventDetails')), - deprecatedRouteProps: true, }, ]; const discoverRoutes: SentryRouteObject = { @@ -1803,7 +1800,6 @@ function buildRoutes(): RouteObject[] { component: make(() => import('sentry/views/discover')), withOrgPath: true, children: discoverChildren, - deprecatedRouteProps: true, }; // Redirects for old LLM monitoring routes diff --git a/static/app/views/discover/eventDetails.tsx b/static/app/views/discover/eventDetails.tsx index da399f8f3b6737..f27a2afb47701d 100644 --- a/static/app/views/discover/eventDetails.tsx +++ b/static/app/views/discover/eventDetails.tsx @@ -9,18 +9,17 @@ import LoadingIndicator from 'sentry/components/loadingIndicator'; import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse'; import {t} from 'sentry/locale'; import type {Event} from 'sentry/types/event'; -import type {RouteComponentProps} from 'sentry/types/legacyReactRouter'; import {useApiQuery} from 'sentry/utils/queryClient'; import {useLocation} from 'sentry/utils/useLocation'; import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; +import {useParams} from 'sentry/utils/useParams'; import {getTraceDetailsUrl} from 'sentry/views/performance/traceDetails/utils'; -type Props = RouteComponentProps<{eventSlug: string}>; - -function EventDetails({params}: Props) { +export default function EventDetails() { const organization = useOrganization(); const location = useLocation(); + const params = useParams<{eventSlug: string}>(); const eventSlug = typeof params.eventSlug === 'string' ? params.eventSlug.trim() : ''; const datetimeSelection = normalizeDateTimeParams(location.query); const navigate = useNavigate(); @@ -105,5 +104,3 @@ const LoadingWrapper = styled('div')` margin: auto; height: 100%; `; - -export default EventDetails; diff --git a/static/app/views/discover/homepage.tsx b/static/app/views/discover/homepage.tsx index 29953d38dc0597..d9c3a276e1df38 100644 --- a/static/app/views/discover/homepage.tsx +++ b/static/app/views/discover/homepage.tsx @@ -1,7 +1,5 @@ import {useEffect} from 'react'; -import type {Location} from 'history'; -import type {Client} from 'sentry/api'; import LoadingError from 'sentry/components/loadingError'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; @@ -10,8 +8,6 @@ import { normalizeDateTimeString, } from 'sentry/components/organizations/pageFilters/parse'; import {getPageFilterStorage} from 'sentry/components/organizations/pageFilters/persistence'; -import type {PageFilters} from 'sentry/types/core'; -import type {InjectedRouter} from 'sentry/types/legacyReactRouter'; import type {Organization, SavedQuery} from 'sentry/types/organization'; import EventView from 'sentry/utils/discover/eventView'; import {useApiQuery, useQueryClient, type ApiQueryKey} from 'sentry/utils/queryClient'; @@ -19,28 +15,15 @@ import {useLocation} from 'sentry/utils/useLocation'; import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; import usePrevious from 'sentry/utils/usePrevious'; -import withApi from 'sentry/utils/withApi'; -import withOrganization from 'sentry/utils/withOrganization'; -import withPageFilters from 'sentry/utils/withPageFilters'; import {getSavedQueryWithDataset} from 'sentry/views/discover/savedQuery/utils'; -import {Results} from './results'; - -type Props = { - api: Client; - loading: boolean; - location: Location; - organization: Organization; - router: InjectedRouter; - selection: PageFilters; - setSavedQuery: (savedQuery: SavedQuery) => void; -}; +import {ResultsWrapper} from './results'; function makeDiscoverHomepageQueryKey(organization: Organization): ApiQueryKey { return [`/organizations/${organization.slug}/discover/homepage/`]; } -function Homepage(props: Props) { +function Homepage() { const organization = useOrganization(); const queryClient = useQueryClient(); const location = useLocation(); @@ -122,22 +105,14 @@ function Homepage(props: Props) { }; return ( - + ); } -function HomepageContainer(props: Props) { +export default function HomepageContainer() { return ( - + ); } - -export default withApi(withOrganization(withPageFilters(HomepageContainer))); diff --git a/static/app/views/discover/results.tsx b/static/app/views/discover/results.tsx index d9c5a35c411115..b88b73f02f964a 100644 --- a/static/app/views/discover/results.tsx +++ b/static/app/views/discover/results.tsx @@ -33,7 +33,6 @@ import {t, tct, tctCode} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {PageFilters} from 'sentry/types/core'; import {SavedSearchType} from 'sentry/types/group'; -import type {InjectedRouter} from 'sentry/types/legacyReactRouter'; import type {NewQuery, Organization, SavedQuery} from 'sentry/types/organization'; import {defined, generateQueryWithTag} from 'sentry/utils'; import {trackAnalytics} from 'sentry/utils/analytics'; @@ -57,6 +56,8 @@ import {setApiQueryData, useApiQuery, useQueryClient} from 'sentry/utils/queryCl import {decodeList, decodeScalar} from 'sentry/utils/queryString'; 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 useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import {hasDatasetSelector} from 'sentry/views/dashboards/utils'; @@ -82,8 +83,8 @@ type Props = { api: Client; loading: boolean; location: Location; + navigate: ReturnType; organization: Organization; - router: InjectedRouter; selection: PageFilters; setSavedQuery: (savedQuery?: SavedQuery) => void; isHomepage?: boolean; @@ -129,7 +130,7 @@ function getYAxis(location: Location, eventView: EventView, savedQuery?: SavedQu : [eventView.getYAxis()]; } -export class Results extends Component { +class Results extends Component { static getDerivedStateFromProps(nextProps: Readonly, prevState: State): State { const savedQueryDataset = getSavedQueryDataset( nextProps.organization, @@ -399,8 +400,7 @@ export class Results extends Component { } handleCursor: CursorHandler = (cursor, path, query, _direction) => { - const {router} = this.props; - router.push({ + this.props.navigate({ pathname: path, query: {...query, cursor}, }); @@ -423,7 +423,7 @@ export class Results extends Component { }; handleSearch = (query: string) => { - const {router, location} = this.props; + const {location, navigate} = this.props; const queryParams = normalizeDateTimeParams({ ...location.query, @@ -433,14 +433,14 @@ export class Results extends Component { // do not propagate pagination when making a new search const searchQueryParams = omit(queryParams, 'cursor'); - router.push({ + navigate({ pathname: location.pathname, query: searchQueryParams, }); }; handleYAxisChange = (value: string[]) => { - const {router, location} = this.props; + const {navigate, location} = this.props; const isDisplayMultiYAxisSupported = MULTI_Y_AXIS_SUPPORTED_DISPLAY_MODES.includes( location.query.display as DisplayModes ); @@ -457,7 +457,7 @@ export class Results extends Component { : location.query.display, }; - router.push({ + navigate({ pathname: location.pathname, query: newQuery, }); @@ -474,14 +474,14 @@ export class Results extends Component { }; handleDisplayChange = (value: string) => { - const {router, location} = this.props; + const {navigate, location} = this.props; const newQuery = { ...location.query, display: value, }; - router.push({ + navigate({ pathname: location.pathname, query: newQuery, }); @@ -493,7 +493,7 @@ export class Results extends Component { }; handleIntervalChange = (value: string | undefined) => { - const {router, location} = this.props; + const {navigate, location} = this.props; const newQuery = { ...location.query, @@ -501,7 +501,7 @@ export class Results extends Component { }; if (location.query.interval !== value) { - router.push({ + navigate({ pathname: location.pathname, query: newQuery, }); @@ -514,14 +514,14 @@ export class Results extends Component { }; handleTopEventsChange = (value: string) => { - const {router, location} = this.props; + const {navigate, location} = this.props; const newQuery = { ...location.query, topEvents: value, }; - router.push({ + navigate({ pathname: location.pathname, query: newQuery, }); @@ -921,9 +921,19 @@ const TipContainer = styled(MarkedText)` } `; -function SavedQueryAPI(props: Omit) { +function SavedQueryAPI( + props: Omit & { + savedQuery?: SavedQuery; + setSavedQuery?: (savedQuery?: SavedQuery) => void; + } +) { const queryClient = useQueryClient(); - const {organization, location} = props; + const { + organization, + location, + savedQuery: providedSavedQuery, + setSavedQuery: providedSetSavedQuery, + } = props; const queryKey = useMemo( (): ApiQueryKey => [ @@ -931,15 +941,17 @@ function SavedQueryAPI(props: Omit( queryKey, { - enabled: Boolean(location.query.id), + enabled: Boolean(location.query.id) && !providedSavedQuery, staleTime: 0, } ); - const setSavedQuery = useCallback( + const defaultSetSavedQuery = useCallback( (newQuery?: SavedQuery) => { setApiQueryData(queryClient, queryKey, newQuery); queryClient.refetchQueries({queryKey}); @@ -947,6 +959,11 @@ function SavedQueryAPI(props: Omit; } @@ -957,22 +974,45 @@ function SavedQueryAPI(props: Omit ); } -export default function ResultsContainer( - props: Omit -) { +export type ResultsWrapperProps = { + isHomepage?: boolean; + savedQuery?: SavedQuery; + setSavedQuery?: (savedQuery?: SavedQuery) => void; +}; + +/** + * ResultsWrapper - Functional wrapper around the Results class component + * + * This component provides modern React patterns (hooks) while maintaining + * compatibility with the legacy Results class component. + * + * Usage: + * - Use the named export `ResultsWrapper` when passing props (e.g., from homepage) + * - The default export is used by routes and accepts no props + */ +export function ResultsWrapper({ + isHomepage, + savedQuery, + setSavedQuery, +}: ResultsWrapperProps) { const api = useApi(); const organization = useOrganization(); const {selection} = usePageFilters(); + const location = useLocation(); + const navigate = useNavigate(); /** * Block `` from mounting until GSH is ready since there are API @@ -989,9 +1029,9 @@ export default function ResultsContainer( ); } +// Default export for routes - no props +export default function ResultsWrapperRoute() { + return ( + + ); +} + const StyledCloseButton = styled(Button)` background-color: transparent; transition: opacity 0.1s linear; From 91a69a111e5219e1923513f06c4ca6bddaff642c Mon Sep 17 00:00:00 2001 From: Shashank Jarmale Date: Wed, 19 Nov 2025 14:20:29 -0800 Subject: [PATCH 2/2] Updates to homepage & results components --- static/app/views/discover/homepage.tsx | 18 +++++- static/app/views/discover/results.tsx | 79 ++++---------------------- 2 files changed, 28 insertions(+), 69 deletions(-) diff --git a/static/app/views/discover/homepage.tsx b/static/app/views/discover/homepage.tsx index d9c3a276e1df38..4eaf304ac0fc4f 100644 --- a/static/app/views/discover/homepage.tsx +++ b/static/app/views/discover/homepage.tsx @@ -11,13 +11,15 @@ import {getPageFilterStorage} from 'sentry/components/organizations/pageFilters/ import type {Organization, SavedQuery} from 'sentry/types/organization'; import EventView from 'sentry/utils/discover/eventView'; import {useApiQuery, useQueryClient, type ApiQueryKey} from 'sentry/utils/queryClient'; +import useApi from 'sentry/utils/useApi'; import {useLocation} from 'sentry/utils/useLocation'; import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; +import usePageFilters from 'sentry/utils/usePageFilters'; import usePrevious from 'sentry/utils/usePrevious'; import {getSavedQueryWithDataset} from 'sentry/views/discover/savedQuery/utils'; -import {ResultsWrapper} from './results'; +import {Results} from './results'; function makeDiscoverHomepageQueryKey(organization: Organization): ApiQueryKey { return [`/organizations/${organization.slug}/discover/homepage/`]; @@ -25,9 +27,11 @@ function makeDiscoverHomepageQueryKey(organization: Organization): ApiQueryKey { function Homepage() { const organization = useOrganization(); + const api = useApi(); const queryClient = useQueryClient(); const location = useLocation(); const navigate = useNavigate(); + const {selection} = usePageFilters(); const {data, isLoading, isError, refetch} = useApiQuery( makeDiscoverHomepageQueryKey(organization), { @@ -105,7 +109,17 @@ function Homepage() { }; return ( - + ); } diff --git a/static/app/views/discover/results.tsx b/static/app/views/discover/results.tsx index b88b73f02f964a..e5960f883722f6 100644 --- a/static/app/views/discover/results.tsx +++ b/static/app/views/discover/results.tsx @@ -130,7 +130,7 @@ function getYAxis(location: Location, eventView: EventView, savedQuery?: SavedQu : [eventView.getYAxis()]; } -class Results extends Component { +export class Results extends Component { static getDerivedStateFromProps(nextProps: Readonly, prevState: State): State { const savedQueryDataset = getSavedQueryDataset( nextProps.organization, @@ -921,19 +921,9 @@ const TipContainer = styled(MarkedText)` } `; -function SavedQueryAPI( - props: Omit & { - savedQuery?: SavedQuery; - setSavedQuery?: (savedQuery?: SavedQuery) => void; - } -) { +function SavedQueryAPI(props: Omit) { const queryClient = useQueryClient(); - const { - organization, - location, - savedQuery: providedSavedQuery, - setSavedQuery: providedSetSavedQuery, - } = props; + const {organization, location} = props; const queryKey = useMemo( (): ApiQueryKey => [ @@ -941,17 +931,15 @@ function SavedQueryAPI( ], [organization, location.query.id] ); - - // Only fetch if we don't already have a savedQuery (homepage provides its own) const {data, isError, isFetching, refetch} = useApiQuery( queryKey, { - enabled: Boolean(location.query.id) && !providedSavedQuery, + enabled: Boolean(location.query.id), staleTime: 0, } ); - const defaultSetSavedQuery = useCallback( + const setSavedQuery = useCallback( (newQuery?: SavedQuery) => { setApiQueryData(queryClient, queryKey, newQuery); queryClient.refetchQueries({queryKey}); @@ -959,11 +947,6 @@ function SavedQueryAPI( [queryClient, queryKey] ); - const setSavedQuery = providedSetSavedQuery ?? defaultSetSavedQuery; - const savedQuery = - providedSavedQuery ?? - (hasDatasetSelector(organization) ? getSavedQueryWithDataset(data) : data); - if (isFetching) { return ; } @@ -974,40 +957,17 @@ function SavedQueryAPI( return ( ); } -export type ResultsWrapperProps = { - isHomepage?: boolean; - savedQuery?: SavedQuery; - setSavedQuery?: (savedQuery?: SavedQuery) => void; -}; - -/** - * ResultsWrapper - Functional wrapper around the Results class component - * - * This component provides modern React patterns (hooks) while maintaining - * compatibility with the legacy Results class component. - * - * Usage: - * - Use the named export `ResultsWrapper` when passing props (e.g., from homepage) - * - The default export is used by routes and accepts no props - */ -export function ResultsWrapper({ - isHomepage, - savedQuery, - setSavedQuery, -}: ResultsWrapperProps) { +export default function ResultsContainer() { const api = useApi(); const organization = useOrganization(); const {selection} = usePageFilters(); @@ -1028,10 +988,9 @@ export function ResultsWrapper({ return ( ); } -// Default export for routes - no props -export default function ResultsWrapperRoute() { - return ( - - ); -} - const StyledCloseButton = styled(Button)` background-color: transparent; transition: opacity 0.1s linear;