From ff2fde2090067df3b24959677986059f54f0947e Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Thu, 27 Nov 2025 13:57:47 -0500 Subject: [PATCH 1/2] feat: Set Default max pickable days This is trying to address a few problems with the date page filter. 1. the `PageFiltersContainer` does not set max pickable days so it properly resets when coming from pages that may have a longer max pickable days like explore > traces 2. the `TimeRangeSelector` hard codes 90 as the max pickable days but in saas, this max pickable days changes based on the plan (and coming soon, the data category) --- .../organizations/pageFilters/container.tsx | 4 ++++ .../app/components/timeRangeSelector/index.tsx | 6 +++++- static/app/types/hooks.tsx | 6 +++++- static/app/utils/useMaxPickableDays.tsx | 17 +++++++++++++++++ static/gsApp/hooks/useMaxPickableDays.tsx | 6 ++++++ static/gsApp/registerHooks.tsx | 3 ++- 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/static/app/components/organizations/pageFilters/container.tsx b/static/app/components/organizations/pageFilters/container.tsx index 25bfd5efc324b5..afa8fe4a010812 100644 --- a/static/app/components/organizations/pageFilters/container.tsx +++ b/static/app/components/organizations/pageFilters/container.tsx @@ -14,6 +14,7 @@ import LoadingIndicator from 'sentry/components/loadingIndicator'; import {DEFAULT_STATS_PERIOD} from 'sentry/constants'; import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser'; import {useLocation} from 'sentry/utils/useLocation'; +import {useDefaultMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; @@ -87,6 +88,9 @@ function PageFiltersContainer({ ? [] : specifiedProjects.filter(project => !project.isMember); + const defaultMaxPickableDays = useDefaultMaxPickableDays(); + maxPickableDays = maxPickableDays ?? defaultMaxPickableDays; + const doInitialization = () => { initializeUrlState({ organization, diff --git a/static/app/components/timeRangeSelector/index.tsx b/static/app/components/timeRangeSelector/index.tsx index 66e5027a5f6b86..172132fdbc6308 100644 --- a/static/app/components/timeRangeSelector/index.tsx +++ b/static/app/components/timeRangeSelector/index.tsx @@ -24,6 +24,7 @@ import { } from 'sentry/utils/dates'; import {parsePeriodToHours} from 'sentry/utils/duration/parsePeriodToHours'; import getRouteStringFromRoutes from 'sentry/utils/getRouteStringFromRoutes'; +import {useDefaultMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import useRouter from 'sentry/utils/useRouter'; @@ -153,7 +154,7 @@ export function TimeRangeSelector({ showRelative = true, defaultAbsolute, defaultPeriod = DEFAULT_STATS_PERIOD, - maxPickableDays = 90, + maxPickableDays, maxDateRange, disallowArbitraryRelativeRanges = false, trigger, @@ -167,6 +168,9 @@ export function TimeRangeSelector({ const router = useRouter(); const organization = useOrganization({allowNull: true}); + const defaultMaxPickableDays = useDefaultMaxPickableDays(); + maxPickableDays = maxPickableDays ?? defaultMaxPickableDays; + const [search, setSearch] = useState(''); const [hasChanges, setHasChanges] = useState(false); const [hasDateRangeErrors, setHasDateRangeErrors] = useState(false); diff --git a/static/app/types/hooks.tsx b/static/app/types/hooks.tsx index ca951e6d25d9dc..7f1a4d2501cc78 100644 --- a/static/app/types/hooks.tsx +++ b/static/app/types/hooks.tsx @@ -8,7 +8,10 @@ import type {ProductSelectionProps} from 'sentry/components/onboarding/productSe import type DateRange from 'sentry/components/timeRangeSelector/dateRange'; import type SelectorItems from 'sentry/components/timeRangeSelector/selectorItems'; import type {SentryRouteObject} from 'sentry/router/types'; -import type {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; +import type { + useDefaultMaxPickableDays, + useMaxPickableDays, +} from 'sentry/utils/useMaxPickableDays'; import type {WidgetType} from 'sentry/views/dashboards/types'; import type {OrganizationStatsProps} from 'sentry/views/organizationStats'; import type {RouteAnalyticsContext} from 'sentry/views/routeAnalyticsContextProvider'; @@ -331,6 +334,7 @@ type ReactHooks = { 'react-hook:use-dashboard-dataset-retention-limit': (props: { dataset: WidgetType; }) => number; + 'react-hook:use-default-max-pickable-days': typeof useDefaultMaxPickableDays; 'react-hook:use-get-max-retention-days': () => number | undefined; 'react-hook:use-max-pickable-days': typeof useMaxPickableDays; 'react-hook:use-metric-detector-limit': () => { diff --git a/static/app/utils/useMaxPickableDays.tsx b/static/app/utils/useMaxPickableDays.tsx index 6753c1ce74db6c..1d1c7ba8245acf 100644 --- a/static/app/utils/useMaxPickableDays.tsx +++ b/static/app/utils/useMaxPickableDays.tsx @@ -2,12 +2,29 @@ import {useMemo, type ReactNode} from 'react'; import HookOrDefault from 'sentry/components/hookOrDefault'; import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; +import {MAX_PICKABLE_DAYS} from 'sentry/constants'; import {t} from 'sentry/locale'; import HookStore from 'sentry/stores/hookStore'; import {DataCategory} from 'sentry/types/core'; import type {Organization} from 'sentry/types/organization'; import useOrganization from 'sentry/utils/useOrganization'; +/** + * This returns the default max pickable days for the current organization. + * + * Use this as the default when there is not known data category. + */ +export function useDefaultMaxPickableDays() { + const useDefaultMaxPickableDaysHook = + HookStore.get('react-hook:use-default-max-pickable-days')[0] ?? + useDefaultMaxPickableDaysImpl; + return useDefaultMaxPickableDaysHook(); +} + +function useDefaultMaxPickableDaysImpl() { + return MAX_PICKABLE_DAYS; +} + export interface MaxPickableDaysOptions { /** * The maximum number of days the user is allowed to pick on the date page filter diff --git a/static/gsApp/hooks/useMaxPickableDays.tsx b/static/gsApp/hooks/useMaxPickableDays.tsx index 754a93fdc1a030..d45ae76663b429 100644 --- a/static/gsApp/hooks/useMaxPickableDays.tsx +++ b/static/gsApp/hooks/useMaxPickableDays.tsx @@ -1,6 +1,7 @@ import {useMemo} from 'react'; import moment from 'moment-timezone'; +import {MAX_PICKABLE_DAYS} from 'sentry/constants'; import {DataCategory} from 'sentry/types/core'; import {defined} from 'sentry/utils'; import { @@ -16,6 +17,11 @@ import type {Subscription} from 'getsentry/types'; import useSubscription from './useSubscription'; +export function useDefaultMaxPickableDays() { + const subscription = useSubscription(); + return subscription?.planDetails?.retentionDays ?? MAX_PICKABLE_DAYS; +} + export function useMaxPickableDays({ dataCategories, }: UseMaxPickableDaysProps): MaxPickableDaysOptions { diff --git a/static/gsApp/registerHooks.tsx b/static/gsApp/registerHooks.tsx index 104457ebcfbdb1..e918b4c9be22b3 100644 --- a/static/gsApp/registerHooks.tsx +++ b/static/gsApp/registerHooks.tsx @@ -82,7 +82,7 @@ import ReplayOnboardingAlert from './components/replayOnboardingAlert'; import ReplaySettingsAlert from './components/replaySettingsAlert'; import useButtonTracking from './hooks/useButtonTracking'; import useGetMaxRetentionDays from './hooks/useGetMaxRetentionDays'; -import {useMaxPickableDays} from './hooks/useMaxPickableDays'; +import {useDefaultMaxPickableDays, useMaxPickableDays} from './hooks/useMaxPickableDays'; import useRouteActivatedHook from './hooks/useRouteActivatedHook'; const PartnershipAgreement = lazy(() => import('getsentry/views/partnershipAgreement')); @@ -233,6 +233,7 @@ const GETSENTRY_HOOKS: Partial = { 'component:crons-list-page-header': () => CronsBillingBanner, 'react-hook:route-activated': useRouteActivatedHook, 'react-hook:use-button-tracking': useButtonTracking, + 'react-hook:use-default-max-pickable-days': useDefaultMaxPickableDays, 'react-hook:use-max-pickable-days': useMaxPickableDays, 'react-hook:use-get-max-retention-days': useGetMaxRetentionDays, 'react-hook:use-metric-detector-limit': useMetricDetectorLimit, From ca94730a6bdbb64820255d06faa038a65c4f6c84 Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Thu, 27 Nov 2025 14:11:16 -0500 Subject: [PATCH 2/2] fix typing --- static/app/utils/useMaxPickableDays.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/utils/useMaxPickableDays.tsx b/static/app/utils/useMaxPickableDays.tsx index 1d1c7ba8245acf..8e552937f32e9f 100644 --- a/static/app/utils/useMaxPickableDays.tsx +++ b/static/app/utils/useMaxPickableDays.tsx @@ -14,7 +14,7 @@ import useOrganization from 'sentry/utils/useOrganization'; * * Use this as the default when there is not known data category. */ -export function useDefaultMaxPickableDays() { +export function useDefaultMaxPickableDays(): number { const useDefaultMaxPickableDaysHook = HookStore.get('react-hook:use-default-max-pickable-days')[0] ?? useDefaultMaxPickableDaysImpl;