utils.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import {Location, Query} from 'history';
  2. import {t} from 'sentry/locale';
  3. import {decodeScalar} from 'sentry/utils/queryString';
  4. import {filterToField, SpanOperationBreakdownFilter} from '../filter';
  5. import {TransactionFilterOptions} from '../utils';
  6. export enum EventsDisplayFilterName {
  7. p50 = 'p50',
  8. p75 = 'p75',
  9. p95 = 'p95',
  10. p99 = 'p99',
  11. p100 = 'p100',
  12. }
  13. export type EventsDisplayFilter = {
  14. label: string;
  15. name: EventsDisplayFilterName;
  16. query?: string[][];
  17. sort?: {field: string; kind: 'desc' | 'asc'};
  18. };
  19. export type EventsFilterOptions = {
  20. [name in EventsDisplayFilterName]: EventsDisplayFilter;
  21. };
  22. export type EventsFilterPercentileValues = {
  23. [name in Exclude<EventsDisplayFilterName, EventsDisplayFilterName.p100>]: number;
  24. };
  25. export function getEventsFilterOptions(
  26. spanOperationBreakdownFilter: SpanOperationBreakdownFilter,
  27. percentileValues?: EventsFilterPercentileValues
  28. ): EventsFilterOptions {
  29. const {p99, p95, p75, p50} = percentileValues
  30. ? percentileValues
  31. : {p99: 0, p95: 0, p75: 0, p50: 0};
  32. return {
  33. [EventsDisplayFilterName.p50]: {
  34. name: EventsDisplayFilterName.p50,
  35. query: p50 ? [['transaction.duration', `<=${p50.toFixed(0)}`]] : undefined,
  36. sort: {
  37. kind: 'desc',
  38. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  39. },
  40. label: t('p50'),
  41. },
  42. [EventsDisplayFilterName.p75]: {
  43. name: EventsDisplayFilterName.p75,
  44. query: p75 ? [['transaction.duration', `<=${p75.toFixed(0)}`]] : undefined,
  45. sort: {
  46. kind: 'desc',
  47. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  48. },
  49. label: t('p75'),
  50. },
  51. [EventsDisplayFilterName.p95]: {
  52. name: EventsDisplayFilterName.p95,
  53. query: p95 ? [['transaction.duration', `<=${p95.toFixed(0)}`]] : undefined,
  54. sort: {
  55. kind: 'desc',
  56. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  57. },
  58. label: t('p95'),
  59. },
  60. [EventsDisplayFilterName.p99]: {
  61. name: EventsDisplayFilterName.p99,
  62. query: p99 ? [['transaction.duration', `<=${p99.toFixed(0)}`]] : undefined,
  63. sort: {
  64. kind: 'desc',
  65. field: filterToField(spanOperationBreakdownFilter) || 'transaction.duration',
  66. },
  67. label: t('p99'),
  68. },
  69. [EventsDisplayFilterName.p100]: {
  70. name: EventsDisplayFilterName.p100,
  71. label: t('p100'),
  72. },
  73. };
  74. }
  75. export function eventsRouteWithQuery({
  76. orgSlug,
  77. transaction,
  78. projectID,
  79. query,
  80. }: {
  81. orgSlug: string;
  82. query: Query;
  83. transaction: string;
  84. projectID?: string | string[];
  85. }) {
  86. const pathname = `/organizations/${orgSlug}/performance/summary/events/`;
  87. return {
  88. pathname,
  89. query: {
  90. transaction,
  91. project: projectID,
  92. environment: query.environment,
  93. statsPeriod: query.statsPeriod,
  94. start: query.start,
  95. end: query.end,
  96. query: query.query,
  97. },
  98. };
  99. }
  100. function stringToFilter(option: string) {
  101. if (
  102. Object.values(EventsDisplayFilterName).includes(option as EventsDisplayFilterName)
  103. ) {
  104. return option as EventsDisplayFilterName;
  105. }
  106. return EventsDisplayFilterName.p100;
  107. }
  108. export function decodeEventsDisplayFilterFromLocation(location: Location) {
  109. return stringToFilter(
  110. decodeScalar(location.query.showTransactions, EventsDisplayFilterName.p100)
  111. );
  112. }
  113. export function filterEventsDisplayToLocationQuery(
  114. option: EventsDisplayFilterName,
  115. spanOperationBreakdownFilter: SpanOperationBreakdownFilter
  116. ) {
  117. const eventsFilterOptions = getEventsFilterOptions(spanOperationBreakdownFilter);
  118. const kind = eventsFilterOptions[option].sort?.kind;
  119. const field = eventsFilterOptions[option].sort?.field;
  120. const query: {showTransactions: string; sort?: string} = {
  121. showTransactions: option,
  122. };
  123. if (kind && field) {
  124. query.sort = `${kind === 'desc' ? '-' : ''}${field}`;
  125. }
  126. return query;
  127. }
  128. export function mapShowTransactionToPercentile(
  129. showTransaction
  130. ): EventsDisplayFilterName | undefined {
  131. switch (showTransaction) {
  132. case TransactionFilterOptions.OUTLIER:
  133. return EventsDisplayFilterName.p100;
  134. case TransactionFilterOptions.SLOW:
  135. return EventsDisplayFilterName.p95;
  136. default:
  137. return undefined;
  138. }
  139. }