content.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import type {InjectedRouter} from 'react-router';
  2. import type {Theme} from '@emotion/react';
  3. import type {Query} from 'history';
  4. import ChartZoom from 'sentry/components/charts/chartZoom';
  5. import ErrorPanel from 'sentry/components/charts/errorPanel';
  6. import type {LineChartProps} from 'sentry/components/charts/lineChart';
  7. import {LineChart} from 'sentry/components/charts/lineChart';
  8. import ReleaseSeries from 'sentry/components/charts/releaseSeries';
  9. import TransitionChart from 'sentry/components/charts/transitionChart';
  10. import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
  11. import Placeholder from 'sentry/components/placeholder';
  12. import {IconWarning} from 'sentry/icons';
  13. import {t} from 'sentry/locale';
  14. import type {Series} from 'sentry/types/echarts';
  15. import {
  16. axisLabelFormatter,
  17. getDurationUnit,
  18. tooltipFormatter,
  19. } from 'sentry/utils/discover/charts';
  20. import getDynamicText from 'sentry/utils/getDynamicText';
  21. import type {NormalizedTrendsTransaction} from 'sentry/views/performance/trends/types';
  22. import {getIntervalLine} from 'sentry/views/performance/utils';
  23. import {transformEventStatsSmoothed} from '../../../trends/utils';
  24. type Props = {
  25. errored: boolean;
  26. loading: boolean;
  27. queryExtra: Query;
  28. reloading: boolean;
  29. router: InjectedRouter;
  30. theme: Theme;
  31. series?: Series[];
  32. timeFrame?: {
  33. end: number;
  34. start: number;
  35. };
  36. transaction?: NormalizedTrendsTransaction;
  37. withBreakpoint?: boolean;
  38. } & Omit<React.ComponentProps<typeof ReleaseSeries>, 'children' | 'queryExtra'> &
  39. Pick<LineChartProps, 'onLegendSelectChanged' | 'legend'>;
  40. function Content({
  41. errored,
  42. theme,
  43. series: data,
  44. timeFrame,
  45. start,
  46. end,
  47. period,
  48. projects,
  49. environments,
  50. loading,
  51. reloading,
  52. legend,
  53. utc,
  54. queryExtra,
  55. router,
  56. withBreakpoint,
  57. transaction,
  58. onLegendSelectChanged,
  59. }: Props) {
  60. if (errored) {
  61. return (
  62. <ErrorPanel>
  63. <IconWarning color="gray500" size="lg" />
  64. </ErrorPanel>
  65. );
  66. }
  67. const series = data
  68. ? data
  69. .map(values => {
  70. return {
  71. ...values,
  72. color: theme.purple300,
  73. lineStyle: {
  74. opacity: 0.75,
  75. width: 1,
  76. },
  77. };
  78. })
  79. .reverse()
  80. : [];
  81. const needsLabel = false;
  82. const breakpointSeries = withBreakpoint
  83. ? getIntervalLine(theme, data || [], 0.5, needsLabel, transaction)
  84. : [];
  85. const durationUnit = getDurationUnit(series, legend);
  86. const chartOptions: Omit<LineChartProps, 'series'> = {
  87. grid: {
  88. left: '10px',
  89. right: '10px',
  90. top: '40px',
  91. bottom: '0px',
  92. },
  93. seriesOptions: {
  94. showSymbol: false,
  95. },
  96. tooltip: {
  97. valueFormatter: (value: number | null) => tooltipFormatter(value, 'duration'),
  98. },
  99. xAxis: timeFrame
  100. ? {
  101. min: timeFrame.start,
  102. max: timeFrame.end,
  103. }
  104. : undefined,
  105. yAxis: {
  106. min: 0,
  107. minInterval: durationUnit,
  108. axisLabel: {
  109. color: theme.chartLabel,
  110. formatter: (value: number) =>
  111. axisLabelFormatter(value, 'duration', undefined, durationUnit),
  112. },
  113. },
  114. };
  115. const {smoothedResults} = transformEventStatsSmoothed(data, t('Smoothed'));
  116. const smoothedSeries = smoothedResults
  117. ? smoothedResults.map(values => {
  118. return {
  119. ...values,
  120. color: theme.purple300,
  121. lineStyle: {
  122. opacity: 1,
  123. },
  124. };
  125. })
  126. : [];
  127. return (
  128. <ChartZoom router={router} period={period} start={start} end={end} utc={utc}>
  129. {zoomRenderProps => (
  130. <ReleaseSeries
  131. start={start}
  132. end={end}
  133. queryExtra={queryExtra}
  134. period={period}
  135. utc={utc}
  136. projects={projects}
  137. environments={environments}
  138. >
  139. {({releaseSeries}) => (
  140. <TransitionChart loading={loading} reloading={reloading}>
  141. <TransparentLoadingMask visible={reloading} />
  142. {getDynamicText({
  143. value: (
  144. <LineChart
  145. {...zoomRenderProps}
  146. {...chartOptions}
  147. legend={legend}
  148. onLegendSelectChanged={onLegendSelectChanged}
  149. series={[
  150. ...series,
  151. ...smoothedSeries,
  152. ...releaseSeries,
  153. ...breakpointSeries,
  154. ]}
  155. />
  156. ),
  157. fixed: <Placeholder height="200px" testId="skeleton-ui" />,
  158. })}
  159. </TransitionChart>
  160. )}
  161. </ReleaseSeries>
  162. )}
  163. </ChartZoom>
  164. );
  165. }
  166. export default Content;