import {Fragment, useCallback, useMemo} from 'react';
import styled from '@emotion/styled';
import Feature from 'sentry/components/acl/feature';
import {Button} from 'sentry/components/button';
import HookOrDefault from 'sentry/components/hookOrDefault';
import {
type Field,
MetricSamplesTable,
SearchableMetricSamplesTable,
} from 'sentry/components/metrics/metricSamplesTable';
import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
import {t} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {PageFilters} from 'sentry/types/core';
import type {MetricAggregation, MRI} from 'sentry/types/metrics';
import {defined} from 'sentry/utils';
import {isVirtualMetric} from 'sentry/utils/metrics';
import type {FocusedMetricsSeries, MetricsWidget} from 'sentry/utils/metrics/types';
import {isMetricsEquationWidget} from 'sentry/utils/metrics/types';
import type {MetricsSamplesResults} from 'sentry/utils/metrics/useMetricsSamples';
import {useVirtualMetricsContext} from 'sentry/utils/metrics/virtualMetricsContext';
import useOrganization from 'sentry/utils/useOrganization';
import usePageFilters from 'sentry/utils/usePageFilters';
import type {FocusAreaProps} from 'sentry/views/metrics/context';
import {useMetricsContext} from 'sentry/views/metrics/context';
import {extendQueryWithGroupBys} from 'sentry/views/metrics/utils';
import {generateTracesRouteWithQuery} from 'sentry/views/traces/utils';
export function WidgetDetails() {
const {
selectedWidgetIndex,
widgets,
focusArea,
setHighlightedSampleId,
setMetricsSamples,
hasPerformanceMetrics,
} = useMetricsContext();
const selectedWidget = widgets[selectedWidgetIndex] as MetricsWidget | undefined;
const handleSampleRowHover = useCallback(
(sampleId?: string) => {
setHighlightedSampleId(sampleId);
},
[setHighlightedSampleId]
);
if (!selectedWidget || isMetricsEquationWidget(selectedWidget)) {
return ;
}
const {mri, aggregation, query, condition, focusedSeries} = selectedWidget;
return (
);
}
interface MetricDetailsProps {
aggregation?: MetricAggregation;
condition?: number;
focusArea?: FocusAreaProps;
focusedSeries?: FocusedMetricsSeries[];
hasPerformanceMetrics?: boolean;
mri?: MRI;
onRowHover?: (sampleId?: string) => void;
query?: string;
setMetricsSamples?: React.Dispatch<
React.SetStateAction['data'] | undefined>
>;
}
export function MetricDetails({
mri,
aggregation,
condition,
query,
focusedSeries,
onRowHover,
focusArea,
setMetricsSamples,
hasPerformanceMetrics,
}: MetricDetailsProps) {
const {selection} = usePageFilters();
const organization = useOrganization();
const {getCondition} = useVirtualMetricsContext();
const queryWithFocusedSeries = useMemo(
() =>
focusedSeries &&
extendQueryWithGroupBys(
query || '',
focusedSeries.map(s => s.groupBy)
),
[focusedSeries, query]
);
const selectionRange = focusArea?.selection?.range;
const tracesTarget = useMemo(() => {
const selectionDatetime =
defined(selectionRange) && defined(selectionRange) && defined(selectionRange)
? ({
start: selectionRange.start,
end: selectionRange.end,
} as PageFilters['datetime'])
: undefined;
if (mri && isVirtualMetric({mri})) {
const conditionQuery = getCondition(mri, condition || -1)?.value || '';
return generateTracesRouteWithQuery({
orgSlug: organization.slug,
query: {
project: selection.projects as unknown as string[],
environment: selection.environments,
...normalizeDateTimeParams(selectionDatetime ?? selection.datetime),
query: `${conditionQuery.trim()} ${queryWithFocusedSeries?.trim()}`,
},
});
}
if (aggregation && mri) {
return generateTracesRouteWithQuery({
orgSlug: organization.slug,
metric: {
max: selectionRange?.max,
min: selectionRange?.min,
op: aggregation,
query: queryWithFocusedSeries,
mri: mri,
},
query: {
project: selection.projects as unknown as string[],
environment: selection.environments,
...normalizeDateTimeParams(selectionDatetime ?? selection.datetime),
},
});
}
return '';
}, [
aggregation,
mri,
organization.slug,
queryWithFocusedSeries,
selection,
selectionRange,
condition,
getCondition,
]);
return (
{t('Span Samples')}
{t('Open in Traces')}
{organization.features.includes('metrics-samples-list-search') ? (
) : (
)}
);
}
const MetricSampleTableWrapper = HookOrDefault({
hookName: 'component:ddm-metrics-samples-list',
defaultComponent: ({children}) => {children},
});
const Heading = styled('h6')`
margin-bottom: ${space(0.5)};
`;
const TrayWrapper = styled('div')`
padding-top: ${space(4)};
display: grid;
grid-template-rows: auto auto 1fr;
`;
const ContentWrapper = styled('div')`
position: relative;
padding-top: ${space(1)};
`;
const OpenInTracesButton = styled(Button)``;
const TabsAndAction = styled('div')`
display: grid;
grid-template-columns: 1fr auto;
gap: ${space(4)};
align-items: end;
`;