queryHandler.tsx 3.3 KB

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