widgetCardChartContainer.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. timeseriesResultsType?: string;
  35. totalIssuesCount?: string;
  36. }) => void;
  37. onLegendSelectChanged?: EChartEventHandler<{
  38. name: string;
  39. selected: Record<string, boolean>;
  40. type: 'legendselectchanged';
  41. }>;
  42. onZoom?: AugmentedEChartDataZoomHandler;
  43. renderErrorMessage?: (errorMessage?: string) => React.ReactNode;
  44. showSlider?: boolean;
  45. tableItemLimit?: number;
  46. windowWidth?: number;
  47. };
  48. export function WidgetCardChartContainer({
  49. location,
  50. router,
  51. api,
  52. organization,
  53. selection,
  54. widget,
  55. dashboardFilters,
  56. isMobile,
  57. renderErrorMessage,
  58. tableItemLimit,
  59. windowWidth,
  60. onZoom,
  61. onLegendSelectChanged,
  62. legendOptions,
  63. expandNumbers,
  64. onDataFetched,
  65. showSlider,
  66. noPadding,
  67. chartZoomOptions,
  68. }: Props) {
  69. if (widget.widgetType === WidgetType.ISSUE) {
  70. return (
  71. <IssueWidgetQueries
  72. api={api}
  73. organization={organization}
  74. widget={widget}
  75. selection={selection}
  76. limit={tableItemLimit}
  77. onDataFetched={onDataFetched}
  78. dashboardFilters={dashboardFilters}
  79. >
  80. {({tableResults, errorMessage, loading}) => {
  81. return (
  82. <Fragment>
  83. {typeof renderErrorMessage === 'function'
  84. ? renderErrorMessage(errorMessage)
  85. : null}
  86. <LoadingScreen loading={loading} />
  87. <IssueWidgetCard
  88. transformedResults={tableResults?.[0].data ?? []}
  89. loading={loading}
  90. errorMessage={errorMessage}
  91. widget={widget}
  92. organization={organization}
  93. location={location}
  94. selection={selection}
  95. />
  96. </Fragment>
  97. );
  98. }}
  99. </IssueWidgetQueries>
  100. );
  101. }
  102. if (widget.widgetType === WidgetType.RELEASE) {
  103. return (
  104. <ReleaseWidgetQueries
  105. api={api}
  106. organization={organization}
  107. widget={widget}
  108. selection={selection}
  109. limit={widget.limit ?? tableItemLimit}
  110. onDataFetched={onDataFetched}
  111. dashboardFilters={dashboardFilters}
  112. >
  113. {({tableResults, timeseriesResults, errorMessage, loading}) => {
  114. return (
  115. <Fragment>
  116. {typeof renderErrorMessage === 'function'
  117. ? renderErrorMessage(errorMessage)
  118. : null}
  119. <WidgetCardChart
  120. timeseriesResults={timeseriesResults}
  121. tableResults={tableResults}
  122. errorMessage={errorMessage}
  123. loading={loading}
  124. location={location}
  125. widget={widget}
  126. selection={selection}
  127. router={router}
  128. organization={organization}
  129. isMobile={isMobile}
  130. windowWidth={windowWidth}
  131. expandNumbers={expandNumbers}
  132. onZoom={onZoom}
  133. showSlider={showSlider}
  134. noPadding={noPadding}
  135. chartZoomOptions={chartZoomOptions}
  136. />
  137. </Fragment>
  138. );
  139. }}
  140. </ReleaseWidgetQueries>
  141. );
  142. }
  143. return (
  144. <WidgetQueries
  145. api={api}
  146. organization={organization}
  147. widget={widget}
  148. selection={selection}
  149. limit={tableItemLimit}
  150. onDataFetched={onDataFetched}
  151. dashboardFilters={dashboardFilters}
  152. >
  153. {({
  154. tableResults,
  155. timeseriesResults,
  156. errorMessage,
  157. loading,
  158. timeseriesResultsType,
  159. }) => {
  160. return (
  161. <Fragment>
  162. {typeof renderErrorMessage === 'function'
  163. ? renderErrorMessage(errorMessage)
  164. : null}
  165. <WidgetCardChart
  166. timeseriesResults={timeseriesResults}
  167. tableResults={tableResults}
  168. errorMessage={errorMessage}
  169. loading={loading}
  170. location={location}
  171. widget={widget}
  172. selection={selection}
  173. router={router}
  174. organization={organization}
  175. isMobile={isMobile}
  176. windowWidth={windowWidth}
  177. onZoom={onZoom}
  178. onLegendSelectChanged={onLegendSelectChanged}
  179. legendOptions={legendOptions}
  180. expandNumbers={expandNumbers}
  181. showSlider={showSlider}
  182. noPadding={noPadding}
  183. chartZoomOptions={chartZoomOptions}
  184. timeseriesResultsType={timeseriesResultsType}
  185. />
  186. </Fragment>
  187. );
  188. }}
  189. </WidgetQueries>
  190. );
  191. }
  192. export default withRouter(WidgetCardChartContainer);
  193. const StyledTransparentLoadingMask = styled(props => (
  194. <TransparentLoadingMask {...props} maskBackgroundColor="transparent" />
  195. ))`
  196. display: flex;
  197. justify-content: center;
  198. align-items: center;
  199. `;
  200. const LoadingScreen = ({loading}: {loading: boolean}) => {
  201. if (!loading) {
  202. return null;
  203. }
  204. return (
  205. <StyledTransparentLoadingMask visible={loading}>
  206. <LoadingIndicator mini />
  207. </StyledTransparentLoadingMask>
  208. );
  209. };