transformSessionsResponseToTable.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import omit from 'lodash/omit';
  2. import type {MetricsApiResponse} from 'sentry/types/metrics';
  3. import type {SessionApiResponse} from 'sentry/types/organization';
  4. import type {TableData} from 'sentry/utils/discover/discoverQuery';
  5. import {aggregateOutputType} from 'sentry/utils/discover/fields';
  6. import {
  7. DERIVED_STATUS_METRICS_PATTERN,
  8. SESSIONS_TAGS,
  9. } from 'sentry/views/dashboards/widgetBuilder/releaseWidget/fields';
  10. import {derivedMetricsToField} from './releaseWidgetQueries';
  11. export function changeObjectValuesToTypes(
  12. obj: Record<string, number | string | null> | undefined
  13. ) {
  14. return Object.keys(obj ?? {}).reduce((acc, key) => {
  15. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  16. acc[key] = SESSIONS_TAGS.includes(key) ? 'string' : aggregateOutputType(key);
  17. return acc;
  18. }, {});
  19. }
  20. export function mapDerivedMetricsToFields(results: Record<string, number | null>) {
  21. const mappedResults: Record<string, number | null> = {};
  22. for (const [key, value] of Object.entries(results)) {
  23. mappedResults[derivedMetricsToField(key)] = value;
  24. }
  25. return mappedResults;
  26. }
  27. export function getDerivedMetrics(
  28. groupBy: any,
  29. totals: any,
  30. requestedStatusMetrics: any
  31. ) {
  32. const derivedTotals = {};
  33. if (!requestedStatusMetrics.length) {
  34. return derivedTotals;
  35. }
  36. if (groupBy['session.status'] === undefined) {
  37. return derivedTotals;
  38. }
  39. requestedStatusMetrics.forEach((status: any) => {
  40. const result = status.match(DERIVED_STATUS_METRICS_PATTERN);
  41. if (result) {
  42. if (groupBy['session.status'] === result[1]) {
  43. if (result[2] === 'session') {
  44. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  45. derivedTotals[status] = totals['sum(session)'];
  46. } else if (result[2] === 'user') {
  47. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  48. derivedTotals[status] = totals['count_unique(user)'];
  49. }
  50. } else {
  51. // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
  52. derivedTotals[status] = 0;
  53. }
  54. }
  55. });
  56. return derivedTotals;
  57. }
  58. export function transformSessionsResponseToTable(
  59. response: SessionApiResponse | MetricsApiResponse | null,
  60. requestedStatusMetrics: string[],
  61. injectedFields: string[]
  62. ): TableData {
  63. const data =
  64. response?.groups.map((group, index) => ({
  65. id: String(index),
  66. // @ts-expect-error TS(2345): Argument of type 'Record<string, string> | Record<... Remove this comment to see the full error message
  67. ...mapDerivedMetricsToFields(group.by),
  68. // if `sum(session)` or `count_unique(user)` are not
  69. // requested as a part of the payload for
  70. // derived status metrics through the Sessions API,
  71. // they are injected into the payload and need to be
  72. // stripped.
  73. ...omit(mapDerivedMetricsToFields(group.totals), injectedFields),
  74. // if session.status is a groupby, some post processing
  75. // is needed to calculate the status derived metrics
  76. // from grouped results of `sum(session)` or `count_unique(user)`
  77. ...getDerivedMetrics(group.by, group.totals, requestedStatusMetrics),
  78. })) ?? [];
  79. const singleRow = data[0];
  80. // TODO(metrics): these should come from the API in the future
  81. const meta = {
  82. ...changeObjectValuesToTypes(omit(singleRow, 'id')),
  83. };
  84. return {meta, data};
  85. }