queryHandler.tsx 3.3 KB

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