index.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import {Fragment} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import {useTheme} from '@emotion/react';
  4. import {Query} from 'history';
  5. import EventsRequest from 'sentry/components/charts/eventsRequest';
  6. import {HeaderTitleLegend} from 'sentry/components/charts/styles';
  7. import {getInterval, getSeriesSelection} from 'sentry/components/charts/utils';
  8. import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
  9. import QuestionTooltip from 'sentry/components/questionTooltip';
  10. import {t, tct} from 'sentry/locale';
  11. import {OrganizationSummary} from 'sentry/types';
  12. import {getUtcToLocalDateObject} from 'sentry/utils/dates';
  13. import useApi from 'sentry/utils/useApi';
  14. import {useLocation} from 'sentry/utils/useLocation';
  15. import useRouter from 'sentry/utils/useRouter';
  16. import {ViewProps} from '../../../types';
  17. import {
  18. SPAN_OPERATION_BREAKDOWN_FILTER_TO_FIELD,
  19. SpanOperationBreakdownFilter,
  20. } from '../../filter';
  21. import Content from './content';
  22. type Props = ViewProps & {
  23. currentFilter: SpanOperationBreakdownFilter;
  24. organization: OrganizationSummary;
  25. queryExtra: Query;
  26. withoutZerofill: boolean;
  27. };
  28. enum DurationFunctionField {
  29. P50 = 'p50',
  30. P75 = 'p75',
  31. P95 = 'p95',
  32. P99 = 'p99',
  33. p100 = 'p100',
  34. }
  35. /**
  36. * Fetch and render a stacked area chart that shows duration percentiles over
  37. * the past 7 days
  38. */
  39. function DurationChart({
  40. project,
  41. environment,
  42. organization,
  43. query,
  44. statsPeriod,
  45. queryExtra,
  46. currentFilter,
  47. withoutZerofill,
  48. start: propsStart,
  49. end: propsEnd,
  50. }: Props) {
  51. const router = useRouter();
  52. const location = useLocation();
  53. const api = useApi();
  54. const theme = useTheme();
  55. function handleLegendSelectChanged(legendChange: {
  56. name: string;
  57. selected: Record<string, boolean>;
  58. type: string;
  59. }) {
  60. const {selected} = legendChange;
  61. const unselected = Object.keys(selected).filter(key => !selected[key]);
  62. const to = {
  63. ...location,
  64. query: {
  65. ...location.query,
  66. unselectedSeries: unselected,
  67. },
  68. };
  69. browserHistory.push(to);
  70. }
  71. const start = propsStart ? getUtcToLocalDateObject(propsStart) : null;
  72. const end = propsEnd ? getUtcToLocalDateObject(propsEnd) : null;
  73. const utc = normalizeDateTimeParams(location.query).utc === 'true';
  74. const period = statsPeriod;
  75. const legend = {right: 10, top: 5, selected: getSeriesSelection(location)};
  76. const datetimeSelection = {start, end, period};
  77. const contentCommonProps = {
  78. theme,
  79. router,
  80. start,
  81. end,
  82. utc,
  83. legend,
  84. queryExtra,
  85. period,
  86. projects: project,
  87. environments: environment,
  88. onLegendSelectChanged: handleLegendSelectChanged,
  89. };
  90. const requestCommonProps = {
  91. api,
  92. start,
  93. end,
  94. project,
  95. environment,
  96. query,
  97. period,
  98. interval: getInterval(datetimeSelection, 'high'),
  99. };
  100. const parameter = SPAN_OPERATION_BREAKDOWN_FILTER_TO_FIELD[currentFilter] ?? '';
  101. const header = (
  102. <HeaderTitleLegend>
  103. {currentFilter === SpanOperationBreakdownFilter.None
  104. ? t('Duration Breakdown')
  105. : tct('Span Operation Breakdown - [operationName]', {
  106. operationName: currentFilter,
  107. })}
  108. <QuestionTooltip
  109. size="sm"
  110. position="top"
  111. title={t(
  112. `Duration Breakdown reflects transaction durations by percentile over time.`
  113. )}
  114. />
  115. </HeaderTitleLegend>
  116. );
  117. const yAxis = Object.values(DurationFunctionField).map(v => `${v}(${parameter})`);
  118. return (
  119. <Fragment>
  120. {header}
  121. <EventsRequest
  122. {...requestCommonProps}
  123. organization={organization}
  124. showLoading={false}
  125. includePrevious={false}
  126. yAxis={yAxis}
  127. partial
  128. withoutZerofill={withoutZerofill}
  129. referrer="api.performance.transaction-summary.duration-chart"
  130. >
  131. {({results, errored, loading, reloading, timeframe: timeFrame}) => (
  132. <Content
  133. series={results}
  134. errored={errored}
  135. loading={loading}
  136. reloading={reloading}
  137. timeFrame={timeFrame}
  138. {...contentCommonProps}
  139. />
  140. )}
  141. </EventsRequest>
  142. </Fragment>
  143. );
  144. }
  145. export default DurationChart;