keyStats.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import {Component} from 'react';
  2. import type {RouteComponentProps} from 'react-router';
  3. import type {Client} from 'sentry/api';
  4. import MiniBarChart from 'sentry/components/charts/miniBarChart';
  5. import EmptyMessage from 'sentry/components/emptyMessage';
  6. import LoadingError from 'sentry/components/loadingError';
  7. import Panel from 'sentry/components/panels/panel';
  8. import PanelBody from 'sentry/components/panels/panelBody';
  9. import PanelHeader from 'sentry/components/panels/panelHeader';
  10. import Placeholder from 'sentry/components/placeholder';
  11. import {t} from 'sentry/locale';
  12. import type {Organization} from 'sentry/types';
  13. import type {Series} from 'sentry/types/echarts';
  14. import theme from 'sentry/utils/theme';
  15. type Props = {
  16. api: Client;
  17. organization: Organization;
  18. } & Pick<
  19. RouteComponentProps<
  20. {
  21. keyId: string;
  22. projectId: string;
  23. },
  24. {}
  25. >,
  26. 'params'
  27. >;
  28. type State = {
  29. emptyStats: boolean;
  30. error: boolean;
  31. loading: boolean;
  32. series: Series[];
  33. since: number;
  34. until: number;
  35. };
  36. const getInitialState = (): State => {
  37. const until = Math.floor(new Date().getTime() / 1000);
  38. return {
  39. since: until - 3600 * 24 * 30,
  40. until,
  41. loading: true,
  42. error: false,
  43. series: [],
  44. emptyStats: false,
  45. };
  46. };
  47. class KeyStats extends Component<Props, State> {
  48. state = getInitialState();
  49. componentDidMount() {
  50. this.fetchData();
  51. }
  52. fetchData = () => {
  53. const {organization} = this.props;
  54. const {keyId, projectId} = this.props.params;
  55. this.props.api.request(
  56. `/projects/${organization.slug}/${projectId}/keys/${keyId}/stats/`,
  57. {
  58. query: {
  59. since: this.state.since,
  60. until: this.state.until,
  61. resolution: '1d',
  62. },
  63. success: data => {
  64. let emptyStats = true;
  65. const dropped: Series['data'] = [];
  66. const accepted: Series['data'] = [];
  67. data.forEach(p => {
  68. if (p.total) {
  69. emptyStats = false;
  70. }
  71. dropped.push({name: p.ts * 1000, value: p.dropped});
  72. accepted.push({name: p.ts * 1000, value: p.accepted});
  73. });
  74. const series = [
  75. {
  76. seriesName: t('Accepted'),
  77. data: accepted,
  78. },
  79. {
  80. seriesName: t('Rate Limited'),
  81. data: dropped,
  82. },
  83. ];
  84. this.setState({
  85. series,
  86. emptyStats,
  87. error: false,
  88. loading: false,
  89. });
  90. },
  91. error: () => {
  92. this.setState({error: true, loading: false});
  93. },
  94. }
  95. );
  96. };
  97. render() {
  98. if (this.state.error) {
  99. return <LoadingError onRetry={this.fetchData} />;
  100. }
  101. return (
  102. <Panel>
  103. <PanelHeader>{t('Key usage in the last 30 days (by day)')}</PanelHeader>
  104. <PanelBody withPadding>
  105. {this.state.loading ? (
  106. <Placeholder height="150px" />
  107. ) : !this.state.emptyStats ? (
  108. <MiniBarChart
  109. isGroupedByDate
  110. series={this.state.series}
  111. height={150}
  112. colors={[theme.gray200, theme.red300]}
  113. stacked
  114. labelYAxisExtents
  115. />
  116. ) : (
  117. <EmptyMessage
  118. title={t('Nothing recorded in the last 30 days.')}
  119. description={t('Total events captured using these credentials.')}
  120. />
  121. )}
  122. </PanelBody>
  123. </Panel>
  124. );
  125. }
  126. }
  127. export default KeyStats;