From 438f90211e23c2524a08bb43054f8c5a73163b73 Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Fri, 21 Nov 2025 11:57:40 -0500 Subject: [PATCH 1/4] feat(explore): Add hooks for date page filter props based on data category This replaces the custom functions we wrote for each data category with a hook that accepts a list of data categories so we can automatically determine what the expected date page filter props should be. This sets it up so that we can replace the hook with an alternate implementation in order to support the coming retention changes. --- static/app/types/hooks.tsx | 7 +- static/app/utils/useDatePageFilterProps.tsx | 72 ++++++++++ static/app/utils/useMaxPickableDays.spec.tsx | 94 +++++++++++++ static/app/utils/useMaxPickableDays.tsx | 132 ++++++++++++++++++ static/app/views/explore/logs/content.tsx | 42 +++--- .../app/views/explore/logs/logsOnboarding.tsx | 15 +- .../app/views/explore/logs/logsTab.spec.tsx | 4 +- static/app/views/explore/logs/logsTab.tsx | 16 +-- static/app/views/explore/logs/utils.tsx | 26 +--- static/app/views/explore/metrics/content.tsx | 41 +++--- .../explore/metrics/metricsOnboarding.tsx | 15 +- .../app/views/explore/metrics/metricsTab.tsx | 28 ++-- static/app/views/explore/metrics/utils.tsx | 26 ---- .../views/explore/multiQueryMode/content.tsx | 28 +++- .../views/explore/multiQueryMode/index.tsx | 5 +- static/app/views/explore/spans/content.tsx | 10 +- .../app/views/explore/spans/spansTab.spec.tsx | 4 +- static/app/views/explore/spans/spansTab.tsx | 37 ++--- static/app/views/explore/utils.tsx | 94 ------------- .../agentModels/views/modelsLandingPage.tsx | 23 ++- .../agentTools/views/toolsLandingPage.tsx | 23 ++- .../insights/aiGenerations/views/overview.tsx | 26 +++- .../common/components/modulePageProviders.tsx | 7 +- .../views/mcpPromptsLandingPage.tsx | 24 +++- .../views/mcpResourcesLandingPage.tsx | 24 +++- .../mcp-tools/views/mcpToolsLandingPage.tsx | 24 +++- .../views/insights/pages/agents/overview.tsx | 23 ++- .../pages/domainOverviewPageProviders.tsx | 15 +- .../app/views/insights/pages/mcp/overview.tsx | 23 ++- .../exploreDateRangeQueryLimitFooter.tsx | 13 -- static/gsApp/registerHooks.tsx | 5 +- 31 files changed, 587 insertions(+), 339 deletions(-) create mode 100644 static/app/utils/useDatePageFilterProps.tsx create mode 100644 static/app/utils/useMaxPickableDays.spec.tsx create mode 100644 static/app/utils/useMaxPickableDays.tsx delete mode 100644 static/gsApp/components/features/exploreDateRangeQueryLimitFooter.tsx diff --git a/static/app/types/hooks.tsx b/static/app/types/hooks.tsx index cf81f46ff2d7ba..70ee56bb6f6c6e 100644 --- a/static/app/types/hooks.tsx +++ b/static/app/types/hooks.tsx @@ -111,6 +111,11 @@ type OrganizationHeaderProps = { type ProductSelectionAvailabilityProps = Omit; +type DateRangeQueryLimitFooterProps = { + description: string; + source: string; +}; + type FirstPartyIntegrationAlertProps = { integrations: Integration[]; hideCTA?: boolean; @@ -190,9 +195,9 @@ type ComponentHooks = { 'component:disabled-member': () => React.ComponentType; 'component:disabled-member-tooltip': () => React.ComponentType; 'component:enhanced-org-stats': () => React.ComponentType; - 'component:explore-date-range-query-limit-footer': () => React.ComponentType; 'component:first-party-integration-additional-cta': () => React.ComponentType; 'component:first-party-integration-alert': () => React.ComponentType; + 'component:header-date-page-filter-upsell-footer': () => React.ComponentType; 'component:header-date-range': () => React.ComponentType; 'component:header-selector-items': () => React.ComponentType; 'component:insights-date-range-query-limit-footer': () => React.ComponentType; diff --git a/static/app/utils/useDatePageFilterProps.tsx b/static/app/utils/useDatePageFilterProps.tsx new file mode 100644 index 00000000000000..43914501960103 --- /dev/null +++ b/static/app/utils/useDatePageFilterProps.tsx @@ -0,0 +1,72 @@ +import {useMemo, type ReactNode} from 'react'; + +import type {SelectOptionWithKey} from 'sentry/components/core/compactSelect/types'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; +import {t} from 'sentry/locale'; +import {defined} from 'sentry/utils'; +import {isEmptyObject} from 'sentry/utils/object/isEmptyObject'; +import type {MaxPickableDaysOptions} from 'sentry/utils/useMaxPickableDays'; + +interface UseDatePageFilterPropsProps extends MaxPickableDaysOptions {} + +export function useDatePageFilterProps({ + defaultPeriod, + maxPickableDays, + maxUpgradableDays, + upsellFooter, +}: UseDatePageFilterPropsProps): DatePageFilterProps { + return useMemo(() => { + if (!defined(maxPickableDays)) { + return {}; + } + + const availableRelativeOptions: Array<[number, string, ReactNode]> = [ + [1 / 24, '1h', t('Last hour')], + [1, '24h', t('Last 24 hours')], + [7, '7d', t('Last 7 days')], + [14, '14d', t('Last 14 days')], + [30, '30d', t('Last 30 days')], + [90, '90d', t('Last 90 days')], + ]; + // ensure the available relative options are always sorted + availableRelativeOptions.sort((a, b) => a[0] - b[0]); + + // find the relative options that should be enabled based on the maxPickableDays + const pickableIndex = + availableRelativeOptions.findLastIndex(([days]) => days <= maxPickableDays) + 1; + const enabledOptions = Object.fromEntries( + availableRelativeOptions + .slice(0, pickableIndex) + .map(([_, period, label]) => [period, label]) + ); + + // find the relative options that should be disabled based on the maxUpgradableDays + // if maxUpgradableDays isn't defined, there should be no disabled options + const upgradableIndex = maxUpgradableDays + ? availableRelativeOptions.findLastIndex(([days]) => days <= maxUpgradableDays) + 1 + : pickableIndex; + const disabledOptions = Object.fromEntries( + availableRelativeOptions + .slice(pickableIndex, upgradableIndex) + .map(([_, period, label]) => [period, label]) + ); + + const isOptionDisabled = (option: SelectOptionWithKey): boolean => { + return disabledOptions.hasOwnProperty(option.value); + }; + + const menuFooter = isEmptyObject(disabledOptions) ? null : (upsellFooter ?? null); + + return { + defaultPeriod, + isOptionDisabled, + maxPickableDays, + menuFooter, + relativeOptions: ({arbitraryOptions}) => ({ + ...arbitraryOptions, + ...enabledOptions, + ...disabledOptions, + }), + }; + }, [defaultPeriod, maxPickableDays, maxUpgradableDays, upsellFooter]); +} diff --git a/static/app/utils/useMaxPickableDays.spec.tsx b/static/app/utils/useMaxPickableDays.spec.tsx new file mode 100644 index 00000000000000..01311d2556caeb --- /dev/null +++ b/static/app/utils/useMaxPickableDays.spec.tsx @@ -0,0 +1,94 @@ +import {OrganizationFixture} from 'sentry-fixture/organization'; + +import {renderHookWithProviders} from 'sentry-test/reactTestingLibrary'; + +import {DataCategory} from 'sentry/types/core'; + +import {useMaxPickableDays} from './useMaxPickableDays'; + +describe('useMaxPickableDays', () => { + it.each([ + [[]], + [[DataCategory.ERRORS, DataCategory.REPLAYS]], + [[DataCategory.ERRORS]], + [[DataCategory.REPLAYS]], + ])('returns undefined for %s', dataCategories => { + const {result} = renderHookWithProviders(() => + useMaxPickableDays({ + dataCategories, + organization: OrganizationFixture(), + }) + ); + + expect(result.current).toEqual({ + maxPickableDays: undefined, + maxUpgradableDays: undefined, + }); + }); + + it('returns 30/30 days for logs', () => { + const {result} = renderHookWithProviders(() => + useMaxPickableDays({ + dataCategories: [DataCategory.LOG_BYTE, DataCategory.LOG_ITEM], + organization: OrganizationFixture(), + }) + ); + + expect(result.current).toEqual({ + defaultPeriod: '24h', + maxPickableDays: 30, + maxUpgradableDays: 30, + }); + }); + + it('returns 30/90 for spans without flag', () => { + const {result} = renderHookWithProviders(() => + useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization: OrganizationFixture({features: []}), + }) + ); + + expect(result.current).toEqual({ + maxPickableDays: 30, + maxUpgradableDays: 90, + upsellFooter: expect.any(Object), + }); + }); + + it('returns 90/90 for spans with flag', () => { + const {result} = renderHookWithProviders(() => + useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization: OrganizationFixture({features: ['visibility-explore-range-high']}), + }) + ); + + expect(result.current).toEqual({ + maxPickableDays: 90, + maxUpgradableDays: 90, + upsellFooter: expect.any(Object), + }); + }); + + it('returns 30/90 for many without flag', () => { + const {result} = renderHookWithProviders(() => + useMaxPickableDays({ + dataCategories: [ + DataCategory.PROFILE_DURATION, + DataCategory.PROFILE_DURATION_UI, + DataCategory.LOG_BYTE, + DataCategory.LOG_ITEM, + DataCategory.SPANS, + ], + organization: OrganizationFixture(), + }) + ); + + expect(result.current).toEqual({ + maxPickableDays: 30, + maxUpgradableDays: 90, + upsellFooter: expect.any(Object), + }); + }); +}); diff --git a/static/app/utils/useMaxPickableDays.tsx b/static/app/utils/useMaxPickableDays.tsx new file mode 100644 index 00000000000000..8d49b9f29a9286 --- /dev/null +++ b/static/app/utils/useMaxPickableDays.tsx @@ -0,0 +1,132 @@ +import {useMemo, type ReactNode} from 'react'; + +import HookOrDefault from 'sentry/components/hookOrDefault'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; +import {t} from 'sentry/locale'; +import {DataCategory} from 'sentry/types/core'; +import type {Organization} from 'sentry/types/organization'; +import {defined} from 'sentry/utils'; + +export interface MaxPickableDaysOptions { + /** + * The maximum number of days the user is allowed to pick on the date page filter + */ + maxPickableDays: DatePageFilterProps['maxPickableDays']; + /** + * The maximum number of days the user can upgrade to on the date page filter + */ + maxUpgradableDays: DatePageFilterProps['maxPickableDays']; + defaultPeriod?: DatePageFilterProps['defaultPeriod']; + upsellFooter?: ReactNode; +} + +interface UseMaxPickableDaysProps { + dataCategories: DataCategory[]; + organization: Organization; +} + +export function useMaxPickableDays({ + dataCategories, + organization, +}: UseMaxPickableDaysProps): MaxPickableDaysOptions { + return useMemo(() => { + function getMaxPickableDaysFor(dataCategory: DataCategory) { + return getMaxPickableDays(dataCategory, organization); + } + + return getBestMaxPickableDays(dataCategories, getMaxPickableDaysFor); + }, [dataCategories, organization]); +} + +function getBestMaxPickableDays( + dataCategories: DataCategory[], + getMaxPickableDaysFor: (dataCategory: DataCategory) => MaxPickableDaysOptions +) { + let maxPickableDays: MaxPickableDaysOptions = { + maxPickableDays: undefined, + maxUpgradableDays: undefined, + }; + + for (const dataCategory of dataCategories) { + const maxPickableDaysForDataCategory = getMaxPickableDaysFor(dataCategory); + maxPickableDays = max(maxPickableDays, maxPickableDaysForDataCategory); + } + + return maxPickableDays; +} + +function max( + a: MaxPickableDaysOptions, + b: MaxPickableDaysOptions +): MaxPickableDaysOptions { + if (!defined(a.maxPickableDays)) { + return b; + } + + if (!defined(b.maxPickableDays)) { + return a; + } + + if (a.maxPickableDays > b.maxPickableDays) { + return a; + } + + if (a.maxPickableDays < b.maxPickableDays) { + return b; + } + + if (!defined(a.maxUpgradableDays)) { + return b; + } + + if (!defined(b.maxUpgradableDays)) { + return a; + } + + if (a.maxUpgradableDays > b.maxUpgradableDays) { + return a; + } + + return b; +} + +const DESCRIPTION = t('To query over longer time ranges, upgrade to Business'); + +function getMaxPickableDays( + dataCategory: DataCategory, + organization: Organization +): MaxPickableDaysOptions { + switch (dataCategory) { + case DataCategory.SPANS: + case DataCategory.SPANS_INDEXED: { + const maxPickableDays = organization.features.includes( + 'visibility-explore-range-high' + ) + ? 90 + : 30; + return { + maxPickableDays, + maxUpgradableDays: 90, + upsellFooter: , + }; + } + case DataCategory.TRACE_METRICS: + case DataCategory.LOG_BYTE: + case DataCategory.LOG_ITEM: + return { + maxPickableDays: 30, + maxUpgradableDays: 30, + defaultPeriod: '24h', + }; + default: + return { + maxPickableDays: undefined, + maxUpgradableDays: undefined, + }; + } +} + +const UpsellFooterHook = HookOrDefault({ + hookName: 'component:header-date-page-filter-upsell-footer', + defaultComponent: () => null, +}); diff --git a/static/app/views/explore/logs/content.tsx b/static/app/views/explore/logs/content.tsx index 8c6d10af9218e9..1b452b70e0c044 100644 --- a/static/app/views/explore/logs/content.tsx +++ b/static/app/views/explore/logs/content.tsx @@ -8,10 +8,13 @@ import {withoutLoggingSupport} from 'sentry/data/platformCategories'; import {platforms} from 'sentry/data/platforms'; import {IconMegaphone, IconOpen} from 'sentry/icons'; import {t} from 'sentry/locale'; +import {DataCategory} from 'sentry/types/core'; import {defined} from 'sentry/utils'; import {trackAnalytics} from 'sentry/utils/analytics'; import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useFeedbackForm} from 'sentry/utils/useFeedbackForm'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; @@ -22,7 +25,6 @@ import {useGetSavedQuery} from 'sentry/views/explore/hooks/useGetSavedQueries'; import {LogsTabOnboarding} from 'sentry/views/explore/logs/logsOnboarding'; import {LogsQueryParamsProvider} from 'sentry/views/explore/logs/logsQueryParamsProvider'; import {LogsTabContent} from 'sentry/views/explore/logs/logsTab'; -import {logsPickableDays} from 'sentry/views/explore/logs/utils'; import { useQueryParamsId, useQueryParamsTitle, @@ -58,22 +60,30 @@ function FeedbackButton() { export default function LogsContent() { const organization = useOrganization(); - const {defaultPeriod, maxPickableDays, relativeOptions} = logsPickableDays(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.LOG_BYTE], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); const onboardingProject = useOnboardingProject({property: 'hasLogs'}); return ( ) : ( - + )} diff --git a/static/app/views/explore/logs/logsOnboarding.tsx b/static/app/views/explore/logs/logsOnboarding.tsx index d7a83fa47dfc68..6e70fc1998e587 100644 --- a/static/app/views/explore/logs/logsOnboarding.tsx +++ b/static/app/views/explore/logs/logsOnboarding.tsx @@ -16,6 +16,7 @@ import { } from 'sentry/components/onboarding/gettingStartedDoc/types'; import {useSourcePackageRegistries} from 'sentry/components/onboarding/gettingStartedDoc/useSourcePackageRegistries'; import {useLoadGettingStarted} from 'sentry/components/onboarding/gettingStartedDoc/utils/useLoadGettingStarted'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; @@ -40,7 +41,6 @@ import { ExploreFilterSection, } from 'sentry/views/explore/components/styles'; import {StyledPageFilterBar} from 'sentry/views/explore/logs/styles'; -import type {PickableDays} from 'sentry/views/explore/utils'; // eslint-disable-next-line no-restricted-imports,boundaries/element-types import QuotaExceededAlert from 'getsentry/components/performance/quotaExceededAlert'; @@ -378,16 +378,15 @@ const OnboardingContainer = styled('div')` `; type LogsTabOnboardingProps = { + datePageFilterProps: DatePageFilterProps; organization: Organization; project: Project; -} & PickableDays; +}; export function LogsTabOnboarding({ organization, project, - defaultPeriod, - maxPickableDays, - relativeOptions, + datePageFilterProps, }: LogsTabOnboardingProps) { return ( @@ -396,11 +395,7 @@ export function LogsTabOnboarding({ - + diff --git a/static/app/views/explore/logs/logsTab.spec.tsx b/static/app/views/explore/logs/logsTab.spec.tsx index b7b18a814ed3b2..8fed38f8ef6178 100644 --- a/static/app/views/explore/logs/logsTab.spec.tsx +++ b/static/app/views/explore/logs/logsTab.spec.tsx @@ -2,6 +2,7 @@ import {initializeLogsTest} from 'sentry-fixture/log'; import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {LogsAnalyticsPageSource} from 'sentry/utils/analytics/logsAnalyticsEvent'; import {LogsPageDataProvider} from 'sentry/views/explore/contexts/logs/logsPageData'; import { @@ -15,9 +16,8 @@ import {LogsQueryParamsProvider} from 'sentry/views/explore/logs/logsQueryParams import {LogsTabContent} from 'sentry/views/explore/logs/logsTab'; import {OurLogKnownFieldKey} from 'sentry/views/explore/logs/types'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import type {PickableDays} from 'sentry/views/explore/utils'; -const datePageFilterProps: PickableDays = { +const datePageFilterProps: DatePageFilterProps = { defaultPeriod: '7d' as const, maxPickableDays: 7, relativeOptions: ({arbitraryOptions}) => ({ diff --git a/static/app/views/explore/logs/logsTab.tsx b/static/app/views/explore/logs/logsTab.tsx index d6de09c0ec368f..76c281338a883d 100644 --- a/static/app/views/explore/logs/logsTab.tsx +++ b/static/app/views/explore/logs/logsTab.tsx @@ -5,6 +5,7 @@ import {Button} from 'sentry/components/core/button'; import {TabList, Tabs} from 'sentry/components/core/tabs'; import {DropdownMenu} from 'sentry/components/dropdownMenu'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; @@ -85,18 +86,15 @@ import { } from 'sentry/views/explore/queryParams/context'; import {ColumnEditorModal} from 'sentry/views/explore/tables/columnEditorModal'; import {useRawCounts} from 'sentry/views/explore/useRawCounts'; -import type {PickableDays} from 'sentry/views/explore/utils'; // eslint-disable-next-line no-restricted-imports,boundaries/element-types import QuotaExceededAlert from 'getsentry/components/performance/quotaExceededAlert'; -type LogsTabProps = PickableDays; +type LogsTabProps = { + datePageFilterProps: DatePageFilterProps; +}; -export function LogsTabContent({ - defaultPeriod, - maxPickableDays, - relativeOptions, -}: LogsTabProps) { +export function LogsTabContent({datePageFilterProps}: LogsTabProps) { const pageFilters = usePageFilters(); const logsSearch = useQueryParamsSearch(); const fields = useQueryParamsFields(); @@ -290,9 +288,7 @@ export function LogsTabContent({ diff --git a/static/app/views/explore/logs/utils.tsx b/static/app/views/explore/logs/utils.tsx index 54f64587597b70..3bc51fcb7e9771 100644 --- a/static/app/views/explore/logs/utils.tsx +++ b/static/app/views/explore/logs/utils.tsx @@ -1,4 +1,3 @@ -import type {ReactNode} from 'react'; import * as Sentry from '@sentry/react'; import type {Location} from 'history'; import * as qs from 'query-string'; @@ -59,7 +58,7 @@ import { type BaseVisualize, type Visualize, } from 'sentry/views/explore/queryParams/visualize'; -import {generateTargetQuery, type PickableDays} from 'sentry/views/explore/utils'; +import {generateTargetQuery} from 'sentry/views/explore/utils'; import type {useSortedTimeSeries} from 'sentry/views/insights/common/queries/useSortedTimeSeries'; const {warn, fmt} = Sentry.logger; @@ -243,29 +242,6 @@ export function adjustLogTraceID(traceID: string) { return traceID.replace(/-/g, ''); } -export function logsPickableDays(): PickableDays { - const relativeOptions: Array<[string, ReactNode]> = [ - ['1h', t('Last hour')], - ['24h', t('Last 24 hours')], - ['7d', t('Last 7 days')], - ['14d', t('Last 14 days')], - ['30d', t('Last 30 days')], - ]; - - return { - defaultPeriod: '24h', - maxPickableDays: 30, - relativeOptions: ({ - arbitraryOptions, - }: { - arbitraryOptions: Record; - }) => ({ - ...arbitraryOptions, - ...Object.fromEntries(relativeOptions), - }), - }; -} - export function getDynamicLogsNextFetchThreshold(lastPageLength: number) { if (lastPageLength * 0.25 > LOGS_GRID_SCROLL_MIN_ITEM_THRESHOLD) { return Math.floor(lastPageLength * 0.25); // Can be up to 250 on large pages. diff --git a/static/app/views/explore/metrics/content.tsx b/static/app/views/explore/metrics/content.tsx index fbb4ec5399002a..011f3ed451858b 100644 --- a/static/app/views/explore/metrics/content.tsx +++ b/static/app/views/explore/metrics/content.tsx @@ -6,15 +6,17 @@ import PageFiltersContainer from 'sentry/components/organizations/pageFilters/co import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {IconMegaphone} from 'sentry/icons'; import {t} from 'sentry/locale'; +import {DataCategory} from 'sentry/types/core'; import {defined} from 'sentry/utils'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useFeedbackForm} from 'sentry/utils/useFeedbackForm'; import {useLocation} from 'sentry/utils/useLocation'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import ExploreBreadcrumb from 'sentry/views/explore/components/breadcrumb'; import {useGetSavedQuery} from 'sentry/views/explore/hooks/useGetSavedQueries'; import {MetricsTabOnboarding} from 'sentry/views/explore/metrics/metricsOnboarding'; import {MetricsTabContent} from 'sentry/views/explore/metrics/metricsTab'; -import {metricsPickableDays} from 'sentry/views/explore/metrics/utils'; import { getIdFromLocation, getTitleFromLocation, @@ -53,18 +55,27 @@ function FeedbackButton() { export default function MetricsContent() { const organization = useOrganization(); const onboardingProject = useOnboardingProject({property: 'hasTraceMetrics'}); - const {defaultPeriod, maxPickableDays, relativeOptions} = metricsPickableDays(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.TRACE_METRICS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); return ( @@ -72,16 +83,10 @@ export default function MetricsContent() { ) : ( - + )} diff --git a/static/app/views/explore/metrics/metricsOnboarding.tsx b/static/app/views/explore/metrics/metricsOnboarding.tsx index 45b0bc661496a2..293f3e289b4c42 100644 --- a/static/app/views/explore/metrics/metricsOnboarding.tsx +++ b/static/app/views/explore/metrics/metricsOnboarding.tsx @@ -16,6 +16,7 @@ import { } from 'sentry/components/onboarding/gettingStartedDoc/types'; import {useSourcePackageRegistries} from 'sentry/components/onboarding/gettingStartedDoc/useSourcePackageRegistries'; import {useLoadGettingStarted} from 'sentry/components/onboarding/gettingStartedDoc/utils/useLoadGettingStarted'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; @@ -40,7 +41,6 @@ import { FilterBarContainer, StyledPageFilterBar, } from 'sentry/views/explore/metrics/styles'; -import type {PickableDays} from 'sentry/views/explore/utils'; const METRICS_GH_DISCUSSION_LINK = 'https://github.com/getsentry/sentry/discussions/102275'; @@ -371,16 +371,15 @@ const Arcade = styled('iframe')` `; type MetricsTabOnboardingProps = { + datePageFilterProps: DatePageFilterProps; organization: Organization; project: Project; -} & PickableDays; +}; export function MetricsTabOnboarding({ + datePageFilterProps, organization, project, - defaultPeriod, - maxPickableDays, - relativeOptions, }: MetricsTabOnboardingProps) { return ( @@ -389,11 +388,7 @@ export function MetricsTabOnboarding({ - + diff --git a/static/app/views/explore/metrics/metricsTab.tsx b/static/app/views/explore/metrics/metricsTab.tsx index 881a03799660ab..4aa15416f6a6b2 100644 --- a/static/app/views/explore/metrics/metricsTab.tsx +++ b/static/app/views/explore/metrics/metricsTab.tsx @@ -2,6 +2,7 @@ import styled from '@emotion/styled'; import {Container, Flex} from 'sentry/components/core/layout'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; @@ -29,36 +30,25 @@ import { FilterBarWithSaveAsContainer, StyledPageFilterBar, } from 'sentry/views/explore/metrics/styles'; -import type {PickableDays} from 'sentry/views/explore/utils'; const MAX_METRICS_ALLOWED = 4; export const METRICS_CHART_GROUP = 'metrics-charts-group'; -type MetricsTabProps = PickableDays; +type MetricsTabProps = { + datePageFilterProps: DatePageFilterProps; +}; -export function MetricsTabContent({ - defaultPeriod, - maxPickableDays, - relativeOptions, -}: MetricsTabProps) { +export function MetricsTabContent({datePageFilterProps}: MetricsTabProps) { return ( - + ); } -function MetricsTabFilterSection({ - defaultPeriod, - maxPickableDays, - relativeOptions, -}: PickableDays) { +function MetricsTabFilterSection({datePageFilterProps}: MetricsTabProps) { return ( @@ -67,9 +57,7 @@ function MetricsTabFilterSection({ diff --git a/static/app/views/explore/metrics/utils.tsx b/static/app/views/explore/metrics/utils.tsx index 8e0d492211fe2f..c7e92babf01747 100644 --- a/static/app/views/explore/metrics/utils.tsx +++ b/static/app/views/explore/metrics/utils.tsx @@ -1,8 +1,6 @@ -import type {ReactNode} from 'react'; import qs from 'query-string'; import {MutableSearch} from 'sentry/components/searchSyntax/mutableSearch'; -import {t} from 'sentry/locale'; import type {PageFilters} from 'sentry/types/core'; import type {Organization} from 'sentry/types/organization'; import type {EventsMetaType, MetaType} from 'sentry/utils/discover/eventView'; @@ -29,7 +27,6 @@ import { import {isGroupBy, type GroupBy} from 'sentry/views/explore/queryParams/groupBy'; import type {VisualizeFunction} from 'sentry/views/explore/queryParams/visualize'; import {Visualize} from 'sentry/views/explore/queryParams/visualize'; -import type {PickableDays} from 'sentry/views/explore/utils'; export function makeMetricsPathname({ organizationSlug, @@ -55,29 +52,6 @@ export function createTraceMetricFilter(traceMetric: TraceMetric): string | unde : undefined; } -export function metricsPickableDays(): PickableDays { - const relativeOptions: Array<[string, ReactNode]> = [ - ['1h', t('Last hour')], - ['24h', t('Last 24 hours')], - ['7d', t('Last 7 days')], - ['14d', t('Last 14 days')], - ['30d', t('Last 30 days')], - ]; - - return { - defaultPeriod: '24h', - maxPickableDays: 30, // May change with downsampled multi month support. - relativeOptions: ({ - arbitraryOptions, - }: { - arbitraryOptions: Record; - }) => ({ - ...arbitraryOptions, - ...Object.fromEntries(relativeOptions), - }), - }; -} - export function getMetricsUnit( meta: MetaType | EventsMetaType, field: string diff --git a/static/app/views/explore/multiQueryMode/content.tsx b/static/app/views/explore/multiQueryMode/content.tsx index b91167553c6702..d1da5ba8012a1c 100644 --- a/static/app/views/explore/multiQueryMode/content.tsx +++ b/static/app/views/explore/multiQueryMode/content.tsx @@ -11,18 +11,23 @@ import {openSaveQueryModal} from 'sentry/actionCreators/modal'; import {Button} from 'sentry/components/core/button'; import {DropdownMenu} from 'sentry/components/dropdownMenu'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; +import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; import {ProjectPageFilter} from 'sentry/components/organizations/projectPageFilter'; import {IconAdd} from 'sentry/icons/iconAdd'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {DataCategory} from 'sentry/types/core'; import {defined} from 'sentry/utils'; import {trackAnalytics} from 'sentry/utils/analytics'; import {encodeSort} from 'sentry/utils/discover/eventView'; import {valueIsEqual} from 'sentry/utils/object/valueIsEqual'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; import {useLocation} from 'sentry/utils/useLocation'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import {WidgetSyncContextProvider} from 'sentry/views/dashboards/contexts/widgetSyncContext'; @@ -37,16 +42,18 @@ import { } from 'sentry/views/explore/multiQueryMode/locationUtils'; import {QueryRow} from 'sentry/views/explore/multiQueryMode/queryRow'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; export const MAX_QUERIES_ALLOWED = 5; -function Content() { +interface ContentProps { + datePageFilterProps: DatePageFilterProps; +} + +function Content({datePageFilterProps}: ContentProps) { const location = useLocation(); const organization = useOrganization(); const pageFilters = usePageFilters(); const {saveQuery, updateQuery} = useSaveMultiQuery(); - const datePageFilterProps = limitMaxPickableDays(organization); const queries = useReadQueriesFromLocation().slice(0, MAX_QUERIES_ALLOWED); const addQuery = useAddQuery(); const totalQueryRows = queries.length; @@ -205,10 +212,19 @@ function Content() { } export function MultiQueryModeContent() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.LOG_BYTE], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - - - + + + + + ); } diff --git a/static/app/views/explore/multiQueryMode/index.tsx b/static/app/views/explore/multiQueryMode/index.tsx index c1a929e60cede4..2181400ee84622 100644 --- a/static/app/views/explore/multiQueryMode/index.tsx +++ b/static/app/views/explore/multiQueryMode/index.tsx @@ -4,7 +4,6 @@ import {ButtonBar} from 'sentry/components/core/button/buttonBar'; import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton'; import * as Layout from 'sentry/components/layouts/thirds'; import {NoAccess} from 'sentry/components/noAccess'; -import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {t} from 'sentry/locale'; import {defined} from 'sentry/utils'; @@ -63,9 +62,7 @@ export default function MultiQueryMode() { - - - + diff --git a/static/app/views/explore/spans/content.tsx b/static/app/views/explore/spans/content.tsx index c2e85d2bdfd362..268f3daea48b64 100644 --- a/static/app/views/explore/spans/content.tsx +++ b/static/app/views/explore/spans/content.tsx @@ -11,7 +11,10 @@ import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {TourContextProvider} from 'sentry/components/tours/components'; import {useAssistant} from 'sentry/components/tours/useAssistant'; import {t} from 'sentry/locale'; +import {DataCategory} from 'sentry/types/core'; import {defined} from 'sentry/utils'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import ExploreBreadcrumb from 'sentry/views/explore/components/breadcrumb'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; @@ -32,7 +35,6 @@ import { } from 'sentry/views/explore/spans/tour'; import {StarSavedQueryButton} from 'sentry/views/explore/starSavedQueryButton'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {useOnboardingProject} from 'sentry/views/insights/common/queries/useOnboardingProject'; export function ExploreContent() { @@ -40,7 +42,11 @@ export function ExploreContent() { const organization = useOrganization(); const onboardingProject = useOnboardingProject(); - const datePageFilterProps = limitMaxPickableDays(organization); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); return ( diff --git a/static/app/views/explore/spans/spansTab.spec.tsx b/static/app/views/explore/spans/spansTab.spec.tsx index d743cad308eca4..b07bae285d4092 100644 --- a/static/app/views/explore/spans/spansTab.spec.tsx +++ b/static/app/views/explore/spans/spansTab.spec.tsx @@ -10,6 +10,7 @@ import { within, } from 'sentry-test/reactTestingLibrary'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import PageFiltersStore from 'sentry/stores/pageFiltersStore'; import type {TagCollection} from 'sentry/types/group'; import {trackAnalytics} from 'sentry/utils/analytics'; @@ -23,7 +24,6 @@ import { import {SpansQueryParamsProvider} from 'sentry/views/explore/spans/spansQueryParamsProvider'; import {SpansTabContent} from 'sentry/views/explore/spans/spansTab'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import type {PickableDays} from 'sentry/views/explore/utils'; function Wrapper({children}: {children: ReactNode}) { return ( @@ -47,7 +47,7 @@ const mockNumberTags: TagCollection = { numberTag2: {key: 'numberTag2', kind: FieldKind.MEASUREMENT, name: 'numberTag2'}, }; -const datePageFilterProps: PickableDays = { +const datePageFilterProps: DatePageFilterProps = { defaultPeriod: '7d' as const, maxPickableDays: 7, relativeOptions: ({arbitraryOptions}) => ({ diff --git a/static/app/views/explore/spans/spansTab.tsx b/static/app/views/explore/spans/spansTab.tsx index 7d1d2033c008f6..c2905f7311ef40 100644 --- a/static/app/views/explore/spans/spansTab.tsx +++ b/static/app/views/explore/spans/spansTab.tsx @@ -3,10 +3,10 @@ import {css} from '@emotion/react'; import styled from '@emotion/styled'; import Feature from 'sentry/components/acl/feature'; -import {getDiffInMinutes} from 'sentry/components/charts/utils'; import {Alert} from 'sentry/components/core/alert'; import {Button} from 'sentry/components/core/button'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; @@ -24,7 +24,6 @@ import {useCaseInsensitivity} from 'sentry/components/searchQueryBuilder/hooks'; import {TourElement} from 'sentry/components/tours/components'; import {IconChevron} from 'sentry/icons/iconChevron'; import {t} from 'sentry/locale'; -import type {PageFilters} from 'sentry/types/core'; import type {Organization} from 'sentry/types/organization'; import type {Project} from 'sentry/types/project'; import {defined} from 'sentry/utils'; @@ -85,7 +84,6 @@ import {useRawCounts} from 'sentry/views/explore/useRawCounts'; import { combineConfidenceForSeries, findSuggestedColumns, - type PickableDays, } from 'sentry/views/explore/utils'; import {Onboarding} from 'sentry/views/performance/onboarding'; @@ -93,7 +91,7 @@ import {Onboarding} from 'sentry/views/performance/onboarding'; import QuotaExceededAlert from 'getsentry/components/performance/quotaExceededAlert'; interface SpansTabOnboardingProps { - datePageFilterProps: PickableDays; + datePageFilterProps: DatePageFilterProps; organization: Organization; project: Project; } @@ -135,7 +133,7 @@ function useControlSectionExpanded() { } interface SpanTabProps { - datePageFilterProps: PickableDays; + datePageFilterProps: DatePageFilterProps; } export function SpansTabContent({datePageFilterProps}: SpanTabProps) { @@ -155,7 +153,6 @@ export function SpansTabContent({datePageFilterProps}: SpanTabProps) { controlSectionExpanded={controlSectionExpanded} /> @@ -175,7 +172,7 @@ function useVisitExplore() { } interface SpanTabSearchSectionProps { - datePageFilterProps: PickableDays; + datePageFilterProps: DatePageFilterProps; } function SpansSearchBar({ @@ -364,16 +361,14 @@ function SpanTabControlSection({ interface SpanTabContentSectionProps { controlSectionExpanded: boolean; - maxPickableDays: PickableDays['maxPickableDays']; setControlSectionExpanded: (expanded: boolean) => void; } function SpanTabContentSection({ - maxPickableDays, controlSectionExpanded, setControlSectionExpanded, }: SpanTabContentSectionProps) { - const {selection} = usePageFilters(); + const {isReady} = usePageFilters(); const query = useQueryParamsQuery(); const visualizes = useQueryParamsVisualizes(); const setVisualizes = useSetQueryParamsVisualizes(); @@ -387,36 +382,31 @@ function SpanTabContentSection({ const limit = 50; - const isAllowedSelection = useMemo( - () => checkIsAllowedSelection(selection, maxPickableDays), - [selection, maxPickableDays] - ); - const rawSpanCounts = useRawCounts({dataset: DiscoverDatasets.SPANS}); const aggregatesTableResult = useExploreAggregatesTable({ query, limit, - enabled: isAllowedSelection && queryType === 'aggregate', + enabled: isReady && queryType === 'aggregate', queryExtras: {caseInsensitive}, }); const spansTableResult = useExploreSpansTable({ query, limit, - enabled: isAllowedSelection && queryType === 'samples', + enabled: isReady && queryType === 'samples', queryExtras: {caseInsensitive}, }); const tracesTableResult = useExploreTracesTable({ query, limit, - enabled: isAllowedSelection && queryType === 'traces', + enabled: isReady && queryType === 'traces', queryExtras: {caseInsensitive}, }); const {result: timeseriesResult, samplingMode: timeseriesSamplingMode} = useExploreTimeseries({ query, - enabled: isAllowedSelection, + enabled: isReady, queryExtras: {caseInsensitive}, }); @@ -532,15 +522,6 @@ function SpanTabContentSection({ ); } -function checkIsAllowedSelection( - selection: PageFilters, - maxPickableDays: PickableDays['maxPickableDays'] -) { - const maxPickableMinutes = maxPickableDays * 24 * 60; - const selectedMinutes = getDiffInMinutes(selection.datetime); - return selectedMinutes <= maxPickableMinutes; -} - const StyledPageFilterBar = styled(PageFilterBar)` width: auto; `; diff --git a/static/app/views/explore/utils.tsx b/static/app/views/explore/utils.tsx index 3a7f2931dbdb84..b6a2c6a4d0a76d 100644 --- a/static/app/views/explore/utils.tsx +++ b/static/app/views/explore/utils.tsx @@ -1,5 +1,3 @@ -import type {ReactNode} from 'react'; -import styled from '@emotion/styled'; import * as Sentry from '@sentry/react'; import type {Location} from 'history'; import * as qs from 'query-string'; @@ -7,11 +5,7 @@ import * as qs from 'query-string'; import {Expression} from 'sentry/components/arithmeticBuilder/expression'; import {isTokenFunction} from 'sentry/components/arithmeticBuilder/token'; import {openConfirmModal} from 'sentry/components/confirm'; -import type {SelectOptionWithKey} from 'sentry/components/core/compactSelect/types'; -import {Flex} from 'sentry/components/core/layout'; import {getTooltipText as getAnnotatedTooltipText} from 'sentry/components/events/meta/annotatedText/utils'; -import HookOrDefault from 'sentry/components/hookOrDefault'; -import {IconBusiness} from 'sentry/icons/iconBusiness'; import {t} from 'sentry/locale'; import type {PageFilters} from 'sentry/types/core'; import type {Tag, TagCollection} from 'sentry/types/group'; @@ -402,76 +396,6 @@ export function viewSamplesTarget({ }); } -type MaxPickableDays = 7 | 14 | 30 | 90; -type DefaultPeriod = '24h' | '7d' | '14d' | '30d' | '90d'; - -export interface PickableDays { - defaultPeriod: DefaultPeriod; - maxPickableDays: MaxPickableDays; - relativeOptions: ({ - arbitraryOptions, - }: { - arbitraryOptions: Record; - }) => Record; - isOptionDisabled?: ({value}: SelectOptionWithKey) => boolean; - menuFooter?: ReactNode; -} - -export function limitMaxPickableDays(organization: Organization): PickableDays { - const defaultPeriods: Record = { - 7: '7d', - 14: '14d', - 30: '30d', - 90: '90d', - }; - - const relativeOptions: Array<[DefaultPeriod, ReactNode]> = [ - ['7d', t('Last 7 days')], - ['14d', t('Last 14 days')], - ['30d', t('Last 30 days')], - ['90d', t('Last 90 days')], - ]; - - const maxPickableDays: MaxPickableDays = organization.features.includes( - 'visibility-explore-range-high' - ) - ? 90 - : 30; - const defaultPeriod: DefaultPeriod = defaultPeriods[maxPickableDays]; - - const index = relativeOptions.findIndex(([period, _]) => period === defaultPeriod) + 1; - const enabledOptions = Object.fromEntries(relativeOptions.slice(0, index)); - const disabledOptions = Object.fromEntries( - relativeOptions.slice(index).map(([value, label]) => { - return [value, ]; - }) - ); - - const isOptionDisabled = (option: SelectOptionWithKey): boolean => { - return disabledOptions.hasOwnProperty(option.value); - }; - - const menuFooter = index === relativeOptions.length ? null : ; - - return { - defaultPeriod, - isOptionDisabled, - maxPickableDays, - menuFooter, - relativeOptions: ({ - arbitraryOptions, - }: { - arbitraryOptions: Record; - }) => ({ - ...arbitraryOptions, - '1h': t('Last hour'), - '24h': t('Last 24 hours'), - ...enabledOptions, - ...disabledOptions, - }), - }; -} - export function getDefaultExploreRoute(organization: Organization) { if ( organization.features.includes('performance-trace-explorer') || @@ -511,24 +435,6 @@ export function computeVisualizeSampleTotals( }); } -function DisabledDateOption({label}: {label: ReactNode}) { - return ( - - {label} - - - ); -} - -const StyledIconBuisness = styled(IconBusiness)` - margin-left: auto; -`; - -const UpsellFooterHook = HookOrDefault({ - hookName: 'component:explore-date-range-query-limit-footer', - defaultComponent: () => undefined, -}); - export function confirmDeleteSavedQuery({ handleDelete, savedQuery, diff --git a/static/app/views/insights/agentModels/views/modelsLandingPage.tsx b/static/app/views/insights/agentModels/views/modelsLandingPage.tsx index cdefd9be99d455..226a59af066d08 100644 --- a/static/app/views/insights/agentModels/views/modelsLandingPage.tsx +++ b/static/app/views/insights/agentModels/views/modelsLandingPage.tsx @@ -2,14 +2,17 @@ import {Fragment} from 'react'; import {Flex} from 'sentry/components/core/layout'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -28,10 +31,12 @@ import {Onboarding} from 'sentry/views/insights/pages/agents/onboarding'; import {TableUrlParams} from 'sentry/views/insights/pages/agents/utils/urlParams'; import {ModuleName} from 'sentry/views/insights/types'; -function AgentModelsLandingPage() { - const organization = useOrganization(); +interface AgentModelsLandingPageProps { + datePageFilterProps: DatePageFilterProps; +} + +function AgentModelsLandingPage({datePageFilterProps}: AgentModelsLandingPageProps) { const showOnboarding = useShowAgentOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); useDefaultToAllProjects(); const agentSpanSearchProps = useAgentSpanSearchProps(); @@ -93,13 +98,21 @@ function AgentModelsLandingPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + ); diff --git a/static/app/views/insights/agentTools/views/toolsLandingPage.tsx b/static/app/views/insights/agentTools/views/toolsLandingPage.tsx index fe25486d7b8b8c..2d43612e5e3c2c 100644 --- a/static/app/views/insights/agentTools/views/toolsLandingPage.tsx +++ b/static/app/views/insights/agentTools/views/toolsLandingPage.tsx @@ -2,14 +2,17 @@ import {Fragment} from 'react'; import {Flex} from 'sentry/components/core/layout'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -27,10 +30,12 @@ import {Onboarding} from 'sentry/views/insights/pages/agents/onboarding'; import {TableUrlParams} from 'sentry/views/insights/pages/agents/utils/urlParams'; import {ModuleName} from 'sentry/views/insights/types'; -function AgentToolsLandingPage() { - const organization = useOrganization(); +interface AgentToolsLandingPageProps { + datePageFilterProps: DatePageFilterProps; +} + +function AgentToolsLandingPage({datePageFilterProps}: AgentToolsLandingPageProps) { const showOnboarding = useShowAgentOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); useDefaultToAllProjects(); const agentSpanSearchProps = useAgentSpanSearchProps(); @@ -89,13 +94,21 @@ function AgentToolsLandingPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + ); diff --git a/static/app/views/insights/aiGenerations/views/overview.tsx b/static/app/views/insights/aiGenerations/views/overview.tsx index ed3da8b39cc759..81ee5c2f559c04 100644 --- a/static/app/views/insights/aiGenerations/views/overview.tsx +++ b/static/app/views/insights/aiGenerations/views/overview.tsx @@ -7,6 +7,7 @@ import {Button} from '@sentry/scraps/button'; import {Container, Flex, Stack} from '@sentry/scraps/layout'; import {openModal} from 'sentry/actionCreators/modal'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import { @@ -17,9 +18,12 @@ import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/c import {useCaseInsensitivity} from 'sentry/components/searchQueryBuilder/hooks'; import {IconChevron, IconEdit} from 'sentry/icons'; import {t} from 'sentry/locale'; +import {DataCategory} from 'sentry/types/core'; import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField'; import {chonkStyled} from 'sentry/utils/theme/theme.chonk'; import {withChonk} from 'sentry/utils/theme/withChonk'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; @@ -31,7 +35,6 @@ import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceIte import {SpansQueryParamsProvider} from 'sentry/views/explore/spans/spansQueryParamsProvider'; import {ColumnEditorModal} from 'sentry/views/explore/tables/columnEditorModal'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {GenerationsChart} from 'sentry/views/insights/aiGenerations/views/components/generationsChart'; import {GenerationsTable} from 'sentry/views/insights/aiGenerations/views/components/generationsTable'; import {GenerationsToolbar} from 'sentry/views/insights/aiGenerations/views/components/generationsToolbar'; @@ -58,11 +61,14 @@ function useShowOnboarding() { return !selectedProjects.some(p => p.hasInsightsAgentMonitoring); } -function AIGenerationsPage() { +interface AIGenerationsPageProps { + datePageFilterProps: DatePageFilterProps; +} + +function AIGenerationsPage({datePageFilterProps}: AIGenerationsPageProps) { const organization = useOrganization(); const [sidebarOpen, setSidebarOpen] = useState(true); const showOnboarding = useShowOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); const [caseInsensitive, setCaseInsensitive] = useCaseInsensitivity(); const [searchQuery, setSearchQuery] = useQueryState( @@ -255,11 +261,21 @@ function AIGenerationsPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + - + diff --git a/static/app/views/insights/common/components/modulePageProviders.tsx b/static/app/views/insights/common/components/modulePageProviders.tsx index ec4d8dca88720e..97a03ad494a0b5 100644 --- a/static/app/views/insights/common/components/modulePageProviders.tsx +++ b/static/app/views/insights/common/components/modulePageProviders.tsx @@ -1,5 +1,6 @@ import * as Layout from 'sentry/components/layouts/thirds'; import NoProjectMessage from 'sentry/components/noProjectMessage'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import type {InsightEventKey} from 'sentry/utils/analytics/insightAnalyticEvents'; @@ -18,6 +19,7 @@ interface Props { children: React.ReactNode; moduleName: TitleableModuleNames; analyticEventName?: InsightEventKey; + maxPickableDays?: DatePageFilterProps['maxPickableDays']; pageTitle?: string; } @@ -26,6 +28,7 @@ export function ModulePageProviders({ pageTitle, children, analyticEventName, + maxPickableDays, }: Props) { const organization = useOrganization(); const moduleTitles = useModuleTitles(); @@ -45,7 +48,9 @@ export function ModulePageProviders({ return ( diff --git a/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx b/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx index 018db53c5c676f..bf602c0a1df59e 100644 --- a/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx +++ b/static/app/views/insights/mcp-prompts/views/mcpPromptsLandingPage.tsx @@ -4,13 +4,16 @@ import {Flex} from '@sentry/scraps/layout'; import * as Layout from 'sentry/components/layouts/thirds'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -28,11 +31,12 @@ import {useShowMCPOnboarding} from 'sentry/views/insights/pages/mcp/hooks/useSho import {Onboarding} from 'sentry/views/insights/pages/mcp/onboarding'; import {ModuleName} from 'sentry/views/insights/types'; -function McpPromptsLandingPage() { - const organization = useOrganization(); - const showOnboarding = useShowMCPOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); +interface McpPromptsLandingPageProps { + datePageFilterProps: DatePageFilterProps; +} +function McpPromptsLandingPage({datePageFilterProps}: McpPromptsLandingPageProps) { + const showOnboarding = useShowMCPOnboarding(); const mcpSpanSearchProps = useMcpSpanSearchProps(); return ( @@ -89,13 +93,21 @@ function McpPromptsLandingPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + ); diff --git a/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx b/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx index a8366e52780a75..3b981a5b82041c 100644 --- a/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx +++ b/static/app/views/insights/mcp-resources/views/mcpResourcesLandingPage.tsx @@ -3,14 +3,17 @@ import {Fragment} from 'react'; import {Flex} from '@sentry/scraps/layout'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -28,11 +31,12 @@ import {useShowMCPOnboarding} from 'sentry/views/insights/pages/mcp/hooks/useSho import {Onboarding} from 'sentry/views/insights/pages/mcp/onboarding'; import {ModuleName} from 'sentry/views/insights/types'; -function McpResourcesLandingPage() { - const organization = useOrganization(); - const showOnboarding = useShowMCPOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); +interface McpResourcesLandingPageProps { + datePageFilterProps: DatePageFilterProps; +} +function McpResourcesLandingPage({datePageFilterProps}: McpResourcesLandingPageProps) { + const showOnboarding = useShowMCPOnboarding(); const mcpSpanSearchProps = useMcpSpanSearchProps(); return ( @@ -89,13 +93,21 @@ function McpResourcesLandingPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + ); diff --git a/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx b/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx index 697e96954c9fec..0e0db946e954c6 100644 --- a/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx +++ b/static/app/views/insights/mcp-tools/views/mcpToolsLandingPage.tsx @@ -3,14 +3,17 @@ import {Fragment} from 'react'; import {Flex} from '@sentry/scraps/layout'; import * as Layout from 'sentry/components/layouts/thirds'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import {ModuleFeature} from 'sentry/views/insights/common/components/moduleFeature'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; @@ -28,11 +31,12 @@ import {useShowMCPOnboarding} from 'sentry/views/insights/pages/mcp/hooks/useSho import {Onboarding} from 'sentry/views/insights/pages/mcp/onboarding'; import {ModuleName} from 'sentry/views/insights/types'; -function McpToolsLandingPage() { - const organization = useOrganization(); - const showOnboarding = useShowMCPOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); +interface McpToolsLandingPageProps { + datePageFilterProps: DatePageFilterProps; +} +function McpToolsLandingPage({datePageFilterProps}: McpToolsLandingPageProps) { + const showOnboarding = useShowMCPOnboarding(); const mcpSpanSearchProps = useMcpSpanSearchProps(); return ( @@ -89,13 +93,21 @@ function McpToolsLandingPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + ); diff --git a/static/app/views/insights/pages/agents/overview.tsx b/static/app/views/insights/pages/agents/overview.tsx index bc70d33174cad8..1e271c2db6a0d3 100644 --- a/static/app/views/insights/pages/agents/overview.tsx +++ b/static/app/views/insights/pages/agents/overview.tsx @@ -6,17 +6,20 @@ import {Flex, Stack} from 'sentry/components/core/layout'; import * as Layout from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {NoAccess} from 'sentry/components/noAccess'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; import {InsightsProjectSelector} from 'sentry/views/insights/common/components/projectSelector'; @@ -54,10 +57,13 @@ function useShowOnboarding() { return !selectedProjects.some(p => p.hasInsightsAgentMonitoring); } -function AgentsOverviewPage() { +interface AgentsOverviewPageProps { + datePageFilterProps: DatePageFilterProps; +} + +function AgentsOverviewPage({datePageFilterProps}: AgentsOverviewPageProps) { const organization = useOrganization(); const showOnboarding = useShowOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); useDefaultToAllProjects(); const {value: conversationTable} = useConversationsTableSwitch(); @@ -166,10 +172,17 @@ function AgentsOverviewPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + - + ); diff --git a/static/app/views/insights/pages/domainOverviewPageProviders.tsx b/static/app/views/insights/pages/domainOverviewPageProviders.tsx index 4c1159068ec07e..2dc1561dc05789 100644 --- a/static/app/views/insights/pages/domainOverviewPageProviders.tsx +++ b/static/app/views/insights/pages/domainOverviewPageProviders.tsx @@ -1,4 +1,7 @@ +import type {ReactNode} from 'react'; + import NoProjectMessage from 'sentry/components/noProjectMessage'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import PageFiltersContainer from 'sentry/components/organizations/pageFilters/container'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {MEPSettingProvider} from 'sentry/utils/performance/contexts/metricsEnhancedSetting'; @@ -7,14 +10,22 @@ import useOrganization from 'sentry/utils/useOrganization'; import {OVERVIEW_PAGE_TITLE} from 'sentry/views/insights/pages/settings'; import {useDomainViewFilters} from 'sentry/views/insights/pages/useFilters'; -export function DomainOverviewPageProviders({children}: {children: React.ReactNode}) { +interface DomainOverviewPageProvidersProps { + children: ReactNode; + maxPickableDays?: DatePageFilterProps['maxPickableDays']; +} + +export function DomainOverviewPageProviders({ + children, + maxPickableDays, +}: DomainOverviewPageProvidersProps) { const organization = useOrganization(); const location = useLocation(); const {view} = useDomainViewFilters(); return ( - + {children} diff --git a/static/app/views/insights/pages/mcp/overview.tsx b/static/app/views/insights/pages/mcp/overview.tsx index 1aa627f031f66a..94a9a266bc2316 100644 --- a/static/app/views/insights/pages/mcp/overview.tsx +++ b/static/app/views/insights/pages/mcp/overview.tsx @@ -5,15 +5,18 @@ import {Flex} from '@sentry/scraps/layout'; import Feature from 'sentry/components/acl/feature'; import * as Layout from 'sentry/components/layouts/thirds'; import {NoAccess} from 'sentry/components/noAccess'; +import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {DatePageFilter} from 'sentry/components/organizations/datePageFilter'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import {EAPSpanSearchQueryBuilder} from 'sentry/components/performance/spanSearchQueryBuilder'; import {SearchQueryBuilderProvider} from 'sentry/components/searchQueryBuilder/context'; +import {DataCategory} from 'sentry/types/core'; import {trackAnalytics} from 'sentry/utils/analytics'; +import {useDatePageFilterProps} from 'sentry/utils/useDatePageFilterProps'; +import {useMaxPickableDays} from 'sentry/utils/useMaxPickableDays'; import useOrganization from 'sentry/utils/useOrganization'; import {TraceItemAttributeProvider} from 'sentry/views/explore/contexts/traceItemAttributeContext'; import {TraceItemDataset} from 'sentry/views/explore/types'; -import {limitMaxPickableDays} from 'sentry/views/explore/utils'; import {InsightsEnvironmentSelector} from 'sentry/views/insights/common/components/enviornmentSelector'; import * as ModuleLayout from 'sentry/views/insights/common/components/moduleLayout'; import {InsightsProjectSelector} from 'sentry/views/insights/common/components/projectSelector'; @@ -33,10 +36,13 @@ import {useShowMCPOnboarding} from 'sentry/views/insights/pages/mcp/hooks/useSho import {Onboarding} from 'sentry/views/insights/pages/mcp/onboarding'; import {useOverviewPageTrackPageload} from 'sentry/views/insights/pages/useOverviewPageTrackAnalytics'; -function McpOverviewPage() { +interface McpOverviewPageProps { + datePageFilterProps: DatePageFilterProps; +} + +function McpOverviewPage({datePageFilterProps}: McpOverviewPageProps) { const organization = useOrganization(); const showOnboarding = useShowMCPOnboarding(); - const datePageFilterProps = limitMaxPickableDays(organization); useOverviewPageTrackPageload(); @@ -118,10 +124,17 @@ function McpOverviewPage() { } function PageWithProviders() { + const organization = useOrganization(); + const maxPickableDays = useMaxPickableDays({ + dataCategories: [DataCategory.SPANS], + organization, + }); + const datePageFilterProps = useDatePageFilterProps(maxPickableDays); + return ( - + - + ); diff --git a/static/gsApp/components/features/exploreDateRangeQueryLimitFooter.tsx b/static/gsApp/components/features/exploreDateRangeQueryLimitFooter.tsx deleted file mode 100644 index e4080481ef0884..00000000000000 --- a/static/gsApp/components/features/exploreDateRangeQueryLimitFooter.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import {t} from 'sentry/locale'; - -import DateRangeQueryLimitFooter from 'getsentry/components/features/dateRangeQueryLimitFooter'; - -const DESCRIPTION = t('To query over longer time ranges, upgrade to Business'); - -const QUERY_LIMIT_REFERRER = 'explore-spans-query-limit-footer'; - -export default function ExploreDateRangeQueryLimitFooter() { - return ( - - ); -} diff --git a/static/gsApp/registerHooks.tsx b/static/gsApp/registerHooks.tsx index db1d648ee96451..002e5638c80065 100644 --- a/static/gsApp/registerHooks.tsx +++ b/static/gsApp/registerHooks.tsx @@ -11,6 +11,7 @@ import DashboardBanner from 'getsentry/components/dashboardBanner'; import DataConsentBanner from 'getsentry/components/dataConsentBanner'; import DataConsentOrgCreationCheckbox from 'getsentry/components/dataConsentCheckbox'; import DataConsentPriorityLearnMore from 'getsentry/components/dataConsentPriorityLearnMore'; +import DateRangeQueryLimitFooter from 'getsentry/components/features/dateRangeQueryLimitFooter'; import DisabledAlertWizard from 'getsentry/components/features/disabledAlertWizard'; import DisabledAuthProvider from 'getsentry/components/features/disabledAuthProvider'; import DisabledCustomInboundFilters from 'getsentry/components/features/disabledCustomInboundFilters'; @@ -19,7 +20,6 @@ import DisabledDateRange from 'getsentry/components/features/disabledDateRange'; import DisabledDiscardGroup from 'getsentry/components/features/disabledDiscardGroup'; import DisabledRateLimits from 'getsentry/components/features/disabledRateLimits'; import DisabledSelectorItems from 'getsentry/components/features/disabledSelectorItems'; -import ExploreDateRangeQueryLimitFooter from 'getsentry/components/features/exploreDateRangeQueryLimitFooter'; import InsightsDateRangeQueryLimitFooter from 'getsentry/components/features/insightsDateRangeQueryLimitFooter'; import PerformanceNewProjectPrompt from 'getsentry/components/features/performanceNewProjectPrompt'; import ProjectPerformanceScoreCard from 'getsentry/components/features/projectPerformanceScoreCard'; @@ -204,8 +204,7 @@ const GETSENTRY_HOOKS: Partial = { ContinuousProfilingBetaSDKAlertBanner, 'component:continuous-profiling-billing-requirement-banner': () => ContinuousProfilingBillingRequirementBanner, - 'component:explore-date-range-query-limit-footer': () => - ExploreDateRangeQueryLimitFooter, + 'component:header-date-page-filter-upsell-footer': () => DateRangeQueryLimitFooter, /** * Augment the datetime picker based on plan retention days. Includes upsell interface */ From 5e9aa951fabf2f2dcbf6b2f132fff93fd89a589d Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Fri, 21 Nov 2025 12:27:31 -0500 Subject: [PATCH 2/4] fix typing --- static/app/views/explore/logs/logsTab.spec.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/app/views/explore/logs/logsTab.spec.tsx b/static/app/views/explore/logs/logsTab.spec.tsx index 8fed38f8ef6178..e71b3e1bae0ff9 100644 --- a/static/app/views/explore/logs/logsTab.spec.tsx +++ b/static/app/views/explore/logs/logsTab.spec.tsx @@ -171,7 +171,7 @@ describe('LogsTabContent', () => { it('should call APIs as expected', async () => { render( - + , {initialRouterConfig, organization} ); @@ -213,7 +213,7 @@ describe('LogsTabContent', () => { it('should switch between modes', async () => { render( - + , {initialRouterConfig, organization} ); @@ -257,7 +257,7 @@ describe('LogsTabContent', () => { it('should pass caseInsensitive to the query', async () => { render( - + , {initialRouterConfig, organization} ); From baad3c2cff3a36aed5e9a6faf4019948c834e8fd Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Fri, 21 Nov 2025 12:27:53 -0500 Subject: [PATCH 3/4] fix incorrect data category --- static/app/views/explore/multiQueryMode/content.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/app/views/explore/multiQueryMode/content.tsx b/static/app/views/explore/multiQueryMode/content.tsx index d1da5ba8012a1c..8a7b8896fdc0bf 100644 --- a/static/app/views/explore/multiQueryMode/content.tsx +++ b/static/app/views/explore/multiQueryMode/content.tsx @@ -214,7 +214,7 @@ function Content({datePageFilterProps}: ContentProps) { export function MultiQueryModeContent() { const organization = useOrganization(); const maxPickableDays = useMaxPickableDays({ - dataCategories: [DataCategory.LOG_BYTE], + dataCategories: [DataCategory.SPANS], organization, }); const datePageFilterProps = useDatePageFilterProps(maxPickableDays); From ba8546d6746d7b9c2ffd7fce161a550dee2734e9 Mon Sep 17 00:00:00 2001 From: Tony Xiao Date: Mon, 24 Nov 2025 15:17:37 -0500 Subject: [PATCH 4/4] resolve feedback --- static/app/utils/useDatePageFilterProps.tsx | 14 +--- static/app/utils/useMaxPickableDays.spec.tsx | 68 +++++++++----------- static/app/utils/useMaxPickableDays.tsx | 48 ++++---------- 3 files changed, 47 insertions(+), 83 deletions(-) diff --git a/static/app/utils/useDatePageFilterProps.tsx b/static/app/utils/useDatePageFilterProps.tsx index 43914501960103..0e0ae841d86aba 100644 --- a/static/app/utils/useDatePageFilterProps.tsx +++ b/static/app/utils/useDatePageFilterProps.tsx @@ -3,7 +3,6 @@ import {useMemo, type ReactNode} from 'react'; import type {SelectOptionWithKey} from 'sentry/components/core/compactSelect/types'; import type {DatePageFilterProps} from 'sentry/components/organizations/datePageFilter'; import {t} from 'sentry/locale'; -import {defined} from 'sentry/utils'; import {isEmptyObject} from 'sentry/utils/object/isEmptyObject'; import type {MaxPickableDaysOptions} from 'sentry/utils/useMaxPickableDays'; @@ -16,10 +15,7 @@ export function useDatePageFilterProps({ upsellFooter, }: UseDatePageFilterPropsProps): DatePageFilterProps { return useMemo(() => { - if (!defined(maxPickableDays)) { - return {}; - } - + // ensure the available relative options are always sorted const availableRelativeOptions: Array<[number, string, ReactNode]> = [ [1 / 24, '1h', t('Last hour')], [1, '24h', t('Last 24 hours')], @@ -28,8 +24,6 @@ export function useDatePageFilterProps({ [30, '30d', t('Last 30 days')], [90, '90d', t('Last 90 days')], ]; - // ensure the available relative options are always sorted - availableRelativeOptions.sort((a, b) => a[0] - b[0]); // find the relative options that should be enabled based on the maxPickableDays const pickableIndex = @@ -41,10 +35,8 @@ export function useDatePageFilterProps({ ); // find the relative options that should be disabled based on the maxUpgradableDays - // if maxUpgradableDays isn't defined, there should be no disabled options - const upgradableIndex = maxUpgradableDays - ? availableRelativeOptions.findLastIndex(([days]) => days <= maxUpgradableDays) + 1 - : pickableIndex; + const upgradableIndex = + availableRelativeOptions.findLastIndex(([days]) => days <= maxUpgradableDays) + 1; const disabledOptions = Object.fromEntries( availableRelativeOptions .slice(pickableIndex, upgradableIndex) diff --git a/static/app/utils/useMaxPickableDays.spec.tsx b/static/app/utils/useMaxPickableDays.spec.tsx index 01311d2556caeb..1f6cce4fae04af 100644 --- a/static/app/utils/useMaxPickableDays.spec.tsx +++ b/static/app/utils/useMaxPickableDays.spec.tsx @@ -1,85 +1,81 @@ import {OrganizationFixture} from 'sentry-fixture/organization'; -import {renderHookWithProviders} from 'sentry-test/reactTestingLibrary'; +import {renderHook} from 'sentry-test/reactTestingLibrary'; import {DataCategory} from 'sentry/types/core'; import {useMaxPickableDays} from './useMaxPickableDays'; describe('useMaxPickableDays', () => { - it.each([ - [[]], - [[DataCategory.ERRORS, DataCategory.REPLAYS]], - [[DataCategory.ERRORS]], - [[DataCategory.REPLAYS]], - ])('returns undefined for %s', dataCategories => { - const {result} = renderHookWithProviders(() => + it('returns 30/90 for spans without flag', () => { + const {result} = renderHook(() => useMaxPickableDays({ - dataCategories, - organization: OrganizationFixture(), + dataCategories: [DataCategory.SPANS], + organization: OrganizationFixture({features: []}), }) ); expect(result.current).toEqual({ - maxPickableDays: undefined, - maxUpgradableDays: undefined, + maxPickableDays: 30, + maxUpgradableDays: 90, + upsellFooter: expect.any(Object), }); }); - it('returns 30/30 days for logs', () => { - const {result} = renderHookWithProviders(() => + it('returns 90/90 for spans with flag', () => { + const {result} = renderHook(() => useMaxPickableDays({ - dataCategories: [DataCategory.LOG_BYTE, DataCategory.LOG_ITEM], - organization: OrganizationFixture(), + dataCategories: [DataCategory.SPANS], + organization: OrganizationFixture({features: ['visibility-explore-range-high']}), }) ); expect(result.current).toEqual({ - defaultPeriod: '24h', - maxPickableDays: 30, - maxUpgradableDays: 30, + maxPickableDays: 90, + maxUpgradableDays: 90, + upsellFooter: expect.any(Object), }); }); - it('returns 30/90 for spans without flag', () => { - const {result} = renderHookWithProviders(() => + it('returns 30/30 days for tracemetrics', () => { + const {result} = renderHook(() => useMaxPickableDays({ - dataCategories: [DataCategory.SPANS], - organization: OrganizationFixture({features: []}), + dataCategories: [DataCategory.TRACE_METRICS], + organization: OrganizationFixture(), }) ); expect(result.current).toEqual({ + defaultPeriod: '24h', maxPickableDays: 30, - maxUpgradableDays: 90, - upsellFooter: expect.any(Object), + maxUpgradableDays: 30, }); }); - it('returns 90/90 for spans with flag', () => { - const {result} = renderHookWithProviders(() => + it('returns 30/30 days for logs', () => { + const {result} = renderHook(() => useMaxPickableDays({ - dataCategories: [DataCategory.SPANS], - organization: OrganizationFixture({features: ['visibility-explore-range-high']}), + dataCategories: [DataCategory.LOG_BYTE, DataCategory.LOG_ITEM], + organization: OrganizationFixture(), }) ); expect(result.current).toEqual({ - maxPickableDays: 90, - maxUpgradableDays: 90, - upsellFooter: expect.any(Object), + defaultPeriod: '24h', + maxPickableDays: 30, + maxUpgradableDays: 30, }); }); it('returns 30/90 for many without flag', () => { - const {result} = renderHookWithProviders(() => + const {result} = renderHook(() => useMaxPickableDays({ dataCategories: [ - DataCategory.PROFILE_DURATION, - DataCategory.PROFILE_DURATION_UI, + DataCategory.SPANS, + DataCategory.SPANS_INDEXED, + DataCategory.TRACE_METRICS, DataCategory.LOG_BYTE, DataCategory.LOG_ITEM, - DataCategory.SPANS, ], organization: OrganizationFixture(), }) diff --git a/static/app/utils/useMaxPickableDays.tsx b/static/app/utils/useMaxPickableDays.tsx index 8d49b9f29a9286..08b57e3ffe7568 100644 --- a/static/app/utils/useMaxPickableDays.tsx +++ b/static/app/utils/useMaxPickableDays.tsx @@ -5,23 +5,22 @@ import type {DatePageFilterProps} from 'sentry/components/organizations/datePage import {t} from 'sentry/locale'; import {DataCategory} from 'sentry/types/core'; import type {Organization} from 'sentry/types/organization'; -import {defined} from 'sentry/utils'; export interface MaxPickableDaysOptions { /** * The maximum number of days the user is allowed to pick on the date page filter */ - maxPickableDays: DatePageFilterProps['maxPickableDays']; + maxPickableDays: NonNullable; /** * The maximum number of days the user can upgrade to on the date page filter */ - maxUpgradableDays: DatePageFilterProps['maxPickableDays']; + maxUpgradableDays: NonNullable; defaultPeriod?: DatePageFilterProps['defaultPeriod']; upsellFooter?: ReactNode; } interface UseMaxPickableDaysProps { - dataCategories: DataCategory[]; + dataCategories: readonly [DataCategory, ...DataCategory[]]; organization: Organization; } @@ -39,15 +38,13 @@ export function useMaxPickableDays({ } function getBestMaxPickableDays( - dataCategories: DataCategory[], + dataCategories: readonly [DataCategory, ...DataCategory[]], getMaxPickableDaysFor: (dataCategory: DataCategory) => MaxPickableDaysOptions ) { - let maxPickableDays: MaxPickableDaysOptions = { - maxPickableDays: undefined, - maxUpgradableDays: undefined, - }; + let maxPickableDays: MaxPickableDaysOptions = getMaxPickableDaysFor(dataCategories[0]); - for (const dataCategory of dataCategories) { + for (let i = 1; i < dataCategories.length; i++) { + const dataCategory = dataCategories[i]!; const maxPickableDaysForDataCategory = getMaxPickableDaysFor(dataCategory); maxPickableDays = max(maxPickableDays, maxPickableDaysForDataCategory); } @@ -59,35 +56,15 @@ function max( a: MaxPickableDaysOptions, b: MaxPickableDaysOptions ): MaxPickableDaysOptions { - if (!defined(a.maxPickableDays)) { - return b; - } - - if (!defined(b.maxPickableDays)) { - return a; - } - - if (a.maxPickableDays > b.maxPickableDays) { - return a; - } - if (a.maxPickableDays < b.maxPickableDays) { return b; } - if (!defined(a.maxUpgradableDays)) { + if (a.maxUpgradableDays < b.maxUpgradableDays) { return b; } - if (!defined(b.maxUpgradableDays)) { - return a; - } - - if (a.maxUpgradableDays > b.maxUpgradableDays) { - return a; - } - - return b; + return a; } const DESCRIPTION = t('To query over longer time ranges, upgrade to Business'); @@ -119,10 +96,9 @@ function getMaxPickableDays( defaultPeriod: '24h', }; default: - return { - maxPickableDays: undefined, - maxUpgradableDays: undefined, - }; + throw new Error( + `Unsupported data category: ${dataCategory} for getMaxPickableDays` + ); } }