breakdownBars.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import space from 'sentry/styles/space';
  4. import {formatPercentage} from 'sentry/utils/formatters';
  5. type Point = {
  6. label: string;
  7. value: number;
  8. onClick?: () => void;
  9. };
  10. type Props = {
  11. /**
  12. * The data to display. The caller should order the points
  13. * in the order they want bars displayed.
  14. */
  15. data: Point[];
  16. };
  17. function BreakdownBars({data}: Props) {
  18. const total = data.reduce((sum, point) => point.value + sum, 0);
  19. return (
  20. <BreakdownGrid>
  21. {data.map((point, i) => (
  22. <Fragment key={`${i}:${point.label}`}>
  23. <Percentage>{formatPercentage(point.value / total, 0)}</Percentage>
  24. <BarContainer
  25. data-test-id={`status-${point.label}`}
  26. cursor={point.onClick ? 'pointer' : 'default'}
  27. onClick={point.onClick}
  28. >
  29. <Bar style={{width: `${((point.value / total) * 100).toFixed(2)}%`}} />
  30. <Label>{point.label}</Label>
  31. </BarContainer>
  32. </Fragment>
  33. ))}
  34. </BreakdownGrid>
  35. );
  36. }
  37. export default BreakdownBars;
  38. const BreakdownGrid = styled('div')`
  39. display: grid;
  40. grid-template-columns: min-content auto;
  41. column-gap: ${space(1)};
  42. row-gap: ${space(1)};
  43. `;
  44. const Percentage = styled('div')`
  45. font-size: ${p => p.theme.fontSizeExtraLarge};
  46. text-align: right;
  47. `;
  48. const BarContainer = styled('div')<{cursor: 'pointer' | 'default'}>`
  49. padding-left: ${space(1)};
  50. padding-right: ${space(1)};
  51. position: relative;
  52. cursor: ${p => p.cursor};
  53. `;
  54. const Label = styled('span')`
  55. position: relative;
  56. color: ${p => p.theme.textColor};
  57. z-index: 2;
  58. font-size: ${p => p.theme.fontSizeSmall};
  59. `;
  60. const Bar = styled('div')`
  61. border-radius: 2px;
  62. background-color: ${p => p.theme.border};
  63. position: absolute;
  64. top: 0;
  65. left: 0;
  66. z-index: 1;
  67. height: 100%;
  68. width: 0%;
  69. `;