123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- import {browserHistory} from 'react-router';
- import styled from '@emotion/styled';
- import {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 {Organization, Project, SelectValue} from 'sentry/types';
- import {trackAnalytics} from 'sentry/utils/analytics';
- import 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<string>[] {
- 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<string>[] = 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<string>[] = 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 (
- <Panel>
- <ChartContainer data-test-id="transaction-summary-charts">
- {display === DisplayModes.LATENCY && (
- <LatencyChart
- organization={organization}
- location={location}
- query={eventView.query}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- currentFilter={currentFilter}
- totalCount={totalValue}
- />
- )}
- {display === DisplayModes.DURATION && (
- <DurationChart
- organization={organization}
- query={eventView.query}
- queryExtra={releaseQueryExtra}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- currentFilter={currentFilter}
- withoutZerofill={withoutZerofill}
- queryExtras={queryExtras}
- />
- )}
- {display === DisplayModes.DURATION_PERCENTILE && (
- <DurationPercentileChart
- organization={organization}
- location={location}
- query={eventView.query}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- currentFilter={currentFilter}
- queryExtras={queryExtras}
- />
- )}
- {display === DisplayModes.TREND && (
- <TrendChart
- eventView={eventView}
- trendFunction={trendFunction}
- trendParameter={trendColumn}
- organization={organization}
- query={eventView.query}
- queryExtra={releaseQueryExtra}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- withoutZerofill={withoutZerofill}
- projects={project ? [project] : []}
- withBreakpoint={organization.features.includes('performance-new-trends')}
- />
- )}
- {display === DisplayModes.VITALS && (
- <VitalsChart
- organization={organization}
- query={eventView.query}
- queryExtra={releaseQueryExtra}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- withoutZerofill={withoutZerofill}
- queryExtras={queryExtras}
- />
- )}
- {display === DisplayModes.USER_MISERY && (
- <UserMiseryChart
- organization={organization}
- query={eventView.query}
- queryExtra={releaseQueryExtra}
- project={eventView.project}
- environment={eventView.environment}
- start={eventView.start}
- end={eventView.end}
- statsPeriod={eventView.statsPeriod}
- withoutZerofill={withoutZerofill}
- />
- )}
- </ChartContainer>
- <ReversedChartControls>
- <InlineContainer>
- {display === DisplayModes.TREND && (
- <OptionSelector
- title={t('Percentile')}
- selected={trendFunction}
- options={TREND_FUNCTIONS_OPTIONS}
- onChange={handleTrendDisplayChange}
- />
- )}
- {display === DisplayModes.TREND && (
- <OptionSelector
- title={t('Parameter')}
- selected={trendParameter}
- options={TREND_PARAMETERS_OPTIONS}
- onChange={handleTrendColumnChange}
- />
- )}
- {display === DisplayModes.LATENCY && (
- <LatencyChartControls location={location} />
- )}
- <OptionSelector
- title={t('Display')}
- selected={display}
- options={generateDisplayOptions(currentFilter)}
- onChange={handleDisplayChange}
- />
- </InlineContainer>
- </ReversedChartControls>
- </Panel>
- );
- }
- const ReversedChartControls = styled(ChartControls)`
- flex-direction: row-reverse;
- `;
- export default TransactionSummaryCharts;
|