import type {StoreDefinition} from 'reflux'; import {createStore} from 'reflux'; import type {Plugin} from 'sentry/types'; interface InternalDefinition { plugins: Map | null; state: { error: Error | null; loading: boolean; pageLinks: string | null; plugins: Plugin[]; }; updating: Map; } interface PluginStoreDefinition extends StoreDefinition, InternalDefinition { getState: () => InternalDefinition['state']; onFetchAll: (options?: {resetLoading?: boolean}) => void; onFetchAllError: (err) => void; onFetchAllSuccess: (data: Plugin[], links: {pageLinks?: string}) => void; onUpdate: (id: string, updateObj: Partial) => void; onUpdateError: (id: string, err: Error) => void; onUpdateSuccess: (id: string) => void; reset: () => void; } const defaultState = { loading: true, plugins: [], error: null, pageLinks: null, }; const storeConfig: PluginStoreDefinition = { plugins: null, state: {...defaultState}, updating: new Map(), reset() { // reset our state this.plugins = null; this.state = {...defaultState}; this.updating = new Map(); return this.state; }, getInitialState() { return this.getState(); }, getState() { const {plugins: _plugins, ...state} = this.state; return { ...state, plugins: this.plugins ? Array.from(this.plugins.values()) : [], }; }, init() { // XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux // listeners due to their leaky nature in tests. this.reset(); }, triggerState() { this.trigger(this.getState()); }, onFetchAll({resetLoading} = {}) { if (resetLoading) { this.state.loading = true; this.state.error = null; this.plugins = null; } this.triggerState(); }, onFetchAllSuccess(data, {pageLinks}) { this.plugins = new Map(data.map(plugin => [plugin.id, plugin])); this.state.pageLinks = pageLinks || null; this.state.loading = false; this.triggerState(); }, onFetchAllError(err) { this.plugins = null; this.state.loading = false; this.state.error = err; this.triggerState(); }, onUpdate(id: string, updateObj: Partial) { if (!this.plugins) { return; } const plugin = this.plugins.get(id); if (!plugin) { return; } const newPlugin = { ...plugin, ...updateObj, }; this.plugins.set(id, newPlugin); this.updating.set(id, plugin); this.triggerState(); }, onUpdateSuccess(id: string) { this.updating.delete(id); }, onUpdateError(id: string, err) { const origPlugin = this.updating.get(id); if (!origPlugin || !this.plugins) { return; } this.plugins.set(id, origPlugin); this.updating.delete(id); this.state.error = err; this.triggerState(); }, }; const PluginStore = createStore(storeConfig); export default PluginStore;