meterBar.tsx 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import {ReactNode} from 'react';
  2. import {useTheme} from '@emotion/react';
  3. import styled from '@emotion/styled';
  4. import {space} from 'sentry/styles/space';
  5. import {getDuration} from 'sentry/utils/formatters';
  6. export function MeterBar({
  7. minWidth,
  8. meterItems,
  9. row,
  10. total,
  11. meterText,
  12. }: {
  13. meterItems: string[];
  14. minWidth: number;
  15. row: any;
  16. total: number;
  17. meterText?: ReactNode;
  18. }) {
  19. const theme = useTheme();
  20. const widths: number[] = [];
  21. meterItems.reduce((acc, item, index) => {
  22. const width = Math.max(
  23. Math.min(
  24. (100 * row[item]) / total - acc,
  25. 100 - acc - minWidth * (meterItems.length - index)
  26. ),
  27. minWidth
  28. );
  29. widths.push(width);
  30. return acc + width;
  31. }, 0);
  32. const color =
  33. widths[0] > 90 ? theme.green300 : widths[0] > 50 ? theme.yellow300 : theme.red300;
  34. return (
  35. <span>
  36. <MeterText>
  37. {meterText ?? `${getDuration(row[meterItems[0]] / 1000, 0, true, true)}`}
  38. </MeterText>
  39. <MeterContainer width={100}>
  40. <Meter width={widths[0]} color={color} />
  41. </MeterContainer>
  42. </span>
  43. );
  44. }
  45. const MeterContainer = styled('span')<{width: number}>`
  46. display: flex;
  47. width: ${p => p.width}%;
  48. height: ${space(1)};
  49. background-color: ${p => p.theme.gray100};
  50. margin-bottom: 4px;
  51. `;
  52. const Meter = styled('span')<{
  53. color: string;
  54. width: number;
  55. }>`
  56. display: block;
  57. width: ${p => p.width}%;
  58. height: 100%;
  59. background-color: ${p => p.color};
  60. `;
  61. const MeterText = styled('span')`
  62. font-size: ${p => p.theme.fontSizeExtraSmall};
  63. color: ${p => p.theme.gray300};
  64. white-space: nowrap;
  65. `;