import {browserHistory} from 'react-router'; import styled from '@emotion/styled'; import type {Location} from 'history'; import OptionSelector from 'sentry/components/charts/optionSelector'; import { ChartContainer, ChartControls, InlineContainer, } from 'sentry/components/charts/styles'; import Panel from 'sentry/components/panels/panel'; import {t} from 'sentry/locale'; import type {Organization, Project, SelectValue} from 'sentry/types'; import {trackAnalytics} from 'sentry/utils/analytics'; import type EventView from 'sentry/utils/discover/eventView'; import {useMetricsCardinalityContext} from 'sentry/utils/performance/contexts/metricsCardinality'; import {useMEPSettingContext} from 'sentry/utils/performance/contexts/metricsEnhancedSetting'; import {removeHistogramQueryStrings} from 'sentry/utils/performance/histogram'; import {decodeScalar} from 'sentry/utils/queryString'; import {getTransactionMEPParamsIfApplicable} from 'sentry/views/performance/transactionSummary/transactionOverview/utils'; import {DisplayModes} from 'sentry/views/performance/transactionSummary/utils'; import {TransactionsListOption} from 'sentry/views/releases/detail/overview'; import { TrendFunctionField, TrendParameterColumn, TrendParameterLabel, } from '../../trends/types'; import {TRENDS_FUNCTIONS, TRENDS_PARAMETERS} from '../../trends/utils'; import {SpanOperationBreakdownFilter} from '../filter'; import LatencyChartControls from './latencyChart/chartControls'; import {ZOOM_END, ZOOM_START} from './latencyChart/utils'; import DurationChart from './durationChart'; import DurationPercentileChart from './durationPercentileChart'; import LatencyChart from './latencyChart'; import TrendChart from './trendChart'; import UserMiseryChart from './userMiseryChart'; import VitalsChart from './vitalsChart'; function generateDisplayOptions( currentFilter: SpanOperationBreakdownFilter ): SelectValue[] { if (currentFilter === SpanOperationBreakdownFilter.NONE) { return [ {value: DisplayModes.DURATION, label: t('Duration Breakdown')}, {value: DisplayModes.DURATION_PERCENTILE, label: t('Duration Percentiles')}, {value: DisplayModes.LATENCY, label: t('Duration Distribution')}, {value: DisplayModes.TREND, label: t('Trends')}, {value: DisplayModes.VITALS, label: t('Web Vitals')}, {value: DisplayModes.USER_MISERY, label: t('User Misery')}, ]; } // A span operation name breakdown has been chosen. return [ {value: DisplayModes.DURATION, label: t('Span Operation Breakdown')}, {value: DisplayModes.DURATION_PERCENTILE, label: t('Span Operation Percentiles')}, {value: DisplayModes.LATENCY, label: t('Span Operation Distribution')}, {value: DisplayModes.TREND, label: t('Trends')}, {value: DisplayModes.VITALS, label: t('Web Vitals')}, ]; } const TREND_FUNCTIONS_OPTIONS: SelectValue[] = TRENDS_FUNCTIONS.map( ({field, label}) => ({ value: field, label, }) ); type Props = { currentFilter: SpanOperationBreakdownFilter; eventView: EventView; location: Location; organization: Organization; totalValue: number | null; withoutZerofill: boolean; project?: Project; }; function TransactionSummaryCharts({ totalValue, eventView, organization, location, currentFilter, withoutZerofill, project, }: Props) { function handleDisplayChange(value: string) { const display = decodeScalar(location.query.display, DisplayModes.DURATION); trackAnalytics('performance_views.transaction_summary.change_chart_display', { organization, from_chart: display, to_chart: value, }); browserHistory.push({ pathname: location.pathname, query: { ...removeHistogramQueryStrings(location, [ZOOM_START, ZOOM_END]), display: value, }, }); } function handleTrendDisplayChange(value: string) { browserHistory.push({ pathname: location.pathname, query: {...location.query, trendFunction: value}, }); } function handleTrendColumnChange(value: string) { browserHistory.push({ pathname: location.pathname, query: { ...location.query, trendParameter: value, }, }); } const TREND_PARAMETERS_OPTIONS: SelectValue[] = TRENDS_PARAMETERS.map( ({label}) => ({ value: label, label, }) ); let display = decodeScalar(location.query.display, DisplayModes.DURATION); let trendFunction = decodeScalar( location.query.trendFunction, TREND_FUNCTIONS_OPTIONS[0].value ) as TrendFunctionField; let trendParameter = decodeScalar( location.query.trendParameter, TREND_PARAMETERS_OPTIONS[0].value ); if (!Object.values(DisplayModes).includes(display as DisplayModes)) { display = DisplayModes.DURATION; } if (!Object.values(TrendFunctionField).includes(trendFunction)) { trendFunction = TrendFunctionField.P50; } if ( !Object.values(TrendParameterLabel).includes(trendParameter as TrendParameterLabel) ) { trendParameter = TrendParameterLabel.DURATION; } const trendColumn = TRENDS_PARAMETERS.find(parameter => parameter.label === trendParameter)?.column || TrendParameterColumn.DURATION; const releaseQueryExtra = { yAxis: display === DisplayModes.VITALS ? 'countVital' : 'countDuration', showTransactions: display === DisplayModes.VITALS ? TransactionsListOption.SLOW_LCP : display === DisplayModes.DURATION ? TransactionsListOption.SLOW : undefined, }; const mepSetting = useMEPSettingContext(); const mepCardinalityContext = useMetricsCardinalityContext(); const queryExtras = getTransactionMEPParamsIfApplicable( mepSetting, mepCardinalityContext, organization ); return ( {display === DisplayModes.LATENCY && ( )} {display === DisplayModes.DURATION && ( )} {display === DisplayModes.DURATION_PERCENTILE && ( )} {display === DisplayModes.TREND && ( )} {display === DisplayModes.VITALS && ( )} {display === DisplayModes.USER_MISERY && ( )} {display === DisplayModes.TREND && ( )} {display === DisplayModes.TREND && ( )} {display === DisplayModes.LATENCY && ( )} ); } const ReversedChartControls = styled(ChartControls)` flex-direction: row-reverse; `; export default TransactionSummaryCharts;