import styled from '@emotion/styled'; import {Tooltip} from 'sentry/components/tooltip'; import {IconFile} from 'sentry/icons'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {getDuration} from 'sentry/utils/formatters'; import {useResourcesQuery} from 'sentry/views/performance/browser/resources/utils/useResourcesQuery'; import type {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types'; import {SpanMetricsField} from 'sentry/views/starfish/types'; export function Recommendations({ transaction, webVital, }: { transaction: string; webVital: WebVitals; }) { switch (webVital) { case 'lcp': return null; case 'fid': return null; case 'cls': return null; case 'fcp': return ; case 'ttfb': return null; default: return null; } } function FcpRecommendations({transaction}: {transaction: string}) { const query = `transaction:"${transaction}" resource.render_blocking_status:blocking`; const {data, isLoading} = useResourcesQuery({ query, sort: {field: `avg(${SpanMetricsField.SPAN_SELF_TIME})`, kind: 'desc'}, defaultResourceTypes: ['resource.script', 'resource.css', 'resource.img'], limit: 7, referrer: 'api.performance.browser.web-vitals.fcp-recommendations', }); if (isLoading || !data || data.length < 1) { return null; } return (
    {t('Eliminate render blocking resources')} {data.map( ({ 'span.op': op, 'span.description': description, 'avg(span.self_time)': duration, }) => { return ( {description} {getFormattedDuration(duration)} ); } )}
); } function RecommendationsHeader() { return ( {t('Recommendations')} ); } function ResourceType({resourceType}: {resourceType: `resource.${string}`}) { switch (resourceType) { case 'resource.script': return ( {t('js')} {' \u2014 '} ); case 'resource.css': return ( {t('css')} {' \u2014 '} ); case 'resource.img': return ( {t('img')} {' \u2014 '} ); default: return null; } } const getFormattedDuration = (value: number | null) => { if (value === null) { return null; } if (value < 1000) { return getDuration(value / 1000, 0, true); } return getDuration(value / 1000, 2, true); }; const StyledIconFile = styled(IconFile)` margin-right: ${space(0.5)}; `; const RecommendationSubHeader = styled('li')` margin-bottom: ${space(1)}; `; const RecommendationsHeaderContainer = styled('div')` margin-bottom: ${space(1)}; font-size: ${p => p.theme.fontSizeExtraLarge}; `; const ResourceList = styled('ul')` padding-left: ${space(1)}; `; const ResourceListItem = styled('li')` margin-bottom: ${space(0.5)}; list-style: none; white-space: nowrap; `; const ResourceDescription = styled('span')` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `; const Flex = styled('span')` display: flex; justify-content: space-between; gap: ${space(1)}; `; const RecommendationsContainer = styled('div')` margin-bottom: ${space(4)}; `; const StyledTooltip = styled(Tooltip)` overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `;