keyStats.tsx 3.2 KB

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