metricsEnhancedSetting.tsx 5.3 KB

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