import {Fragment, useCallback, useMemo, useState} from 'react'; import {css} from '@emotion/react'; import styled from '@emotion/styled'; import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator'; import { type ModalOptions, type ModalRenderProps, openModal, } from 'sentry/actionCreators/modal'; import SelectControl from 'sentry/components/forms/controls/selectControl'; import ProjectBadge from 'sentry/components/idBadge/projectBadge'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {MetricsExtractionRule} from 'sentry/types/metrics'; import type {Project} from 'sentry/types/project'; import {useCardinalityLimitedMetricVolume} from 'sentry/utils/metrics/useCardinalityLimitedMetricVolume'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; import { createCondition, explodeAggregateGroup, type FormData, MetricsExtractionRuleForm, } from 'sentry/views/settings/projectMetrics/metricsExtractionRuleForm'; import {useCreateMetricsExtractionRules} from 'sentry/views/settings/projectMetrics/utils/useMetricsExtractionRules'; interface Props { initialData?: Partial; projectId?: string | number; } const INITIAL_DATA: FormData = { spanAttribute: null, unit: 'none', aggregates: ['count'], tags: ['release', 'environment'], conditions: [createCondition()], }; export function MetricsExtractionRuleCreateModal({ Header, Body, closeModal, CloseButton, initialData: initalDataProp = {}, projectId: projectIdProp, }: Props & ModalRenderProps) { const {projects} = useProjects(); const {selection} = usePageFilters(); const initialData = useMemo(() => { return { ...INITIAL_DATA, ...initalDataProp, }; }, [initalDataProp]); const initialProjectId = useMemo(() => { if (projectIdProp) { return projectIdProp; } if (selection.projects.length === 1 && selection.projects[0] !== -1) { return projects.find(p => p.id === String(selection.projects[0]))?.id; } return undefined; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const [projectId, setProjectId] = useState( initialProjectId ); const projectOptions = useMemo(() => { const nonMemberProjects: Project[] = []; const memberProjects: Project[] = []; projects .filter( project => selection.projects.length === 0 || selection.projects.includes(parseInt(project.id, 10)) ) .forEach(project => project.isMember ? memberProjects.push(project) : nonMemberProjects.push(project) ); return [ { label: t('My Projects'), options: memberProjects.map(p => ({ value: p.id, label: p.slug, leadingItems: , })), }, { label: t('All Projects'), options: nonMemberProjects.map(p => ({ value: p.id, label: p.slug, leadingItems: , })), }, ]; }, [selection.projects, projects]); return (

{t('Create Metric')}

{initialProjectId === undefined ? ( setProjectId(value)} stacked={false} /> ) : null} {projectId ? ( ) : null}
); } function FormWrapper({ closeModal, projectId, initialData, }: { closeModal: () => void; initialData: FormData; projectId: string | number; }) { const organization = useOrganization(); const createExtractionRuleMutation = useCreateMetricsExtractionRules( organization.slug, projectId ); const {data: cardinality} = useCardinalityLimitedMetricVolume({ projects: [projectId], }); const handleSubmit = useCallback( ( data: FormData, onSubmitSuccess: (data: FormData) => void, onSubmitError: (error: any) => void ) => { const extractionRule: MetricsExtractionRule = { spanAttribute: data.spanAttribute!, tags: data.tags, aggregates: data.aggregates.flatMap(explodeAggregateGroup), unit: data.unit, conditions: data.conditions, projectId: Number(projectId), // Will be set by the backend createdById: null, dateAdded: '', dateUpdated: '', }; createExtractionRuleMutation.mutate( { metricsExtractionRules: [extractionRule], }, { onSuccess: () => { onSubmitSuccess(data); addSuccessMessage(t('Metric extraction rule created')); closeModal(); }, onError: error => { const message = error?.responseJSON?.detail ? (error.responseJSON.detail as string) : t('Unable to save your changes.'); onSubmitError(message); addErrorMessage(message); }, } ); onSubmitSuccess(data); }, [closeModal, projectId, createExtractionRuleMutation] ); return ( ); } const ProjectSelectionWrapper = styled('div')` padding-bottom: ${space(2)}; & > label { color: ${p => p.theme.gray300}; } `; export const modalCss = css` width: 100%; max-width: 900px; `; export function openExtractionRuleCreateModal(props: Props, options?: ModalOptions) { openModal( modalProps => , { modalCss, ...options, } ); }