index.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import {Fragment} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import type {Query} from 'history';
  4. import EventsRequest from 'sentry/components/charts/eventsRequest';
  5. import {HeaderTitleLegend} from 'sentry/components/charts/styles';
  6. import {getInterval, getSeriesSelection} from 'sentry/components/charts/utils';
  7. import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
  8. import QuestionTooltip from 'sentry/components/questionTooltip';
  9. import {t} from 'sentry/locale';
  10. import type {OrganizationSummary} from 'sentry/types/organization';
  11. import {getUtcToLocalDateObject} from 'sentry/utils/dates';
  12. import {getAggregateArg, getMeasurementSlug} from 'sentry/utils/discover/fields';
  13. import {WebVital} from 'sentry/utils/fields';
  14. import useApi from 'sentry/utils/useApi';
  15. import {useLocation} from 'sentry/utils/useLocation';
  16. import {useNavigate} from 'sentry/utils/useNavigate';
  17. import type {ViewProps} from '../../../types';
  18. import Content from './content';
  19. type Props = ViewProps & {
  20. organization: OrganizationSummary;
  21. queryExtra: Query;
  22. withoutZerofill: boolean;
  23. queryExtras?: Record<string, string>;
  24. };
  25. function VitalsChart({
  26. project,
  27. environment,
  28. organization,
  29. query,
  30. statsPeriod,
  31. queryExtra,
  32. withoutZerofill,
  33. start: propsStart,
  34. end: propsEnd,
  35. queryExtras,
  36. }: Props) {
  37. const navigate = useNavigate();
  38. const location = useLocation();
  39. const api = useApi();
  40. const theme = useTheme();
  41. const handleLegendSelectChanged = (legendChange: {
  42. name: string;
  43. selected: Record<string, boolean>;
  44. type: string;
  45. }) => {
  46. const {selected} = legendChange;
  47. const unselected = Object.keys(selected).filter(key => !selected[key]);
  48. const to = {
  49. ...location,
  50. query: {
  51. ...location.query,
  52. unselectedSeries: unselected,
  53. },
  54. };
  55. navigate(to);
  56. };
  57. const vitals = [WebVital.FCP, WebVital.LCP, WebVital.FID, WebVital.CLS];
  58. const start = propsStart ? getUtcToLocalDateObject(propsStart) : null;
  59. const end = propsEnd ? getUtcToLocalDateObject(propsEnd) : null;
  60. const utc = normalizeDateTimeParams(location.query).utc === 'true';
  61. const period = statsPeriod;
  62. const legend = {
  63. right: 10,
  64. top: 0,
  65. selected: getSeriesSelection(location),
  66. formatter: (seriesName: string) => {
  67. const arg = getAggregateArg(seriesName);
  68. if (arg !== null) {
  69. const slug = getMeasurementSlug(arg);
  70. if (slug !== null) {
  71. seriesName = slug.toUpperCase();
  72. }
  73. }
  74. return seriesName;
  75. },
  76. };
  77. const datetimeSelection = {start, end, period};
  78. const contentCommonProps = {
  79. theme,
  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 header = (
  101. <HeaderTitleLegend>
  102. {t('Web Vitals Breakdown')}
  103. <QuestionTooltip
  104. size="sm"
  105. position="top"
  106. title={t(
  107. `Web Vitals Breakdown reflects the 75th percentile of web vitals over time.`
  108. )}
  109. />
  110. </HeaderTitleLegend>
  111. );
  112. const yAxis = vitals.map(v => `p75(${v})`);
  113. return (
  114. <Fragment>
  115. {header}
  116. <EventsRequest
  117. {...requestCommonProps}
  118. organization={organization}
  119. showLoading={false}
  120. includePrevious={false}
  121. yAxis={yAxis}
  122. partial
  123. withoutZerofill={withoutZerofill}
  124. referrer="api.performance.transaction-summary.vitals-chart"
  125. queryExtras={queryExtras}
  126. >
  127. {({results, errored, loading, reloading, timeframe: timeFrame}) => (
  128. <Content
  129. series={results}
  130. errored={errored}
  131. loading={loading}
  132. reloading={reloading}
  133. timeFrame={timeFrame}
  134. {...contentCommonProps}
  135. />
  136. )}
  137. </EventsRequest>
  138. </Fragment>
  139. );
  140. }
  141. export default VitalsChart;