useTransactionWebVitalsQuery.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import {useDiscoverQuery} from 'sentry/utils/discover/discoverQuery';
  2. import EventView from 'sentry/utils/discover/eventView';
  3. import {useLocation} from 'sentry/utils/useLocation';
  4. import useOrganization from 'sentry/utils/useOrganization';
  5. import usePageFilters from 'sentry/utils/usePageFilters';
  6. import {calculatePerformanceScore} from 'sentry/views/performance/browser/webVitals/utils/calculatePerformanceScore';
  7. import {
  8. RowWithScore,
  9. WebVitals,
  10. } from 'sentry/views/performance/browser/webVitals/utils/types';
  11. type Props = {
  12. limit?: number;
  13. orderBy?: WebVitals | null;
  14. };
  15. export const useTransactionWebVitalsQuery = ({orderBy, limit}: Props) => {
  16. const organization = useOrganization();
  17. const pageFilters = usePageFilters();
  18. const location = useLocation();
  19. const eventView = EventView.fromNewQueryWithPageFilters(
  20. {
  21. fields: [
  22. 'transaction',
  23. 'transaction.op',
  24. 'p75(measurements.lcp)',
  25. 'p75(measurements.fcp)',
  26. 'p75(measurements.cls)',
  27. 'p75(measurements.ttfb)',
  28. 'p75(measurements.fid)',
  29. 'count()',
  30. ],
  31. name: 'Web Vitals',
  32. query:
  33. 'transaction.op:pageload (transaction:/performance* or transaction:/discover* or transaction:/dashboards*)',
  34. orderby: mapWebVitalToOrderBy(orderBy),
  35. version: 2,
  36. },
  37. pageFilters.selection
  38. );
  39. const {data, isLoading, ...rest} = useDiscoverQuery({
  40. eventView,
  41. limit: limit ?? 50,
  42. location,
  43. orgSlug: organization.slug,
  44. options: {
  45. enabled: pageFilters.isReady,
  46. refetchOnWindowFocus: false,
  47. },
  48. });
  49. const tableData: RowWithScore[] =
  50. !isLoading && data?.data.length
  51. ? data.data
  52. .map(row => ({
  53. transaction: row.transaction?.toString(),
  54. 'transaction.op': row['transaction.op']?.toString(),
  55. 'p75(measurements.lcp)': row['p75(measurements.lcp)'] as number,
  56. 'p75(measurements.fcp)': row['p75(measurements.fcp)'] as number,
  57. 'p75(measurements.cls)': row['p75(measurements.cls)'] as number,
  58. 'p75(measurements.ttfb)': row['p75(measurements.ttfb)'] as number,
  59. 'p75(measurements.fid)': row['p75(measurements.fid)'] as number,
  60. 'count()': row['count()'] as number,
  61. }))
  62. .map(row => {
  63. const {totalScore, clsScore, fcpScore, lcpScore, ttfbScore, fidScore} =
  64. calculatePerformanceScore({
  65. lcp: row['p75(measurements.lcp)'],
  66. fcp: row['p75(measurements.fcp)'],
  67. cls: row['p75(measurements.cls)'],
  68. ttfb: row['p75(measurements.ttfb)'],
  69. fid: row['p75(measurements.fid)'],
  70. });
  71. return {
  72. ...row,
  73. score: totalScore,
  74. clsScore,
  75. fcpScore,
  76. lcpScore,
  77. ttfbScore,
  78. fidScore,
  79. };
  80. })
  81. : [];
  82. return {
  83. data: tableData,
  84. isLoading,
  85. ...rest,
  86. };
  87. };
  88. const mapWebVitalToOrderBy = (webVital?: WebVitals | null) => {
  89. switch (webVital) {
  90. case 'lcp':
  91. return '-p75_measurements_lcp';
  92. case 'fcp':
  93. return '-p75_measurements_fcp';
  94. case 'cls':
  95. return '-p75_measurements_cls';
  96. case 'ttfb':
  97. return '-p75_measurements_ttfb';
  98. case 'fid':
  99. return '-p75_measurements_fid';
  100. default:
  101. return '-count';
  102. }
  103. };