queryHandler.tsx 3.4 KB

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