utils.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import type {Query} from 'history';
  2. import type {EventTag} from 'sentry/types/event';
  3. import {appendTagCondition} from 'sentry/utils/queryString';
  4. export function intcomma(x: number): string {
  5. return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
  6. }
  7. /**
  8. * Replaces slug special chars with a space
  9. */
  10. export function explodeSlug(slug: string): string {
  11. return slug.replace(/[-_]+/g, ' ').trim();
  12. }
  13. export function defined<T>(item: T): item is Exclude<T, null | undefined> {
  14. return item !== undefined && item !== null;
  15. }
  16. export function nl2br(str: string): string {
  17. return str.replace(/(?:\r\n|\r|\n)/g, '<br />');
  18. }
  19. export function escape(str: string): string {
  20. return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  21. }
  22. export function percent(value: number, totalValue: number): number {
  23. // prevent division by zero
  24. if (totalValue === 0) {
  25. return 0;
  26. }
  27. return (value / totalValue) * 100;
  28. }
  29. /**
  30. * Converts a multi-line textarea input value into an array,
  31. * eliminating empty lines
  32. */
  33. export function extractMultilineFields(value: string): string[] {
  34. return value
  35. .split('\n')
  36. .map(f => f.trim())
  37. .filter(f => f !== '');
  38. }
  39. /**
  40. * If the value is of type Array, converts it to type string, keeping the line breaks, if there is any
  41. */
  42. export function convertMultilineFieldValue<T extends string | string[]>(
  43. value: T
  44. ): string {
  45. if (Array.isArray(value)) {
  46. return value.join('\n');
  47. }
  48. if (typeof value === 'string') {
  49. return value.split('\n').join('\n');
  50. }
  51. return '';
  52. }
  53. // build actorIds
  54. export const buildUserId = (id: string) => `user:${id}`;
  55. export const buildTeamId = (id: string) => `team:${id}`;
  56. /**
  57. * Removes the organization / project scope prefix on feature names.
  58. */
  59. export function descopeFeatureName<T>(feature: T): T | string {
  60. if (typeof feature !== 'string') {
  61. return feature;
  62. }
  63. const results = feature.match(/(?:^(?:projects|organizations):)?(.*)/);
  64. if (results && results.length > 0) {
  65. return results.pop()!;
  66. }
  67. return feature;
  68. }
  69. export function isWebpackChunkLoadingError(error: Error): boolean {
  70. return (
  71. error &&
  72. typeof error.message === 'string' &&
  73. error.message.toLowerCase().includes('loading chunk')
  74. );
  75. }
  76. export function generateQueryWithTag(prevQuery: Query, tag: EventTag): Query {
  77. const query = {...prevQuery};
  78. // some tags are dedicated query strings since other parts of the app consumes this,
  79. // for example, the global selection header.
  80. switch (tag.key) {
  81. case 'environment':
  82. query.environment = tag.value;
  83. break;
  84. case 'project':
  85. query.project = tag.value;
  86. break;
  87. default:
  88. query.query = appendTagCondition(query.query, tag.key, tag.value);
  89. }
  90. return query;
  91. }
  92. // NOTE: only escapes a " if it's not already escaped
  93. export function escapeDoubleQuotes(str: string) {
  94. return str.replace(/\\([\s\S])|(")/g, '\\$1$2');
  95. }
  96. export function generateOrgSlugUrl(orgSlug) {
  97. const sentryDomain = window.__initialData.links.sentryUrl.split('/')[2];
  98. return `${window.location.protocol}//${orgSlug}.${sentryDomain}${window.location.pathname}`;
  99. }