utils.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import {DateTimeObject, getSeriesApiInterval} from 'sentry/components/charts/utils';
  2. import {DataCategory} from 'sentry/types';
  3. import {formatBytesBase10} from 'sentry/utils';
  4. import {parsePeriodToHours} from 'sentry/utils/dates';
  5. export const MILLION = 10 ** 6;
  6. export const BILLION = 10 ** 9;
  7. export const GIGABYTE = 10 ** 9;
  8. type FormatOptions = {
  9. /**
  10. * Truncate 1234 => 1.2k or 1,234,000 to 1.23M
  11. */
  12. isAbbreviated?: boolean;
  13. /**
  14. * Convert attachments to use the most appropriate unit KB/MB/GB/TB/etc.
  15. * Otherwise, it will default to GB
  16. */
  17. useUnitScaling?: boolean;
  18. };
  19. /**
  20. * This expects usage values/quantities for the data categories that we sell.
  21. *
  22. * Note: usageQuantity for Attachments should be in BYTES
  23. */
  24. export function formatUsageWithUnits(
  25. usageQuantity: number = 0,
  26. dataCategory: DataCategory,
  27. options: FormatOptions = {isAbbreviated: false, useUnitScaling: false}
  28. ) {
  29. if (dataCategory !== DataCategory.ATTACHMENTS) {
  30. return options.isAbbreviated
  31. ? abbreviateUsageNumber(usageQuantity)
  32. : usageQuantity.toLocaleString();
  33. }
  34. if (options.useUnitScaling) {
  35. return formatBytesBase10(usageQuantity);
  36. }
  37. const usageGb = usageQuantity / GIGABYTE;
  38. return options.isAbbreviated
  39. ? `${abbreviateUsageNumber(usageGb)} GB`
  40. : `${usageGb.toLocaleString(undefined, {maximumFractionDigits: 2})} GB`;
  41. }
  42. /**
  43. * Good default for "formatUsageWithUnits"
  44. */
  45. export function getFormatUsageOptions(dataCategory: DataCategory): FormatOptions {
  46. return {
  47. isAbbreviated: dataCategory !== DataCategory.ATTACHMENTS,
  48. useUnitScaling: dataCategory === DataCategory.ATTACHMENTS,
  49. };
  50. }
  51. /**
  52. * Instead of using this function directly, use formatReservedWithUnits or
  53. * formatUsageWithUnits with options.isAbbreviated to true instead.
  54. *
  55. * This function display different precision for billion/million/thousand to
  56. * provide clarity on usage of errors/transactions/attachments to the user.
  57. *
  58. * If you are not displaying usage numbers, it might be better to use
  59. * `formatAbbreviatedNumber` in 'sentry/utils/formatters'
  60. */
  61. export function abbreviateUsageNumber(n: number) {
  62. if (n >= BILLION) {
  63. return (n / BILLION).toLocaleString(undefined, {maximumFractionDigits: 2}) + 'B';
  64. }
  65. if (n >= MILLION) {
  66. return (n / MILLION).toLocaleString(undefined, {maximumFractionDigits: 1}) + 'M';
  67. }
  68. if (n >= 1000) {
  69. return (n / 1000).toFixed().toLocaleString() + 'K';
  70. }
  71. // Do not show decimals
  72. return n.toFixed().toLocaleString();
  73. }
  74. /**
  75. * We want to display datetime in UTC in the following situations:
  76. *
  77. * 1) The user selected an absolute date range with UTC
  78. * 2) The user selected a wide date range with 1d interval
  79. *
  80. * When the interval is 1d, we need to use UTC because the 24 hour range might
  81. * shift forward/backward depending on the user's timezone, or it might be
  82. * displayed as a day earlier/later
  83. */
  84. export function isDisplayUtc(datetime: DateTimeObject): boolean {
  85. if (datetime.utc) {
  86. return true;
  87. }
  88. const interval = getSeriesApiInterval(datetime);
  89. const hours = parsePeriodToHours(interval);
  90. return hours >= 24;
  91. }