releaseChartControls.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import * as React from 'react';
  2. import OptionSelector from 'app/components/charts/optionSelector';
  3. import {
  4. ChartControls,
  5. InlineContainer,
  6. SectionHeading,
  7. SectionValue,
  8. } from 'app/components/charts/styles';
  9. import QuestionTooltip from 'app/components/questionTooltip';
  10. import NOT_AVAILABLE_MESSAGES from 'app/constants/notAvailableMessages';
  11. import {t} from 'app/locale';
  12. import {Organization, SelectValue} from 'app/types';
  13. import {WebVital} from 'app/utils/discover/fields';
  14. import {WEB_VITAL_DETAILS} from 'app/utils/performance/vitals/constants';
  15. export enum YAxis {
  16. SESSIONS = 'sessions',
  17. USERS = 'users',
  18. CRASH_FREE = 'crashFree',
  19. SESSION_DURATION = 'sessionDuration',
  20. EVENTS = 'events',
  21. FAILED_TRANSACTIONS = 'failedTransactions',
  22. COUNT_DURATION = 'countDuration',
  23. COUNT_VITAL = 'countVital',
  24. }
  25. export enum EventType {
  26. ALL = 'all',
  27. CSP = 'csp',
  28. DEFAULT = 'default',
  29. ERROR = 'error',
  30. TRANSACTION = 'transaction',
  31. }
  32. export const PERFORMANCE_AXIS = [
  33. YAxis.FAILED_TRANSACTIONS,
  34. YAxis.COUNT_DURATION,
  35. YAxis.COUNT_VITAL,
  36. ];
  37. type Props = {
  38. summary: React.ReactNode;
  39. yAxis: YAxis;
  40. onYAxisChange: (value: YAxis) => void;
  41. eventType: EventType;
  42. onEventTypeChange: (value: EventType) => void;
  43. vitalType: WebVital;
  44. onVitalTypeChange: (value: WebVital) => void;
  45. organization: Organization;
  46. hasHealthData: boolean;
  47. hasDiscover: boolean;
  48. hasPerformance: boolean;
  49. };
  50. const ReleaseChartControls = ({
  51. summary,
  52. yAxis,
  53. onYAxisChange,
  54. organization,
  55. hasHealthData,
  56. hasDiscover,
  57. hasPerformance,
  58. eventType = EventType.ALL,
  59. onEventTypeChange,
  60. vitalType = WebVital.LCP,
  61. onVitalTypeChange,
  62. }: Props) => {
  63. const noHealthDataTooltip = !hasHealthData
  64. ? NOT_AVAILABLE_MESSAGES.releaseHealth
  65. : undefined;
  66. const noDiscoverTooltip = !hasDiscover ? NOT_AVAILABLE_MESSAGES.discover : undefined;
  67. const noPerformanceTooltip = !hasPerformance
  68. ? NOT_AVAILABLE_MESSAGES.performance
  69. : undefined;
  70. const yAxisOptions: SelectValue<YAxis>[] = [
  71. {
  72. value: YAxis.SESSIONS,
  73. label: t('Session Count'),
  74. disabled: !hasHealthData,
  75. tooltip: noHealthDataTooltip,
  76. },
  77. {
  78. value: YAxis.SESSION_DURATION,
  79. label: t('Session Duration'),
  80. disabled: !hasHealthData,
  81. tooltip: noHealthDataTooltip,
  82. },
  83. {
  84. value: YAxis.USERS,
  85. label: t('User Count'),
  86. disabled: !hasHealthData,
  87. tooltip: noHealthDataTooltip,
  88. },
  89. {
  90. value: YAxis.CRASH_FREE,
  91. label: t('Crash Free Rate'),
  92. disabled: !hasHealthData,
  93. tooltip: noHealthDataTooltip,
  94. },
  95. {
  96. value: YAxis.FAILED_TRANSACTIONS,
  97. label: t('Failure Count'),
  98. disabled: !hasPerformance,
  99. tooltip: noPerformanceTooltip,
  100. },
  101. {
  102. value: YAxis.COUNT_DURATION,
  103. label: t('Slow Duration Count'),
  104. disabled: !hasPerformance,
  105. tooltip: noPerformanceTooltip,
  106. },
  107. {
  108. value: YAxis.COUNT_VITAL,
  109. label: t('Slow Vital Count'),
  110. disabled: !hasPerformance,
  111. tooltip: noPerformanceTooltip,
  112. },
  113. {
  114. value: YAxis.EVENTS,
  115. label: t('Event Count'),
  116. disabled: !hasDiscover && !hasPerformance,
  117. tooltip: noDiscoverTooltip,
  118. },
  119. ];
  120. const getSummaryHeading = () => {
  121. switch (yAxis) {
  122. case YAxis.USERS:
  123. return t('Total Active Users');
  124. case YAxis.CRASH_FREE:
  125. return t('Average Rate');
  126. case YAxis.SESSION_DURATION:
  127. return t('Median Duration');
  128. case YAxis.EVENTS:
  129. return t('Total Events');
  130. case YAxis.FAILED_TRANSACTIONS:
  131. return t('Failed Transactions');
  132. case YAxis.COUNT_DURATION:
  133. return t('Count over %sms', organization.apdexThreshold);
  134. case YAxis.COUNT_VITAL:
  135. return vitalType !== WebVital.CLS
  136. ? t('Count over %sms', WEB_VITAL_DETAILS[vitalType].poorThreshold)
  137. : t('Count over %s', WEB_VITAL_DETAILS[vitalType].poorThreshold);
  138. case YAxis.SESSIONS:
  139. default:
  140. return t('Total Sessions');
  141. }
  142. };
  143. return (
  144. <ChartControls>
  145. <InlineContainer>
  146. <SectionHeading key="total-label">
  147. {getSummaryHeading()}
  148. <QuestionTooltip
  149. position="top"
  150. size="sm"
  151. title={t('This value includes only the current release.')}
  152. />
  153. </SectionHeading>
  154. <SectionValue key="total-value">{summary}</SectionValue>
  155. </InlineContainer>
  156. <InlineContainer>
  157. <SecondarySelector
  158. yAxis={yAxis}
  159. eventType={eventType}
  160. onEventTypeChange={onEventTypeChange}
  161. vitalType={vitalType}
  162. onVitalTypeChange={onVitalTypeChange}
  163. />
  164. <OptionSelector
  165. title={t('Display')}
  166. selected={yAxis}
  167. options={yAxisOptions}
  168. onChange={onYAxisChange as (value: string) => void}
  169. />
  170. </InlineContainer>
  171. </ChartControls>
  172. );
  173. };
  174. const eventTypeOptions: SelectValue<EventType>[] = [
  175. {value: EventType.ALL, label: t('All')},
  176. {value: EventType.CSP, label: t('CSP')},
  177. {value: EventType.DEFAULT, label: t('Default')},
  178. {value: EventType.ERROR, label: 'Error'},
  179. {value: EventType.TRANSACTION, label: t('Transaction')},
  180. ];
  181. const vitalTypeOptions: SelectValue<WebVital>[] = [
  182. WebVital.FP,
  183. WebVital.FCP,
  184. WebVital.LCP,
  185. WebVital.FID,
  186. WebVital.CLS,
  187. ].map(vital => ({value: vital, label: WEB_VITAL_DETAILS[vital].name}));
  188. type SecondarySelectorProps = {
  189. yAxis: YAxis;
  190. eventType: EventType;
  191. onEventTypeChange: (v: EventType) => void;
  192. vitalType: WebVital;
  193. onVitalTypeChange: (v: WebVital) => void;
  194. };
  195. function SecondarySelector({
  196. yAxis,
  197. eventType,
  198. onEventTypeChange,
  199. vitalType,
  200. onVitalTypeChange,
  201. }: SecondarySelectorProps) {
  202. switch (yAxis) {
  203. case YAxis.EVENTS:
  204. return (
  205. <OptionSelector
  206. title={t('Event Type')}
  207. selected={eventType}
  208. options={eventTypeOptions}
  209. onChange={onEventTypeChange as (value: string) => void}
  210. />
  211. );
  212. case YAxis.COUNT_VITAL:
  213. return (
  214. <OptionSelector
  215. title={t('Vital')}
  216. selected={vitalType}
  217. options={vitalTypeOptions}
  218. onChange={onVitalTypeChange as (value: string) => void}
  219. />
  220. );
  221. default:
  222. return null;
  223. }
  224. }
  225. export default ReleaseChartControls;