import {Fragment, useCallback, useMemo, useState} from 'react'; import {css} from '@emotion/react'; import type {ModalRenderProps} from 'sentry/actionCreators/modal'; import {Button, LinkButton} from 'sentry/components/button'; import ButtonBar from 'sentry/components/buttonBar'; import { MetricWidgetTitle, type MetricWidgetTitleState, } from 'sentry/components/modals/metricWidgetViewerModal/header'; import {Queries} from 'sentry/components/modals/metricWidgetViewerModal/queries'; import {MetricVisualization} from 'sentry/components/modals/metricWidgetViewerModal/visualization'; import type {WidgetViewerModalOptions} from 'sentry/components/modals/widgetViewerModal'; import {t} from 'sentry/locale'; import type {Organization} from 'sentry/types'; import {getDdmUrl} from 'sentry/utils/metrics'; import {toDisplayType} from 'sentry/utils/metrics/dashboard'; import {MetricQueryType} from 'sentry/utils/metrics/types'; import usePageFilters from 'sentry/utils/usePageFilters'; import type { DashboardMetricsEquation, DashboardMetricsQuery, Order, } from 'sentry/views/dashboards/metrics/types'; import { expressionsToApiQueries, expressionsToWidget, filterEquationsByDisplayType, filterQueriesByDisplayType, getMetricEquations, getMetricQueries, getMetricWidgetTitle, useGenerateExpressionId, } from 'sentry/views/dashboards/metrics/utils'; import {MetricDetails} from 'sentry/views/ddm/widgetDetails'; import {OrganizationContext} from 'sentry/views/organizationContext'; interface Props extends ModalRenderProps, WidgetViewerModalOptions { organization: Organization; } function MetricWidgetViewerModal({ organization, widget, Footer, Body, Header, closeModal, onMetricWidgetEdit, dashboardFilters, }: Props) { const {selection} = usePageFilters(); const [displayType, setDisplayType] = useState(widget.displayType); const [metricQueries, setMetricQueries] = useState(() => getMetricQueries(widget, dashboardFilters) ); const [metricEquations, setMetricEquations] = useState(() => getMetricEquations(widget) ); const filteredQueries = useMemo( () => filterQueriesByDisplayType(metricQueries, displayType), [metricQueries, displayType] ); const filteredEquations = useMemo( () => filterEquationsByDisplayType(metricEquations, displayType).filter( equation => equation.formula !== '' ), [metricEquations, displayType] ); const generateQueryId = useGenerateExpressionId(metricQueries); const generateEquationId = useGenerateExpressionId(metricEquations); const apiQueries = useMemo( () => expressionsToApiQueries([...filteredQueries, ...filteredEquations]), [filteredQueries, filteredEquations] ); const widgetMQL = useMemo( () => getMetricWidgetTitle([...filteredQueries, ...filteredEquations]), [filteredQueries, filteredEquations] ); const [title, setTitle] = useState({ stored: widget.title, edited: widget.title, isEditing: false, }); const handleTitleChange = useCallback( (patch: Partial) => { setTitle(curr => ({...curr, ...patch})); }, [setTitle] ); const handleQueryChange = useCallback( (data: Partial, index: number) => { setMetricQueries(curr => { const updated = [...curr]; updated[index] = {...updated[index], ...data} as DashboardMetricsQuery; return updated; }); }, [setMetricQueries] ); const handleEquationChange = useCallback( (data: Partial, index: number) => { setMetricEquations(curr => { const updated = [...curr]; updated[index] = {...updated[index], ...data} as DashboardMetricsEquation; return updated; }); }, [setMetricEquations] ); const handleOrderChange = useCallback( ({id, order}: {id: number; order: Order}) => { const queryIdx = filteredQueries.findIndex(query => query.id === id); if (queryIdx > -1) { setMetricQueries(curr => { return curr.map((query, i) => { const orderBy = i === queryIdx ? order : undefined; return {...query, orderBy}; }); }); return; } const equationIdx = filteredEquations.findIndex(equation => equation.id === id); if (equationIdx > -1) { setMetricEquations(curr => { return curr.map((equation, i) => { const orderBy = i === equationIdx ? order : undefined; return {...equation, orderBy}; }); }); } }, [filteredEquations, filteredQueries] ); const addQuery = useCallback(() => { setMetricQueries(curr => { return [ ...curr, { ...metricQueries[metricQueries.length - 1], id: generateQueryId(), }, ]; }); }, [generateQueryId, metricQueries]); const addEquation = useCallback(() => { setMetricEquations(curr => { return [ ...curr, { formula: '', name: '', id: generateEquationId(), type: MetricQueryType.FORMULA, }, ]; }); }, [generateEquationId]); const removeEquation = useCallback( (index: number) => { setMetricEquations(curr => { const updated = [...curr]; updated.splice(index, 1); return updated; }); }, [setMetricEquations] ); const removeQuery = useCallback( (index: number) => { setMetricQueries(curr => { const updated = [...curr]; updated.splice(index, 1); return updated; }); }, [setMetricQueries] ); const handleSubmit = useCallback(() => { const convertedWidget = expressionsToWidget( [...filteredQueries, ...filteredEquations], title.edited, toDisplayType(displayType) ); onMetricWidgetEdit?.(convertedWidget); closeModal(); }, [ filteredQueries, filteredEquations, title.edited, displayType, onMetricWidgetEdit, closeModal, ]); return (
); } export default MetricWidgetViewerModal; export const modalCss = css` width: 100%; max-width: 1200px; `;