metricsDataSwitcher.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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 type EventView from 'sentry/utils/discover/eventView';
  7. import type {MetricDataSwitcherOutcome} from 'sentry/utils/performance/contexts/metricsCardinality';
  8. import {useMetricsCardinalityContext} from 'sentry/utils/performance/contexts/metricsCardinality';
  9. import {
  10. canUseMetricsData,
  11. MEPState,
  12. METRIC_SEARCH_SETTING_PARAM,
  13. } from 'sentry/utils/performance/contexts/metricsEnhancedSetting';
  14. import {decodeScalar} from 'sentry/utils/queryString';
  15. import {useNavigate} from 'sentry/utils/useNavigate';
  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 navigate = useNavigate();
  86. const shouldAdjustQuery =
  87. hasQuery && queryIsTransactionsBased && !outcome.forceTransactionsOnly;
  88. useEffect(() => {
  89. if (shouldAdjustQuery) {
  90. navigate({
  91. pathname: location.pathname,
  92. query: {
  93. ...location.query,
  94. cursor: undefined,
  95. query: undefined,
  96. [METRIC_SEARCH_SETTING_PARAM]: undefined,
  97. },
  98. });
  99. }
  100. }, [shouldAdjustQuery, location, navigate]);
  101. if (hasQuery && queryIsTransactionsBased && !outcome.forceTransactionsOnly) {
  102. eventView.query = ''; // TODO: Create switcher provider and move it to the route level to remove the need for this.
  103. }
  104. return <Fragment>{switcherChildren(outcome)}</Fragment>;
  105. }
  106. const LoadingContainer = styled('div')`
  107. display: flex;
  108. justify-content: center;
  109. `;