11import { Fragment , useEffect , useMemo , useState } from 'react' ;
22import { useTheme } from '@emotion/react' ;
33import styled from '@emotion/styled' ;
4+ import moment from 'moment-timezone' ;
45
56import emptyTraceImg from 'sentry-images/spot/performance-empty-trace.svg' ;
67
@@ -17,18 +18,21 @@ import {IconChevron} from 'sentry/icons/iconChevron';
1718import { IconMegaphone } from 'sentry/icons/iconMegaphone' ;
1819import { t } from 'sentry/locale' ;
1920import { space } from 'sentry/styles/space' ;
21+ import { getUserTimezone } from 'sentry/utils/dates' ;
2022import { useDebouncedValue } from 'sentry/utils/useDebouncedValue' ;
2123import { useFeedbackForm } from 'sentry/utils/useFeedbackForm' ;
2224import type { ChartInfo } from 'sentry/views/explore/components/chart/types' ;
2325import useAttributeBreakdowns from 'sentry/views/explore/hooks/useAttributeBreakdowns' ;
2426import type { BoxSelectOptions } from 'sentry/views/explore/hooks/useChartBoxSelect' ;
27+ import { prettifyAggregation } from 'sentry/views/explore/utils' ;
2528
2629import { Chart } from './chart' ;
2730import { useChartSelection } from './chartSelectionContext' ;
2831import { SortingToggle , type SortingMethod } from './sortingToggle' ;
2932
3033const CHARTS_COLUMN_COUNT = 3 ;
3134const CHARTS_PER_PAGE = CHARTS_COLUMN_COUNT * 4 ;
35+ const PERCENTILE_FUNCTION_PREFIXES = [ 'p50' , 'p75' , 'p90' , 'p95' , 'p99' , 'avg' ] ;
3236
3337function FeedbackButton ( ) {
3438 const openForm = useFeedbackForm ( ) ;
@@ -133,6 +137,44 @@ function ContentImpl({
133137 setPage ( 0 ) ;
134138 } , [ filteredRankedAttributes ] ) ;
135139
140+ const selectionHint = useMemo ( ( ) => {
141+ if ( ! boxSelectOptions . xRange ) {
142+ return null ;
143+ }
144+
145+ const [ x1 , x2 ] = boxSelectOptions . xRange ;
146+
147+ let startTimestamp = Math . floor ( x1 / 60_000 ) * 60_000 ;
148+ const endTimestamp = Math . ceil ( x2 / 60_000 ) * 60_000 ;
149+ startTimestamp = Math . min ( startTimestamp , endTimestamp - 60_000 ) ;
150+
151+ const userTimezone = getUserTimezone ( ) || moment . tz . guess ( ) ;
152+ const startDate = moment
153+ . tz ( startTimestamp , userTimezone )
154+ . format ( 'MMM D YYYY h:mm A z' ) ;
155+ const endDate = moment . tz ( endTimestamp , userTimezone ) . format ( 'MMM D YYYY h:mm A z' ) ;
156+
157+ // Check if yAxis is a percentile function (only these functions should include "and is greater than or equal to")
158+ const yAxisLower = chartInfo . yAxis . toLowerCase ( ) ;
159+ const isPercentileFunction = PERCENTILE_FUNCTION_PREFIXES . some ( prefix =>
160+ yAxisLower . startsWith ( prefix )
161+ ) ;
162+
163+ const formattedFunction = prettifyAggregation ( chartInfo . yAxis ) ?? chartInfo . yAxis ;
164+
165+ return {
166+ selection : isPercentileFunction
167+ ? t (
168+ `Selection is data between %s - %s and is greater than or equal to %s` ,
169+ startDate ,
170+ endDate ,
171+ formattedFunction
172+ )
173+ : t ( `Selection is data between %s - %s` , startDate , endDate ) ,
174+ baseline : t ( 'Baseline is all other spans from your query' ) ,
175+ } ;
176+ } , [ boxSelectOptions . xRange , chartInfo . yAxis ] ) ;
177+
136178 return (
137179 < Flex direction = "column" gap = "xl" padding = "xl" >
138180 { isLoading ? (
@@ -152,6 +194,14 @@ function ContentImpl({
152194 />
153195 < SortingToggle value = { sortingMethod } onChange = { setSortingMethod } />
154196 </ ControlsContainer >
197+ { selectionHint && (
198+ < SelectionHintContainer >
199+ < SelectionHint color = { theme . chart . getColorPalette ( 0 ) ?. [ 0 ] } >
200+ { selectionHint . selection }
201+ </ SelectionHint >
202+ < SelectionHint color = "#A29FAA" > { selectionHint . baseline } </ SelectionHint >
203+ </ SelectionHintContainer >
204+ ) }
155205 { filteredRankedAttributes . length > 0 ? (
156206 < Fragment >
157207 < ChartsGrid >
@@ -269,3 +319,27 @@ const PaginationContainer = styled('div')`
269319 justify-content: end;
270320 align-items: center;
271321` ;
322+
323+ const SelectionHintContainer = styled ( 'div' ) `
324+ display: flex;
325+ flex-direction: column;
326+ gap: ${ space ( 0.5 ) } ;
327+ margin-bottom: ${ space ( 1 ) } ;
328+ ` ;
329+
330+ const SelectionHint = styled ( Text ) < { color ?: string } > `
331+ display: flex;
332+ align-items: center;
333+ color: ${ p => p . theme . subText } ;
334+ font-size: ${ p => p . theme . fontSize . sm } ;
335+
336+ &::before {
337+ content: '';
338+ width: 8px;
339+ height: 8px;
340+ border-radius: 50%;
341+ background-color: ${ p => p . color || p . theme . gray400 } ;
342+ margin-right: ${ space ( 0.5 ) } ;
343+ flex-shrink: 0;
344+ }
345+ ` ;
0 commit comments