useInpSpanSamplesWebVitalsQuery.tsx 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  2. import {
  3. DEFAULT_INDEXED_INTERACTION_SORT,
  4. type InteractionSpanSampleRowWithScore,
  5. SORTABLE_INDEXED_INTERACTION_FIELDS,
  6. } from 'sentry/views/insights/browser/webVitals/types';
  7. import type {BrowserType} from 'sentry/views/insights/browser/webVitals/utils/queryParameterDecoders/browserType';
  8. import {useWebVitalsSort} from 'sentry/views/insights/browser/webVitals/utils/useWebVitalsSort';
  9. import {useSpansIndexed} from 'sentry/views/insights/common/queries/useDiscover';
  10. import {SpanIndexedField} from 'sentry/views/insights/types';
  11. export function useInpSpanSamplesWebVitalsQuery({
  12. transaction,
  13. limit,
  14. enabled,
  15. filters = {},
  16. sortName,
  17. browserTypes,
  18. }: {
  19. limit: number;
  20. browserTypes?: BrowserType[];
  21. enabled?: boolean;
  22. filters?: {[key: string]: string[] | string | number | undefined};
  23. sortName?: string;
  24. transaction?: string;
  25. }) {
  26. const filteredSortableFields = SORTABLE_INDEXED_INTERACTION_FIELDS;
  27. const sort = useWebVitalsSort({
  28. sortName,
  29. defaultSort: DEFAULT_INDEXED_INTERACTION_SORT,
  30. sortableFields: filteredSortableFields as unknown as string[],
  31. });
  32. const mutableSearch = MutableSearch.fromQueryObject({
  33. has: 'message',
  34. [`!${SpanIndexedField.SPAN_DESCRIPTION}`]: '<unknown>',
  35. 'span.op': 'ui.interaction.click',
  36. 'measurements.score.weight.inp': '>0',
  37. ...filters,
  38. });
  39. if (transaction !== undefined) {
  40. mutableSearch.addFilterValue(SpanIndexedField.ORIGIN_TRANSACTION, transaction);
  41. }
  42. if (browserTypes) {
  43. mutableSearch.addDisjunctionFilterValues(SpanIndexedField.BROWSER_NAME, browserTypes);
  44. }
  45. const {data, isLoading, ...rest} = useSpansIndexed(
  46. {
  47. search: mutableSearch,
  48. sorts: [sort],
  49. fields: [
  50. SpanIndexedField.INP,
  51. SpanIndexedField.INP_SCORE,
  52. SpanIndexedField.INP_SCORE_WEIGHT,
  53. SpanIndexedField.TOTAL_SCORE,
  54. SpanIndexedField.ID,
  55. SpanIndexedField.TIMESTAMP,
  56. SpanIndexedField.PROFILE_ID,
  57. SpanIndexedField.REPLAY_ID,
  58. SpanIndexedField.USER,
  59. SpanIndexedField.ORIGIN_TRANSACTION,
  60. SpanIndexedField.PROJECT,
  61. SpanIndexedField.BROWSER_NAME,
  62. SpanIndexedField.SPAN_SELF_TIME,
  63. SpanIndexedField.SPAN_DESCRIPTION,
  64. ],
  65. enabled,
  66. limit,
  67. },
  68. 'api.performance.browser.web-vitals.spans'
  69. );
  70. const tableData: InteractionSpanSampleRowWithScore[] =
  71. !isLoading && data?.length
  72. ? data.map(row => {
  73. return {
  74. ...row,
  75. 'measurements.inp': row[SpanIndexedField.INP],
  76. 'user.display': row[SpanIndexedField.USER],
  77. replayId: row[SpanIndexedField.REPLAY_ID],
  78. 'profile.id': row[SpanIndexedField.PROFILE_ID],
  79. inpScore: Math.round(
  80. ((row[`measurements.score.inp`] ?? 0) /
  81. (row[`measurements.score.weight.inp`] ?? 0)) *
  82. 100
  83. ),
  84. totalScore: Math.round(row[`measurements.score.total`] ?? 0),
  85. projectSlug: row[SpanIndexedField.PROJECT],
  86. };
  87. })
  88. : [];
  89. return {
  90. data: tableData,
  91. isLoading,
  92. ...rest,
  93. };
  94. }