transactionThresholdButton.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import {Component} from 'react';
  2. import {addErrorMessage} from 'sentry/actionCreators/indicator';
  3. import {openModal} from 'sentry/actionCreators/modal';
  4. import type {Client} from 'sentry/api';
  5. import {Button} from 'sentry/components/button';
  6. import {IconSettings} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import type {Organization, Project} from 'sentry/types';
  9. import {defined} from 'sentry/utils';
  10. import type EventView from 'sentry/utils/discover/eventView';
  11. import withApi from 'sentry/utils/withApi';
  12. import withProjects from 'sentry/utils/withProjects';
  13. import type {TransactionThresholdMetric} from './transactionThresholdModal';
  14. import TransactionThresholdModal, {modalCss} from './transactionThresholdModal';
  15. type Props = {
  16. api: Client;
  17. eventView: EventView;
  18. organization: Organization;
  19. projects: Project[];
  20. transactionName: string;
  21. onChangeThreshold?: (threshold: number, metric: TransactionThresholdMetric) => void;
  22. };
  23. type State = {
  24. loadingThreshold: boolean;
  25. transactionThreshold: number | undefined;
  26. transactionThresholdMetric: TransactionThresholdMetric | undefined;
  27. };
  28. class TransactionThresholdButton extends Component<Props, State> {
  29. state: State = {
  30. transactionThreshold: undefined,
  31. transactionThresholdMetric: undefined,
  32. loadingThreshold: false,
  33. };
  34. componentDidMount() {
  35. this.fetchTransactionThreshold();
  36. }
  37. getProject() {
  38. const {projects, eventView} = this.props;
  39. if (!defined(eventView)) {
  40. return undefined;
  41. }
  42. const projectId = String(eventView.project[0]);
  43. const project = projects.find(proj => proj.id === projectId);
  44. return project;
  45. }
  46. fetchTransactionThreshold = () => {
  47. const {api, organization, transactionName} = this.props;
  48. const project = this.getProject();
  49. if (!defined(project)) {
  50. return;
  51. }
  52. const transactionThresholdUrl = `/organizations/${organization.slug}/project-transaction-threshold-override/`;
  53. this.setState({loadingThreshold: true});
  54. api
  55. .requestPromise(transactionThresholdUrl, {
  56. method: 'GET',
  57. includeAllArgs: true,
  58. query: {
  59. project: project.id,
  60. transaction: transactionName,
  61. },
  62. })
  63. .then(([data]) => {
  64. this.setState({
  65. loadingThreshold: false,
  66. transactionThreshold: data.threshold,
  67. transactionThresholdMetric: data.metric,
  68. });
  69. })
  70. .catch(() => {
  71. const projectThresholdUrl = `/projects/${organization.slug}/${project.slug}/transaction-threshold/configure/`;
  72. this.props.api
  73. .requestPromise(projectThresholdUrl, {
  74. method: 'GET',
  75. includeAllArgs: true,
  76. query: {
  77. project: project.id,
  78. },
  79. })
  80. .then(([data]) => {
  81. this.setState({
  82. loadingThreshold: false,
  83. transactionThreshold: data.threshold,
  84. transactionThresholdMetric: data.metric,
  85. });
  86. })
  87. .catch(err => {
  88. this.setState({loadingThreshold: false});
  89. const errorMessage = err.responseJSON?.threshold ?? null;
  90. addErrorMessage(errorMessage);
  91. });
  92. });
  93. };
  94. onChangeThreshold(threshold: number, metric: TransactionThresholdMetric) {
  95. const {onChangeThreshold} = this.props;
  96. this.setState({
  97. transactionThreshold: threshold,
  98. transactionThresholdMetric: metric,
  99. });
  100. if (defined(onChangeThreshold)) {
  101. onChangeThreshold(threshold, metric);
  102. }
  103. }
  104. openModal() {
  105. const {organization, transactionName, eventView} = this.props;
  106. const {transactionThreshold, transactionThresholdMetric} = this.state;
  107. openModal(
  108. modalProps => (
  109. <TransactionThresholdModal
  110. {...modalProps}
  111. organization={organization}
  112. transactionName={transactionName}
  113. eventView={eventView}
  114. transactionThreshold={transactionThreshold}
  115. transactionThresholdMetric={transactionThresholdMetric}
  116. onApply={(threshold, metric) => this.onChangeThreshold(threshold, metric)}
  117. />
  118. ),
  119. {modalCss, closeEvents: 'escape-key'}
  120. );
  121. }
  122. render() {
  123. const {loadingThreshold} = this.state;
  124. return (
  125. <Button
  126. size="sm"
  127. onClick={() => this.openModal()}
  128. icon={<IconSettings />}
  129. disabled={loadingThreshold}
  130. aria-label={t('Settings')}
  131. data-test-id="set-transaction-threshold"
  132. />
  133. );
  134. }
  135. }
  136. export default withApi(withProjects(TransactionThresholdButton));