pluginComponentBase.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. import {Component} from 'react';
  2. import isFunction from 'lodash/isFunction';
  3. import {
  4. addErrorMessage,
  5. addLoadingMessage,
  6. addSuccessMessage,
  7. clearIndicators,
  8. } from 'sentry/actionCreators/indicator';
  9. import {Client} from 'sentry/api';
  10. import GenericField from 'sentry/components/deprecatedforms/genericField';
  11. import FormState from 'sentry/components/forms/state';
  12. import {t} from 'sentry/locale';
  13. const callbackWithArgs = function (context: any, callback: any, ...args: any) {
  14. return isFunction(callback) ? callback.bind(context, ...args) : undefined;
  15. };
  16. type GenericFieldProps = Parameters<typeof GenericField>[0];
  17. type Props = {};
  18. type State = {state: FormState};
  19. class PluginComponentBase<
  20. P extends Props = Props,
  21. S extends State = State,
  22. > extends Component<P, S> {
  23. constructor(props: P, context: any) {
  24. super(props, context);
  25. [
  26. 'onLoadSuccess',
  27. 'onLoadError',
  28. 'onSave',
  29. 'onSaveSuccess',
  30. 'onSaveError',
  31. 'onSaveComplete',
  32. 'renderField',
  33. ].map(method => (this[method] = this[method].bind(this)));
  34. if (this.fetchData) {
  35. this.fetchData = this.onLoad.bind(this, this.fetchData.bind(this));
  36. }
  37. if (this.onSubmit) {
  38. this.onSubmit = this.onSave.bind(this, this.onSubmit.bind(this));
  39. }
  40. this.state = {
  41. state: FormState.READY,
  42. } as Readonly<S>;
  43. }
  44. componentWillUnmount() {
  45. this.api.clear();
  46. window.clearTimeout(this.successMessageTimeout);
  47. window.clearTimeout(this.errorMessageTimeout);
  48. }
  49. successMessageTimeout: number | undefined = undefined;
  50. errorMessageTimeout: number | undefined = undefined;
  51. api = new Client();
  52. fetchData() {
  53. // Allow children to implement this
  54. }
  55. onSubmit() {
  56. // Allow children to implement this
  57. }
  58. onLoad(callback, ...args) {
  59. this.setState(
  60. {
  61. state: FormState.LOADING,
  62. },
  63. callbackWithArgs(this, callback, ...args)
  64. );
  65. }
  66. onLoadSuccess() {
  67. this.setState({
  68. state: FormState.READY,
  69. });
  70. }
  71. onLoadError(callback, ...args) {
  72. this.setState(
  73. {
  74. state: FormState.ERROR,
  75. },
  76. callbackWithArgs(this, callback, ...args)
  77. );
  78. addErrorMessage(t('An error occurred.'));
  79. }
  80. onSave(callback, ...args) {
  81. if (this.state.state === FormState.SAVING) {
  82. return;
  83. }
  84. callback = callbackWithArgs(this, callback, ...args);
  85. this.setState(
  86. {
  87. state: FormState.SAVING,
  88. },
  89. () => {
  90. addLoadingMessage(t('Saving changes\u2026'));
  91. callback?.();
  92. }
  93. );
  94. }
  95. onSaveSuccess(callback, ...args) {
  96. callback = callbackWithArgs(this, callback, ...args);
  97. this.setState(
  98. {
  99. state: FormState.READY,
  100. },
  101. () => callback?.()
  102. );
  103. window.clearTimeout(this.successMessageTimeout);
  104. this.successMessageTimeout = window.setTimeout(() => {
  105. addSuccessMessage(t('Success!'));
  106. }, 0);
  107. }
  108. onSaveError(callback, ...args) {
  109. callback = callbackWithArgs(this, callback, ...args);
  110. this.setState(
  111. {
  112. state: FormState.ERROR,
  113. },
  114. () => callback?.()
  115. );
  116. window.clearTimeout(this.errorMessageTimeout);
  117. this.errorMessageTimeout = window.setTimeout(() => {
  118. addErrorMessage(t('Unable to save changes. Please try again.'));
  119. }, 0);
  120. }
  121. onSaveComplete(callback, ...args) {
  122. clearIndicators();
  123. callback = callbackWithArgs(this, callback, ...args);
  124. callback?.();
  125. }
  126. renderField(props: Omit<GenericFieldProps, 'formState'>): React.ReactNode {
  127. props = {...props};
  128. const newProps = {
  129. ...props,
  130. formState: this.state.state,
  131. };
  132. return <GenericField key={newProps.config?.name} {...newProps} />;
  133. }
  134. }
  135. export default PluginComponentBase;