queryHandler.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. import {Fragment, useEffect} from 'react';
  2. import {getUtcToLocalDateObject} from 'sentry/utils/dates';
  3. import {
  4. getIsMetricsDataFromResults,
  5. useMEPDataContext,
  6. } from 'sentry/utils/performance/contexts/metricsEnhancedPerformanceDataContext';
  7. import type {
  8. QueryDefinitionWithKey,
  9. QueryHandlerProps,
  10. WidgetDataConstraint,
  11. } from '../types';
  12. import type {PerformanceWidgetSetting} from '../widgetDefinitions';
  13. /**
  14. * Component to handle switching component-style queries over to state. This
  15. * should be temporary to make it easier to switch away from waterfall style
  16. * api components.
  17. */
  18. export function QueryHandler<T extends WidgetDataConstraint>(
  19. props: QueryHandlerProps<T>
  20. ) {
  21. const children = props.children ?? <Fragment />;
  22. if (!props.queries.length) {
  23. return <Fragment>{children}</Fragment>;
  24. }
  25. return (
  26. <Fragment>
  27. {props.queries
  28. .filter(q => (q.enabled ? q.enabled(props.widgetData) : true))
  29. .map(query => (
  30. <SingleQueryHandler key={query.queryKey} {...props} query={query} />
  31. ))}
  32. </Fragment>
  33. );
  34. }
  35. function genericQueryReferrer(setting: PerformanceWidgetSetting) {
  36. return `api.performance.generic-widget-chart.${setting.replace(/_/g, '-')}`;
  37. }
  38. function SingleQueryHandler<T extends WidgetDataConstraint>(
  39. props: QueryHandlerProps<T> & {query: QueryDefinitionWithKey<T>}
  40. ) {
  41. const query = props.query;
  42. const globalSelection = props.queryProps.eventView.getPageFilters();
  43. const start = globalSelection.datetime.start
  44. ? getUtcToLocalDateObject(globalSelection.datetime.start)
  45. : null;
  46. const end = globalSelection.datetime.end
  47. ? getUtcToLocalDateObject(globalSelection.datetime.end)
  48. : null;
  49. useEffect(
  50. () => () => {
  51. // Destroy previous data on unmount, in case enabled value changes and unmounts the query component.
  52. props.removeWidgetDataForKey(query.queryKey);
  53. },
  54. // eslint-disable-next-line react-hooks/exhaustive-deps
  55. []
  56. );
  57. return (
  58. <query.component
  59. key={query.queryKey}
  60. fields={query.fields}
  61. yAxis={query.fields}
  62. start={start}
  63. end={end}
  64. period={globalSelection.datetime.period}
  65. project={globalSelection.projects}
  66. environment={globalSelection.environments}
  67. organization={props.queryProps.organization}
  68. orgSlug={props.queryProps.organization.slug}
  69. eventView={props.queryProps.eventView}
  70. query={props.queryProps.eventView.getQueryWithAdditionalConditions()}
  71. widgetData={props.widgetData}
  72. referrer={genericQueryReferrer(props.queryProps.chartSetting)}
  73. >
  74. {results => {
  75. return (
  76. <Fragment>
  77. <QueryResultSaver<T> results={results} {...props} query={query} />
  78. </Fragment>
  79. );
  80. }}
  81. </query.component>
  82. );
  83. }
  84. function QueryResultSaver<T extends WidgetDataConstraint>(
  85. props: {
  86. // TODO(k-fish): Fix this any.
  87. query: QueryDefinitionWithKey<T>;
  88. results: any;
  89. } & QueryHandlerProps<T>
  90. ) {
  91. const mepContext = useMEPDataContext();
  92. const {results, query} = props;
  93. const transformed = query.transform(props.queryProps, results, props.query);
  94. useEffect(() => {
  95. const isMetricsData = getIsMetricsDataFromResults(
  96. results,
  97. props.queryProps.fields[0]
  98. );
  99. mepContext.setIsMetricsData(isMetricsData);
  100. props.setWidgetDataForKey(query.queryKey, transformed);
  101. // eslint-disable-next-line react-hooks/exhaustive-deps
  102. }, [transformed?.hasData, transformed?.isLoading, transformed?.isErrored]);
  103. return <Fragment />;
  104. }