widgetCardChartContainer.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import {Fragment} from 'react';
  2. // eslint-disable-next-line no-restricted-imports
  3. import {withRouter, WithRouterProps} from 'react-router';
  4. import styled from '@emotion/styled';
  5. import type {DataZoomComponentOption} from 'echarts';
  6. import {LegendComponentOption} from 'echarts';
  7. import {Client} from 'sentry/api';
  8. import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
  9. import LoadingIndicator from 'sentry/components/loadingIndicator';
  10. import {Organization, PageFilters} from 'sentry/types';
  11. import {EChartEventHandler, Series} from 'sentry/types/echarts';
  12. import {TableDataWithTitle} from 'sentry/utils/discover/discoverQuery';
  13. import {DashboardFilters, Widget, WidgetType} from '../types';
  14. import WidgetCardChart, {AugmentedEChartDataZoomHandler} from './chart';
  15. import {IssueWidgetCard} from './issueWidgetCard';
  16. import IssueWidgetQueries from './issueWidgetQueries';
  17. import ReleaseWidgetQueries from './releaseWidgetQueries';
  18. import WidgetQueries from './widgetQueries';
  19. type Props = WithRouterProps & {
  20. api: Client;
  21. organization: Organization;
  22. selection: PageFilters;
  23. widget: Widget;
  24. chartZoomOptions?: DataZoomComponentOption;
  25. dashboardFilters?: DashboardFilters;
  26. expandNumbers?: boolean;
  27. isMobile?: boolean;
  28. legendOptions?: LegendComponentOption;
  29. noPadding?: boolean;
  30. onDataFetched?: (results: {
  31. pageLinks?: string;
  32. tableResults?: TableDataWithTitle[];
  33. timeseriesResults?: Series[];
  34. totalIssuesCount?: string;
  35. }) => void;
  36. onLegendSelectChanged?: EChartEventHandler<{
  37. name: string;
  38. selected: Record<string, boolean>;
  39. type: 'legendselectchanged';
  40. }>;
  41. onZoom?: AugmentedEChartDataZoomHandler;
  42. renderErrorMessage?: (errorMessage?: string) => React.ReactNode;
  43. showSlider?: boolean;
  44. tableItemLimit?: number;
  45. windowWidth?: number;
  46. };
  47. export function WidgetCardChartContainer({
  48. location,
  49. router,
  50. api,
  51. organization,
  52. selection,
  53. widget,
  54. dashboardFilters,
  55. isMobile,
  56. renderErrorMessage,
  57. tableItemLimit,
  58. windowWidth,
  59. onZoom,
  60. onLegendSelectChanged,
  61. legendOptions,
  62. expandNumbers,
  63. onDataFetched,
  64. showSlider,
  65. noPadding,
  66. chartZoomOptions,
  67. }: Props) {
  68. if (widget.widgetType === WidgetType.ISSUE) {
  69. return (
  70. <IssueWidgetQueries
  71. api={api}
  72. organization={organization}
  73. widget={widget}
  74. selection={selection}
  75. limit={tableItemLimit}
  76. onDataFetched={onDataFetched}
  77. dashboardFilters={dashboardFilters}
  78. >
  79. {({tableResults, errorMessage, loading}) => {
  80. return (
  81. <Fragment>
  82. {typeof renderErrorMessage === 'function'
  83. ? renderErrorMessage(errorMessage)
  84. : null}
  85. <LoadingScreen loading={loading} />
  86. <IssueWidgetCard
  87. transformedResults={tableResults?.[0].data ?? []}
  88. loading={loading}
  89. errorMessage={errorMessage}
  90. widget={widget}
  91. organization={organization}
  92. location={location}
  93. selection={selection}
  94. />
  95. </Fragment>
  96. );
  97. }}
  98. </IssueWidgetQueries>
  99. );
  100. }
  101. if (widget.widgetType === WidgetType.RELEASE) {
  102. return (
  103. <ReleaseWidgetQueries
  104. api={api}
  105. organization={organization}
  106. widget={widget}
  107. selection={selection}
  108. limit={widget.limit ?? tableItemLimit}
  109. onDataFetched={onDataFetched}
  110. dashboardFilters={dashboardFilters}
  111. >
  112. {({tableResults, timeseriesResults, errorMessage, loading}) => {
  113. return (
  114. <Fragment>
  115. {typeof renderErrorMessage === 'function'
  116. ? renderErrorMessage(errorMessage)
  117. : null}
  118. <WidgetCardChart
  119. timeseriesResults={timeseriesResults}
  120. tableResults={tableResults}
  121. errorMessage={errorMessage}
  122. loading={loading}
  123. location={location}
  124. widget={widget}
  125. selection={selection}
  126. router={router}
  127. organization={organization}
  128. isMobile={isMobile}
  129. windowWidth={windowWidth}
  130. expandNumbers={expandNumbers}
  131. onZoom={onZoom}
  132. showSlider={showSlider}
  133. noPadding={noPadding}
  134. chartZoomOptions={chartZoomOptions}
  135. />
  136. </Fragment>
  137. );
  138. }}
  139. </ReleaseWidgetQueries>
  140. );
  141. }
  142. return (
  143. <WidgetQueries
  144. api={api}
  145. organization={organization}
  146. widget={widget}
  147. selection={selection}
  148. limit={tableItemLimit}
  149. onDataFetched={onDataFetched}
  150. dashboardFilters={dashboardFilters}
  151. >
  152. {({tableResults, timeseriesResults, errorMessage, loading}) => {
  153. return (
  154. <Fragment>
  155. {typeof renderErrorMessage === 'function'
  156. ? renderErrorMessage(errorMessage)
  157. : null}
  158. <WidgetCardChart
  159. timeseriesResults={timeseriesResults}
  160. tableResults={tableResults}
  161. errorMessage={errorMessage}
  162. loading={loading}
  163. location={location}
  164. widget={widget}
  165. selection={selection}
  166. router={router}
  167. organization={organization}
  168. isMobile={isMobile}
  169. windowWidth={windowWidth}
  170. onZoom={onZoom}
  171. onLegendSelectChanged={onLegendSelectChanged}
  172. legendOptions={legendOptions}
  173. expandNumbers={expandNumbers}
  174. showSlider={showSlider}
  175. noPadding={noPadding}
  176. chartZoomOptions={chartZoomOptions}
  177. />
  178. </Fragment>
  179. );
  180. }}
  181. </WidgetQueries>
  182. );
  183. }
  184. export default withRouter(WidgetCardChartContainer);
  185. const StyledTransparentLoadingMask = styled(props => (
  186. <TransparentLoadingMask {...props} maskBackgroundColor="transparent" />
  187. ))`
  188. display: flex;
  189. justify-content: center;
  190. align-items: center;
  191. `;
  192. const LoadingScreen = ({loading}: {loading: boolean}) => {
  193. if (!loading) {
  194. return null;
  195. }
  196. return (
  197. <StyledTransparentLoadingMask visible={loading}>
  198. <LoadingIndicator mini />
  199. </StyledTransparentLoadingMask>
  200. );
  201. };