durationChart.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import * as ReactRouter from 'react-router';
  2. import withRouter, {WithRouterProps} from 'react-router/lib/withRouter';
  3. import styled from '@emotion/styled';
  4. import {Location} from 'history';
  5. import {Client} from 'app/api';
  6. import ErrorPanel from 'app/components/charts/errorPanel';
  7. import EventsRequest from 'app/components/charts/eventsRequest';
  8. import {HeaderTitleLegend} from 'app/components/charts/styles';
  9. import TransparentLoadingMask from 'app/components/charts/transparentLoadingMask';
  10. import {getInterval} from 'app/components/charts/utils';
  11. import {getParams} from 'app/components/organizations/globalSelectionHeader/getParams';
  12. import Placeholder from 'app/components/placeholder';
  13. import QuestionTooltip from 'app/components/questionTooltip';
  14. import {IconWarning} from 'app/icons';
  15. import space from 'app/styles/space';
  16. import {Organization} from 'app/types';
  17. import {getUtcToLocalDateObject} from 'app/utils/dates';
  18. import EventView from 'app/utils/discover/eventView';
  19. import getDynamicText from 'app/utils/getDynamicText';
  20. import withApi from 'app/utils/withApi';
  21. import Chart from '../../charts/chart';
  22. import {DoubleHeaderContainer} from '../../styles';
  23. import {getFieldOrBackup} from '../display/utils';
  24. type Props = {
  25. api: Client;
  26. eventView: EventView;
  27. organization: Organization;
  28. location: Location;
  29. router: ReactRouter.InjectedRouter;
  30. field: string;
  31. title: string;
  32. titleTooltip: string;
  33. backupField?: string;
  34. usingBackupAxis: boolean;
  35. } & WithRouterProps;
  36. function DurationChart(props: Props) {
  37. const {
  38. organization,
  39. api,
  40. eventView,
  41. location,
  42. router,
  43. field,
  44. title,
  45. titleTooltip,
  46. backupField,
  47. usingBackupAxis,
  48. } = props;
  49. // construct request parameters for fetching chart data
  50. const globalSelection = eventView.getGlobalSelection();
  51. const start = globalSelection.datetime.start
  52. ? getUtcToLocalDateObject(globalSelection.datetime.start)
  53. : null;
  54. const end = globalSelection.datetime.end
  55. ? getUtcToLocalDateObject(globalSelection.datetime.end)
  56. : null;
  57. const {utc} = getParams(location.query);
  58. const _backupField = backupField ? [backupField] : [];
  59. const apiPayload = eventView.getEventsAPIPayload(location);
  60. return (
  61. <EventsRequest
  62. organization={organization}
  63. api={api}
  64. period={globalSelection.datetime.period}
  65. project={globalSelection.projects}
  66. environment={globalSelection.environments}
  67. team={apiPayload.team}
  68. start={start}
  69. end={end}
  70. interval={getInterval(
  71. {
  72. start,
  73. end,
  74. period: globalSelection.datetime.period,
  75. },
  76. true
  77. )}
  78. showLoading={false}
  79. query={apiPayload.query}
  80. includePrevious={false}
  81. yAxis={[field, ..._backupField]}
  82. partial
  83. hideError
  84. >
  85. {({
  86. loading,
  87. reloading,
  88. errored,
  89. timeseriesData: singleAxisResults,
  90. results: multiAxisResults,
  91. }) => {
  92. const _field = usingBackupAxis ? getFieldOrBackup(field, backupField) : field;
  93. const results = singleAxisResults
  94. ? singleAxisResults
  95. : [multiAxisResults?.find(r => r.seriesName === _field)].filter(Boolean);
  96. const series = results
  97. ? results.map(({...rest}) => {
  98. return {
  99. ...rest,
  100. seriesName: _field,
  101. };
  102. })
  103. : [];
  104. if (errored) {
  105. return (
  106. <ErrorPanel>
  107. <IconWarning color="gray300" size="lg" />
  108. </ErrorPanel>
  109. );
  110. }
  111. return (
  112. <div>
  113. <DoubleHeaderContainer>
  114. <HeaderTitleLegend>
  115. {title}
  116. <QuestionTooltip position="top" size="sm" title={titleTooltip} />
  117. </HeaderTitleLegend>
  118. </DoubleHeaderContainer>
  119. {results && (
  120. <ChartContainer>
  121. <MaskContainer>
  122. <TransparentLoadingMask visible={loading} />
  123. {getDynamicText({
  124. value: (
  125. <Chart
  126. height={250}
  127. data={series}
  128. loading={loading || reloading}
  129. router={router}
  130. statsPeriod={globalSelection.datetime.period}
  131. start={start}
  132. end={end}
  133. utc={utc === 'true'}
  134. grid={{
  135. left: space(3),
  136. right: space(3),
  137. top: space(3),
  138. bottom: loading || reloading ? space(4) : space(1.5),
  139. }}
  140. disableMultiAxis
  141. />
  142. ),
  143. fixed: <Placeholder height="250px" testId="skeleton-ui" />,
  144. })}
  145. </MaskContainer>
  146. </ChartContainer>
  147. )}
  148. </div>
  149. );
  150. }}
  151. </EventsRequest>
  152. );
  153. }
  154. const ChartContainer = styled('div')`
  155. padding-top: ${space(1)};
  156. `;
  157. const MaskContainer = styled('div')`
  158. position: relative;
  159. `;
  160. export default withRouter(withApi(DurationChart));