indicatorStore.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {createStore} from 'reflux';
  2. import type {Indicator} from 'sentry/actionCreators/indicator';
  3. import {t} from 'sentry/locale';
  4. import type {StrictStoreDefinition} from './types';
  5. interface InternalDefinition {
  6. lastId: number;
  7. }
  8. interface IndicatorStoreDefinition
  9. extends StrictStoreDefinition<Indicator[]>,
  10. InternalDefinition {
  11. /**
  12. * When this method is called directly via older parts of the application,
  13. * we want to maintain the old behavior in that it is replaced (and not queued up)
  14. *
  15. * @param message Toast message to be displayed
  16. * @param type One of ['error', 'success', '']
  17. * @param options Options object
  18. */
  19. add(
  20. message: React.ReactNode,
  21. type?: Indicator['type'],
  22. options?: Indicator['options']
  23. ): Indicator;
  24. addError(message?: string): Indicator;
  25. /**
  26. * Alias for add()
  27. */
  28. addMessage(
  29. message: React.ReactNode,
  30. type: Indicator['type'],
  31. options?: Indicator['options']
  32. ): Indicator;
  33. addSuccess(message: string): Indicator;
  34. /**
  35. * Appends a message to be displayed in list of indicators
  36. *
  37. * @param message Toast message to be displayed
  38. * @param type One of ['error', 'success', '']
  39. * @param options Options object
  40. */
  41. append(
  42. message: React.ReactNode,
  43. type: Indicator['type'],
  44. options?: Indicator['options']
  45. ): Indicator;
  46. /**
  47. * Remove all current indicators.
  48. */
  49. clear(): void;
  50. init(): void;
  51. /**
  52. * Remove an indicator
  53. */
  54. remove(indicator: Indicator): void;
  55. }
  56. const storeConfig: IndicatorStoreDefinition = {
  57. state: [],
  58. lastId: 0,
  59. init() {
  60. // XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux
  61. // listeners due to their leaky nature in tests.
  62. this.state = [];
  63. this.lastId = 0;
  64. },
  65. addSuccess(message) {
  66. return this.add(message, 'success', {duration: 2000});
  67. },
  68. addError(message = t('An error occurred')) {
  69. return this.add(message, 'error', {duration: 2000});
  70. },
  71. addMessage(message, type, {append, ...options} = {}) {
  72. const indicator: Indicator = {
  73. id: this.lastId++,
  74. message,
  75. type,
  76. options,
  77. clearId: null,
  78. };
  79. if (options.duration) {
  80. indicator.clearId = window.setTimeout(() => {
  81. this.remove(indicator);
  82. }, options.duration);
  83. }
  84. const newItems = append ? [...this.state, indicator] : [indicator];
  85. this.state = newItems;
  86. this.trigger(this.state);
  87. return indicator;
  88. },
  89. append(message, type, options) {
  90. return this.addMessage(message, type, {
  91. ...options,
  92. append: true,
  93. });
  94. },
  95. add(message, type = 'loading', options = {}) {
  96. return this.addMessage(message, type, {
  97. ...options,
  98. append: false,
  99. });
  100. },
  101. clear() {
  102. this.state = [];
  103. this.trigger(this.state);
  104. },
  105. remove(indicator) {
  106. if (!indicator) {
  107. return;
  108. }
  109. this.state = this.state.filter(item => item !== indicator);
  110. if (indicator.clearId) {
  111. window.clearTimeout(indicator.clearId);
  112. indicator.clearId = null;
  113. }
  114. this.trigger(this.state);
  115. },
  116. getState() {
  117. return this.state;
  118. },
  119. };
  120. const IndicatorStore = createStore(storeConfig);
  121. export default IndicatorStore;