exclusiveTimeTimeSeries.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {Fragment} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import ChartZoom from 'sentry/components/charts/chartZoom';
  4. import ErrorPanel from 'sentry/components/charts/errorPanel';
  5. import EventsRequest from 'sentry/components/charts/eventsRequest';
  6. import {LineChart} from 'sentry/components/charts/lineChart';
  7. import {HeaderTitleLegend} from 'sentry/components/charts/styles';
  8. import TransitionChart from 'sentry/components/charts/transitionChart';
  9. import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
  10. import {getInterval, getSeriesSelection} from 'sentry/components/charts/utils';
  11. import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
  12. import Placeholder from 'sentry/components/placeholder';
  13. import QuestionTooltip from 'sentry/components/questionTooltip';
  14. import {IconWarning} from 'sentry/icons';
  15. import {t} from 'sentry/locale';
  16. import type {Organization} from 'sentry/types/organization';
  17. import {browserHistory} from 'sentry/utils/browserHistory';
  18. import {getUtcToLocalDateObject} from 'sentry/utils/dates';
  19. import {axisLabelFormatter, tooltipFormatter} from 'sentry/utils/discover/charts';
  20. import type EventView from 'sentry/utils/discover/eventView';
  21. import getDynamicText from 'sentry/utils/getDynamicText';
  22. import type {SpanSlug} from 'sentry/utils/performance/suspectSpans/types';
  23. import useApi from 'sentry/utils/useApi';
  24. import {useLocation} from 'sentry/utils/useLocation';
  25. import {getExclusiveTimeDisplayedValue} from '../utils';
  26. type Props = {
  27. eventView: EventView;
  28. organization: Organization;
  29. spanSlug: SpanSlug;
  30. withoutZerofill: boolean;
  31. };
  32. export default function ExclusiveTimeTimeSeries(props: Props) {
  33. const location = useLocation();
  34. const {organization, eventView, spanSlug, withoutZerofill} = props;
  35. const api = useApi();
  36. const theme = useTheme();
  37. const period = eventView.statsPeriod;
  38. const start = eventView.start ? getUtcToLocalDateObject(eventView.start) : null;
  39. const end = eventView.end ? getUtcToLocalDateObject(eventView.end) : null;
  40. const {utc} = normalizeDateTimeParams(location.query);
  41. const datetimeSelection = {
  42. start,
  43. end,
  44. period,
  45. };
  46. const yAxis = [
  47. 'percentileArray(spans_exclusive_time, 0.50)',
  48. 'percentileArray(spans_exclusive_time, 0.75)',
  49. 'percentileArray(spans_exclusive_time, 0.95)',
  50. 'percentileArray(spans_exclusive_time, 0.99)',
  51. ];
  52. const handleLegendSelectChanged = legendChange => {
  53. const {selected} = legendChange;
  54. const unselected = Object.keys(selected).filter(key => !selected[key]);
  55. const to = {
  56. ...location,
  57. query: {
  58. ...location.query,
  59. unselectedSeries: unselected,
  60. },
  61. };
  62. browserHistory.push(to);
  63. };
  64. return (
  65. <Fragment>
  66. <HeaderTitleLegend>
  67. {t('Self Time Breakdown')}
  68. <QuestionTooltip
  69. size="sm"
  70. position="top"
  71. title={t(
  72. 'Self Time Breakdown reflects the span self time by percentile over time.'
  73. )}
  74. />
  75. </HeaderTitleLegend>
  76. <ChartZoom period={period} start={start} end={end} utc={utc === 'true'}>
  77. {zoomRenderProps => (
  78. <EventsRequest
  79. api={api}
  80. organization={organization}
  81. project={eventView.project}
  82. environment={eventView.environment}
  83. start={start}
  84. end={end}
  85. period={period}
  86. interval={getInterval(datetimeSelection, 'high')}
  87. showLoading={false}
  88. query={eventView.query}
  89. includePrevious={false}
  90. yAxis={yAxis}
  91. partial
  92. withoutZerofill={withoutZerofill}
  93. queryExtras={{span: `${spanSlug.op}:${spanSlug.group}`}}
  94. generatePathname={org => `/organizations/${org.slug}/events-spans-stats/`}
  95. >
  96. {({results, errored, loading, reloading, timeframe}) => {
  97. if (errored) {
  98. return (
  99. <ErrorPanel>
  100. <IconWarning color="gray300" size="lg" />
  101. </ErrorPanel>
  102. );
  103. }
  104. const chartOptions = {
  105. grid: {
  106. left: '10px',
  107. right: '10px',
  108. top: '40px',
  109. bottom: '0px',
  110. },
  111. colors: theme.charts.getColorPalette(yAxis.length - 2),
  112. seriesOptions: {
  113. showSymbol: false,
  114. },
  115. tooltip: {
  116. trigger: 'axis' as const,
  117. // p50() coerces the axis to be time based
  118. valueFormatter: (value, _seriesName) =>
  119. tooltipFormatter(value, 'duration'),
  120. },
  121. xAxis: timeframe
  122. ? {
  123. min: timeframe.start,
  124. max: timeframe.end,
  125. }
  126. : undefined,
  127. yAxis: {
  128. axisLabel: {
  129. color: theme.chartLabel,
  130. formatter: (value: number) => axisLabelFormatter(value, 'duration'),
  131. },
  132. },
  133. };
  134. const legend = {
  135. right: 10,
  136. top: 5,
  137. selected: getSeriesSelection(location),
  138. };
  139. const formattedResults = results?.map(result => ({
  140. ...result,
  141. seriesName: getExclusiveTimeDisplayedValue(result.seriesName),
  142. }));
  143. return (
  144. <TransitionChart loading={loading} reloading={reloading}>
  145. <TransparentLoadingMask visible={reloading} />
  146. {getDynamicText({
  147. value: (
  148. <LineChart
  149. {...zoomRenderProps}
  150. {...chartOptions}
  151. legend={legend}
  152. onLegendSelectChanged={handleLegendSelectChanged}
  153. series={formattedResults ?? []}
  154. />
  155. ),
  156. fixed: <Placeholder height="200px" />,
  157. })}
  158. </TransitionChart>
  159. );
  160. }}
  161. </EventsRequest>
  162. )}
  163. </ChartZoom>
  164. </Fragment>
  165. );
  166. }