utils.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import {t, tct} from 'sentry/locale';
  2. import {
  3. SamplingConditionLogicalInner,
  4. SamplingInnerName,
  5. SamplingInnerOperator,
  6. SamplingRule,
  7. } from 'sentry/types/sampling';
  8. import {getInnerNameLabel} from '../../utils';
  9. import {Conditions} from './conditions';
  10. import {TruncatedLabel} from './truncatedLabel';
  11. type Condition = React.ComponentProps<typeof Conditions>['conditions'][0];
  12. export function getMatchFieldPlaceholder(category: SamplingInnerName) {
  13. switch (category) {
  14. case SamplingInnerName.TRACE_ENVIRONMENT:
  15. return t('ex. prod, dev');
  16. case SamplingInnerName.TRACE_RELEASE:
  17. return t('ex. 1*, [I3].[0-9].*');
  18. default:
  19. return undefined;
  20. }
  21. }
  22. export function getNewCondition(condition: Condition): SamplingConditionLogicalInner {
  23. const newValue = (condition.match ?? '')
  24. .split('\n')
  25. .filter(match => !!match.trim())
  26. .map(match => match.trim());
  27. if (condition.category === SamplingInnerName.TRACE_RELEASE) {
  28. return {
  29. op: SamplingInnerOperator.GLOB_MATCH,
  30. name: condition.category,
  31. value: newValue,
  32. };
  33. }
  34. return {
  35. op: SamplingInnerOperator.EQUAL,
  36. name: condition.category,
  37. value: newValue,
  38. options: {
  39. ignoreCase: true,
  40. },
  41. };
  42. }
  43. const unexpectedErrorMessage = t('An internal error occurred while saving sampling rule');
  44. type ResponseJSONDetailed = {
  45. detail: string[];
  46. };
  47. type ResponseJSON = {
  48. dynamicSampling?: {
  49. rules: Array<Partial<SamplingRule>>;
  50. };
  51. };
  52. export function getErrorMessage(
  53. error: {
  54. responseJSON?: ResponseJSON | ResponseJSONDetailed;
  55. },
  56. currentRuleIndex: number
  57. ) {
  58. const detailedErrorResponse = (error.responseJSON as undefined | ResponseJSONDetailed)
  59. ?.detail;
  60. if (detailedErrorResponse) {
  61. // This is a temp solution until we enable error rules again, therefore it does not need translation
  62. return detailedErrorResponse[0];
  63. }
  64. const errorResponse = error.responseJSON as undefined | ResponseJSON;
  65. if (!errorResponse) {
  66. return unexpectedErrorMessage;
  67. }
  68. const responseErrors = errorResponse.dynamicSampling?.rules[currentRuleIndex] ?? {};
  69. const [type, _value] = Object.entries(responseErrors)[0];
  70. if (type === 'sampleRate') {
  71. return {
  72. type: 'sampleRate',
  73. message: t('Ensure this value is a floating number between 0 and 100'),
  74. };
  75. }
  76. return unexpectedErrorMessage;
  77. }
  78. export function getTagKey(condition: Condition) {
  79. switch (condition.category) {
  80. case SamplingInnerName.TRACE_RELEASE:
  81. return 'release';
  82. case SamplingInnerName.TRACE_ENVIRONMENT:
  83. return 'environment';
  84. default:
  85. return undefined;
  86. }
  87. }
  88. export const distributedTracesConditions = [
  89. SamplingInnerName.TRACE_RELEASE,
  90. SamplingInnerName.TRACE_ENVIRONMENT,
  91. ];
  92. export function generateConditionCategoriesOptions(
  93. conditionCategories: SamplingInnerName[]
  94. ): [SamplingInnerName, string][] {
  95. const sortedConditionCategories = conditionCategories
  96. // sort dropdown options alphabetically based on display labels
  97. .sort((a, b) => getInnerNameLabel(a).localeCompare(getInnerNameLabel(b)));
  98. // massage into format that select component understands
  99. return sortedConditionCategories.map(innerName => [
  100. innerName,
  101. getInnerNameLabel(innerName),
  102. ]);
  103. }
  104. export function formatCreateTagLabel(label: string) {
  105. return tct('Add "[newLabel]"', {
  106. newLabel: <TruncatedLabel value={label} />,
  107. });
  108. }