userMisery.tsx 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import ScoreBar from 'sentry/components/scoreBar';
  2. import Tooltip from 'sentry/components/tooltip';
  3. import CHART_PALETTE from 'sentry/constants/chartPalette';
  4. import {tct} from 'sentry/locale';
  5. import {defined} from 'sentry/utils';
  6. type Props = {
  7. barHeight: number;
  8. bars: number;
  9. miserableUsers: number | undefined;
  10. miseryLimit: number | undefined;
  11. totalUsers: number | undefined;
  12. userMisery: number;
  13. };
  14. function UserMisery(props: Props) {
  15. const {bars, barHeight, userMisery, miseryLimit, totalUsers, miserableUsers} = props;
  16. // User Misery will always be > 0 because of the maximum a posteriori estimate
  17. // and below 5% will always be an overestimation of the actual proportion
  18. // of miserable to total unique users. We are going to visualize it as
  19. // 0 User Misery while still preserving the actual value for sorting purposes.
  20. const adjustedMisery = userMisery > 0.05 ? userMisery : 0;
  21. const palette = new Array(bars).fill([CHART_PALETTE[0][0]]);
  22. const score = Math.round(adjustedMisery * palette.length);
  23. let title: React.ReactNode;
  24. if (defined(miserableUsers) && defined(totalUsers) && defined(miseryLimit)) {
  25. title = tct(
  26. '[miserableUsers] out of [totalUsers] unique users waited more than [duration]ms (4x the response time threshold)',
  27. {
  28. miserableUsers,
  29. totalUsers,
  30. duration: 4 * miseryLimit,
  31. }
  32. );
  33. } else if (defined(miseryLimit)) {
  34. title = tct(
  35. 'User Misery score is [userMisery], representing users who waited more than [duration]ms (4x the response time threshold)',
  36. {
  37. duration: 4 * miseryLimit,
  38. userMisery: userMisery.toFixed(3),
  39. }
  40. );
  41. } else if (defined(miserableUsers) && defined(totalUsers)) {
  42. title = tct(
  43. 'User Misery score is [userMisery], because [miserableUsers] out of [totalUsers] unique users had a miserable experience.',
  44. {
  45. miserableUsers,
  46. totalUsers,
  47. userMisery: userMisery.toFixed(3),
  48. }
  49. );
  50. } else {
  51. title = tct('User Misery score is [userMisery].', {
  52. userMisery: userMisery.toFixed(3),
  53. });
  54. }
  55. return (
  56. <Tooltip title={title} containerDisplayMode="block">
  57. <ScoreBar size={barHeight} score={score} palette={palette} radius={0} />
  58. </Tooltip>
  59. );
  60. }
  61. export default UserMisery;