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..0e0ae841d86aba --- /dev/null +++ b/static/app/utils/useDatePageFilterProps.tsx @@ -0,0 +1,64 @@ +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 {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(() => { + // 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')], + [7, '7d', t('Last 7 days')], + [14, '14d', t('Last 14 days')], + [30, '30d', t('Last 30 days')], + [90, '90d', t('Last 90 days')], + ]; + + // 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 + const upgradableIndex = + availableRelativeOptions.findLastIndex(([days]) => days <= maxUpgradableDays) + 1; + 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..1f6cce4fae04af --- /dev/null +++ b/static/app/utils/useMaxPickableDays.spec.tsx @@ -0,0 +1,90 @@ +import {OrganizationFixture} from 'sentry-fixture/organization'; + +import {renderHook} from 'sentry-test/reactTestingLibrary'; + +import {DataCategory} from 'sentry/types/core'; + +import {useMaxPickableDays} from './useMaxPickableDays'; + +describe('useMaxPickableDays', () => { + it('returns 30/90 for spans without flag', () => { + const {result} = renderHook(() => + 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} = renderHook(() => + 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/30 days for tracemetrics', () => { + const {result} = renderHook(() => + useMaxPickableDays({ + dataCategories: [DataCategory.TRACE_METRICS], + organization: OrganizationFixture(), + }) + ); + + expect(result.current).toEqual({ + defaultPeriod: '24h', + maxPickableDays: 30, + maxUpgradableDays: 30, + }); + }); + + it('returns 30/30 days for logs', () => { + const {result} = renderHook(() => + 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 many without flag', () => { + const {result} = renderHook(() => + useMaxPickableDays({ + dataCategories: [ + DataCategory.SPANS, + DataCategory.SPANS_INDEXED, + DataCategory.TRACE_METRICS, + DataCategory.LOG_BYTE, + DataCategory.LOG_ITEM, + ], + 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..08b57e3ffe7568 --- /dev/null +++ b/static/app/utils/useMaxPickableDays.tsx @@ -0,0 +1,108 @@ +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'; + +export interface MaxPickableDaysOptions { + /** + * The maximum number of days the user is allowed to pick on the date page filter + */ + maxPickableDays: NonNullable; + /** + * The maximum number of days the user can upgrade to on the date page filter + */ + maxUpgradableDays: NonNullable; + defaultPeriod?: DatePageFilterProps['defaultPeriod']; + upsellFooter?: ReactNode; +} + +interface UseMaxPickableDaysProps { + dataCategories: readonly [DataCategory, ...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: readonly [DataCategory, ...DataCategory[]], + getMaxPickableDaysFor: (dataCategory: DataCategory) => MaxPickableDaysOptions +) { + let maxPickableDays: MaxPickableDaysOptions = getMaxPickableDaysFor(dataCategories[0]); + + for (let i = 1; i < dataCategories.length; i++) { + const dataCategory = dataCategories[i]!; + const maxPickableDaysForDataCategory = getMaxPickableDaysFor(dataCategory); + maxPickableDays = max(maxPickableDays, maxPickableDaysForDataCategory); + } + + return maxPickableDays; +} + +function max( + a: MaxPickableDaysOptions, + b: MaxPickableDaysOptions +): MaxPickableDaysOptions { + if (a.maxPickableDays < b.maxPickableDays) { + return b; + } + + if (a.maxUpgradableDays < b.maxUpgradableDays) { + return b; + } + + return a; +} + +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: + throw new Error( + `Unsupported data category: ${dataCategory} for getMaxPickableDays` + ); + } +} + +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..e71b3e1bae0ff9 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}) => ({ @@ -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} ); 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..8a7b8896fdc0bf 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.SPANS], + 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 */