utils.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import {Location} from 'history';
  2. import {t} from 'app/locale';
  3. import {LightWeightOrganization, Organization, Project} from 'app/types';
  4. import EventView from 'app/utils/discover/eventView';
  5. import {
  6. formatAbbreviatedNumber,
  7. formatFloat,
  8. formatPercentage,
  9. getDuration,
  10. } from 'app/utils/formatters';
  11. import {HistogramData} from 'app/utils/performance/histogram/types';
  12. import {decodeScalar} from 'app/utils/queryString';
  13. import {AxisOption, getTermHelp, PERFORMANCE_TERM} from '../data';
  14. import {Rectangle} from '../transactionSummary/transactionVitals/types';
  15. import {platformToPerformanceType, PROJECT_PERFORMANCE_TYPE} from '../utils';
  16. export const LEFT_AXIS_QUERY_KEY = 'left';
  17. export const RIGHT_AXIS_QUERY_KEY = 'right';
  18. type LandingDisplay = {
  19. label: string;
  20. field: LandingDisplayField;
  21. };
  22. export enum LandingDisplayField {
  23. ALL = 'all',
  24. FRONTEND_PAGELOAD = 'frontend_pageload',
  25. FRONTEND_OTHER = 'frontend_other',
  26. BACKEND = 'backend',
  27. MOBILE = 'mobile',
  28. }
  29. export const LANDING_DISPLAYS = [
  30. {
  31. label: 'All Transactions',
  32. field: LandingDisplayField.ALL,
  33. },
  34. {
  35. label: 'Frontend (Pageload)',
  36. field: LandingDisplayField.FRONTEND_PAGELOAD,
  37. },
  38. {
  39. label: 'Frontend (Other)',
  40. field: LandingDisplayField.FRONTEND_OTHER,
  41. },
  42. {
  43. label: 'Backend',
  44. field: LandingDisplayField.BACKEND,
  45. },
  46. {
  47. label: 'Mobile',
  48. field: LandingDisplayField.MOBILE,
  49. isShown: (organization: Organization) =>
  50. organization.features.includes('performance-mobile-vitals'),
  51. alpha: true,
  52. },
  53. ];
  54. export function getCurrentLandingDisplay(
  55. location: Location,
  56. projects: Project[],
  57. eventView?: EventView
  58. ): LandingDisplay {
  59. const landingField = decodeScalar(location?.query?.landingDisplay);
  60. const display = LANDING_DISPLAYS.find(({field}) => field === landingField);
  61. if (display) {
  62. return display;
  63. }
  64. const defaultDisplayField = getDefaultDisplayFieldForPlatform(projects, eventView);
  65. const defaultDisplay = LANDING_DISPLAYS.find(
  66. ({field}) => field === defaultDisplayField
  67. );
  68. return defaultDisplay || LANDING_DISPLAYS[0];
  69. }
  70. export function getChartWidth(chartData: HistogramData, refPixelRect: Rectangle | null) {
  71. const distance = refPixelRect ? refPixelRect.point2.x - refPixelRect.point1.x : 0;
  72. const chartWidth = chartData.length * distance;
  73. return {
  74. chartWidth,
  75. };
  76. }
  77. export function getDefaultDisplayFieldForPlatform(
  78. projects: Project[],
  79. eventView?: EventView
  80. ) {
  81. if (!eventView) {
  82. return LandingDisplayField.ALL;
  83. }
  84. const projectIds = eventView.project;
  85. const performanceTypeToDisplay = {
  86. [PROJECT_PERFORMANCE_TYPE.ANY]: LandingDisplayField.ALL,
  87. [PROJECT_PERFORMANCE_TYPE.FRONTEND]: LandingDisplayField.FRONTEND_PAGELOAD,
  88. [PROJECT_PERFORMANCE_TYPE.BACKEND]: LandingDisplayField.BACKEND,
  89. };
  90. const performanceType = platformToPerformanceType(projects, projectIds);
  91. const landingField =
  92. performanceTypeToDisplay[performanceType] ?? LandingDisplayField.ALL;
  93. return landingField;
  94. }
  95. type VitalCardDetail = {
  96. title: string;
  97. tooltip: string;
  98. formatter: (value: number) => string | number;
  99. };
  100. export const vitalCardDetails = (
  101. organization: LightWeightOrganization
  102. ): {[key: string]: VitalCardDetail | undefined} => {
  103. return {
  104. 'p75(transaction.duration)': {
  105. title: t('Duration (p75)'),
  106. tooltip: getTermHelp(organization, PERFORMANCE_TERM.P75),
  107. formatter: value => getDuration(value / 1000, value >= 1000 ? 3 : 0, true),
  108. },
  109. 'tpm()': {
  110. title: t('Throughput'),
  111. tooltip: getTermHelp(organization, PERFORMANCE_TERM.THROUGHPUT),
  112. formatter: formatAbbreviatedNumber,
  113. },
  114. 'failure_rate()': {
  115. title: t('Failure Rate'),
  116. tooltip: getTermHelp(organization, PERFORMANCE_TERM.FAILURE_RATE),
  117. formatter: value => formatPercentage(value, 2),
  118. },
  119. 'apdex()': {
  120. title: t('Apdex'),
  121. tooltip: organization.features.includes('project-transaction-threshold')
  122. ? getTermHelp(organization, PERFORMANCE_TERM.APDEX_NEW)
  123. : getTermHelp(organization, PERFORMANCE_TERM.APDEX),
  124. formatter: value => formatFloat(value, 4),
  125. },
  126. 'p75(measurements.frames_slow_rate)': {
  127. title: t('Slow Frames (p75)'),
  128. tooltip: getTermHelp(organization, PERFORMANCE_TERM.SLOW_FRAMES),
  129. formatter: value => formatPercentage(value, 2),
  130. },
  131. 'p75(measurements.frames_frozen_rate)': {
  132. title: t('Frozen Frames (p75)'),
  133. tooltip: getTermHelp(organization, PERFORMANCE_TERM.FROZEN_FRAMES),
  134. formatter: value => formatPercentage(value, 2),
  135. },
  136. 'p75(measurements.app_start_cold)': {
  137. title: t('Cold Start (p75)'),
  138. tooltip: getTermHelp(organization, PERFORMANCE_TERM.APP_START_COLD),
  139. formatter: value => getDuration(value / 1000, value >= 1000 ? 3 : 0, true),
  140. },
  141. 'p75(measurements.app_start_warm)': {
  142. title: t('Warm Start (p75)'),
  143. tooltip: getTermHelp(organization, PERFORMANCE_TERM.APP_START_WARM),
  144. formatter: value => getDuration(value / 1000, value >= 1000 ? 3 : 0, true),
  145. },
  146. 'p75(measurements.stall_percentage)': {
  147. title: t('Stall Percentage (p75)'),
  148. tooltip: getTermHelp(organization, PERFORMANCE_TERM.STALL_PERCENTAGE),
  149. formatter: value => formatPercentage(value, 2),
  150. },
  151. };
  152. };
  153. export function getDisplayAxes(options: AxisOption[], location: Location) {
  154. const leftDefault = options.find(opt => opt.isLeftDefault) || options[0];
  155. const rightDefault = options.find(opt => opt.isRightDefault) || options[1];
  156. const leftAxis =
  157. options.find(opt => opt.value === location.query[LEFT_AXIS_QUERY_KEY]) || leftDefault;
  158. const rightAxis =
  159. options.find(opt => opt.value === location.query[RIGHT_AXIS_QUERY_KEY]) ||
  160. rightDefault;
  161. return {
  162. leftAxis,
  163. rightAxis,
  164. };
  165. }