import {Fragment, memo, useEffect, useMemo, useState} from 'react'; import styled from '@emotion/styled'; import type {ButtonProps} from 'sentry/components/button'; import {Button} from 'sentry/components/button'; import {CompactSelect} from 'sentry/components/compactSelect'; import Input from 'sentry/components/input'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import PageFilterBar from 'sentry/components/organizations/pageFilterBar'; import Tag from 'sentry/components/tag'; import { IconCheckmark, IconClose, IconLightning, IconReleases, IconSliders, } from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {MetricMeta, MRI} from 'sentry/types'; import { isAllowedOp, isCustomMetric, isMeasurement, isSpanMetric, isTransactionDuration, stringifyMetricWidget, } from 'sentry/utils/metrics'; import {getReadableMetricType} from 'sentry/utils/metrics/formatters'; import type { MetricsQuery, MetricsQuerySubject, MetricWidgetQueryParams, } from 'sentry/utils/metrics/types'; import {MetricDisplayType} from 'sentry/utils/metrics/types'; import {useMetricsTags} from 'sentry/utils/metrics/useMetricsTags'; import {MetricSearchBar} from 'sentry/views/ddm/metricSearchBar'; import {formatMRI} from '../../../../utils/metrics/mri'; import {useMetricsDashboardContext} from '../metricsContext'; type InlineEditorProps = { displayType: MetricDisplayType; isEdit: boolean; metricsQuery: MetricsQuerySubject; onCancel: () => void; onChange: (data: Partial) => void; onSubmit: () => void; projects: number[]; title: string; onTitleChange?: (title: string) => void; powerUserMode?: boolean; size?: 'xs' | 'sm'; }; const isShownByDefault = (metric: MetricMeta) => isCustomMetric(metric) || isTransactionDuration(metric) || isMeasurement(metric) || isSpanMetric(metric); export const InlineEditor = memo(function InlineEditor({ metricsQuery, projects, displayType, onChange, onCancel, onSubmit, onTitleChange, title, isEdit, size = 'sm', }: InlineEditorProps) { const [editingName, setEditingName] = useState(false); const {metricsMeta: meta, isLoading: isMetaLoading} = useMetricsDashboardContext(); const {data: tags = []} = useMetricsTags(metricsQuery.mri, {projects}); const displayedMetrics = useMemo(() => { const isSelected = (metric: MetricMeta) => metric.mri === metricsQuery.mri; return meta .filter(metric => isShownByDefault(metric) || isSelected(metric)) .sort(metric => (isSelected(metric) ? -1 : 1)); }, [meta, metricsQuery.mri]); const selectedMeta = useMemo(() => { return meta.find(metric => metric.mri === metricsQuery.mri); }, [meta, metricsQuery.mri]); // Reset the query data if the selected metric is no longer available useEffect(() => { if ( metricsQuery.mri && !isMetaLoading && !displayedMetrics.find(metric => metric.mri === metricsQuery.mri) ) { onChange({mri: '' as MRI, op: '', groupBy: []}); } }, [isMetaLoading, displayedMetrics, metricsQuery.mri, onChange]); const [loading, setIsLoading] = useState(false); useEffect(() => { if (loading && !isEdit) { setIsLoading(false); } }, [isEdit, loading]); return ( {editingName && ( { onTitleChange?.(e.target.value); }} /> )} setEditingName(curr => !curr)} aria-label="edit name" /> {!editingName && ( { onChange({query}); }} query={metricsQuery.query} /> )} { onSubmit(); setIsLoading(true); }} aria-label="apply" />