webVitalDescription.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import {useTheme} from '@emotion/react';
  2. import styled from '@emotion/styled';
  3. import ProgressRing from 'sentry/components/progressRing';
  4. import {IconCheckmark} from 'sentry/icons/iconCheckmark';
  5. import {IconClose} from 'sentry/icons/iconClose';
  6. import {t} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import {WebVital} from 'sentry/utils/fields';
  9. import {Browser} from 'sentry/utils/performance/vitals/constants';
  10. import {getScoreColor} from 'sentry/views/performance/browser/webVitals/utils/getScoreColor';
  11. import {WebVitals} from 'sentry/views/performance/browser/webVitals/utils/types';
  12. import {
  13. vitalDescription,
  14. vitalSupportedBrowsers,
  15. } from 'sentry/views/performance/vitalDetail/utils';
  16. type Props = {
  17. score: number;
  18. value: string;
  19. webVital: WebVitals;
  20. };
  21. const webVitalFullNameMap = {
  22. cls: t('Cumulative Layout Shift'),
  23. fcp: t('First Contentful Paint'),
  24. fid: t('First Input Delay'),
  25. lcp: t('Largest Contentful Paint'),
  26. ttfb: t('Time to First Byte'),
  27. };
  28. export function WebVitalDescription({score, value, webVital}: Props) {
  29. const theme = useTheme();
  30. return (
  31. <div>
  32. <Header>
  33. <span>
  34. <WebVitalName>{`${webVitalFullNameMap[webVital]} (P75)`}</WebVitalName>
  35. <Value>{value}</Value>
  36. </span>
  37. <ProgressRing
  38. value={score}
  39. size={100}
  40. barWidth={16}
  41. text={
  42. <ProgressRingTextContainer>
  43. <ProgressRingText>{score}</ProgressRingText>
  44. <ProgressRingSubText>{webVital.toUpperCase()}</ProgressRingSubText>
  45. </ProgressRingTextContainer>
  46. }
  47. progressColor={getScoreColor(score, theme)}
  48. backgroundColor={`${getScoreColor(score, theme)}33`}
  49. />
  50. </Header>
  51. <p>{vitalDescription[WebVital[webVital.toUpperCase()]]}</p>
  52. <SupportedBrowsers>
  53. {Object.values(Browser).map(browser => (
  54. <BrowserItem key={browser}>
  55. {vitalSupportedBrowsers[WebVital[webVital.toUpperCase()]]?.includes(
  56. browser
  57. ) ? (
  58. <IconCheckmark color="successText" size="sm" />
  59. ) : (
  60. <IconClose color="dangerText" size="sm" />
  61. )}
  62. {browser}
  63. </BrowserItem>
  64. ))}
  65. </SupportedBrowsers>
  66. </div>
  67. );
  68. }
  69. const SupportedBrowsers = styled('div')`
  70. display: inline-flex;
  71. gap: ${space(2)};
  72. margin-bottom: ${space(3)};
  73. `;
  74. const BrowserItem = styled('div')`
  75. display: flex;
  76. align-items: center;
  77. gap: ${space(1)};
  78. `;
  79. const Header = styled('span')`
  80. display: flex;
  81. justify-content: space-between;
  82. margin-bottom: ${space(3)};
  83. `;
  84. const Value = styled('h2')`
  85. font-weight: normal;
  86. margin-bottom: ${space(1)};
  87. `;
  88. const WebVitalName = styled('h4')`
  89. margin-bottom: ${space(1)};
  90. margin-top: 40px;
  91. `;
  92. const ProgressRingTextContainer = styled('div')`
  93. display: flex;
  94. flex-direction: column;
  95. align-items: center;
  96. justify-content: center;
  97. `;
  98. const ProgressRingText = styled('h4')`
  99. color: ${p => p.theme.textColor};
  100. margin: ${space(2)} 0 0 0;
  101. `;
  102. const ProgressRingSubText = styled('h5')`
  103. font-size: ${p => p.theme.fontSizeSmall};
  104. color: ${p => p.theme.textColor};
  105. `;