projectErrorsBasicChart.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import {browserHistory} from 'react-router';
  2. import type {BarSeriesOption} from 'echarts';
  3. import {Location} from 'history';
  4. import AsyncComponent from 'sentry/components/asyncComponent';
  5. import BaseChart from 'sentry/components/charts/baseChart';
  6. import {HeaderTitleLegend} from 'sentry/components/charts/styles';
  7. import TransitionChart from 'sentry/components/charts/transitionChart';
  8. import TransparentLoadingMask from 'sentry/components/charts/transparentLoadingMask';
  9. import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
  10. import {t} from 'sentry/locale';
  11. import {Organization, Project} from 'sentry/types';
  12. import getDynamicText from 'sentry/utils/getDynamicText';
  13. export const ERRORS_BASIC_CHART_PERIODS = ['1h', '24h', '7d', '14d', '30d'];
  14. type Props = AsyncComponent['props'] & {
  15. location: Location;
  16. onTotalValuesChange: (value: number | null) => void;
  17. organization: Organization;
  18. projectId?: string;
  19. };
  20. type State = AsyncComponent['state'] & {
  21. projects: Project[] | null;
  22. };
  23. class ProjectErrorsBasicChart extends AsyncComponent<Props, State> {
  24. getDefaultState() {
  25. return {
  26. ...super.getDefaultState(),
  27. projects: null,
  28. };
  29. }
  30. getEndpoints(): ReturnType<AsyncComponent['getEndpoints']> {
  31. const {organization, projectId} = this.props;
  32. if (!projectId) {
  33. return [];
  34. }
  35. return [
  36. [
  37. 'projects',
  38. `/organizations/${organization.slug}/projects/`,
  39. {
  40. query: {
  41. statsPeriod: this.getStatsPeriod(),
  42. query: `id:${projectId}`,
  43. },
  44. },
  45. ],
  46. ];
  47. }
  48. componentDidMount() {
  49. const {location} = this.props;
  50. if (!ERRORS_BASIC_CHART_PERIODS.includes(location.query.statsPeriod)) {
  51. browserHistory.replace({
  52. pathname: location.pathname,
  53. query: {
  54. ...location.query,
  55. statsPeriod: this.getStatsPeriod(),
  56. start: undefined,
  57. end: undefined,
  58. },
  59. });
  60. }
  61. }
  62. onLoadAllEndpointsSuccess() {
  63. this.props.onTotalValuesChange(
  64. this.state.projects?.[0]?.stats?.reduce((acc, [, value]) => acc + value, 0) ?? null
  65. );
  66. }
  67. getStatsPeriod() {
  68. const {location} = this.props;
  69. const statsPeriod = location.query.statsPeriod;
  70. if (ERRORS_BASIC_CHART_PERIODS.includes(statsPeriod)) {
  71. return statsPeriod;
  72. }
  73. return DEFAULT_STATS_PERIOD;
  74. }
  75. getSeries(): BarSeriesOption[] {
  76. const {projects} = this.state;
  77. return [
  78. {
  79. cursor: 'normal' as const,
  80. name: t('Errors'),
  81. type: 'bar',
  82. data:
  83. projects?.[0]?.stats?.map(([timestamp, value]) => [timestamp * 1000, value]) ??
  84. [],
  85. },
  86. ];
  87. }
  88. renderLoading() {
  89. return this.renderBody();
  90. }
  91. renderBody() {
  92. const {loading, reloading} = this.state;
  93. return getDynamicText({
  94. value: (
  95. <TransitionChart loading={loading} reloading={reloading}>
  96. <TransparentLoadingMask visible={reloading} />
  97. <HeaderTitleLegend>{t('Daily Errors')}</HeaderTitleLegend>
  98. <BaseChart
  99. series={this.getSeries()}
  100. isGroupedByDate
  101. showTimeInTooltip
  102. colors={theme => [theme.purple300, theme.purple200]}
  103. grid={{left: '10px', right: '10px', top: '40px', bottom: '0px'}}
  104. />
  105. </TransitionChart>
  106. ),
  107. fixed: t('Number of Errors Chart'),
  108. });
  109. }
  110. }
  111. export default ProjectErrorsBasicChart;