metricsDataSwitcherAlert.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import {useCallback, useMemo} from 'react';
  2. import {WithRouterProps} from 'react-router';
  3. import {Location} from 'history';
  4. import {updateProjects} from 'sentry/actionCreators/pageFilters';
  5. import Alert from 'sentry/components/alert';
  6. import {GlobalSdkUpdateAlert} from 'sentry/components/globalSdkUpdateAlert';
  7. import ExternalLink from 'sentry/components/links/externalLink';
  8. import Link from 'sentry/components/links/link';
  9. import {SidebarPanelKey} from 'sentry/components/sidebar/types';
  10. import {t, tct} from 'sentry/locale';
  11. import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
  12. import {Organization, Project} from 'sentry/types';
  13. import EventView from 'sentry/utils/discover/eventView';
  14. import {MetricDataSwitcherOutcome} from 'sentry/utils/performance/contexts/metricsCardinality';
  15. import {
  16. areMultipleProjectsSelected,
  17. createUnnamedTransactionsDiscoverTarget,
  18. DiscoverQueryPageSource,
  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 handleReviewUpdatesClick = useCallback(() => {
  56. SidebarPanelStore.activatePanel(SidebarPanelKey.Broadcasts);
  57. }, []);
  58. const docsLink = useMemo(() => {
  59. const platforms = getSelectedProjectPlatformsArray(props.location, props.projects);
  60. if (platforms.length < 1) {
  61. return null;
  62. }
  63. const platform = platforms[0];
  64. if (UNSUPPORTED_TRANSACTION_NAME_DOCS.includes(platform)) {
  65. return null;
  66. }
  67. const supportedPlatform = SUPPORTED_TRANSACTION_NAME_DOCS.find(platformBase =>
  68. platform.includes(platformBase)
  69. );
  70. if (!supportedPlatform) {
  71. return null;
  72. }
  73. return `https://docs.sentry.io/platforms/${supportedPlatform}/enriching-events/transaction-name/`;
  74. }, [props.location, props.projects]);
  75. const handleSwitchToCompatibleProjects = useCallback(() => {
  76. updateProjects(props.compatibleProjects || [], props.router);
  77. }, [props.compatibleProjects, props.router]);
  78. if (!props.shouldNotifyUnnamedTransactions && !props.shouldWarnIncompatibleSDK) {
  79. // Control showing generic sdk-alert here since stacking alerts is noisy.
  80. return <GlobalSdkUpdateAlert />;
  81. }
  82. const discoverTarget = createUnnamedTransactionsDiscoverTarget(props);
  83. if (props.shouldWarnIncompatibleSDK) {
  84. const updateSDK = (
  85. <Link to="" onClick={handleReviewUpdatesClick}>
  86. {t('update your SDK version')}
  87. </Link>
  88. );
  89. if (areMultipleProjectsSelected(props.eventView)) {
  90. if ((props.compatibleProjects ?? []).length === 0) {
  91. return (
  92. <Alert
  93. type="warning"
  94. showIcon
  95. data-test-id="landing-mep-alert-multi-project-all-incompatible"
  96. >
  97. {tct(
  98. `A few projects are incompatible with dynamic sampling. To enable this feature [updateSDK].`,
  99. {
  100. updateSDK,
  101. }
  102. )}
  103. </Alert>
  104. );
  105. }
  106. return (
  107. <Alert
  108. type="warning"
  109. showIcon
  110. data-test-id="landing-mep-alert-multi-project-incompatible"
  111. >
  112. {tct(
  113. `A few projects are incompatible with dynamic sampling. You can either [updateSDK] or [onlyViewCompatible]`,
  114. {
  115. updateSDK,
  116. onlyViewCompatible: (
  117. <Link to="" onClick={handleSwitchToCompatibleProjects}>
  118. {t('only view compatible projects.')}
  119. </Link>
  120. ),
  121. }
  122. )}
  123. </Alert>
  124. );
  125. }
  126. return (
  127. <Alert
  128. type="warning"
  129. showIcon
  130. data-test-id="landing-mep-alert-single-project-incompatible"
  131. >
  132. {tct(
  133. `Your project has an outdated SDK which is incompatible with dynamic sampling. To enable this feature [updateSDK].`,
  134. {
  135. updateSDK,
  136. }
  137. )}
  138. </Alert>
  139. );
  140. }
  141. if (props.shouldNotifyUnnamedTransactions) {
  142. const discover = <Link to={discoverTarget}>{t('open them in Discover.')}</Link>;
  143. if (!docsLink) {
  144. return (
  145. <Alert type="warning" showIcon data-test-id="landing-mep-alert-unnamed-discover">
  146. {tct(
  147. `You have some unparameterized transactions which are incompatible with dynamic sampling. You can [discover]`,
  148. {
  149. discover,
  150. }
  151. )}
  152. </Alert>
  153. );
  154. }
  155. return (
  156. <Alert
  157. type="warning"
  158. showIcon
  159. data-test-id="landing-mep-alert-unnamed-discover-or-set"
  160. >
  161. {tct(
  162. `You have some unparameterized transactions which are incompatible with dynamic sampling. You can either [setNames] or [discover]`,
  163. {
  164. setNames: (
  165. <ExternalLink href={docsLink}>{t('set names manually')}</ExternalLink>
  166. ),
  167. discover,
  168. }
  169. )}
  170. </Alert>
  171. );
  172. }
  173. return null;
  174. }