import {useState} from 'react'; import type {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import Feature from 'sentry/components/acl/feature'; import FeatureDisabled from 'sentry/components/acl/featureDisabled'; import FeatureBadge from 'sentry/components/badge/featureBadge'; import Tag from 'sentry/components/badge/tag'; import CreateAlertButton from 'sentry/components/createAlertButton'; import {Hovercard} from 'sentry/components/hovercard'; import * as Layout from 'sentry/components/layouts/thirds'; import ExternalLink from 'sentry/components/links/externalLink'; import List from 'sentry/components/list'; import ListItem from 'sentry/components/list/listItem'; import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import PanelHeader from 'sentry/components/panels/panelHeader'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Organization} from 'sentry/types/organization'; import {trackAnalytics} from 'sentry/utils/analytics'; import {hasCustomMetricsExtractionRules} from 'sentry/utils/metrics/features'; import BuilderBreadCrumbs from 'sentry/views/alerts/builder/builderBreadCrumbs'; import {Dataset} from 'sentry/views/alerts/rules/metric/types'; import {AlertRuleType} from 'sentry/views/alerts/types'; import type {AlertType, WizardRuleTemplate} from './options'; import { AlertWizardAlertNames, AlertWizardRuleTemplates, getAlertWizardCategories, } from './options'; import {AlertWizardPanelContent} from './panelContent'; import RadioPanelGroup from './radioPanelGroup'; type RouteParams = { projectId?: string; }; type AlertWizardProps = RouteComponentProps & { organization: Organization; projectId: string; }; const DEFAULT_ALERT_OPTION = 'issues'; function AlertWizard({organization, params, location, projectId}: AlertWizardProps) { const [alertOption, setAlertOption] = useState( location.query.alert_option in AlertWizardAlertNames ? location.query.alert_option : DEFAULT_ALERT_OPTION ); const projectSlug = params.projectId ?? projectId; const handleChangeAlertOption = (option: AlertType) => { setAlertOption(option); }; function renderCreateAlertButton() { let metricRuleTemplate: Readonly | undefined = AlertWizardRuleTemplates[alertOption]; const isMetricAlert = !!metricRuleTemplate; const isTransactionDataset = metricRuleTemplate?.dataset === Dataset.TRANSACTIONS; // If theres anything using the legacy sessions dataset, we need to convert it to metrics if (metricRuleTemplate?.dataset === Dataset.SESSIONS) { metricRuleTemplate = {...metricRuleTemplate, dataset: Dataset.METRICS}; } if (metricRuleTemplate?.dataset === Dataset.ERRORS) { // Pre-fill is:unresolved for error metric alerts // Filters out events in issues that are archived or resolved metricRuleTemplate = {...metricRuleTemplate, query: 'is:unresolved'}; } const renderNoAccess = p => ( } > {p.children(p)} ); return ( {({hasFeature}) => ( trackAnalytics('alert_wizard.option_selected', { organization, alert_type: alertOption, }) } > {t('Set Conditions')} )} ); } const panelContent = AlertWizardPanelContent[alertOption]; return ( {t('Select Alert')} {getAlertWizardCategories(organization).map( ({categoryHeading, options}) => (
{categoryHeading} { return [ alertType, AlertWizardAlertNames[alertType], alertType === 'custom_metrics' && hasCustomMetricsExtractionRules(organization) ? ( {t('deprecated')} ) : alertType === 'insights_metrics' ? ( ) : null, ]; })} onChange={option => handleChangeAlertOption(option as AlertType)} value={alertOption} label="alert-option" />
) )}
{AlertWizardAlertNames[alertOption]} {panelContent.description}{' '} {panelContent.docsLink && ( {t('Learn more')} )} {t('Examples')} {panelContent.examples.map((example, i) => ( {example} ))}
{renderCreateAlertButton()}
); } const StyledHeaderContent = styled(Layout.HeaderContent)` overflow: visible; `; const CategoryTitle = styled('h2')` font-weight: ${p => p.theme.fontWeightNormal}; font-size: ${p => p.theme.fontSizeExtraLarge}; margin-bottom: ${space(1)} !important; `; const WizardBody = styled('div')` display: flex; padding-top: ${space(1)}; `; const WizardOptions = styled('div')` display: flex; flex-direction: column; gap: ${space(4)}; flex: 3; margin-right: ${space(3)}; padding-right: ${space(3)}; max-width: 300px; `; const WizardImage = styled('img')` max-height: 300px; `; const WizardPanel = styled(Panel)<{visible?: boolean}>` max-width: 700px; position: sticky; top: 20px; flex: 5; display: flex; ${p => !p.visible && 'visibility: hidden'}; flex-direction: column; align-items: start; align-self: flex-start; ${p => p.visible && 'animation: 0.6s pop ease forwards'}; @keyframes pop { 0% { transform: translateY(30px); opacity: 0; } 100% { transform: translateY(0); opacity: 1; } } `; const ExampleList = styled(List)` margin-bottom: ${space(2)} !important; `; const WizardPanelBody = styled(PanelBody)` flex: 1; min-width: 100%; `; const PanelDescription = styled('p')` margin-bottom: ${space(2)}; `; const ExampleHeader = styled('div')` margin: 0 0 ${space(1)} 0; font-size: ${p => p.theme.fontSizeLarge}; `; const ExampleItem = styled(ListItem)` font-size: ${p => p.theme.fontSizeMedium}; `; const WizardFooter = styled('div')` border-top: 1px solid ${p => p.theme.border}; padding: ${space(1.5)} ${space(1.5)} ${space(1.5)} ${space(1.5)}; `; const WizardButtonContainer = styled('div')` display: flex; justify-content: flex-end; a:not(:last-child) { margin-right: ${space(1)}; } `; const WizardGroupedOptions = styled(RadioPanelGroup)` label { grid-template-columns: repeat(3, max-content); } `; export default AlertWizard;