metricsDataSwitcherAlert.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import {useCallback, useMemo} from 'react';
  2. import type {WithRouterProps} from 'react-router';
  3. import type {Location} from 'history';
  4. import {updateProjects} from 'sentry/actionCreators/pageFilters';
  5. import {Alert} from 'sentry/components/alert';
  6. import ExternalLink from 'sentry/components/links/externalLink';
  7. import Link from 'sentry/components/links/link';
  8. import {SidebarPanelKey} from 'sentry/components/sidebar/types';
  9. import {t, tct} from 'sentry/locale';
  10. import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
  11. import type {Organization} from 'sentry/types/organization';
  12. import type {Project} from 'sentry/types/project';
  13. import type EventView from 'sentry/utils/discover/eventView';
  14. import type {MetricDataSwitcherOutcome} from 'sentry/utils/performance/contexts/metricsCardinality';
  15. import type {DiscoverQueryPageSource} from '../utils';
  16. import {
  17. createUnnamedTransactionsDiscoverTarget,
  18. getIsMultiProject,
  19. getSelectedProjectPlatformsArray,
  20. } from '../utils';
  21. interface MetricEnhancedDataAlertProps extends MetricDataSwitcherOutcome {
  22. eventView: EventView;
  23. location: Location;
  24. organization: Organization;
  25. projects: Project[];
  26. router: WithRouterProps['router'];
  27. source?: DiscoverQueryPageSource;
  28. }
  29. /**
  30. * From
  31. * https://github.com/getsentry/sentry-docs/blob/master/src/platforms/common/enriching-events/transaction-name.mdx
  32. */
  33. const SUPPORTED_TRANSACTION_NAME_DOCS = [
  34. 'javascript',
  35. 'node',
  36. 'python',
  37. 'ruby',
  38. 'native',
  39. 'react-native',
  40. 'dotnet',
  41. 'unity',
  42. 'flutter',
  43. 'dart',
  44. 'java',
  45. 'android',
  46. ];
  47. const UNSUPPORTED_TRANSACTION_NAME_DOCS = [
  48. 'javascript.cordova',
  49. 'javascript.nextjs',
  50. 'native.minidumps',
  51. ];
  52. export function MetricsDataSwitcherAlert(
  53. props: MetricEnhancedDataAlertProps
  54. ): React.ReactElement | null {
  55. const isOnFallbackThresolds = props.organization.features.includes(
  56. 'performance-mep-bannerless-ui'
  57. );
  58. const handleReviewUpdatesClick = useCallback(() => {
  59. SidebarPanelStore.activatePanel(SidebarPanelKey.BROADCASTS);
  60. }, []);
  61. const docsLink = useMemo(() => {
  62. const platforms = getSelectedProjectPlatformsArray(props.location, props.projects);
  63. if (platforms.length < 1) {
  64. return null;
  65. }
  66. const platform = platforms[0];
  67. if (UNSUPPORTED_TRANSACTION_NAME_DOCS.includes(platform)) {
  68. return null;
  69. }
  70. const supportedPlatform = SUPPORTED_TRANSACTION_NAME_DOCS.find(platformBase =>
  71. platform.includes(platformBase)
  72. );
  73. if (!supportedPlatform) {
  74. return null;
  75. }
  76. return `https://docs.sentry.io/platforms/${supportedPlatform}/enriching-events/transaction-name/`;
  77. }, [props.location, props.projects]);
  78. const handleSwitchToCompatibleProjects = useCallback(() => {
  79. updateProjects(props.compatibleProjects || [], props.router);
  80. }, [props.compatibleProjects, props.router]);
  81. if (!props.shouldNotifyUnnamedTransactions && !props.shouldWarnIncompatibleSDK) {
  82. // Control showing generic sdk-alert here since stacking alerts is noisy.
  83. return null;
  84. }
  85. const discoverTarget = createUnnamedTransactionsDiscoverTarget(props);
  86. if (isOnFallbackThresolds) {
  87. return null;
  88. }
  89. if (props.shouldWarnIncompatibleSDK) {
  90. const updateSDK = (
  91. <Link to="" onClick={handleReviewUpdatesClick}>
  92. {t('update your SDK version')}
  93. </Link>
  94. );
  95. if (getIsMultiProject(props.eventView.project)) {
  96. if ((props.compatibleProjects ?? []).length === 0) {
  97. return (
  98. <Alert
  99. type="warning"
  100. showIcon
  101. data-test-id="landing-mep-alert-multi-project-all-incompatible"
  102. >
  103. {tct(
  104. `A few projects are incompatible with dynamic sampling. To enable this feature [updateSDK].`,
  105. {
  106. updateSDK,
  107. }
  108. )}
  109. </Alert>
  110. );
  111. }
  112. return (
  113. <Alert
  114. type="warning"
  115. showIcon
  116. data-test-id="landing-mep-alert-multi-project-incompatible"
  117. >
  118. {tct(
  119. `A few projects are incompatible with dynamic sampling. You can either [updateSDK] or [onlyViewCompatible]`,
  120. {
  121. updateSDK,
  122. onlyViewCompatible: (
  123. <Link to="" onClick={handleSwitchToCompatibleProjects}>
  124. {t('only view compatible projects.')}
  125. </Link>
  126. ),
  127. }
  128. )}
  129. </Alert>
  130. );
  131. }
  132. return (
  133. <Alert
  134. type="warning"
  135. showIcon
  136. data-test-id="landing-mep-alert-single-project-incompatible"
  137. >
  138. {tct(
  139. `Your project has an outdated SDK which is incompatible with dynamic sampling. To enable this feature [updateSDK].`,
  140. {
  141. updateSDK,
  142. }
  143. )}
  144. </Alert>
  145. );
  146. }
  147. if (props.shouldNotifyUnnamedTransactions) {
  148. const discover = <Link to={discoverTarget}>{t('open them in Discover.')}</Link>;
  149. if (!docsLink) {
  150. return (
  151. <Alert type="warning" showIcon data-test-id="landing-mep-alert-unnamed-discover">
  152. {tct(
  153. `You have some unparameterized transactions which are incompatible with dynamic sampling. You can [discover]`,
  154. {
  155. discover,
  156. }
  157. )}
  158. </Alert>
  159. );
  160. }
  161. return (
  162. <Alert
  163. type="warning"
  164. showIcon
  165. data-test-id="landing-mep-alert-unnamed-discover-or-set"
  166. >
  167. {tct(
  168. `You have some unparameterized transactions which are incompatible with dynamic sampling. You can either [setNames] or [discover]`,
  169. {
  170. setNames: (
  171. <ExternalLink href={docsLink}>{t('set names manually')}</ExternalLink>
  172. ),
  173. discover,
  174. }
  175. )}
  176. </Alert>
  177. );
  178. }
  179. return null;
  180. }