codecovLegend.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import {useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import {IconCircle, IconCircleFill} from 'sentry/icons';
  4. import {t} from 'sentry/locale';
  5. import {space} from 'sentry/styles/space';
  6. import {Event, Frame, Organization} from 'sentry/types';
  7. import {CodecovStatusCode} from 'sentry/types/integrations';
  8. import {defined} from 'sentry/utils';
  9. import useProjects from 'sentry/utils/useProjects';
  10. import useStacktraceLink from './useStacktraceLink';
  11. interface CodecovLegendProps {
  12. event: Event;
  13. frame: Frame;
  14. organization?: Organization;
  15. }
  16. export function CodecovLegend({event, frame, organization}: CodecovLegendProps) {
  17. const {projects} = useProjects();
  18. const project = useMemo(
  19. () => projects.find(p => p.id === event.projectID),
  20. [projects, event]
  21. );
  22. const {data, isLoading} = useStacktraceLink(
  23. {
  24. event,
  25. frame,
  26. orgSlug: organization?.slug || '',
  27. projectSlug: project?.slug,
  28. },
  29. {enabled: defined(project) && defined(organization)}
  30. );
  31. if (isLoading || !data || !data.codecov) {
  32. return null;
  33. }
  34. if (
  35. data.codecov.status !== CodecovStatusCode.COVERAGE_EXISTS ||
  36. data.config?.provider.key !== 'github'
  37. ) {
  38. return null;
  39. }
  40. return (
  41. <CodeCovLegendContainer>
  42. <LegendIcon>
  43. <IconCircleFill size="xs" color="green100" style={{position: 'absolute'}} />
  44. <IconCircle size="xs" color="green300" />
  45. </LegendIcon>
  46. <LegendLabel>{t('Covered')}</LegendLabel>
  47. <LegendIcon>
  48. <IconCircleFill size="xs" color="red100" style={{position: 'absolute'}} />
  49. <IconCircle size="xs" color="red300" />
  50. </LegendIcon>
  51. <LegendLabel>{t('Uncovered')}</LegendLabel>
  52. <LegendIcon>
  53. <IconCircleFill size="xs" color="yellow100" style={{position: 'absolute'}} />
  54. <IconCircle size="xs" color="yellow300" />
  55. </LegendIcon>
  56. <LegendLabel>{t('Partial')}</LegendLabel>
  57. </CodeCovLegendContainer>
  58. );
  59. }
  60. const LegendLabel = styled('span')`
  61. line-height: 0;
  62. padding-right: 4px;
  63. `;
  64. const LegendIcon = styled('span')`
  65. display: flex;
  66. gap: ${space(0.75)};
  67. `;
  68. const CodeCovLegendContainer = styled('div')`
  69. gap: ${space(1)};
  70. color: ${p => p.theme.subText};
  71. font-family: ${p => p.theme.text.family};
  72. border-bottom: 1px solid ${p => p.theme.border};
  73. padding: ${space(0.25)} ${space(3)};
  74. box-shadow: ${p => p.theme.dropShadowLight};
  75. display: flex;
  76. justify-content: end;
  77. flex-direction: row;
  78. align-items: center;
  79. min-height: 28px;
  80. `;