utils.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 {Confidence, Organization} from 'sentry/types/organization';
  6. import type {Project} from 'sentry/types/project';
  7. import {defined} from 'sentry/utils';
  8. import {DiscoverDatasets} from 'sentry/utils/discover/types';
  9. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  10. import {newExploreTarget} from 'sentry/views/explore/contexts/pageParamsContext';
  11. import {Mode} from 'sentry/views/explore/contexts/pageParamsContext/mode';
  12. import type {Visualize} from 'sentry/views/explore/contexts/pageParamsContext/visualizes';
  13. import {makeTracesPathname} from 'sentry/views/traces/pathnames';
  14. import type {TimeSeries} from '../dashboards/widgets/common/types';
  15. export function getExploreUrl({
  16. organization,
  17. selection,
  18. interval,
  19. mode,
  20. visualize,
  21. query,
  22. groupBy,
  23. sort,
  24. field,
  25. }: {
  26. interval: string;
  27. organization: Organization;
  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 (
  55. makeTracesPathname({
  56. organization,
  57. path: '/',
  58. }) + `?${qs.stringify(queryParams, {skipNull: true})}`
  59. );
  60. }
  61. export function combineConfidenceForSeries(
  62. series: Array<Pick<TimeSeries, 'confidence'>>
  63. ): Confidence {
  64. let lows = 0;
  65. let highs = 0;
  66. let nulls = 0;
  67. for (const s of series) {
  68. if (s.confidence === 'low') {
  69. lows += 1;
  70. } else if (s.confidence === 'high') {
  71. highs += 1;
  72. } else {
  73. nulls += 1;
  74. }
  75. }
  76. if (lows <= 0 && highs <= 0 && nulls >= 0) {
  77. return null;
  78. }
  79. if (lows / (lows + highs) > 0.5) {
  80. return 'low';
  81. }
  82. return 'high';
  83. }
  84. export function viewSamplesTarget(
  85. location: Location,
  86. query: string,
  87. groupBys: string[],
  88. row: Record<string, any>,
  89. extras: {
  90. // needed to generate targets when `project` is in the group by
  91. projects: Project[];
  92. }
  93. ) {
  94. const search = new MutableSearch(query);
  95. for (const groupBy of groupBys) {
  96. const value = row[groupBy];
  97. if (groupBy === 'project' && typeof value === 'string') {
  98. const project = extras.projects.find(p => p.slug === value);
  99. if (defined(project)) {
  100. location.query.project = project.id;
  101. }
  102. } else if (groupBy === 'project.id' && typeof value === 'number') {
  103. location.query.project = String(value);
  104. } else if (groupBy === 'environment' && typeof value === 'string') {
  105. location.query.environment = value;
  106. } else if (typeof value === 'string') {
  107. search.setFilterValues(groupBy, [value]);
  108. }
  109. }
  110. return newExploreTarget(location, {
  111. mode: Mode.SAMPLES,
  112. query: search.formatString(),
  113. });
  114. }
  115. export type MaxPickableDays = 7 | 14 | 30;
  116. export type DefaultPeriod = '7d' | '14d' | '30d';
  117. export function limitMaxPickableDays(organization: Organization): {
  118. defaultPeriod: DefaultPeriod;
  119. maxPickableDays: MaxPickableDays;
  120. relativeOptions: Record<string, React.ReactNode>;
  121. } {
  122. const defaultPeriods: Record<MaxPickableDays, DefaultPeriod> = {
  123. 7: '7d',
  124. 14: '14d',
  125. 30: '30d',
  126. };
  127. const relativeOptions: Array<[DefaultPeriod, React.ReactNode]> = [
  128. ['7d', t('Last 7 days')],
  129. ['14d', t('Last 14 days')],
  130. ['30d', t('Last 30 days')],
  131. ];
  132. const maxPickableDays: MaxPickableDays = organization.features.includes(
  133. 'visibility-explore-range-high'
  134. )
  135. ? 30
  136. : organization.features.includes('visibility-explore-range-medium')
  137. ? 14
  138. : 7;
  139. const defaultPeriod: DefaultPeriod = defaultPeriods[maxPickableDays];
  140. const index = relativeOptions.findIndex(([period, _]) => period === defaultPeriod) + 1;
  141. const enabledOptions = relativeOptions.slice(0, index);
  142. return {
  143. defaultPeriod,
  144. maxPickableDays,
  145. relativeOptions: {
  146. '1h': t('Last hour'),
  147. '24h': t('Last 24 hours'),
  148. ...Object.fromEntries(enabledOptions),
  149. },
  150. };
  151. }
  152. export function showConfidence(isSampled: boolean | null | undefined) {
  153. if (defined(isSampled) && isSampled === false) {
  154. return false;
  155. }
  156. return true;
  157. }