import styled from '@emotion/styled'; import {Location} from 'history'; import {SectionHeading} from 'sentry/components/charts/styles'; import {DropdownMenu} from 'sentry/components/dropdownMenu'; import Panel from 'sentry/components/panels/panel'; import {IconEllipsis} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {Organization} from 'sentry/types'; import {Event} from 'sentry/types/event'; import EventView from 'sentry/utils/discover/eventView'; import { DURATION_UNITS, FIELD_FORMATTERS, PERCENTAGE_UNITS, SIZE_UNITS, } from 'sentry/utils/discover/fieldRenderers'; import {isCustomMeasurement} from 'sentry/views/dashboards/utils'; import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils'; export enum EventDetailPageSource { PERFORMANCE = 'performance', DISCOVER = 'discover', } type Props = { event: Event; location: Location; organization: Organization; isHomepage?: boolean; source?: EventDetailPageSource; }; function isNotMarkMeasurement(field: string) { return !field.startsWith('mark.'); } export default function EventCustomPerformanceMetrics({ event, location, organization, source, isHomepage, }: Props) { const measurementNames = Object.keys(event.measurements ?? {}) .filter(name => isCustomMeasurement(`measurements.${name}`)) .filter(isNotMarkMeasurement) .sort(); if (measurementNames.length === 0) { return null; } return ( {t('Custom Performance Metrics')} {measurementNames.map(name => { return ( ); })} ); } type EventCustomPerformanceMetricProps = Props & { name: string; }; export function getFieldTypeFromUnit(unit) { if (unit) { if (DURATION_UNITS[unit]) { return 'duration'; } if (SIZE_UNITS[unit]) { return 'size'; } if (PERCENTAGE_UNITS.includes(unit)) { return 'percentage'; } if (unit === 'none') { return 'integer'; } return 'string'; } return 'number'; } function EventCustomPerformanceMetric({ event, name, location, organization, source, isHomepage, }: EventCustomPerformanceMetricProps) { const {value, unit} = event.measurements?.[name] ?? {}; if (value === null) { return null; } const fieldType = getFieldTypeFromUnit(unit); const renderValue = fieldType === 'string' ? `${value} ${unit}` : value; const rendered = fieldType ? FIELD_FORMATTERS[fieldType].renderFunc( name, {[name]: renderValue}, {location, organization, unit} ) : renderValue; function generateLinkWithQuery(query: string) { const eventView = EventView.fromLocation(location); eventView.query = query; switch (source) { case EventDetailPageSource.PERFORMANCE: return transactionSummaryRouteWithQuery({ orgSlug: organization.slug, transaction: event.title, projectID: event.projectID, query: {query}, }); case EventDetailPageSource.DISCOVER: default: return eventView.getResultsViewUrlTarget(organization.slug, isHomepage); } } // Some custom perf metrics have units. // These custom perf metrics need to be adjusted to the correct value. let customMetricValue = value; if (typeof value === 'number' && unit && customMetricValue) { if (Object.keys(SIZE_UNITS).includes(unit)) { customMetricValue *= SIZE_UNITS[unit]; } else if (Object.keys(DURATION_UNITS).includes(unit)) { customMetricValue *= DURATION_UNITS[unit]; } } return (
{name}
{rendered}
${customMetricValue}`), }, { key: 'includeLessThanEvents', label: t('Show events with values less than'), to: generateLinkWithQuery(`measurements.${name}:<${customMetricValue}`), }, ]} triggerProps={{ 'aria-label': t('Widget actions'), size: 'xs', borderless: true, showChevron: false, icon: , }} position="bottom-end" />
); } const Measurements = styled('div')` display: grid; grid-column-gap: ${space(1)}; `; const Container = styled('div')` font-size: ${p => p.theme.fontSizeMedium}; margin-bottom: ${space(4)}; `; const StyledPanel = styled(Panel)` padding: ${space(1)} ${space(1.5)}; margin-bottom: ${space(1)}; display: flex; `; const ValueRow = styled('div')` display: flex; align-items: center; `; const Value = styled('span')` font-size: ${p => p.theme.fontSizeExtraLarge}; `; const StyledDropdownMenuControl = styled(DropdownMenu)` margin-left: auto; `;