events.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import {LocationDescriptor} from 'history';
  2. import pick from 'lodash/pick';
  3. import {Client} from 'app/api';
  4. import {canIncludePreviousPeriod} from 'app/components/charts/utils';
  5. import {
  6. DateString,
  7. EventsStats,
  8. MultiSeriesEventsStats,
  9. OrganizationSummary,
  10. } from 'app/types';
  11. import {LocationQuery} from 'app/utils/discover/eventView';
  12. import {getPeriod} from 'app/utils/getPeriod';
  13. import {PERFORMANCE_URL_PARAM} from 'app/utils/performance/constants';
  14. type Options = {
  15. organization: OrganizationSummary;
  16. project?: Readonly<number[]>;
  17. environment?: Readonly<string[]>;
  18. team?: Readonly<string | string[]>;
  19. period?: string;
  20. start?: DateString;
  21. end?: DateString;
  22. interval?: string;
  23. includePrevious?: boolean;
  24. limit?: number;
  25. query?: string;
  26. yAxis?: string | string[];
  27. field?: string[];
  28. topEvents?: number;
  29. orderby?: string;
  30. partial: boolean;
  31. withoutZerofill?: boolean;
  32. };
  33. /**
  34. * Make requests to `events-stats` endpoint
  35. *
  36. * @param {Object} api API client instance
  37. * @param {Object} options Request parameters
  38. * @param {Object} options.organization Organization object
  39. * @param {Number[]} options.project List of project ids
  40. * @param {String[]} options.environment List of environments to query for
  41. * @param {String[]} options.team List of teams to query for
  42. * @param {String} options.period Time period to query for, in the format: <integer><units> where units are "d" or "h"
  43. * @param {String} options.interval Time interval to group results in, in the format: <integer><units> where units are "d", "h", "m", "s"
  44. * @param {Boolean} options.includePrevious Should request also return reqsults for previous period?
  45. * @param {Number} options.limit The number of rows to return
  46. * @param {String} options.query Search query
  47. */
  48. export const doEventsRequest = (
  49. api: Client,
  50. {
  51. organization,
  52. project,
  53. environment,
  54. team,
  55. period,
  56. start,
  57. end,
  58. interval,
  59. includePrevious,
  60. query,
  61. yAxis,
  62. field,
  63. topEvents,
  64. orderby,
  65. partial,
  66. withoutZerofill,
  67. }: Options
  68. ): Promise<EventsStats | MultiSeriesEventsStats> => {
  69. const shouldDoublePeriod = canIncludePreviousPeriod(includePrevious, period);
  70. const urlQuery = Object.fromEntries(
  71. Object.entries({
  72. interval,
  73. project,
  74. environment,
  75. team,
  76. query,
  77. yAxis,
  78. field,
  79. topEvents,
  80. orderby,
  81. partial: partial ? '1' : undefined,
  82. withoutZerofill: withoutZerofill ? '1' : undefined,
  83. }).filter(([, value]) => typeof value !== 'undefined')
  84. );
  85. // Doubling period for absolute dates is not accurate unless starting and
  86. // ending times are the same (at least for daily intervals). This is
  87. // the tradeoff for now.
  88. const periodObj = getPeriod({period, start, end}, {shouldDoublePeriod});
  89. return api.requestPromise(`/organizations/${organization.slug}/events-stats/`, {
  90. query: {
  91. ...urlQuery,
  92. ...periodObj,
  93. },
  94. });
  95. };
  96. export type EventQuery = {
  97. field: string[];
  98. equation?: string[];
  99. team?: string | string[];
  100. project?: string | string[];
  101. sort?: string | string[];
  102. query: string;
  103. per_page?: number;
  104. referrer?: string;
  105. environment?: string[];
  106. noPagination?: boolean;
  107. };
  108. export type TagSegment = {
  109. count: number;
  110. name: string;
  111. value: string;
  112. url: LocationDescriptor;
  113. isOther?: boolean;
  114. key?: string;
  115. };
  116. export type Tag = {
  117. key: string;
  118. topValues: Array<TagSegment>;
  119. };
  120. /**
  121. * Fetches tag facets for a query
  122. */
  123. export async function fetchTagFacets(
  124. api: Client,
  125. orgSlug: string,
  126. query: EventQuery
  127. ): Promise<Tag[]> {
  128. const urlParams = pick(query, Object.values(PERFORMANCE_URL_PARAM));
  129. const queryOption = {...urlParams, query: query.query};
  130. return api.requestPromise(`/organizations/${orgSlug}/events-facets/`, {
  131. query: queryOption,
  132. });
  133. }
  134. /**
  135. * Fetches total count of events for a given query
  136. */
  137. export async function fetchTotalCount(
  138. api: Client,
  139. orgSlug: String,
  140. query: EventQuery & LocationQuery
  141. ): Promise<number> {
  142. const urlParams = pick(query, Object.values(PERFORMANCE_URL_PARAM));
  143. const queryOption = {...urlParams, query: query.query};
  144. type Response = {
  145. count: number;
  146. };
  147. return api
  148. .requestPromise(`/organizations/${orgSlug}/events-meta/`, {
  149. query: queryOption,
  150. })
  151. .then((res: Response) => res.count);
  152. }