pluginsStore.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import type {StoreDefinition} from 'reflux';
  2. import {createStore} from 'reflux';
  3. import type {Plugin} from 'sentry/types/integrations';
  4. interface InternalDefinition {
  5. plugins: Map<string, Plugin> | null;
  6. state: {
  7. error: Error | null;
  8. loading: boolean;
  9. pageLinks: string | null;
  10. plugins: Plugin[];
  11. };
  12. updating: Map<string, Plugin>;
  13. }
  14. interface PluginStoreDefinition extends StoreDefinition, InternalDefinition {
  15. getState: () => InternalDefinition['state'];
  16. onFetchAll: (options?: {resetLoading?: boolean}) => void;
  17. onFetchAllError: (err) => void;
  18. onFetchAllSuccess: (data: Plugin[], links: {pageLinks?: string}) => void;
  19. onUpdate: (id: string, updateObj: Partial<Plugin>) => void;
  20. onUpdateError: (id: string, err: Error) => void;
  21. onUpdateSuccess: (id: string) => void;
  22. reset: () => void;
  23. }
  24. const defaultState = {
  25. loading: true,
  26. plugins: [],
  27. error: null,
  28. pageLinks: null,
  29. };
  30. const storeConfig: PluginStoreDefinition = {
  31. plugins: null,
  32. state: {...defaultState},
  33. updating: new Map(),
  34. reset() {
  35. // reset our state
  36. this.plugins = null;
  37. this.state = {...defaultState};
  38. this.updating = new Map();
  39. return this.state;
  40. },
  41. getInitialState() {
  42. return this.getState();
  43. },
  44. getState() {
  45. const {plugins: _plugins, ...state} = this.state;
  46. return {
  47. ...state,
  48. plugins: this.plugins ? Array.from(this.plugins.values()) : [],
  49. };
  50. },
  51. init() {
  52. // XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux
  53. // listeners due to their leaky nature in tests.
  54. this.reset();
  55. },
  56. triggerState() {
  57. this.trigger(this.getState());
  58. },
  59. onFetchAll({resetLoading} = {}) {
  60. if (resetLoading) {
  61. this.state.loading = true;
  62. this.state.error = null;
  63. this.plugins = null;
  64. }
  65. this.triggerState();
  66. },
  67. onFetchAllSuccess(data, {pageLinks}) {
  68. this.plugins = new Map(data.map(plugin => [plugin.id, plugin]));
  69. this.state.pageLinks = pageLinks || null;
  70. this.state.loading = false;
  71. this.triggerState();
  72. },
  73. onFetchAllError(err) {
  74. this.plugins = null;
  75. this.state.loading = false;
  76. this.state.error = err;
  77. this.triggerState();
  78. },
  79. onUpdate(id: string, updateObj: Partial<Plugin>) {
  80. if (!this.plugins) {
  81. return;
  82. }
  83. const plugin = this.plugins.get(id);
  84. if (!plugin) {
  85. return;
  86. }
  87. const newPlugin = {
  88. ...plugin,
  89. ...updateObj,
  90. };
  91. this.plugins.set(id, newPlugin);
  92. this.updating.set(id, plugin);
  93. this.triggerState();
  94. },
  95. onUpdateSuccess(id: string) {
  96. this.updating.delete(id);
  97. },
  98. onUpdateError(id: string, err) {
  99. const origPlugin = this.updating.get(id);
  100. if (!origPlugin || !this.plugins) {
  101. return;
  102. }
  103. this.plugins.set(id, origPlugin);
  104. this.updating.delete(id);
  105. this.state.error = err;
  106. this.triggerState();
  107. },
  108. };
  109. const PluginStore = createStore(storeConfig);
  110. export default PluginStore;