utils.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import type {Location} from 'history';
  2. import * as qs from 'query-string';
  3. import {t} from 'sentry/locale';
  4. import type {PageFilters} from 'sentry/types/core';
  5. import type {Series} from 'sentry/types/echarts';
  6. import type {Confidence, Organization} from 'sentry/types/organization';
  7. import type {Project} from 'sentry/types/project';
  8. import {defined} from 'sentry/utils';
  9. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  10. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  11. import normalizeUrl from 'sentry/utils/url/normalizeUrl';
  12. import {newExploreTarget} from 'sentry/views/explore/contexts/pageParamsContext';
  13. import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
  14. import type {Visualize} from 'sentry/views/explore/contexts/pageParamsContext/visualizes';
  15. export function getExploreUrl({
  16. orgSlug,
  17. selection,
  18. interval,
  19. mode,
  20. visualize,
  21. query,
  22. groupBy,
  23. sort,
  24. field,
  25. }: {
  26. interval: string;
  27. orgSlug: string;
  28. selection: PageFilters;
  29. visualize: Array<Omit<Visualize, 'label'>>;
  30. field?: string[];
  31. groupBy?: string[];
  32. mode?: Mode;
  33. query?: string;
  34. sort?: string;
  35. }) {
  36. const {start, end, period: statsPeriod, utc} = selection.datetime;
  37. const {environments, projects} = selection;
  38. const queryParams = {
  39. dataset: DiscoverDatasets.SPANS_EAP_RPC,
  40. project: projects,
  41. environment: environments,
  42. statsPeriod,
  43. start,
  44. end,
  45. interval,
  46. mode,
  47. query,
  48. visualize: visualize.map(v => JSON.stringify(v)),
  49. groupBy,
  50. sort,
  51. field,
  52. utc,
  53. };
  54. return normalizeUrl(
  55. `/organizations/${orgSlug}/traces/?${qs.stringify(queryParams, {skipNull: true})}`
  56. );
  57. }
  58. export function combineConfidenceForSeries(series: Series[]): Confidence {
  59. let lows = 0;
  60. let highs = 0;
  61. let nulls = 0;
  62. for (const s of series) {
  63. if (s.confidence === 'low') {
  64. lows += 1;
  65. } else if (s.confidence === 'high') {
  66. highs += 1;
  67. } else {
  68. nulls += 1;
  69. }
  70. }
  71. if (lows <= 0 && highs <= 0 && nulls >= 0) {
  72. return null;
  73. }
  74. if (lows / (lows + highs) > 0.5) {
  75. return 'low';
  76. }
  77. return 'high';
  78. }
  79. export function viewSamplesTarget(
  80. location: Location,
  81. query: string,
  82. groupBys: string[],
  83. row: Record<string, any>,
  84. extras: {
  85. // needed to generate targets when `project` is in the group by
  86. projects: Project[];
  87. }
  88. ) {
  89. const search = new MutableSearch(query);
  90. for (const groupBy of groupBys) {
  91. const value = row[groupBy];
  92. if (groupBy === 'project' && typeof value === 'string') {
  93. const project = extras.projects.find(p => p.slug === value);
  94. if (defined(project)) {
  95. location.query.project = project.id;
  96. }
  97. } else if (groupBy === 'project.id' && typeof value === 'number') {
  98. location.query.project = String(value);
  99. } else if (groupBy === 'environment' && typeof value === 'string') {
  100. location.query.environment = value;
  101. } else if (typeof value === 'string') {
  102. search.setFilterValues(groupBy, [value]);
  103. }
  104. }
  105. return newExploreTarget(location, {
  106. mode: Mode.SAMPLES,
  107. query: search.formatString(),
  108. });
  109. }
  110. export type MaxPickableDays = 7 | 14 | 30;
  111. export type DefaultPeriod = '7d' | '14d' | '30d';
  112. export function limitMaxPickableDays(organization: Organization): {
  113. defaultPeriod: DefaultPeriod;
  114. maxPickableDays: MaxPickableDays;
  115. relativeOptions: Record<string, React.ReactNode>;
  116. } {
  117. const defaultPeriods: Record<MaxPickableDays, DefaultPeriod> = {
  118. 7: '7d',
  119. 14: '14d',
  120. 30: '30d',
  121. };
  122. const relativeOptions: Array<[DefaultPeriod, React.ReactNode]> = [
  123. ['7d', t('Last 7 days')],
  124. ['14d', t('Last 14 days')],
  125. ['30d', t('Last 30 days')],
  126. ];
  127. const maxPickableDays: MaxPickableDays = organization.features.includes(
  128. 'visibility-explore-range-high'
  129. )
  130. ? 30
  131. : organization.features.includes('visibility-explore-range-medium')
  132. ? 14
  133. : 7;
  134. const defaultPeriod: DefaultPeriod = defaultPeriods[maxPickableDays];
  135. const index = relativeOptions.findIndex(([period, _]) => period === defaultPeriod) + 1;
  136. const enabledOptions = relativeOptions.slice(0, index);
  137. return {
  138. defaultPeriod,
  139. maxPickableDays,
  140. relativeOptions: {
  141. '1h': t('Last hour'),
  142. '24h': t('Last 24 hours'),
  143. ...Object.fromEntries(enabledOptions),
  144. },
  145. };
  146. }