import {useCallback, useMemo} from 'react'; import type {WithRouterProps} from 'react-router'; import type {Location} from 'history'; import {updateProjects} from 'sentry/actionCreators/pageFilters'; import {Alert} from 'sentry/components/alert'; import ExternalLink from 'sentry/components/links/externalLink'; import Link from 'sentry/components/links/link'; import {SidebarPanelKey} from 'sentry/components/sidebar/types'; import {t, tct} from 'sentry/locale'; import SidebarPanelStore from 'sentry/stores/sidebarPanelStore'; import type {Organization, Project} from 'sentry/types'; import type EventView from 'sentry/utils/discover/eventView'; import type {MetricDataSwitcherOutcome} from 'sentry/utils/performance/contexts/metricsCardinality'; import type {DiscoverQueryPageSource} from '../utils'; import { createUnnamedTransactionsDiscoverTarget, getIsMultiProject, getSelectedProjectPlatformsArray, } from '../utils'; interface MetricEnhancedDataAlertProps extends MetricDataSwitcherOutcome { eventView: EventView; location: Location; organization: Organization; projects: Project[]; router: WithRouterProps['router']; source?: DiscoverQueryPageSource; } /** * From * https://github.com/getsentry/sentry-docs/blob/master/src/platforms/common/enriching-events/transaction-name.mdx */ const SUPPORTED_TRANSACTION_NAME_DOCS = [ 'javascript', 'node', 'python', 'ruby', 'native', 'react-native', 'dotnet', 'unity', 'flutter', 'dart', 'java', 'android', ]; const UNSUPPORTED_TRANSACTION_NAME_DOCS = [ 'javascript.cordova', 'javascript.nextjs', 'native.minidumps', ]; export function MetricsDataSwitcherAlert( props: MetricEnhancedDataAlertProps ): React.ReactElement | null { const isOnFallbackThresolds = props.organization.features.includes( 'performance-mep-bannerless-ui' ); const handleReviewUpdatesClick = useCallback(() => { SidebarPanelStore.activatePanel(SidebarPanelKey.BROADCASTS); }, []); const docsLink = useMemo(() => { const platforms = getSelectedProjectPlatformsArray(props.location, props.projects); if (platforms.length < 1) { return null; } const platform = platforms[0]; if (UNSUPPORTED_TRANSACTION_NAME_DOCS.includes(platform)) { return null; } const supportedPlatform = SUPPORTED_TRANSACTION_NAME_DOCS.find(platformBase => platform.includes(platformBase) ); if (!supportedPlatform) { return null; } return `https://docs.sentry.io/platforms/${supportedPlatform}/enriching-events/transaction-name/`; }, [props.location, props.projects]); const handleSwitchToCompatibleProjects = useCallback(() => { updateProjects(props.compatibleProjects || [], props.router); }, [props.compatibleProjects, props.router]); if (!props.shouldNotifyUnnamedTransactions && !props.shouldWarnIncompatibleSDK) { // Control showing generic sdk-alert here since stacking alerts is noisy. return null; } const discoverTarget = createUnnamedTransactionsDiscoverTarget(props); if (isOnFallbackThresolds) { return null; } if (props.shouldWarnIncompatibleSDK) { const updateSDK = ( {t('update your SDK version')} ); if (getIsMultiProject(props.eventView.project)) { if ((props.compatibleProjects ?? []).length === 0) { return ( {tct( `A few projects are incompatible with dynamic sampling. To enable this feature [updateSDK].`, { updateSDK, } )} ); } return ( {tct( `A few projects are incompatible with dynamic sampling. You can either [updateSDK] or [onlyViewCompatible]`, { updateSDK, onlyViewCompatible: ( {t('only view compatible projects.')} ), } )} ); } return ( {tct( `Your project has an outdated SDK which is incompatible with dynamic sampling. To enable this feature [updateSDK].`, { updateSDK, } )} ); } if (props.shouldNotifyUnnamedTransactions) { const discover = {t('open them in Discover.')}; if (!docsLink) { return ( {tct( `You have some unparameterized transactions which are incompatible with dynamic sampling. You can [discover]`, { discover, } )} ); } return ( {tct( `You have some unparameterized transactions which are incompatible with dynamic sampling. You can either [setNames] or [discover]`, { setNames: ( {t('set names manually')} ), discover, } )} ); } return null; }