// eslint-disable-next-line no-restricted-imports import {withRouter, WithRouterProps} from 'react-router'; import { addErrorMessage, addLoadingMessage, addSuccessMessage, } from 'sentry/actionCreators/indicator'; import {navigateTo} from 'sentry/actionCreators/navigation'; import Access from 'sentry/components/acl/access'; import GuideAnchor from 'sentry/components/assistant/guideAnchor'; import Button, {ButtonProps} from 'sentry/components/button'; import Link from 'sentry/components/links/link'; import {IconSiren} from 'sentry/icons'; import type {SVGIconProps} from 'sentry/icons/svgIcon'; import {t, tct} from 'sentry/locale'; import type {Organization, Project} from 'sentry/types'; import type EventView from 'sentry/utils/discover/eventView'; import useApi from 'sentry/utils/useApi'; import { AlertType, AlertWizardAlertNames, AlertWizardRuleTemplates, DEFAULT_WIZARD_TEMPLATE, } from 'sentry/views/alerts/wizard/options'; export type CreateAlertFromViewButtonProps = ButtonProps & { /** * Discover query used to create the alert */ eventView: EventView; organization: Organization; projects: Project[]; alertType?: AlertType; className?: string; /** * Passed in value to override any metrics decision and switch back to transactions dataset. * We currently do a few checks on metrics data on performance pages and this passes the decision onward to alerts. */ disableMetricDataset?: boolean; /** * Called when the user is redirected to the alert builder */ onClick?: () => void; referrer?: string; }; /** * Provide a button that can create an alert from an event view. * Emits incompatible query issues on click */ function CreateAlertFromViewButton({ projects, eventView, organization, referrer, onClick, alertType, disableMetricDataset, ...buttonProps }: CreateAlertFromViewButtonProps) { const project = projects.find(p => p.id === `${eventView.project[0]}`); const queryParams = eventView.generateQueryStringObject(); if (queryParams.query?.includes(`project:${project?.slug}`)) { queryParams.query = (queryParams.query as string).replace( `project:${project?.slug}`, '' ); } const alertTemplate = alertType ? AlertWizardRuleTemplates[alertType] : DEFAULT_WIZARD_TEMPLATE; const to = { pathname: `/organizations/${organization.slug}/alerts/new/metric/`, query: { ...queryParams, createFromDiscover: true, disableMetricDataset, referrer, ...alertTemplate, project: project?.slug, aggregate: queryParams.yAxis ?? alertTemplate.aggregate, }, }; const handleClick = () => { onClick?.(); }; return ( ); } type CreateAlertButtonProps = { organization: Organization; alertOption?: keyof typeof AlertWizardAlertNames; hideIcon?: boolean; iconProps?: SVGIconProps; /** * Callback when the button is clicked. * This is different from `onClick` which always overrides the default * behavior when the button was clicked. */ onEnter?: () => void; projectSlug?: string; referrer?: string; showPermissionGuide?: boolean; } & WithRouterProps & ButtonProps; const CreateAlertButton = withRouter( ({ organization, projectSlug, iconProps, referrer, router, hideIcon, showPermissionGuide, alertOption, onEnter, ...buttonProps }: CreateAlertButtonProps) => { const api = useApi(); const createAlertUrl = (providedProj: string): string => { const params = new URLSearchParams(); if (referrer) { params.append('referrer', referrer); } if (providedProj !== ':projectId') { params.append('project', providedProj); } if (alertOption) { params.append('alert_option', alertOption); } return `/organizations/${organization.slug}/alerts/wizard/?${params.toString()}`; }; function handleClickWithoutProject(event: React.MouseEvent) { event.preventDefault(); onEnter?.(); navigateTo(createAlertUrl(':projectId'), router); } async function enableAlertsMemberWrite() { const settingsEndpoint = `/organizations/${organization.slug}/`; addLoadingMessage(); try { await api.requestPromise(settingsEndpoint, { method: 'PUT', data: { alertsMemberWrite: true, }, }); addSuccessMessage(t('Successfully updated organization settings')); } catch (err) { addErrorMessage(t('Unable to update organization settings')); } } const permissionTooltipText = tct( 'Ask your organization owner or manager to [settingsLink:enable alerts access] for you.', {settingsLink: } ); const renderButton = (hasAccess: boolean) => ( ); const showGuide = !organization.alertsMemberWrite && !!showPermissionGuide; return ( {({hasAccess}) => showGuide ? ( {({hasAccess: isOrgAdmin}) => ( {renderButton(hasAccess)} )} ) : ( renderButton(hasAccess) ) } ); } ); export {CreateAlertFromViewButton}; export default CreateAlertButton;