import {Component, Fragment} from 'react'; import {RouteComponentProps} from 'react-router'; import styled from '@emotion/styled'; import * as Layout from 'sentry/components/layouts/thirds'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle'; import {t} from 'sentry/locale'; import {Organization, Project} from 'sentry/types'; import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent'; import EventView from 'sentry/utils/discover/eventView'; import {uniqueId} from 'sentry/utils/guid'; import Teams from 'sentry/utils/teams'; import BuilderBreadCrumbs from 'sentry/views/alerts/builder/builderBreadCrumbs'; import IssueRuleEditor from 'sentry/views/alerts/rules/issue'; import MetricRulesCreate from 'sentry/views/alerts/rules/metric/create'; import MetricRulesDuplicate from 'sentry/views/alerts/rules/metric/duplicate'; import {AlertRuleType} from 'sentry/views/alerts/types'; import { AlertType as WizardAlertType, AlertWizardAlertNames, DEFAULT_WIZARD_TEMPLATE, WizardRuleTemplate, } from 'sentry/views/alerts/wizard/options'; import {getAlertTypeFromAggregateDataset} from 'sentry/views/alerts/wizard/utils'; type RouteParams = { orgId: string; alertType?: AlertRuleType; projectId?: string; }; type Props = RouteComponentProps & { hasMetricAlerts: boolean; organization: Organization; project: Project; }; type State = { alertType: AlertRuleType; }; class Create extends Component { state = this.getInitialState(); getInitialState(): State { const {organization, location, project, params, router} = this.props; const { createFromDiscover, createFromWizard, aggregate, dataset, eventTypes, createFromDuplicate, } = location?.query ?? {}; let alertType = AlertRuleType.ISSUE; const hasAlertWizardV3 = organization.features.includes('alert-wizard-v3'); // Alerts can only be created via create from discover or alert wizard, until alert-wizard-v3 is fully implemented if (hasAlertWizardV3) { alertType = params.alertType || AlertRuleType.METRIC; // TODO(taylangocmen): Remove redirect with aggregate && dataset && eventTypes, init from template if ( alertType === AlertRuleType.METRIC && !(aggregate && dataset && eventTypes) && !createFromDuplicate ) { router.replace({ ...location, pathname: `/organizations/${organization.slug}/alerts/new/${alertType}`, query: { ...location.query, ...DEFAULT_WIZARD_TEMPLATE, project: project.slug, }, }); } } else if (createFromDiscover) { alertType = AlertRuleType.METRIC; } else if (createFromWizard) { if (aggregate && dataset && eventTypes) { alertType = AlertRuleType.METRIC; } else { // Just to be explicit alertType = AlertRuleType.ISSUE; } } else { router.replace(`/organizations/${organization.slug}/alerts/${project.slug}/wizard`); } return {alertType}; } componentDidMount() { const {organization, project} = this.props; const hasAlertWizardV3 = organization.features.includes('alert-wizard-v3'); trackAdvancedAnalyticsEvent('new_alert_rule.viewed', { organization, project_id: project.id, session_id: this.sessionId, alert_type: this.state.alertType, duplicate_rule: this.isDuplicateRule ? 'true' : 'false', wizard_v3: hasAlertWizardV3 ? 'true' : 'false', }); } /** Used to track analytics within one visit to the creation page */ sessionId = uniqueId(); get isDuplicateRule(): boolean { const {location, organization} = this.props; const createFromDuplicate = location?.query.createFromDuplicate === 'true'; const hasDuplicateAlertRules = organization.features.includes('duplicate-alert-rule'); return ( hasDuplicateAlertRules && createFromDuplicate && location?.query.duplicateRuleId ); } render() { const {hasMetricAlerts, organization, project, location, routes} = this.props; const {alertType} = this.state; const {aggregate, dataset, eventTypes, createFromWizard, createFromDiscover} = location?.query ?? {}; const wizardTemplate: WizardRuleTemplate = { aggregate: aggregate ?? DEFAULT_WIZARD_TEMPLATE.aggregate, dataset: dataset ?? DEFAULT_WIZARD_TEMPLATE.dataset, eventTypes: eventTypes ?? DEFAULT_WIZARD_TEMPLATE.eventTypes, }; const eventView = createFromDiscover ? EventView.fromLocation(location) : undefined; let wizardAlertType: undefined | WizardAlertType; if (createFromWizard && alertType === AlertRuleType.METRIC) { wizardAlertType = wizardTemplate ? getAlertTypeFromAggregateDataset(wizardTemplate) : 'issues'; } const title = t('New Alert Rule'); return ( {wizardAlertType ? `${t('Set Conditions for')} ${AlertWizardAlertNames[wizardAlertType]}` : title} {({teams, initiallyLoaded}) => initiallyLoaded ? ( {(!hasMetricAlerts || alertType === AlertRuleType.ISSUE) && ( id)} /> )} {hasMetricAlerts && alertType === AlertRuleType.METRIC && (this.isDuplicateRule ? ( id)} /> ) : ( id)} /> ))} ) : ( ) } ); } } const StyledHeaderContent = styled(Layout.HeaderContent)` overflow: visible; `; const Body = styled(Layout.Body)` && { padding: 0; gap: 0; } grid-template-rows: 1fr; @media (min-width: ${p => p.theme.breakpoints.large}) { grid-template-columns: minmax(100px, auto) 400px; } `; export default Create;