From d12c906e3c6e18782b2c4a47984bf20d2e50ffa2 Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 4 Nov 2025 17:18:04 -0800 Subject: [PATCH 1/3] tooltip name --- .../views/explore/components/attributeBreakdowns/content.tsx | 2 +- .../explore/components/attributeBreakdowns/floatingTrigger.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/static/app/views/explore/components/attributeBreakdowns/content.tsx b/static/app/views/explore/components/attributeBreakdowns/content.tsx index 95ae2e1ba60bf4..c0f60713a5387c 100644 --- a/static/app/views/explore/components/attributeBreakdowns/content.tsx +++ b/static/app/views/explore/components/attributeBreakdowns/content.tsx @@ -70,7 +70,7 @@ function EmptyState() { {t( - "Drag to select an area on the chart and click 'Find Attribute Breakdowns' to analyze differences between selected and unselected (baseline) data. Attributes that differ most in frequency appear first, making it easier to identify key differences:" + "Drag to select an area on the chart and click 'Compare Attribute Breakdowns' to analyze differences between selected and unselected (baseline) data. Attributes that differ most in frequency appear first, making it easier to identify key differences:" )} diff --git a/static/app/views/explore/components/attributeBreakdowns/floatingTrigger.tsx b/static/app/views/explore/components/attributeBreakdowns/floatingTrigger.tsx index 3703774829ff29..5ca60441ab1942 100644 --- a/static/app/views/explore/components/attributeBreakdowns/floatingTrigger.tsx +++ b/static/app/views/explore/components/attributeBreakdowns/floatingTrigger.tsx @@ -81,7 +81,7 @@ export function FloatingTrigger({ {t('Zoom in')} - {t('Find Attribute Breakdowns')} + {t('Compare Attribute Breakdowns')} , From 251b04c112febe7ddf0d931b1b1b84ae66a3a8df Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 4 Nov 2025 21:38:16 -0800 Subject: [PATCH 2/3] hint for cohorts --- .../attributeBreakdowns/content.tsx | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/static/app/views/explore/components/attributeBreakdowns/content.tsx b/static/app/views/explore/components/attributeBreakdowns/content.tsx index c0f60713a5387c..c8fc6a0c524532 100644 --- a/static/app/views/explore/components/attributeBreakdowns/content.tsx +++ b/static/app/views/explore/components/attributeBreakdowns/content.tsx @@ -1,6 +1,7 @@ import {Fragment, useEffect, useMemo, useState} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; +import moment from 'moment-timezone'; import emptyTraceImg from 'sentry-images/spot/performance-empty-trace.svg'; @@ -22,6 +23,7 @@ import {useFeedbackForm} from 'sentry/utils/useFeedbackForm'; import type {ChartInfo} from 'sentry/views/explore/components/chart/types'; import useAttributeBreakdowns from 'sentry/views/explore/hooks/useAttributeBreakdowns'; import type {BoxSelectOptions} from 'sentry/views/explore/hooks/useChartBoxSelect'; +import {prettifyAggregation} from 'sentry/views/explore/utils'; import {Chart} from './chart'; import {useChartSelection} from './chartSelectionContext'; @@ -29,6 +31,7 @@ import {SortingToggle, type SortingMethod} from './sortingToggle'; const CHARTS_COLUMN_COUNT = 3; const CHARTS_PER_PAGE = CHARTS_COLUMN_COUNT * 4; +const PERCENTILE_FUNCTION_PREFIXES = ['p50', 'p75', 'p90', 'p95', 'p99', 'avg']; function FeedbackButton() { const openForm = useFeedbackForm(); @@ -133,6 +136,41 @@ function ContentImpl({ setPage(0); }, [filteredRankedAttributes]); + const selectionHint = useMemo(() => { + if (!boxSelectOptions.xRange) { + return null; + } + + const [x1, x2] = boxSelectOptions.xRange; + + let startTimestamp = Math.floor(x1 / 60_000) * 60_000; + const endTimestamp = Math.ceil(x2 / 60_000) * 60_000; + startTimestamp = Math.min(startTimestamp, endTimestamp - 60_000); + + const startDate = moment(startTimestamp).format('MMM D YYYY HH:mm'); + const endDate = moment(endTimestamp).format('MMM D YYYY HH:mm'); + + // Check if yAxis is a percentile function (only these functions should include "and is greater than or equal to") + const yAxisLower = chartInfo.yAxis.toLowerCase(); + const isPercentileFunction = PERCENTILE_FUNCTION_PREFIXES.some(prefix => + yAxisLower.startsWith(prefix) + ); + + const formattedFunction = prettifyAggregation(chartInfo.yAxis) ?? chartInfo.yAxis; + + return { + selection: isPercentileFunction + ? t( + `Selection is data between %s - %s and is greater than or equal to %s`, + startDate, + endDate, + formattedFunction + ) + : t(`Selection is data between %s - %s`, startDate, endDate), + baseline: t('Baseline is all other spans from your query'), + }; + }, [boxSelectOptions.xRange, chartInfo.yAxis]); + return ( {isLoading ? ( @@ -152,6 +190,14 @@ function ContentImpl({ /> + {selectionHint && ( + + + {selectionHint.selection} + + {selectionHint.baseline} + + )} {filteredRankedAttributes.length > 0 ? ( @@ -269,3 +315,27 @@ const PaginationContainer = styled('div')` justify-content: end; align-items: center; `; + +const SelectionHintContainer = styled('div')` + display: flex; + flex-direction: column; + gap: ${space(0.5)}; + margin-bottom: ${space(1)}; +`; + +const SelectionHint = styled(Text)<{color?: string}>` + display: flex; + align-items: center; + color: ${p => p.theme.subText}; + font-size: ${p => p.theme.fontSize.sm}; + + &::before { + content: ''; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: ${p => p.color || p.theme.gray400}; + margin-right: ${space(0.5)}; + flex-shrink: 0; + } +`; From 1bd0396f629adeb9e7f266e3106ecf6b6b1d63c0 Mon Sep 17 00:00:00 2001 From: Aayush Seth Date: Tue, 4 Nov 2025 21:47:28 -0800 Subject: [PATCH 3/3] am/pm and utc indication --- .../explore/components/attributeBreakdowns/content.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/static/app/views/explore/components/attributeBreakdowns/content.tsx b/static/app/views/explore/components/attributeBreakdowns/content.tsx index c8fc6a0c524532..ec83853a344588 100644 --- a/static/app/views/explore/components/attributeBreakdowns/content.tsx +++ b/static/app/views/explore/components/attributeBreakdowns/content.tsx @@ -18,6 +18,7 @@ import {IconChevron} from 'sentry/icons/iconChevron'; import {IconMegaphone} from 'sentry/icons/iconMegaphone'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; +import {getUserTimezone} from 'sentry/utils/dates'; import {useDebouncedValue} from 'sentry/utils/useDebouncedValue'; import {useFeedbackForm} from 'sentry/utils/useFeedbackForm'; import type {ChartInfo} from 'sentry/views/explore/components/chart/types'; @@ -147,8 +148,11 @@ function ContentImpl({ const endTimestamp = Math.ceil(x2 / 60_000) * 60_000; startTimestamp = Math.min(startTimestamp, endTimestamp - 60_000); - const startDate = moment(startTimestamp).format('MMM D YYYY HH:mm'); - const endDate = moment(endTimestamp).format('MMM D YYYY HH:mm'); + const userTimezone = getUserTimezone() || moment.tz.guess(); + const startDate = moment + .tz(startTimestamp, userTimezone) + .format('MMM D YYYY h:mm A z'); + const endDate = moment.tz(endTimestamp, userTimezone).format('MMM D YYYY h:mm A z'); // Check if yAxis is a percentile function (only these functions should include "and is greater than or equal to") const yAxisLower = chartInfo.yAxis.toLowerCase();