metricsDataSwitcher.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import {Fragment, useEffect} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import LoadingIndicator from 'sentry/components/loadingIndicator';
  5. import type {Organization} from 'sentry/types/organization';
  6. import {browserHistory} from 'sentry/utils/browserHistory';
  7. import type EventView from 'sentry/utils/discover/eventView';
  8. import type {MetricDataSwitcherOutcome} from 'sentry/utils/performance/contexts/metricsCardinality';
  9. import {useMetricsCardinalityContext} from 'sentry/utils/performance/contexts/metricsCardinality';
  10. import {
  11. canUseMetricsData,
  12. MEPState,
  13. METRIC_SEARCH_SETTING_PARAM,
  14. } from 'sentry/utils/performance/contexts/metricsEnhancedSetting';
  15. import {decodeScalar} from 'sentry/utils/queryString';
  16. interface MetricDataSwitchProps {
  17. children: (props: MetricDataSwitcherOutcome) => React.ReactNode;
  18. eventView: EventView;
  19. location: Location;
  20. organization: Organization;
  21. hideLoadingIndicator?: boolean;
  22. }
  23. /**
  24. * This component decides based on some stats about current projects whether to show certain views of the landing page.
  25. * It is primarily needed for the rollout during which time users, despite having the flag enabled,
  26. * may or may not have sampling rules, compatible sdk's etc. This can be simplified post rollout.
  27. */
  28. export function MetricsDataSwitcher(props: MetricDataSwitchProps) {
  29. const isUsingMetrics = canUseMetricsData(props.organization);
  30. const metricsCardinality = useMetricsCardinalityContext();
  31. if (!isUsingMetrics) {
  32. return (
  33. <Fragment>
  34. {props.children({
  35. forceTransactionsOnly: true,
  36. })}
  37. </Fragment>
  38. );
  39. }
  40. if (metricsCardinality.isLoading && !props.hideLoadingIndicator) {
  41. return (
  42. <Fragment>
  43. <LoadingContainer>
  44. <LoadingIndicator />
  45. </LoadingContainer>
  46. </Fragment>
  47. );
  48. }
  49. if (!metricsCardinality.outcome) {
  50. return (
  51. <Fragment>
  52. {props.children({
  53. forceTransactionsOnly: true,
  54. })}
  55. </Fragment>
  56. );
  57. }
  58. return (
  59. <Fragment>
  60. <MetricsSwitchHandler
  61. eventView={props.eventView}
  62. location={props.location}
  63. outcome={metricsCardinality.outcome}
  64. switcherChildren={props.children}
  65. />
  66. </Fragment>
  67. );
  68. }
  69. interface SwitcherHandlerProps {
  70. eventView: EventView;
  71. location: Location;
  72. outcome: MetricDataSwitcherOutcome;
  73. switcherChildren: MetricDataSwitchProps['children'];
  74. }
  75. function MetricsSwitchHandler({
  76. switcherChildren,
  77. outcome,
  78. location,
  79. eventView,
  80. }: SwitcherHandlerProps) {
  81. const {query} = location;
  82. const mepSearchState = decodeScalar(query[METRIC_SEARCH_SETTING_PARAM], '');
  83. const hasQuery = decodeScalar(query.query, '');
  84. const queryIsTransactionsBased = mepSearchState === MEPState.TRANSACTIONS_ONLY;
  85. const shouldAdjustQuery =
  86. hasQuery && queryIsTransactionsBased && !outcome.forceTransactionsOnly;
  87. useEffect(() => {
  88. if (shouldAdjustQuery) {
  89. browserHistory.push({
  90. pathname: location.pathname,
  91. query: {
  92. ...location.query,
  93. cursor: undefined,
  94. query: undefined,
  95. [METRIC_SEARCH_SETTING_PARAM]: undefined,
  96. },
  97. });
  98. }
  99. }, [shouldAdjustQuery, location]);
  100. if (hasQuery && queryIsTransactionsBased && !outcome.forceTransactionsOnly) {
  101. eventView.query = ''; // TODO: Create switcher provider and move it to the route level to remove the need for this.
  102. }
  103. return <Fragment>{switcherChildren(outcome)}</Fragment>;
  104. }
  105. const LoadingContainer = styled('div')`
  106. display: flex;
  107. justify-content: center;
  108. `;