metricsEnhancedSetting.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import {Dispatch, ReactNode, useCallback, useReducer} from 'react';
  2. import {browserHistory} from 'react-router';
  3. import {Location} from 'history';
  4. import localStorage from 'sentry/utils/localStorage';
  5. import {decodeScalar} from 'sentry/utils/queryString';
  6. import useOrganization from 'sentry/utils/useOrganization';
  7. import {createDefinedContext} from './utils';
  8. export interface MetricsEnhancedSettingContext {
  9. autoSampleState: AutoSampleState;
  10. memoizationKey: string;
  11. metricSettingState: MEPState | null;
  12. setAutoSampleState: Dispatch<AutoSampleState>;
  13. setMetricSettingState: Dispatch<MEPState>;
  14. shouldQueryProvideMEPAutoParams: boolean;
  15. shouldQueryProvideMEPMetricParams: boolean;
  16. shouldQueryProvideMEPTransactionParams: boolean;
  17. }
  18. const [_MEPSettingProvider, _useMEPSettingContext, _MEPSettingContext] =
  19. createDefinedContext<MetricsEnhancedSettingContext>({
  20. name: 'MetricsEnhancedSettingContext',
  21. });
  22. export const MEPConsumer = _MEPSettingContext.Consumer;
  23. /**
  24. * These will be called something else in the copy, but functionally the data is coming from metrics / transactions.
  25. * "Unset" should be the initial state before any queries return for the first time.
  26. */
  27. export enum AutoSampleState {
  28. unset = 'unset',
  29. metrics = 'metrics',
  30. transactions = 'transactions',
  31. }
  32. /**
  33. * Metrics/transactions will be called something else in the copy, but functionally the data is coming from metrics / transactions.
  34. */
  35. export enum MEPState {
  36. auto = 'auto',
  37. metricsOnly = 'metricsOnly',
  38. transactionsOnly = 'transactionsOnly',
  39. }
  40. const METRIC_SETTING_PARAM = 'metricSetting';
  41. const storageKey = 'performance.metrics-enhanced-setting';
  42. export class MEPSetting {
  43. static get(): MEPState | null {
  44. const value = localStorage.getItem(storageKey);
  45. if (value) {
  46. if (!(value in MEPState)) {
  47. localStorage.removeItem(storageKey);
  48. return null;
  49. }
  50. return MEPState[value];
  51. }
  52. return null;
  53. }
  54. static set(value: MEPState) {
  55. localStorage.setItem(storageKey, value);
  56. }
  57. }
  58. export const MEPSettingProvider = ({
  59. children,
  60. location,
  61. _hasMEPState,
  62. }: {
  63. children: ReactNode;
  64. _hasMEPState?: MEPState;
  65. location?: Location;
  66. }) => {
  67. const organization = useOrganization();
  68. const canUseMEP =
  69. organization.features.includes('performance-use-metrics') ||
  70. organization.features.includes('performance-transaction-name-only-search');
  71. const shouldDefaultToMetrics = organization.features.includes(
  72. 'performance-transaction-name-only-search'
  73. );
  74. const allowedStates = [MEPState.auto, MEPState.metricsOnly, MEPState.transactionsOnly];
  75. const _metricSettingFromParam = location
  76. ? decodeScalar(location.query[METRIC_SETTING_PARAM])
  77. : MEPState.auto;
  78. const defaultMetricsState = shouldDefaultToMetrics
  79. ? MEPState.metricsOnly
  80. : MEPState.auto;
  81. const metricSettingFromParam =
  82. allowedStates.find(s => s === _metricSettingFromParam) ?? defaultMetricsState;
  83. const isControlledMEP = typeof _hasMEPState !== 'undefined';
  84. const [_metricSettingState, _setMetricSettingState] = useReducer(
  85. (_: MEPState, next: MEPState) => next,
  86. metricSettingFromParam
  87. );
  88. const setMetricSettingState = useCallback(
  89. (settingState: MEPState) => {
  90. if (!location) {
  91. return;
  92. }
  93. browserHistory.replace({
  94. ...location,
  95. query: {
  96. ...location.query,
  97. [METRIC_SETTING_PARAM]: settingState,
  98. },
  99. });
  100. _setMetricSettingState(settingState);
  101. },
  102. [location, _setMetricSettingState]
  103. );
  104. const [autoSampleState, setAutoSampleState] = useReducer(
  105. (_: AutoSampleState, next: AutoSampleState) => next,
  106. AutoSampleState.unset
  107. );
  108. const metricSettingState = isControlledMEP ? _hasMEPState : _metricSettingState;
  109. const shouldQueryProvideMEPAutoParams =
  110. canUseMEP && metricSettingState === MEPState.auto;
  111. const shouldQueryProvideMEPMetricParams =
  112. canUseMEP && metricSettingState === MEPState.metricsOnly;
  113. const shouldQueryProvideMEPTransactionParams =
  114. canUseMEP && metricSettingState === MEPState.transactionsOnly;
  115. const memoizationKey = `${metricSettingState}`;
  116. return (
  117. <_MEPSettingProvider
  118. value={{
  119. autoSampleState,
  120. metricSettingState,
  121. shouldQueryProvideMEPAutoParams,
  122. shouldQueryProvideMEPMetricParams,
  123. shouldQueryProvideMEPTransactionParams,
  124. memoizationKey,
  125. setMetricSettingState,
  126. setAutoSampleState,
  127. }}
  128. >
  129. {children}
  130. </_MEPSettingProvider>
  131. );
  132. };
  133. export const useMEPSettingContext = _useMEPSettingContext;