breakpointChart.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import {useMemo} from 'react';
  2. import TransitionChart from 'sentry/components/charts/transitionChart';
  3. import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
  4. import {Event, EventsStatsData} from 'sentry/types';
  5. import EventView, {MetaType} from 'sentry/utils/discover/eventView';
  6. import {
  7. DiscoverQueryProps,
  8. useGenericDiscoverQuery,
  9. } from 'sentry/utils/discover/genericDiscoverQuery';
  10. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  11. import {useLocation} from 'sentry/utils/useLocation';
  12. import useOrganization from 'sentry/utils/useOrganization';
  13. import {
  14. NormalizedTrendsTransaction,
  15. TrendFunctionField,
  16. } from 'sentry/views/performance/trends/types';
  17. import {generateTrendFunctionAsString} from 'sentry/views/performance/trends/utils';
  18. import {DataSection} from '../styles';
  19. import Chart from './lineChart';
  20. function camelToUnderscore(key: string) {
  21. return key.replace(/([A-Z\d])/g, '_$1').toLowerCase();
  22. }
  23. type EventBreakpointChartProps = {
  24. event: Event;
  25. };
  26. const DAY = 24 * 60 * 60 * 1000;
  27. function EventBreakpointChart({event}: EventBreakpointChartProps) {
  28. const organization = useOrganization();
  29. const location = useLocation();
  30. const {transaction, breakpoint} = event?.occurrence?.evidenceData ?? {};
  31. const eventView = EventView.fromLocation(location);
  32. eventView.query = `event.type:transaction transaction:"${transaction}"`;
  33. eventView.dataset = DiscoverDatasets.METRICS;
  34. const maxDateTime = useMemo(() => Date.now(), []);
  35. const minDateTime = maxDateTime - 90 * DAY;
  36. const breakpointTime = breakpoint * 1000;
  37. const beforeTime = breakpointTime - DAY * 7;
  38. const beforeDateTime =
  39. beforeTime >= minDateTime ? new Date(beforeTime) : new Date(minDateTime);
  40. const afterTime = breakpointTime + DAY * 7;
  41. const afterDateTime =
  42. afterTime <= maxDateTime ? new Date(afterTime) : new Date(maxDateTime);
  43. eventView.start = beforeDateTime.toISOString();
  44. eventView.end = afterDateTime.toISOString();
  45. eventView.statsPeriod = undefined;
  46. // The evidence data keys are returned to us in camelCase, but we need to
  47. // convert them to snake_case to match the NormalizedTrendsTransaction type
  48. const normalizedOccurrenceEvent = Object.keys(
  49. event?.occurrence?.evidenceData ?? []
  50. ).reduce((acc, key) => {
  51. acc[camelToUnderscore(key)] = event?.occurrence?.evidenceData?.[key];
  52. return acc;
  53. }, {}) as NormalizedTrendsTransaction;
  54. const {data, isLoading} = useGenericDiscoverQuery<
  55. {
  56. data: EventsStatsData;
  57. meta: MetaType;
  58. },
  59. DiscoverQueryProps
  60. >({
  61. route: 'events-stats',
  62. location,
  63. eventView,
  64. orgSlug: organization.slug,
  65. getRequestPayload: () => ({
  66. // Manually inject y-axis for events-stats because
  67. // getEventsAPIPayload doesn't pass it along
  68. ...eventView.getEventsAPIPayload(location),
  69. yAxis: 'p95(transaction.duration)',
  70. }),
  71. });
  72. return (
  73. <DataSection>
  74. <TransitionChart loading={isLoading} reloading>
  75. <TransparentLoadingMask visible={isLoading} />
  76. <Chart
  77. statsData={data?.data ?? []}
  78. evidenceData={normalizedOccurrenceEvent}
  79. start={eventView.start}
  80. end={eventView.end}
  81. chartLabel={generateTrendFunctionAsString(
  82. TrendFunctionField.P95,
  83. 'transaction.duration'
  84. )}
  85. />
  86. </TransitionChart>
  87. </DataSection>
  88. );
  89. }
  90. export default EventBreakpointChart;