diff --git a/static/app/components/charts/eventsRequest.tsx b/static/app/components/charts/eventsRequest.tsx index 102946cd12badd..2462b5251c5793 100644 --- a/static/app/components/charts/eventsRequest.tsx +++ b/static/app/components/charts/eventsRequest.tsx @@ -462,9 +462,6 @@ class EventsRequest extends PureComponent ({ name: timestamp * 1000, value: countsForTimestamp.reduce((acc, {count}) => acc + count, 0) * scale, - ...(countsForTimestamp[0]?.confidence - ? {confidence: countsForTimestamp[0].confidence} - : {}), })), }, ]; diff --git a/static/app/types/echarts.tsx b/static/app/types/echarts.tsx index d7d633d9d19154..16c957d6972d23 100644 --- a/static/app/types/echarts.tsx +++ b/static/app/types/echarts.tsx @@ -12,7 +12,6 @@ export type SeriesDataUnit = { // number because we sometimes use timestamps name: string | number; value: number; - confidence?: Confidence; itemStyle?: { color?: string; }; diff --git a/static/app/types/organization.tsx b/static/app/types/organization.tsx index 5c62b930016573..e5ab6cc57b600e 100644 --- a/static/app/types/organization.tsx +++ b/static/app/types/organization.tsx @@ -295,10 +295,7 @@ export type SavedQueryState = { export type Confidence = 'high' | 'low' | null; -export type EventsStatsData = [ - number, - {count: number; comparisonCount?: number; confidence?: Confidence}[], -][]; +export type EventsStatsData = [number, {count: number; comparisonCount?: number}[]][]; export type ConfidenceStatsData = [number, {count: Confidence}[]][]; diff --git a/static/app/views/alerts/rules/metric/ruleForm.tsx b/static/app/views/alerts/rules/metric/ruleForm.tsx index 6b050436d9cef1..8c82d5b9f875b2 100644 --- a/static/app/views/alerts/rules/metric/ruleForm.tsx +++ b/static/app/views/alerts/rules/metric/ruleForm.tsx @@ -55,10 +55,13 @@ import RuleNameOwnerForm from 'sentry/views/alerts/rules/metric/ruleNameOwnerFor import ThresholdTypeForm from 'sentry/views/alerts/rules/metric/thresholdTypeForm'; import Triggers from 'sentry/views/alerts/rules/metric/triggers'; import TriggersChart, {ErrorChart} from 'sentry/views/alerts/rules/metric/triggers/chart'; +import { + determineMultiSeriesConfidence, + determineSeriesConfidence, +} from 'sentry/views/alerts/rules/metric/utils/determineSeriesConfidence'; import {getEventTypeFilter} from 'sentry/views/alerts/rules/metric/utils/getEventTypeFilter'; import hasThresholdValue from 'sentry/views/alerts/rules/metric/utils/hasThresholdValue'; import {isCustomMetricAlert} from 'sentry/views/alerts/rules/metric/utils/isCustomMetricAlert'; -import {isLowConfidenceTimeSeries} from 'sentry/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries'; import {isOnDemandMetricAlert} from 'sentry/views/alerts/rules/metric/utils/onDemandMetricAlert'; import {AlertRuleType, type Anomaly} from 'sentry/views/alerts/types'; import {ruleNeedsErrorMigration} from 'sentry/views/alerts/utils/migrationUi'; @@ -68,6 +71,7 @@ import { DatasetMEPAlertQueryTypes, } from 'sentry/views/alerts/wizard/options'; import {getAlertTypeFromAggregateDataset} from 'sentry/views/alerts/wizard/utils'; +import {isEventsStats} from 'sentry/views/insights/common/queries/useSortedTimeSeries'; import {MetricsBetaEndAlert} from 'sentry/views/metrics/metricsBetaEndAlert'; import PermissionAlert from 'sentry/views/settings/project/permissionAlert'; @@ -1053,7 +1057,13 @@ class RuleFormContainer extends DeprecatedAsyncComponent { handleConfidenceTimeSeriesDataFetched( data: EventsStats | MultiSeriesEventsStats | null ) { - this.setState({isLowConfidenceChartData: isLowConfidenceTimeSeries(data)}); + if (!data) { + return; + } + const confidence = isEventsStats(data) + ? determineSeriesConfidence(data) + : determineMultiSeriesConfidence(data); + this.setState({isLowConfidenceChartData: confidence === 'low'}); } handleHistoricalTimeSeriesDataFetched( diff --git a/static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.spec.tsx b/static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.spec.tsx similarity index 59% rename from static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.spec.tsx rename to static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.spec.tsx index 8a6b5ab3685c37..c405b67a31f347 100644 --- a/static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.spec.tsx +++ b/static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.spec.tsx @@ -1,92 +1,4 @@ -import type {EventsStats, MultiSeriesEventsStats} from 'sentry/types/organization'; -import { - determineSeriesConfidence, - isLowConfidenceTimeSeries, -} from 'sentry/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries'; - -describe('isLowConfidenceTimeSeries', () => { - describe('EventsStats', () => { - it('should return false when no data points have low confidence', () => { - const eventsStats: EventsStats = { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'high'}]], - [1731560400, [{count: 'high'}]], - ], - }; - expect(isLowConfidenceTimeSeries(eventsStats)).toBe(false); - }); - it('should return true when any data points have low confidence', () => { - const eventsStats: EventsStats = { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'low'}]], - [1731560400, [{count: 'high'}]], - ], - }; - expect(isLowConfidenceTimeSeries(eventsStats)).toBe(true); - }); - }); - - describe('MultiSeriesEventsStats', () => { - it('should return false when no data points have low confidence', () => { - const multiSeriesEventsStats: MultiSeriesEventsStats = { - a: { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'high'}]], - [1731560400, [{count: 'high'}]], - ], - }, - b: { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'high'}]], - [1731560400, [{count: 'high'}]], - ], - }, - }; - expect(isLowConfidenceTimeSeries(multiSeriesEventsStats)).toBe(false); - }); - it('should return true when any data points have low confidence', () => { - const multiSeriesEventsStats: MultiSeriesEventsStats = { - a: { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'low'}]], - [1731560400, [{count: 'high'}]], - ], - }, - b: { - data: [ - [1731556800, [{count: 100}]], - [1731560400, [{count: 200}]], - ], - confidence: [ - [1731556800, [{count: 'high'}]], - [1731560400, [{count: 'high'}]], - ], - }, - }; - expect(isLowConfidenceTimeSeries(multiSeriesEventsStats)).toBe(true); - }); - }); -}); +import {determineSeriesConfidence} from 'sentry/views/alerts/rules/metric/utils/determineSeriesConfidence'; describe('determineSeriesConfidence', () => { it('equal null if no data', () => { diff --git a/static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.tsx b/static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.tsx similarity index 74% rename from static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.tsx rename to static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.tsx index b3ad927b423811..1358a15e7d7e39 100644 --- a/static/app/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries.tsx +++ b/static/app/views/alerts/rules/metric/utils/determineSeriesConfidence.tsx @@ -4,20 +4,6 @@ import type { MultiSeriesEventsStats, } from 'sentry/types/organization'; import {defined} from 'sentry/utils'; -import {isEventsStats} from 'sentry/views/insights/common/queries/useSortedTimeSeries'; - -// Returns true if any of the time series are low confidence -export function isLowConfidenceTimeSeries( - data: EventsStats | MultiSeriesEventsStats | null -) { - if (data) { - if (isEventsStats(data)) { - return determineSeriesConfidence(data) === 'low'; - } - return Object.values(data).some(d => determineSeriesConfidence(d) === 'low'); - } - return false; -} // Timeseries with more than this ratio of low confidence intervals will be considered low confidence const LOW_CONFIDENCE_THRESHOLD = 0.25; @@ -63,7 +49,18 @@ export function determineSeriesConfidence( return 'high'; } -function combineConfidence(a: Confidence, b: Confidence): Confidence { +export function determineMultiSeriesConfidence( + data: MultiSeriesEventsStats, + threshold = LOW_CONFIDENCE_THRESHOLD +): Confidence { + return Object.values(data).reduce( + (acc, eventsStats) => + combineConfidence(acc, determineSeriesConfidence(eventsStats, threshold)), + null as Confidence + ); +} + +export function combineConfidence(a: Confidence, b: Confidence): Confidence { if (!defined(a)) { return b; } diff --git a/static/app/views/insights/common/queries/useSortedTimeSeries.tsx b/static/app/views/insights/common/queries/useSortedTimeSeries.tsx index 4964fa987f482e..0c81710e851e26 100644 --- a/static/app/views/insights/common/queries/useSortedTimeSeries.tsx +++ b/static/app/views/insights/common/queries/useSortedTimeSeries.tsx @@ -18,7 +18,7 @@ import type {MutableSearch} from 'sentry/utils/tokenizeSearch'; import {useLocation} from 'sentry/utils/useLocation'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; -import {determineSeriesConfidence} from 'sentry/views/alerts/rules/metric/utils/isLowConfidenceTimeSeries'; +import {determineSeriesConfidence} from 'sentry/views/alerts/rules/metric/utils/determineSeriesConfidence'; import {getSeriesEventView} from 'sentry/views/insights/common/queries/getSeriesEventView'; import type {SpanFunctions, SpanIndexedField} from 'sentry/views/insights/types';